Skip to content

obs-gpu-status: Keep one PDH query open between label ticks - #1271

Merged
zackees merged 3 commits into
obs-rust:masterfrom
vpacher:perf/1022-pdh-open-query
Oct 17, 2026
Merged

zackees merged 3 commits into
obs-rust:masterfrom
vpacher:perf/1022-pdh-open-query

Conversation

@vpacher

@vpacher vpacher commented Oct 17, 2026 •

Copy link
Copy Markdown
Contributor

Refs #1022

What and why

The follow-up from the review of #1264: gpu_engine_samples() opened a PDH query, added the counter, collected twice 100 ms apart and closed the query, on every label tick. On an RTX 3060 that cost about 230 ms per tick (900 ms for the first), and the value covered only 100 ms of the second.

This PR keeps one query open:

  1. pdh::PdhTicker (Tier 1, platform-neutral) keeps one EngineCounters query and returns the utilization since the previous call. The first call after the query opens only primes it (Unavailable). A failed query, or a failed open, is retried on the next call.
  2. platform/windows.rs: EngineQuery opens \GPU Engine(*)\Utilization Percentage and adds the counter once; each tick is one PdhCollectQueryData and the read of the array (the read code is unchanged, now read_counter()). No 100 ms sleep: the previous tick is the baseline, so the value is the average over the second since then.
  3. PdhSource keeps one ticker. gpu_engine_samples() stays as a one-shot read (open, prime, 100 ms, read) for the probe.
  4. The probe takes three label samples one second apart, as the frontend's sampler thread does.

RED → GREEN

  • Rebased onto master after obs-gpu-status: Windows GPU: x% from PDH GPU Engine counters #1264 merged (by zackees; the patch is unchanged).

  • RED af4f8f3: four Tier 1 tests drive PdhTicker with fake queries. With a stub that never opens a query, 3 fail: the first-tick baseline (left: Unavailable, right: Percent(37)), the reopen of a failed query (Percent(25)) and the retry of a failed open (Percent(9)). The render-adapter filter passes with the stub.

  • GREEN f9f801b: 133/133 crate tests pass on macOS. 8b15895 names the fake query results in the tests (clippy type_complexity, which Fast Gate caught: my local clippy output went through a filter that missed soldr's timestamp prefix). Now clippy -D warnings finishes clean for aarch64-apple-darwin and x86_64-pc-windows-msvc, checked on the Finished line. fmt is clean.

  • Real hardware: the same Windows 11 VM with the RTX 3060 (driver 617.42) as obs-gpu-status: Windows GPU: x% from PDH GPU Engine counters #1264, the old probe (a new query per sample) and the new one (three ticks per run), idle and under a GPU-bound WebGL load:

    Old: new query per sample New: query stays open
    First sample 906 ms, 925 ms 123 ms, 124 ms, 147 ms (open and prime, once)
    Each later tick 228 to 234 ms 0.36 to 0.55 ms
    Under load (nvidia-smi 30 %, then 39 %) 0 %, 30 %, 59 % 30 %, 33 %, then 32 %, 38 %

    A tick is about 500 times cheaper, and the one-second average follows nvidia-smi more closely than the 100 ms window did.

  • Real app: not applicable (no change in what the label shows, only how often the source costs time). The Windows app check for frontend: GPU: x% readout replaces the GPU status light #1025 waits for a beta that has obs-gpu-status: Windows GPU: x% from PDH GPU Engine counters #1264.

Checklist

  • Base is master (or the description starts with a Stacked: note)
  • I claimed the issue, or no one else has an open PR for it (obs-gpu-status: Windows GPU utilization through PDH GPU Engine counters #1022 is zackees'; he handed this part over in obs-gpu-status: Windows GPU: x% from PDH GPU Engine counters #1264)
  • Characterization test (if the unit had none), then RED, then GREEN commits
  • User-visible change: its line in docs/features.md is added or updated (not applicable: no user-visible change)
  • (Optional) Local gate passed and the pushed head is stamped; otherwise PR CI runs the full suite
  • Warning or flag changes (-W..., ratchets): built with scripting ON (a flag change under cmake/ or build-aux/ runs the full builds) and cross-checked with clang and MSVC (not applicable: no flag changes)
  • Intentional differences from C listed in the parity test header and rust/README.md (ports) (not applicable: new code, no C original)

🤖 Generated with Claude Code

@vpacher
vpacher requested a review from zackees as a code owner October 17, 2026 17:05
@vpacher
vpacher force-pushed the perf/1022-pdh-open-query branch from 8602645 to 5d9f703 Compare October 17, 2026 17:07
@zackees

zackees commented Oct 17, 2026

Copy link
Copy Markdown
Member

@vpacher Fast Gate fails on clippy type_complexity at rust/obs-gpu-status/tests/gpu_status/pdh.rs:184 ("very complex type used. Consider factoring parts into type definitions"); a type alias fixes it, and ./lint catches it locally. Also, this carries #1264's three commits, so it's stacked: I'll queue #1264 first, then this once it's rebased onto master and green.

@vpacher

vpacher commented Oct 17, 2026

Copy link
Copy Markdown
Contributor Author

@zackees Fixed in 21a73be: a Collections type alias for the fake query results. Thanks for the catch. My local clippy output went through a filter that missed soldr's timestamp prefix, so it hid the error; now checked on the Finished line for macOS and x86_64-pc-windows-msvc. Understood on the order: I'll rebase this onto master once #1264 merges and drop the stacked note.

vpacher and others added 3 commits October 17, 2026 10:41
…rust#1022)

PdhTicker keeps one GPU Engine query open and uses the previous tick as
the baseline: the first tick after the query opens only primes it, a
failed query or open is retried on the next tick. Tier 1 tests drive it
with fake queries. With a stub that never opens a query, 3 of 4 fail:
the first-tick baseline, the reopen of a failed query and the retry of
a failed open. Only the render-adapter filter passes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s-rust#1022)

PdhTicker opens the query once and returns the utilization since the
previous call; a failed query or open is retried on the next call.
On Windows, EngineQuery opens \GPU Engine(*)\Utilization Percentage and
adds the counter once, then does one PdhCollectQueryData per tick; the
first tick primes it. PdhSource keeps one ticker, so a label tick no
longer opens a query, adds the counter or sleeps 100 ms, and the value
is averaged over the second since the previous tick instead of 100 ms.
gpu_engine_samples() stays a one-shot read for the probe. The probe
takes three label samples one second apart, as the frontend does.
133/133 crate tests pass; clippy -D warnings is clean for macOS and
x86_64-pc-windows-msvc.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
clippy::type_complexity rejected the nested Vec<Option<Vec<...>>> of
the ticker helper; a Collections alias names one fake query's results.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@zackees

zackees commented Oct 17, 2026

Copy link
Copy Markdown
Member

#1264 merged, so I rebased this onto master and dropped its three commits; your three remain (8b15895). Clean rebase, ./lint passes. Will queue once CI is green.

@zackees
zackees added this pull request to the merge queue Oct 17, 2026
Merged via the queue into obs-rust:master with commit a9952c8 Oct 17, 2026
26 checks passed
@vpacher
vpacher deleted the perf/1022-pdh-open-query branch October 18, 2026 07:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants