Skip to main content

Module wddm

Module wddm 

Source
Expand description

Windows cross-vendor WDDM backend (docs/design/cross-platform.md §3) — AMD and Intel on Windows (and NVIDIA when NVML is absent), entirely from OS surfaces: DXGI for enumeration and VRAM totals, PDH GPU counters for utilization and memory, D3DKMT for the LUID→PCI identity. pdh.dll/gdi32.dll/dxgi.dll are OS system libraries — linking them via the windows crate does NOT violate the no-vendor-SDK rule (that rule targets vendor SDKs with soname churn, not the OS itself).

Honesty contract, per metric (§3.4 — these are load-bearing semantics, not trivia):

  • util_pct is scheduler duty-cycle, not capacity. The PDH GPU Engine counters report how busy the WDDM scheduler (VidSch) kept each engine — time with work resident, exactly the same kind of number as NVML’s duty-cycle “utilization”, and it must be labeled exactly as honestly: a GPU can read 100% here while its execution units idle. The device headline is the busiest single engine (summed across pids per engine first), which is what Task Manager’s Performance tab shows — comparable on purpose, so users cross-checking against Task Manager see agreement, not a mystery.
  • mem_used_bytes comes from GPU Adapter Memory\Dedicated Usage — the VidMm (Windows video memory manager) number, the adapter-level counter Microsoft confirms stays correct (KB4490156). DXGI’s QueryVideoMemoryInfo is never used for device-used: it reports the calling process’s budget/usage by design and would show gpuviewer’s own ~0 — a silently-wrong number, the worst kind.
  • temp_c, power_mw, fan_pct, sm_clock_mhz, mem_clock_mhz are None on this backend — Windows exposes no public temperature/power/clock API for AMD/Intel GPUs without installing vendor SDKs (ADLX/IGCL), which the no-vendor-SDK rule forbids. The UI renders these as unavailable; fabricating them is not an option. The two known semi-public paths are explicitly out of scope per §3.6: D3DKMT KMTQAITYPE_ADAPTERPERFDATA (driver-optional kernel thunk, deci-°C, power in 0.1% units) is a future opportunistic probe, and DXCore’s QueryState telemetry is still prerelease. Do not “fix” these in.
  • throttle is None: this source cannot observe throttling at all, and the §5.4 Option<ThrottleReasons> model makes that unobservability representable — None means “unobserved”, and the event engine/UI/rollups treat it as a blind spot. The all-false struct (a fabricated fact-grade “not throttling”) is never emitted here.
  • Per-process rows come from PDH GPU Engine / GPU Process Memory instances joined by (pid, LUID). kind is Unknown — PDH does not distinguish compute/graphics; an engtype of Compute/Cuda upgrades to Compute as a labeled heuristic only. cpu_pct/container are None (no /proc on Windows).
  • Absence is normal. A GPU-less machine (CI runner, RDP session without vGPU) has no GPU Engine PDH object at all (PDH_CSTATUS_NO_OBJECT) and possibly no hardware DXGI adapter — every such outcome is None/empty/skipped-backend, never an error. The first PDH collection legitimately yields no rate data (rate counters need two collections) — the first frame is honestly empty.

Identity (§3.1): the in-session join key is the adapter LUID (matches PDH instance tokens and D3DKMT). A LUID is session-scoped — it changes on reboot/driver update — so it is never persisted as identity. The persistent DeviceId is the normalized PCI BDF ("0000:bb:dd.f") obtained via D3DKMT ADAPTERADDRESS, the same key shape NVML and sysfs produce, so history identity works and the collector’s first-wins PCI dedupe lets NVML claim NVIDIA boards ahead of this backend (registry order nvidia → wddm, §3.7). If the D3DKMT thunk fails, the fallback id wddm:<vendor>:<device>:<ordinal> deliberately does NOT parse as a PCI address, so normalize_pci_id refuses to dedupe it: listing a device twice beats wrongly merging two.

Layout: the pdh and adapters submodules carry the §9 interface-freeze surface (pdh::shared(), SharedPdh::snapshot, parse_instance, adapters::enumerate); the integrator may re-export them as win::pdh/win::adapters or split them into files later. Everything that touches a Windows API is #[cfg(target_os = "windows")]; the counter-instance grammar and all aggregation math are pure functions that compile and unit-test on every OS (CI has no GPUs — the Linux leg runs those tests from string fixtures).

Modules§

adapters
DXGI adapter enumeration + D3DKMT LUID→PCI identity (§3.1/§3.3).
pdh
PDH GPU counters: instance-name grammar, aggregation math, and (on Windows) the shared process-wide query both Windows backends read from.