300 lines
23 KiB
PowerShell
300 lines
23 KiB
PowerShell
# Counter ASIC 3.0, PC 1 AMD job 1 (6 October 2026): gate G1 for the class v4 candidate and item 8's AMD ladder on PC 1's
|
|
# RX 9070 XT (machine ae432dc7, gfx1201 on the eGPU), docs/plans/counter-asic-3-status.md sections 3, 5 and 7.
|
|
# Published as a plain signed `run` job (NOT --stop-miners): the RTX 5090 and the RTX 4070 keep mining; this script
|
|
# switches ONLY the 9070 XT off in the installed app through POST <app.url>api/cards with the card key read from the
|
|
# app's settings.json (never api/state) in EVERY form (the key as written, vendor:index, vendor:code; the 6 October
|
|
# finding: the index-less form switched nothing on 5 October), confirms by the process list that the card's
|
|
# igneum-worker-opencl process (the one with its --device index) is gone, runs the kit's igneum-worker-opencl.exe
|
|
# (proto-opencl/host.c of branch ca3-pc1-amd: the installed worker's source plus one `build <ms> clBuildProgram` line,
|
|
# cross-compiled with mingw as proto-cuda/nvrtc/build-windows.sh does) with --bench-pack on every pack of the kit while
|
|
# the AMD helper igneum-gpu-telemetry.exe (ADLX board watts, the installed app's own helper, run as a second copy at
|
|
# 1 Hz through a wrapper this script starts and ends by its own pid) samples the card, and restores the card in a
|
|
# finally block whatever happens. It never quits, pauses, resumes or updates the installed app, never writes
|
|
# settings.json and never touches the manifest. If --stop-miners IS used at publish time the card is already quiet
|
|
# and the switch is a no-op: the script works either way and says which it saw.
|
|
# Per pack: the self-test (cache, dataset, 64 samples, 96 vector lanes, from the worker's own line), the 2^24
|
|
# fingerprint at base nonce 0 against the Mac's and the 5090's (G1), and a 75 to 120 s rate with the card alone for
|
|
# MH/s; the mean board watts over the bench window give microjoules per hash. The control row doubles as item 1's AMD
|
|
# per-joule row. Lines: `RESULT G1 pack=<name> fingerprint=<hex> match=<yes/no> ...`,
|
|
# `RESULT LADDER pack=<name> ops=<N> mhs=<x> watts=<y|owed> uj=<z|owed> ...`, a `SUMMARY {json}` line at the end.
|
|
# Read back with `node tools/jobs.mjs <job id>`. The kit: fetch job fetch-ca3-pc1-amd-20261006 (tools/ca3-pc1-amd/README.md).
|
|
$ErrorActionPreference = 'Continue'
|
|
$jobName = 'pc1-amd-g1-shadow'
|
|
$kitId = 'fetch-ca3-pc1-amd-20261006'
|
|
$started = Get-Date
|
|
function Stamp { (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ssZ') }
|
|
function Summary([string] $status, [hashtable] $extra) {
|
|
$o = [ordered]@{ job = $jobName; status = $status; duration_s = [int]((Get-Date) - $started).TotalSeconds; finished_at = (Stamp) }
|
|
foreach ($k in $extra.Keys) { $o[$k] = $extra[$k] }
|
|
'SUMMARY ' + ($o | ConvertTo-Json -Compress -Depth 4)
|
|
}
|
|
# the expected 2^24 fingerprints at base nonce 0 (the Mac on Metal and Apple OpenCL, the 5090 on CUDA: status file
|
|
# section 3, docs/analysis/latency-shadow-2026-10-06.md sections 2 and 5, counter-asic-2-status.md 22:16 for the
|
|
# control; re-checked on Apple OpenCL through this kit's host.c on 6 October 2026, 15:2x UTC)
|
|
$expected = @{
|
|
'mx8-devnet-epoch0' = '90f794dd556f7a3b'
|
|
'sh256x13' = '59ac286fe2a5a9ef'
|
|
'sh256x27' = '3d2e8245cc084d07'
|
|
'sh256x53' = '4f824b15cf2b124a'
|
|
'sh256x88' = '0572522e39a94d8a'
|
|
'sh64x52' = '9dd010f79d8ca9f4'
|
|
}
|
|
# ops per hash as the status file counts them (x1.83 counted ops per shadow instruction + 930 for the base program);
|
|
# the shadow instruction count is read from each pack's program.json at run time and printed beside it
|
|
$opsPerHash = @{ 'mx8-devnet-epoch0' = 930; 'sh256x13' = 49700; 'sh256x27' = 102100; 'sh256x53' = 199600; 'sh256x88' = 330700; 'sh64x52' = 49700 }
|
|
# timed dispatches of 2^24 nonces per pack: about 0.9 s each at 19 MH/s, longer where the shadow binds the card
|
|
$batches = @{ 'mx8-devnet-epoch0' = 90; 'sh256x13' = 90; 'sh256x27' = 90; 'sh256x53' = 80; 'sh256x88' = 60; 'sh64x52' = 90 }
|
|
$order = @('mx8-devnet-epoch0', 'sh256x13', 'sh256x27', 'sh256x53', 'sh256x88', 'sh64x52', 'mx8-devnet-epoch0')
|
|
|
|
"RESULT start $(Stamp) job=$jobName machine=$env:COMPUTERNAME app_version=$env:IGNEUM_APP_VERSION"
|
|
# ---- the kit (the wiped-jobs-folder rule: tested before use; republish the fetch after any app update) ----
|
|
$jobs = Split-Path $env:IGNEUM_JOB_DIR
|
|
$kit = Join-Path $jobs $kitId
|
|
if (-not (Test-Path $kit)) { "RESULT error kit missing at $kit (the fetch job $kitId runs first; republish it after any app update)"; Summary 'failed' @{ error = 'kit missing' }; exit 2 }
|
|
$exe = Join-Path $kit 'bin\igneum-worker-opencl.exe'
|
|
$packs = Join-Path $kit 'packs'
|
|
if (-not (Test-Path $exe)) { "RESULT error worker missing at $exe"; Summary 'failed' @{ error = 'worker missing' }; exit 2 }
|
|
if (-not (Test-Path $packs)) { "RESULT error packs missing at $packs"; Summary 'failed' @{ error = 'packs missing' }; exit 2 }
|
|
"RESULT worker kit $exe sha256 $((Get-FileHash -Algorithm SHA256 $exe).Hash.ToLower()) bytes $((Get-Item $exe).Length)"
|
|
foreach ($f in (Get-ChildItem $kit -Recurse -File | Where-Object { $_.Name -match '\.(exe|c|json)$|SHA256SUMS' } | Sort-Object FullName)) { "RESULT kitfile $($f.FullName.Substring($kit.Length + 1).Replace('\', '/')) sha256 $((Get-FileHash -Algorithm SHA256 $f.FullName).Hash.ToLower()) bytes $($f.Length)" }
|
|
$job = $env:IGNEUM_JOB_DIR; if (-not $job) { $job = Join-Path $env:TEMP 'igneum-ca3-pc1-amd' }; New-Item -ItemType Directory -Force -Path $job | Out-Null
|
|
|
|
# ---- the installed app: install folder (the installed worker for the cross-check and the AMD helper), app dir, URL ----
|
|
$inst = @("$env:LOCALAPPDATA\Programs\Igneum Miner", "$env:ProgramFiles\Igneum Miner") | Where-Object { Test-Path (Join-Path $_ 'igneum-app.exe') } | Select-Object -First 1
|
|
$appDir = if ($env:IGNEUM_APP_DIR) { $env:IGNEUM_APP_DIR } else { Join-Path $env:LOCALAPPDATA 'igneum\app' }
|
|
$urlFile = Join-Path $appDir 'app.url'
|
|
$base = $null
|
|
if (Test-Path $urlFile) { $base = (Get-Content -LiteralPath $urlFile -Raw).Trim().TrimEnd('/') }
|
|
"RESULT app install=$inst app_dir=$appDir url_present=$([bool]$base)"
|
|
|
|
# ---- the OpenCL device index of the 9070 XT, from the worker's own list (the current platform; the older platform's duplicate is marked dup) ----
|
|
$listExe = $exe
|
|
if ($inst -and (Test-Path (Join-Path $inst 'igneum-worker-opencl.exe'))) { $listExe = Join-Path $inst 'igneum-worker-opencl.exe' }
|
|
$list = @(& $listExe --list 2>&1 | ForEach-Object { "$_" })
|
|
$list | ForEach-Object { "RESULT list $_" }
|
|
$dev = $null
|
|
foreach ($l in $list) { if ($l -match '^\s*\[(\d+)\].*gfx1201' -and $l -notmatch 'dup') { $dev = [int]$Matches[1]; break } }
|
|
if ($null -eq $dev) { "RESULT error no gfx1201 device in --list (the eGPU is off the bus: every row OWED)"; Summary 'failed' @{ error = 'no gfx1201' }; exit 2 }
|
|
"RESULT device $dev gfx1201 (list from $listExe)"
|
|
|
|
# ---- the card's keys from settings.json (READ ONLY), every form ----
|
|
$entries = @()
|
|
try {
|
|
$sj = Get-Content -LiteralPath (Join-Path $appDir 'settings.json') -Raw | ConvertFrom-Json
|
|
foreach ($prop in $sj.cards.PSObject.Properties) {
|
|
if ($prop.Name -like 'amd:*' -and $prop.Name -match 'gfx1201') {
|
|
$parts = $prop.Name -split ':'
|
|
$forms = @()
|
|
if ($parts.Count -ge 3) { $forms += ($parts[0] + ':' + $parts[1]); $forms += ($parts[0] + ':' + $parts[2]) }
|
|
$ident = 1; if ($prop.Value.identities) { $ident = [int] $prop.Value.identities }
|
|
$entries += [pscustomobject]@{ key = $prop.Name; forms = $forms; enabled = [bool] $prop.Value.enabled; identities = $ident }
|
|
"RESULT card settings_key=$($prop.Name) enabled=$([bool] $prop.Value.enabled) identities=$ident derived_forms=[$($forms -join ' | ')]"
|
|
}
|
|
}
|
|
} catch { "RESULT settings_read_failed $($_.Exception.Message)" }
|
|
if ($entries.Count -eq 0) { "RESULT card none in settings.json matching amd:*gfx1201*: no switch; the rows below carry whatever load the card has" }
|
|
# off: every form of every entry; restore: the derived forms first, then each key as written with ITS OWN enabled flag and
|
|
# identities, so an entry's own settings win on the live key (the first run of this job, 15:46Z, posted one entry's
|
|
# identities to every form while settings.json held three gfx1201 entries: the class fixed here)
|
|
function PostCards([bool] $enabled) {
|
|
if (-not $base) { "RESULT cards no app.url: nothing posted"; return }
|
|
foreach ($pass in @('derived', 'written')) {
|
|
foreach ($e in $entries) {
|
|
$keys = if ($pass -eq 'derived') { $e.forms } else { @($e.key) }
|
|
$on = if ($enabled) { $e.enabled } else { $false }
|
|
foreach ($k in $keys) {
|
|
$body = @{ cards = @(@{ key = $k; enabled = $on; identities = $e.identities }) } | ConvertTo-Json -Depth 5
|
|
try { Invoke-RestMethod -Uri "$base/api/cards" -Method POST -Body $body -ContentType 'application/json' -TimeoutSec 10 | Out-Null; "RESULT cards key=$k enabled=$on identities=$($e.identities) posted (from entry $($e.key))" } catch { "RESULT cards key=$k enabled=$on error=$($_.Exception.Message)" }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
function Workers {
|
|
@(Get-CimInstance Win32_Process -Filter "Name = 'igneum-worker-opencl.exe' OR Name = 'igneum-worker-cuda.exe' OR Name = 'igneum-worker-metal.exe'" -ErrorAction SilentlyContinue | ForEach-Object { "$($_.Name):$($_.ProcessId):[$($_.CommandLine -replace '\s+', ' ')]" })
|
|
}
|
|
function CardWorkers { @(Get-CimInstance Win32_Process -Filter "Name = 'igneum-worker-opencl.exe'" -ErrorAction SilentlyContinue | Where-Object { $_.CommandLine -match "--device\s+$dev(\s|$)" } | ForEach-Object { $_.ProcessId }) }
|
|
"RESULT workers_before $(Stamp) $((Workers) -join ' ')"
|
|
|
|
# ---- the AMD helper: the installed app's igneum-gpu-telemetry.exe (0.3.10+), else the newest one under an amd-kit job folder ----
|
|
$tele = $null
|
|
if ($inst -and (Test-Path (Join-Path $inst 'igneum-gpu-telemetry.exe'))) { $tele = Join-Path $inst 'igneum-gpu-telemetry.exe' }
|
|
if (-not $tele) { $found = Get-ChildItem -Path (Join-Path $appDir 'jobs') -Recurse -Filter 'igneum-gpu-telemetry.exe' -ErrorAction SilentlyContinue | Where-Object { $_.FullName -match 'amd-kit' } | Sort-Object LastWriteTime -Descending | Select-Object -First 1; if ($found) { $tele = $found.FullName } }
|
|
$wattsSource = 'owed'
|
|
if ($tele) {
|
|
$one = @(& $tele 2>&1 | ForEach-Object { "$_" })
|
|
$one | ForEach-Object { "RESULT tele_once $_" }
|
|
$card9070 = $one | Where-Object { $_ -match '^amd \d+ .*name "[^"]*9070[^"]*" watts (\S+) .* source (\S+)' } | Select-Object -First 1
|
|
if ($card9070 -and $card9070 -match ' watts (\S+) .* source (\S+)$') { if ($Matches[1] -ne '-') { $wattsSource = $Matches[2] } }
|
|
"RESULT tele helper=$tele sha256=$((Get-FileHash -Algorithm SHA256 $tele).Hash.ToLower()) watts_source=$wattsSource (board watts through ADLX GPUPower, GPUTotalBoardPower as the fallback; 'owed' = the helper gives no watts for the 9070 XT)"
|
|
} else { "RESULT tele none (no igneum-gpu-telemetry.exe in the install folder or under an amd-kit job folder): watts OWED" }
|
|
|
|
$samples = Join-Path $job 'amd-samples.log'
|
|
$sampler = $null
|
|
$windows = @()
|
|
$results = @()
|
|
$cardAlone = $false
|
|
$switched = $false
|
|
try {
|
|
# ---- the card off, confirmed by the process list (never api/state) ----
|
|
if ($entries.Count -gt 0 -and $base) {
|
|
$before = @(CardWorkers)
|
|
"RESULT card_workers_before pids=[$($before -join ' ')]"
|
|
if ($before.Count -eq 0) { "RESULT card already quiet before the switch (no opencl worker with --device ${dev}: --stop-miners or the card is off in the app)"; $cardAlone = $true }
|
|
else {
|
|
PostCards $false; $switched = $true
|
|
$t = 0
|
|
while ($t -lt 150) { Start-Sleep -Seconds 5; $t += 5; if ((@(CardWorkers)).Count -eq 0) { break } }
|
|
$left = @(CardWorkers)
|
|
if ($left.Count -eq 0) { "RESULT card $(Stamp) quiet after $t s: no igneum-worker-opencl process with --device $dev (the card to itself)"; $cardAlone = $true }
|
|
else { "RESULT card $(Stamp) UNCONFIRMED after $t s: opencl worker pids [$($left -join ' ')] still carry --device $dev; the rows below are LOADED-card figures" }
|
|
Start-Sleep -Seconds 5
|
|
}
|
|
} else { "RESULT card not switched (no entry or no app.url): the rows below carry whatever load the card has" }
|
|
"RESULT workers_during $(Stamp) $((Workers) -join ' ')"
|
|
|
|
# ---- the sampler: the helper at 1 Hz through a wrapper; its paths through the ENVIRONMENT (inherited by the child,
|
|
# never on a command line: Start-Process -ArgumentList in Windows PowerShell 5.1 joins arguments WITHOUT quoting,
|
|
# and "Igneum Miner" holds a space, which is why the 15:46Z run wrote no samples), the -File path quoted; ended
|
|
# by its own pid in finally. The sampler PROVES itself in the 12 idle seconds: the first three raw lines are
|
|
# printed, and without a 9070 XT line with watts the ladder is NOT run blind (the rates are on record from 15:46Z). ----
|
|
$samplerOk = $false
|
|
if ($tele -and $wattsSource -ne 'owed') {
|
|
$wrapper = Join-Path $job 'sampler.ps1'
|
|
$wrapperText = @'
|
|
$exe = $env:IGNEUM_SAMPLER_EXE
|
|
$out = $env:IGNEUM_SAMPLER_OUT
|
|
Add-Content -LiteralPath $out -Value ('wrapper start ' + (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fff') + ' exe=' + $exe + ' exists=' + (Test-Path -LiteralPath $exe))
|
|
& $exe -l 1 2>&1 | ForEach-Object { Add-Content -LiteralPath $out -Value ((Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fff') + ' ' + $_) }
|
|
Add-Content -LiteralPath $out -Value ('wrapper end ' + (Get-Date).ToUniversalTime().ToString('yyyy-MM-ddTHH:mm:ss.fff') + ' exit=' + $LASTEXITCODE)
|
|
'@
|
|
[IO.File]::WriteAllText($wrapper, $wrapperText, (New-Object System.Text.UTF8Encoding $false))
|
|
Remove-Item -LiteralPath $samples -Force -ErrorAction SilentlyContinue
|
|
$env:IGNEUM_SAMPLER_EXE = $tele
|
|
$env:IGNEUM_SAMPLER_OUT = $samples
|
|
$sampler = Start-Process -FilePath 'powershell.exe' -ArgumentList @('-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', ('"' + $wrapper + '"')) -WindowStyle Hidden -PassThru
|
|
"RESULT sampler pid=$($sampler.Id) wrapper=$wrapper file=$samples exe_via_env=$tele"
|
|
Start-Sleep -Seconds 12
|
|
$raw = @(); if (Test-Path -LiteralPath $samples) { $raw = @(Get-Content -LiteralPath $samples) }
|
|
$raw | Select-Object -First 3 | ForEach-Object { "RESULT sampler_raw $_" }
|
|
$n9070 = @($raw | Where-Object { $_ -match '^\S+ amd \d+ .*name "[^"]*9070[^"]*" watts [\d.]+ ' }).Count
|
|
"RESULT sampler_idle lines=$($raw.Count) lines_9070_with_watts=$n9070 sampler_alive=$(-not $sampler.HasExited)"
|
|
if ($n9070 -eq 0) {
|
|
$why = if ($raw.Count -eq 0) { 'the sampler wrote nothing in 12 s (file absent or empty)' } else { 'the sampler wrote ' + $raw.Count + ' line(s) but none is a 9070 XT line with a watts number (first lines above)' }
|
|
"RESULT watts error=$why; the ladder is NOT run blind"
|
|
foreach ($pk in $order) { "RESULT LADDER pack=$pk error=$why" }
|
|
} else { $samplerOk = $true; "RESULT idle $(Stamp) sampler proven on the idle window" }
|
|
} else { "RESULT watts error=no helper or no watts in its one-shot sample: the ladder runs with watts owed"; $samplerOk = $true }
|
|
|
|
# ---- the ladder ----
|
|
$i = 0
|
|
foreach ($pk in $order) {
|
|
if (-not $samplerOk) { break }
|
|
$i++
|
|
$d = Join-Path $packs $pk
|
|
if (-not (Test-Path $d)) { "RESULT G1 pack=$pk error=pack missing at $d"; "RESULT LADDER pack=$pk error=pack missing"; continue }
|
|
$instrs = 0; $cls = ''
|
|
try { $pj = Get-Content -LiteralPath (Join-Path $d 'program.json') -Raw | ConvertFrom-Json; $cls = [string] $pj.load_class; if ($pj.shadow) { $instrs = [int] $pj.shadow.instrs_per_hash } } catch { "RESULT note program.json of $pk unreadable: $($_.Exception.Message)" }
|
|
$n = $batches[$pk]
|
|
$tag = "$pk#$i"
|
|
$t0 = (Get-Date).ToUniversalTime()
|
|
"RESULT bench $tag start $(Stamp) batches=$n class=$cls shadow_instrs_per_hash=$instrs"
|
|
$lines = @(& $exe --bench-pack --pack $d --batches $n --batch-log2 24 --device $dev 2>&1 | ForEach-Object { "$_" })
|
|
$rc = $LASTEXITCODE
|
|
$t1 = (Get-Date).ToUniversalTime()
|
|
$lines | ForEach-Object { "RESULT bench $tag $_" }
|
|
"RESULT bench $tag end $(Stamp) exit=$rc wall_s=$([int]($t1 - $t0).TotalSeconds)"
|
|
$res = $lines | Where-Object { $_ -match '^RESULT pack=' } | Select-Object -First 1
|
|
$fp = ''; $mhs = ''; $check = ''
|
|
if ($res -and $res -match 'fingerprint=([0-9a-f]{16})') { $fp = $Matches[1] }
|
|
if ($res -and $res -match 'mhs=([\d.]+)') { $mhs = $Matches[1] }
|
|
if ($res -and $res -match 'check=(\S+)') { $check = $Matches[1] }
|
|
$buildMs = ''; if (($lines | Where-Object { $_ -match '^build ([\d.]+) ms clBuildProgram' } | Select-Object -First 1) -match '^build ([\d.]+) ms') { $buildMs = $Matches[1] }
|
|
$dsMs = ''; if (($lines | Where-Object { $_ -match '^pack .*: cache \d+ dataset (\d+) ' } | Select-Object -First 1) -match ' dataset (\d+) ') { $dsMs = $Matches[1] }
|
|
if (-not $res -or $rc -ne 0) {
|
|
$err = ($lines | Where-Object { $_ -match 'FAIL|error|MISMATCH' } | Select-Object -First 1); if (-not $err) { $err = "exit $rc, no RESULT line" }
|
|
"RESULT G1 pack=$pk error=$($err -replace '\s+', ' ')"
|
|
"RESULT LADDER pack=$pk error=$($err -replace '\s+', ' ')"
|
|
continue
|
|
}
|
|
$want = $expected[$pk]
|
|
$match = if ($want -and $fp -eq $want) { 'yes' } elseif ($want) { 'no' } else { 'unknown' }
|
|
"RESULT G1 pack=$pk fingerprint=$fp match=$match expected=$want check=$check card=gfx1201 harness=opencl-kit"
|
|
$results += [pscustomobject]@{ tag = $tag; pack = $pk; instrs = $instrs; ops = $opsPerHash[$pk]; mhs = $mhs; fp = $fp; match = $match; check = $check; build_ms = $buildMs; dataset_ms = $dsMs; t0 = $t0; t1 = $t1 }
|
|
Start-Sleep -Seconds 3
|
|
}
|
|
|
|
# ---- the cross-check: the INSTALLED worker on the control pack, if it carries --bench-pack ----
|
|
if ($inst -and (Test-Path (Join-Path $inst 'igneum-worker-opencl.exe'))) {
|
|
$iexe = Join-Path $inst 'igneum-worker-opencl.exe'
|
|
$help = (& $iexe --help 2>&1 | Out-String)
|
|
if ($help -match '--bench-pack') {
|
|
$d = Join-Path $packs 'mx8-devnet-epoch0'
|
|
$t0 = (Get-Date).ToUniversalTime()
|
|
"RESULT xcheck start $(Stamp) worker=installed sha256=$((Get-FileHash -Algorithm SHA256 $iexe).Hash.ToLower())"
|
|
$lines = @(& $iexe --bench-pack --pack $d --batches 40 --batch-log2 24 --device $dev 2>&1 | ForEach-Object { "$_" })
|
|
$rc = $LASTEXITCODE
|
|
$t1 = (Get-Date).ToUniversalTime()
|
|
$lines | Where-Object { $_ -match '^RESULT|^pack |^warm-up|FAIL|error' } | ForEach-Object { "RESULT xcheck $_" }
|
|
$res = $lines | Where-Object { $_ -match '^RESULT pack=' } | Select-Object -First 1
|
|
$fp = ''; $mhs = ''
|
|
if ($res -and $res -match 'fingerprint=([0-9a-f]{16})') { $fp = $Matches[1] }
|
|
if ($res -and $res -match 'mhs=([\d.]+)') { $mhs = $Matches[1] }
|
|
if ($res) { "RESULT XCHECK worker=installed pack=mx8-devnet-epoch0 fingerprint=$fp match=$(if ($fp -eq $expected['mx8-devnet-epoch0']) { 'yes' } else { 'no' }) mhs=$mhs exit=$rc (the kit worker's control rows are the LADDER lines)"; $windows += [pscustomobject]@{ tag = 'xcheck-installed'; t0 = $t0; t1 = $t1 } }
|
|
else { "RESULT XCHECK worker=installed error=exit $rc, no RESULT line" }
|
|
} else { "RESULT XCHECK worker=installed skipped: the installed igneum-worker-opencl.exe has no --bench-pack" }
|
|
}
|
|
} finally {
|
|
# ---- whatever happened: the sampler ended by its own pid (never by name: the app runs its own copy of the helper), the card back ----
|
|
if ($sampler) { try { & taskkill /T /F /PID $sampler.Id 2>&1 | Out-Null; "RESULT sampler ended pid=$($sampler.Id)" } catch { "RESULT sampler end error=$($_.Exception.Message)" } }
|
|
if ($switched) {
|
|
PostCards $true
|
|
"RESULT card restore posted: each settings.json entry with its own enabled flag and identities"
|
|
$t = 0; $back = @()
|
|
$anyEnabled = ($entries | Where-Object { $_.enabled }).Count -gt 0
|
|
while ($t -lt 90 -and $anyEnabled) { Start-Sleep -Seconds 5; $t += 5; $back = @(CardWorkers); if ($back.Count -gt 0) { break } }
|
|
"RESULT card_workers_after $(Stamp) pids=[$($back -join ' ')] after $t s $(if ($back.Count -gt 0) { '(the card mines again)' } elseif ($anyEnabled) { '(NOT back yet: check the app)' } else { '(no entry was enabled before this job)' })"
|
|
}
|
|
"RESULT workers_after $(Stamp) $((Workers) -join ' ')"
|
|
}
|
|
|
|
# ---- the samples: board watts and clocks of the 9070 XT inside each bench window (after its first 12 s, before its last 2 s) ----
|
|
$rows = @()
|
|
if (Test-Path $samples) {
|
|
foreach ($l in (Get-Content -LiteralPath $samples)) {
|
|
if ($l -match '^(\S+) amd (\d+) bus (\S+) kind (\S+) name "([^"]*)" watts (\S+) temp_c (\S+) fan_rpm (\S+) fan_pct (\S+) mclk_mhz (\S+) gclk_mhz (\S+) util_pct (\S+) source (\S+)') {
|
|
if ($Matches[5] -notmatch '9070') { continue }
|
|
try { $ts = [datetime]::ParseExact($Matches[1], 'yyyy-MM-ddTHH:mm:ss.fff', [Globalization.CultureInfo]::InvariantCulture) } catch { continue }
|
|
$w = if ($Matches[6] -eq '-') { $null } else { [double] $Matches[6] }
|
|
$rows += [pscustomobject]@{ ts = $ts; w = $w; temp = $Matches[7]; fan = $Matches[9]; mclk = $Matches[10]; gclk = $Matches[11]; util = $Matches[12]; src = $Matches[13] }
|
|
}
|
|
}
|
|
}
|
|
"RESULT samples total $($rows.Count) file $samples (9070 XT lines)"
|
|
function Window([datetime] $t0, [datetime] $t1) { @($rows | Where-Object { $_.ts -gt $t0.AddSeconds(12) -and $_.ts -lt $t1.AddSeconds(-2) -and $null -ne $_.w }) }
|
|
$g1Match = 0; $ladderRows = 0
|
|
foreach ($r in $results) {
|
|
$in = @(Window $r.t0 $r.t1)
|
|
$watts = 'owed'; $uj = 'owed'; $gclk = 'owed'; $mclk = 'owed'; $tmax = 'owed'; $wmin = ''; $wmax = ''
|
|
if ($in.Count -gt 0) {
|
|
$m = $in | Measure-Object -Property w -Average -Minimum -Maximum
|
|
$watts = [math]::Round($m.Average, 1); $wmin = $m.Minimum; $wmax = $m.Maximum
|
|
$gclk = [math]::Round((($in | ForEach-Object { [double] $_.gclk }) | Measure-Object -Average).Average)
|
|
$mclk = [math]::Round((($in | ForEach-Object { [double] $_.mclk }) | Measure-Object -Average).Average)
|
|
$tmax = (($in | ForEach-Object { [double] $_.temp }) | Measure-Object -Maximum).Maximum
|
|
if ($r.mhs -and [double] $r.mhs -gt 0) { $uj = [math]::Round($m.Average / [double] $r.mhs, 3) }
|
|
}
|
|
if ($r.match -eq 'yes') { $g1Match++ }
|
|
$ladderRows++
|
|
"RESULT LADDER pack=$($r.pack) ops=$($r.ops) shadow_instrs=$($r.instrs) mhs=$($r.mhs) watts=$watts uj=$uj watts_min=$wmin watts_max=$wmax gclk_mhz=$gclk mclk_mhz=$mclk temp_max=$tmax samples=$($in.Count) window_s=$([int]($r.t1 - $r.t0).TotalSeconds) build_ms=$($r.build_ms) dataset_ms=$($r.dataset_ms) fingerprint=$($r.fp) match=$($r.match) card_alone=$cardAlone tag=$($r.tag)"
|
|
}
|
|
foreach ($win in $windows) { $in = @(Window $win.t0 $win.t1); if ($in.Count -gt 0) { $m = $in | Measure-Object -Property w -Average; "RESULT power $($win.tag) samples=$($in.Count) watts_mean=$([math]::Round($m.Average, 1))" } }
|
|
if ($rows.Count -gt 0) {
|
|
$idle = @($rows | Where-Object { $results.Count -gt 0 -and $_.ts -lt $results[0].t0 -and $null -ne $_.w })
|
|
if ($idle.Count -gt 0) { "RESULT idle_power samples=$($idle.Count) watts_mean=$([math]::Round(($idle | Measure-Object -Property w -Average).Average, 1)) (the card switched off in the app, before the first bench)" }
|
|
foreach ($r in $rows) { "RESULT sample $($r.ts.ToString('HH:mm:ss')) $($r.w) $($r.temp) $($r.fan) $($r.mclk) $($r.gclk) $($r.util) $($r.src)" }
|
|
}
|
|
$status = if (-not $samplerOk) { 'failed' } elseif ($results.Count -eq $order.Count) { 'done' } elseif ($results.Count -gt 0) { 'partial' } else { 'failed' }
|
|
"RESULT end $(Stamp)"
|
|
Summary $status @{ packs_run = $results.Count; packs_wanted = $order.Count; g1_match = $g1Match; ladder_rows = $ladderRows; watts = $wattsSource; sampler_proven = $samplerOk; card_alone = $cardAlone; device = $dev }
|
|
if ($status -eq 'failed') { exit 1 }
|
|
exit 0
|