GPEC - NEW FEATURE - Per-stage runtime records in gpec.h5 under Info/Runtimes - #385
GPEC - NEW FEATURE - Per-stage runtime records in gpec.h5 under Info/Runtimes#385logan-nc wants to merge 14 commits into
Conversation
…Runtimes main_from_inputs already timed every pipeline stage but only logged the durations. Persist them under Info/Runtimes/<stage> (Float64 seconds, annotated with long_name/units) so an output file answers "where did the time go" on its own. Only the stages that ran are recorded; timings are informational, never a regression quantity. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…Runtimes Collect Info/Runtimes inside the warm-run loop (each run overwrites gpec.h5), average over the stages present in every run, and print a per-stage delta table alongside the existing totals. Refs predating the record yield an empty dict and the table is skipped silently, so old-vs-new comparisons still work. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ture/h5-runtime-records # Conflicts: # src/GeneralizedPerturbedEquilibrium.jl
…erge) Temporary scaffolding for continuing this branch on another machine: what the branch does, the merge resolution against upstream's inline-path convention, verification already done, the wrong-baseline regression pitfall, and the outstanding work. Carries its own removal instructions. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…sion question Both test files pass on the merged tree, and the regression residuals are resolved: the case is deterministic, and parent-vs-feature run through the same worktree path shows 48 unchanged / 0 changed. Documents the commit-vs-local environment trap that produced the earlier spurious diffs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Verification complete — post-mergeAll checks re-run against the merged tree (
Regression tableZero movement, as expected — this change computes Note for anyone rerunning the harness on this branchTwo baseline traps produced misleading reports along the way; both are documented in the handoff doc:
The case itself is deterministic: two
|
…pinning fix Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ture/h5-runtime-records
…put file The isfile guard alone let a run with write_outputs_to_HDF5=false stamp its timings into a stale gpec.h5 left over from an earlier run. Gate both call sites on the run having produced the file, keeping the SLAYER-created case. Move the stage long_names into HDF5Schema.jl as RUNTIME_H5_ANNOTATIONS, next to the other Info/ metadata; annotate! skips the stages that did not run. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dh1NCejnd3fYMmcRKoQRcG
Temporary scaffolding for a machine switch; its contents are folded into the PR description. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dh1NCejnd3fYMmcRKoQRcG
…ture/h5-runtime-records
…arison The replay guard compares every dataset in a source gpec.h5 against its rerun. Wall-clock seconds cannot repeat, so the new records broke it the same way Info/git_version would; skip the group alongside it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dh1NCejnd3fYMmcRKoQRcG
…le the run wrote Four corrections to the Info/Runtimes records after the schema overhaul landed: - The stage token is `tearing`, not `slayer`. The `slayer/` group became `Tearing/` under the "name the physics, not the algorithm" rule, and every other token already mirrors its group. The solver is named in the long_name instead. - `perturbed_equilibrium` is recorded only when the section is present. It was pushed unconditionally, so a stability-only run stamped the stage at ~0 s for work that never happened. - `_write_runtimes!` now targets the file the run actually wrote. It hardcoded ctrl.HDF5_filename, but PerturbedEquilibrium, KineticForces and SLAYER each write their own filename, so timings were silently dropped whenever a stage other than ForceFreeStates produced the output. Each write site records its path in `written_h5` (last writer wins, matching where SLAYER appends) and both exit paths stamp that file, replacing the write_outputs_to_HDF5/slayer_result proxy with the fact it was approximating. - The benchmark per-stage table prints an em dash instead of Inf/NaN when the branch-1 baseline is zero. The galerkin and total long_names now state that the values nest rather than partition the run, so a reader does not sum them, and workflow.md's Info/ row mentions Runtimes/. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VGmFuAw5JdYrAyBSXCVssR
Brought current with develop + four correctionsBranch updated. #364 merged this morning, so GitHub auto-retargeted this PR from Re-reviewed against the conventions as they finally landed. Four things needed fixing (
Also: the The rest reviewed clean: the annotation table, the Local Important This PR requires a third-party human review approval of its current head before merge. No auto-merge label applied. |
|
All checks green, and the suite ran against this branch in CI for the first time now that the base is
Local, against the final tree: Direct check of the written files on two real runs, confirming the two behavioural fixes: The SLAYER run records Important Green CI is not review. This PR still requires a third-party human approval of its current head ( |
|
@priyanshlunia review & merge this in the next 24 hrs please. Just fix any minor issues yourself directly. Ping me if anything significant changes. |
Re-thread the Info/Runtimes instrumentation through the staged pipeline (run_force_free_states / run_perturbed_equilibrium / run_kinetic_forces / run_slayer_stage): stage windows and the written-file tracking now live at the call sites in main_from_inputs, with an optional runtimes collector kwarg on run_force_free_states (galerkin) and run_slayer_stage (tearing) for the timers those stages own.
|
Context. The PR head ( The resolution taken: keep all bookkeeping decisions in The three mechanisms1. Call-site timing (equilibrium, force_free_states, perturbed_equilibrium, kinetic_forces, total)
2. Collector kwarg (galerkin, tearing)Two timers measure something inside a stage function, so the call-site window can't
Both default to 3. Write-site inference (
|
| Stage | Where the write happens now | Inference in main_from_inputs |
|---|---|---|
| ForceFreeStates | still in the orchestrator | direct assignment inside the existing if ctrl.write_outputs_to_HDF5 block (unchanged) |
| PerturbedEquilibrium | inside public perturbed_equilibrium, gated on pe_ctrl.write_outputs_to_HDF5 (default true) with filename fallback output_filename == "" → ctrl.HDF5_filename |
section present && get(inputs["PerturbedEquilibrium"], "write_outputs_to_HDF5", true) → written_h5 = pe_file; the pe_file derivation (which already mirrored the filename fallback for SLAYER) was hoisted above the PE call |
| KineticForces | inside run_kinetic_forces, gated on section && pe_state !== nothing && kf_ctrl.write_outputs_to_HDF5 |
same three conditions, all visible in the orchestrator (kf_ctrl is in scope) |
| SLAYER | inside run_slayer_stage's guarded try |
slayer_result !== nothing ⟹ the Tearing/ append succeeded → written_h5 = pe_file (or ctrl.HDF5_filename on the force_termination path) |
"Last writer wins" ordering and the two stamp points (the force_termination early return
and the final banner) are unchanged from the PR head, as are _write_runtimes!,
RUNTIME_H5_ANNOTATIONS, the tests, the benchmark-script changes, and the docs rows.
What changed relative to the PR head, in one list
- Removed the
_run_slayer_stageclosure instrumentation (the closure itself is gone
on develop) → replaced by theruntimeskwarg on the top-levelrun_slayer_stage. - Moved the galerkin timer into
run_force_free_statesvia the same kwarg pattern. - Moved PE/KF timing from inside the (former) inline blocks to call-site windows —
numerically equivalent (same window + function-call overhead). - Replaced direct
written_h5assignments at the PE and KF write sites with the
gate-mirroring inference above; SLAYER's assignment became result-based inference. - Reverted a bad auto-merge: git had spliced the PR's
push!(runtimes, "perturbed_equilibrium" => ...)intorun_perturbed_equilibrium, whereruntimes
doesn't exist — it parsed fine and would have thrownUndefVarErroron every PE run.
Trade-off and review focus
This implementation keeps the diff minimal and every stage function's signature/return contract
intact (only two additive kwargs), at the cost of duplicating three write-gate
conditions in the orchestrator. If a default flips (e.g.
PerturbedEquilibriumControl.write_outputs_to_HDF5) or a write gate gains a condition, the
mirror in main_from_inputs must follow — each mirror carries a one-line comment naming
what it mirrors. These three conditions are the right review focus; the alternative
(stage functions return the filename they wrote) is drift-proof but touches
internal signatures — easy to switch to later if the mirrors prove fragile.
Verification: 99 tracked harness quantities across 5 runnable cases, zero moved;
19/19 fullruns tests plus schema and replay tests pass; Info/Runtimes confirmed in real
outputs including the tearing record.
|
@logan-nc pinging you since this was a relatively significant edit. |
What and why
main_from_inputstimed every pipeline stage but only logged the durations, so an output file could not answer "where did the time go". This persists them underInfo/Runtimes/<stage>(Float64 seconds,long_name+units="s"per the self-describing-HDF5 contract from #364), and teachesbenchmarks/benchmark_git_branches.jlto report per-stage deltas averaged over its warm runs.Stages, each recorded only when it actually runs:
equilibrium,galerkin,force_free_states,tearing,perturbed_equilibrium,kinetic_forces, plustotal.The values nest rather than partition:
galerkinis measured inside theforce_free_stateswindow andtotalspans the whole run, so the seven numbers do not sum. Bothlong_names say so, since that is the one thing a reader of the file cannot infer.Timings are informational only — machine- and load-dependent. They are not regression quantities and should never be added to the harness.
Notes for review
total_dt, so the log line and the recorded value cannot disagree._write_runtimes!guards onisfile(no-op whenwrite_outputs_to_HDF5=falseand nothing else wrote a file) and deletes an existingInfo/Runtimesbefore writing, so reruns into an existing file stay idempotent. It targets the file this run actually produced:ctrl.HDF5_filenamenormally, or the SLAYER stage'spe_filewhenwrite_outputs_to_HDF5=false.Utilities.HDF5Annotations.annotate!; no new annotation path.test/runtests_h5_schema.jlenforces the metadata automatically — its walker fails if anyInfo/Runtimes/*dataset lackslong_name/units.Info/Runtimesread is inside the warm-run loop, since each run overwritesgpec.h5. Refs predating the feature yield an empty dict and the table is skipped silently, so old-vs-new comparisons keep working.tearing, notslayer: ALL - IMPROVEMENT - Self-describing HDF5 metadata (issue #226, PR B) #364 renamed theslayer/group toTearing/under the "name the physics, not the algorithm" rule, and the other tokens already mirror their groups. The solver is named in thelong_nameinstead.Verification
runtests_h5_schema.jlruntests_fullruns.jlruntests_rerun_from_h5.jlInfo/Runtimesexempted from the bit-for-bit replay comparison)diiid_n1total-last ordering, silent skip on empty/disjoint sides, zero-baseline Δ% guard🤖 Generated with Claude Code