Files
Qt_DesktopPet/tools/perf_sample.ps1
T
2026-05-31 16:27:49 +08:00

172 lines
5.4 KiB
PowerShell

param(
[string]$ProcessName = "QtDesktopPet",
[Alias("Pid")]
[int]$ProcessId = 0,
[ValidateRange(1, 86400)]
[int]$IntervalSeconds = 5,
[ValidateRange(1, 604800)]
[int]$DurationSeconds = 300,
[string]$OutputPath = "reports/perf"
)
Set-StrictMode -Version Latest
$ErrorActionPreference = "Stop"
function Resolve-TargetProcess {
param(
[string]$Name,
[int]$Id
)
if ($Id -gt 0) {
return Get-Process -Id $Id -ErrorAction SilentlyContinue
}
$processes = @(Get-Process -Name $Name -ErrorAction SilentlyContinue)
if ($processes.Count -eq 0) {
return $null
}
if ($processes.Count -gt 1) {
Write-Warning "Multiple processes named '$Name' were found. Sampling PID $($processes[0].Id). Use -Pid to target a specific process."
}
return $processes[0]
}
function Read-ProcessSnapshot {
param(
[System.Diagnostics.Process]$Process
)
$path = ""
try {
$path = $Process.Path
}
catch {
$path = ""
}
$responding = ""
try {
$responding = $Process.Responding
}
catch {
$responding = ""
}
return [pscustomobject]@{
TimestampUtc = (Get-Date).ToUniversalTime().ToString("o")
Pid = $Process.Id
CpuSeconds = [double]($Process.CPU)
WorkingSetMB = [math]::Round($Process.WorkingSet64 / 1MB, 2)
PrivateMemoryMB = [math]::Round($Process.PrivateMemorySize64 / 1MB, 2)
HandleCount = $Process.HandleCount
ThreadCount = $Process.Threads.Count
Responding = $responding
Path = $path
}
}
function New-OutputFilePath {
param(
[string]$Directory,
[string]$Name
)
if (-not (Test-Path -LiteralPath $Directory)) {
New-Item -ItemType Directory -Force -Path $Directory | Out-Null
}
$safeName = $Name -replace '[^a-zA-Z0-9._-]', '_'
$timestamp = Get-Date -Format "yyyyMMdd-HHmmss"
return Join-Path $Directory "$timestamp-$safeName.csv"
}
$target = Resolve-TargetProcess -Name $ProcessName -Id $ProcessId
if ($null -eq $target) {
if ($ProcessId -gt 0) {
Write-Error "Process with PID $ProcessId was not found."
}
else {
Write-Error "Process '$ProcessName' was not found. Start the app first or pass -Pid."
}
exit 1
}
$logicalProcessorCount = [Environment]::ProcessorCount
if ($logicalProcessorCount -lt 1) {
$logicalProcessorCount = 1
}
$outputFile = New-OutputFilePath -Directory $OutputPath -Name $target.ProcessName
$sampleCount = [math]::Max(1, [math]::Ceiling($DurationSeconds / $IntervalSeconds))
Write-Host "Sampling PID $($target.Id) ($($target.ProcessName)) every $IntervalSeconds seconds for up to $DurationSeconds seconds."
Write-Host "Output: $outputFile"
$previousSnapshot = Read-ProcessSnapshot -Process $target
$previousTime = Get-Date
$firstRow = [pscustomobject]@{
TimestampUtc = $previousSnapshot.TimestampUtc
Pid = $previousSnapshot.Pid
CpuPercent = 0
WorkingSetMB = $previousSnapshot.WorkingSetMB
PrivateMemoryMB = $previousSnapshot.PrivateMemoryMB
HandleCount = $previousSnapshot.HandleCount
ThreadCount = $previousSnapshot.ThreadCount
Responding = $previousSnapshot.Responding
Path = $previousSnapshot.Path
Status = "running"
}
$firstRow | Export-Csv -Path $outputFile -NoTypeInformation -Encoding UTF8
for ($index = 1; $index -le $sampleCount; $index++) {
Start-Sleep -Seconds $IntervalSeconds
$currentProcess = Get-Process -Id $target.Id -ErrorAction SilentlyContinue
if ($null -eq $currentProcess) {
[pscustomobject]@{
TimestampUtc = (Get-Date).ToUniversalTime().ToString("o")
Pid = $target.Id
CpuPercent = ""
WorkingSetMB = ""
PrivateMemoryMB = ""
HandleCount = ""
ThreadCount = ""
Responding = ""
Path = $previousSnapshot.Path
Status = "exited"
} | Export-Csv -Path $outputFile -NoTypeInformation -Encoding UTF8 -Append
Write-Warning "Process $($target.Id) exited. Sampling stopped."
break
}
$currentSnapshot = Read-ProcessSnapshot -Process $currentProcess
$currentTime = Get-Date
$elapsedSeconds = [math]::Max(0.001, ($currentTime - $previousTime).TotalSeconds)
$cpuPercent = (($currentSnapshot.CpuSeconds - $previousSnapshot.CpuSeconds) / $elapsedSeconds) * 100 / $logicalProcessorCount
if ($cpuPercent -lt 0) {
$cpuPercent = 0
}
[pscustomobject]@{
TimestampUtc = $currentSnapshot.TimestampUtc
Pid = $currentSnapshot.Pid
CpuPercent = [math]::Round($cpuPercent, 2)
WorkingSetMB = $currentSnapshot.WorkingSetMB
PrivateMemoryMB = $currentSnapshot.PrivateMemoryMB
HandleCount = $currentSnapshot.HandleCount
ThreadCount = $currentSnapshot.ThreadCount
Responding = $currentSnapshot.Responding
Path = $currentSnapshot.Path
Status = "running"
} | Export-Csv -Path $outputFile -NoTypeInformation -Encoding UTF8 -Append
$previousSnapshot = $currentSnapshot
$previousTime = $currentTime
}
Write-Host "Sampling finished."