Skip to content

fix: memoize static disk-name resolution so the Dashboard 2s temp poll stops re-querying WMI/SMART#1426

Merged
laurentiu021 merged 1 commit into
mainfrom
fix/temperature-memoize-diskname-poll
Jul 10, 2026
Merged

fix: memoize static disk-name resolution so the Dashboard 2s temp poll stops re-querying WMI/SMART#1426
laurentiu021 merged 1 commit into
mainfrom
fix/temperature-memoize-diskname-poll

Conversation

@laurentiu021

Copy link
Copy Markdown
Owner

Summary

Fresh ultra-audit finding (performance, P2), verified against current source.

RefreshTemperaturesAsync calls TemperatureService.ReadAllAsync() with includeStorage defaulting to true. On an elevated session, the Dashboard's 2-second temperature poll (the Dashboard is the app's default/home tab) therefore ran, on every tick:

  • GetDiskNamesFromWmi() — a Win32_DiskDrive WMI query, and
  • EnrichStorageNamesAsyncDiskHealthService.CollectAsync() — an MSFT_PhysicalDisk enumeration plus a per-disk MSFT_StorageReliabilityCounter (SMART) association walk, which the code's own comments call "by far the heaviest part of a read."

All of that was spent solely to relabel LibreHardwareMonitor storage sensors with disk friendly-names — static hardware identity that never changes. (The 10s resource sampler was already optimized to skip this with includeStorage:false; the more frequent Dashboard poll was not.)

Fix

Both resolutions are memoized once, mirroring the existing _nvApiInitTried "resolve static hardware once" pattern:

  • _cachedWmiDiskNames (??=, under the existing _sensorLock).
  • _cachedStorageFriendlyNames behind a SemaphoreSlim gate (double-checked) so the first resolution is race-safe when the 2s poll, the user's Refresh, and the 10s sampler overlap.

After the first read the hot poll only calls LibreHardwareMonitor's Update() for live temperatures. _enrichGate is disposed in Dispose().

Regression test (integration)

EnrichStorageNames_ResolvesOnce_AndCachesFriendlyNames — drives the private enricher twice and asserts _cachedStorageFriendlyNames is populated once and reference-stable across calls (proving it resolves once). DiskHealthService.CollectAsync() degrades to an empty list on a WMI-less CI host but still caches, so the assertion is deterministic.

Checks

  • All 3 projects build 0 warnings / 0 errors
  • Leak scan on diff: clean
  • Behavior unchanged: the same friendly-names are applied; they're just resolved once instead of every 2s.

…l stops re-querying WMI/SMART

RefreshTemperaturesAsync calls TemperatureService.ReadAllAsync() with includeStorage
defaulting to true, so on an elevated session the Dashboard's 2s poll ran, every
tick: GetDiskNamesFromWmi() (a Win32_DiskDrive query) AND EnrichStorageNamesAsync ->
DiskHealthService.CollectAsync() (MSFT_PhysicalDisk enumeration + per-disk
MSFT_StorageReliabilityCounter SMART walk — the heaviest part of a read). All of it
just to relabel LHM storage sensors with disk friendly-names, which are static
hardware identity.

Both resolutions are now memoized once (mirroring the _nvApiInitTried 'resolve static
hardware once' pattern): _cachedWmiDiskNames under _sensorLock, and
_cachedStorageFriendlyNames behind a SemaphoreSlim gate that makes the first
resolution race-safe across the 2s poll, the user Refresh, and the 10s sampler. After
the first read the hot poll only calls LHM Update() for live temps.

Fixes ultra-audit finding P2 #14.

Regression test (integration): EnrichStorageNames_ResolvesOnce_AndCachesFriendlyNames
drives the private enricher twice and asserts the cache field is populated once and
reference-stable (CollectAsync degrades to empty on a WMI-less CI host but still
caches, so the assertion is deterministic).
await _enrichGate.WaitAsync().ConfigureAwait(false);
try
{
if (_cachedStorageFriendlyNames is null)
@laurentiu021 laurentiu021 merged commit 7cd2259 into main Jul 10, 2026
4 checks passed
@laurentiu021 laurentiu021 deleted the fix/temperature-memoize-diskname-poll branch July 10, 2026 22:07
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