vdi-cloud/tools/validate-sunshine-nvenc.ps1

106 lines
4.5 KiB
PowerShell
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

param(
[string]$SunshineLogPath = "",
[int]$MaxLogAgeMinutes = 30
)
# 只读验收脚本:不重启 VM、设备、VFIO 或 Sunshine,不修改任何配置。
# 退出码 0 才表示当前状态满足“可继续做串流性能验收”的前置条件。
$ErrorActionPreference = "Stop"
$ok = $true
function Report([string]$Name, [bool]$Passed, [string]$Detail) {
$state = if ($Passed) { "PASS" } else { "FAIL" }
Write-Output ("[{0}] {1}: {2}" -f $state, $Name, $Detail)
}
$nvidiaCommand = Get-Command nvidia-smi -ErrorAction SilentlyContinue
if ($null -eq $nvidiaCommand) {
Report "nvidia-smi" $false "命令不存在"
$ok = $false
} else {
$ErrorActionPreference = 'Continue'
$gpuText = & $nvidiaCommand.Source --query-gpu=name,driver_version,pstate --format=csv,noheader 2>&1
$queryExitCode = $LASTEXITCODE
$ErrorActionPreference = 'Stop'
if ($queryExitCode -ne 0 -or [string]::IsNullOrWhiteSpace(($gpuText -join ""))) {
Report "nvidia-smi" $false (($gpuText -join " ").Trim())
$ok = $false
} else {
Report "nvidia-smi" $true (($gpuText -join " ").Trim())
}
}
try {
$displayAdapters = @(Get-CimInstance Win32_VideoController |
Where-Object { $_.Name -match "NVIDIA|GeForce|Quadro|Tesla" })
$healthy = @($displayAdapters | Where-Object { $_.ConfigManagerErrorCode -eq 0 }).Count -gt 0
Report "NVIDIA PnP" $healthy (($displayAdapters | ForEach-Object { "$($_.Name): code=$($_.ConfigManagerErrorCode)" }) -join "; ")
$ok = $ok -and $healthy
if (-not ('VdiDiagnostics.D3DProbe' -as [type])) {
Add-Type -Path (Join-Path $PSScriptRoot 'probe-nvidia-d3d.cs')
}
$dxgi = @([VdiDiagnostics.D3DProbe]::Check())
$healthy = @($dxgi | Where-Object { $_.DeviceResult -eq 0 }).Count -gt 0
$detail = if ($dxgi.Count) { ($dxgi | ForEach-Object { '{0}: HRESULT=0x{1:X8}' -f $_.Name,$_.DeviceResult }) -join '; ' } else { 'DXGI did not enumerate an NVIDIA adapter' }
Report "NVIDIA DXGI + D3D11" $healthy $detail
$ok = $ok -and $healthy
} catch {
Report "NVIDIA DXGI + D3D11" $false $_.Exception.Message
$ok = $false
}
if ([string]::IsNullOrWhiteSpace($SunshineLogPath)) {
$candidates = @(
"C:\Program Files\Sunshine\config\sunshine.log",
"C:\ProgramData\Sunshine\config\sunshine.log"
)
$SunshineLogPath = $candidates | Where-Object { Test-Path -LiteralPath $_ } | Select-Object -First 1
}
if ([string]::IsNullOrWhiteSpace($SunshineLogPath) -or -not (Test-Path -LiteralPath $SunshineLogPath)) {
Report "Sunshine encoder" $false "找不到 sunshine.log;不能证明实际使用 h264_nvenc"
$ok = $false
} else {
# Encoder discovery/probing can mention both NVENC and x264. Inspect only
# the most recent actual creation, with a timestamp, never the entire history.
$pattern = '\[(?<time>\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d+)\].*Creating encoder \[(?<encoder>[^\]]+)\]'
$matches = [regex]::Matches((Get-Content -LiteralPath $SunshineLogPath -Raw), $pattern)
$healthy = $false
$detail = '没有实际编码器创建记录;请连接Moonlight并播放测试动画'
if ($matches.Count -gt 0) {
$entry = $matches[$matches.Count - 1]
$encoder = $entry.Groups['encoder'].Value
$createdAt = [datetime]::Parse($entry.Groups['time'].Value, [Globalization.CultureInfo]::InvariantCulture)
$ageMinutes = ((Get-Date) - $createdAt).TotalMinutes
$healthy = $encoder -eq 'h264_nvenc' -and $ageMinutes -ge 0 -and $ageMinutes -le $MaxLogAgeMinutes
$detail = '{0}, created {1}, age {2:N1} min' -f $encoder,$createdAt,$ageMinutes
}
Report "Sunshine active encoder" $healthy $detail
$ok = $ok -and $healthy
}
if ($nvidiaCommand) {
$ErrorActionPreference = 'Continue'
$activity = & $nvidiaCommand.Source --query-gpu=encoder.stats.sessionCount,utilization.encoder --format=csv,noheader,nounits 2>&1
$queryExitCode = $LASTEXITCODE
$ErrorActionPreference = 'Stop'
$healthy = $false
if ($queryExitCode -eq 0) {
foreach ($row in $activity) {
if ([string]$row -match '^\s*(\d+),\s*(\d+)\s*$') {
if ([int]$Matches[1] -gt 0 -and [int]$Matches[2] -gt 0) { $healthy = $true }
}
}
}
Report "NVENC session/utilization" $healthy ($activity -join '; ')
$ok = $ok -and $healthy
}
if ($ok) {
Write-Output "GPU/NVENC 前置验收通过:可以继续做 Moonlight 帧率与延迟测试。"
exit 0
}
Write-Output "GPU/NVENC 前置验收失败:不要把当前状态作为硬编码性能结果。"
exit 1