Files
dolphin/Tools/PerformanceTrace/Prepare-Native-Update-P1.ps1
Yaya48 c230971f07 IOS LLE: checkpoint NAND conformance and diagnostic tooling
Preserve formatted NAND boot and Wii Remote pairing, add DMA/SRAM conformance tests and a Wii comparison probe. Keep P1 profiling tools and native update A/B evidence; reject the unhelpful targeted SRAM shortcut.
2026-09-23 13:30:17 +02:00

111 lines
6.3 KiB
PowerShell

param(
[ValidatePattern('^P1-trace-[0-9]{3}$')][string]$Name='P1-trace-001',
[string]$BuildDirectory='.starlet_diag_p1',
[string]$RuntimeDirectory='.starlet_msvc2',
[Parameter(Mandatory=$true)][string]$PythonExecutable
)
# Create an independent, verified pre-update NAND and frozen diagnostic build.
# Never write to the user's normal NAND, the seed, or an existing experiment.
$ErrorActionPreference = 'Stop'
$p1Repo = [IO.Path]::GetFullPath((Join-Path $PSScriptRoot '../..'))
$p1Root = Join-Path $p1Repo '.starlet_update_ab_20260913'
$p1Profile = Join-Path $p1Root $Name
$p1Build = Join-Path $p1Root "build-$Name"
$p1SourceBuild = [IO.Path]::GetFullPath((Join-Path $p1Repo $BuildDirectory))
$p1RuntimeBuild = [IO.Path]::GetFullPath((Join-Path $p1Repo $RuntimeDirectory))
$p1SourceExe = Join-Path $p1SourceBuild 'Binaries/DolphinNoGUI.exe'
$p1SourcePDB = Join-Path $p1SourceBuild 'pdb/DolphinNoGUI.pdb'
$p1Seed = Join-Path $p1Root 'pre-update.nand-journal'
$p1JournalRelative = 'Starlet\0238188DE97894AE3AF93A92C4F238C0572731A7.nand-journal'
$p1Manifest = Get-Content -LiteralPath (Join-Path $p1Root 'manifest.json') -Raw | ConvertFrom-Json
$p1Expected = Get-Content -LiteralPath (Join-Path $p1Root 'initial-files-B.json') -Raw | ConvertFrom-Json
$p1Python = (Resolve-Path -LiteralPath $PythonExecutable).Path
if (Get-Process DolphinNoGUI,Dolphin -ErrorAction SilentlyContinue) {
throw 'Close the existing Dolphin instance before preparing a native-update run.'
}
foreach ($p1Target in @($p1Profile, $p1Build)) {
if (Test-Path -LiteralPath $p1Target) { throw "Refusing to overwrite $p1Target" }
}
foreach ($p1Required in @($p1Seed, $p1SourceExe, $p1SourcePDB,
(Join-Path $p1RuntimeBuild 'Binaries/Sys'),
(Join-Path $p1SourceBuild 'Binaries/Network'))) {
if (-not (Test-Path -LiteralPath $p1Required)) { throw "Missing input: $p1Required" }
}
if ((Get-FileHash -LiteralPath $p1Seed -Algorithm SHA256).Hash -ne $p1Manifest.SeedSHA256) {
throw 'The preserved pre-update NAND journal differs from its manifest.'
}
$p1InputBytes = ($p1Expected | Measure-Object -Property Bytes -Sum).Sum
$p1InputBytes += (Get-Item -LiteralPath $p1SourceExe).Length + (Get-Item -LiteralPath $p1SourcePDB).Length
foreach ($p1Folder in @('Sys','Network')) {
$p1FolderSource = if ($p1Folder -eq 'Sys') { $p1RuntimeBuild } else { $p1SourceBuild }
$p1InputBytes += (Get-ChildItem -LiteralPath (Join-Path $p1FolderSource "Binaries/$p1Folder") `
-File -Recurse | Measure-Object -Property Length -Sum).Sum
}
if ((Get-PSDrive C).Free -lt ($p1InputBytes + 5GB)) {
throw 'Insufficient free space for copies, update growth, and a 5 GiB reserve.'
}
$p1Copies = foreach ($p1File in $p1Expected) {
$p1Target = [IO.Path]::GetFullPath((Join-Path $p1Profile $p1File.Relative))
if (-not $p1Target.StartsWith($p1Profile + '\', [StringComparison]::OrdinalIgnoreCase)) {
throw 'Invalid relative path in the initial-file manifest.'
}
$p1Sources = if ($p1File.Relative -eq $p1JournalRelative) { @($p1Seed) } else {
@((Join-Path (Join-Path $p1Root 'B') $p1File.Relative),
(Join-Path (Join-Path $p1Repo '.starlet_formatter_test_20260913') $p1File.Relative))
}
$p1Selected = $null
foreach ($p1Source in $p1Sources) {
if ((Test-Path -LiteralPath $p1Source -PathType Leaf) -and
(Get-FileHash -LiteralPath $p1Source -Algorithm SHA256).Hash -eq $p1File.SHA256) {
$p1Selected = $p1Source
break
}
}
if (-not $p1Selected) { throw "No byte-identical initial source for $($p1File.Relative)" }
[pscustomobject]@{ Relative=$p1File.Relative; Source=$p1Selected; Target=$p1Target; SHA256=$p1File.SHA256 }
}
New-Item -ItemType Directory -Path $p1Profile,(Join-Path $p1Build 'Binaries'),
(Join-Path $p1Build 'pdb') | Out-Null
foreach ($p1Copy in $p1Copies) {
New-Item -ItemType Directory -Force -Path (Split-Path $p1Copy.Target -Parent) | Out-Null
Copy-Item -LiteralPath $p1Copy.Source -Destination $p1Copy.Target
if ((Get-FileHash -LiteralPath $p1Copy.Target -Algorithm SHA256).Hash -ne $p1Copy.SHA256) {
throw "Copied input verification failed: $($p1Copy.Relative)"
}
}
foreach ($p1Folder in @('Sys','Network')) {
$p1FolderSource = if ($p1Folder -eq 'Sys') { $p1RuntimeBuild } else { $p1SourceBuild }
Copy-Item -LiteralPath (Join-Path $p1FolderSource "Binaries/$p1Folder") `
-Destination (Join-Path $p1Build 'Binaries') -Recurse
}
Copy-Item -LiteralPath $p1SourceExe -Destination (Join-Path $p1Build 'Binaries/DolphinNoGUI.exe')
Copy-Item -LiteralPath $p1SourcePDB -Destination (Join-Path $p1Build 'pdb/DolphinNoGUI.pdb')
foreach ($p1Folder in @('Logs','Perf','Capture')) {
New-Item -ItemType Directory -Force -Path (Join-Path $p1Profile $p1Folder) | Out-Null
}
$p1ConfigPath = Join-Path $p1Profile 'Config/Dolphin.ini'
$p1OriginalConfig = [IO.File]::ReadAllText($p1ConfigPath)
$p1OldPrefix = (Join-Path $p1Root 'B').Replace('\','/') + '/'
$p1NewPrefix = $p1Profile.Replace('\','/') + '/'
if (-not $p1OriginalConfig.Contains($p1OldPrefix)) {
throw 'The source configuration has no expected baseline profile path.'
}
$p1NewConfig = $p1OriginalConfig.Replace($p1OldPrefix, $p1NewPrefix)
if ($p1NewConfig.Replace($p1NewPrefix, $p1OldPrefix) -cne $p1OriginalConfig) {
throw 'The isolated configuration differs beyond its profile paths.'
}
[IO.File]::WriteAllText($p1ConfigPath, $p1NewConfig, [Text.UTF8Encoding]::new($false))
& $p1Python -B (Join-Path $p1Root '../.starlet-profile/VerifyJournalCheckpoint.py') `
(Join-Path $p1Profile $p1JournalRelative) $p1Manifest.PrefixBytes `
> (Join-Path $p1Profile 'Capture/initial-journal-verification.txt') 2>&1
if ($LASTEXITCODE) { throw 'Preserved NAND checkpoint verification failed; no emulator was launched.' }
[pscustomobject]@{
CreatedUTC=[datetime]::UtcNow.ToString('o'); Profile=$p1Profile; Build=$p1Build
InitialFiles=$p1Copies.Count; SeedSHA256=$p1Manifest.SeedSHA256
ExeSHA256=(Get-FileHash -LiteralPath (Join-Path $p1Build 'Binaries/DolphinNoGUI.exe')).Hash
PdbSHA256=(Get-FileHash -LiteralPath (Join-Path $p1Build 'pdb/DolphinNoGUI.pdb')).Hash
SourceBuild=$p1SourceBuild; RuntimeBuild=$p1RuntimeBuild
PerformanceTraceRequestedAtLaunch=$false
} | ConvertTo-Json -Depth 4 | Out-File -LiteralPath (Join-Path $p1Profile 'Capture/prepare-manifest.json') -Encoding utf8
Write-Output "Prepared isolated profile $p1Profile and frozen build $p1Build. No Dolphin instance was launched."