106 lines
4.5 KiB
PowerShell
106 lines
4.5 KiB
PowerShell
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
|