Merge branch 'ca3-pc1-amd' into ca3-coord
This commit is contained in:
commit
ee99de1b40
3 changed files with 218 additions and 91 deletions
|
|
@ -37,7 +37,8 @@ The fetch lands at `<jobs>\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=<p> ops=<N> 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=<why>`, 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 <ordinal> --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=<why>`, 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 <pack> found <n> of 1024 distinct=<d> sha256 <digest> file <path> exit=<code>` (the hash lane's form) plus `RESULT G2 pack= found= distinct= digest= digest_match=yes|no`; the found lines go to `g2-<pack>.found` in the job folder, never to stdout; the Mac re-check is `tools/ca3-v4/g2-recheck.sh proto-cuda/packs-ca3-v4/<pack> --digest <hex>` (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=<f> ratio=<r> 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 |
|
||||
|
||||
|
|
|
|||
93
tools/ca3-pc1-amd/pc1-amd-reset.ps1
Normal file
93
tools/ca3-pc1-amd/pc1-amd-reset.ps1
Normal file
|
|
@ -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 <ordinal> --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 <job id>`.
|
||||
$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 <ordinal> name "<name>" gmax <MHz> gmax_range <min> <max> plimit <offset %> plimit_range <min> <max> factory 0|1 ok|<error>
|
||||
$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
|
||||
|
|
@ -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=<why>` 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=<name> ops=<N> mhs=<x> watts=<y> uj=<z> ...`,
|
||||
# `RESULT G1 ...` again for the two packs, a `SUMMARY {json}` line. Read back with `node tools/jobs.mjs <job id>`.
|
||||
# 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=<why>` 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 <job id>`.
|
||||
$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
|
||||
|
|
|
|||
Loading…
Reference in a new issue