diff --git a/src/cpu.rs b/src/cpu.rs index 4c8d5c3..9cf90e1 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -1,17 +1,30 @@ -/* CPU controller */ +//! This module contains the implementation of the `cpu` cgroup subsystem. +//! +//! See the Kernel's documentation for more information about this subsystem, found at: +//! [Documentation/scheduler/sched-design-CFS.txt](https://www.kernel.org/doc/Documentation/scheduler/sched-design-CFS.txt) +//! paragraph 7 ("GROUP SCHEDULER EXTENSIONS TO CFS"). use std::path::PathBuf; use std::io::{Read, Write}; use {CpuResources, Controllers, Controller, Resources, ControllIdentifier, Subsystem}; +/// A controller that allows controlling the `cpu` subsystem of a Cgroup. +/// +/// In essence, it allows gathering information about how much the tasks inside the control group +/// are using the CPU and creating rules that limit their usage. Note that this crate does not yet +/// support managing realtime tasks. #[derive(Debug, Clone)] pub struct CpuController{ base: PathBuf, path: PathBuf, } +/// The current state of the control group and its processes. #[derive(Debug)] pub struct Cpu { + /// Reports CPU time statistics. + /// + /// Corresponds the `cpu.stat` file in `cpu` control group. pub stat: String, } @@ -56,6 +69,7 @@ impl<'a> From<&'a Subsystem> for &'a CpuController { } impl CpuController { + /// Contructs a new `CpuController` with `oroot` serving as the root of the control group. pub fn new(oroot: PathBuf) -> Self { let mut root = oroot; root.push(Self::controller_type().to_string()); @@ -64,6 +78,8 @@ impl CpuController { path: root, } } + + /// Returns CPU time statistics based on the processes in the control group. pub fn cpu(self: &Self) -> Cpu { Cpu { stat: self.open_path("cpu.stat", false).and_then(|mut file| { @@ -74,18 +90,28 @@ impl CpuController { } } + /// Configures the CPU bandwidth (in relative relation to other control groups and this control + /// group's parent). + /// + /// For example, setting control group `A`'s `shares` to `100`, and control group `B`'s + /// `shares` to `200` ensures that control group `B` receives twice as much as CPU bandwidth. + /// (Assuming both `A` and `B` are of the same parent) pub fn set_shares(self: &Self, shares: u64) { self.open_path("cpu.shares", true).and_then(|mut file| { file.write_all(shares.to_string().as_ref()).ok() }); } + /// Specify a period (when using the CFS scheduler) of time in microseconds for how often this + /// control group's access to the CPU should be reallocated. pub fn set_cfs_period(self: &Self, us: u64) { self.open_path("cpu.cfs_period_us", true).and_then(|mut file| { file.write_all(us.to_string().as_ref()).ok() }); } + /// Specify a quota (when using the CFS scheduler) of time in microseconds for which all tasks + /// in this control group can run during one period (see: `set_cfs_period()`). pub fn set_cfs_quota(self: &Self, us: u64) { self.open_path("cpu.cfs_quota_us", true).and_then(|mut file| { file.write_all(us.to_string().as_ref()).ok() diff --git a/src/cpuacct.rs b/src/cpuacct.rs index b91820a..c11506e 100644 --- a/src/cpuacct.rs +++ b/src/cpuacct.rs @@ -1,24 +1,51 @@ -/* cpuacct controller */ +//! This module contains the implementation of the `cpuacct` cgroup subsystem. +//! +//! See the Kernel's documentation for more information about this subsystem, found at: +//! [Documentation/cgroup-v1/cpuacct.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/cpuacct.txt) use std::path::PathBuf; use std::io::{Read, Write}; use std::fs::File; use {Controllers, Resources, Subsystem, ControllIdentifier, Controller}; +/// A controller that allows controlling the `cpuacct` subsystem of a Cgroup. +/// +/// In essence, this control group provides accounting (hence the name `cpuacct`) for CPU usage of +/// the tasks in the control group. #[derive(Debug, Clone)] pub struct CpuAcctController { base: PathBuf, path: PathBuf, } +/// Represents the statistics retrieved from the control group. pub struct CpuAcct { + /// Divides the time used by the tasks into `user` time and `system` time. pub stat: String, + /// Total CPU time (in nanoseconds) spent by the tasks. pub usage: u64, + /// Total CPU time (in nanoseconds) spent by the tasks, broken down by CPU and by whether the + /// time spent is `user` time or `system` time. + /// + /// An example is as follows: + /// ``` + /// cpu user system + /// 0 8348363768 0 + /// 1 8324369100 0 + /// 2 8598185449 0 + /// 3 8648262473 0 + /// ``` pub usage_all: String, + /// CPU time (in nanoseconds) spent by the tasks, broken down by each CPU. + /// Times spent in each CPU are separated by a space. pub usage_percpu: String, + /// As for `usage_percpu`, but the `system` time spent. pub usage_percpu_sys: String, + /// As for `usage_percpu`, but the `user` time spent. pub usage_percpu_user: String, + /// CPU time (in nanoseconds) spent by the tasks that counted for `system` time. pub usage_sys: u64, + /// CPU time (in nanoseconds) spent by the tasks that counted for `user` time. pub usage_user: u64, } @@ -59,6 +86,8 @@ fn read_u64_from(mut file: File) -> Option { } impl CpuAcctController { + + /// Contructs a new `CpuAcctController` with `oroot` serving as the root of the control group. pub fn new(oroot: PathBuf) -> Self { let mut root = oroot; root.push(Self::controller_type().to_string()); @@ -67,6 +96,8 @@ impl CpuAcctController { path: root, } } + + /// Gathers the statistics that are available in the control group into a `CpuAcct` structure. pub fn cpuacct(self: &Self) -> CpuAcct { CpuAcct { stat: self.open_path("cpuacct.stat", false) @@ -110,6 +141,8 @@ impl CpuAcctController { .unwrap_or(0), } } + + /// Reset the statistics the kernel has gathered about the control group. pub fn reset(self: &Self) { self.open_path("cpuacct.usage", true).and_then(|mut file| { file.write_all(b"0").ok() diff --git a/src/cpuset.rs b/src/cpuset.rs index c58e71f..b96e11f 100644 --- a/src/cpuset.rs +++ b/src/cpuset.rs @@ -1,30 +1,73 @@ -/* cpuset controller */ +//! This module contains the implementation of the `cpuset` cgroup subsystem. +//! +//! See the Kernel's documentation for more information about this subsystem, found at: +//! [Documentation/cgroup-v1/cpusets.txt](https://www.kernel.org/doc/Documentation/cgroup-v1/cpusets.txt) use std::path::PathBuf; use std::io::{Read, Write}; use std::fs::File; use {CpuResources, Resources, Controller, ControllIdentifier, Subsystem, Controllers}; +/// A controller that allows controlling the `cpuset` subsystem of a Cgroup. +/// +/// In essence, this controller is responsible for restricting the tasks in the control group to a +/// set of CPUs and/or memory nodes. #[derive(Debug, Clone)] pub struct CpuSetController { base: PathBuf, path: PathBuf, } +/// The current state of the `cpuset` controller for this control group. pub struct CpuSet { + /// If true, no other control groups can share the CPUs listed in the `cpus` field. pub cpu_exclusive: bool, + /// The list of CPUs the tasks of the control group can run on. This is a comma-separated list + /// with dashes between numbers representing ranges. pub cpus: String, + /// The list of CPUs that the tasks can effectively run on. This removes the list of CPUs that + /// the parent (and all of its parents) cannot run on from the `cpus` field of this control + /// group. pub effective_cpus: String, + /// The list of memory nodes that the tasks can effectively use. This removes the list of nodes that + /// the parent (and all of its parents) cannot use from the `mems` field of this control + /// group. pub effective_mems: String, + /// If true, no other control groups can share the memory nodes listed in the `mems` field. pub mem_exclusive: bool, + /// If true, the control group is 'hardwalled'. Kernel memory allocations (except for a few + /// minor exceptions) are made from the memory nodes designated in the `mems` field. pub mem_hardwall: bool, + /// If true, whenever `mems` is changed via `set_mems()`, the memory stored on the previous + /// nodes are migrated to the new nodes selected by the new `mems`. pub memory_migrate: bool, + /// Running average of the memory pressured faced by the tasks in the control group. pub memory_pressure: u64, + /// This field is only at the root control group and controls whether the kernel will compute + /// the memory pressure for control groups or not. pub memory_pressure_enabled: Option, + /// If true, filesystem buffers are spread across evenly between the nodes specified in `mems`. pub memory_spread_page: bool, + /// If true, kernel slab caches for file I/O are spread across evenly between the nodes + /// specified in `mems`. pub memory_spread_slab: bool, + /// The list of memory nodes the tasks of the control group can use. This is a comma-separated list + /// with dashes between numbers representing ranges. pub mems: String, + /// If true, the kernel will attempt to rebalance the load between the CPUs specified in the + /// `cpus` field of this control group. pub sched_load_balance: bool, + /// Represents how much work the kernel should do to rebalance this cpuset. + /// + /// | `sched_load_balance` | Effect | + /// | -------------------- | ------ | + /// | -1 | Use the system default value | + /// | 0 | Only balance loads periodically | + /// | 1 | Immediately balance the load across tasks on the same core | + /// | 2 | Immediately balance the load across cores in the same CPU package | + /// | 4 | Immediately balance the load across CPUs on the same node | + /// | 5 | Immediately balance the load between CPUs even if the system is NUMA | + /// | 6 | Immediately balance the load between all CPUs | pub sched_relax_domain_level: u64, } @@ -74,6 +117,7 @@ fn read_u64_from(mut file: File) -> Option { } impl CpuSetController { + /// Contructs a new `CpuSetController` with `oroot` serving as the root of the control group. pub fn new(oroot: PathBuf) -> Self { let mut root = oroot; root.push(Self::controller_type().to_string()); @@ -83,6 +127,8 @@ impl CpuSetController { } } + /// Returns the statistics gathered by the kernel for this control group. See the struct for + /// more information on what information this entails. pub fn cpuset(self: &Self) -> CpuSet { CpuSet { cpu_exclusive: { @@ -166,6 +212,8 @@ impl CpuSetController { } } + /// Control whether the CPUs selected via `set_cpus()` should be exclusive to this control + /// group or not. pub fn set_cpu_exclusive(self: &Self, b: bool) { self.open_path("cpuset.cpu_exclusive", true).and_then(|mut file| { if b { @@ -176,6 +224,8 @@ impl CpuSetController { }); } + /// Control whether the memory nodes selected via `set_memss()` should be exclusive to this control + /// group or not. pub fn set_mem_exclusive(self: &Self, b: bool) { self.open_path("cpuset.mem_exclusive", true).and_then(|mut file| { if b { @@ -186,18 +236,30 @@ impl CpuSetController { }); } + /// Set the CPUs that the tasks in this control group can run on. + /// + /// Syntax is a comma separated list of CPUs, with an additional extension that ranges can + /// be represented via dashes. pub fn set_cpus(self: &Self, cpus: &String) { self.open_path("cpuset.cpus", true).and_then(|mut file| { file.write_all(cpus.as_ref()).ok() }); } + /// Set the memory nodes that the tasks in this control group can use. + /// + /// Syntax is the same as with `set_cpus()`. pub fn set_mems(self: &Self, mems: &String) { self.open_path("cpuset.mems", true).and_then(|mut file| { file.write_all(mems.as_ref()).ok() }); } + /// Controls whether the control group should be "hardwalled", i.e., whether kernel allocations + /// should exclusively use the memory nodes set via `set_mems()`. + /// + /// Note that some kernel allocations, most notably those that are made in interrupt handlers + /// may disregard this. pub fn set_hardwall(self: &Self, b: bool) { self.open_path("cpuset.mem_hardwall", true).and_then(|mut file| { if b { @@ -208,6 +270,8 @@ impl CpuSetController { }); } + /// Controls whether the kernel should attempt to rebalance the load between the CPUs specified in the + /// `cpus` field of this control group. pub fn set_load_balancing(self: &Self, b: bool) { self.open_path("cpuset.sched_load_balance", true).and_then(|mut file| { if b { @@ -218,12 +282,17 @@ impl CpuSetController { }); } + /// Contorl how much effort the kernel should invest in rebalacing the control group. + /// + /// See @CpuSet 's similar field for more information. pub fn set_rebalance_relax_domain_level(self: &Self, i: i64) { self.open_path("cpuset.sched_relax_domain_level", true).and_then(|mut file| { file.write_all(i.to_string().as_ref()).ok() }); } + /// Control whether when using `set_mems()` the existing memory used by the tasks should be + /// migrated over to the now-selected nodes. pub fn set_memory_migration(self: &Self, b: bool) { self.open_path("cpuset.memory_migrate", true).and_then(|mut file| { if b { @@ -234,6 +303,8 @@ impl CpuSetController { }); } + /// Control whether filesystem buffers should be evenly split across the nodes selected via + /// `set_mems()`. pub fn set_memory_spread_page(self: &Self, b: bool) { self.open_path("cpuset.memory_spread_page", true).and_then(|mut file| { if b { @@ -244,6 +315,8 @@ impl CpuSetController { }); } + /// Control whether the kernel's slab cache for file I/O should be evenly split across the + /// nodes selected via `set_mems()`. pub fn set_memory_spread_slab(self: &Self, b: bool) { self.open_path("cpuset.memory_spread_slab", true).and_then(|mut file| { if b { @@ -254,6 +327,11 @@ impl CpuSetController { }); } + /// Control whether the kernel should collect information to calculate memory pressure for + /// control groups. + /// + /// Note: This is a no-operation if the control group referred by `self` is not the root + /// control group. pub fn set_enable_memory_pressure(self: &Self, b: bool) { /* XXX: this file should only be present in the root cpuset cg */ self.open_path("cpuset.memory_pressure_enabled", true).and_then(|mut file| {