Skip to content

measure: cold-cache attribution of varve verify (REQ-VERIFYPAR-001 clause 1) - #341

Merged
avrabe merged 3 commits into
mainfrom
measure/verifypar-cold
Nov 8, 2026
Merged

avrabe merged 3 commits into
mainfrom
measure/verifypar-cold

Conversation

@avrabe

@avrabe avrabe commented Nov 8, 2026

Copy link
Copy Markdown
Contributor

This PR discharges clause 1 of REQ-VERIFYPAR-001, which is in v0.47.0's lean scope. Clause 1 says to measure verify's per-stage cost on a runner with a cold page cache before writing any concurrency.

It adds the instrument and records its first result. It changes no varve behaviour.

What lands

  • tools/measure/verify-cold.sh builds a local layer offline with a throwaway key, using tools/systest/lib.sh's systest_sign_spec_and_pin, the same path the system tests take. The layer has one 2048 MiB random payload and five 64 KiB ones. The script then runs varve verify --timing in three cases:

    • five times warm, after one priming run;
    • five times cold, with sync; drop_caches 3 before each run;
    • five times warm on a small layer of five 64 KiB payloads, for clause 4's baseline.

    It prints the environment and a per-run and median block for each case. Off Linux, or without passwordless sudo, it says the cold case was skipped and implies no figure.

  • .github/workflows/measure-verify.yml runs the script.

    • It triggers on pushes to measure/** and on workflow_dispatch only, so it is never a PR gate and is not a required check.
    • It runs on GitHub-hosted ubuntu-latest, with contents: read, and its actions are pinned to the same commits as ci.yml. action_coverage, pr_gates_cannot_be_switched_off and runner_trust_boundary accept it unchanged.
  • VER-VERIFYPAR-001, method analysis, records the result. It discharges clause 1 only; the requirement stays proposed.

The result

Run 42402881731 used an AMD EPYC 7763 runner with 4 vCPUs, sha_ni and ext4. Medians of 5 runs:

Case Read Hash Wall
2 GiB payload, warm 0.180 s 1.357 s 1.573 s
2 GiB payload, cold 3.655 s 1.376 s 5.093 s
Small layer, warm 0.000 s 0.000 s 0.016 s

On this runner, reading dominates when the cache is cold: 72% of the wall time. That is the requirement's own condition for withdrawal. Two limits keep it from being a verdict:

  • The disk. This runner reads cold at about 560 MiB/s. A local NVMe disk reads cold at several GB/s, and there hashing, at about 1.5 GB/s, would dominate again. The figure holds for this runner only.
  • The payload layout. The measured layer has one large payload. Digesting payloads concurrently, as clause 2 proposes, gains almost nothing for it on any disk. Overlapping the read with the hash would gain something.

What happens to the requirement is a decision for the maintainer (factory-notice 20261107T193300-80b3fc). This PR records the evidence for that decision; it does not make it.

Because this branch matches measure/**, pushing it re-ran the workflow, which re-checks the instrument on the rebased tree.

Local gates, rebased on 72c8868 (#340)

  • cargo fmt --check: OK.
  • clippy with -D warnings: clean.
  • Workspace tests: 1999 passed, 0 failed. These include the workflow-scanning tests.
  • tools unittest: OK.
  • rivet validate: exits 0.
  • rivet check verification-evidence, trace-gate, claim-check, tracepack-check and review-check all exit 0.
  • tools/systest/install-shadow.sh: exits 0.
  • shellcheck 0.11.0, -S warning: clean.
  • tools/check-py-floor.py: exits 0.

🤖 Generated with Claude Code

https://claude.ai/code/session_019TNtfRjLNhEz82G2ggeeNu

avrabe and others added 3 commits November 8, 2026 03:21
One-off script and GitHub-hosted workflow that build a 6-payload layer
(one 2 GiB random payload) offline through the systest deposit path,
then take `varve verify --timing` warm and cold (drop_caches) plus the
small-layer baseline, and print a machine-readable summary.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019TNtfRjLNhEz82G2ggeeNu
VER-VERIFYPAR-001 records run 42402881731 of measure-verify.yml on a
GitHub-hosted runner. With a 2 GiB payload, the cold medians are
read 3.655 s, hash 1.376 s and wall 5.093 s; warm, read 0.180 s and
hash 1.357 s. On this runner reading dominates cold: 72% of the wall.

That is clause 1's own withdrawal condition. But the verdict depends on
the disk: the runner reads cold at about 560 MiB/s, and a local NVMe
disk at several GB/s would leave hashing dominant. The measured shape
also has a single large payload, so concurrent per-payload digests
would gain almost nothing on it. Whether to withdraw, reword or keep
the requirement is the maintainer's call; it stays proposed. This
artifact discharges clause 1 only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019TNtfRjLNhEz82G2ggeeNu
@avrabe

avrabe commented Nov 8, 2026

Copy link
Copy Markdown
Contributor Author

Reproduction: pushing the rebased branch re-ran the workflow (42438484840) on the same runner class (AMD EPYC 7763, 4 vCPU). Medians of 5:

  • 2 GiB payload, cold: read 3.673 s, hash 1.375 s, wall 5.109 s. The first run gave 3.655, 1.376 and 5.093.
  • 2 GiB payload, warm: read 0.179 s, hash 1.356 s, wall 1.571 s.
  • Small layer, warm: wall 0.016 s.

The two runs agree within 0.5%, so the instrument is stable on this runner. The limit on what this shows still holds: it is this runner's disk.

🤖 Generated with Claude Code

@avrabe
avrabe merged commit 6175ab9 into main Nov 8, 2026
48 checks passed
@avrabe
avrabe deleted the measure/verifypar-cold branch November 8, 2026 04:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant