1
0
mirror of https://github.com/containers/youki synced 2024-11-23 01:11:58 +01:00

Merge pull request #2524 from xiaoyang-sde/cpu-throttling

fix(libcgroups): report CPU throttling stats in 'libcgroups::v2'
This commit is contained in:
Toru Komatsu 2023-11-17 16:24:05 +09:00 committed by GitHub
commit 3c7cc26574
Signed by: GitHub
GPG Key ID: 4AEE18F83AFDEB23

@ -1,12 +1,11 @@
use std::{
borrow::Cow,
num::ParseIntError,
path::{Path, PathBuf},
};
use crate::{
common::{self, ControllerOpt, WrappedIoError},
stats::{self, CpuStats, StatsProvider},
stats::{self, CpuStats, ParseFlatKeyedDataError, StatsProvider},
};
use oci_spec::runtime::LinuxCpu;
@ -49,13 +48,10 @@ impl Controller for Cpu {
pub enum V2CpuStatsError {
#[error("io error: {0}")]
WrappedIo(#[from] WrappedIoError),
#[error("failed parsing value {value} for field {field} in {path}: {err}")]
ParseField {
value: String,
field: String,
path: PathBuf,
err: ParseIntError,
},
#[error("while parsing stat table: {0}")]
ParseNestedKeyedData(#[from] ParseFlatKeyedDataError),
#[error("missing field {field} from {path}")]
MissingField { field: &'static str, path: PathBuf },
}
impl StatsProvider for Cpu {
@ -66,29 +62,27 @@ impl StatsProvider for Cpu {
let mut stats = CpuStats::default();
let stats_path = cgroup_path.join(CPU_STAT);
let stat_content = common::read_cgroup_file(&stats_path)?;
for entry in stat_content.lines() {
let parts: Vec<&str> = entry.split_ascii_whitespace().collect();
if parts.len() != 2 {
continue;
}
let stats_table = stats::parse_flat_keyed_data(&stats_path)?;
let value = parts[1]
.parse()
.map_err(|err| V2CpuStatsError::ParseField {
value: parts[1].into(),
field: parts[0].into(),
path: stats_path.clone(),
err,
})?;
match parts[0] {
"usage_usec" => stats.usage.usage_total = value,
"user_usec" => stats.usage.usage_user = value,
"system_usec" => stats.usage.usage_kernel = value,
_ => continue,
}
macro_rules! get {
($name: expr => $field1:ident.$field2:ident) => {
stats.$field1.$field2 =
*stats_table
.get($name)
.ok_or_else(|| V2CpuStatsError::MissingField {
field: $name,
path: stats_path.clone(),
})?;
};
}
get!("usage_usec" => usage.usage_total);
get!("user_usec" => usage.usage_user);
get!("system_usec" => usage.usage_kernel);
get!("nr_periods" => throttling.periods);
get!("nr_throttled" => throttling.throttled_periods);
get!("throttled_usec" => throttling.throttled_time);
stats.psi = stats::psi_stats(&cgroup_path.join(CPU_PSI))?;
Ok(stats)
}
@ -176,7 +170,7 @@ impl Cpu {
mod tests {
use super::*;
use crate::{
stats::CpuUsage,
stats::{CpuThrottling, CpuUsage},
test::{set_fixture, setup},
};
use oci_spec::runtime::LinuxCpuBuilder;
@ -337,19 +331,36 @@ mod tests {
#[test]
fn test_stat_usage() {
let tmp = tempfile::tempdir().unwrap();
let content = ["usage_usec 7730", "user_usec 4387", "system_usec 3498"].join("\n");
let content = [
"usage_usec 7730",
"user_usec 4387",
"system_usec 3498",
"nr_periods 400",
"nr_throttled 20",
"throttled_usec 5000",
]
.join("\n");
set_fixture(tmp.path(), CPU_STAT, &content).expect("create stat file");
set_fixture(tmp.path(), CPU_PSI, "").expect("create psi file");
let actual = Cpu::stats(tmp.path()).expect("get cgroup stats");
let expected = CpuUsage {
usage_total: 7730,
usage_user: 4387,
usage_kernel: 3498,
let expected = CpuStats {
usage: CpuUsage {
usage_total: 7730,
usage_user: 4387,
usage_kernel: 3498,
..Default::default()
},
throttling: CpuThrottling {
periods: 400,
throttled_periods: 20,
throttled_time: 5000,
},
..Default::default()
};
assert_eq!(actual.usage, expected);
assert_eq!(actual.usage, expected.usage);
assert_eq!(actual.throttling, expected.throttling);
}
#[test]