The probe's sample plumbing leaves the gate module (the gate never kills; the probe may kill its own hung child). The counter path is one exported constant passed to the script as -Util3dPath, the script reports how many 3D engine counters resolved, and a child that is alive but silent for 3 intervals is killed and respawned. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
24 lines
1.4 KiB
PowerShell
24 lines
1.4 KiB
PowerShell
# One sample line per interval: {"quns":n,"freeMiB":n,"util3d":n,"engines":n}. Numbers only; no process
|
|
# identity is read. engines is how many 3D-engine counters the path resolved: zero means the path is
|
|
# wrong, and the gate treats that as a probe fault.
|
|
param([int]$ParentPid, [int]$IntervalMs = 15000, [string]$Util3dPath)
|
|
$ErrorActionPreference = 'Stop'
|
|
Add-Type -Namespace Vili -Name Shell -MemberDefinition '[DllImport("shell32.dll")] public static extern int SHQueryUserNotificationState(out int state);'
|
|
while ($true) {
|
|
$clock = [Diagnostics.Stopwatch]::StartNew()
|
|
if (-not (Get-Process -Id $ParentPid -ErrorAction SilentlyContinue)) { exit }
|
|
try {
|
|
$quns = 0
|
|
if ([Vili.Shell]::SHQueryUserNotificationState([ref]$quns) -ne 0) { throw 'quns' }
|
|
$smi = @(nvidia-smi.exe --query-gpu=memory.free --format=csv,noheader,nounits)
|
|
if ($LASTEXITCODE -ne 0) { throw 'smi' }
|
|
$free = $smi[0]
|
|
$counters = @((Get-Counter $Util3dPath -SampleInterval 1 -MaxSamples 1).CounterSamples)
|
|
$sum = $counters | Measure-Object -Property CookedValue -Sum
|
|
$line = [ordered]@{ quns = [int]$quns; freeMiB = [int]$free; util3d = [math]::Min(100, [math]::Round([double]$sum.Sum, 1)); engines = $counters.Count } | ConvertTo-Json -Compress
|
|
[Console]::Out.WriteLine($line)
|
|
[Console]::Out.Flush()
|
|
} catch { }
|
|
$rest = $IntervalMs - $clock.ElapsedMilliseconds
|
|
if ($rest -gt 0) { Start-Sleep -Milliseconds $rest }
|
|
}
|