Tracking Background GPU Activity and an Unused Virtual Display
Tracking Background GPU Activity and an Unused Virtual Display
After remote use, an apparently idle Windows desktop may still have a background application waking the discrete GPU, while a Mac virtual ultrawide display remains enabled. These are separate systems and require separate evidence.
This article combines LegionZone attribution and RustDesk display-cleanup records: identify resource users, establish session state, then consider a configuration change or display action. Historical GPU observations remain intact; the original single-connection cleanup script is not presented as validated automation.
Device 0% does not establish zero engine activity
Task Manager engines and NVIDIA SMI device utilization, power, and P-state have different semantics. Do not add 3D, Copy, and Video Encode percentages into a device total. Short rendering activity and a 0% device sample can occur in different windows. Task Manager GPU metrics
Fix external displays, power source, MUX/hybrid mode, application windows, and monitoring polling. Align engine/device timestamps before closing a candidate. Do not simultaneously switch GPU mode, update drivers, and disable displays.
| State | Recorded observations | Supported interpretation |
|---|---|---|
| LegionZone running | 30 loops, 26 above-threshold engine records; old Mean 9.1, Peak 20.7; 11.87 W, P5 | Candidate activity, not device-wide average utilization |
| Fully exited | NONE above 1%; 7.61 W, P8 | Activity fell in that window, not strict zero on every engine |
| Preference written and app restarted | NONE above 1%; 7.61 W, P5 | No above-threshold activity, without proof of iGPU migration |
26 counts engine records; multiple engines may match one PID in a sample. It is not a 26/30 time fraction. Mean 9.1 excludes low records. Calls plus sleeps did not produce an exact 60-second span; historical tool execution took about 95 seconds. Use timestamps.
Preserve engine instances before aggregation
This read-only PowerShell example writes a new CSV and has not received a new Windows runtime test. English counter paths may be localized; inspect Get-Counter -ListSet first.
$gpuSamples = Get-Counter -Counter '\GPU Engine(*)\Utilization Percentage' `
-SampleInterval 2 -MaxSamples 30 -ErrorAction Stop
$gpuRows = foreach ($sample in $gpuSamples) {
foreach ($counter in $sample.CounterSamples) {
[pscustomobject]@{
Timestamp = $sample.Timestamp.ToString('o')
Instance = $counter.InstanceName
Status = $counter.Status
Value = $counter.CookedValue
}
}
}
$gpuCsv = Join-Path $env:TEMP ('gpu-engines-' + [guid]::NewGuid().ToString('N') + '.csv')
$gpuRows | Export-Csv -LiteralPath $gpuCsv -NoTypeInformation -Encoding UTF8
$gpuCsvKeep PID, adapter LUID, physical index, and engine type. Match process path and start time: a reused PID does not identify an earlier process. Count invalid status, parsing failures, and missing samples separately rather than filling them with zero. Redact personal paths before sharing.
nvidia-smi --query-gpu=timestamp,name,pstate,power.draw,utilization.gpu --format=csv -l 2Keep unsupported fields as N/A; an empty process table is not proof of no graphics workload. NVIDIA SMI
Attribution and GPU migration need different acceptance
The exit-related decrease supports investigating LegionZone. Repeat A/B/A under fixed conditions to strengthen attribution. The record restored 6 processes but did not sufficiently establish recurrence of the original load.
The historical GpuPreference=2; was incorrectly called an iGPU preference. In the formal DXGI enumeration, 2 means high performance rather than minimum power; that API enum is not a complete registry-format specification. No blind numeric registry fix is provided. DXGI GPU preference
In the actual desktop user's Windows Graphics settings, select the current executable, record its original preference, choose power saving with the named GPU, fully restart it, and confirm its actual engine/device in Task Manager. A maintenance account's HKCU is a different user's configuration. Dedicated-only mode may make the iGPU unavailable. Test tray, sensor, and device-control functions before claiming no functional loss. Windows graphics preference workflow
Restore only that application's original option. P8 after exit and P5 after restart are distinct, even at the same power. Two readings do not establish long-term energy savings.
RustDesk logs are a session proxy, not an authoritative API
The Mac record aimed to close a 43:18 virtual display 15 minutes after disconnection. Logs contained connection IDs, opened/closed events, and loop-exited messages. A relay transport connection or listening port does not establish active remote desktop use.
tail -n 100 "$HOME/Library/Logs/RustDesk/RustDesk_rCURRENT.log"Observe the installed version's actual format and pair it with a complete connect/disconnect cycle. “Opened” may precede authenticated desktop control. The case does not establish that every RustDesk version lacks a session API or justify guessing an undocumented IPC protocol.
The original script checked only the last opened connection and its close. Earlier active sessions were missed; rotation, process restart, reused IDs, and lost logs were unhandled. Its stated manual-reopen flag reset was also absent: only the active branch cleared the flag.
Use a conservative state machine before enabling actions
Run a decision-only observer first:
Read connection events from a known boundary
Track all open connections by process lifetime and connection ID
Any unclosed connection → ACTIVE
Unresolved rotation/restart/missing log/parse failure/clock reversal → UNKNOWN
Continuous trusted observation with all sessions closed → IDLE(last_all_closed)
IDLE for 15 minutes → propose closing the target display only
UNKNOWN or ACTIVE → no display actionA known boundary matters. The last 100 lines cannot establish that older sessions ended. Initial deployment, absent connections, or corrupt logs must not default to idle. Observe a complete cycle to establish continuity, and reset certainty after restart.
| Input | Expected decision |
|---|---|
| A opens, B opens, B closes | ACTIVE: A remains |
| A and B close, trusted idle reaches 15 minutes | May propose closure |
| Missing or unreadable log | UNKNOWN |
| Close without corresponding open | UNKNOWN |
| Unresolved process restart or rotation | UNKNOWN; rebuild baseline |
| User manually reopens the display | Explicit exemption or a new idle cycle |
These are revised acceptance requirements, not a newly executed automatic-close experiment. Preserve the display when the observer cannot establish absence of users.
Validate the display action independently
The old connected@VirtualScreen:160 preference was specific to that object/version. Restarting all of BetterDisplay can affect other displays. Inspect the current supported integration/CLI and identify the target before a single-display trial. BetterDisplay integrations
Record physical and virtual displays, stable identity, state, and original settings. Test closure with an available recovery path; verify the physical display remains usable. Do not mark an action complete after failure. A manual reopen should override automation rather than be undone two minutes later.
Keep collection, session classification, and actions independently stoppable. Disabling actions should preserve telemetry; stop the schedule and restore the display manually when necessary. Windows graphics preferences roll back separately. Moonlight/Sunshine troubleshooting covers encoding failures at another layer.
The date is the main KB's first Git commit date, 2026-09-15 (UTC+8), commit a13b11a. Merged sources are retained in metadata; historical operation dates are separate from repository dates. Revised configuration examples were not executed on production devices.
