From cf323946a559e12011d6cf4a967a33200af7c5b4 Mon Sep 17 00:00:00 2001 From: Vlad Pronsky Date: Tue, 17 Dec 2024 12:44:51 +0200 Subject: [PATCH] feat: ram power & limit samples count in pipe command --- .github/workflows/release.yml | 1 + Cargo.lock | 2 +- Cargo.toml | 2 +- readme.md | 47 ++++++++++++++++++++++++++++++++++- src/main.rs | 17 ++++++++++--- src/metrics.rs | 14 ++++++++--- 6 files changed, 73 insertions(+), 10 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index aebbd2c..bca4849 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -39,6 +39,7 @@ jobs: - uses: softprops/action-gh-release@v2 with: files: macmon-${{ github.ref_name }}.tar.gz + generate_release_notes: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Cargo.lock b/Cargo.lock index 48169af..e16228c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -321,7 +321,7 @@ dependencies = [ [[package]] name = "macmon" -version = "0.4.1" +version = "0.4.2" dependencies = [ "clap", "core-foundation", diff --git a/Cargo.toml b/Cargo.toml index 55b5ec5..8a01b05 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "macmon" -version = "0.4.1" +version = "0.4.2" edition = "2021" [lints.rust] diff --git a/readme.md b/readme.md index d03c6f0..31ea2c2 100644 --- a/readme.md +++ b/readme.md @@ -67,7 +67,7 @@ sudo cp target/release/macmon /usr/local/bin Usage: macmon [OPTIONS] [COMMAND] Commands: - raw Print metrics in JSON format – can be used for piping + pipe Output metrics in JSON format debug Print debug information help Print this message or the help of the given subcommand(s) @@ -82,6 +82,51 @@ Controls: q - quit ``` +## Piping + +You can use the pipe subcommand to output metrics in JSON format, which is suitable for piping into other tools or scripts. For example: + +```sh +macmon pipe | jq +``` + +This command runs `macmon` in "pipe" mode and navigate output to `jq` for pretty-printing. + +You can also specify the number of samples to run using `-s` or `--samples` parameter (default: `0`, which runs indefinitely), and set update interval in milliseconds using the `-i` or `--interval` parameter (default: `1000` ms). For example: + +```sh +macmon pipe -s 10 -i 500 | jq +``` + +This will collect 10 samples with an update interval of 500 milliseconds. + +### Output + +```json +{ + "temp": { + "cpu_temp_avg": 43.73614, // Celsius + "gpu_temp_avg": 36.95167 // Celsius + }, + "memory": { + "ram_total": 25769803776, // Bytes + "ram_usage": 20985479168, // Bytes + "swap_total": 4294967296, // Bytes + "swap_usage": 2602434560 // Bytes + }, + "ecpu_usage": [1181, 0.082656614], // (Frequency MHz, Usage %) + "pcpu_usage": [1974, 0.015181795], // (Frequency MHz, Usage %) + "gpu_usage": [461, 0.021497859], // (Frequency MHz, Usage %) + "cpu_power": 0.20486385, // Watts + "gpu_power": 0.017451683, // Watts + "ane_power": 0.0, // Watts + "all_power": 0.22231553, // Watts + "sys_power": 5.876533, // Watts + "ram_power": 0.11635789, // Watts + "gpu_ram_power": 0.0009615385 // Watts +} +``` + ## 🤝 Contributing We love contributions! Whether you have ideas, suggestions, or bug reports, feel free to open an issue or submit a pull request. Your input is essential in helping us improve `macmon` 💪 diff --git a/src/main.rs b/src/main.rs index 18c663f..5fd5b15 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,8 +11,13 @@ use std::error::Error; #[derive(Debug, Subcommand)] enum Commands { - /// Print metrics in JSON format – can be used for piping - Raw, + /// Output metrics in JSON format (suitable for piping) + #[command(alias = "raw")] + Pipe { + /// Number of samples to run for. Set to 0 to run indefinitely + #[arg(short, long, default_value_t = 0)] + samples: u32, + }, /// Print debug information Debug, @@ -36,13 +41,19 @@ fn main() -> Result<(), Box> { let msec = args.interval.max(100); match &args.command { - Some(Commands::Raw) => { + Some(Commands::Pipe { samples }) => { let mut sampler = Sampler::new()?; + let mut counter = 0u32; loop { let doc = sampler.get_metrics(msec)?; let doc = serde_json::to_string(&doc)?; println!("{}", doc); + + counter += 1; + if *samples > 0 && counter >= *samples { + break; + } } } Some(Commands::Debug) => debug::print_debug()?, diff --git a/src/metrics.rs b/src/metrics.rs index ee9eda3..844502d 100644 --- a/src/metrics.rs +++ b/src/metrics.rs @@ -39,6 +39,8 @@ pub struct Metrics { pub ane_power: f32, // Watts pub all_power: f32, // Watts pub sys_power: f32, // Watts + pub ram_power: f32, // Watts + pub gpu_ram_power: f32, // Watts } // MARK: Helpers @@ -220,7 +222,7 @@ impl Sampler { // do several samples to smooth metrics // see: https://github.com/vladkens/macmon/issues/10 - for (sample, sample_dt) in self.ior.get_samples(duration, measures) { + for (sample, dt) in self.ior.get_samples(duration, measures) { let mut ecpu_usages = Vec::new(); let mut pcpu_usages = Vec::new(); let mut rs = Metrics::default(); @@ -247,9 +249,11 @@ impl Sampler { if x.group == "Energy Model" { match x.channel.as_str() { - "CPU Energy" => rs.cpu_power += cfio_watts(x.item, &x.unit, sample_dt)?, - "GPU Energy" => rs.gpu_power += cfio_watts(x.item, &x.unit, sample_dt)?, - c if c.starts_with("ANE") => rs.ane_power += cfio_watts(x.item, &x.unit, sample_dt)?, + "CPU Energy" => rs.cpu_power += cfio_watts(x.item, &x.unit, dt)?, + "GPU Energy" => rs.gpu_power += cfio_watts(x.item, &x.unit, dt)?, + c if c.starts_with("ANE") => rs.ane_power += cfio_watts(x.item, &x.unit, dt)?, + c if c.starts_with("DRAM") => rs.ram_power += cfio_watts(x.item, &x.unit, dt)?, + c if c.starts_with("GPU SRAM") => rs.gpu_ram_power += cfio_watts(x.item, &x.unit, dt)?, _ => {} } } @@ -270,6 +274,8 @@ impl Sampler { rs.cpu_power = zero_div(results.iter().map(|x| x.cpu_power).sum(), measures as _); rs.gpu_power = zero_div(results.iter().map(|x| x.gpu_power).sum(), measures as _); rs.ane_power = zero_div(results.iter().map(|x| x.ane_power).sum(), measures as _); + rs.ram_power = zero_div(results.iter().map(|x| x.ram_power).sum(), measures as _); + rs.gpu_ram_power = zero_div(results.iter().map(|x| x.gpu_ram_power).sum(), measures as _); rs.all_power = rs.cpu_power + rs.gpu_power + rs.ane_power; rs.memory = self.get_mem()?;