Remove game log backpressure and measure Windows K/M kernels

This commit is contained in:
Codex committed 2026-10-01 18:37:14 +03:00
1 parent 74395b6aef
commit 40d9a55e10
13 files changed
+437 -9

No files matched your search

+4
View File
@@ -15,6 +15,7 @@ public static class D4RWindowCapture {
[DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr window, out Rect rect);
[DllImport("user32.dll",CharSet=CharSet.Unicode)] public static extern int GetWindowText(IntPtr window, StringBuilder text, int count);
[DllImport("user32.dll")] public static extern bool IsWindowVisible(IntPtr window);
[DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")] public static extern IntPtr SetThreadDpiAwarenessContext(IntPtr context);
}
'@
@@ -39,6 +40,9 @@ $callback = [D4RWindowCapture+Callback]{ param($window,$data)
$windows | Select-Object handle,title,visible,area | Format-Table
$chosen = $windows | Where-Object { $_.visible -and $_.area -gt 4096 } | Sort-Object area -Descending | Select-Object -First 1
if (!$chosen) { throw "No visible game window for PID $GameProcessId" }
if ([D4RWindowCapture]::GetForegroundWindow() -ne $chosen.handle) {
throw 'Game window is not foreground; capture refused to avoid including unrelated overlapping windows.'
}
$rect = $chosen.rect
$bitmap = [Drawing.Bitmap]::new($rect.Right-$rect.Left,$rect.Bottom-$rect.Top)
$graphics = [Drawing.Graphics]::FromImage($bitmap)
+3 -1
View File
@@ -49,6 +49,7 @@ Stage (Join-Path $repo 'scripts/windows/windows-game.ps1') 'windows-game.ps1'
Stage (Join-Path $repo 'scripts/windows/capture-game-window.ps1') 'capture-game-window.ps1'
Stage (Join-Path $repo 'scripts/windows/send-game-key.ps1') 'send-game-key.ps1'
Stage (Join-Path $repo 'docs/windows-game.md') 'README.md'
Stage (Join-Path $repo 'docs/windows-performance.md') 'windows-performance.md'
Stage (Join-Path $repo 'LICENSE') 'licenses/d4r.txt'
Stage (Join-Path $OptiScalerRoot 'GPL-3.0.txt') 'licenses/OptiScaler.txt'
Stage (Join-Path $repo 'external/ZLUDA/LICENSE-MIT') 'licenses/ZLUDA-MIT.txt'
@@ -62,8 +63,9 @@ foreach ($patch in Get-ChildItem -LiteralPath (Join-Path $repo 'patches/zluda')
$metadata = [ordered]@{
architecture='gfx1201'; nativeKernels=16; dlssSha256='3975567b8943c53acce397f2b72380092f84f162d00b0d2c7d08a1025c563983';
d4rCommit=(& git -C $repo rev-parse HEAD).Trim();
d4rWorkingTreeDirty=[bool](& git -C $repo status --porcelain);
optiScaler=(Get-Content -LiteralPath (Join-Path $OptiScalerRoot 'build-info.json') -Raw | ConvertFrom-Json);
zludaCommit=(& git -C (Join-Path $repo 'external/ZLUDA') rev-parse HEAD).Trim();
zludaBuild=(Get-Content -LiteralPath (Join-Path $ZludaRoot 'build-info.json') -Raw | ConvertFrom-Json);
hipRuntime='TheRock 10.2.0a20260929 / HIP 7.17.26386';
files=@($stagedFiles | ForEach-Object { Get-Item -LiteralPath (Join-Path $PackageRoot $_) } | ForEach-Object {
@{path=$_.FullName.Substring($PackageRoot.Length+1); sha256=(Get-FileHash -LiteralPath $_.FullName -Algorithm SHA256).Hash; version=$_.VersionInfo.FileVersion}
+30
View File
@@ -0,0 +1,30 @@
[CmdletBinding()]
param(
[ValidateSet(11,13)][int]$Preset = 11,
[string]$ZludaRoot, [string]$PackageRoot, [string]$OutputDirectory,
[int]$Iterations = 4,
[switch]$Translated
)
$ErrorActionPreference='Stop'
$repo=[IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
if (!$ZludaRoot) { $ZludaRoot=Join-Path $repo 'dist/zluda-windows-profile' }
if (!$PackageRoot) { $PackageRoot=Join-Path $repo 'dist/windows-rdna4-command-list' }
if (!$OutputDirectory) { $OutputDirectory=Join-Path $repo ('test-results/profile-' + $Preset + '-' + (Get-Date -Format 'yyyyMMdd-HHmmss-fff')) }
$settings=@{D4R_ZLUDA_PROFILE='1'; D4R_PROFILE_STAGES='1'; D4R_VALIDATE_OUTPUT='1';
D4R_ZLUDA_NATIVE_DIR=$(if ($Translated) { $null } elseif ($Preset -eq 11) { Join-Path $repo 'build/native-k-gfx1201' } else { Join-Path $repo 'build/native-m-gfx1201' })}
$old=@{}
try {
foreach ($key in $settings.Keys) { $old[$key]=[Environment]::GetEnvironmentVariable($key,'Process'); [Environment]::SetEnvironmentVariable($key,$settings[$key],'Process') }
$arguments=@{RuntimeProfile='therock'; ZludaRoot=$ZludaRoot; PackageRoot=$PackageRoot; OutputDirectory=$OutputDirectory;
NgxCore=(Join-Path $repo '_nvngx.dll'); DlssDll=(Join-Path $repo 'nvngx_dlss.dll'); NgxMode='d3d12';
NgxAbi='project-legacy'; Preset=$Preset; NgxOnly=$true; RequireNativeNetwork=(!$Translated); CommandListBackend=$true;
CaptureExceptions=$true; EarlyIndirectProbe=$true; PixelProfile='depth-stencil'; BarrierMode='inherited-legacy';
Iterations=$Iterations; TimeoutSeconds=300; OptiScalerDll=(Join-Path $repo 'dist/optiscaler-windows-d4r/OptiScaler.dll')}
& (Join-Path $PSScriptRoot 'test-windows-rdna4.ps1') @arguments
if ($LASTEXITCODE) { throw 'Profiling workload failed; see diagnostic bundle.' }
$python=(Get-Command python.exe -ErrorAction Stop).Source
& $python (Join-Path $repo 'tools/windows/profile_report.py') $OutputDirectory --output (Join-Path $OutputDirectory 'profile.json')
if ($LASTEXITCODE) { throw 'No usable profile records.' }
} finally {
foreach ($key in $old.Keys) { [Environment]::SetEnvironmentVariable($key,$old[$key],'Process') }
}
+30 -3
View File
@@ -8,6 +8,8 @@ param(
[string]$DiagnosticResolution,
[string]$CacheDirectory = $env:ZLUDA_CACHE_DIR,
[switch]$ValidateOutput,
[switch]$ProfileStages,
[switch]$VerboseRuntime,
[string[]]$GameArguments = @('-dx12','-windowed','-ResX=1280','-ResY=720'),
[string]$OutputDirectory
)
@@ -108,7 +110,7 @@ RestoreGraphicSignature=false
ExtendedStateRestore=false
[Log]
LogToFile=true
LogLevel=0
LogLevel=$(if ($VerboseRuntime) { 0 } else { 2 })
[Menu]
DisableSplash=true
"@
@@ -129,11 +131,18 @@ $settings = @{
D4R_FORMAT_MODULE=(GamePath 'd4r/pixel_convert_gfx1201.hsaco');
D4R_ZLUDA_NATIVE_DIR=(GamePath 'd4r/native'); D4R_D3D12_COMMAND_BACKEND='1'; D4R_ZLUDA_VERBOSE='1';
D4R_ZLUDA_WMMA='1'; D4R_ZLUDA_WMMA_FP8='1'; D4R_ZLUDA_WMMA_FP8_NATIVE='0'; D4R_ZLUDA_WMMA_F16_REFERENCE='1';
# Do not inherit relaxation flags from unrelated experiments. Unset and
# false have the same numerical effect; unset reuses the validated cache.
D4R_ZLUDA_IGNORE_DENORMAL=$null; D4R_ZLUDA_FAST_MATH=$null;
D4R_ZLUDA_WMMA_F32ACC=$null; D4R_ZLUDA_WAVE64=$null;
D4R_QUIET_API=$(if ($VerboseRuntime) { $null } else { '1' });
D4R_DIAG_DIR=$OutputDirectory; ZLUDA_LOG_DIR=(Join-Path $OutputDirectory 'zluda-trace');
ZLUDA_CACHE_DIR=$CacheDirectory; PATH=((GamePath 'd4r/hip/bin') + ';' + (GamePath 'd4r/zluda') + ';' + $env:PATH)
}
$old = @{}; $process = $null; $originalSettings = @()
$outFile = $null; $errFile = $null; $outTask = $null; $errTask = $null
if ($ValidateOutput) { $settings['D4R_VALIDATE_OUTPUT']='1' }
if ($ProfileStages) { $settings['D4R_PROFILE_STAGES']='1' }
try {
if ($DiagnosticResolution) {
if ([IO.Path]::GetFileName($GameExe) -ne 'SHProto-Win64-Shipping.exe' -or $DiagnosticResolution -notmatch '^([0-9]{3,4})x([0-9]{3,4})$') { throw 'DiagnosticResolution currently supports Silent Hill 2 only; use e.g. 1280x720.' }
@@ -168,14 +177,28 @@ try {
ConvertTo-Json -Depth 12 | Set-Content -LiteralPath (Join-Path $OutputDirectory 'environment.json') -Encoding UTF8
function Quote([string]$value) { if ($value.Contains('"')) { throw 'A command argument contains an unsupported quote.' }; return '"' + $value + '"' }
$arguments = @('--output-directory', (Quote $OutputDirectory), '--', (Quote $GameExe)) + @($GameArguments | ForEach-Object { Quote $_ })
$process = Start-Process -FilePath (GamePath 'd4r/d4r_debug_launcher.exe') -ArgumentList $arguments -WorkingDirectory $game -WindowStyle Hidden -PassThru `
-RedirectStandardOutput (Join-Path $OutputDirectory 'd4r.stdout.log') -RedirectStandardError (Join-Path $OutputDirectory 'd4r.stderr.log')
# Drain raw bytes concurrently. PowerShell's line-oriented redirection can
# throttle a verbose game and distort the very timings we are collecting.
$info = [Diagnostics.ProcessStartInfo]::new()
$info.FileName = GamePath 'd4r/d4r_debug_launcher.exe'
$info.Arguments = $arguments -join ' '
$info.WorkingDirectory = $game
$info.UseShellExecute = $false; $info.CreateNoWindow = $true
$info.RedirectStandardOutput = $true; $info.RedirectStandardError = $true
$process = [Diagnostics.Process]::new(); $process.StartInfo = $info
if (!$process.Start()) { throw 'Game debugger launch failed.' }
$outFile = [IO.File]::Open((Join-Path $OutputDirectory 'd4r.stdout.log'), [IO.FileMode]::Create, [IO.FileAccess]::Write, [IO.FileShare]::Read)
$errFile = [IO.File]::Open((Join-Path $OutputDirectory 'd4r.stderr.log'), [IO.FileMode]::Create, [IO.FileAccess]::Write, [IO.FileShare]::Read)
$outTask = $process.StandardOutput.BaseStream.CopyToAsync($outFile)
$errTask = $process.StandardError.BaseStream.CopyToAsync($errFile)
Write-Host "Game diagnostic started (preset $Preset). Logs: $OutputDirectory"
$timer = [Diagnostics.Stopwatch]::StartNew()
while (!$process.WaitForExit(1000)) {
if ($RunSeconds -gt 0 -and $timer.Elapsed.TotalSeconds -ge $RunSeconds) { $process.Kill(); $process.WaitForExit(); break }
}
$process.WaitForExit()
[void]$outTask.GetAwaiter().GetResult(); [void]$errTask.GetAwaiter().GetResult()
$outFile.Dispose(); $outFile = $null; $errFile.Dispose(); $errFile = $null
foreach ($file in Get-ChildItem -LiteralPath $game -Filter 'OptiScaler*.log' -File) { Copy-Item -LiteralPath $file.FullName -Destination $OutputDirectory -Force }
$stderr = Get-Content -LiteralPath (Join-Path $OutputDirectory 'd4r.stderr.log') -Raw
$stdout = Get-Content -LiteralPath (Join-Path $OutputDirectory 'd4r.stdout.log') -Raw
@@ -201,6 +224,10 @@ try {
Write-Host "Game diagnostic bundle: $OutputDirectory.zip"
} finally {
if ($process -and !$process.HasExited) { $process.Kill(); $process.WaitForExit() }
if ($outTask) { try { [void]$outTask.GetAwaiter().GetResult() } catch {} }
if ($errTask) { try { [void]$errTask.GetAwaiter().GetResult() } catch {} }
if ($outFile) { $outFile.Dispose() }; if ($errFile) { $errFile.Dispose() }
if ($process) { $process.Dispose() }
foreach ($key in $old.Keys) { [Environment]::SetEnvironmentVariable($key,$old[$key],'Process') }
foreach ($entry in $originalSettings) { Copy-Item -LiteralPath $entry.saved -Destination $entry.path -Force }
}