1
0
Fork 0
mirror of https://github.com/containers/youki synced 2024-05-10 09:36:13 +02:00

Merge pull request #908 from wineway/main

support configure cpu.idle by Cgroupfs
This commit is contained in:
utam0k 2022-05-12 05:39:49 +09:00 committed by GitHub
commit 84bb36321c
Signed by: GitHub
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 242 additions and 97 deletions

99
Cargo.lock generated
View File

@ -380,16 +380,6 @@ dependencies = [
"lazy_static",
]
[[package]]
name = "darling"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f2c43f534ea4b0b049015d00269734195e6d3f0f6635cb692251aca6f9f8b3c"
dependencies = [
"darling_core 0.12.4",
"darling_macro 0.12.4",
]
[[package]]
name = "darling"
version = "0.13.4"
@ -410,20 +400,6 @@ dependencies = [
"darling_macro 0.14.0",
]
[[package]]
name = "darling_core"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e91455b86830a1c21799d94524df0845183fa55bafd9aa137b01c7d1065fa36"
dependencies = [
"fnv",
"ident_case",
"proc-macro2",
"quote",
"strsim",
"syn",
]
[[package]]
name = "darling_core"
version = "0.13.4"
@ -451,17 +427,6 @@ dependencies = [
"syn",
]
[[package]]
name = "darling_macro"
version = "0.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29b5acf0dea37a7f66f7b25d2c5e93fd46f8f6968b1a5d7a3e02e97768afc95a"
dependencies = [
"darling_core 0.12.4",
"quote",
"syn",
]
[[package]]
name = "darling_macro"
version = "0.13.4"
@ -495,34 +460,13 @@ dependencies = [
"winapi",
]
[[package]]
name = "derive_builder"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d13202debe11181040ae9063d739fa32cfcaaebe2275fe387703460ae2365b30"
dependencies = [
"derive_builder_macro 0.10.2",
]
[[package]]
name = "derive_builder"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d07adf7be193b71cc36b193d0f5fe60b918a3a9db4dad0449f57bcfd519704a3"
dependencies = [
"derive_builder_macro 0.11.2",
]
[[package]]
name = "derive_builder_core"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66e616858f6187ed828df7c64a6d71720d83767a7f19740b2d1b6fe6327b36e5"
dependencies = [
"darling 0.12.4",
"proc-macro2",
"quote",
"syn",
"derive_builder_macro",
]
[[package]]
@ -537,23 +481,13 @@ dependencies = [
"syn",
]
[[package]]
name = "derive_builder_macro"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58a94ace95092c5acb1e97a7e846b310cfbd499652f72297da7493f618a98d73"
dependencies = [
"derive_builder_core 0.10.2",
"syn",
]
[[package]]
name = "derive_builder_macro"
version = "0.11.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f0314b72bed045f3a68671b3c86328386762c93f82d98c65c3cb5e5f573dd68"
dependencies = [
"derive_builder_core 0.11.2",
"derive_builder_core",
"syn",
]
@ -996,7 +930,7 @@ dependencies = [
"log",
"nix",
"num_cpus",
"oci-spec 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"oci-spec",
"once_cell",
"pnet",
"procfs",
@ -1094,7 +1028,7 @@ dependencies = [
"log",
"mockall",
"nix",
"oci-spec 0.5.5 (git+https://github.com/containers/oci-spec-rs?rev=89376af)",
"oci-spec",
"procfs",
"quickcheck",
"rbpf",
@ -1121,7 +1055,7 @@ dependencies = [
"log",
"mio",
"nix",
"oci-spec 0.5.5 (git+https://github.com/containers/oci-spec-rs?rev=89376af)",
"oci-spec",
"path-clean",
"prctl",
"procfs",
@ -1415,23 +1349,10 @@ dependencies = [
[[package]]
name = "oci-spec"
version = "0.5.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71a85b9f9654fe5c3eab8907369250c05aeda9d807b76bd06c740601f881dc02"
version = "0.5.6"
source = "git+https://github.com/containers/oci-spec-rs?rev=6df620e#6df620e6d372fe080322f2a4b5e164f11f209bb0"
dependencies = [
"derive_builder 0.10.2",
"getset",
"serde",
"serde_json",
"thiserror",
]
[[package]]
name = "oci-spec"
version = "0.5.5"
source = "git+https://github.com/containers/oci-spec-rs?rev=89376af#89376af909b308e7fa65189f8fccc7cd20468dd1"
dependencies = [
"derive_builder 0.11.2",
"derive_builder",
"getset",
"quickcheck",
"serde",
@ -1938,7 +1859,7 @@ name = "runtimetest"
version = "0.0.1"
dependencies = [
"nix",
"oci-spec 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
"oci-spec",
]
[[package]]
@ -2927,7 +2848,7 @@ dependencies = [
"liboci-cli",
"log",
"nix",
"oci-spec 0.5.5 (git+https://github.com/containers/oci-spec-rs?rev=89376af)",
"oci-spec",
"once_cell",
"pentacle",
"procfs",

View File

@ -25,7 +25,7 @@ nix = "0.24.1"
procfs = "0.12.0"
log = "0.4"
anyhow = "1.0"
oci-spec = { git = "https://github.com/containers/oci-spec-rs", rev = "89376af" }
oci-spec = { git = "https://github.com/containers/oci-spec-rs", rev = "6df620e" }
dbus = { version = "0.9.5", optional = true }
fixedbitset = "0.4.1"
serde = { version = "1.0", features = ["derive"] }
@ -35,7 +35,7 @@ errno = { version = "0.2.8", optional = true }
libc = { version = "0.2.125", optional = true }
[dev-dependencies]
oci-spec = { git = "https://github.com/containers/oci-spec-rs", rev = "89376af", features = ["proptests"] }
oci-spec = { git = "https://github.com/containers/oci-spec-rs", rev = "6df620e", features = ["proptests"] }
quickcheck = "1"
mockall = { version = "0.11.0", features = [] }
clap = "3.1.18"

View File

@ -17,6 +17,7 @@ const CGROUP_CPU_BURST: &str = "cpu.cfs_burst_us";
const CGROUP_CPU_RT_RUNTIME: &str = "cpu.rt_runtime_us";
const CGROUP_CPU_RT_PERIOD: &str = "cpu.rt_period_us";
const CGROUP_CPU_STAT: &str = "cpu.stat";
const CGROUP_CPU_IDLE: &str = "cpu.idle";
pub struct Cpu {}
@ -40,6 +41,7 @@ impl Controller for Cpu {
|| cpu.quota().is_some()
|| cpu.realtime_period().is_some()
|| cpu.realtime_runtime().is_some()
|| cpu.idle().is_some()
{
return Some(cpu);
}
@ -130,6 +132,10 @@ impl Cpu {
}
}
if let Some(idle) = cpu.idle() {
common::write_cgroup_file(root_path.join(CGROUP_CPU_IDLE), idle)?;
}
Ok(())
}
}
@ -209,6 +215,33 @@ mod tests {
assert_eq!(content, RUNTIME.to_string());
}
#[test]
fn test_set_cpu_idle() {
// arrange
const IDLE: i64 = 1;
const CPU: &str = "cpu";
if !Path::new(common::DEFAULT_CGROUP_ROOT)
.join(CPU)
.join(CGROUP_CPU_IDLE)
.exists()
{
// skip test_set_cpu_idle due to not found cpu.idle, maybe due to old kernel version
return;
}
let (tmp, max) = setup("test_set_cpu_idle", CGROUP_CPU_IDLE);
let cpu = LinuxCpuBuilder::default().idle(IDLE).build().unwrap();
// act
Cpu::apply(&tmp, &cpu).expect("apply cpu");
// assert
let content = fs::read_to_string(max)
.unwrap_or_else(|_| panic!("read {} file content", CGROUP_CPU_IDLE));
assert_eq!(content, IDLE.to_string());
}
#[test]
fn test_set_rt_period() {
// arrange

View File

@ -13,6 +13,7 @@ use super::controller::Controller;
const CGROUP_CPU_WEIGHT: &str = "cpu.weight";
const CGROUP_CPU_MAX: &str = "cpu.max";
const CGROUP_CPU_BURST: &str = "cpu.max.burst";
const CGROUP_CPU_IDLE: &str = "cpu.idle";
const UNRESTRICTED_QUOTA: &str = "max";
const MAX_CPU_WEIGHT: u64 = 10000;
@ -96,6 +97,10 @@ impl Cpu {
common::write_cgroup_file(path.join(CGROUP_CPU_BURST), burst)?;
}
if let Some(idle) = cpu.idle() {
common::write_cgroup_file(path.join(CGROUP_CPU_IDLE), idle)?;
}
Ok(())
}
@ -153,6 +158,33 @@ mod tests {
assert_eq!(content, 840.to_string());
}
#[test]
fn test_set_cpu_idle() {
// arrange
const IDLE: i64 = 1;
const CPU: &str = "cpu";
if !Path::new(common::DEFAULT_CGROUP_ROOT)
.join(CPU)
.join(CGROUP_CPU_IDLE)
.exists()
{
// skip test_set_cpu_idle due to not found cpu.idle, maybe due to old kernel version
return;
}
let (tmp, max) = setup("test_set_cpu_idle", CGROUP_CPU_IDLE);
let cpu = LinuxCpuBuilder::default().idle(IDLE).build().unwrap();
// act
Cpu::apply(&tmp, &cpu).expect("apply cpu");
// assert
let content = fs::read_to_string(max)
.unwrap_or_else(|_| panic!("read {} file content", CGROUP_CPU_IDLE));
assert_eq!(content, format!("{}", IDLE))
}
#[test]
fn test_set_positive_quota() {
// arrange

View File

@ -29,7 +29,7 @@ libc = "0.2.125"
log = "0.4"
mio = { version = "0.8.3", features = ["os-ext", "os-poll"] }
nix = "0.24.1"
oci-spec = { git = "https://github.com/containers/oci-spec-rs", rev = "89376af" }
oci-spec = { git = "https://github.com/containers/oci-spec-rs", rev = "6df620e" }
path-clean = "0.1.0"
procfs = "0.12.0"
prctl = "1.0.0"
@ -43,7 +43,7 @@ wasmer = { version = "2.2.0", optional = true }
wasmer-wasi = { version = "2.2.0", optional = true }
[dev-dependencies]
oci-spec = { git = "https://github.com/containers/oci-spec-rs", rev = "89376af", features = ["proptests"] }
oci-spec = { git = "https://github.com/containers/oci-spec-rs", rev = "6df620e", features = ["proptests"] }
quickcheck = "1"
serial_test = "0.6.0"
rand = "0.8.5"

View File

@ -25,7 +25,7 @@ libcontainer = { version = "0.0.3", path = "../libcontainer" }
liboci-cli = { version = "0.0.3", path = "../liboci-cli" }
log = { version = "0.4", features = ["std"]}
nix = "0.24.1"
oci-spec = { git = "https://github.com/containers/oci-spec-rs", rev = "89376af" }
oci-spec = { git = "https://github.com/containers/oci-spec-rs", rev = "6df620e" }
once_cell = "1.10.0"
pentacle = "1.0.0"
procfs = "0.12.0"

View File

@ -12,7 +12,7 @@ libcontainer = { path = "../../../crates/libcontainer" }
log = { version = "0.4", features = ["std"] }
nix = "0.24.1"
num_cpus = "1.13"
oci-spec = "0.5.5"
oci-spec = { git = "https://github.com/containers/oci-spec-rs", rev = "6df620e" }
once_cell = "1.10.0"
pnet = "0.29.0"
procfs = "0.12.0"

View File

@ -12,6 +12,7 @@ fn create_cpu_spec(
shares: u64,
quota: i64,
period: u64,
idle_opt: Option<i64>,
cpus: &str,
mems: &str,
realtime_period_opt: Option<u64>,
@ -24,6 +25,10 @@ fn create_cpu_spec(
.cpus(cpus)
.mems(mems);
if let Some(idle) = idle_opt {
builder = builder.idle(idle);
}
if let Some(realtime_period) = realtime_period_opt {
builder = builder.realtime_period(realtime_period);
}

View File

@ -1,5 +1,6 @@
use std::path::Path;
use libcgroups::common;
use num_cpus;
use test_framework::{test_result, ConditionalTest, TestGroup, TestResult};
@ -44,6 +45,7 @@ fn test_cpu_cgroups() -> TestResult {
1024,
100000,
50000,
None,
"0",
"0",
realtime_period,
@ -53,6 +55,7 @@ fn test_cpu_cgroups() -> TestResult {
1024,
100000,
50000,
None,
&cpu_range,
"0",
realtime_period,
@ -62,6 +65,7 @@ fn test_cpu_cgroups() -> TestResult {
1024,
100000,
200000,
None,
"0",
"0",
realtime_period,
@ -71,6 +75,7 @@ fn test_cpu_cgroups() -> TestResult {
1024,
100000,
200000,
None,
&cpu_range,
"0",
realtime_period,
@ -80,6 +85,7 @@ fn test_cpu_cgroups() -> TestResult {
1024,
500000,
50000,
None,
"0",
"0",
realtime_period,
@ -89,6 +95,7 @@ fn test_cpu_cgroups() -> TestResult {
1024,
500000,
50000,
None,
&cpu_range,
"0",
realtime_period,
@ -98,6 +105,7 @@ fn test_cpu_cgroups() -> TestResult {
1024,
500000,
200000,
None,
"0",
"0",
realtime_period,
@ -107,6 +115,7 @@ fn test_cpu_cgroups() -> TestResult {
1024,
500000,
200000,
None,
&cpu_range,
"0",
realtime_period,
@ -116,6 +125,7 @@ fn test_cpu_cgroups() -> TestResult {
2048,
100000,
50000,
None,
"0",
"0",
realtime_period,
@ -125,6 +135,7 @@ fn test_cpu_cgroups() -> TestResult {
2048,
100000,
50000,
None,
&cpu_range,
"0",
realtime_period,
@ -134,6 +145,7 @@ fn test_cpu_cgroups() -> TestResult {
2048,
100000,
200000,
None,
"0",
"0",
realtime_period,
@ -143,6 +155,7 @@ fn test_cpu_cgroups() -> TestResult {
2048,
100000,
200000,
None,
&cpu_range,
"0",
realtime_period,
@ -152,6 +165,7 @@ fn test_cpu_cgroups() -> TestResult {
2048,
500000,
50000,
None,
"0",
"0",
realtime_period,
@ -161,6 +175,7 @@ fn test_cpu_cgroups() -> TestResult {
2048,
500000,
50000,
None,
&cpu_range,
"0",
realtime_period,
@ -170,6 +185,7 @@ fn test_cpu_cgroups() -> TestResult {
2048,
500000,
200000,
None,
"0",
"0",
realtime_period,
@ -179,6 +195,7 @@ fn test_cpu_cgroups() -> TestResult {
2048,
500000,
200000,
None,
&cpu_range,
"0",
realtime_period,
@ -212,10 +229,69 @@ fn test_empty_cpu() -> TestResult {
})
}
// Tests if a cpu idle value can be set
fn test_cpu_idle_set() -> TestResult {
let idle: i64 = 1;
let realtime_period = get_realtime_period();
let realtime_runtime = get_realtime_runtime();
let cgroup_name = "test_cpu_idle_set";
let cpu = test_result!(create_cpu_spec(
2048,
500000,
200000,
Some(idle),
"0",
"0",
realtime_period,
realtime_runtime,
));
let spec = test_result!(create_spec(cgroup_name, cpu));
test_outside_container(spec, &|data| {
test_result!(check_container_created(&data));
TestResult::Passed
})
}
/// Tests default idle value
fn test_cpu_idle_default() -> TestResult {
let realtime_period = get_realtime_period();
let realtime_runtime = get_realtime_runtime();
let cgroup_name = "test_cpu_idle_default";
let cpu = test_result!(create_cpu_spec(
2048,
500000,
200000,
None,
"0",
"0",
realtime_period,
realtime_runtime,
));
let spec = test_result!(create_spec(cgroup_name, cpu));
test_outside_container(spec, &|data| {
test_result!(check_container_created(&data));
TestResult::Passed
})
}
fn can_run() -> bool {
Path::new(CPU_CGROUP_PREFIX).exists()
}
fn can_run_idle() -> bool {
const CPU: &str = "cpu";
const CGROUP_CPU_IDLE: &str = "cpu.idle";
let idle_path = Path::new(common::DEFAULT_CGROUP_ROOT)
.join(CPU)
.join(CGROUP_CPU_IDLE);
can_run() && idle_path.exists()
}
pub fn get_test_group<'a>() -> TestGroup<'a> {
let mut test_group = TestGroup::new("cgroup_v1_cpu");
let linux_cgroups_cpus = ConditionalTest::new(
@ -230,7 +306,24 @@ pub fn get_test_group<'a>() -> TestGroup<'a> {
Box::new(test_empty_cpu),
);
test_group.add(vec![Box::new(linux_cgroups_cpus), Box::new(empty_cpu)]);
let cpu_idle_default = ConditionalTest::new(
"test_cpu_idle_default",
Box::new(can_run_idle),
Box::new(test_cpu_idle_default),
);
let cpu_idle_set = ConditionalTest::new(
"test_cpu_idle_set",
Box::new(can_run_idle),
Box::new(test_cpu_idle_set),
);
test_group.add(vec![
Box::new(linux_cgroups_cpus),
Box::new(empty_cpu),
Box::new(cpu_idle_set),
Box::new(cpu_idle_default),
]);
test_group
}

View File

@ -23,6 +23,8 @@ use test_framework::{assert_result_eq, test_result, ConditionalTest, TestGroup,
use super::create_spec;
const DEFAULT_PERIOD: u64 = 100_000;
const CPU: &str = "cpu";
const CGROUP_CPU_IDLE: &str = "cpu.idle";
// SPEC: The runtime spec does not specify what should happen if the cpu weight is outside
// of the valid range of values [1, 10000]. We assume that a value of zero means that no action
@ -32,6 +34,35 @@ const DEFAULT_PERIOD: u64 = 100_000;
// We assume that a negative value means that it should be set to the default value and zero means
// that it should be unchanged.
/// Tests if a cpu idle value is successfully set
fn test_cpu_idle_set() -> TestResult {
let idle: i64 = 1;
let cpu = test_result!(LinuxCpuBuilder::default()
.idle(idle)
.build()
.context("build cpu spec"));
let spec = test_result!(create_spec("test_cpu_idle_set", cpu));
test_outside_container(spec, &|data| {
test_result!(check_container_created(&data));
test_result!(check_cpu_idle("test_cpu_idle_set", idle));
TestResult::Passed
})
}
/// Tests default idle value is correct
fn test_cpu_idle_default() -> TestResult {
let default_idle = 0;
let cpu = test_result!(LinuxCpuBuilder::default().build().context("build cpu spec"));
let spec = test_result!(create_spec("test_cpu_idle_default", cpu));
test_outside_container(spec, &|data| {
test_result!(check_container_created(&data));
test_result!(check_cpu_idle("test_cpu_idle_default", default_idle));
TestResult::Passed
})
}
/// Tests if a cpu weight that is in the valid range [1, 10000] is successfully set
fn test_cpu_weight_valid_set() -> TestResult {
let cpu_weight = 22_000u64;
@ -239,6 +270,15 @@ fn check_cpu_weight(cgroup_name: &str, expected_weight: u64) -> Result<()> {
assert_result_eq!(actual_weight, expected_weight, "unexpected cpu weight")
}
fn check_cpu_idle(cgroup_name: &str, expected_value: i64) -> Result<()> {
let data = read_cgroup_data(cgroup_name, "cpu.idle")?;
assert_result_eq!(
data.parse::<i64>()
.with_context(|| format!("failed to parse {:?}", data))?,
expected_value
)
}
fn check_cpu_max(cgroup_name: &str, expected_quota: i64, expected_period: u64) -> Result<()> {
let data = read_cgroup_data(cgroup_name, "cpu.max")?;
let parts: Vec<&str> = data.split_whitespace().collect();
@ -336,6 +376,13 @@ fn can_run() -> bool {
true
}
fn can_run_idle() -> bool {
let idle_path = Path::new(common::DEFAULT_CGROUP_ROOT)
.join(CPU)
.join(CGROUP_CPU_IDLE);
can_run() && idle_path.exists()
}
pub fn get_test_group<'a>() -> TestGroup<'a> {
let mut test_group = TestGroup::new("cgroup_v2_cpu");
let test_cpu_weight_valid_set = ConditionalTest::new(
@ -392,6 +439,18 @@ pub fn get_test_group<'a>() -> TestGroup<'a> {
Box::new(test_cpu_period_and_quota_valid_set),
);
let test_cpu_idle_set = ConditionalTest::new(
"test_cpu_idle_set",
Box::new(can_run_idle),
Box::new(test_cpu_idle_set),
);
let test_cpu_idle_default = ConditionalTest::new(
"test_cpu_idle_default",
Box::new(can_run_idle),
Box::new(test_cpu_idle_default),
);
test_group.add(vec![
Box::new(test_cpu_weight_valid_set),
Box::new(test_cpu_weight_zero_ignored),
@ -402,6 +461,8 @@ pub fn get_test_group<'a>() -> TestGroup<'a> {
Box::new(test_cpu_period_valid_set),
Box::new(test_cpu_period_unspecified_unchanged),
Box::new(test_cpu_period_and_quota_valid_set),
Box::new(test_cpu_idle_set),
Box::new(test_cpu_idle_default),
]);
test_group
}

View File

@ -4,5 +4,5 @@ version = "0.0.1"
edition = "2021"
[dependencies]
oci-spec = "0.5.5"
oci-spec = { git = "https://github.com/containers/oci-spec-rs", rev = "6df620e" }
nix = "0.24.1"