Skip to content

GPU clock: trace which NVPCF branch the 620 nvidia-powerd takes at start #3

Closed

Description

@seankd3

Task

Find out which NVPCF branch the unmodified 620 nvidia-powerd (sha256 eb9e0371…) takes when it starts on this laptop. Use one bounded bpftrace start on the 620 boot. The probes only read registers and memory. The traced powerd is not read-only: it makes its normal vendor calls, and these can include requests that set platform values. The trace forces and overrides nothing.

Context

  • The GPU clock cap is not fixed. Under sustained FP32 and BF16 GEMM, the reported SM clock settles at about 721-754 MHz with reason 0x400 (GPU diagnostic: run the exact GEMM check with BF16 inputs as well as FP32 #1). This issue does not unlock the GPU. It is one diagnostic step.
  • Observed on the 620 driver: nvidia-powerd exits 0 after about 0.25 s and logs its quit message. Which route it takes is not measured.
  • In the static code, two conditional routes end in a quit with no worker:
    • (a) the NVPCF 3x init returns true, and that factory branch creates no worker;
    • (b) 3x and 2x/1x both report not supported.
      Which route runs on this laptop is unmeasured. The platform's 3x GET_SUPPORTED query returns 0x3f. That closes only the ACPI capability binding. It does not rank (a) over (b).
  • A trace design exists, with 11 read-only probes under bpftrace -c. The review found three corrections before any run:
    1. The "primitive load" result carries no information. The wrapper at 0x1521b0 returns 0 whether it calls 0x14dc70 or skips it because the pointer at +0x17f0 is NULL. The binary logs "ObjPrimitiveLinux loaded successfully" on both paths. The probe must read the pointer at 0x1521bc instead.
    2. Exit reporting. bpftrace's exit code is not powerd's. The child's exit code or signal is logged only with -v. A timeout or -k kill has its own meaning.
    3. Binary pin. The start step must check the binary hash, so the 71 build can never start under the trace.

Status

The design is under review. There is no source and no run yet. The trace needs the 620 boot, which does not happen while other work on the laptop needs the current boot.

Activity

  1. seankd3 commented on Nov 5, 2026

    @seankd3
    OwnerAuthor

    Shape card

    Problem. Which NVPCF route the unmodified 620 nvidia-powerd takes on this laptop is unmeasured. The existing trace design reads a wrapper result that is 0 on both routes it was meant to tell apart.

    The thing. One bpftrace program, scripts/powerd620-nvpcf-branch.bt, and one short doc, docs/powerd620-nvpcf-trace.md. The doc holds the run command and the fixed reading rules. The program is the reviewed lab design (11 probes, bpftrace -c, every probe filtered on pid == cpid) with three changes:

    1. Replace the probe at 0x7367c with one at 0x1521bc, which prints reg("r0"). That is the +0x17f0 pointer after the load and before the cbz. 0 means the wrapper skipped the call. Nonzero means the call path was chosen. Neither proves an ongoing loop or a working controller.
    2. Mark the two stack reads as user space: *uptr((uint64 *)($sp + 0x68)) and *uptr((uint8 *)($sp + 0x70)). The bpftrace 0.27 docs (Language, Address Spaces) say auto-inference can fail.
    3. The run command uses -k and -v. -k reports probe-read helper errors, which are hidden by default. -v logs the child's exit code or signal.

    Side effects. The probes only read registers and memory. The traced powerd is not read-only: it makes its normal vendor calls, and these can include requests that set platform values. The trace forces, overrides and spoofs nothing.

    Facts and reads.

    • Stored:

      • the trace lines (event, nsecs, pid, raw values);
      • stderr (helper warnings, lost events, attach errors, the child exit line);
      • the exit code;
      • the before and after pins.
    • Computed: the route, by this ordered rule list:

      1. VALID only if all of these hold. Otherwise the result is INCONCLUSIVE.

        • The exit code is 0, so bpftrace ended because powerd ended.
        • stderr has Child exited with code: 0, not terminated by signal.
        • Both BEGIN and END lines are present.
        • factory_create_entry is present.
        • stderr has no Failed to probe_read warning, no lost events and no attach or parse error.

        A timeout (124), a -k kill (137) or a signal-terminated child never counts as a normal exit.

      2. Route (a): init bool=1, factory_3x_true_branch, main_no_worker. The pointer value from change 1 is reported with it.

      3. Route (b), fallback to 2x/1x: init bool=0, factory_3x_false_branch and nvpcf2x_ret present, with the raw value reported.
        The 3x query result does not decide the route. Its has_value and raw value are reported separately for both routes:

        • has_value=0: the query failed with a status (0x56 is not supported);
        • has_value=1: the query succeeded. The init return separately shows whether initialization succeeded.
      4. Anything else: INCONCLUSIVE, with the events listed.

      quit_entry w0=2 is reported but does not decide anything, because 2 is also SIGINT. main_no_worker is the discriminator.

    Impossible states.

    • The program cannot write or override anything.
    • The run command checks /usr/bin/nvidia-powerd sha256 eb9e0371f73667f242e8d4742e17a21a68470e08cdc6438a84c263a4c3b6f4d2 and /@nv620 before the start, so the 71 build cannot start under the trace.
    • A helper read error or a cut run cannot read as a route.

    Deletes.

    • The 0x7367c probe.
    • The rule "w0 != 0 means the load failed". That path cannot be reached.
    • The wrong claim that "the timeout fires, -k 5 kills bpftrace". In fact, on TERM bpftrace runs END and SIGKILLs a powerd that is still alive. -k 5 kills bpftrace only if it is still alive 5 s later, and then powerd gets SIGTERM through PDEATHSIG (bpftrace v0.27.0 src/util/proc.cpp).
    • The lab copy of the design, after merge, once the root checks its consumers.

    Acceptance (one command, later, on the 620 boot only, separately authorized).
    sudo -n timeout -k 5 60 bpftrace -k -v -q -o T-trace.txt -c /usr/bin/nvidia-powerd scripts/powerd620-nvpcf-branch.bt 2> T-stderr.txt
    The pins run first. The result is read only by the rule list above. Before merge: static review only. The diff against the lab design must show exactly the three changes, and every probe offset must be an instruction start in the 620 disassembly.

    Plan. This issue, one branch from fork main f23be84 in the existing worktree, created only after this card passes, and one small PR with the .bt, the doc and one README link line. About 800 tokens of code and 600 of docs. No helper and no framework.

    Package prep plan (offline into @nv620, no reboot; not run)

    Root @nv620 has UUID aa28477c-4598-fd40-8804-6f1fbfb158b2. The reviewed helper is $DC/stage-chroot.sh (sha256 7deeadcf…).
    S="taskset -c 0,1 nice -n19 ionice -c3 sudo -n unshare --mount --propagation private sh $DC/stage-chroot.sh @nv620 aa28477c-4598-fd40-8804-6f1fbfb158b2"

    The chroot gets a fresh /run, which hides the live /etc/resolv.conf target (../run/systemd/resolve/stub-resolv.conf). So the chroot does no network work. The live side downloads and verifies the files, and the chroot installs them offline.

    1. Pins.
      • The live root is /@nv71.
      • The helper hash is 7deeadcf….
      • The lab nv620-steps/hookcheck.sh hash is f9e9b81c….
      • The private run directory $P is new, with mode 700.
    2. Live baseline (before).
      • sha256 of every file under /boot, and of the Boot*, Loader* and Limine* efivars.
      • The pacman -Q hash and the live sync DB hashes.
      • The enabled unit-file list hash.
      • systemctl is-active nvidia-powerd must report inactive.
    3. Resolve (live, no root): pacman -Sp bpftrace must give exactly bcc-0.37.0-2-aarch64.pkg.tar.xz and bpftrace-0.27.0-2-aarch64.pkg.tar.xz.
    4. Download (live, no root): curl -fL each package and its .sig into $P. No pacman cache and no -Sw.
    5. Verify (live).
      • sha256 must equal the live sync DB %SHA256SUM%: bcc 6d7ce098…, bpftrace 7d779ab8….
      • sudo -n pacman-key --verify must report a good signature for both.
    6. Chroot gate.
      • The helper must print stage-chroot: @nv620 aa28477c-….
      • The bounds check must print 2, 0-1, 19 and idle.
      • $S sha256sum /var/tmp/nv620/hookcheck.sh must be f9e9b81c….
      • $S sh /var/tmp/nv620/hookcheck.sh must print 11 × masked with rc 0.
      • $S pacman -Q bcc bpftrace must find neither.
    7. Copy in: $S sh -c 'mkdir -p -m 700 /var/tmp/nv620/btpkg && cat > /var/tmp/nv620/btpkg/<name>' < $P/<name> for the 4 files. Then $S sha256sum must equal the hashes in $P.
    8. Chroot signature: $S pacman-key --verify checks both files against the candidate's own keyring.
    9. Plan only: $S pacman --hookdir /etc/pacman.d/hooks --hookdir /var/tmp/nv620/hookmask -Up --print-format '%n %v' <2 files> must print exactly bcc 0.37.0-2 and bpftrace 0.27.0-2. Any dependency line means stop.
    10. Install: $S pacman --hookdir /etc/pacman.d/hooks --hookdir /var/tmp/nv620/hookmask --noconfirm -U <2 files>. No -S, -Sy or -Syu, no kernel and no other package.
    11. Chroot after.
      • pacman -Q shows the two versions.
      • This transaction in pacman.log installs only these two, with no running line for a masked hook.
      • ldd /usr/bin/bpftrace has no not found.
      • bpftrace --version reports v0.27.0. That loads no BPF.
      • The /etc/fstab root line still has subvol=/@nv620.
    12. Live after: the step 2 baseline is identical, and the live pacman -Q bcc bpftrace finds neither.

    Rollback (inside @nv620 only): $S pacman --hookdir /etc/pacman.d/hooks --hookdir /var/tmp/nv620/hookmask --noconfirm -R bpftrace bcc.

    Not done: no reboot, no BPF load or attach, no GPU or CUDA call, no live package, service, ESP or config change, and no powerd start.

    The GPU clock goal is not fixed.

  2. seankd3 commented on Nov 5, 2026

    @seankd3
    OwnerAuthor

    Review record: shape card and package plan

    Both passes were fresh Terra (gpt-6.1-terra) reviews, read-only, run by the root session.

    Elegance: PASS. The pass accepts:

    • the one .bt plus doc shape with exactly three changes to the reviewed design;
    • the 11-probe count and the pointer read at 0x1521bc;
    • the existing stage-chroot.sh boundary and the offline package plan;
    • the estimated 800 code and 600 doc tokens.

    Bugs: FAIL, 1 blocking finding. The route rule required has_value=0 for route (b). The 3x query can succeed while the init still fails, and the factory then takes the false branch into 2x. The old rule called that observed fallback INCONCLUSIVE. The package plan had no reported blocker.

    Response. I edited the card's rule list in place: #3 (comment)

    • The route now comes from the init result, the factory branch and the 2x return.
    • The 3x query result (has_value and raw) is reported separately for both routes, and decides neither. So route (a) no longer requires has_value=1 either.
    • The probes, the probe count, the pointer read, the validity rules and the package plan are unchanged.

    A reviewer said the worktree was absent. The root checked it directly: it exists, it is registered, and it is clean at 3b1c1d7. There is no checkout blocker.

    Status. This waits for a fresh Terra delta review. There is no branch, no source and no install yet. The no-reboot hold stays. The GPU clock goal is not fixed.

  3. seankd3 commented on Nov 5, 2026

    @seankd3
    OwnerAuthor

    Review record: card revision of 2026-11-05T23:45:56Z

    • The root corrected one wording point in the card: has_value=1 means only that the query succeeded. The init return separately shows whether initialization succeeded.
    • Both fresh Terra delta passes (bugs and elegance) confirmed that revision. The earlier route (b) finding is closed.
    • The shape and the package-prep plan now pass both reviews.
    • Next: implement the approved change on a new branch from fork main f23be84. Then run static checks only and push. The exact-commit Terra reviews come before the PR. There is no install, BPF, powerd or GPU step, and no reboot.
  4. seankd3 commented on Nov 5, 2026

    @seankd3
    OwnerAuthor

    Offline package staging commands (for the root's review; not run)

    This is the approved plan as one literal script, nv620-btpkg-stage.sh (sha256 81aea327fc86c8953eca5a4c6dd66ef6e359032cdcf2ed72e69beadeaee1dd3c). Save it and run it with bash <file> on the live @nv71 root. Only bash -n was run on it.

    Revision 2 (replaces 8e96d3a2… after the root's review):

    • Identity: c() now matches the unchanged helper's real first line, stage-chroot: @nv620 aa28477c-… at /run/stage-nv620. The helper itself is not edited (7deeadcf…).
    • pacman evidence covers only this transaction:
      • Before the install, the script records the line count of the candidate's pacman.log. After the install it reads only the new lines.
      • Those lines must hold exactly this Running 'pacman … -U' line, one transaction start and one transaction end, and exactly installed bcc (0.37.0-2) and installed bpftrace (0.27.0-2) with no other package change. There must be no running line for a masked hook.
      • A synthetic-log check passes a clean transaction and stops on an extra upgrade or a masked hook.

    Unchanged from the reviewed plan:

    • It uses the reviewed stage-chroot.sh with root @nv620, UUID aa28477c-4598-fd40-8804-6f1fbfb158b2, taskset -c 0,1, nice 19 and idle IO.
    • Downloads and signatures go to a new private run directory, apart from source.
    • The live side only reads and downloads. The baseline is taken before and after, and both must match.
    • Signatures are checked only against the candidate's own keyring.
    • bcc and bpftrace are each checked as absent, one at a time.
    • hookcheck.sh must print 11 masked lines.
    • A plan-only -Up must list exactly the two packages, then one offline pacman -U runs with the hook masks.
    • Rollback inside @nv620 only: $S pacman --hookdir /etc/pacman.d/hooks --hookdir /var/tmp/nv620/hookmask --noconfirm -R bpftrace bcc.
    #!/bin/bash
    # Stage bcc 0.37.0-2 and bpftrace 0.27.0-2 offline into @nv620 from the live @nv71 root. No reboot, no BPF load,
    # no live package/service/ESP/config change. Downloads and signatures stay in a private run dir, apart from source.
    set -euo pipefail
    DC=$HOME/.floor-poller/gpu-clock/opus-linux/driver-candidate
    U620=aa28477c-4598-fd40-8804-6f1fbfb158b2
    S="taskset -c 0,1 nice -n19 ionice -c3 sudo -n unshare --mount --propagation private sh $DC/stage-chroot.sh @nv620 $U620"
    BCC=bcc-0.37.0-2-aarch64.pkg.tar.xz; BT=bpftrace-0.27.0-2-aarch64.pkg.tar.xz; Q=/var/tmp/nv620/btpkg
    HM="--hookdir /etc/pacman.d/hooks --hookdir /var/tmp/nv620/hookmask"
    MASKED='10-limine-snapper-lock|60-limine-mkinitcpio-remove-pre|60-mkinitcpio-remove|70-dkms-install|70-dkms-upgrade|71-dkms-remove|80-limine-efi-deploy|90-limine-mkinitcpio-remove-post|90-mkinitcpio-apple-install|90-mkinitcpio-install|99-omarchy-limine'
    P=$HOME/.floor-poller/gpu-clock/runs/nv620-btpkg-$(date +%m%d-%H%M%S); mkdir -m 700 "$P"; cd "$P"; umask 077
    # c CMD...: run CMD in the @nv620 chroot; the first output line must be the helper's identity line.
    c() { local rc=0; $S "$@" > C.out 2>&1 || rc=$?
      [ "$(sed -n 1p C.out)" = "stage-chroot: @nv620 $U620 at /run/stage-nv620" ] || { cat C.out; echo "IDENTITY FAIL"; exit 9; }
      sed 1d C.out; return $rc; }
    base() { sudo -n find /boot -xdev -type f -print0 | sort -z | sudo -n xargs -0 sha256sum
      for v in /sys/firmware/efi/efivars/Boot* /sys/firmware/efi/efivars/Loader* /sys/firmware/efi/efivars/Limine*; do
        if [ -e "$v" ]; then sudo -n sha256sum "$v"; fi; done
      pacman -Q | sha256sum; sha256sum /var/lib/pacman/sync/*.db
      systemctl list-unit-files --state=enabled --no-legend | sha256sum; systemctl is-active nvidia-powerd || true; }
    
    # 1. Pins
    [ "$(findmnt -no FSROOT /)" = /@nv71 ]
    echo "7deeadcfa88f01af140c11296977f84439692ec81fe8a521a285de0e71bdd42f  $DC/stage-chroot.sh" | sha256sum -c --quiet
    echo "f9e9b81c31f630c12728eb9f2ba3e5166922ecdb41dcfed784e9577a98eeca4e  $DC/nv620-steps/hookcheck.sh" | sha256sum -c --quiet
    for p in bcc bpftrace; do if pacman -Q $p > /dev/null 2>&1; then echo "live has $p"; exit 9; fi; done
    # 2. Live baseline
    base > A-before.txt; [ "$(tail -1 A-before.txt)" = inactive ]
    # 3-5. Resolve, download and hash-check on the live side (no root, no pacman cache, no -Sw)
    pacman -Sp bpftrace > A-urls.txt
    [ "$(wc -l < A-urls.txt)" = 2 ]; grep -q "/$BCC\$" A-urls.txt; grep -q "/$BT\$" A-urls.txt
    while read -r u; do curl -fsSL -o "${u##*/}" "$u"; curl -fsSL -o "${u##*/}.sig" "$u.sig"; done < A-urls.txt
    printf '%s  %s\n' 6d7ce09805b1a25beefbac74d6cd6cfb23160c224fdc9f87242aee15f8160e37 $BCC \
      7d779ab8f4b0a87f036587f131d511d86f20b709114a225dbfd1e5ac5de97207 $BT | sha256sum -c
    sha256sum $BCC $BCC.sig $BT $BT.sig > A-files.sha
    # 6. Chroot gate: identity, bounds, hook masks, both packages absent (each one checked alone)
    c sh -c 'nproc; grep Cpus_allowed_list /proc/self/status; cut -d" " -f19 /proc/self/stat; ionice' > B-bounds.txt
    [ "$(sed -n 1p B-bounds.txt)" = 2 ]; grep -Eq '^Cpus_allowed_list:\s+0-1$' B-bounds.txt
    [ "$(sed -n 3p B-bounds.txt)" = 19 ]; [ "$(sed -n 4p B-bounds.txt)" = idle ]
    c sha256sum /var/tmp/nv620/hookcheck.sh | grep '^f9e9b81c31f630c12728eb9f2ba3e5166922ecdb41dcfed784e9577a98eeca4e ' > /dev/null
    c sh /var/tmp/nv620/hookcheck.sh > B-hookcheck.txt; [ "$(grep -c '^masked ' B-hookcheck.txt)" = 11 ]
    for p in bcc bpftrace; do if c pacman -Q $p > B-absent-$p.txt; then echo "@nv620 has $p"; exit 9; fi; done
    # 7. Copy in through stdin, then compare hashes
    c sh -c "[ ! -e $Q ] && mkdir -m 700 $Q"
    for f in $BCC $BCC.sig $BT $BT.sig; do c sh -c "cat > $Q/$f" < "$f"; done
    c sh -c "cd $Q && sha256sum $BCC $BCC.sig $BT $BT.sig" | diff A-files.sha -
    # 8. Signatures against the candidate's own keyring
    for f in $BCC $BT; do c pacman-key --verify $Q/$f.sig $Q/$f >> B-sigs.txt; done
    # 9. Plan only: exactly the two packages, no dependency
    c pacman $HM -Up --print-format '%n %v' $Q/$BCC $Q/$BT > B-plan.txt
    [ "$(sort B-plan.txt)" = "$(printf 'bcc 0.37.0-2\nbpftrace 0.27.0-2')" ]
    # 10. Offline install with the hook masks (no -S, -Sy or -Syu). N = log lines before this transaction.
    N=$(c sh -c '[ -e /var/log/pacman.log ] && wc -l < /var/log/pacman.log || echo 0'); echo "$N" > C-loglines-before.txt
    if c pacman $HM --noconfirm -U $Q/$BCC $Q/$BT > C-install.txt; then echo "install rc=0" > C-rc.txt
    else rc=$?; echo "install rc=$rc" > C-rc.txt; exit 8; fi
    # 11. Chroot after
    c pacman -Q bcc bpftrace > C-q.txt; [ "$(cat C-q.txt)" = "$(printf 'bcc 0.37.0-2\nbpftrace 0.27.0-2')" ]
    c tail -n +$((N + 1)) /var/log/pacman.log > C-pacmanlog.txt        # only this transaction's lines
    grep -q "\[PACMAN\] Running 'pacman $HM --noconfirm -U $Q/$BCC $Q/$BT'" C-pacmanlog.txt
    [ "$(grep -c '\[ALPM\] transaction started' C-pacmanlog.txt)" = 1 ]
    [ "$(grep -c '\[ALPM\] transaction completed' C-pacmanlog.txt)" = 1 ]
    [ "$(grep -E '\[ALPM\] (installed|upgraded|downgraded|reinstalled|removed) ' C-pacmanlog.txt | sed 's/^.*\] //')" \
      = "$(printf 'installed bcc (0.37.0-2)\ninstalled bpftrace (0.27.0-2)')" ]
    if grep -Eq "running '($MASKED)\.hook'" C-pacmanlog.txt; then echo "masked hook ran"; exit 9; fi
    c ldd /usr/bin/bpftrace > C-ldd.txt; if grep -q 'not found' C-ldd.txt; then exit 9; fi
    c bpftrace --version > C-version.txt; grep -q 'v0.27.0' C-version.txt
    c sh -c "awk '\$2 == \"/\"' /etc/fstab" | grep -E 'subvol=/@nv620([[:space:],]|$)' > /dev/null
    # 12. Live after: identical baseline, both packages still absent on the live root
    base > A-after.txt; diff A-before.txt A-after.txt
    for p in bcc bpftrace; do if pacman -Q $p > /dev/null 2>&1; then echo "live has $p"; exit 9; fi; done
    echo "STAGED OK $P"

    No reboot, mount, BPF attach, powerd start or GPU call has happened. The GPU clock goal is not fixed.

  5. seankd3 commented on Nov 6, 2026

    @seankd3
    OwnerAuthor

    Staging result and compile-only command (for the root to run; not run)

    Staging, verified from the raw files (runs/nv620-btpkg-1105-180828, script 81aea327…, one execution):

    • install rc=0. Before the install, bcc and bpftrace were each checked absent. After the install, pacman -Q shows exactly bcc 0.37.0-2 and bpftrace 0.27.0-2.
    • Both signatures are good in the candidate's own keyring (Arch Linux ARM Build System key 68B3537F…, trust full). There are 11 masked lines, and ldd has nothing not found.
    • bpftrace --version reports v0.27.0-872e7a56a, the tag commit.
    • The pacman.log lines for this transaction are exactly the -U line, a start, two installed lines and a completion. The only hook was 35-systemd-update, which is not masked.
    • The live baseline (ESP, efivars, packages, sync DB, enabled units, nvidia-powerd inactive) is identical before and after.

    Compile-only command (sha256 2db69f17ea66174cc5c522076f7c0bae0b47f5c1f4f12ea5d90085a64a0b0bc9; only bash -n was run on it):

    (
      set -euC; umask 077
      DC=$HOME/.floor-poller/gpu-clock/opus-linux/driver-candidate
      U620=aa28477c-4598-fd40-8804-6f1fbfb158b2
      P=$HOME/.floor-poller/gpu-clock/runs/nv620-btpkg-1105-180828
      B=/home/sean/.t3/worktrees/asus-proart-p16-rtx-spark-linux/t3-n1x-bf16-gemm/scripts/powerd620-nvpcf-branch.bt
      cd "$P"; [ "$(cat C-rc.txt)" = "install rc=0" ]
      for f in D-codegen.out D-codegen.err D-codegen-rc.txt; do [ ! -e "$f" ]; done
      echo "7deeadcfa88f01af140c11296977f84439692ec81fe8a521a285de0e71bdd42f  $DC/stage-chroot.sh" | sha256sum -c --quiet
      echo "812e5a8643800e5d0ee24da0ed4edc4193f805f425d35d6f2d099eb59c79dbf6  $B" | sha256sum -c --quiet
      set +e
      taskset -c 0,1 nice -n19 ionice -c3 sudo -n unshare --mount --propagation private sh "$DC/stage-chroot.sh" @nv620 "$U620" \
        sh -c 'echo "eb9e0371f73667f242e8d4742e17a21a68470e08cdc6438a84c263a4c3b6f4d2  /usr/bin/nvidia-powerd" | sha256sum -c --quiet || exit 90
               exec bpftrace --mode=codegen -k -c /bin/true -' < "$B" > D-codegen.out 2> D-codegen.err
      rc=$?; echo "rc=$rc" > D-codegen-rc.txt
      [ "$(sed -n 1p D-codegen.out)" = "stage-chroot: @nv620 $U620 at /run/stage-nv620" ] || echo "IDENTITY FAIL" >> D-codegen-rc.txt
      cat D-codegen-rc.txt; exit "$rc"
    )
    • What runs: the unchanged helper (7deeadcf…) enters @nv620 (identity line stage-chroot: @nv620 aa28477c-… at /run/stage-nv620). Inside the chroot, the command pins /usr/bin/nvidia-powerd to the 620 binary eb9e0371… and exits 90 if it does not match. Then it runs bpftrace --mode=codegen -k -c /bin/true -.

    • Input: the reviewed program, sha256 812e5a86… at 623995d, comes in on stdin (-). There is no other copy of the source.

    • Evidence: D-codegen.out, D-codegen.err and D-codegen-rc.txt go into the existing private staging run directory. The command refuses to overwrite them. The exit code and stderr are kept when they are nonzero.

    • Why this does not attach or start a target (bpftrace v0.27.0 source, commit 872e7a56):

      • src/main.cpp 1032–1040: -c clones the child before compilation.
      • src/util/proc.cpp childfn: the clone waits for a command before execve.
      • src/bpftrace.cpp around line 489: the only child_->run(...) is inside BPFtrace::run, which only run_bpftrace reaches (src/run_bpftrace.cpp line 236).
      • src/main.cpp 1210–1211: if (args.mode == Mode::CODEGEN) return 0; returns before that.

      So no probe attaches, no NVIDIA target runs, and /bin/true is not run either. bpftrace kills the waiting clone when it exits. There is no --dry-run, which attaches.

    • Not claimed: whether bpftrace's feature checks load small BPF programs during compilation. That is not checked.

    • Exit codes:

      • 0: compiled.
      • 1: a bpftrace error (parse, semantic or probe resolution) or sudo -n.
      • 9: the helper refused.
      • 90: the 620 binary pin failed.
    • Accept only if all of these hold:

      • D-codegen-rc.txt is rc=0 with no IDENTITY FAIL;
      • D-codegen.err holds no ERROR line.

      Report every other stderr line raw, for the root to rule on.

    No reboot, trace attach, powerd start or GPU call. The GPU clock goal is not fixed.

  6. seankd3 commented on Nov 6, 2026

    @seankd3
    OwnerAuthor

    Compile-only attempt 1 result, and attempt 2 command (for the root to run; not run)

    Attempt 1 (2db69f17…, one run, D-* files kept): rc=1. The error was Failed to open kernel function info: Error reading events from /sys/kernel/tracing/available_events (No such file or directory). Causes, from bpftrace v0.27.0 src/symbols/kernel.cpp:

    • KernelInfoImpl::open reads available_events before it compiles, and a missing file is a hard error.
    • available_filter_functions is read too. A missing file there only gives a warning.
    • src/tracefs/tracefs.cpp uses /sys/kernel/debug/tracing if it exists, else /sys/kernel/tracing.
    • The helper's fresh read-only sysfs has no tracefs on that path.

    Why not a fresh tracefs mount. In kernel v7.2 fs/tracefs/inode.c, tracefs_get_tree() calls tracefs_reconfigure() on every new mount, read-only mounts included. That copies the new mount's options into the one shared tracefs superblock, then runs sync_filesystem. The host mount shows default options (rw,nosuid,nodev,noexec,relatime, no uid, gid or mode), so the values would be the same. It would still be a write to host tracefs state.

    Attempt 2: bind the existing mount read-only, inside the private namespace only.

    1. In the new private mount namespace, before the helper runs, sh opens fd 9 on /sys/kernel/tracing. That is the namespace's own copy of the host tracefs mount.
    2. The unchanged helper (7deeadcf…) enters @nv620.
    3. Inside the chroot:
      • the 620 binary pin runs first, with exit 90 on a mismatch;
      • then mount --bind -c -o ro /proc/self/fd/9 /sys/kernel/tracing runs, with exit 91 on failure;
      • fd 9 is closed;
      • the mountinfo line is recorded as evidence;
      • then exec bpftrace --mode=codegen -k -c /bin/true - runs with the reviewed .bt (812e5a86…) on stdin.
    4. A bind mount does not call get_tree, so nothing is written to the superblock. The mount is read-only per mount, so any tracefs write would fail. The bind exists only in the private namespace and goes away when the command exits. No tracing setting is written, nothing attaches, and no NVIDIA process runs.

    Command (sha256 1f1d2dfdc48edd0eb79a7854b7a072dcbfdcc38dd97b36ba0855d7894d379b2f; outer bound timeout -k 5 120; evidence in new E-* files in the existing private run directory):

    (
      set -euC; umask 077
      DC=$HOME/.floor-poller/gpu-clock/opus-linux/driver-candidate
      U620=aa28477c-4598-fd40-8804-6f1fbfb158b2
      P=$HOME/.floor-poller/gpu-clock/runs/nv620-btpkg-1105-180828
      B=/home/sean/.t3/worktrees/asus-proart-p16-rtx-spark-linux/t3-n1x-bf16-gemm/scripts/powerd620-nvpcf-branch.bt
      cd "$P"; [ "$(cat C-rc.txt)" = "install rc=0" ]; [ "$(cat D-codegen-rc.txt)" = "rc=1" ]
      for f in E-codegen.out E-codegen.err E-codegen-rc.txt; do [ ! -e "$f" ]; done
      echo "7deeadcfa88f01af140c11296977f84439692ec81fe8a521a285de0e71bdd42f  $DC/stage-chroot.sh" | sha256sum -c --quiet
      echo "812e5a8643800e5d0ee24da0ed4edc4193f805f425d35d6f2d099eb59c79dbf6  $B" | sha256sum -c --quiet
      # Runs inside the chroot. fd 9 is the private namespace's copy of the host tracefs mount, opened before chroot.
      INNER='echo "eb9e0371f73667f242e8d4742e17a21a68470e08cdc6438a84c263a4c3b6f4d2  /usr/bin/nvidia-powerd" | sha256sum -c --quiet || exit 90
    mount --bind -c -o ro /proc/self/fd/9 /sys/kernel/tracing || exit 91
    exec 9<&-
    grep " /sys/kernel/tracing " /proc/self/mountinfo
    exec bpftrace --mode=codegen -k -c /bin/true -'
      set +e
      timeout -k 5 120 taskset -c 0,1 nice -n19 ionice -c3 sudo -n unshare --mount --propagation private \
        sh -c 'exec 9</sys/kernel/tracing || exit 92; exec sh "$1" @nv620 "$2" sh -c "$3"' sh "$DC/stage-chroot.sh" "$U620" "$INNER" \
        < "$B" > E-codegen.out 2> E-codegen.err
      rc=$?; echo "rc=$rc" > E-codegen-rc.txt
      [ "$(sed -n 1p E-codegen.out)" = "stage-chroot: @nv620 $U620 at /run/stage-nv620" ] || echo "IDENTITY FAIL" >> E-codegen-rc.txt
      sed -n 2p E-codegen.out | grep -q ' /sys/kernel/tracing ro,' || echo "TRACEFS NOT RO" >> E-codegen-rc.txt
      cat E-codegen-rc.txt; exit "$rc"
    )

    Checks done (no root, no tracefs, no bpftrace):

    • bash -n passes.
    • Mechanism test: in an unprivileged user and mount namespace with dummy directories, a directory fd opened before chroot was bind-mounted read-only from inside it, with and without -c. mountinfo showed ro, a write failed with Read-only file system, and the source stayed unchanged.
    • Quoting harness: the same command, with only paths, hashes and sudo changed for the test, ran in a user namespace with a stub helper and a stub bpftrace. It gave:
      • the identity line first, then the ro tracefs mountinfo line;
      • a stub that received --mode=codegen -k -c /bin/true - and the program on stdin;
      • fd 9 closed before exec, and rc=0;
      • a refusal when run again with E-* files present.

    Exit codes:

    • 0: compiled.
    • 1: a bpftrace error, or sudo -n.
    • 9: the helper refused.
    • 90: the 620 binary pin failed.
    • 91: the bind failed.
    • 92: fd 9 could not be opened.
    • 124 or 137: the 120 s bound was hit.

    Accept only if all of these hold:

    • E-codegen-rc.txt is rc=0, with no IDENTITY FAIL and no TRACEFS NOT RO;
    • E-codegen.err holds no ERROR line.

    Every other stderr line is reported raw. I make no claim about whether bpftrace's feature checks load small BPF programs.

    The D-* files are untouched. No PR until the parser is accepted. The GPU clock goal is not fixed.

  7. seankd3 commented on Nov 6, 2026

    @seankd3
    OwnerAuthor

    Compile-only acceptance: PASS (root, once, no reboot)

    • Command: /tmp/nv620-bt-codegen-e.sh sha256 1f1d2dfd…, under timeout -k 5 120. The live root stayed /@nv71 with driver 615.71.09 loaded.
    • E-codegen-rc.txt: rc=0, with no IDENTITY FAIL and no TRACEFS NOT RO.
    • E-codegen.out: stage-chroot: @nv620 aa28477c-4598-fd40-8804-6f1fbfb158b2 at /run/stage-nv620, then … / /sys/kernel/tracing ro,nosuid,nodev,noexec,relatime - tracefs tracefs rw. The ro applies to the bind mount only. The superblock flag shows rw because the host's superblock is untouched.
    • E-codegen.err: empty, so there were no errors and no warnings.
    • Evidence hashes:
      • E-codegen.out 3976c5de…
      • E-codegen.err e3b0c442… (empty)
      • E-codegen-rc.txt 93ff7811…
      • The first attempt is kept unchanged: D-codegen.err 0f8b609e…, D-codegen-rc.txt 91d957f8….

    What this proves: bpftrace 0.27.0 parses and compiles the reviewed program (812e5a86…), resolving its probes against the real 620 binary eb9e0371… inside @nv620, including the uptr() stack reads. It does not prove which route powerd takes, and it does not fix anything. Codegen mode attaches no probe and runs no target. I make no claim about bpftrace's feature checks.

  8. seankd3 commented on Nov 6, 2026

    @seankd3
    OwnerAuthor

    PR #5 merged; next runtime requirement; GPU-test repoint proposal (not applied)

    Merged. PR #5 was squash-merged as 4167ee49623539c58e3adbbf8d1f829c8d243f24 (2026-11-06 00:21:08Z) from the reviewed head 623995d. The program scripts/powerd620-nvpcf-branch.bt has sha256 812e5a86…. This issue stays open, because the route has not been measured on hardware.

    Next runtime requirement, in order. Each step needs its own authorization, and the reboot needs Sean's go.

    1. Review this repoint proposal. Then the root runs apply-block.sh once, and it must print APPLY PASS.
    2. One-shot GPU-test and one reboot. Both are blocked by the current no-reboot hold.
    3. On the 620 boot, these pre-checks must hold:
      • root /@nv620, with driver 620.70.06 loaded and the RMSkipACPIBattCap=1 key;
      • AC online;
      • no nvidia-powerd process, and its unit inactive;
      • bpftrace 0.27.0 present (it is staged in @nv620).
    4. Run the merged doc's run block once, with REPO pointing at a checkout that holds 812e5a86… and with a private RUNS. Read the result only by the fixed rules. The result is a route at start, not a running controller.
    5. A plain reboot returns to default_entry 1, the normal entry.

    Repoint proposal (lab directory driver-candidate/boot-menu-nv620-repoint/, mode 700):

    • Live menu read as root, read-only: sha256 47713d991922b29d9903b4623e37d0361036442facc6abfe5ec526bb1a26eea6, 5078 B. It is byte-identical to the reviewed nv71 proposal.
    • Proposed menu: sha256 a13de7a8df51512bddfe1b916e71015920689220d95693bae8b56b588d3713e0, 5081 B. It is built from the current live copy by changing only lines 29, 31 and 32, all inside /GPU test:
      • the comment becomes "Test root @nv620 with matched NVIDIA 620.70.06. Pick by hand; the normal boot stays default.";
      • the path becomes boot():/EFI/Linux/omarchy_linux-p16-asus-24-nv620.efi#5f356d64…, the b2 of the real file;
      • the cmdline becomes the UKI's embedded .cmdline. Exactly 1 of the 25 tokens differs from the live line: rootflags=subvol=@nv71 becomes @nv620.
    • Unchanged: every other byte, which covers the header, default_entry: 1, /Omarchy (normal) with its battcap pin, protocol: efi, the /GPU test label (BLI id GPU-test) and the generated /+Omarchy group.
    • Cross-check: the result is byte-identical to the earlier 620 menu a13de7a8…. That is a check only. Nothing old is restored.
    • Image, read-only: the ESP omarchy_linux-p16-asus-24-nv620.efi has sha256 0d48c2e2…dc19d and b2 5f356d64…da0f2b, both equal to the out620 copy. Its PE .cmdline equals out620/p16-nv620.cmdline, and .uname is 7.2.8-24-omarchy-p16-asus.

    Apply block. It uses the same atomic pattern as the executed nv71 apply. The diff against that block shows only names and pins.

    • New ESP names: limine.conf.pre-nv620-repoint and limine.conf.nv620-repoint-new. Both must not exist yet. The existing .pre-nv620 and .pre-nv71 are not touched.
    • No limine-update, no hooks, no BootOrder, NVRAM or one-shot change.

    apply-block.sh sha256 0900b05a118f01668f155beb5d3f32a3dd9e6bb84e4016b7e199a941170c80c7, revision 2 (only bash -n was run). It replaces 4c232c7f… after the bugs review. The nv71 and battcap recovery image checks moved before any ESP write, so drift or a missing recovery image stops the apply before the backup, staging or replace. The checks are the same 10, only reordered:

    ( set -euo pipefail; B=/boot; M=/home/sean/.floor-poller/gpu-clock/opus-linux/driver-candidate/boot-menu-nv620-repoint
      sha() { sudo -n sha256sum "$1" | cut -c1-64; }
      need() { [ "$1" = "$2" ] || { echo "FAIL: $3: got [$1] want [$2]" >&2; exit 9; }; }
      LIVE=47713d991922b29d9903b4623e37d0361036442facc6abfe5ec526bb1a26eea6
      NEW=a13de7a8df51512bddfe1b916e71015920689220d95693bae8b56b588d3713e0
      need "$(sha $B/limine.conf)" $LIVE "live menu"
      need "$(sha $M/limine.conf.proposed-nv620)" $NEW "proposed menu"
      need "$(sha $B/EFI/Linux/omarchy_linux-p16-asus-24-nv620.efi)" 0d48c2e2c030930e6addd7bb40e28ab6d62b04f18965e07c3fe85a61a23dc19d "nv620 UKI"
      need "$(sudo -n b2sum $B/EFI/Linux/omarchy_linux-p16-asus-24-nv620.efi | cut -c1-128)" 5f356d641f4fc02268219ab062a3ddfed22e202b529e531f3cda1f09659cbab2a8c97f1b20d1395a76d6d153a668b6467ee231a50481ffb2e162c1eaa7da0f2b "nv620 UKI b2 pin"
      need "$(sha $B/EFI/Linux/omarchy_linux-p16-asus-24-nv71.efi)" 29ca5e0ee80f2c14c3d6352a0ee8753dc68832d7ff58114f30690b4471f5e542 "nv71 UKI unchanged"
      need "$(sha $B/EFI/Linux/omarchy_linux-p16-asus-24-battcap.efi)" a31ef89ef5e4873cab482bada6145757dac2aa54695448fe9b528fbf7b824ce5 "battcap UKI unchanged"
      for f in $B/limine.conf.pre-nv620-repoint $B/limine.conf.nv620-repoint-new; do
        if sudo -n test -e $f || sudo -n test -L $f; then echo "FAIL: $f exists" >&2; exit 9; fi; done
      sudo -n cp -a $B/limine.conf $B/limine.conf.pre-nv620-repoint; sudo -n sync -f $B
      need "$(sha $B/limine.conf.pre-nv620-repoint)" $LIVE "ESP backup"
      sudo -n install -m600 $M/limine.conf.proposed-nv620 $B/limine.conf.nv620-repoint-new; sudo -n sync -f $B
      need "$(sha $B/limine.conf.nv620-repoint-new)" $NEW "staged menu"
      need "$(sha $B/limine.conf)" $LIVE "live menu just before replace"
      sudo -n mv -f $B/limine.conf.nv620-repoint-new $B/limine.conf; sudo -n sync -f $B
      need "$(sha $B/limine.conf)" $NEW "menu after replace"
      echo "APPLY PASS" )

    Recovery is the preserved normal entry. No whole menu is restored. The ESP, the menu and NVRAM were not written. Nothing was rebooted, and no powerd or GPU work ran. The GPU clock goal is not fixed.

  9. seankd3 commented on Nov 6, 2026

    @seankd3
    OwnerAuthor

    Preparation is complete. PR #5 is merged as 4167ee4, with the reviewed tree unchanged. The trace passed real bpftrace 0.27 code generation inside @nv620 with rc=0 and empty stderr. bcc and bpftrace are installed only in that candidate. The live before/after baseline matched. The later boot-menu proposal also passed fresh BUGS and ELEGANCE reviews at apply-block.sh SHA-256 0900b05a118f01668f155beb5d3f32a3dd9e6bb84e4016b7e199a941170c80c7. It has not been applied. The running root remains @nv71 with loaded driver 615.71.09, and the live menu remains 47713d99. No powerd or bpftrace process remains. Runtime tracing requires a later 620 boot and is pending the existing reboot hold. The GPU cap is unresolved.

  10. seankd3 commented on Nov 6, 2026

    @seankd3
    OwnerAuthor

    Restart is authorized. Desktop autologin is configured in both roots and the saved Omarchy desktop restores the T3 AppImage. The 620 candidate has the matched driver and trace tools. GPU-test is verified as the next one-shot boot, with the normal entry remaining the permanent default. A single T3 scheduled continuation is bound to this existing thread, due 2026-11-06T02:12:42Z. Source inspection confirms overdue one-time tasks are processed when T3 starts again. The continuation first checks the new boot and matched 620 stack, then runs the reviewed trace once. The encrypted disk still needs its password before Linux starts. This records preparation and authorization, not a GPU fix.

  11. 26 remaining items

  12. seankd3 commented on Nov 7, 2026

    @seankd3
    OwnerAuthor

    Charger telemetry boundary

    Read-only UCSI GET_CAPABILITY through the running kernel's debugfs interface returned 0x000000000000000001300030012000010000000300004146. Decoding the packed struct ucsi_capability gives attributes 0x4146, three connectors, and optional features 0x0000. Thus firmware does not advertise UCSI_CAP_PDO_DETAILS.

    This explains why the standard Linux source-PDO list is empty: ucsi_get_pdos() returns without issuing GET_PDOS when that feature is absent. The empty list and zero voltage telemetry are not evidence of a low-wattage contract. Sysfs reports an online USB-PD source and current_now=5,000,000 uA, but voltage remains unknown. No negotiated wattage is claimed. No role, PDO, power, or charger setting was changed. Raw command and decode are retained as gpu-cpu-cap-25tex9a0/ucsi-capability.json.

    The physical adapter/cable identity and prior EC-reset history still need owner input. ASUS documents a full controller reset separately from a normal reboot: https://www.asus.com/us/support/faq/1050239/ . This is a reversible next diagnostic, not a proven GPU fix.

  13. seankd3 commented on Nov 7, 2026

    @seankd3
    OwnerAuthor

    CPU-only 2 GHz cap: no sustained unlock

    Completed gpu-cpu-cap-25tex9a0 with unit exit 0 after 4m11.653s. Only CPU policy maxima changed. PPD and ASUS platform profile stayed performance in every phase. All 20 maxima read back at 2,000,000 kHz in B, then returned to their original 2,808,000/4,004,000 kHz values. restore_rc=0. All saved maxima still match after completion.

    • A, original CPU limits, 30.034s: median SM 923 MHz, median event throughput 1891.0 GFLOP/s.
    • B, 2 GHz CPU maxima, 180.841s: late window has 80.753s complete GEMM windows and 160 NVML samples. SM min/median/max 734/747/754 MHz, event median 1530.0 GFLOP/s. Maximum late sample gap 0.5074s, edge lags 0.3805/0.2379s.
    • C, original CPU limits restored, 30.135s: median SM 750.5 MHz, event median 1533.25 GFLOP/s.

    All GEMM/sampler exits were 0. All warmup/end correctness checks had zero mismatches among 66 samples. AC remained online. Every recorded NVML status was 0. Maximum GPU temperature was 41 C. Reason 0x400 stayed present.

    B fails the declared sustained unlock gate. C did not return to A throughput, so do not attribute that initial drop solely to the CPU limit. The tested CPU limit is not a fix. No claim is made about every possible shared firmware budget. The requested limits are verified through CPUFreq, not independent physical clock measurements.

    Cleanup verified: original CPU maxima, performance profile, no profile holds, no test GEMM/sampler/private powerd processes. No installed source, GPU protection, or firmware changed. Raw data and summary.json remain in /home/sean/.floor-poller/gpu-clock/runs/gpu-cpu-cap-25tex9a0.

    Next discriminating physical check remains the original ASUS adapter/cable and full EC reset history. The current firmware reports no optional UCSI PDO-details support, so Linux cannot settle adapter wattage from its empty PDO list.

  14. seankd3 commented on Nov 7, 2026

    @seankd3
    OwnerAuthor

    Focused configuration observation

    The boot is unchanged (4ac8cfa6-310b-44ee-8026-7bcc8180235f), so the requested physical controller reset has not occurred. The prior turn completed bounded negative profile/CPU-limit tests.

    A remaining ambiguity is what the successful NVPCF 3.x startup actually loaded. Static disassembly of the pinned stock 620.70.06 powerd shows five configuration-return call sites at 0x72e4c/0x72eec/0x72f14/0x72f3c/0x72f64. The compiled initialization log at 0x73630..0x73650 obtains its object count from the global map at 0x3275b8+0x28. The configuration object layout has the returned size at +8 and a byte-vector range at +0x10/+0x18/+0x20. The following framework load returns at 0x7367c.

    Extend the existing SHA-pinned GDB observer to record these values once during an unmodified normal daemon startup. Read at most 4096 bytes per configuration object, require valid vector bounds, verify every breakpoint instruction against the pinned ELF, and retain normal-exit/cleanup evidence. No branch, register, setting, or installed file is changed. This can distinguish successful wrapper startup from actual populated configuration. It cannot prove a working power controller or fix the GPU.

  15. seankd3 commented on Nov 7, 2026

    @seankd3
    OwnerAuthor

    NVPCF configuration capture completed

    Stock SHA-pinned 620.70.06 powerd loaded six configuration wrapper objects, returned load status 0, returned true from the 3.x initializer, then took the normal no-worker exit. GDB exited 0, stderr was empty, inferior exited 0, and no powerd process remained.

    The observed configuration objects contain:

    • Slot 0x31, initialization data: size field 128 bytes. The backing vector is 4096 bytes, with its remaining bytes zero. A byte-for-byte check confirms that the first 128 bytes match the retained P16 DSDT initialization buffer. SHA-256 of those 128 bytes: be080f9851faa0257f915be627644d61227c31f9817eb2bdf190a142e2ae94b1.
    • Slots 0x32/0x33, subscribed/dynamic primitives: size fields six bytes, each all zero. Backing vectors are 4096 bytes and entirely zero. These match firmware subfunctions 2 and 3.
    • Slot 0x34, write-primitives object: size field and zero vector 4096 bytes. This is an allocated output buffer, not a returned firmware policy. Constructor 0x1569b0 calls allocation helper 0x1553c0 with 4096 at 0x156a00, then returns the object at 0x156b58. It does not fetch DSM subfunction 4 there.
    • Slot 0x35, critical-status write object: size field and zero vector four bytes. Constructor 0x157090 likewise allocates four bytes at 0x1570e4. This observation does not show a DSM subfunction-5 response.

    Correction: the first version of this comment incorrectly attributed the 4096-byte slot to a kernel integer-zero response. The constructor disassembly disproves that explanation. The raw trace is unchanged.

    The six objects are configuration wrappers, not six power controllers. Successful framework load does not prove populated power-budget primitives or control effectiveness. No new clock measurement or fix claim follows from this trace.

    Artifacts: /home/sean/.floor-poller/gpu-clock/runs/powerd620-config-wkugf4kp. Observer SHA-256 fc3b11aa5892f33cb3e7ff13caa9079862f272cd2a9f67b7a39db9323a59e1bd. Trace SHA-256 d3416a7f15c393726738bfd372f2a7396e370ad1ea3a3d4ff6a4a1918bff1479. Raw bytes and concise decoded events retained separately.

    Owner confirmed the original ASUS charger is directly connected and has performed no manual controller reset. Prepare the same-stack measurement after a full physical EC reset. No further daemon startup is needed.

  16. seankd3 commented on Nov 7, 2026

    @seankd3
    OwnerAuthor

    Abrupt restart during one-shot boot preparation

    The prior sudo bootctl set-oneshot @current command is the final sudo entry in boot 4ac8cfa6-310b-44ee-8026-7bcc8180235f. No shutdown sequence was retained. A new boot 39b67962-caed-4247-ae98-2f8bfd6b676c is now running the same 7.3.0-26 kernel, @nv620 root, stock 620.70.06 module and battcap key. I will not repeat that EFI-variable operation. Temporal association is established. Firmware causality and a physical controller reset are not established.

    This boot has no CPUFreq policy entries, no loaded cppc_cpufreq, and PPD exposes only the ASUS platform driver. CPU acpi_cppc metadata still exists. The first measurement job (gpu-newboot-f22nvzt0) failed in the metadata snapshot because its glob assumed at least one CPU policy. It stopped before any GEMM or NVML sampler launched. Its failed result is retained.

    The metadata collector now records a zero policy count and does not treat absent CPU policies as a literal path. A separate bounded 180s observation in gpu-newboot-z4gxukcc will measure the current boot without changing its CPU/GPU settings. This is not a same-CPU-stack comparison or a confirmed EC-reset test. No one-shot boot request or additional reboot is being issued.

  17. seankd3 commented on Nov 7, 2026

    @seankd3
    OwnerAuthor

    Owner now confirms completing the requested physical reset. This means the restart coincided with an attended reset. Do not attribute it to bootctl from temporal ordering alone. No additional boot-selection write is needed.

    The current 180s measurement is running. Early samples show roughly 2.2 GHz SM, about 61 W NVML GPU power, and roughly 13.5 TFLOP/s event throughput with the unchanged FP32 GEMM. These are early observations, not acceptance or a fix claim. Preserve the current state. If the 180s run passes, measure for at least 15 further minutes because other N1X reports describe delayed fallback after several minutes. The missing CPUFreq policies are a separate changed condition that still needs examination before causal attribution.

  18. seankd3 commented on Nov 7, 2026

    @seankd3
    OwnerAuthor

    First high-clock sustained result after the attended reset

    gpu-newboot-z4gxukcc completed on boot 39b67962-caed-4247-ae98-2f8bfd6b676c, with 7.3.0-26, @nv620, stock 620.70.06 srcversion 5B0BEF94704B2BE1D8BB68B, AC online and ASUS performance profile.

    • GEMM span 180.140s. GEMM and sampler exited 0. Unit deactivated successfully.
    • Warmup/end each checked 66 samples with zero mismatches.
    • 359 NVML samples. Maximum gap 0.5120s, edge lags 0.2086/0.3724s. AC online throughout, all NVML statuses zero.
    • Late window after 100s: 79.501s complete GEMM windows, SM min/median/max 2086/2184/2242 MHz, median event throughput 12,204.2 GFLOP/s.
    • Maximum GPU temperature 73 C. Reason 0x400 remained present despite the higher clocks.

    This proves substantially higher measured GPU performance on this boot. It does not prove indefinite persistence or isolate the reset as the cause: CPUFreq policies and the NVIDIA PPD CPU backend are absent on this boot. Static CPPC metadata remains readable, but feedback counter reads fail. Those differences stay explicit.

    A 900s persistence test is now confirmed live as gpu-reset-sustain-2.service, using the same GEMM and getters. The sampler's only operational change is a 1000s stop ceiling, replacing 340s so it covers the whole test. Whole unit runtime is bounded to 960s. No CPU/GPU setting changes during it. Source/input hashes are verified and raw artifacts go to gpu-reset-sustain-h063eda7.

    An initial launch of the long-test unit exited 1 before hash checking or workload launch. No workload or result directory existed. A separate read-only shell trace then verified all preflight gates, and the traced second unit passed every gate and started the one 900s workload. The first setup failure remains in the journal. Do not count it as a performance test.

  19. seankd3 commented on Nov 7, 2026

    @seankd3
    OwnerAuthor

    Correction to the persistence test duration: the pinned GEMM clamps its seconds argument with min(secs, 300). Thus the 900 request in gpu-reset-sustain-h063eda7 completed successfully after about 300s, not 900s. The raw timestamps show this. Both correctness checks passed, all process exits were 0, and GPU clocks remained high through the five-minute run, but it is not 15-minute evidence.

    Use a private copy with only the argument ceiling and its docstring changed from 300 to 900. Arithmetic, data, CUDA calls, timing windows, and correctness checks remain byte-for-byte unchanged. An isolated AST check verifies that the real argument parser returns 900 for 900 and still caps larger requests at 900, without loading CUDA. The new run retains a diff and input hashes. A separate 900s measurement will establish the actual elapsed workload span. This corrects a measurement setup error, not a GPU fault.

  20. seankd3 commented on Nov 7, 2026

    @seankd3
    OwnerAuthor

    Concrete CPU-enumeration regression: stale GNVS address in the DSDT override

    Read the current firmware DSDT from the original FADT Xdsdt address 0x86f10018, using read-only aligned 32-bit accesses and validating signature, length, and checksum. Ordinary byte-copy reads faulted on this device mapping. The aligned read completed with exit 0.

    Current firmware DSDT: 74052 bytes, SHA-256 b6a1ef004b71c54878ca6f1dfa13c776a8621b561988df61495c12ae78173c7b, OEM revision 4. Its GNVS OperationRegion points at 0x86f70000.

    Loaded override: same length, SHA-256 80e0ad4a051704003d09029cb600a9814e1cd370ce774b9749dc09d2232b5aaf, OEM revision 5. It still points at 0x86f50000.

    The current original firmware DSDT differs from the retained original 0b9ed926... in exactly two bytes: its checksum and the GNVS address byte at AML offset 0x4ee (f5 -> f7). No BIOS version change is needed for this address to move.

    Read-only first-word checks: old address = 0x02261201; current firmware address = 0xffffffff. The loaded DSDT's CPU _STA methods read C0CE/C0BE/C1CE/C1BE from those four bytes. ACPI currently marks only CPU device instances 00/06/09/0b/0c/10 present. Only those six CPU devices have CPPC metadata, although all 20 CPUs are online through MADT. acpi_cpc_valid() requires descriptors for every online CPU, so missing descriptors explain why CPUFreq cannot initialize.

    Artifacts: /home/sean/.floor-poller/gpu-clock/runs/acpi-aligned-read-n6wq55q2, including original table, loaded table, validated address comparison, and the two-byte original-table delta. No firmware or ACPI setting changed during these reads.

    Do not call the reset a complete fix while this regression exists. Check whether the DSDT override is redundant with the existing acpi_osi="!Windows 2022" boot option. If so, remove that override and let the firmware supply its current addresses, preserving the independent ASUS SSDT response-buffer correction. This would fix the class of moved firmware-data addresses rather than pinning another physical address.

  21. seankd3 commented on Nov 7, 2026

    @seankd3
    OwnerAuthor

    Actual 15-minute GPU run passed; corrective boot image prepared

    gpu-reset-900s-4vuxv6m_ completed with 900.640s measured GEMM span. The private benchmark copy changes only its duration ceiling/docstring from 300 to 900. Unit exited 0 after 15m2.351s. Both GEMM and sampler exited 0. Warmup and end each checked 66 values with zero mismatches.

    All 1795 NVML samples reported AC online and all status codes zero. Maximum sample gap 0.7496s, edge lags 0.1496/0.3497s. Full-run SM min/median/max 1891/2047/2405 MHz. Median event throughput 16,540.75 GFLOP/s. Last-five-minute SM min/median/max 1891/2041/2060 MHz, median event throughput 16,603.4 GFLOP/s. Maximum temperature 73 C. Reason bits 0x400 and 0x4 both occurred. These are normal protected driver settings, with no voltage or protection override.

    This passes sustained high GPU performance on the current boot. It does not pass full-system acceptance because the stale DSDT hides CPU ACPI devices.

    The actual firmware ASUS SSDT at physical 0x86f60018 is byte-identical to the retained original (SHA-256 46d9ed16af06093cdb849df69646683317d53d7342dfd38f24eab00795d396f0). Its independent response-buffer correction can stay. The DSDT override changes only SSPM's _OSI("Windows 2022") predicate to false, which the existing boot option already does. The running kernel explicitly logs Deleted _OSI(Windows 2022).

    Prepared a separate UKI by removing only the early kernel/firmware/acpi/DSDT.aml cpio member. Every remaining initrd member, in order, has identical headers and contents. The ASUS SSDT remains SHA-256 9b28ffc14c19f8b7ea2278de88ff9ec070f5f70401107d81fef067a916aa9695. Bytes outside the initrd are identical except validated size/checksum fields. PE section sizes, SizeOfImage, initialized-data size and checksum passed the existing verifier's checks. Kernel, GPU modules, userspace selection and cmdline are unchanged.

    Candidate: /boot/EFI/Linux/omarchy_linux-p16-asus-26-fresh-acpi.efi, SHA-256 e3931e65abbb3e439f4405bc526dcc311febc63fbcbbb7b5e61944f6a7da5b03. Prepared menu entry Omarchy.linux-p16-asus-26-fresh-acpi. Existing entries and default remain. Full static evidence, source script and original menu backup: /home/sean/.floor-poller/gpu-clock/runs/gpu-fresh-acpi-image-by0c7h13.

    Not booted. Owner approval for the interrupting reboot is pending. Next verify native DSDT/GNVS, all CPU ACPI devices, all CPUFreq policies, the NVIDIA PPD CPU backend, and sustained GPU performance together. Do not load CPUFreq on the broken ACPI namespace as an attempted fix.

  22. seankd3 commented on Nov 7, 2026

    @seankd3
    OwnerAuthor

    Prepared the durable source correction as draft PR #19, commit 29c045b894f6ed0f51c1607e3f416c637bda871f. All 49 offline tests pass. The new regression checks reproduce the old behavior against main. The full ACPICA build works with only the machine's original ASUS SSDT, and its output still matches the existing SSDT pin.

    The first prepared test UKI preserved its member bytes but omitted the 512-byte boundary adjustment after deleting the DSDT entry. A later full lsinitcpio check caught this before boot. That test image has been replaced. The corrected image preserves the compressed main payload byte-for-byte and adds 464 bytes of padding. Both the private copy and installed image pass the complete updated UKI/module verifier, with release/package identity set to the installed 7.3.0-26 kernel.

    Current candidate: /boot/EFI/Linux/omarchy_linux-p16-asus-26-fresh-acpi.efi, SHA-256 c539c4c7b3b83680f2b6f460e1bf2bb71353c6052682ac106bd04918f5a6356c. Menu entry remains Omarchy.linux-p16-asus-26-fresh-acpi. Normal default and normal images remain available. New menu SHA-256 2b4cf6cb2088ed79434a714e2b5ae157e68f3941d8a046eebb9f1a3e115a86f7. Artifacts: /home/sean/.floor-poller/gpu-clock/runs/gpu-fresh-acpi-aligned-ik5v17mt.

    Reboot approval is still pending. No one-shot selection or reboot was made. Required next proof remains: a new boot using native firmware DSDT, complete CPU ACPI/CPPC enumeration and CPUFreq controls, followed by sustained high GPU performance. The 900.64-second GPU pass on the current boot does not establish that combined acceptance.

  23. seankd3 commented on Nov 7, 2026

    @seankd3
    OwnerAuthor

    Read-only follow-up to the new RATED_TDP lead on upstream #1521. Audited the complete published preload and matched command 0x2080206e and its 12-byte parameters against the installed 620 source. It adds GET_CONTROL queries only. No SET_CONTROL or protection change was used.

    The pinned source blob is 5dda71550c05e537d13d3f4fb2d66f442c1d52ef, source SHA-256 20f466d44ef18c54018a71d736a8daf7a59657384feb00f025e98faa2839185f. On the current post-reset boot, RM, WAR, GLOBAL, PROFILE and OS all read action 0 / DEFAULT, with ioctl rc 0 and RM status 0, both at idle and during a 30.120-second cuBLAS workload. A sampler row before and after the loaded query showed 2281 MHz and 96% utilization. All workload telemetry statuses were zero, AC stayed 1, and both 66-element correctness checks had zero mismatches. Workload, sampler and outer service exited 0.

    This is the fast-state baseline only. We have no corresponding RATED_TDP read from the earlier affected boot, so it does not rule out this arbitration path as the original limiter. It adds a specific read-only comparison to the corrected-image acceptance if low clocks return.

    Artifacts: /home/sean/.floor-poller/gpu-clock/runs/gpu-ratedtdp-read-lutcvw6z. Boot remains 39b67962-caed-4247-ae98-2f8bfd6b676c; reboot approval is pending. No further load is running.

  24. seankd3 commented on Nov 7, 2026

    @seankd3
    OwnerAuthor

    Corrected image: 900 s run passed; made default; PR #19 merged

    Boot adcbe679-07d3-41f7-b303-a701e160eade, entry Omarchy.linux-p16-asus-26-fresh-acpi, kernel 7.3.0-26, stock NVIDIA 620.70.06, firmware DSDT OEM revision 4, retained ASUS SSDT 9b28ffc1….

    CPU controls are back. All 20 ACPI CPU devices report status 15 with a physical node. All 20 CPPC directories and 20 CPUFreq policies exist, before and after the run. power-profiles-daemon and the platform profile both read performance.

    900 s FP32 cuBLAS run (gpu-fresh-acpi-accept-89t0okec/measurement900): actual span 900.691 s. 1793 NVML samples cover the span, with a largest gap of 0.645 s. All seven NVML status codes are 0 and AC stayed online. Warmup and end checks found 0 mismatches in 66 sampled outputs each. GEMM and sampler exited 0. SM min/median/max is 1430/2034/2424 MHz. Median throughput is 11,025 GFLOP/s. Maximum GPU temperature is 73 C.

    Throughput follows the reason state, not the SM clock. The same binary and inputs on both boots:

    Run Reason Time SM median Power median GFLOP/s median
    Previous boot (copied DSDT) 0x400 0-296 s 2177 MHz 60.1 W 11,953
    Previous boot (copied DSDT) 0x4 296-901 s 2041 MHz 61.6 W 16,632
    This boot (firmware DSDT) 0x400 0-772 s 2047 MHz 49.6 W 10,898
    This boot (firmware DSDT) 0x4 772-901 s 1839 MHz 47.6 W 14,848

    This boot spent 772 s in the 0x400 state, against 296 s on the previous boot. That is why its full-run median is 33% lower than the previous 16,541 GFLOP/s. Both boots stay far above the old 754 MHz / 2.3 W state. These runs do not show what sets either state, and the sampler did not record memory or other clock domains. No run reached the 3003 MHz maximum that the driver reports.

    Persistence (gpu-fresh-acpi-persist-qaO0qSm0/receipt.json):

    • Hook /etc/initcpio/install/p16-acpi: the DSDT add_file_early line is removed. The SSDT line and all eight allowed kernel versions, including 7.3.0-26, stay. SHA-256 is aa2c2189… before and 03d73c74… after. A test initramfs for 7.3.0-26 has the same early archive list as the booted image, with only kernel/firmware/acpi/SSDT.aml at the pinned SHA-256.
    • Menu /boot/limine.conf: default_entry: 1 is now default_entry: Omarchy/linux-p16-asus-26-fresh-acpi. Only comments changed otherwise. SHA-256 is 2b4cf6cb… before and a308e4b3… after. The image (c539c4c7…) and its BLAKE2b pin are unchanged. The edit ran under the boot-partition lock with pinned hashes.
    • bootctl set-default would not work here. Limine reads LoaderEntryDefault only when default_entry is not set.
    • The new default is not yet observed on a boot.
    • Rollback: copy /boot/limine.conf.pre-fresh-acpi-default back to /boot/limine.conf, and reinstall the hook backup at gpu-fresh-acpi-persist-qaO0qSm0/p16-acpi.before. For one boot, pick "Omarchy (normal)" in the menu.

    Source: PR #19 merged at 492d7e5d (head 3809bedf). 48 offline tests pass.

    Prior art: upstream fixed the same defect in f3d7778 (2026-11-06). Its docs/update-safe.md describes the frozen DSDT that declares GNVS at 0x86f50000, and the same six registered CPU devices (0, 6, 9, 11, 12, 16). Its hook loads only the ASUS SSDT and checks for the kernel's arch_alloc_acpi_tables symbol instead of a version list. Because upstream already documents the defect, no new upstream issue was filed.

  25. seankd3 commented on Nov 7, 2026

    @seankd3
    OwnerAuthor

    Closed: the GPU cap is lifted

    On AC with a sustained load, the GPU ran at 754 MHz before the fix. It now holds about 2,000 MHz and peaks near 2,500 MHz. That matches the Surface Laptop Ultra, which has the same N1X chip.

    The fix: RMSkipACPIBattCap=1, and the firmware's own DSDT instead of the stale copy (PR #19, merged). That copy kept an old GNVS address, so ACPI exposed only 6 of 20 CPUs. The corrected image is the default boot: kernel 7.3.0-26 with NVIDIA 620.70.06.

    Evidence: a 900 s FP32 cuBLAS run, comment 6709116632.

    • SM clock: 1430 / 2034 / 2424 MHz (min / median / max).
    • Throughput: 11,025 GFLOP/s median.
    • Maximum GPU temperature: 73 °C.
    • 0 mismatches. All 20 CPUFreq policies were present before and after the run.

    What still holds the clock below the 3003 MHz table maximum:

    • The SW power cap (reason 0x4), at a median of 49 W.
    • Reason 0x400, which the Surface also shows.

    All NVPCF controls read DEFAULT. Sustained 3 GHz is not a goal for this issue.

    Cleanup: I removed the 620.70.06nopsr DKMS source. It has no AUTOINSTALL line, and it made dkms autoinstall build nothing for new kernels. dkms autoinstall -k 7.3.0-26-omarchy-p16-asus now returns 0, with only 620.70.06 installed.

    The _PSR skip test was inconclusive, and it is not needed now. The upstream thread NVIDIA/open-gpu-kernel-modules#1521 has the data.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions