101 lines
3.5 KiB
PowerShell
101 lines
3.5 KiB
PowerShell
[CmdletBinding()]
|
||
param(
|
||
[Parameter(Mandatory = $true)]
|
||
[string]$ExecutablePath,
|
||
|
||
[string[]]$ApplicationArguments = @(),
|
||
|
||
[ValidateRange(0.0167, 168)]
|
||
[double]$DurationHours = 24,
|
||
|
||
[ValidateRange(5, 3600)]
|
||
[int]$SampleIntervalSeconds = 60,
|
||
|
||
[ValidateRange(128, 16384)]
|
||
[int]$MaximumWorkingSetMb = 2048,
|
||
|
||
[string]$OutputDirectory = ""
|
||
)
|
||
|
||
$ErrorActionPreference = 'Stop'
|
||
$resolvedExecutable = [System.IO.Path]::GetFullPath($ExecutablePath)
|
||
if (-not (Test-Path -LiteralPath $resolvedExecutable -PathType Leaf)) {
|
||
throw 'Не найден исполняемый файл для soak-теста.'
|
||
}
|
||
|
||
$resolvedOutputDirectory = if ([string]::IsNullOrWhiteSpace($OutputDirectory)) {
|
||
Join-Path (Get-Location) 'artifacts\soak'
|
||
} else {
|
||
[System.IO.Path]::GetFullPath($OutputDirectory)
|
||
}
|
||
New-Item -ItemType Directory -Path $resolvedOutputDirectory -Force | Out-Null
|
||
$timestamp = Get-Date -Format 'yyyyMMdd-HHmmss'
|
||
$csvPath = Join-Path $resolvedOutputDirectory "runtime-soak-$timestamp.csv"
|
||
$summaryPath = Join-Path $resolvedOutputDirectory "runtime-soak-$timestamp.txt"
|
||
$deadline = [DateTimeOffset]::Now.AddHours($DurationHours)
|
||
$process = $null
|
||
$peakWorkingSetMb = 0.0
|
||
$samples = 0
|
||
|
||
try {
|
||
$workingDirectory = [System.IO.Path]::GetDirectoryName($resolvedExecutable)
|
||
$process = Start-Process `
|
||
-FilePath $resolvedExecutable `
|
||
-ArgumentList $ApplicationArguments `
|
||
-WorkingDirectory $workingDirectory `
|
||
-WindowStyle Hidden `
|
||
-PassThru
|
||
|
||
'Timestamp,WorkingSetMb,PrivateMemoryMb,Responding' | Set-Content -LiteralPath $csvPath -Encoding UTF8
|
||
while ([DateTimeOffset]::Now -lt $deadline) {
|
||
Start-Sleep -Seconds $SampleIntervalSeconds
|
||
$process.Refresh()
|
||
if ($process.HasExited) {
|
||
throw "Процесс завершился до окончания soak-теста: exit_code=$($process.ExitCode)."
|
||
}
|
||
|
||
$workingSetMb = [Math]::Round($process.WorkingSet64 / 1MB, 2)
|
||
$privateMemoryMb = [Math]::Round($process.PrivateMemorySize64 / 1MB, 2)
|
||
$peakWorkingSetMb = [Math]::Max($peakWorkingSetMb, $workingSetMb)
|
||
$samples++
|
||
[string]::Format(
|
||
[Globalization.CultureInfo]::InvariantCulture,
|
||
'{0:o},{1:F2},{2:F2},{3}',
|
||
[DateTimeOffset]::Now,
|
||
$workingSetMb,
|
||
$privateMemoryMb,
|
||
$process.Responding) |
|
||
Add-Content -LiteralPath $csvPath -Encoding UTF8
|
||
|
||
if ($workingSetMb -gt $MaximumWorkingSetMb) {
|
||
throw "Working set превысил безопасный предел $MaximumWorkingSetMb МБ."
|
||
}
|
||
}
|
||
|
||
@(
|
||
'Result=Passed'
|
||
"DurationHours=$DurationHours"
|
||
"Samples=$samples"
|
||
'PeakWorkingSetMb=' + $peakWorkingSetMb.ToString('F2', [Globalization.CultureInfo]::InvariantCulture)
|
||
"ProcessId=$($process.Id)"
|
||
) | Set-Content -LiteralPath $summaryPath -Encoding UTF8
|
||
} catch {
|
||
@(
|
||
'Result=Failed'
|
||
"DurationHours=$DurationHours"
|
||
"Samples=$samples"
|
||
'PeakWorkingSetMb=' + $peakWorkingSetMb.ToString('F2', [Globalization.CultureInfo]::InvariantCulture)
|
||
"ErrorType=$($_.Exception.GetType().Name)"
|
||
) | Set-Content -LiteralPath $summaryPath -Encoding UTF8
|
||
throw
|
||
} finally {
|
||
if ($null -ne $process -and -not $process.HasExited) {
|
||
$null = $process.CloseMainWindow()
|
||
if (-not $process.WaitForExit(10000)) {
|
||
Stop-Process -Id $process.Id -Force
|
||
}
|
||
}
|
||
}
|
||
|
||
Write-Output "Soak-тест завершён. Сводка: $summaryPath"
|