pdh: convert all raw time counter types to seconds (#2776)

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: Claude <noreply@anthropic.com>
This commit is contained in:
Jan-Otto Kröpke
2026-10-16 22:54:44 +02:00
committed by GitHub
co-authored by Claude
parent a9d5bbef48
commit da7bebc6b3
23 changed files with 313 additions and 246 deletions
+1 -1
View File
@@ -369,7 +369,7 @@ The `vm` label holds the instance name of the `Hyper-V Virtual SMB` performance
The `Latency`, `Lower Latency`, `Queue Length` and `Lower Queue Length` performance counters
are averages that Windows computes from two samples. Their raw values only grow: the sum of
all IO latencies in 100ns ticks, and the raw queue length values are the same as the raw
all IO latencies in ticks of the counter time base (usually 10 MHz), and the raw queue length values are the same as the raw
latency values. windows_exporter publishes them as the `*_io_latency_seconds_total` counters:
```promql
+18 -10
View File
@@ -218,16 +218,24 @@ keep counting up. If the multiplier is the reciprocal of an integer, like `0.001
the value is divided by that integer instead, which avoids rounding artifacts
such as `0.009000000000000001`. If not specified, the value is exported as is.
With the object `type` `raw`, the default, some counters are already converted
to seconds, so do not scale them again: `PERF_100NSEC_TIMER` and
`PERF_PRECISION_100NS_TIMER` counters such as `% Idle Time` are exported in
seconds, and `PERF_ELAPSED_TIME` counters such as `Process\Elapsed Time` as
seconds since the start. `PERF_100NSEC_TIMER_INV` counters such as
`% Processor Time` are not converted and arrive in 100 ns ticks of inactive time
(for `% Processor Time`, the idle time); a multiplier of `1e-7` converts them to
seconds. `PERF_AVERAGE_TIMER` counters such as `Avg. Disk sec/Read` count ticks
of the performance timer, whose frequency depends on the host, so a fixed
multiplier does not fit them; use the `formatted` type for them.
With the object `type` `raw`, the default, time counters are already converted
to seconds, so do not scale them again:
- the 100 ns timers (`PERF_100NSEC_TIMER`, `PERF_100NSEC_TIMER_INV`,
`PERF_100NSEC_MULTI_TIMER`, `PERF_100NSEC_MULTI_TIMER_INV` and
`PERF_PRECISION_100NS_TIMER`), such as `% Idle Time`;
- `PERF_COUNTER_100NS_QUEUELEN_TYPE` counters, such as `Avg. Data Queue Length`
of `SMB Client Shares`, as queue length times seconds, so their rate is the
average queue length;
- `PERF_AVERAGE_TIMER` counters, such as `Avg. Disk sec/Read`, as the summed
duration in seconds, using the time base of the counter. Their second value
is the number of operations;
- `PERF_ELAPSED_TIME` counters, such as `Process\Elapsed Time`, as seconds since
the start.
The raw value of an `_INV` counter is the inactive time: for `% Processor Time`,
that is the idle time, not the busy time. `MULTI_TIMER` values are summed over
all units of the counter, so they can grow faster than wall time.
This key is optional.
+3
View File
@@ -931,6 +931,9 @@ These metrics keep their names, but 0.31 reported wrong values. Graphs show a st
#### performancecounter and PDH-based collectors
- In the `performancecounter` collector, counters without an explicit `type` now always get the type of the underlying Windows counter. In 0.31 a mixed object could report counters as gauges, or the other way around, and the type could change between scrapes. If Prometheus scrapes with OpenMetrics, a counter that 0.31 reported as a gauge is now stored with a `_total` suffix, which the compatibility rules can't cover.
- Raw `PERF_100NSEC_TIMER_INV`, `PERF_100NSEC_MULTI_TIMER` and `PERF_100NSEC_MULTI_TIMER_INV` counters, such as `% Processor Time` read with the `raw` type, are exported in seconds, like the other 100 ns timers. In 0.31 they were exported in 100 ns ticks, so values read this way are 10,000,000 times smaller; remove any query that divided them by `1e7`. The raw value of an `_INV` counter such as `% Processor Time` is the inactive (idle) time, not the busy time; `PERF_100NSEC_MULTI_TIMER(_INV)` values are summed over all units of the counter.
- Raw `PERF_AVERAGE_TIMER` counters, such as `Avg. Disk sec/Read`, and raw `PERF_COUNTER_100NS_QUEUELEN_TYPE` counters, such as `Avg. Data Queue Length`, read with the `performancecounter` collector are exported in seconds and as counters. In 0.31 they were exported in ticks and as gauges. `PERF_AVERAGE_TIMER` uses the time base of the counter, which is 10 MHz on most hosts. The latencies of the `physical_disk`, `smbclient` and `hyperv` collectors now use it too; on a host with another time base, 0.31 reported them wrong.
- Values converted from 100 ns ticks to seconds, in the `performancecounter`, `cpu`, `process`, `physical_disk`, `logical_disk`, `smbclient`, `container` and `hyperv` collectors, are now rounded correctly and can differ from 0.31 in the last digit. A counter that doesn't move across the upgrade can drop by that last digit once, which `rate()` and `increase()` count as a reset for one window.
- Instances without a valid sample are left out. In 0.31 they were reported as `0`, which looked like a counter reset.
- An explicit instance list such as `instances: ["C:", "D:"]` now returns one series per instance. In 0.31 all listed instances were merged into one series.
- When Windows reports the same instance name more than once, for example every `svchost` process of the `Process` object, the `performancecounter`, `netframework`, `hyperv` and `exchange` (ADAccess processes) collectors publish each occurrence as a separate series. The first keeps the name, later ones get the suffix `#1`, `#2` and so on (`exchange` keeps its `_2`, `_3` label suffixes), which depends on the order of the sample and does not identify the instance across scrapes. The other PDH-based collectors read objects that Windows names uniquely; if one still reports a name twice, they publish the first instance with valid data and log a warning. In 0.31 the occurrences overwrote each other.