Skip to content

Commit

Permalink
feat: add streaming mode
Browse files Browse the repository at this point in the history
  • Loading branch information
graelo committed Aug 3, 2023
1 parent 3a3cae4 commit 4df5912
Show file tree
Hide file tree
Showing 10 changed files with 337 additions and 28 deletions.
18 changes: 18 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ ratatui = { version = "0.22", default-features = false, features = ['termion'] }

num-traits = "0.2"
sysinfo = "0.29.6"
serde_json = "1.0.104"

[dev-dependencies]
assert_approx_eq = "1.1.0"
Expand Down
26 changes: 22 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ cargo install pumas
sudo pumas run
```

Use the arrow keys to switch between tabs. Press `q` or `x` to quit.
Use the arrow keys to switch between tabs. Press `Esc`, `q` or `x` to quit.

### Screenshots

Expand Down Expand Up @@ -92,7 +92,7 @@ Options:
-V, --version Print version
```

and
Pumas can run in two modes: UI mode (the default) and JSON mode.

```sh
$ pumas run --help
Expand All @@ -104,16 +104,34 @@ Options:
-i, --sample-rate <SAMPLE_RATE_MS> Update rate (milliseconds): min: 100 [default: 1000]
--accent-color <ACCENT_COLOR> Accent color: ASCII code in 0~255 [default: 2]
--gauge-bg-color <GAUGE_BG_COLOR> Gauge background color: ASCII code in 0~255 [default: 7]
--json Print metrics to stdout as JSON instead of running the UI
-h, --help Print help (see more with '--help')
-V, --version Print version
```

## Details
### JSON Mode

In JSON mode, Pumas will stream metrics to stdout as JSON instead of running the UI. You can
then pipe the metrics to `jq`, or create a node-exporter for Prometheus, etc.

For instance, the following command will stream the active ratio of the third CPU core of the
first CPU cluster at each sample interval:

```sh
$ sudo pumas run --json | jq '.metrics.e_clusters[0].cpus[2].active_ratio'
0.04624276980757713
0.11764705926179886
^C
```

The JSON schema and an example are available in the [schema](./schema) directory.

## Source of metrics

`sysinfo` crate is used to measure the following:

- per-cluster CPU utilization
- per-core CPU utilization (planned)
- per-core CPU utilization

`powermetrics` is used to measure the following:

Expand Down
1 change: 1 addition & 0 deletions schema/sample-output.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"metrics":{"consumption":{"ane_w":0.0,"cpu_w":0.03471331298351288,"gpu_w":0.0,"package_w":0.034713298082351685},"e_clusters":[{"cpus":[{"active_ratio":0.06896551698446274,"dvfm_states":[{"active_ratio":0.0612191,"freq_mhz":912},{"active_ratio":0.00970609,"freq_mhz":1284},{"active_ratio":0.00419491,"freq_mhz":1752},{"active_ratio":0.00425338,"freq_mhz":2004},{"active_ratio":0.00322888,"freq_mhz":2256},{"active_ratio":0.0,"freq_mhz":2424}],"freq_mhz":1107.15,"id":0},{"active_ratio":0.05202312022447586,"dvfm_states":[{"active_ratio":0.051112,"freq_mhz":912},{"active_ratio":0.00748263,"freq_mhz":1284},{"active_ratio":0.000224149,"freq_mhz":1752},{"active_ratio":0.000167617,"freq_mhz":2004},{"active_ratio":0.000370117,"freq_mhz":2256},{"active_ratio":0.0,"freq_mhz":2424}],"freq_mhz":973.541,"id":1},{"active_ratio":0.05232558399438858,"dvfm_states":[{"active_ratio":0.0639049,"freq_mhz":912},{"active_ratio":0.0021332,"freq_mhz":1284},{"active_ratio":0.000665972,"freq_mhz":1752},{"active_ratio":0.0000973124,"freq_mhz":2004},{"active_ratio":0.000384054,"freq_mhz":2256},{"active_ratio":0.0,"freq_mhz":2424}],"freq_mhz":941.411,"id":2},{"active_ratio":0.034682080149650574,"dvfm_states":[{"active_ratio":0.0321492,"freq_mhz":912},{"active_ratio":0.00232173,"freq_mhz":1284},{"active_ratio":0.0000779737,"freq_mhz":1752},{"active_ratio":0.0,"freq_mhz":2004},{"active_ratio":0.0000592534,"freq_mhz":2256},{"active_ratio":0.0,"freq_mhz":2424}],"freq_mhz":941.158,"id":3}],"dvfm_states":[{"active_ratio":0.962445,"freq_mhz":912},{"active_ratio":0.0213573,"freq_mhz":1284},{"active_ratio":0.00419281,"freq_mhz":1752},{"active_ratio":0.00425953,"freq_mhz":2004},{"active_ratio":0.00774513,"freq_mhz":2256},{"active_ratio":0.0,"freq_mhz":2424}],"freq_mhz":938.537,"name":"E-Cluster"}],"gpu":{"active_ratio":0.0021250000000000435,"dvfm_states":[{"active_ratio":0.00212492,"freq_mhz":444},{"active_ratio":0.0,"freq_mhz":612},{"active_ratio":0.0,"freq_mhz":808},{"active_ratio":0.0,"freq_mhz":968},{"active_ratio":0.0,"freq_mhz":1110},{"active_ratio":0.0,"freq_mhz":1236},{"active_ratio":0.0,"freq_mhz":1338},{"active_ratio":0.0,"freq_mhz":1398}],"freq_mhz":444.0},"p_clusters":[{"cpus":[{"active_ratio":0.011560692451894283,"dvfm_states":[{"active_ratio":0.0,"freq_mhz":702},{"active_ratio":0.0,"freq_mhz":948},{"active_ratio":0.0,"freq_mhz":1188},{"active_ratio":0.0,"freq_mhz":1452},{"active_ratio":0.0,"freq_mhz":1704},{"active_ratio":0.0,"freq_mhz":1968},{"active_ratio":0.0,"freq_mhz":2208},{"active_ratio":0.0,"freq_mhz":2400},{"active_ratio":0.0,"freq_mhz":2568},{"active_ratio":0.0,"freq_mhz":2724},{"active_ratio":0.0,"freq_mhz":2868},{"active_ratio":0.0,"freq_mhz":3000},{"active_ratio":0.0,"freq_mhz":3132},{"active_ratio":0.0,"freq_mhz":3264},{"active_ratio":0.0,"freq_mhz":3360},{"active_ratio":0.0,"freq_mhz":3408},{"active_ratio":0.0,"freq_mhz":3504},{"active_ratio":0.0,"freq_mhz":3528},{"active_ratio":0.00343957,"freq_mhz":3696}],"freq_mhz":3696.13,"id":4},{"active_ratio":0.0,"dvfm_states":[{"active_ratio":0.0,"freq_mhz":702},{"active_ratio":0.0,"freq_mhz":948},{"active_ratio":0.0,"freq_mhz":1188},{"active_ratio":0.0,"freq_mhz":1452},{"active_ratio":0.0,"freq_mhz":1704},{"active_ratio":0.0,"freq_mhz":1968},{"active_ratio":0.0,"freq_mhz":2208},{"active_ratio":0.0,"freq_mhz":2400},{"active_ratio":0.0,"freq_mhz":2568},{"active_ratio":0.0,"freq_mhz":2724},{"active_ratio":0.0,"freq_mhz":2868},{"active_ratio":0.0,"freq_mhz":3000},{"active_ratio":0.0,"freq_mhz":3132},{"active_ratio":0.0,"freq_mhz":3264},{"active_ratio":0.0,"freq_mhz":3360},{"active_ratio":0.0,"freq_mhz":3408},{"active_ratio":0.0,"freq_mhz":3504},{"active_ratio":0.0,"freq_mhz":3528},{"active_ratio":0.000229297,"freq_mhz":3696}],"freq_mhz":3696.13,"id":5},{"active_ratio":0.0,"dvfm_states":[{"active_ratio":0.0,"freq_mhz":702},{"active_ratio":0.0,"freq_mhz":948},{"active_ratio":0.0,"freq_mhz":1188},{"active_ratio":0.0,"freq_mhz":1452},{"active_ratio":0.0,"freq_mhz":1704},{"active_ratio":0.0,"freq_mhz":1968},{"active_ratio":0.0,"freq_mhz":2208},{"active_ratio":0.0,"freq_mhz":2400},{"active_ratio":0.0,"freq_mhz":2568},{"active_ratio":0.0,"freq_mhz":2724},{"active_ratio":0.0,"freq_mhz":2868},{"active_ratio":0.0,"freq_mhz":3000},{"active_ratio":0.0,"freq_mhz":3132},{"active_ratio":0.0,"freq_mhz":3264},{"active_ratio":0.0,"freq_mhz":3360},{"active_ratio":0.0,"freq_mhz":3408},{"active_ratio":0.0,"freq_mhz":3504},{"active_ratio":0.0,"freq_mhz":3528},{"active_ratio":7.98591e-7,"freq_mhz":3696}],"freq_mhz":3696.13,"id":6},{"active_ratio":0.0,"dvfm_states":[{"active_ratio":0.0,"freq_mhz":702},{"active_ratio":0.0,"freq_mhz":948},{"active_ratio":0.0,"freq_mhz":1188},{"active_ratio":0.0,"freq_mhz":1452},{"active_ratio":0.0,"freq_mhz":1704},{"active_ratio":0.0,"freq_mhz":1968},{"active_ratio":0.0,"freq_mhz":2208},{"active_ratio":0.0,"freq_mhz":2400},{"active_ratio":0.0,"freq_mhz":2568},{"active_ratio":0.0,"freq_mhz":2724},{"active_ratio":0.0,"freq_mhz":2868},{"active_ratio":0.0,"freq_mhz":3000},{"active_ratio":0.0,"freq_mhz":3132},{"active_ratio":0.0,"freq_mhz":3264},{"active_ratio":0.0,"freq_mhz":3360},{"active_ratio":0.0,"freq_mhz":3408},{"active_ratio":0.0,"freq_mhz":3504},{"active_ratio":0.0,"freq_mhz":3528},{"active_ratio":0.0,"freq_mhz":3696}],"freq_mhz":0.0,"id":7}],"dvfm_states":[{"active_ratio":0.0,"freq_mhz":702},{"active_ratio":0.0,"freq_mhz":948},{"active_ratio":0.0,"freq_mhz":1188},{"active_ratio":0.0,"freq_mhz":1452},{"active_ratio":0.0,"freq_mhz":1704},{"active_ratio":0.0,"freq_mhz":1968},{"active_ratio":0.0,"freq_mhz":2208},{"active_ratio":0.0,"freq_mhz":2400},{"active_ratio":0.0,"freq_mhz":2568},{"active_ratio":0.0,"freq_mhz":2724},{"active_ratio":0.0,"freq_mhz":2868},{"active_ratio":0.0,"freq_mhz":3000},{"active_ratio":0.0,"freq_mhz":3132},{"active_ratio":0.0,"freq_mhz":3264},{"active_ratio":0.0,"freq_mhz":3360},{"active_ratio":0.0,"freq_mhz":3408},{"active_ratio":0.0,"freq_mhz":3504},{"active_ratio":0.0,"freq_mhz":3528},{"active_ratio":0.0,"freq_mhz":3696}],"freq_mhz":0.0,"name":"P0-Cluster"},{"cpus":[{"active_ratio":0.3988439440727234,"dvfm_states":[{"active_ratio":0.0,"freq_mhz":702},{"active_ratio":0.0,"freq_mhz":948},{"active_ratio":0.0,"freq_mhz":1188},{"active_ratio":0.0,"freq_mhz":1452},{"active_ratio":0.0,"freq_mhz":1704},{"active_ratio":0.0,"freq_mhz":1968},{"active_ratio":0.0,"freq_mhz":2208},{"active_ratio":0.0,"freq_mhz":2400},{"active_ratio":0.0,"freq_mhz":2568},{"active_ratio":0.0,"freq_mhz":2724},{"active_ratio":0.0,"freq_mhz":2868},{"active_ratio":0.0,"freq_mhz":3000},{"active_ratio":0.0,"freq_mhz":3132},{"active_ratio":0.0,"freq_mhz":3264},{"active_ratio":0.0,"freq_mhz":3360},{"active_ratio":0.0,"freq_mhz":3408},{"active_ratio":0.0,"freq_mhz":3504},{"active_ratio":0.0,"freq_mhz":3528},{"active_ratio":0.0,"freq_mhz":3696}],"freq_mhz":0.0,"id":8},{"active_ratio":0.0,"dvfm_states":[{"active_ratio":0.0,"freq_mhz":702},{"active_ratio":0.0,"freq_mhz":948},{"active_ratio":0.0,"freq_mhz":1188},{"active_ratio":0.0,"freq_mhz":1452},{"active_ratio":0.0,"freq_mhz":1704},{"active_ratio":0.0,"freq_mhz":1968},{"active_ratio":0.0,"freq_mhz":2208},{"active_ratio":0.0,"freq_mhz":2400},{"active_ratio":0.0,"freq_mhz":2568},{"active_ratio":0.0,"freq_mhz":2724},{"active_ratio":0.0,"freq_mhz":2868},{"active_ratio":0.0,"freq_mhz":3000},{"active_ratio":0.0,"freq_mhz":3132},{"active_ratio":0.0,"freq_mhz":3264},{"active_ratio":0.0,"freq_mhz":3360},{"active_ratio":0.0,"freq_mhz":3408},{"active_ratio":0.0,"freq_mhz":3504},{"active_ratio":0.0,"freq_mhz":3528},{"active_ratio":0.0,"freq_mhz":3696}],"freq_mhz":0.0,"id":9},{"active_ratio":0.0,"dvfm_states":[{"active_ratio":0.0,"freq_mhz":702},{"active_ratio":0.0,"freq_mhz":948},{"active_ratio":0.0,"freq_mhz":1188},{"active_ratio":0.0,"freq_mhz":1452},{"active_ratio":0.0,"freq_mhz":1704},{"active_ratio":0.0,"freq_mhz":1968},{"active_ratio":0.0,"freq_mhz":2208},{"active_ratio":0.0,"freq_mhz":2400},{"active_ratio":0.0,"freq_mhz":2568},{"active_ratio":0.0,"freq_mhz":2724},{"active_ratio":0.0,"freq_mhz":2868},{"active_ratio":0.0,"freq_mhz":3000},{"active_ratio":0.0,"freq_mhz":3132},{"active_ratio":0.0,"freq_mhz":3264},{"active_ratio":0.0,"freq_mhz":3360},{"active_ratio":0.0,"freq_mhz":3408},{"active_ratio":0.0,"freq_mhz":3504},{"active_ratio":0.0,"freq_mhz":3528},{"active_ratio":0.0,"freq_mhz":3696}],"freq_mhz":0.0,"id":10},{"active_ratio":0.0,"dvfm_states":[{"active_ratio":0.0,"freq_mhz":702},{"active_ratio":0.0,"freq_mhz":948},{"active_ratio":0.0,"freq_mhz":1188},{"active_ratio":0.0,"freq_mhz":1452},{"active_ratio":0.0,"freq_mhz":1704},{"active_ratio":0.0,"freq_mhz":1968},{"active_ratio":0.0,"freq_mhz":2208},{"active_ratio":0.0,"freq_mhz":2400},{"active_ratio":0.0,"freq_mhz":2568},{"active_ratio":0.0,"freq_mhz":2724},{"active_ratio":0.0,"freq_mhz":2868},{"active_ratio":0.0,"freq_mhz":3000},{"active_ratio":0.0,"freq_mhz":3132},{"active_ratio":0.0,"freq_mhz":3264},{"active_ratio":0.0,"freq_mhz":3360},{"active_ratio":0.0,"freq_mhz":3408},{"active_ratio":0.0,"freq_mhz":3504},{"active_ratio":0.0,"freq_mhz":3528},{"active_ratio":0.0,"freq_mhz":3696}],"freq_mhz":0.0,"id":11}],"dvfm_states":[{"active_ratio":0.0,"freq_mhz":702},{"active_ratio":0.0,"freq_mhz":948},{"active_ratio":0.0,"freq_mhz":1188},{"active_ratio":0.0,"freq_mhz":1452},{"active_ratio":0.0,"freq_mhz":1704},{"active_ratio":0.0,"freq_mhz":1968},{"active_ratio":0.0,"freq_mhz":2208},{"active_ratio":0.0,"freq_mhz":2400},{"active_ratio":0.0,"freq_mhz":2568},{"active_ratio":0.0,"freq_mhz":2724},{"active_ratio":0.0,"freq_mhz":2868},{"active_ratio":0.0,"freq_mhz":3000},{"active_ratio":0.0,"freq_mhz":3132},{"active_ratio":0.0,"freq_mhz":3264},{"active_ratio":0.0,"freq_mhz":3360},{"active_ratio":0.0,"freq_mhz":3408},{"active_ratio":0.0,"freq_mhz":3504},{"active_ratio":0.0,"freq_mhz":3528},{"active_ratio":0.0,"freq_mhz":3696}],"freq_mhz":0.0,"name":"P1-Cluster"}],"thermal_pressure":"Nominal"},"soc":{"cpu_brand_name":"Apple M2 Max","max_ane_w":8.0,"max_cpu_w":28.0,"max_gpu_w":65.0,"max_package_w":101.0,"num_cpu_cores":12,"num_efficiency_cores":4,"num_gpu_cores":38,"num_performance_cores":8}}
203 changes: 203 additions & 0 deletions schema/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
{
"$schema": "http://json-schema.org/draft-06/schema#",
"$ref": "#/definitions/Welcome9",
"definitions": {
"Welcome9": {
"type": "object",
"additionalProperties": false,
"properties": {
"metrics": {
"$ref": "#/definitions/Metrics"
},
"soc": {
"$ref": "#/definitions/Soc"
}
},
"required": [
"metrics",
"soc"
],
"title": "Welcome9"
},
"Metrics": {
"type": "object",
"additionalProperties": false,
"properties": {
"consumption": {
"$ref": "#/definitions/Consumption"
},
"e_clusters": {
"type": "array",
"items": {
"$ref": "#/definitions/Cluster"
}
},
"gpu": {
"$ref": "#/definitions/GPU"
},
"p_clusters": {
"type": "array",
"items": {
"$ref": "#/definitions/Cluster"
}
},
"thermal_pressure": {
"type": "string"
}
},
"required": [
"consumption",
"e_clusters",
"gpu",
"p_clusters",
"thermal_pressure"
],
"title": "Metrics"
},
"Consumption": {
"type": "object",
"additionalProperties": false,
"properties": {
"ane_w": {
"type": "number"
},
"cpu_w": {
"type": "number"
},
"gpu_w": {
"type": "number"
},
"package_w": {
"type": "number"
}
},
"required": [
"ane_w",
"cpu_w",
"gpu_w",
"package_w"
],
"title": "Consumption"
},
"Cluster": {
"type": "object",
"additionalProperties": false,
"properties": {
"cpus": {
"type": "array",
"items": {
"$ref": "#/definitions/GPU"
}
},
"dvfm_states": {
"type": "array",
"items": {
"$ref": "#/definitions/DvfmState"
}
},
"freq_mhz": {
"type": "number"
},
"name": {
"type": "string"
}
},
"required": [
"cpus",
"dvfm_states",
"freq_mhz",
"name"
],
"title": "Cluster"
},
"GPU": {
"type": "object",
"additionalProperties": false,
"properties": {
"active_ratio": {
"type": "number"
},
"dvfm_states": {
"type": "array",
"items": {
"$ref": "#/definitions/DvfmState"
}
},
"freq_mhz": {
"type": "number"
},
"id": {
"type": "integer"
}
},
"required": [
"active_ratio",
"dvfm_states",
"freq_mhz"
],
"title": "GPU"
},
"DvfmState": {
"type": "object",
"additionalProperties": false,
"properties": {
"active_ratio": {
"type": "number"
},
"freq_mhz": {
"type": "integer"
}
},
"required": [
"active_ratio",
"freq_mhz"
],
"title": "DvfmState"
},
"Soc": {
"type": "object",
"additionalProperties": false,
"properties": {
"cpu_brand_name": {
"type": "string"
},
"max_ane_w": {
"type": "number"
},
"max_cpu_w": {
"type": "number"
},
"max_gpu_w": {
"type": "number"
},
"max_package_w": {
"type": "number"
},
"num_cpu_cores": {
"type": "integer"
},
"num_efficiency_cores": {
"type": "integer"
},
"num_gpu_cores": {
"type": "integer"
},
"num_performance_cores": {
"type": "integer"
}
},
"required": [
"cpu_brand_name",
"max_ane_w",
"max_cpu_w",
"max_gpu_w",
"max_package_w",
"num_cpu_cores",
"num_efficiency_cores",
"num_gpu_cores",
"num_performance_cores"
],
"title": "Soc"
}
}
}
4 changes: 4 additions & 0 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ pub struct RunConfig {
/// Gauge background color: ASCII code in 0~255.
#[arg(long, default_value = "7")]
pub gauge_bg_color: u8,

/// Print metrics to stdout as JSON instead of running the UI.
#[arg(long, default_value = "false")]
pub json: bool,
}

impl RunConfig {
Expand Down
Loading

0 comments on commit 4df5912

Please sign in to comment.