Lot 16: what the watcher keeps - #13
Merged
Merged
Conversation
The refinement's read of the GPU Engine counters left some 3.7 MB and 19 handles in the watcher for the rest of its run: PdhCloseQuery frees the query, not what PDH loaded to resolve the counter path. GPU Engine is a V2 counter set, and Microsoft documents the PerfLib consumer functions for reading those with minimal overhead. The reader now finds the counter set and its counter by their English names, checks the counter's registered type (PERF_100NSEC_TIMER) before applying its formula, and walks the documented sample layout in plain code, every size bounded, tested on blocks built by hand. The same read now leaves 0.23 MB and 18 handles; its values match typeperf's over the same seconds. presence-probe gains menu-cost, which measured that one shell open leaves 141 handles and 1.2 MB and one update check 111 handles and 1 MB, and gpu-load, to set the reader beside typeperf. The Lot 16 page records the measurements and proposes what to do about the menu. Cargo.toml's comment on the registry feature still described the change notification Lot 15 measured never arrives; corrected. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The branch build installed, sampled once a second from outside while the maintainer played Battlefield 6 and used the menu: the refinement's read through PerfLib left 18 handles and 0.24 MB and named bf6.exe at 75%, as PDH did; the menu's first opening cost 41 handles and 1.1 MB, the shell open 147 handles. A configuration fault and its fix, twice, left nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Opened and closed again at 18:00 and 18:01, the menu left the watcher at 357 handles both times, its private bytes 4.18 then 4.22 MB: the 41 handles and 1.1 MB of its first opening are Windows' cost for a process's first menu, not a leak. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
presence-probe menu-cost gains menu and menu-dark: the tray's menu on a hidden window of a fresh process, shown three times and closed by a timer, with or without the SetPreferredAppMode call the tray makes at start. Both cost 55 handles and some 0.7 MB the first time and nothing after; the call itself costs a handle. The menu's cost is Windows', not the undocumented call's. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The previous commit went in with cargo fmt --check failing on it; the test script is green again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ShellExecute leaves the shell's machinery in its caller for the rest of the process's life: 141 handles and 1.2 MB after a first open, and 84 handles more when the log was opened after the configuration. The menu's four entries now start the watcher's own executable with a hidden `open` command, which makes the one call and exits; the watcher keeps what a plain CreateProcess keeps, two handles. The helper does what Microsoft documents for a caller that exits right after the call: COM as a single-threaded apartment first, and ShellExecuteExW with SEE_MASK_NOASYNC, plus SEE_MASK_FLAG_LOG_USAGE for a launch the user asked for. A file with no associated program still opens in Notepad. The watcher passes the helper the right to bring its window to the front and says in the log how the open went. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The helper's build installed and used from the menu at 23:44: the configuration, the log and the documentation opened in front, three handles kept for the three where the build without it had kept 147 and 84. How it works gains a section with the measured figures, and the lot page a table against 0.3.0, saying where 0.3.0's side comes from. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The three PerfLib calls that size their answer and are asked again now try four times and give no opinion after, instead of looping on the engine's thread for as long as Windows says the buffer is too small. The helper's failure line no longer says Notepad was tried for an address. AGENTS.md points at the open helper where it named ShellExecuteW, and its cost principle says to measure what a call leaves. The lot is marked done. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Lot 16, What the watcher keeps: where the handles and memory the installed watcher gained over its first sessions came from, and what was done about them. Measured step by step, then on the whole installed process on the maintainer's machine through a Battlefield 6 session, a five-hour GTA Online session and the menu.
What changed for the person running it
PdhCloseQueryfrees the query, not what PDH loaded to resolve the counter path. GPU Engine is a V2 counter set, and Microsoft documents the PerfLib consumer functions for reading those with minimal overhead. The reader finds the set and the counter by their English names, checks the counter's registered type (PERF_100NSEC_TIMER) before applying its documented formula, and walks the documented sample layout in plain code, every size bounded, tested on hand-built blocks. It now leaves 0.24 MB and 18 handles; checked againsttypeperf, then in the field: bf6.exe (75% of the rendering), as PDH said on 2026-09-16.ShellExecuteleaves the shell's machinery in its caller: 147 handles for Edit configuration, 84 more for Open log. The watcher now starts its own executable with a hiddenopencommand, which does what Microsoft documents for a caller that exits right after (STA COM,ShellExecuteExWwithSEE_MASK_NOASYNC) and ends. Verified from the menu: all three entries open in front, three handles kept for the three.Left as they are, by decision: the menu's own first opening (some 50 handles and 1 MB, Windows' cost for a process's first menu, the same with or without the dark-mode call, paid once) and Check for updates (111 handles and 1 MB, a click made once a release).
Sessions, reloads and configuration faults were measured to leave nothing.
For the reviewer
src/detect/gpu.rs: rewritten on PerfLib; the three calls that size their answer are bounded to four attempts, since the refinement runs on the engine's thread.src/open.rs,cli.rs(open, hidden),tray.rs: the helper and its callers.presence-probe:menu-cost <open|check|spawn|menu|menu-dark>andgpu-load, the instruments behind the figures.Cargo.toml:Win32_System_Comfor the helper; the registry feature's comment corrected (it still described the change notification Lot 15 measured never arrives).AGENTS.md: the cost principle says to measure what a call leaves, not only what it takes; the menu pitfall points at the helper.One commit (
1c8c3ec) went in withcargo fmt --checkfailing;ecb6ff1fixes it rather than rewriting history.scripts\build.ps1 testgreen locally, 207 tests.🤖 Generated with Claude Code