From 3411532de39271dec119a449325739523052ca8a Mon Sep 17 00:00:00 2001 From: igneum-labs <337424239+igneum-labs@users.noreply.github.com> Date: Tue, 6 Oct 2026 16:49:57 +0000 Subject: [PATCH] Counter ASIC 3.0 PC 1 AMD: the 9070 XT ADLX factory-reset job with the identities read, and the watts job revised to the app's path (control row from /api/state with the card on, the helper calibrated beside it, the candidate row alone through the kit worker with the calibration ratio) Co-Authored-By: Claude Fable 5.1 --- tools/ca3-pc1-amd/README.md | 7 +- tools/ca3-pc1-amd/pc1-amd-reset.ps1 | 93 +++++++++++++ tools/ca3-pc1-amd/pc1-amd-watts.ps1 | 209 ++++++++++++++++------------ 3 files changed, 218 insertions(+), 91 deletions(-) create mode 100644 tools/ca3-pc1-amd/pc1-amd-reset.ps1 diff --git a/tools/ca3-pc1-amd/README.md b/tools/ca3-pc1-amd/README.md index 47720ad6a..d9186b4b0 100644 --- a/tools/ca3-pc1-amd/README.md +++ b/tools/ca3-pc1-amd/README.md @@ -37,7 +37,8 @@ The fetch lands at `\fetch-ca3-pc1-amd-20261006\{bin,packs,src,SHA256SUMS} | # | Script | Publish (after the fetch; `--id` fixed so the read-back is one command) | Length | Card | Rows it fills | |---|---|---|---|---|---| | 1 | `pc1-amd-g1-shadow.ps1` | `packaging/ota/publish-jobs.sh add --kind run --target ae432dc7 --id run-ca3-pc1-amd-g1-shadow-20261006 --script tools/ca3-pc1-amd/pc1-amd-g1-shadow.ps1 --timeout-minutes 40 --title "CA3 PC 1: G1 + AMD ladder on the 9070 XT" --deploy` | about 15 min (7 benches of 60 to 90 dispatches of 2^24 at 0.9 to 2 s each, the card switch up to 150 s, the installed-worker cross-check 40 dispatches) | 9070 XT ALONE (its worker stopped; 5090 and 4070 keep mining) | G1 for `mx8+sh256x27` on the AMD vendor (section 5: `RESULT G1 pack=sh256x27 fingerprint=3d2e8245cc084d07 match=yes` turns "AMD vendor NOT RUN" green; the other five packs give the same for the ladder); the 9070 XT column of the item 8 tables (section 3: `RESULT LADDER pack=

ops= mhs= watts= uj= gclk_mhz=`), where the card leaves the latency bound by the 5 percent rule; item 1's AMD per-joule row from the control (`RESULT LADDER pack=mx8-devnet-epoch0 ... uj=`: section 3 "Consequences per tier (item 1)", 16 GB AMD row); section 7 rows "item 8: the 9070 XT rows", "item 1: the 9070 XT rows" | -| 1b (the watts re-run) | `pc1-amd-watts.ps1` | `packaging/ota/publish-jobs.sh add --kind run --target ae432dc7 --id run-ca3-pc1-amd-watts-20261006 --script tools/ca3-pc1-amd/pc1-amd-watts.ps1 --timeout-minutes 20 --title "CA3 PC 1: watts on the 9070 XT (control + sh256x27)" --deploy` | about 5 min (2 x 100 dispatches at the 18.9 to 19.3 MH/s job 1 measured = 87 to 89 s each, the switch, 12 s of proof) | 9070 XT ALONE | the two `watts= uj=` cells job 1 left owed: item 1's AMD per-joule row (the control) and the candidate's AMD row in the item 8 table (sh256x27); the sampler is proven on the 12 idle seconds first (`RESULT sampler_raw` x3, `RESULT sampler_idle lines= lines_9070_with_watts=`) and the benches do not run without a 9070 XT watts line (`RESULT watts error=`, status failed, card restored) | +| 0b (first in the queue after "Ember closed") | `pc1-amd-reset.ps1` | `packaging/ota/publish-jobs.sh add --kind run --target ae432dc7 --id run-ca3-pc1-amd-reset-20261006 --script tools/ca3-pc1-amd/pc1-amd-reset.ps1 --timeout-minutes 5 --title "CA3 PC 1: 9070 XT ADLX back to factory, identities read" --deploy` | about 1 min | beside the miners, no card switch | the 9070 XT's ADLX tuning state after Ember run 6 (`gmax 0 plimit 0 factory 0`): `RESULT amd_state before gmax= plimit= factory=`, the factory reset as the Ember playbook did it (ember-tune ca990c2: `igneum-gpu-telemetry --card --reset`, the helper that answers `--tune`: the installed one first, else the newest amd-kit copy, which one printed), `RESULT amd_state after ...`, FAILED unless the after line reads factory 1; then READ ONLY the identities question of the 15:56Z restore: every gfx1201 settings.json entry (`RESULT settings_entry key= enabled= identities=`) and the app's live card list (`RESULT state_card key= identities= state= mhs_now= watts=`), `RESULT identities_answer live_key= identities=`; no POST of identities (the coordinator's call after the read) | +| 1b (the watts re-run, LAST in the queue) | `pc1-amd-watts.ps1` | `packaging/ota/publish-jobs.sh add --kind run --target ae432dc7 --id run-ca3-pc1-amd-watts-20261006 --script tools/ca3-pc1-amd/pc1-amd-watts.ps1 --timeout-minutes 20 --title "CA3 PC 1: watts on the 9070 XT (app control + sh256x27 alone)" --deploy` | about 5 min | the control row with the card ON in the app; the candidate row with the 9070 XT ALONE | the two `watts= uj=` cells job 1 left owed, taken the way main trusts after Ember run 6 (the app's path: engine telemetry 363 of 363 nonzero, /api/state 456 of 456; a direct helper call alone is not trusted): (1) the CONTROL row with the card ON in the app mining class v3, `/api/state` polled at 1 Hz for 90 s (`RESULT APPROW class=v3 mhs_wall= watts_mean= watts_min= watts_max= samples= uj=`; the app's watts come from its own helper at -l 5, so they move every 5 s: `distinct_watts=` says how many values), the helper sampler running beside over the same 90 s (`RESULT sampler_vs_app helper_mean= app_mean= ratio=`); (2) the CANDIDATE row (sh256x27, the card alone through the kit worker, which /api/state cannot see) with the sampler as its only source and the ratio as its calibration (`RESULT LADDER ... watts_source=adlx calibration_ratio=`); a ratio outside 0.95 to 1.05 prints the candidate's watts as owed with the reason. The sampler is proven on the 12 idle seconds first (`RESULT sampler_raw` x3, `RESULT sampler_idle lines= lines_9070_with_watts=`); without a 9070 XT watts line no row is taken (`RESULT watts error=`, status failed). About 5 min: 12 s proof, 90 s app window, the switch, about 90 s of bench, the restore | | G2 (job 2's slot, after "Ember closed") | `pc1-amd-g2.ps1` | its own small kit first: `tools/ca3-pc1-amd/make-g2-kit.sh "$TMPDIR/igneum-ca3-pc1-amd-g2-kit.zip"` (rebuilt 6 October 16:4x UTC from the merged tree with the generator-4 packs and the merged packfile.h: sha256 `a16165483cbef9c9001897e2e965b95051c4e683940e0dbc9bded002ed0a0e7e`, 198,597 bytes, 35 files; worker exe `7dc3b1ee…`; the 16:2x build `f4c029c7…` carried the generator-3 copies and is superseded), then `packaging/ota/publish-jobs.sh add --kind fetch --target ae432dc7 --id fetch-ca3-pc1-amd-g2-20261006 --file "$TMPDIR/igneum-ca3-pc1-amd-g2-kit.zip" --dir jobs --extract --title "CA3 PC 1 G2 kit" --deploy`, then `packaging/ota/publish-jobs.sh add --kind run --target ae432dc7 --id run-ca3-pc1-amd-g2-20261006 --script tools/ca3-pc1-amd/pc1-amd-g2.ps1 --timeout-minutes 10 --title "CA3 PC 1: gate G2 on the 9070 XT" --deploy` | about 2 min (two serve-mode jobs of 1,024 nonces; the Apple OpenCL dry run took 2.6 s a pack) | beside the miners (a correctness gate) | the "RX 9070 XT" cell of G2 in `docs/plans/counter-asic-3-gate/hash-gates.md` and the AMD line of G2 in status section 5: `RESULT g2 found of 1024 distinct= sha256 file exit=` (the hash lane's form) plus `RESULT G2 pack= found= distinct= digest= digest_match=yes|no`; the found lines go to `g2-.found` in the job folder, never to stdout; the Mac re-check is `tools/ca3-v4/g2-recheck.sh proto-cuda/packs-ca3-v4/ --digest ` (a digest match is 1,024 of 1,024), or `--file` after `publish-jobs.sh add --kind collect --target ae432dc7 --glob "app/jobs/run-ca3-pc1-amd-g2-20261006/g2-*.found"`. Packs: `packs-ca3-v4/mx8-devnet-epoch0` (control, class v3, id 73bcbfe8ccf988f1) and `packs-ca3-v4/v4-devnet-epoch0` (the candidate with the era at the devnet epoch-0 chain seeds; since the program-id fix 7c22d0d generator 4, class "v4", id c120d7963abdcd96, kernels and vectors byte-identical), NOT the first kit's `sh256x27`: that one is the genesis string-seed pack (`IGNEUM_SEED_BYTES_HEX` of 14 bytes) and the worker's job protocol takes only a 64-hex epoch seed, so it cannot be served (the script refuses such a pack with a RESULT line instead of a malformed job). The job line's class token is the pack's own `IGNEUM_PROGRAM_CLASS` (`class=v3` for the control, `class=v4` for the candidate), as `pc2-v4-gates.ps1` does since ca61dec: the worker refuses a token that disagrees with the pack (Mac check 16:41Z: `class=v3` on the v4 pack found 0, the known-bad case). Expected digests (the verifier through g2-recheck.sh on the Mac, equal to the kit worker's serve mode on Apple OpenCL at 16:21Z on the generator-3 copies and again at 16:41Z on the generator-4 packs through the merged host.c and packfile.h with `class=v4`, 1,024 of 1,024 every time; UNCHANGED by the re-export, as the byte-identical kernels require): mx8 `2a1824a2e0834287cf53b33f84cb7322014c85efa9788bece574e4e0730940bd`, v4 `435b976a4de57c5a26c8bada8b3b9e003504687c790d4b856bc56619d3aabd18`; the script carries them and prints `digest_match` itself | | 2 | `pc1-amd-family.ps1` | `packaging/ota/publish-jobs.sh add --kind run --target ae432dc7 --id run-ca3-pc1-amd-family-20261006 --script tools/ca3-pc1-amd/pc1-amd-family.ps1 --timeout-minutes 15 --title "CA3 PC 1: family step costs on the 9070 XT" --deploy` | about 3 min (3 runs x up to 3 AMD devices, 26 variants each, builds dominate) | beside the miners (ratios; every row says `card_state=`) | the "RX 9070 XT" column of the item 6 table (section 3: `RESULT FAMILYBEST name= ratio= exact= path=` per family, `RESULT FAMILY ... variant=` for the form each took: `shfla_bperm` = `ds_bpermute_b32`, the one number that could move R3; `shflx_swz` / `shflx_bperm`; `perm_amd` = `v_perm_b32` through `amd_perm` or `perm_c` emulated; `bfe_amd`; `dot4_amd` = the 5 October sudot4 row re-measured; `mm8_gfx12` / `mm8_gfx11` = the WMMA builtins, exact=unverified); section 7 row "item 6: the 9070 XT step costs" | | 3 | `pc1-amd-derive.ps1` | `packaging/ota/publish-jobs.sh add --kind run --target ae432dc7 --id run-ca3-pc1-amd-derive-20261006 --script tools/ca3-pc1-amd/pc1-amd-derive.ps1 --timeout-minutes 15 --title "CA3 PC 1: dr736 on the 9070 XT" --deploy` | about 4 min (3 packs x a 60-dispatch pass and a 3-dispatch pass) | beside the miners (build, compile and bit-exact rows; the rate as a ratio to mx8 in the same job) | the item 2 table's 9070 XT cells (section 3: `RESULT DERIVE pack=dr736-genesis build_ms= build_ms_cached= build_ms_over_mx8= dataset_ms= fingerprint= match= mhs= ratio_to_mx8=`): the OpenCL compile cost of the derivation program against mx8's (the NVRTC +1.1 s finding on AMD), the 1 GiB daily build against mx8's 72 to 77 ms (5 October), bit-exactness on the AMD vendor; section 7 row "item 2: the 9070 XT rows" | @@ -66,8 +67,8 @@ G1 on the AMD vendor 7 of 7 (every fingerprint equal to the Mac's and the 5090's | `proto-opencl/host.c` with the build line, `--bench-pack` on all eight kit packs on Apple OpenCL | self-test PASS (96 of 96 lanes) and the 2^24 fingerprint at base 0 equal to the recorded one on every pack: mx8-devnet-epoch0 `90f794dd556f7a3b`, sh256x13 `59ac286fe2a5a9ef`, sh256x27 `3d2e8245cc084d07`, sh256x53 `4f824b15cf2b124a`, sh256x88 `0572522e39a94d8a`, sh64x52 `9dd010f79d8ca9f4`, dr736-genesis `50e3eaa779da4f1e`, dr736-devnet-epoch0 `9553f6d5c667205a`; `build` line: mx8 70 ms, shadow packs 70 to 88 ms, dr736 337 to 356 ms (+270 ms on Apple OpenCL: item 2's compile cost shows on this harness too) | | mingw cross-builds of both exes | clean (`-Wall -Wextra`), 116 KB and 35 KB | | The kit worker's serve mode on Apple OpenCL (G2 dry runs, 16:21 UTC at load 5.2 to 5.7 on the generator-3 copies; 16:41 UTC at load 27 to 57, a loaded box, on the generator-4 packs with the merged packfile.h and the `class=v4` token: a correctness run, no number taken) | `packs-ca3-v4/mx8-devnet-epoch0` and `v4-devnet-epoch0`: 1,024 of 1,024 found each (2.6 s), nonces 0 to 1,023, the sorted found file's sha256 equal to the verifier's through `tools/ca3-v4/g2-recheck.sh --file` (the coordinator's `igneum-pow` binary): the two digests above | -| `tools/ci/bash-body-check.sh` on the six scripts | 0 bash bodies, all parse | -| `tools/ci/kit-path-check.sh` on the six scripts | 6 of 6 kit paths checked before use | +| `tools/ci/bash-body-check.sh` on the seven scripts | 0 bash bodies, all parse | +| `tools/ci/kit-path-check.sh` on the seven scripts | 6 of 6 kit paths checked before use (the reset job reads no kit) | | `tools/ci/prover-socket-check.sh`, `copied-sources-check.sh`, `no-conflict-markers.sh` | pass | | The Windows PowerShell 5.1 parse (`windows.yml` parse job) | the real parser runs only on the Windows runner and only over `relay/playbooks` and the other listed folders (not `tools/`); on the Mac the same rule's approximation (`tools/ci/check-workflow-shell.mjs`'s drive-reference regex, applied to these five files by hand) fired once on `"$dev: --stop-miners"` and the line was fixed to `${dev}:`; 0 findings after; brace, paren and bracket depth 0 by the bash-body-check tokenizer | diff --git a/tools/ca3-pc1-amd/pc1-amd-reset.ps1 b/tools/ca3-pc1-amd/pc1-amd-reset.ps1 new file mode 100644 index 000000000..817ab06b9 --- /dev/null +++ b/tools/ca3-pc1-amd/pc1-amd-reset.ps1 @@ -0,0 +1,93 @@ +# Counter ASIC 3.0, PC 1 AMD reset job (6 October 2026, after Ember run 6): the RX 9070 XT's ADLX tuning state back to +# factory, and the identities question answered by reading. Main's facts: after Ember the card reads `gmax 0 plimit 0 +# factory 0` (every offset zero, nothing applied, but the factory flag is off). This job prints the state line BEFORE +# (`RESULT amd_state before gmax= plimit= factory=`), applies the factory reset the way the Ember playbook did +# (`igneum-gpu-telemetry --card --reset`, ember-tune ca990c2: the helper prints the `tune` line read back after +# the change), prints the state line AFTER, and fails loudly if the after line does not read factory 1. The helper is the +# one that answers `--tune`: the installed app's igneum-gpu-telemetry.exe first, else the newest copy under an amd-kit +# job folder (the Ember kit); which one answered is printed. Then, READ ONLY: every gfx1201 entry of settings.json (key, +# enabled, identities) and the app's /api/state card list (key, identities, state, MH/s, watts), so the 15:56Z restore +# question (identities 8 or 2 on the live key) is answered in this report; NO POST of identities here. Beside the miners, +# no card switch; the only write is the ADLX reset on the card's tuning (not the app). Never quits, pauses, resumes or +# updates the installed app; never writes settings.json. Every result line starts with RESULT; a `SUMMARY {json}` line +# ends the job. Read back with `node tools/jobs.mjs `. +$ErrorActionPreference = 'Continue' +$jobName = 'pc1-amd-reset' +$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) +} +"RESULT start $(Stamp) job=$jobName machine=$env:COMPUTERNAME app_version=$env:IGNEUM_APP_VERSION" +$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 helper that answers --tune ---- +$cands = @() +if ($inst -and (Test-Path (Join-Path $inst 'igneum-gpu-telemetry.exe'))) { $cands += (Join-Path $inst 'igneum-gpu-telemetry.exe') } +$kits = @(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 | ForEach-Object { $_.FullName }) +$cands += $kits +$tele = $null; $tuneBefore = @() +foreach ($c in $cands) { + $t = @(& $c --tune 2>&1 | ForEach-Object { "$_" }) + $t | ForEach-Object { "RESULT tune_probe helper=$c $_" } + if (($t | Where-Object { $_ -match '^tune \d+ name ' }).Count -gt 0) { $tele = $c; $tuneBefore = $t; break } +} +if (-not $tele) { "RESULT amd_state error=no igneum-gpu-telemetry.exe answered --tune (tried: $($cands -join ' ; '))"; Summary 'failed' @{ error = 'no helper with --tune' }; exit 2 } +"RESULT tele helper=$tele sha256=$((Get-FileHash -Algorithm SHA256 $tele).Hash.ToLower())" +# tune name "" gmax gmax_range plimit plimit_range factory 0|1 ok| +$re = '^tune (\d+) name "([^"]*)" gmax (\S+) gmax_range (\S+) (\S+) plimit (\S+) plimit_range (\S+) (\S+) factory (\S+) (.*)$' +$line = $tuneBefore | Where-Object { $_ -match $re -and $_ -match '9070' } | Select-Object -First 1 +if (-not $line) { "RESULT amd_state error=no tune line for the 9070 XT in: $($tuneBefore -join ' | ')"; Summary 'failed' @{ error = 'no 9070 XT tune line' }; exit 2 } +$null = $line -match $re +$ordinal = [int]$Matches[1]; $name = $Matches[2] +"RESULT amd_state before gmax=$($Matches[3]) gmax_range=$($Matches[4])..$($Matches[5]) plimit=$($Matches[6]) plimit_range=$($Matches[7])..$($Matches[8]) factory=$($Matches[9]) verdict=$($Matches[10]) ordinal=$ordinal name='$name'" +$factoryBefore = $Matches[9] +$factoryAfter = '' +if ($factoryBefore -eq '1') { + "RESULT amd_reset skipped: the card already reads factory 1" + $factoryAfter = '1' +} else { + $r = @(& $tele --card $ordinal --reset 2>&1 | ForEach-Object { "$_" }) + $r | ForEach-Object { "RESULT amd_reset $_" } + Start-Sleep -Seconds 2 + $after = @(& $tele --tune 2>&1 | ForEach-Object { "$_" }) + $la = $after | Where-Object { $_ -match $re -and $_ -match '9070' } | Select-Object -First 1 + if ($la -and ($la -match $re)) { + $factoryAfter = $Matches[9] + "RESULT amd_state after gmax=$($Matches[3]) gmax_range=$($Matches[4])..$($Matches[5]) plimit=$($Matches[6]) plimit_range=$($Matches[7])..$($Matches[8]) factory=$factoryAfter verdict=$($Matches[10]) ordinal=$ordinal name='$name'" + } else { "RESULT amd_state after error=no tune line for the 9070 XT after the reset: $($after -join ' | ')" } + if ($factoryAfter -ne '1') { "RESULT amd_reset error=the card does not read factory 1 after --reset (reads '$factoryAfter'); the reset did not take or the flag does not follow a zero-offset reset" } +} + +# ---- READ ONLY: settings.json entries and the app's live card list ---- +$entries = 0 +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') { $entries++; "RESULT settings_entry key=$($prop.Name) enabled=$([bool] $prop.Value.enabled) identities=$($prop.Value.identities) power_pct=$($prop.Value.power_pct) pinned=$($prop.Value.pinned)" } + } +} catch { "RESULT settings_read_failed $($_.Exception.Message)" } +$liveKey = ''; $liveIdent = '' +if ($base) { + try { + $st = Invoke-RestMethod -Uri "$base/api/state" -Method GET -TimeoutSec 10 + $cards = $st.mining.cards; if (-not $cards) { $cards = $st.cards } + foreach ($c in @($cards)) { + "RESULT state_card key=$($c.key) vendor=$($c.vendor) name='$($c.name)' device=$($c.device) enabled=$($c.enabled) identities=$($c.identities) state=$($c.state) pid=$($c.pid) mhs_now=$($c.hash_now) mhs_avg=$($c.hash_avg) watts=$($c.power_w) temp=$($c.temp_gpu)" + if ($c.vendor -eq 'amd' -and ("$($c.key)" -match 'gfx1201') -and $c.state -ne 'off') { $liveKey = $c.key; $liveIdent = $c.identities } + } + "RESULT identities_answer live_key=$liveKey identities=$liveIdent (the entry the app runs the 9070 XT under, and its identities as it mines now; settings entries above: $entries)" + } catch { "RESULT state_read_failed $($_.Exception.Message) (api/state answered nothing: the settings entries above are the record)" } +} else { "RESULT state_read_skipped no app.url" } +"RESULT end $(Stamp)" +$status = if ($factoryAfter -eq '1') { 'done' } else { 'failed' } +Summary $status @{ factory_before = $factoryBefore; factory_after = $factoryAfter; helper = $tele; live_key = $liveKey; live_identities = "$liveIdent"; settings_entries = $entries } +if ($status -eq 'failed') { exit 1 } +exit 0 diff --git a/tools/ca3-pc1-amd/pc1-amd-watts.ps1 b/tools/ca3-pc1-amd/pc1-amd-watts.ps1 index 687eebcd3..3f5da7cea 100644 --- a/tools/ca3-pc1-amd/pc1-amd-watts.ps1 +++ b/tools/ca3-pc1-amd/pc1-amd-watts.ps1 @@ -1,20 +1,24 @@ -# Counter ASIC 3.0, PC 1 AMD job 1b (6 October 2026, 16:xx UTC): the WATTS re-run for the two rows job 1 left owed. -# Job 1 (run-ca3-pc1-amd-g1-shadow-20261006, 15:46 to 15:56Z) gave G1 7 of 7 and the ladder's rates but every -# LADDER row read watts=owed with samples=0: the helper's one-shot call worked (140.0 W on the 9070 XT) and the 1 Hz -# sampler wrote nothing, because Start-Process -ArgumentList in Windows PowerShell 5.1 joins its arguments WITHOUT -# quoting, and the helper's path holds a space ("Igneum Miner"), so the wrapper received a split path and its -# `& $Exe -l 1` failed silently. Here the wrapper takes its paths from environment variables (inherited by the child, -# no quoting) and the -File path is quoted; and the sampler PROVES ITSELF in the 12 idle seconds before any bench: -# the first three raw helper lines are printed, and if no 9070 XT line with watts arrived the job prints -# `RESULT watts error=` and ends WITHOUT the benches (the card restored in finally), never running blind. -# Packs: the class v3 control mx8-devnet-epoch0 and the class v4 candidate sh256x27, 90 s each, the 9070 XT ALONE -# (switched off in the installed app through POST api/cards with every key form of every settings.json entry for -# the card, confirmed quiet by the process list, each entry restored with ITS OWN settings in finally). Plain signed -# `run` job (NOT --stop-miners): the 5090 and the 4070 keep mining. Never quits, pauses, resumes or updates the app, -# never writes settings.json. Watts = ADLX board watts from the installed app's own igneum-gpu-telemetry.exe -# (a second copy at -l 1), the mean over each bench window after its first 12 s and before its last 2 s; -# microjoules per hash = watts / MH/s. Lines: `RESULT LADDER pack= ops= mhs= watts= uj= ...`, -# `RESULT G1 ...` again for the two packs, a `SUMMARY {json}` line. Read back with `node tools/jobs.mjs `. +# Counter ASIC 3.0, PC 1 AMD job 1b (6 October 2026, revised after Ember run 6): the two watts cells job 1 left owed, +# taken the way main trusts. Main's facts (Ember run 6, PC 1 through the installed app): the 9070 XT's watts are fine +# through the APP's path (the engine's telemetry 363 of 363 nonzero samples, /api/state 456 of 456); a direct helper +# call outside the app is not trusted by itself. So: +# 1. the CONTROL row (item 1's AMD per-joule row, class v3) is taken with the card ON in the app, mining the live class +# v3 program as it does now: /api/state polled at 1 Hz for 90 s, the gfx1201 card's watts (power_w, from the app's +# own helper at -l 5, so the value moves every 5 s) and its MH/s wall (hash_now, the app's last interval; hash_avg +# printed beside it), the key read from settings.json: `RESULT APPROW class=v3 mhs_wall= watts_mean= watts_min= +# watts_max= samples= uj=`. The helper sampler (a second copy of igneum-gpu-telemetry.exe at -l 1 through the +# environment-fed wrapper) runs BESIDE it over the same 90 s: `RESULT sampler_vs_app helper_mean= app_mean= ratio=`. +# 2. the CANDIDATE row (sh256x27, the card ALONE through the kit worker, which /api/state cannot see because the card is +# off in the app): the helper sampler is its only source, printed with the ratio as the calibration (`RESULT LADDER +# ... watts_source=adlx calibration_ratio=`); a ratio outside 0.95 to 1.05 prints the candidate's watts as owed with +# the reason. The sampler proves itself in the first 12 s (first three raw lines, a 9070 XT line with watts) before +# anything else, else `RESULT watts error=` and no rows. +# The card switch: every key form of every settings.json gfx1201 entry posted through POST api/cards, quiet confirmed by +# the process list (the opencl worker carrying the card's --device index gone), each entry restored with ITS OWN enabled +# flag and identities in finally (derived forms first, the key as written last). Plain signed `run` job (NOT +# --stop-miners): the 5090 and the 4070 keep mining. Never quits, pauses, resumes or updates the app; never writes +# settings.json. Lines: `RESULT APPROW ...`, `RESULT sampler_vs_app ...`, `RESULT LADDER ...`, `RESULT G1 ...` for the +# candidate, a `SUMMARY {json}` line. Read back with `node tools/jobs.mjs `. $ErrorActionPreference = 'Continue' $jobName = 'pc1-amd-watts' $kitId = 'fetch-ca3-pc1-amd-20261006' @@ -25,19 +29,17 @@ function Summary([string] $status, [hashtable] $extra) { foreach ($k in $extra.Keys) { $o[$k] = $extra[$k] } 'SUMMARY ' + ($o | ConvertTo-Json -Compress -Depth 4) } -$expected = @{ 'mx8-devnet-epoch0' = '90f794dd556f7a3b'; 'sh256x27' = '3d2e8245cc084d07' } -$opsPerHash = @{ 'mx8-devnet-epoch0' = 930; 'sh256x27' = 102100 } -# 100 dispatches of 2^24 at the 18.9 to 19.3 MH/s job 1 measured = 87 to 89 s per pack -$batches = @{ 'mx8-devnet-epoch0' = 100; 'sh256x27' = 100 } -$order = @('mx8-devnet-epoch0', 'sh256x27') +$expectedFp = '3d2e8245cc084d07' # sh256x27 at base nonce 0, 2^24 (the Mac, the 5090, PC 1 job 1) +$appWindowS = 90 +$candBatches = 100 # 2^24 dispatches at the 19.3 MH/s job 1 measured: about 87 s "RESULT start $(Stamp) job=$jobName machine=$env:COMPUTERNAME app_version=$env:IGNEUM_APP_VERSION" $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' +$packDir = Join-Path $kit 'packs\sh256x27' 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 } +if (-not (Test-Path $packDir)) { "RESULT error pack missing at $packDir"; Summary 'failed' @{ error = 'pack missing' }; exit 2 } "RESULT worker kit $exe sha256 $((Get-FileHash -Algorithm SHA256 $exe).Hash.ToLower()) bytes $((Get-Item $exe).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 $inst = @("$env:LOCALAPPDATA\Programs\Igneum Miner", "$env:ProgramFiles\Igneum Miner") | Where-Object { Test-Path (Join-Path $_ 'igneum-app.exe') } | Select-Object -First 1 @@ -46,6 +48,7 @@ $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)" +if (-not $base) { "RESULT error no app.url: the control row needs the app's /api/state"; Summary 'failed' @{ error = 'no app.url' }; exit 2 } $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 { "$_" }) @@ -70,11 +73,8 @@ try { } } } 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 settings, so an -# entry's own identities win on the live key (job 1 posted one entry's identities to every form: the class fixed here) +if ($entries.Count -eq 0) { "RESULT card none in settings.json matching amd:*gfx1201*: no switch possible" } 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) } @@ -88,9 +88,16 @@ function PostCards([bool] $enabled) { } function Workers { @(Get-CimInstance Win32_Process -Filter "Name = 'igneum-worker-opencl.exe' OR Name = 'igneum-worker-cuda.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 }) } +function StateCard { + try { + $st = Invoke-RestMethod -Uri "$base/api/state" -Method GET -TimeoutSec 5 + $cards = $st.mining.cards; if (-not $cards) { $cards = $st.cards } + return @($cards | Where-Object { $_.vendor -eq 'amd' -and ("$($_.key)" -match 'gfx1201') -and $_.state -ne 'off' } | Select-Object -First 1) + } catch { return @() } +} "RESULT workers_before $(Stamp) $((Workers) -join ' ')" -# ---- the AMD helper: one in-process sample first (the path that worked in job 1) ---- +# ---- the AMD helper: one in-process sample first ---- $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 } } @@ -103,30 +110,14 @@ if (-not $line9070 -or $line9070 -notmatch ' watts ([\d.]+) ') { "RESULT watts e $samples = Join-Path $job 'amd-samples.log' $sampler = $null -$results = @() -$cardAlone = $false $switched = $false $samplerOk = $false +$cardAlone = $false +$appRows = @() +$appT0 = $null; $appT1 = $null +$cand = $null try { - # ---- the card off, confirmed by the process list ---- - 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; paths through the ENVIRONMENT (inherited, never quoted on a - # command line), the -File path quoted; ended by its own pid in finally ---- + # ---- the sampler through the environment-fed wrapper; proven on 12 idle seconds before anything else ---- $wrapper = Join-Path $job 'sampler.ps1' $wrapperText = @' $exe = $env:IGNEUM_SAMPLER_EXE @@ -142,35 +133,59 @@ Add-Content -LiteralPath $out -Value ('wrapper end ' + (Get-Date).ToUniversalTim $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 - # ---- the proof: the first three raw lines, and a 9070 XT line with watts inside the idle window, or no benches ---- $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 benches are NOT run blind" - "RESULT LADDER pack=mx8-devnet-epoch0 error=$why" + "RESULT watts error=$why; no rows are taken" + "RESULT APPROW class=v3 error=$why" "RESULT LADDER pack=sh256x27 error=$why" } else { $samplerOk = $true "RESULT idle $(Stamp) sampler proven on the idle window" - $i = 0 - foreach ($pk in $order) { - $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 } + + # ---- 1. the control row: the card ON in the app, mining class v3; /api/state at 1 Hz for 90 s, the sampler beside ---- + $sc = @(StateCard) + if ($sc.Count -eq 0) { "RESULT APPROW class=v3 error=the app's /api/state lists no mining gfx1201 card (the card is off or the app is not running): the control row needs the card ON in the app" } + else { + "RESULT app_card key=$($sc[0].key) identities=$($sc[0].identities) state=$($sc[0].state) pid=$($sc[0].pid) mhs_now=$($sc[0].hash_now) watts=$($sc[0].power_w) (before the window)" + $appT0 = (Get-Date).ToUniversalTime() + "RESULT approw start $(Stamp) window_s=$appWindowS" + for ($i = 0; $i -lt $appWindowS; $i++) { + $c = @(StateCard) + if ($c.Count -gt 0) { $appRows += [pscustomobject]@{ ts = (Get-Date).ToUniversalTime(); w = [double] $c[0].power_w; mhs = [double] $c[0].hash_now; avg = [double] $c[0].hash_avg; state = "$($c[0].state)" } } + Start-Sleep -Seconds 1 + } + $appT1 = (Get-Date).ToUniversalTime() + "RESULT approw end $(Stamp) polls=$($appRows.Count)" + } + + # ---- 2. the candidate row: the card off in the app, the kit worker alone on sh256x27, the sampler as the only source ---- + if ($entries.Count -gt 0) { + $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})"; $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 candidate row is a LOADED-card figure" } + Start-Sleep -Seconds 8 + } + "RESULT workers_during $(Stamp) $((Workers) -join ' ')" $instrs = 0 - try { $pj = Get-Content -LiteralPath (Join-Path $d 'program.json') -Raw | ConvertFrom-Json; if ($pj.shadow) { $instrs = [int] $pj.shadow.instrs_per_hash } } catch { } - $n = $batches[$pk] - $tag = "$pk#$i" + try { $pj = Get-Content -LiteralPath (Join-Path $packDir 'program.json') -Raw | ConvertFrom-Json; if ($pj.shadow) { $instrs = [int] $pj.shadow.instrs_per_hash } } catch { } $t0 = (Get-Date).ToUniversalTime() - "RESULT bench $tag start $(Stamp) batches=$n shadow_instrs_per_hash=$instrs" - $lines = @(& $exe --bench-pack --pack $d --batches $n --batch-log2 24 --device $dev 2>&1 | ForEach-Object { "$_" }) + "RESULT bench sh256x27 start $(Stamp) batches=$candBatches shadow_instrs_per_hash=$instrs" + $lines = @(& $exe --bench-pack --pack $packDir --batches $candBatches --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)" + $lines | ForEach-Object { "RESULT bench sh256x27 $_" } + "RESULT bench sh256x27 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] } @@ -178,13 +193,12 @@ Add-Content -LiteralPath $out -Value ('wrapper end ' + (Get-Date).ToUniversalTim if ($res -and $res -match 'check=(\S+)') { $check = $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 + "RESULT G1 pack=sh256x27 error=$($err -replace '\s+', ' ')"; "RESULT LADDER pack=sh256x27 error=$($err -replace '\s+', ' ')" + } else { + "RESULT G1 pack=sh256x27 fingerprint=$fp match=$(if ($fp -eq $expectedFp) { 'yes' } else { 'no' }) expected=$expectedFp check=$check card=gfx1201 harness=opencl-kit" + $cand = [pscustomobject]@{ instrs = $instrs; mhs = $mhs; fp = $fp; t0 = $t0; t1 = $t1 } } - $match = if ($fp -eq $expected[$pk]) { 'yes' } else { 'no' } - "RESULT G1 pack=$pk fingerprint=$fp match=$match expected=$($expected[$pk]) check=$check card=gfx1201 harness=opencl-kit" - $results += [pscustomobject]@{ tag = $tag; pack = $pk; instrs = $instrs; ops = $opsPerHash[$pk]; mhs = $mhs; fp = $fp; match = $match; t0 = $t0; t1 = $t1 } - Start-Sleep -Seconds 3 - } + } else { "RESULT LADDER pack=sh256x27 error=no settings.json entry for the card: it cannot be switched off for the card-alone row" } } } finally { 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)" } } @@ -199,7 +213,7 @@ Add-Content -LiteralPath $out -Value ('wrapper end ' + (Get-Date).ToUniversalTim "RESULT workers_after $(Stamp) $((Workers) -join ' ')" } -# ---- the samples: board watts and clocks inside each bench window (after its first 12 s, before its last 2 s) ---- +# ---- the helper samples (9070 XT lines) ---- $rows = @() if (Test-Path -LiteralPath $samples) { foreach ($l in (Get-Content -LiteralPath $samples)) { @@ -212,29 +226,48 @@ if (Test-Path -LiteralPath $samples) { } } "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 }) } -$withWatts = 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) { +function Window([datetime] $t0, [datetime] $t1, [int] $head, [int] $tail) { @($rows | Where-Object { $_.ts -gt $t0.AddSeconds($head) -and $_.ts -lt $t1.AddSeconds(-$tail) -and $null -ne $_.w }) } + +# the control row from the app, and the sampler against it over the same window +$ratio = $null; $appMean = $null; $helperMean = $null +if ($appRows.Count -gt 0) { + $valid = @($appRows | Where-Object { $_.w -gt 0 }) + $m = $valid | Measure-Object -Property w -Average -Minimum -Maximum + $mh = ($valid | Measure-Object -Property mhs -Average).Average + $ma = ($valid | Measure-Object -Property avg -Average).Average + $distinct = ($valid | Select-Object -ExpandProperty w -Unique | Measure-Object).Count + $appMean = $m.Average + $uj = if ($mh -gt 0) { [math]::Round($m.Average / $mh, 3) } else { 'owed' } + "RESULT APPROW class=v3 mhs_wall=$([math]::Round($mh, 3)) mhs_avg_app=$([math]::Round($ma, 3)) watts_mean=$([math]::Round($m.Average, 1)) watts_min=$($m.Minimum) watts_max=$($m.Maximum) samples=$($valid.Count) polls=$($appRows.Count) distinct_watts=$distinct uj=$uj window_s=$appWindowS source=api/state (the app's own helper at -l 5: the watts value moves every 5 s) states=$(($appRows | Select-Object -ExpandProperty state -Unique) -join ',')" + $hin = @(Window $appT0 $appT1 0 0) + if ($hin.Count -gt 0 -and $appMean -gt 0) { + $helperMean = ($hin | Measure-Object -Property w -Average).Average + $ratio = [math]::Round($helperMean / $appMean, 4) + "RESULT sampler_vs_app helper_mean=$([math]::Round($helperMean, 1)) app_mean=$([math]::Round($appMean, 1)) ratio=$ratio helper_samples=$($hin.Count) app_samples=$($valid.Count) window_s=$appWindowS calibration=$(if ($ratio -ge 0.95 -and $ratio -le 1.05) { 'inside 0.95..1.05' } else { 'OUTSIDE 0.95..1.05' })" + } else { "RESULT sampler_vs_app error=no helper samples inside the app window (helper $($hin.Count), app mean $appMean)" } +} +# the candidate row from the sampler, calibrated +if ($cand) { + $in = @(Window $cand.t0 $cand.t1 12 2) + $watts = 'owed'; $uj = 'owed'; $gclk = 'owed'; $mclk = 'owed'; $tmax = 'owed'; $wmin = ''; $wmax = ''; $why = '' + if ($in.Count -eq 0) { $why = 'no helper samples inside the bench window' } + elseif ($null -eq $ratio) { $why = 'no calibration ratio (the app window gave no pair of means)' } + elseif ($ratio -lt 0.95 -or $ratio -gt 1.05) { $why = "calibration ratio $ratio outside 0.95..1.05: the helper's reading beside the app's disagrees; raw helper mean $([math]::Round(($in | Measure-Object -Property w -Average).Average, 1)) W kept for the record only" } + else { $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) } - $withWatts++ + if ($cand.mhs -and [double] $cand.mhs -gt 0) { $uj = [math]::Round($m.Average / [double] $cand.mhs, 3) } } - "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) fingerprint=$($r.fp) match=$($r.match) card_alone=$cardAlone tag=$($r.tag)" + "RESULT LADDER pack=sh256x27 ops=102100 shadow_instrs=$($cand.instrs) mhs=$($cand.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]($cand.t1 - $cand.t0).TotalSeconds) watts_source=adlx calibration_ratio=$ratio fingerprint=$($cand.fp) card_alone=$cardAlone$(if ($why) { " owed_reason=$why" })" } -if ($rows.Count -gt 0) { - $idle = @($rows | Where-Object { ($results.Count -eq 0 -or $_.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 ($withWatts -eq $order.Count) { 'done' } elseif ($results.Count -gt 0) { 'partial' } else { 'failed' } +if ($rows.Count -gt 0) { 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)" } } +$haveApp = $appRows.Count -gt 0 +$haveCand = $null -ne $cand -and $null -ne $ratio -and $ratio -ge 0.95 -and $ratio -le 1.05 +$status = if (-not $samplerOk) { 'failed' } elseif ($haveApp -and $haveCand) { 'done' } elseif ($haveApp -or $cand) { 'partial' } else { 'failed' } "RESULT end $(Stamp)" -Summary $status @{ packs_run = $results.Count; packs_wanted = $order.Count; rows_with_watts = $withWatts; sampler_proven = $samplerOk; card_alone = $cardAlone; device = $dev } +Summary $status @{ approw = $haveApp; candidate_row = [bool]$cand; calibration_ratio = "$ratio"; candidate_watts_taken = $haveCand; sampler_proven = $samplerOk; card_alone = $cardAlone; device = $dev } if ($status -eq 'failed') { exit 1 } exit 0