Skip to content

Commit

Permalink
Merge pull request #171 from Furisto/events
Browse files Browse the repository at this point in the history
Implement events command for cgroup v1 stats
  • Loading branch information
utam0k authored Jul 31, 2021
2 parents 429ab0e + 7087b44 commit 62a1121
Show file tree
Hide file tree
Showing 16 changed files with 1,190 additions and 43 deletions.
10 changes: 10 additions & 0 deletions src/cgroups/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ fn booted() -> Result<bool> {
use crate::cgroups::v1;
use crate::cgroups::v2;

use super::stats::Stats;

pub const CGROUP_PROCS: &str = "cgroup.procs";
pub const DEFAULT_CGROUP_ROOT: &str = "/sys/fs/cgroup";

Expand All @@ -32,6 +34,8 @@ pub trait CgroupManager {
fn remove(&self) -> Result<()>;
// Sets the freezer cgroup to the specified state
fn freeze(&self, state: FreezerState) -> Result<()>;
/// Retrieve statistics for the cgroup
fn stats(&self) -> Result<Stats>;
}

#[derive(Debug)]
Expand Down Expand Up @@ -79,6 +83,12 @@ pub fn write_cgroup_file<P: AsRef<Path>, T: ToString>(path: P, data: T) -> Resul
Ok(())
}

#[inline]
pub fn read_cgroup_file<P: AsRef<Path>>(path: P) -> Result<String> {
let path = path.as_ref();
fs::read_to_string(path).with_context(|| format!("failed to open {:?}", path))
}

pub fn get_supported_cgroup_fs() -> Result<Vec<Cgroup>> {
let cgroup_mount = Process::myself()?
.mountinfo()?
Expand Down
1 change: 1 addition & 0 deletions src/cgroups/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//! freezing, checkpointing and restarting groups of processes.

pub mod common;
pub mod stats;
mod test;
pub mod v1;
pub mod v2;
263 changes: 263 additions & 0 deletions src/cgroups/stats.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,263 @@
use anyhow::Result;
use std::{collections::HashMap, fmt::Display, path::Path};

pub trait StatsProvider {
type Stats;

fn stats(cgroup_path: &Path) -> Result<Self::Stats>;
}

/// Reports the statistics for a cgroup
#[derive(Debug)]
pub struct Stats {
/// Cpu statistics for the cgroup
pub cpu: CpuStats,
/// Pid statistics for the cgroup
pub pids: PidStats,
/// Hugetlb statistics for the cgroup
pub hugetlb: HashMap<String, HugeTlbStats>,
/// Blkio statistics for the cgroup
pub blkio: BlkioStats,
/// Memory statistics for the cgroup
pub memory: MemoryStats,
}

impl Default for Stats {
fn default() -> Self {
Self {
cpu: CpuStats::default(),
pids: PidStats::default(),
hugetlb: HashMap::new(),
blkio: BlkioStats::default(),
memory: MemoryStats::default(),
}
}
}

/// Reports the cpu statistics for a cgroup
#[derive(Debug)]
pub struct CpuStats {
/// Cpu usage statistics for the cgroup
pub usage: CpuUsage,
/// Cpu Throttling statistics for the cgroup
pub throttling: CpuThrottling,
}

impl Default for CpuStats {
fn default() -> Self {
Self {
usage: CpuUsage::default(),
throttling: CpuThrottling::default(),
}
}
}

/// Reports the cpu usage for a cgroup
#[derive(Debug, PartialEq, Eq)]
pub struct CpuUsage {
/// Cpu time consumed by tasks in total
pub usage_total: u64,
/// Cpu time consumed by tasks in user mode
pub usage_user: u64,
/// Cpu time consumed by tasks in kernel mode
pub usage_kernel: u64,
/// Cpu time consumed by tasks itemized per core
pub per_core_usage_total: Vec<u64>,
/// Cpu time consumed by tasks in user mode itemized per core
pub per_core_usage_user: Vec<u64>,
/// Cpu time consumed by tasks in kernel mode itemized per core
pub per_core_usage_kernel: Vec<u64>,
}

impl Default for CpuUsage {
fn default() -> Self {
Self {
usage_total: 0,
usage_user: 0,
usage_kernel: 0,
per_core_usage_total: Vec::new(),
per_core_usage_user: Vec::new(),
per_core_usage_kernel: Vec::new(),
}
}
}

/// Reports the cpu throttling for a cgroup
#[derive(Debug, PartialEq, Eq)]
pub struct CpuThrottling {
/// Number of period intervals (as specified in cpu.cfs_period_us) that have elapsed
pub periods: u64,
/// Number of period intervals where tasks have been throttled because they exhausted their quota
pub throttled_periods: u64,
/// Total time duration for which tasks have been throttled
pub throttled_time: u64,
}

impl Default for CpuThrottling {
fn default() -> Self {
Self {
periods: 0,
throttled_periods: 0,
throttled_time: 0,
}
}
}

/// Reports memory stats for a cgroup
#[derive(Debug)]
pub struct MemoryStats {
/// Usage of memory
pub memory: MemoryData,
/// Usage of memory and swap
pub memswap: MemoryData,
/// Usage of kernel memory
pub kernel: MemoryData,
/// Usage of kernel tcp memory
pub kernel_tcp: MemoryData,
/// Page cache in bytes
pub cache: u64,
/// Returns true if hierarchical accounting is enabled
pub hierarchy: bool,
/// Various memory statistics
pub stats: HashMap<String, u64>,
}

impl Default for MemoryStats {
fn default() -> Self {
Self {
memory: MemoryData::default(),
memswap: MemoryData::default(),
kernel: MemoryData::default(),
kernel_tcp: MemoryData::default(),
cache: 0,
hierarchy: false,
stats: HashMap::default(),
}
}
}

/// Reports memory stats for one type of memory
#[derive(Debug, PartialEq, Eq)]
pub struct MemoryData {
/// Usage in bytes
pub usage: u64,
/// Maximum recorded usage in bytes
pub max_usage: u64,
/// Number of times memory usage hit limits
pub fail_count: u64,
/// Memory usage limit
pub limit: u64,
}

impl Default for MemoryData {
fn default() -> Self {
Self {
usage: 0,
max_usage: 0,
fail_count: 0,
limit: 0,
}
}
}

/// Reports pid stats for a cgroup
#[derive(Debug, PartialEq, Eq)]
pub struct PidStats {
/// Current number of active pids
pub current: u64,
/// Allowed number of active pids (0 means no limit)
pub limit: u64,
}

impl Default for PidStats {
fn default() -> Self {
Self {
current: 0,
limit: 0,
}
}
}

/// Reports block io stats for a cgroup
#[derive(Debug, PartialEq, Eq)]
pub struct BlkioStats {
// Number of bytes transfered to/from a device by the cgroup
pub service_bytes: Vec<BlkioDeviceStat>,
// Number of I/O operations performed on a device by the cgroup
pub serviced: Vec<BlkioDeviceStat>,
// Time in milliseconds that the cgroup had access to a device
pub time: Vec<BlkioDeviceStat>,
// Number of sectors transferred to/from a device by the cgroup
pub sectors: Vec<BlkioDeviceStat>,
// Total time between request dispatch and request completion
pub service_time: Vec<BlkioDeviceStat>,
// Total time spend waiting in the scheduler queues for service
pub wait_time: Vec<BlkioDeviceStat>,
// Number of requests queued for I/O operations
pub queued: Vec<BlkioDeviceStat>,
// Number of requests merged into requests for I/O operations
pub merged: Vec<BlkioDeviceStat>,
}

impl Default for BlkioStats {
fn default() -> Self {
Self {
service_bytes: Vec::new(),
serviced: Vec::new(),
time: Vec::new(),
sectors: Vec::new(),
service_time: Vec::new(),
wait_time: Vec::new(),
queued: Vec::new(),
merged: Vec::new(),
}
}
}

/// Reports single stat value for a specific device
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct BlkioDeviceStat {
/// Major device number
pub major: u64,
/// Minor device number
pub minor: u64,
/// Operation type
pub op_type: Option<String>,
/// Stat value
pub value: u64,
}

impl Display for BlkioDeviceStat {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
if let Some(op_type) = &self.op_type {
write!(
f,
"{}:{} {} {}",
self.major, self.minor, op_type, self.value
)
} else {
write!(f, "{}:{} {}", self.major, self.minor, self.value)
}
}
}

/// Reports hugetlb stats for a cgroup
#[derive(Debug, PartialEq, Eq)]
pub struct HugeTlbStats {
/// Current usage in bytes
pub usage: u64,
/// Maximum recorded usage in bytes
pub max_usage: u64,
/// Number of allocation failures due to HugeTlb usage limit
pub fail_count: u64,
}

impl Default for HugeTlbStats {
fn default() -> Self {
Self {
usage: 0,
max_usage: 0,
fail_count: 0,
}
}
}
8 changes: 5 additions & 3 deletions src/cgroups/test.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
#![cfg(test)]

use anyhow::Result;
use anyhow::{Context, Result};
use std::{
io::Write,
path::{Path, PathBuf},
Expand All @@ -25,8 +25,10 @@ pub fn set_fixture(temp_dir: &Path, filename: &str, val: &str) -> Result<PathBuf
.create(true)
.write(true)
.truncate(true)
.open(&full_path)?
.write_all(val.as_bytes())?;
.open(&full_path)
.with_context(|| format!("failed to open {:?}", full_path))?
.write_all(val.as_bytes())
.with_context(|| format!("failed to write to {:?}", full_path))?;

Ok(full_path)
}
Expand Down
Loading

0 comments on commit 62a1121

Please sign in to comment.