waybetter/dev-tools/native-stress-watch.ps1
CRT 5c64f2f6f8 dev-tools: the generic development harnesses (perf probes, close check, tab and webview stress)
Moved from wayBetter for X; an app passes its own origin, process name, scripts and fixtures.
2026-09-30 14:48:06 +07:00

57 lines
2.6 KiB
PowerShell

param(
[Parameter(Mandatory = $true)][int]$AppPid,
[Parameter(Mandatory = $true)][string]$OutputPath,
[int]$Seconds = 90,
[int]$IntervalSeconds = 2,
[int]$AbortAtWorkingSetMB = 0,
[string]$ExpectedExecutable = ''
)
# Independent telemetry for native-webview-stress.mjs. Follow only descendants of the
# isolated app PID; a hung shell CDP target cannot stop this watcher from recording CPU.
$previousCpu = @{}
$watch = [System.Diagnostics.Stopwatch]::StartNew()
while ($watch.Elapsed.TotalSeconds -lt $Seconds) {
$all = @(Get-CimInstance Win32_Process | Select-Object ProcessId, ParentProcessId)
$ids = @($AppPid)
do {
$children = @($all | Where-Object {
$ids -contains $_.ParentProcessId -and $ids -notcontains $_.ProcessId
} | Select-Object -ExpandProperty ProcessId)
$ids += $children
} while ($children.Count -gt 0)
$processes = @(Get-Process -Id $ids -ErrorAction SilentlyContinue)
if (-not ($processes | Where-Object Id -EQ $AppPid)) { break }
$rows = @($processes | ForEach-Object {
$cpu = if ($null -eq $_.CPU) { 0 } else { [double]$_.CPU }
$before = if ($previousCpu.ContainsKey($_.Id)) { $previousCpu[$_.Id] } else { $cpu }
$previousCpu[$_.Id] = $cpu
[pscustomobject]@{
pid = $_.Id
name = $_.ProcessName
cpuDeltaSeconds = [math]::Round($cpu - $before, 3)
cpuTotalSeconds = [math]::Round($cpu, 3)
workingSetMB = [math]::Round($_.WorkingSet64 / 1MB)
privateMB = [math]::Round($_.PrivateMemorySize64 / 1MB)
}
} | Sort-Object cpuDeltaSeconds -Descending)
$totalWorkingSetMB = ($rows | Measure-Object workingSetMB -Sum).Sum
[pscustomobject]@{
elapsedSeconds = [math]::Round($watch.Elapsed.TotalSeconds, 2)
processCount = $rows.Count
totalCpuDeltaSeconds = [math]::Round(($rows | Measure-Object cpuDeltaSeconds -Sum).Sum, 3)
totalWorkingSetMB = $totalWorkingSetMB
top = @($rows | Select-Object -First 8)
} | ConvertTo-Json -Depth 5 -Compress | Add-Content -LiteralPath $OutputPath
if ($AbortAtWorkingSetMB -gt 0 -and $totalWorkingSetMB -ge $AbortAtWorkingSetMB) {
$app = Get-CimInstance Win32_Process -Filter "ProcessId=$AppPid"
if ($app -and $ExpectedExecutable -and $app.ExecutablePath -ieq $ExpectedExecutable) {
[pscustomobject]@{ event = 'memory-abort'; appPid = $AppPid; workingSetMB = $totalWorkingSetMB } |
ConvertTo-Json -Compress | Add-Content -LiteralPath $OutputPath
Stop-Process -Id $AppPid -Force
}
break
}
Start-Sleep -Seconds $IntervalSeconds
}