Context
pcp_compare_windows needs to compare counter metrics across historical time windows. Counters are cumulative odometers — comparing raw values is meaningless; you need rate-of-change.
We implemented client-side rate conversion in #31 (_compute_rates() in _stats.py), which works correctly. However, this is compensating for a gap in pmproxy's API surface.
The gap
pmproxy has two API surfaces with different capabilities:
|
Series API (/series/*) |
PMAPI (/pmapi/*) |
| Historical windows |
Yes |
No (live snapshot only) |
rate() support |
No |
Yes (via /pmapi/derive) |
| State |
Stateless |
Context-scoped (120s timeout) |
- Series API is the only path to historical data, but has no rate conversion
- PMAPI has
rate() via derived metrics, but only returns live values and derived metrics are ephemeral (tied to context lifetime)
Any tool consuming historical counter data from the Series API must reimplement max(0, dv/dt) client-side. This likely affects Grafana's PCP datasource plugin and any other Series API consumer too.
What pmproxy already knows
/series/descs returns "semantics": "counter" — pmproxy knows which metrics are counters
- Raw data in Redis/Valkey includes timestamps — all information needed for rate computation is available server-side
- The PMAPI expression engine already implements
rate() — the math is not novel
Proposed upstream feature
Ask the PCP project to add rate conversion support to the Series API. Possible shapes:
rate=true parameter on /series/values — auto-converts counter metrics to per-second rates based on semantics
rate() function in /series/query expressions — mirrors PMAPI derive syntax, e.g. rate(disk.dev.read)
- New endpoint like
/series/rates — dedicated rate-converted series fetch
Option 2 feels most consistent with PCP's existing patterns — it mirrors the PMAPI rate() function and keeps the Series expression language expressive.
Why this isn't just us
- Counter semantics is a first-class PCP concept — the Series API exposing semantics metadata but not acting on it is an inconsistency
- Every Series API consumer building analysis/dashboarding tools faces this exact problem
- The PMAPI side solved this years ago with
rate() — the Series API is the gap
Our current workaround
PR #31 adds _compute_rates(samples) which computes max(0.0, dv/dt) per consecutive sample pair, with counter-wrap clamping and zero-dt protection. This is correct and matches PCP's rate() semantics, but ideally pmproxy would handle this server-side.
Action
Use this issue as the basis for an upstream feature request to the PCP project. Remove pmmcp-specific references and frame as a general Series API enhancement.
Context
pcp_compare_windowsneeds to compare counter metrics across historical time windows. Counters are cumulative odometers — comparing raw values is meaningless; you need rate-of-change.We implemented client-side rate conversion in #31 (
_compute_rates()in_stats.py), which works correctly. However, this is compensating for a gap in pmproxy's API surface.The gap
pmproxy has two API surfaces with different capabilities:
/series/*)/pmapi/*)rate()support/pmapi/derive)rate()via derived metrics, but only returns live values and derived metrics are ephemeral (tied to context lifetime)Any tool consuming historical counter data from the Series API must reimplement
max(0, dv/dt)client-side. This likely affects Grafana's PCP datasource plugin and any other Series API consumer too.What pmproxy already knows
/series/descsreturns"semantics": "counter"— pmproxy knows which metrics are countersrate()— the math is not novelProposed upstream feature
Ask the PCP project to add rate conversion support to the Series API. Possible shapes:
rate=trueparameter on/series/values— auto-converts counter metrics to per-second rates based on semanticsrate()function in/series/queryexpressions — mirrors PMAPI derive syntax, e.g.rate(disk.dev.read)/series/rates— dedicated rate-converted series fetchOption 2 feels most consistent with PCP's existing patterns — it mirrors the PMAPI
rate()function and keeps the Series expression language expressive.Why this isn't just us
rate()— the Series API is the gapOur current workaround
PR #31 adds
_compute_rates(samples)which computesmax(0.0, dv/dt)per consecutive sample pair, with counter-wrap clamping and zero-dt protection. This is correct and matches PCP'srate()semantics, but ideally pmproxy would handle this server-side.Action
Use this issue as the basis for an upstream feature request to the PCP project. Remove pmmcp-specific references and frame as a general Series API enhancement.