battery: cross-platform timing report for rc175 3be5dcaac - the timing benchmark on six platforms
Build Packages / Create release (push) Successful in 7s
Build Packages / build:portable:macos-arm64:nocuda (push) Successful in 4m46s
Build Packages / build:rugnux:linux-aarch64:cuda (push) Successful in 10m42s
Build Packages / build:portable:linux-x86_64:nocuda (push) Successful in 16m50s
Build Packages / build:portable:linux-x86_64:cuda (push) Successful in 20m38s
Build Packages / build:portable:windows-x86_64:nocuda (push) Successful in 21m14s
Build Packages / build:jfjoch:ubuntu2204:nocuda (push) Successful in 21m9s
Build Packages / build:jfjoch:rocky8:nocuda (push) Successful in 24m53s
Build Packages / build:portable:windows-x86_64:cuda (push) Successful in 25m45s
Build Packages / build:jfjoch:rocky9:nocuda (push) Successful in 25m45s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 30m53s
Build Packages / build:jfjoch:ubuntu2404:nocuda (push) Successful in 20m24s
Build Packages / Generate python client (push) Successful in 29s
Build Packages / Build documentation (push) Successful in 1m7s
Build Packages / build:jfjoch:rocky8:cuda-sls9 (push) Successful in 22m28s
Build Packages / build:jfjoch:rocky9:cuda-sls9 (push) Successful in 24m39s
Build Packages / build:jfjoch:ubuntu2204:cuda (push) Successful in 19m38s
Build Packages / build:jfjoch:rocky8:cuda (push) Successful in 24m14s
Build Packages / build:jfjoch:rocky9:cuda (push) Successful in 24m36s
Build Packages / build:jfjoch:ubuntu2404:cuda (push) Successful in 20m4s
Build Packages / Unit tests (push) Successful in 1h29m33s
Build Packages / Validation Battery (push) Successful in 34m9s

tools/battery/results/timing_platforms/: the timing benchmark (myob and cytochrome C from AlphaFold DB
models, 4nwv from a moved deposited model, all placed by molecular replacement) on the workstation
(RTX 5080, and CPU only), the 4x T4 server, GB10, an 8 GB Windows laptop and a Mac mini M6: Table 1 wall
time for the three sets, Tables 2-4 time per pipeline stage (the workflow figure's boxes) with the sum of
steps against the wall time, and per platform the commit, build, command, hardware and conditions as
recorded. All checks pass everywhere with the same MR decisions. Generated by timing_table.py from
platforms.json (the packs it reads are kept outside the repository).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4
This commit is contained in:
leonarski_fandClaude Opus 5.5 committed 2026-10-16 12:04:44 +02:00
1 parent 622b691f69
commit 57a3e02f59
3 files changed
+848

No files matched your search

@@ -0,0 +1,289 @@
{
"title": "rugnux timing benchmark across platforms: rc175 3be5dcaac",
"intro": "`battery.py timing` (tools/battery/README.md, 'The timing benchmark'; timing.py, timing.json). myob_x10sa and cytc_x10sa start from AlphaFold DB models, 4nwv from its deposited model moved by a fixed transform; each must be placed by molecular replacement. Code: rc175 3be5dcaac, pushed 2026-10-16; its rugnux code is identical to e25876055 (the later commits change docs only). Each platform's numbers come from its own pack (named under Reproducibility); 'not recorded' means the pack does not have it. This file is generated by timing_table.py from platforms.json, kept beside it with a copy of timing.json: add a platform to platforms.json and re-run `python3 -I timing_table.py platforms.json -o <this file>`.",
"timing_json": "../../timing.json",
"stands_out": [
"Every check passed on every platform and run (server and GB10 included) (6 of 6 checks on each of the 3 sets). The MR decisions are the same everywhere: myob and 4nwv AGREES. For cytc the data give P 31 2 1 and MR places the model in P 32 2 1 (ENANTIOMORPH); the Mac report gives the same hand but no MR_DECISION key.",
"The steps cover rugnux's whole clock on every platform: on 4nwv the sum of the TIMING steps equals WALL_TIME to 0.1 s. Outside that clock, process launch to exit (elapsed_s) adds 0.5-1.0 s. There is no hidden time between steps.",
"On Windows, the first set of a run (myob_x10sa) has 4.0-4.3 s between process launch and exit that rugnux's own clock does not cover; the later sets and every other platform have 0.1-1.0 s. What that time is (process or CUDA start-up before step 1, say) is not recorded.",
"Workstation (RTX 5080): 4nwv takes 84 s. Scaling and merging is the biggest step (25 s), then MR (20 s), then integration (10.5 s). The run of 10-15 23:26, said to be on a loaded machine, is within 1% of the clean run. So load did not inflate that particular run, whatever it did to others.",
"Workstation (RTX 5080): 4nwv takes 84 s. Scale & merge (P1 merge, symmetry, final merge, analyses) is the largest stage at 28 s. Structure & map follows at 27 s (MR 20 s of it), then post-refine at 8 s and the two per-image passes at 10.5 s together. The run of 10-15 23:26, said to be on a loaded machine, is within 1% of the clean run, and used the identical binary. So load did not inflate that particular run, whatever it did to others.",
"Workstation CPU only: 4nwv takes 515 s, 6.2x the GPU run. Structure & map takes 331 s of it (MR 243 s, about 12x the GPU), and the per-image passes 83 s (8x). Scale & merge is only 2x slower (56 s). The two small sets are 7x slower.",
"Mac M6 (CPU + Metal integration): 4nwv takes 431 s, 0.84x the workstation's CPU-only time. Its MR runs on the CPU and takes as long as the workstation's CPU-only MR (240 vs 243 s); it is 56% of the Mac's wall time. Metal brings the per-image passes to 55 s (CPU-only workstation: 83 s). Model validation (56 s) and scale & merge (49 s) also beat the 16-core CPU-only run. Caveat: the Mac binary has no -march flags, the workstation's has x86-64-v3.",
"Windows laptop (RTX PRO 2000, 8 GB): 4nwv takes 167-206 s, 2.0-2.5x the workstation GPU run. Every stage is slower: per-image passes 27 s (2.6x), scale & merge 40-58 s, structure & map 71-87 s (MR 52-62 s, 2.7-3.1x). Back-to-back runs differ by 23%, spread over the GPU/CPU-heavy stages. The laptop also spends 2.6-5.6 s writing files and 3.3-4.4 s in the geometry-walk probe (0.5 and 0.1 s on the workstation).",
"GB10 (DGX Spark, unified memory): 4nwv takes 123 s, 1.47x the RTX 5080 workstation and faster than the laptop (167-206 s). By stage against the workstation: scale & merge is nearly level (29.0 vs 27.9 s), the per-image passes are 1.4x (15.1 vs 10.5 s), and structure & map is 2.3x (61.0 vs 27.1 s; MR alone 2.4x, 46.6 vs 19.7 s). MR is its largest step, 38% of the wall time; per the pack's profile the GPU rotation function alone takes 25.7 s. The small sets lose more: myob 17.1 s and cytc 25.7 s, 1.9x the workstation. Everything ran on the GPU. With a 104.5 GB budget, model validation planned 22.1 GB with 10 rigid-body engines and MR 21.6 GB with 9; the 8 and 16 GB cards ran 1-2.",
"Server (4x Xeon Gold 6146, 4x T4; rugnux uses the 24 CPUs of the GPUs' sockets and all four cards): 4nwv takes 248 s. That is 3.0x the RTX 5080 workstation and slower than the 8 GB laptop (167-206 s). The gap is almost all structure & map: 150 s, of which MR is 123 s (6.3x the workstation's 19.7 s, 2.0-2.4x the laptop's) and model validation 26 s (3.5x). Scale & merge (57 s) and post-refine (16 s) are about 2x the workstation. The two per-image passes, spread over four cards, are level with it (11.0 vs 10.5 s). The small sets match GB10: myob 16.9 s and cytc 25.8 s (GB10: 17.1 and 25.7 s), 1.8-2.0x the workstation, with pre-scan and indexing the largest stages. The run started 5 s after a full battery on the same machine ended; the load during it was not recorded.",
"Peak host memory for 4nwv: workstation GPU 18.4 GiB RSS, workstation CPU-only 26.8 GiB, Mac 9.1 GiB RSS (~22 GiB physical footprint). The Windows, GB10 and server packs recorded none. The two numbers are not directly comparable: Mac RSS vs footprint, unified memory."
],
"platforms": [
{
"platform": "Workstation: AMD Ryzen 9 5950X (16C/32T)",
"gpu": "RTX 5080 16 GB",
"role": "reference (clean)",
"run": "/data/battery/runs/20261016-0941_e25876_ws-3be5dc-timing",
"os": "Rocky Linux 8.10, kernel 4.18.0-553.22.1.el8_10.x86_64, NVIDIA driver 580.82.07 (read 2026-10-16, after the runs)",
"build": "GCC 13.3.1 (gcc-toolset-13), nvcc 13.0.88, CUDA code for sm_75/80/86/89/90/100/120/121 (the default list; JFJOCH_CUDA_ARCHITECTURES empty), CMAKE_CXX_FLAGS/CMAKE_C_FLAGS = -march=x86-64-v3, no LTO; build dir /data/tmp/rc175-metal-merge/build (CMakeCache and CMakeFiles read 2026-10-16)",
"battery_cmd": "`cd /home/jungfrau/nextgendcu && nice -n 0 python3 tools/battery/battery.py --site /data/battery/site.json timing --rugnux /data/tmp/rc175-metal-merge/build/rugnux/rugnux --gpulock --label ws-3be5dc-timing`",
"conditions": "started 09:41:50 right after a full battery ended (09:41); no other rugnux/battery/build process, GPU lock free, 0.3 GiB in use on the card before; load average 1.43 before, 6.70 after, highest 1-min load sampled during the run 9.75 (rugnux's own threads); page cache warm (the full battery had just read the same datasets); not the first run after the build",
"peak_mem": {
"myob_x10sa": "3.5 GiB RSS",
"cytc_x10sa": "5.1 GiB RSS",
"4nwv": "18.4 GiB RSS"
},
"notes": [
"Peak RSS = VmHWM from /proc/<pid>/status, sampled every 0.5 s. Whole-card GPU memory in use peaked at 8.1 GiB (nvidia-smi every 0.5 s; 0.3 GiB idle baseline).",
"The binary reports git e25876; the rugnux code of e25876055 and 3be5dcaac is identical (the later commits change docs only). The battery runner was the shared checkout at 2be738f55 (3be5dcaac plus the Windows battery fixes).",
"The manifest's 'source HEAD' is the build directory's source tree at run time (it had moved on to 2be738f55); the commit the binary was built from is the one it reports (e25876)."
]
},
{
"platform": "Workstation: AMD Ryzen 9 5950X (16C/32T)",
"gpu": "none (--no-gpu)",
"role": "reference (clean)",
"run": "/data/battery/runs/20261016-0943_e25876_ws-3be5dc-timing-nogpu",
"os": "Rocky Linux 8.10, kernel 4.18.0-553.22.1.el8_10.x86_64, NVIDIA driver 580.82.07 (read 2026-10-16, after the runs)",
"build": "GCC 13.3.1 (gcc-toolset-13), nvcc 13.0.88, CUDA code for sm_75/80/86/89/90/100/120/121 (the default list; JFJOCH_CUDA_ARCHITECTURES empty), CMAKE_CXX_FLAGS/CMAKE_C_FLAGS = -march=x86-64-v3, no LTO; build dir /data/tmp/rc175-metal-merge/build (CMakeCache and CMakeFiles read 2026-10-16) (same binary as the GPU run)",
"battery_cmd": "`cd /home/jungfrau/nextgendcu && nice -n 0 python3 tools/battery/battery.py --site /data/battery/site.json timing --rugnux /data/tmp/rc175-metal-merge/build/rugnux/rugnux --gpulock --extra=--no-gpu --label ws-3be5dc-timing-nogpu`",
"conditions": "started 09:43:50 right after the GPU run, nothing else running; load average 5.67 before, 12.22 after, highest 1-min load sampled 34.1 during 4nwv (rugnux's own 32 threads); page cache warm",
"peak_mem": {
"myob_x10sa": "9.9 GiB RSS",
"cytc_x10sa": "10.0 GiB RSS",
"4nwv": "26.8 GiB RSS"
},
"notes": [
"Peak RSS = VmHWM from /proc, sampled every 0.5 s.",
"Runner and binary as in the GPU run.",
"The manifest's 'source HEAD' is the build directory's source tree at run time (it had moved on to 2be738f55); the commit the binary was built from is the one it reports (e25876)."
]
},
{
"platform": "Server: 4x Intel Xeon Gold 6146 (48C/48T recorded; rugnux used 24)",
"gpu": "4x Tesla T4 (15360 MiB each, as recorded)",
"role": "reference",
"archive": "/data/perf/bundle_rc175_3be5dc.tar.gz",
"member": "bundle_rc175_3be5dc/b_mr_timing",
"os": "not recorded",
"build": "Release, -march=x86-64-v3, CUDA on (manifest; build dir build_v3); compiler, CUDA version, CUDA arch and LTO not recorded",
"battery_cmd": "not recorded (the pack's console.log shows `battery.py timing` output; the manifest: label 'timing', no gpulock, no extra arguments)",
"conditions": "started 05:31:22, 5 s after a full battery run on the same machine ended (03:27:52 to 05:31:17, the pack's a_battery), so the page cache was presumably warm (not recorded as such); GPU not shared during that battery (its report); load average at 05:37:04, 40 s after the timing run ended: 0.52 / 3.85 / 6.32 (1 / 5 / 15 min), all four GPUs idle then (c_profile machine_before); load during the run not recorded; rugnux limits itself to 24 threads, the CPUs of the GPUs' sockets (24-47), and uses all 4 GPUs",
"notes": [
"Peak memory not recorded. 4nwv model validation planned 5.18 GB of a 12.52 GB budget (80% of the card's 15.65 GB) and MR 4.79 GB, on the GPU.",
"The pack also holds the full battery (a_battery) and nsys/perf profiles (c_profile); they are not used here."
],
"run_name": "20261016-0531_3be5dc_timing (on the server; b_mr_timing in the pack, name from its console.log)"
},
{
"platform": "DGX Spark: NVIDIA GB10 (ARM, 20 CPUs recorded)",
"gpu": "GB10 (unified memory, 121.7 GiB recorded)",
"role": "reference",
"archive": "/data/perf/rugnux_gb10_perf_rc175-3be5dc_20261016.tar.gz",
"member": "rugnux_gb10_perf_rc175-3be5dc_20261016/battery/20261016-0944_3be5dc_gb10-rc175-3be5dc-mr",
"os": "not recorded (DGX Spark per the pack's ANALYSIS.md)",
"build": "Release, -DJFJOCH_RUGNUX_ONLY=ON -DJFJOCH_CUDA_ARCHITECTURES=121, no -march (ANALYSIS.md); LTO, compiler and CUDA versions not recorded",
"battery_cmd": "not recorded (ANALYSIS.md: rc175's tools/battery `battery.py timing`, the pack's data, an absolute-path site config)",
"conditions": "GPU not shared: the resident GPU service was stopped for the whole session (ANALYSIS.md; the report says 'GPU was not shared during the run'); no gpulock; started 4 min after a six-set battery run on the same data (page cache state not recorded); load not recorded; the pack's pdb_cache JSONs were repointed by hand before this run",
"notes": [
"Peak memory not recorded. With unified memory the GPU budget is 104.53 GB: 4nwv model validation planned 22.12 GB (10 rigid-body engines), MR 21.60 GB (9 rigid-body engines).",
"The same binary with the deposited 4nwv model (six-set run 20261016-0940_3be5dc_gb10-rc175-3be5dc in the same pack): 76.7 s."
]
},
{
"platform": "Laptop: Intel Core Ultra 7 255H (16C/16T)",
"gpu": "RTX PRO 2000 Blackwell Laptop 8 GB",
"role": "reference",
"archive": "/data/perf/rugnux_win11_perf_3be5dc_20261016.tar.gz",
"member": "rugnux_win11_perf_3be5dc_20261016/runs/1_timing",
"os": "Windows 11 (pack name; build number not recorded); GPU in WDDM mode (BRIEF.md)",
"build": "MSVC 19.51 + CUDA 13.3, CI Windows settings /arch:AVX (BRIEF.md); CUDA arch and LTO not recorded; build dir build-win-ci",
"battery_cmd": "not recorded (BRIEF.md: `battery.py timing` with the runner patched by battery-windows.patch, run from the pack's unmodified site.json)",
"conditions": "nothing else on the GPU, no gpulock (site gpulock null); the session's second timing run (the first is the next row); load and page cache not recorded",
"notes": [
"Why this run is the reference: it is the run the pack's BRIEF.md reports as its result (`1_timing`, the patched runner from the pack's own site.json). The earlier run (next row) used the same binary (same sha256) and the unpatched runner. BRIEF.md puts the 167 vs 206 s 4nwv spread down to laptop thermals/power; that is its reading, not a measurement."
],
"run_name": "20261016-0753_3be5dc_3be5dc-timing-patched (on the laptop; runs/1_timing in the pack, name from its SOURCE_RUN.txt)"
},
{
"platform": "Laptop: Intel Core Ultra 7 255H (16C/16T)",
"gpu": "RTX PRO 2000 Blackwell Laptop 8 GB",
"role": "repeat (earlier run)",
"archive": "/data/perf/rugnux_win11_perf_3be5dc_20261016.tar.gz",
"member": "rugnux_win11_perf_3be5dc_20261016/runs/repeat_timing",
"os": "Windows 11 (pack name; build number not recorded)",
"build": "same binary as the reference row (sha256 ce0248ef...)",
"battery_cmd": "not recorded (BRIEF.md: the repo's unpatched runner with an absolute-path site config)",
"conditions": "the session's first timing run; nothing else on the GPU; load and page cache not recorded; hardware not recorded in this run's manifest (same host PC17975)",
"run_name": "20261016-0741_3be5dc_3be5dc-timing (on the laptop; runs/repeat_timing in the pack, name from its SOURCE_RUN.txt)"
},
{
"platform": "Mac mini: Apple M6, 12 cores",
"gpu": "Apple M6 GPU (Metal, integration only)",
"role": "reference",
"conditions": "nothing else running; data read cold (the report)",
"devices": [
"CPU",
"CPU",
"CPU (no CUDA build)"
],
"peak_mem": {
"myob_x10sa": "6.7 GiB RSS (~6.9 GiB footprint)",
"cytc_x10sa": "5.9 GiB RSS (~10 GiB footprint)",
"4nwv": "9.1 GiB RSS (~22 GiB footprint)"
},
"notes": [
"Peak memory sampled once a second by the Mac agent (ps RSS; top's physical footprint, rounded to whole GiB above 10 GiB).",
"The pack's 4nwv pdb_cache JSON had to be corrected by hand before 4nwv would run."
],
"manual": {
"sets": {
"myob_x10sa": {
"verdict": "pass",
"wall": 40.4,
"steps": {
"Molecular replacement": 1.6
}
},
"cytc_x10sa": {
"verdict": "pass",
"wall": 56.8,
"steps": {
"Molecular replacement": 4.3
}
},
"4nwv": {
"verdict": "pass",
"wall": 430.6,
"steps": {
"Pre-scan": 3.9,
"Indexing": 10.1,
"Integration (geometry pre-pass)": 24.9,
"Scaling and post-refinement": 9.4,
"Metric-symmetry check": 5.3,
"Integration (refined geometry)": 30.1,
"Scaling and merging": 45.6,
"Analyses": 3.2,
"Model validation": 56.4,
"Molecular replacement": 239.9,
"Writing files": 1.7
}
}
},
"repro": {
"run directory": "runs/20261016-0727_3be5dc_timing-3be5dc (on the Mac)",
"date/time": "2026-10-16 07:27 start (from the run directory name); end not recorded",
"host": null,
"OS": "macOS (version not recorded)",
"rugnux (as the binary reports)": "not recorded (the report: origin/rc175 tip 3be5dcaac, metal-integration merged)",
"build flags (as the binary reports)": null,
"build (battery manifest)": "not recorded (the report: Release, no -march/LTO flags, JFJOCH_USE_CUDA=OFF, built in the jungfraujoch-origin-rc175 worktree)",
"compiler / CUDA / arch": "not recorded (no CUDA; Metal integration engine)",
"battery command": "not recorded (the report: `battery.py timing` with an absolute-path copy of the site config)",
"battery runner": "the repo's tools/battery at 3be5dcaac (the report), not patched",
"threads (rugnux reports)": null,
"hardware (manifest)": "Mac mini M6, 12 cores (performance/efficiency split not recorded), 16 GB (the report)",
"GPU (rugnux reports)": null,
"rugnux command, myob_x10sa": null,
"rugnux command, cytc_x10sa": null,
"rugnux command, 4nwv": null
}
},
"table_notes": {
"4nwv": "the Mac pack is one markdown report (rugnux_mac_timing_3be5dc_20261016.md), no run directory or logs. Its 4nwv step table lists 11 steps; Reading input, Indexing at the refined geometry and Geometry check are not in it (n/r), so its sum covers only the listed steps; elapsed_s is not in it.",
"cytc_x10sa": "the Mac report gives only the wall time and the MR step (4.3 s) for this set; no other step is in it (n/r).",
"myob_x10sa": "the Mac report gives only the wall time and the MR step (1.6 s) for this set; no other step is in it (n/r)."
}
},
{
"platform": "Workstation: AMD Ryzen 9 5950X (16C/32T)",
"gpu": "RTX 5080 16 GB",
"role": "earlier run (10-15 23:26)",
"run": "/data/battery/runs/20261015-2326_e25876_rc175-r10-timing",
"os": "Rocky Linux 8.10, kernel 4.18.0-553.22.1.el8_10.x86_64, NVIDIA driver 580.82.07 (read 2026-10-16, after the runs)",
"build": "same binary as the clean workstation runs (sha256 identical)",
"battery_cmd": "not recorded (options in the manifest below)",
"conditions": "described by the owner as taken while the machine was heavily loaded by other agents (load 15-35); load during this run not recorded; its times are within 1% of the clean run",
"notes": [
"Same binary as the clean runs: identical sha256 (4ace4e1f...); at this run the source tree was still at e25876055."
]
}
],
"step_groups": [
{
"box": "Input",
"steps": [
"Reading input"
],
"why": "opening the dataset and reading its header"
},
{
"box": "Pre-scan",
"steps": [
"Pre-scan"
],
"why": "frame projection, spot widths, beam-stop shadow, defective pixels"
},
{
"box": "Index",
"steps": [
"Indexing",
"Metric-symmetry check",
"Indexing at the refined geometry"
],
"why": "pass 1 first-pass indexing; the metric-symmetry check (only where the free refinement departs from the promoted Bravais class: the alternative class is re-indexed and re-run as a probe on a copy, RugnuxPasses.cpp); pass 2's re-indexing at the post-refined geometry. Pass 1 and pass 2 are kept together because pass 2's indexing is 0.1-0.2 s"
},
{
"box": "Per image, pass 1",
"steps": [
"Integration (geometry pre-pass)"
],
"why": "the per-image chain (decode, azimuthal profile, spot finding, refine, predict, integrate) at the header geometry"
},
{
"box": "Post-refine",
"steps": [
"Scaling and post-refinement",
"Geometry check"
],
"why": "pass 1's P1 scale-and-merge plus the post-refinement of distance, beam, cell and axis (one Step in RugnuxScaleMerge.cpp); and the geometry walk after pass 2, which re-indexes a probe at the refined geometry to check it holds (RugnuxPasses.cpp; it is logged last, after Writing files)"
},
{
"box": "Per image, pass 2",
"steps": [
"Integration (refined geometry)",
"Integration"
],
"why": "the per-image chain again: 'Integration (refined geometry)' where post-refinement moved the detector geometry, plain 'Integration' where it did not and pass 2 runs at the header geometry (RugnuxImagePass.cpp; cytc_x10sa here)"
},
{
"box": "Scale & merge (P1) -> Symmetry -> Scale & merge",
"steps": [
"Scaling and merging",
"Analyses"
],
"why": "one Step covers the P1 merge, the space-group search and the merge in the chosen group (plus pass 2's post-refinement observations and the rotation-scale probe); Analyses is the anisotropy, tNCS and twinning analysis of that merge. Kept as one column: the sub-timings inside the step overlap (the all-observation P1 merge runs concurrently with the space-group search, and 'space-group search' encloses 'merge <group>'), so the three boxes cannot be split exactly"
},
{
"box": "Structure & map",
"steps": [
"Model validation",
"Molecular replacement"
],
"why": "Model validation is the rigid-body fit of the given model against its null; on 4nwv the moved model is rejected there. For the AlphaFold predictions (myob, cytc) there is no Model validation step, because a predicted model goes straight to MR (RugnuxScaleMerge.cpp). Molecular replacement covers the search, the placement and the maps"
},
{
"box": "Report",
"steps": [
"Writing files"
],
"why": "MTZ, mmCIF, HKL and maps"
}
],
"step_extra_columns": [
[
"of which Molecular replacement",
"Molecular replacement"
]
],
"step_notes": [
"The figure's 'Geometry' box is the stills workflow's and does not apply here."
]
}
@@ -0,0 +1,315 @@
# rugnux timing benchmark across platforms: rc175 3be5dcaac
`battery.py timing` (tools/battery/README.md, 'The timing benchmark'; timing.py, timing.json). myob_x10sa and cytc_x10sa start from AlphaFold DB models, 4nwv from its deposited model moved by a fixed transform; each must be placed by molecular replacement. Code: rc175 3be5dcaac, pushed 2026-10-16; its rugnux code is identical to e25876055 (the later commits change docs only). Each platform's numbers come from its own pack (named under Reproducibility); 'not recorded' means the pack does not have it. This file is generated by timing_table.py from platforms.json, kept beside it with a copy of timing.json: add a platform to platforms.json and re-run `python3 -I timing_table.py platforms.json -o <this file>`.
## Table 1: wall time (s), timing benchmark
Wall = rugnux's own WALL_TIME. Checks = the benchmark's six checks on each set (space_group, placed, mr_group, r_free, confirmed, placement_cc); a failing check would be named.
| Platform | GPU | run | myob_x10sa | cytc_x10sa | 4nwv | checks | MR decision (myob / cytc / 4nwv) |
|:--|:--|:--|--:|--:|--:|:--|:--|
| Workstation: AMD Ryzen 9 5950X (16C/32T) | RTX 5080 16 GB | reference (clean) | 9.2 | 13.2 | 83.7 | all pass | AGREES / ENANTIOMORPH / AGREES |
| Workstation: AMD Ryzen 9 5950X (16C/32T) | none (--no-gpu) | reference (clean) | 65.4 | 95.7 | 515.1 | all pass | AGREES / ENANTIOMORPH / AGREES |
| Server: 4x Intel Xeon Gold 6146 (48C/48T recorded; rugnux used 24) | 4x Tesla T4 (15360 MiB each, as recorded) | reference | 16.9 | 25.8 | 247.7 | all pass | AGREES / ENANTIOMORPH / AGREES |
| DGX Spark: NVIDIA GB10 (ARM, 20 CPUs recorded) | GB10 (unified memory, 121.7 GiB recorded) | reference | 17.1 | 25.7 | 123.2 | all pass | AGREES / ENANTIOMORPH / AGREES |
| Laptop: Intel Core Ultra 7 255H (16C/16T) | RTX PRO 2000 Blackwell Laptop 8 GB | reference | 23.4 | 35.0 | 205.7 | all pass | AGREES / ENANTIOMORPH / AGREES |
| Laptop: Intel Core Ultra 7 255H (16C/16T) | RTX PRO 2000 Blackwell Laptop 8 GB | repeat (earlier run) | 23.3 | 36.0 | 167.2 | all pass | AGREES / ENANTIOMORPH / AGREES |
| Mac mini: Apple M6, 12 cores | Apple M6 GPU (Metal, integration only) | reference | 40.4 | 56.8 | 430.6 | all pass | not recorded / not recorded / not recorded |
| Workstation: AMD Ryzen 9 5950X (16C/32T) | RTX 5080 16 GB | earlier run (10-15 23:26) | 9.2 | 13.4 | 84.5 | all pass | AGREES / ENANTIOMORPH / AGREES |
## Table 2: 4nwv, time per pipeline stage (s)
rugnux's `TIMING step` lines of 4nwv's p_log.txt, grouped into the boxes of the workflow figure (docs/images/rugnux_pipeline.svg); the mapping is below. `-` = none of the stage's steps ran (from the log); `n/r` = a pack without logs reports none of them; `*` = it reports only some of them, so a sum marked `*` is partial. Wall - sum shows whether the steps cover rugnux's own clock (WALL_TIME). Elapsed (the battery's `elapsed_s`, from process launch to exit) minus wall is the time outside rugnux's clock: process start-up before step 1 and the exit after the last step.
| Platform | GPU | run | Input | Pre-scan | Index | Per image, pass 1 | Post-refine | Per image, pass 2 | Scale & merge (P1) -> Symmetry -> Scale & merge | Structure & map | Report | of which Molecular replacement | **sum of steps** | **wall (WALL_TIME)** | wall - sum | elapsed (elapsed_s) | elapsed - wall |
|:--|:--|:--|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|
| Workstation: AMD Ryzen 9 5950X (16C/32T) | RTX 5080 16 GB | reference (clean) | 0.1 | 4.2 | 5.0 | 5.5 | 8.3 | 5.0 | 27.9 | 27.1 | 0.5 | 19.7 | 83.7 | 83.7 | +0.0 | 84.2 | +0.5 |
| Workstation: AMD Ryzen 9 5950X (16C/32T) | none (--no-gpu) | reference (clean) | 0.1 | 7.0 | 23.2 | 36.8 | 15.0 | 46.2 | 55.4 | 330.7 | 0.5 | 243.0 | 515.1 | 515.1 | -0.0 | 515.7 | +0.6 |
| Server: 4x Intel Xeon Gold 6146 (48C/48T recorded; rugnux used 24) | 4x Tesla T4 (15360 MiB each, as recorded) | reference | 0.2 | 6.2 | 6.5 | 4.8 | 16.2 | 6.2 | 56.9 | 149.6 | 1.1 | 123.4 | 247.7 | 247.7 | +0.0 | 249.3 | +1.6 |
| DGX Spark: NVIDIA GB10 (ARM, 20 CPUs recorded) | GB10 (unified memory, 121.7 GiB recorded) | reference | 0.2 | 3.8 | 4.2 | 6.5 | 9.5 | 8.6 | 29.0 | 61.0 | 0.6 | 46.6 | 123.3 | 123.2 | -0.0 | 124.2 | +1.0 |
| Laptop: Intel Core Ultra 7 255H (16C/16T) | RTX PRO 2000 Blackwell Laptop 8 GB | reference | 0.2 | 4.2 | 8.3 | 11.8 | 14.9 | 15.4 | 58.1 | 87.2 | 5.6 | 61.5 | 205.7 | 205.7 | -0.0 | 206.6 | +0.9 |
| Laptop: Intel Core Ultra 7 255H (16C/16T) | RTX PRO 2000 Blackwell Laptop 8 GB | repeat (earlier run) | 0.2 | 4.6 | 8.4 | 11.8 | 13.6 | 15.5 | 39.6 | 70.9 | 2.6 | 52.3 | 167.2 | 167.2 | +0.0 | 168.0 | +0.8 |
| Mac mini: Apple M6, 12 cores | Apple M6 GPU (Metal, integration only) | reference | n/r | 3.9 | 15.4* | 24.9 | 9.4* | 30.1 | 48.8 | 296.3 | 1.7 | 239.9 | 430.5* | 430.6 | +0.1* | not recorded | not recorded |
| Workstation: AMD Ryzen 9 5950X (16C/32T) | RTX 5080 16 GB | earlier run (10-15 23:26) | 0.1 | 4.4 | 5.0 | 5.3 | 8.5 | 5.1 | 28.7 | 27.0 | 0.6 | 19.5 | 84.5 | 84.5 | -0.0 | 85.0 | +0.5 |
Figure box <- rugnux steps (what each step covers, from rugnux/*.cpp):
- **Input** <- Reading input: opening the dataset and reading its header
- **Pre-scan** <- Pre-scan: frame projection, spot widths, beam-stop shadow, defective pixels
- **Index** <- Indexing + Metric-symmetry check + Indexing at the refined geometry: pass 1 first-pass indexing; the metric-symmetry check (only where the free refinement departs from the promoted Bravais class: the alternative class is re-indexed and re-run as a probe on a copy, RugnuxPasses.cpp); pass 2's re-indexing at the post-refined geometry. Pass 1 and pass 2 are kept together because pass 2's indexing is 0.1-0.2 s
- **Per image, pass 1** <- Integration (geometry pre-pass): the per-image chain (decode, azimuthal profile, spot finding, refine, predict, integrate) at the header geometry
- **Post-refine** <- Scaling and post-refinement + Geometry check: pass 1's P1 scale-and-merge plus the post-refinement of distance, beam, cell and axis (one Step in RugnuxScaleMerge.cpp); and the geometry walk after pass 2, which re-indexes a probe at the refined geometry to check it holds (RugnuxPasses.cpp; it is logged last, after Writing files)
- **Per image, pass 2** <- Integration (refined geometry) + Integration: the per-image chain again: 'Integration (refined geometry)' where post-refinement moved the detector geometry, plain 'Integration' where it did not and pass 2 runs at the header geometry (RugnuxImagePass.cpp; cytc_x10sa here)
- **Scale & merge (P1) -> Symmetry -> Scale & merge** <- Scaling and merging + Analyses: one Step covers the P1 merge, the space-group search and the merge in the chosen group (plus pass 2's post-refinement observations and the rotation-scale probe); Analyses is the anisotropy, tNCS and twinning analysis of that merge. Kept as one column: the sub-timings inside the step overlap (the all-observation P1 merge runs concurrently with the space-group search, and 'space-group search' encloses 'merge <group>'), so the three boxes cannot be split exactly
- **Structure & map** <- Model validation + Molecular replacement: Model validation is the rigid-body fit of the given model against its null; on 4nwv the moved model is rejected there. For the AlphaFold predictions (myob, cytc) there is no Model validation step, because a predicted model goes straight to MR (RugnuxScaleMerge.cpp). Molecular replacement covers the search, the placement and the maps
- **Report** <- Writing files: MTZ, mmCIF, HKL and maps
- The figure's 'Geometry' box is the stills workflow's and does not apply here.
- Mac mini: Apple M6, 12 cores (Apple M6 GPU (Metal, integration only)): the Mac pack is one markdown report (rugnux_mac_timing_3be5dc_20261016.md), no run directory or logs. Its 4nwv step table lists 11 steps; Reading input, Indexing at the refined geometry and Geometry check are not in it (n/r), so its sum covers only the listed steps; elapsed_s is not in it.
## Table 3: cytochrome C (cytc_x10sa), time per pipeline stage (s)
rugnux's `TIMING step` lines of cytc_x10sa's p_log.txt, grouped into the boxes of the workflow figure (docs/images/rugnux_pipeline.svg); the mapping is under Table 2. `-` = none of the stage's steps ran (from the log); `n/r` = a pack without logs reports none of them; `*` = it reports only some of them, so a sum marked `*` is partial. Wall - sum shows whether the steps cover rugnux's own clock (WALL_TIME). Elapsed (the battery's `elapsed_s`, from process launch to exit) minus wall is the time outside rugnux's clock: process start-up before step 1 and the exit after the last step.
| Platform | GPU | run | Input | Pre-scan | Index | Per image, pass 1 | Post-refine | Per image, pass 2 | Scale & merge (P1) -> Symmetry -> Scale & merge | Structure & map | Report | of which Molecular replacement | **sum of steps** | **wall (WALL_TIME)** | wall - sum | elapsed (elapsed_s) | elapsed - wall |
|:--|:--|:--|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|
| Workstation: AMD Ryzen 9 5950X (16C/32T) | RTX 5080 16 GB | reference (clean) | 0.2 | 1.1 | 1.4 | 1.3 | 1.0 | 3.3 | 3.6 | 1.1 | 0.2 | 1.1 | 13.2 | 13.2 | -0.0 | 13.5 | +0.3 |
| Workstation: AMD Ryzen 9 5950X (16C/32T) | none (--no-gpu) | reference (clean) | 0.2 | 5.8 | 10.3 | 17.8 | 1.5 | 46.0 | 7.2 | 6.8 | 0.1 | 6.8 | 95.7 | 95.7 | +0.0 | 96.0 | +0.3 |
| Server: 4x Intel Xeon Gold 6146 (48C/48T recorded; rugnux used 24) | 4x Tesla T4 (15360 MiB each, as recorded) | reference | 0.2 | 3.2 | 3.2 | 1.7 | 2.2 | 4.7 | 7.7 | 2.4 | 0.4 | 2.4 | 25.7 | 25.8 | +0.0 | 26.7 | +0.9 |
| DGX Spark: NVIDIA GB10 (ARM, 20 CPUs recorded) | GB10 (unified memory, 121.7 GiB recorded) | reference | 0.2 | 2.1 | 2.5 | 3.1 | 1.2 | 8.0 | 5.2 | 3.1 | 0.4 | 3.1 | 25.7 | 25.7 | +0.0 | 26.3 | +0.6 |
| Laptop: Intel Core Ultra 7 255H (16C/16T) | RTX PRO 2000 Blackwell Laptop 8 GB | reference | 0.3 | 2.0 | 3.2 | 5.2 | 1.4 | 12.5 | 6.1 | 3.9 | 0.5 | 3.9 | 35.0 | 35.0 | +0.0 | 35.4 | +0.4 |
| Laptop: Intel Core Ultra 7 255H (16C/16T) | RTX PRO 2000 Blackwell Laptop 8 GB | repeat (earlier run) | 0.2 | 2.0 | 3.2 | 5.3 | 1.3 | 12.9 | 6.5 | 4.1 | 0.4 | 4.1 | 35.9 | 36.0 | +0.0 | 36.1 | +0.1 |
| Mac mini: Apple M6, 12 cores | Apple M6 GPU (Metal, integration only) | reference | n/r | n/r | n/r | n/r | n/r | n/r | n/r | 4.3 | n/r | 4.3 | 4.3* | 56.8 | +52.5* | not recorded | not recorded |
| Workstation: AMD Ryzen 9 5950X (16C/32T) | RTX 5080 16 GB | earlier run (10-15 23:26) | 0.1 | 1.1 | 1.5 | 1.3 | 1.1 | 3.3 | 3.7 | 1.1 | 0.3 | 1.1 | 13.5 | 13.4 | -0.0 | 13.8 | +0.4 |
Mapping of steps to figure boxes: as under Table 2.
- Mac mini: Apple M6, 12 cores (Apple M6 GPU (Metal, integration only)): the Mac report gives only the wall time and the MR step (4.3 s) for this set; no other step is in it (n/r).
## Table 4: myoglobin (myob_x10sa), time per pipeline stage (s)
rugnux's `TIMING step` lines of myob_x10sa's p_log.txt, grouped into the boxes of the workflow figure (docs/images/rugnux_pipeline.svg); the mapping is under Table 2. `-` = none of the stage's steps ran (from the log); `n/r` = a pack without logs reports none of them; `*` = it reports only some of them, so a sum marked `*` is partial. Wall - sum shows whether the steps cover rugnux's own clock (WALL_TIME). Elapsed (the battery's `elapsed_s`, from process launch to exit) minus wall is the time outside rugnux's clock: process start-up before step 1 and the exit after the last step.
| Platform | GPU | run | Input | Pre-scan | Index | Per image, pass 1 | Post-refine | Per image, pass 2 | Scale & merge (P1) -> Symmetry -> Scale & merge | Structure & map | Report | of which Molecular replacement | **sum of steps** | **wall (WALL_TIME)** | wall - sum | elapsed (elapsed_s) | elapsed - wall |
|:--|:--|:--|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|
| Workstation: AMD Ryzen 9 5950X (16C/32T) | RTX 5080 16 GB | reference (clean) | 0.2 | 1.3 | 1.6 | 1.0 | 0.8 | 2.4 | 1.5 | 0.5 | 0.0 | 0.5 | 9.2 | 9.2 | -0.0 | 9.6 | +0.4 |
| Workstation: AMD Ryzen 9 5950X (16C/32T) | none (--no-gpu) | reference (clean) | 0.1 | 6.2 | 12.8 | 11.9 | 0.7 | 27.3 | 4.4 | 1.8 | 0.0 | 1.8 | 65.4 | 65.4 | -0.0 | 65.7 | +0.3 |
| Server: 4x Intel Xeon Gold 6146 (48C/48T recorded; rugnux used 24) | 4x Tesla T4 (15360 MiB each, as recorded) | reference | 0.2 | 3.6 | 3.7 | 1.2 | 1.8 | 2.5 | 2.8 | 0.8 | 0.1 | 0.8 | 16.9 | 16.9 | +0.0 | 18.0 | +1.1 |
| DGX Spark: NVIDIA GB10 (ARM, 20 CPUs recorded) | GB10 (unified memory, 121.7 GiB recorded) | reference | 0.2 | 2.3 | 3.0 | 2.1 | 1.1 | 4.8 | 2.5 | 1.0 | 0.1 | 1.0 | 17.1 | 17.1 | +0.0 | 17.7 | +0.6 |
| Laptop: Intel Core Ultra 7 255H (16C/16T) | RTX PRO 2000 Blackwell Laptop 8 GB | reference | 0.3 | 2.4 | 3.8 | 3.4 | 2.4 | 7.3 | 2.1 | 1.5 | 0.1 | 1.5 | 23.4 | 23.4 | +0.0 | 27.7 | +4.3 |
| Laptop: Intel Core Ultra 7 255H (16C/16T) | RTX PRO 2000 Blackwell Laptop 8 GB | repeat (earlier run) | 0.2 | 2.2 | 3.8 | 3.5 | 2.2 | 7.4 | 2.0 | 1.8 | 0.1 | 1.8 | 23.3 | 23.3 | +0.0 | 27.3 | +4.0 |
| Mac mini: Apple M6, 12 cores | Apple M6 GPU (Metal, integration only) | reference | n/r | n/r | n/r | n/r | n/r | n/r | n/r | 1.6 | n/r | 1.6 | 1.6* | 40.4 | +38.8* | not recorded | not recorded |
| Workstation: AMD Ryzen 9 5950X (16C/32T) | RTX 5080 16 GB | earlier run (10-15 23:26) | 0.1 | 1.3 | 1.7 | 1.0 | 0.9 | 2.1 | 1.5 | 0.4 | 0.0 | 0.4 | 9.2 | 9.2 | -0.0 | 9.5 | +0.3 |
Mapping of steps to figure boxes: as under Table 2.
- Mac mini: Apple M6, 12 cores (Apple M6 GPU (Metal, integration only)): the Mac report gives only the wall time and the MR step (1.6 s) for this set; no other step is in it (n/r).
Where 4nwv's work ran and peak memory:
| Platform | GPU | run | scaling | model validation | MR search | peak memory (myob / cytc / 4nwv) |
|:--|:--|:--|:--|:--|:--|:--|
| Workstation: AMD Ryzen 9 5950X (16C/32T) | RTX 5080 16 GB | reference (clean) | GPU | GPU (6.56 GB of a 13.29 GB budget) | GPU | 3.5 GiB RSS / 5.1 GiB RSS / 18.4 GiB RSS |
| Workstation: AMD Ryzen 9 5950X (16C/32T) | none (--no-gpu) | reference (clean) | CPU | CPU | CPU | 9.9 GiB RSS / 10.0 GiB RSS / 26.8 GiB RSS |
| Server: 4x Intel Xeon Gold 6146 (48C/48T recorded; rugnux used 24) | 4x Tesla T4 (15360 MiB each, as recorded) | reference | GPU | GPU (5.18 GB of a 12.52 GB budget) | GPU | not recorded |
| DGX Spark: NVIDIA GB10 (ARM, 20 CPUs recorded) | GB10 (unified memory, 121.7 GiB recorded) | reference | GPU | GPU (22.12 GB of a 104.53 GB budget) | GPU | not recorded |
| Laptop: Intel Core Ultra 7 255H (16C/16T) | RTX PRO 2000 Blackwell Laptop 8 GB | reference | GPU | GPU (4.42 GB of a 6.84 GB budget) | GPU | not recorded |
| Laptop: Intel Core Ultra 7 255H (16C/16T) | RTX PRO 2000 Blackwell Laptop 8 GB | repeat (earlier run) | GPU | GPU (4.42 GB of a 6.84 GB budget) | GPU | not recorded |
| Mac mini: Apple M6, 12 cores | Apple M6 GPU (Metal, integration only) | reference | CPU | CPU | CPU (no CUDA build) | 6.7 GiB RSS (~6.9 GiB footprint) / 5.9 GiB RSS (~10 GiB footprint) / 9.1 GiB RSS (~22 GiB footprint) |
| Workstation: AMD Ryzen 9 5950X (16C/32T) | RTX 5080 16 GB | earlier run (10-15 23:26) | GPU | GPU (6.56 GB of a 13.29 GB budget) | GPU | not recorded |
## Data
The three sets of tools/battery/timing.json (copy: `timing.json` beside this report). Each is started from a model it has to place by molecular replacement:
| set | arm | start model (--model) | expected: MR group (sgno), R_free max, placement CC min |
|:--|:--|:--|:--|
| myob_x10sa | inhouse | `tools/battery/models/AF-P68082-F1-model_v6.cif`: AlphaFold DB AF-P68082-F1 v6: myoglobin, Equus caballus (UniProt P68082), the species of the battery's reference model 4DC8 (horse heart). No heme | 4, 0.5, 0.3 |
| cytc_x10sa | inhouse | `tools/battery/models/AF-P62894-F1-model_v6.cif`: AlphaFold DB AF-P62894-F1 v6: cytochrome c, Bos taurus (UniProt P62894), the protein of the battery's reference model (bovine heart, placed with 6FF5). No heme; three copies to place, related by a pseudo-translation | 154, 0.5, 0.3 |
| 4nwv | open | deposited 4NWV from the site's pdb_cache, strict NCS expanded, turned 30.0 deg about the unit axis (0.36, 0.48, 0.8) through the centroid c of the expanded asymmetric unit and shifted t = (12.0, -18.0, 25.0) A (x' = R (x - c) + c + t), written as 4nwv_moved.cif.gz | 23, 0.35, 0.3 |
Each platform's input path for each set is in its rugnux commands below.
## Reproducibility, per platform and run
### Workstation: AMD Ryzen 9 5950X (16C/32T) | RTX 5080 16 GB | reference (clean)
- **pack**: run directory on the machine itself
- **run directory**: 20261016-0941_e25876_ws-3be5dc-timing
- **date/time**: 2026-10-16T09:41:50 to 2026-10-16T09:43:41 (the machine's local time)
- **host**: mpc2898.psi.ch
- **OS**: Rocky Linux 8.10, kernel 4.18.0-553.22.1.el8_10.x86_64, NVIDIA driver 580.82.07 (read 2026-10-16, after the runs)
- **rugnux (as the binary reports)**: rugnux Version 1.0.0-rc.175 (git e25876 Thu Oct 15 23:13:40 2026) - CUDA build
- **build flags (as the binary reports)**: -march=x86-64-v3
- **build (battery manifest)**: Release CXX_FLAGS='-march=x86-64-v3' CUDA=ON; CMakeCache /data/tmp/rc175-metal-merge/build/CMakeCache.txt; source HEAD 2be738f557d985250bcbfad63f51735a069f799e; sha256 4ace4e1febbad7ff2502e5cb1295c3d70723e67424161934a1e22c9c250ce89f
- **compiler / CUDA / arch**: GCC 13.3.1 (gcc-toolset-13), nvcc 13.0.88, CUDA code for sm_75/80/86/89/90/100/120/121 (the default list; JFJOCH_CUDA_ARCHITECTURES empty), CMAKE_CXX_FLAGS/CMAKE_C_FLAGS = -march=x86-64-v3, no LTO; build dir /data/tmp/rc175-metal-merge/build (CMakeCache and CMakeFiles read 2026-10-16)
- **battery command**: `cd /home/jungfrau/nextgendcu && nice -n 0 python3 tools/battery/battery.py --site /data/battery/site.json timing --rugnux /data/tmp/rc175-metal-merge/build/rugnux/rugnux --gpulock --label ws-3be5dc-timing`
- **battery runner**: tools/battery at 2be738f55
- **battery options (manifest)**: label ws-3be5dc-timing, threads 0 (0 = no -N), gpulock /data/battery/gpulock.sh, extra args [], timeout 10800 s
- **threads (rugnux reports)**: 32
- **hardware (manifest)**: CPU AMD Ryzen 9 5950X 16-Core Processor, 16 cores / 32 threads, 125.3 GiB RAM, GPU NVIDIA GeForce RTX 5080 (memory 16303 MiB)
- **GPU (rugnux reports)**: NVIDIA GeForce RTX 5080 (1 visible)
- **conditions**: started 09:41:50 right after a full battery ended (09:41); no other rugnux/battery/build process, GPU lock free, 0.3 GiB in use on the card before; load average 1.43 before, 6.70 after, highest 1-min load sampled during the run 9.75 (rugnux's own threads); page cache warm (the full battery had just read the same datasets); not the first run after the build
- **rugnux command, myob_x10sa**: `/data/battery/gpulock.sh /data/battery/runs/20261016-0941_e25876_ws-3be5dc-timing/bin/rugnux -o p --no-export-unmerged --report-resolution 1.742,50.000 --model /home/jungfrau/nextgendcu/tools/battery/models/AF-P68082-F1-model_v6.cif /ssd/data/inhouse/myob_x10sa/MyoB_13_110ee0_master.h5`
- **rugnux command, cytc_x10sa**: `/data/battery/gpulock.sh /data/battery/runs/20261016-0941_e25876_ws-3be5dc-timing/bin/rugnux -o p --no-export-unmerged --report-resolution 2.039,50.000 --model /home/jungfrau/nextgendcu/tools/battery/models/AF-P62894-F1-model_v6.cif /ssd/data/inhouse/cytc_x10sa/cytC_10_002_master.h5`
- **rugnux command, 4nwv**: `/data/battery/gpulock.sh /data/battery/runs/20261016-0941_e25876_ws-3be5dc-timing/bin/rugnux -o p --no-export-unmerged --model /data/battery/runs/20261016-0941_e25876_ws-3be5dc-timing/work/open/4nwv/4nwv_moved.cif.gz /ssd/data/open/4nwv/sbgrid9/formal.001`
- Peak RSS = VmHWM from /proc/<pid>/status, sampled every 0.5 s. Whole-card GPU memory in use peaked at 8.1 GiB (nvidia-smi every 0.5 s; 0.3 GiB idle baseline).
- The binary reports git e25876; the rugnux code of e25876055 and 3be5dcaac is identical (the later commits change docs only). The battery runner was the shared checkout at 2be738f55 (3be5dcaac plus the Windows battery fixes).
- The manifest's 'source HEAD' is the build directory's source tree at run time (it had moved on to 2be738f55); the commit the binary was built from is the one it reports (e25876).
### Workstation: AMD Ryzen 9 5950X (16C/32T) | none (--no-gpu) | reference (clean)
- **pack**: run directory on the machine itself
- **run directory**: 20261016-0943_e25876_ws-3be5dc-timing-nogpu
- **date/time**: 2026-10-16T09:43:51 to 2026-10-16T09:55:13 (the machine's local time)
- **host**: mpc2898.psi.ch
- **OS**: Rocky Linux 8.10, kernel 4.18.0-553.22.1.el8_10.x86_64, NVIDIA driver 580.82.07 (read 2026-10-16, after the runs)
- **rugnux (as the binary reports)**: rugnux Version 1.0.0-rc.175 (git e25876 Thu Oct 15 23:13:40 2026) - CUDA build
- **build flags (as the binary reports)**: -march=x86-64-v3
- **build (battery manifest)**: Release CXX_FLAGS='-march=x86-64-v3' CUDA=ON; CMakeCache /data/tmp/rc175-metal-merge/build/CMakeCache.txt; source HEAD 2be738f557d985250bcbfad63f51735a069f799e; sha256 4ace4e1febbad7ff2502e5cb1295c3d70723e67424161934a1e22c9c250ce89f
- **compiler / CUDA / arch**: GCC 13.3.1 (gcc-toolset-13), nvcc 13.0.88, CUDA code for sm_75/80/86/89/90/100/120/121 (the default list; JFJOCH_CUDA_ARCHITECTURES empty), CMAKE_CXX_FLAGS/CMAKE_C_FLAGS = -march=x86-64-v3, no LTO; build dir /data/tmp/rc175-metal-merge/build (CMakeCache and CMakeFiles read 2026-10-16) (same binary as the GPU run)
- **battery command**: `cd /home/jungfrau/nextgendcu && nice -n 0 python3 tools/battery/battery.py --site /data/battery/site.json timing --rugnux /data/tmp/rc175-metal-merge/build/rugnux/rugnux --gpulock --extra=--no-gpu --label ws-3be5dc-timing-nogpu`
- **battery runner**: tools/battery at 2be738f55
- **battery options (manifest)**: label ws-3be5dc-timing-nogpu, threads 0 (0 = no -N), gpulock /data/battery/gpulock.sh, extra args ['--no-gpu'], timeout 10800 s
- **threads (rugnux reports)**: 32
- **hardware (manifest)**: CPU AMD Ryzen 9 5950X 16-Core Processor, 16 cores / 32 threads, 125.3 GiB RAM, GPU NVIDIA GeForce RTX 5080 (memory 16303 MiB)
- **GPU (rugnux reports)**: not used (--no-gpu) - running on the CPU
- **conditions**: started 09:43:50 right after the GPU run, nothing else running; load average 5.67 before, 12.22 after, highest 1-min load sampled 34.1 during 4nwv (rugnux's own 32 threads); page cache warm
- **rugnux command, myob_x10sa**: `/data/battery/gpulock.sh /data/battery/runs/20261016-0943_e25876_ws-3be5dc-timing-nogpu/bin/rugnux -o p --no-export-unmerged --report-resolution 1.742,50.000 --model /home/jungfrau/nextgendcu/tools/battery/models/AF-P68082-F1-model_v6.cif --no-gpu /ssd/data/inhouse/myob_x10sa/MyoB_13_110ee0_master.h5`
- **rugnux command, cytc_x10sa**: `/data/battery/gpulock.sh /data/battery/runs/20261016-0943_e25876_ws-3be5dc-timing-nogpu/bin/rugnux -o p --no-export-unmerged --report-resolution 2.039,50.000 --model /home/jungfrau/nextgendcu/tools/battery/models/AF-P62894-F1-model_v6.cif --no-gpu /ssd/data/inhouse/cytc_x10sa/cytC_10_002_master.h5`
- **rugnux command, 4nwv**: `/data/battery/gpulock.sh /data/battery/runs/20261016-0943_e25876_ws-3be5dc-timing-nogpu/bin/rugnux -o p --no-export-unmerged --model /data/battery/runs/20261016-0943_e25876_ws-3be5dc-timing-nogpu/work/open/4nwv/4nwv_moved.cif.gz --no-gpu /ssd/data/open/4nwv/sbgrid9/formal.001`
- Peak RSS = VmHWM from /proc, sampled every 0.5 s.
- Runner and binary as in the GPU run.
- The manifest's 'source HEAD' is the build directory's source tree at run time (it had moved on to 2be738f55); the commit the binary was built from is the one it reports (e25876).
### Server: 4x Intel Xeon Gold 6146 (48C/48T recorded; rugnux used 24) | 4x Tesla T4 (15360 MiB each, as recorded) | reference
- **pack**: bundle_rc175_3be5dc.tar.gz, bundle_rc175_3be5dc/b_mr_timing
- **run directory**: 20261016-0531_3be5dc_timing (on the server; b_mr_timing in the pack, name from its console.log)
- **date/time**: 2026-10-16T05:31:22 to 2026-10-16T05:36:23 (the machine's local time)
- **host**: mx-aare-test
- **OS**: not recorded
- **rugnux (as the binary reports)**: rugnux Version 1.0.0-rc.175 (git 3be5dc Fri Oct 16 00:55:26 2026) - CUDA build
- **build flags (as the binary reports)**: -march=x86-64-v3
- **build (battery manifest)**: Release CXX_FLAGS='-march=x86-64-v3' CUDA=ON; CMakeCache build_v3/CMakeCache.txt; source HEAD 3be5dcaac8cf39a6871d0865efd669f608f4442d; sha256 00843ce39f5bda1e8b00d45f81f475f99251de2ffd6ef047c648c27ca881fb69
- **compiler / CUDA / arch**: Release, -march=x86-64-v3, CUDA on (manifest; build dir build_v3); compiler, CUDA version, CUDA arch and LTO not recorded
- **battery command**: not recorded (the pack's console.log shows `battery.py timing` output; the manifest: label 'timing', no gpulock, no extra arguments)
- **battery runner**: tools/battery at 3be5dcaac
- **battery options (manifest)**: label timing, threads 0 (0 = no -N), gpulock None, extra args [], timeout 10800 s
- **threads (rugnux reports)**: 24
- **hardware (manifest)**: CPU Intel(R) Xeon(R) Gold 6146 CPU @ 3.20GHz, 48 cores / 48 threads, 1479.3 GiB RAM, GPU Tesla T4 (memory 15360 MiB), Tesla T4 (memory 15360 MiB), Tesla T4 (memory 15360 MiB), Tesla T4 (memory 15360 MiB)
- **GPU (rugnux reports)**: 4x Tesla T4 (4 visible)
- **conditions**: started 05:31:22, 5 s after a full battery run on the same machine ended (03:27:52 to 05:31:17, the pack's a_battery), so the page cache was presumably warm (not recorded as such); GPU not shared during that battery (its report); load average at 05:37:04, 40 s after the timing run ended: 0.52 / 3.85 / 6.32 (1 / 5 / 15 min), all four GPUs idle then (c_profile machine_before); load during the run not recorded; rugnux limits itself to 24 threads, the CPUs of the GPUs' sockets (24-47), and uses all 4 GPUs
- **rugnux command, myob_x10sa**: `/data/battery/runs/20261016-0531_3be5dc_timing/bin/rugnux -o p --no-export-unmerged --report-resolution 1.742,50.000 --model /home/jungfrau/jungfraujoch/tools/battery/models/AF-P68082-F1-model_v6.cif /data/inhouse/myob_x10sa/MyoB_13_110ee0_master.h5`
- **rugnux command, cytc_x10sa**: `/data/battery/runs/20261016-0531_3be5dc_timing/bin/rugnux -o p --no-export-unmerged --report-resolution 2.039,50.000 --model /home/jungfrau/jungfraujoch/tools/battery/models/AF-P62894-F1-model_v6.cif /data/inhouse/cytc_x10sa/cytC_10_002_master.h5`
- **rugnux command, 4nwv**: `/data/battery/runs/20261016-0531_3be5dc_timing/bin/rugnux -o p --no-export-unmerged --model /data/battery/runs/20261016-0531_3be5dc_timing/work/open/4nwv/4nwv_moved.cif.gz /data/open/4nwv/sbgrid9/formal.001`
- Peak memory not recorded. 4nwv model validation planned 5.18 GB of a 12.52 GB budget (80% of the card's 15.65 GB) and MR 4.79 GB, on the GPU.
- The pack also holds the full battery (a_battery) and nsys/perf profiles (c_profile); they are not used here.
### DGX Spark: NVIDIA GB10 (ARM, 20 CPUs recorded) | GB10 (unified memory, 121.7 GiB recorded) | reference
- **pack**: rugnux_gb10_perf_rc175-3be5dc_20261016.tar.gz, rugnux_gb10_perf_rc175-3be5dc_20261016/battery/20261016-0944_3be5dc_gb10-rc175-3be5dc-mr
- **run directory**: 20261016-0944_3be5dc_gb10-rc175-3be5dc-mr
- **date/time**: 2026-10-16T09:44:46 to 2026-10-16T09:47:38 (the machine's local time)
- **host**: mx-spark-01
- **OS**: not recorded (DGX Spark per the pack's ANALYSIS.md)
- **rugnux (as the binary reports)**: rugnux Version 1.0.0-rc.175 (git 3be5dc Fri Oct 16 06:55:26 2026) - CUDA build
- **build flags (as the binary reports)**: none
- **build (battery manifest)**: Release CXX_FLAGS='' CUDA=ON; CMakeCache /home/jungfrau/jfj-rc175/build-rel/CMakeCache.txt; source HEAD 3be5dcaac8cf39a6871d0865efd669f608f4442d; sha256 0f536f07f21de2421688bb7651a73fdf4e5a1d2e4cfa464bb3e95d362803a10e
- **compiler / CUDA / arch**: Release, -DJFJOCH_RUGNUX_ONLY=ON -DJFJOCH_CUDA_ARCHITECTURES=121, no -march (ANALYSIS.md); LTO, compiler and CUDA versions not recorded
- **battery command**: not recorded (ANALYSIS.md: rc175's tools/battery `battery.py timing`, the pack's data, an absolute-path site config)
- **battery runner**: tools/battery at 3be5dcaac
- **battery options (manifest)**: label gb10-rc175-3be5dc-mr, threads 0 (0 = no -N), gpulock None, extra args [], timeout 10800 s
- **threads (rugnux reports)**: 20
- **hardware (manifest)**: CPU not recorded, not recorded cores / 20 threads, 121.7 GiB RAM, GPU NVIDIA GB10 (memory not recorded)
- **GPU (rugnux reports)**: NVIDIA GB10 (1 visible)
- **conditions**: GPU not shared: the resident GPU service was stopped for the whole session (ANALYSIS.md; the report says 'GPU was not shared during the run'); no gpulock; started 4 min after a six-set battery run on the same data (page cache state not recorded); load not recorded; the pack's pdb_cache JSONs were repointed by hand before this run
- **rugnux command, myob_x10sa**: `/home/jungfrau/jungfraujoch/battery/rugnux_battery_perf_20261014/runs/20261016-0944_3be5dc_gb10-rc175-3be5dc-mr/bin/rugnux -o p --no-export-unmerged --report-resolution 1.742,50.000 --model /home/jungfrau/jfj-rc175/tools/battery/models/AF-P68082-F1-model_v6.cif /home/jungfrau/jungfraujoch/battery/rugnux_battery_perf_20261014/data/inhouse/myob_x10sa/MyoB_13_110ee0_master.h5`
- **rugnux command, cytc_x10sa**: `/home/jungfrau/jungfraujoch/battery/rugnux_battery_perf_20261014/runs/20261016-0944_3be5dc_gb10-rc175-3be5dc-mr/bin/rugnux -o p --no-export-unmerged --report-resolution 2.039,50.000 --model /home/jungfrau/jfj-rc175/tools/battery/models/AF-P62894-F1-model_v6.cif /home/jungfrau/jungfraujoch/battery/rugnux_battery_perf_20261014/data/inhouse/cytc_x10sa/cytC_10_002_master.h5`
- **rugnux command, 4nwv**: `/home/jungfrau/jungfraujoch/battery/rugnux_battery_perf_20261014/runs/20261016-0944_3be5dc_gb10-rc175-3be5dc-mr/bin/rugnux -o p --no-export-unmerged --model /home/jungfrau/jungfraujoch/battery/rugnux_battery_perf_20261014/runs/20261016-0944_3be5dc_gb10-rc175-3be5dc-mr/work/open/4nwv/4nwv_moved.cif.gz /home/jungfrau/jungfraujoch/battery/rugnux_battery_perf_20261014/data/open/4nwv/sbgrid9/formal.001`
- Peak memory not recorded. With unified memory the GPU budget is 104.53 GB: 4nwv model validation planned 22.12 GB (10 rigid-body engines), MR 21.60 GB (9 rigid-body engines).
- The same binary with the deposited 4nwv model (six-set run 20261016-0940_3be5dc_gb10-rc175-3be5dc in the same pack): 76.7 s.
### Laptop: Intel Core Ultra 7 255H (16C/16T) | RTX PRO 2000 Blackwell Laptop 8 GB | reference
- **pack**: rugnux_win11_perf_3be5dc_20261016.tar.gz, rugnux_win11_perf_3be5dc_20261016/runs/1_timing
- **run directory**: 20261016-0753_3be5dc_3be5dc-timing-patched (on the laptop; runs/1_timing in the pack, name from its SOURCE_RUN.txt)
- **date/time**: 2026-10-16T07:53:42 to 2026-10-16T07:58:21 (the machine's local time)
- **host**: PC17975
- **OS**: Windows 11 (pack name; build number not recorded); GPU in WDDM mode (BRIEF.md)
- **rugnux (as the binary reports)**: rugnux Version 1.0.0-rc.175 (git 3be5dc Fri Oct 16 06:55:26 2026) - CUDA build
- **build flags (as the binary reports)**: /arch:AVX
- **build (battery manifest)**: Release CXX_FLAGS='/arch:AVX' CUDA=ON; CMakeCache build-win-ci\CMakeCache.txt; source HEAD 3be5dcaac8cf39a6871d0865efd669f608f4442d (tree dirty); sha256 ce0248ef8b9c5b270a886d0dfed682cc3533b8fc962cdf54f086c247165b77b8
- **compiler / CUDA / arch**: MSVC 19.51 + CUDA 13.3, CI Windows settings /arch:AVX (BRIEF.md); CUDA arch and LTO not recorded; build dir build-win-ci
- **battery command**: not recorded (BRIEF.md: `battery.py timing` with the runner patched by battery-windows.patch, run from the pack's unmodified site.json)
- **battery runner**: tools/battery at 3be5dcaac (dirty)
- **battery options (manifest)**: label 3be5dc-timing-patched, threads 0 (0 = no -N), gpulock None, extra args [], timeout 10800 s
- **threads (rugnux reports)**: 16
- **hardware (manifest)**: CPU Intel(R) Core(TM) Ultra 7 255H, 16 cores / 16 threads, 31.4 GiB RAM, GPU NVIDIA RTX PRO 2000 Blackwell Generation Laptop GPU (memory 8151 MiB)
- **GPU (rugnux reports)**: NVIDIA RTX PRO 2000 Blackwell Generation Laptop GPU (1 visible)
- **conditions**: nothing else on the GPU, no gpulock (site gpulock null); the session's second timing run (the first is the next row); load and page cache not recorded
- **rugnux command, myob_x10sa**: `C:\Users\leonarski_f\rugnux_battery_perf_20261014\runs\20261016-0753_3be5dc_3be5dc-timing-patched\bin\rugnux.exe -o p --no-export-unmerged --report-resolution 1.742,50.000 --model C:\Users\leonarski_f\jungfraujoch\tools\battery\models/AF-P68082-F1-model_v6.cif C:\Users\leonarski_f\rugnux_battery_perf_20261014\data/inhouse\myob_x10sa/MyoB_13_110ee0_master.h5`
- **rugnux command, cytc_x10sa**: `C:\Users\leonarski_f\rugnux_battery_perf_20261014\runs\20261016-0753_3be5dc_3be5dc-timing-patched\bin\rugnux.exe -o p --no-export-unmerged --report-resolution 2.039,50.000 --model C:\Users\leonarski_f\jungfraujoch\tools\battery\models/AF-P62894-F1-model_v6.cif C:\Users\leonarski_f\rugnux_battery_perf_20261014\data/inhouse\cytc_x10sa/cytC_10_002_master.h5`
- **rugnux command, 4nwv**: `C:\Users\leonarski_f\rugnux_battery_perf_20261014\runs\20261016-0753_3be5dc_3be5dc-timing-patched\bin\rugnux.exe -o p --no-export-unmerged --model C:\Users\leonarski_f\rugnux_battery_perf_20261014\runs\20261016-0753_3be5dc_3be5dc-timing-patched\work\open\4nwv\4nwv_moved.cif.gz C:\Users\leonarski_f\rugnux_battery_perf_20261014\data/open\4nwv/sbgrid9/formal.001`
- Why this run is the reference: it is the run the pack's BRIEF.md reports as its result (`1_timing`, the patched runner from the pack's own site.json). The earlier run (next row) used the same binary (same sha256) and the unpatched runner. BRIEF.md puts the 167 vs 206 s 4nwv spread down to laptop thermals/power; that is its reading, not a measurement.
### Laptop: Intel Core Ultra 7 255H (16C/16T) | RTX PRO 2000 Blackwell Laptop 8 GB | repeat (earlier run)
- **pack**: rugnux_win11_perf_3be5dc_20261016.tar.gz, rugnux_win11_perf_3be5dc_20261016/runs/repeat_timing
- **run directory**: 20261016-0741_3be5dc_3be5dc-timing (on the laptop; runs/repeat_timing in the pack, name from its SOURCE_RUN.txt)
- **date/time**: 2026-10-16T07:41:16 to 2026-10-16T07:45:13 (the machine's local time)
- **host**: PC17975
- **OS**: Windows 11 (pack name; build number not recorded)
- **rugnux (as the binary reports)**: rugnux Version 1.0.0-rc.175 (git 3be5dc Fri Oct 16 06:55:26 2026) - CUDA build
- **build flags (as the binary reports)**: /arch:AVX
- **build (battery manifest)**: Release CXX_FLAGS='/arch:AVX' CUDA=ON; CMakeCache C:/Users/leonarski_f/jungfraujoch/build-win-ci\CMakeCache.txt; source HEAD 3be5dcaac8cf39a6871d0865efd669f608f4442d; sha256 ce0248ef8b9c5b270a886d0dfed682cc3533b8fc962cdf54f086c247165b77b8
- **compiler / CUDA / arch**: same binary as the reference row (sha256 ce0248ef...)
- **battery command**: not recorded (BRIEF.md: the repo's unpatched runner with an absolute-path site config)
- **battery runner**: tools/battery at 3be5dcaac
- **battery options (manifest)**: label 3be5dc-timing, threads 0 (0 = no -N), gpulock None, extra args [], timeout 10800 s
- **threads (rugnux reports)**: 16
- **hardware (manifest)**: not recorded
- **GPU (rugnux reports)**: NVIDIA RTX PRO 2000 Blackwell Generation Laptop GPU (1 visible)
- **conditions**: the session's first timing run; nothing else on the GPU; load and page cache not recorded; hardware not recorded in this run's manifest (same host PC17975)
- **rugnux command, myob_x10sa**: `C:/Users/leonarski_f/rugnux_battery_perf_20261014/runs\20261016-0741_3be5dc_3be5dc-timing\bin\rugnux.exe -o p --no-export-unmerged --report-resolution 1.742,50.000 --model C:\Users\leonarski_f\jungfraujoch\tools\battery\models/AF-P68082-F1-model_v6.cif C:/Users/leonarski_f/rugnux_battery_perf_20261014/data/inhouse\myob_x10sa/MyoB_13_110ee0_master.h5`
- **rugnux command, cytc_x10sa**: `C:/Users/leonarski_f/rugnux_battery_perf_20261014/runs\20261016-0741_3be5dc_3be5dc-timing\bin\rugnux.exe -o p --no-export-unmerged --report-resolution 2.039,50.000 --model C:\Users\leonarski_f\jungfraujoch\tools\battery\models/AF-P62894-F1-model_v6.cif C:/Users/leonarski_f/rugnux_battery_perf_20261014/data/inhouse\cytc_x10sa/cytC_10_002_master.h5`
- **rugnux command, 4nwv**: `C:/Users/leonarski_f/rugnux_battery_perf_20261014/runs\20261016-0741_3be5dc_3be5dc-timing\bin\rugnux.exe -o p --no-export-unmerged --model C:/Users/leonarski_f/rugnux_battery_perf_20261014/runs\20261016-0741_3be5dc_3be5dc-timing\work\open\4nwv\4nwv_moved.cif.gz C:/Users/leonarski_f/rugnux_battery_perf_20261014/data/open\4nwv/sbgrid9/formal.001`
### Mac mini: Apple M6, 12 cores | Apple M6 GPU (Metal, integration only) | reference
- **run directory**: runs/20261016-0727_3be5dc_timing-3be5dc (on the Mac)
- **date/time**: 2026-10-16 07:27 start (from the run directory name); end not recorded
- **host**: not recorded
- **OS**: macOS (version not recorded)
- **rugnux (as the binary reports)**: not recorded (the report: origin/rc175 tip 3be5dcaac, metal-integration merged)
- **build flags (as the binary reports)**: not recorded
- **build (battery manifest)**: not recorded (the report: Release, no -march/LTO flags, JFJOCH_USE_CUDA=OFF, built in the jungfraujoch-origin-rc175 worktree)
- **compiler / CUDA / arch**: not recorded (no CUDA; Metal integration engine)
- **battery command**: not recorded (the report: `battery.py timing` with an absolute-path copy of the site config)
- **battery runner**: the repo's tools/battery at 3be5dcaac (the report), not patched
- **threads (rugnux reports)**: not recorded
- **hardware (manifest)**: Mac mini M6, 12 cores (performance/efficiency split not recorded), 16 GB (the report)
- **GPU (rugnux reports)**: not recorded
- **conditions**: nothing else running; data read cold (the report)
- **rugnux command, myob_x10sa**: not recorded
- **rugnux command, cytc_x10sa**: not recorded
- **rugnux command, 4nwv**: not recorded
- Peak memory sampled once a second by the Mac agent (ps RSS; top's physical footprint, rounded to whole GiB above 10 GiB).
- The pack's 4nwv pdb_cache JSON had to be corrected by hand before 4nwv would run.
### Workstation: AMD Ryzen 9 5950X (16C/32T) | RTX 5080 16 GB | earlier run (10-15 23:26)
- **pack**: run directory on the machine itself
- **run directory**: 20261015-2326_e25876_rc175-r10-timing
- **date/time**: 2026-10-15T23:26:18 to 2026-10-15T23:28:11 (the machine's local time)
- **host**: mpc2898.psi.ch
- **OS**: Rocky Linux 8.10, kernel 4.18.0-553.22.1.el8_10.x86_64, NVIDIA driver 580.82.07 (read 2026-10-16, after the runs)
- **rugnux (as the binary reports)**: rugnux Version 1.0.0-rc.175 (git e25876 Thu Oct 15 23:13:40 2026) - CUDA build
- **build flags (as the binary reports)**: -march=x86-64-v3
- **build (battery manifest)**: Release CXX_FLAGS='-march=x86-64-v3' CUDA=ON; CMakeCache /data/tmp/rc175-metal-merge/build/CMakeCache.txt; source HEAD e25876055feaff22bd10c092f911019e5d0ec54d; sha256 4ace4e1febbad7ff2502e5cb1295c3d70723e67424161934a1e22c9c250ce89f
- **compiler / CUDA / arch**: same binary as the clean workstation runs (sha256 identical)
- **battery command**: not recorded (options in the manifest below)
- **battery runner**: tools/battery at 0a8eda37f
- **battery options (manifest)**: label rc175-r10-timing, threads 0 (0 = no -N), gpulock /data/battery/gpulock.sh, extra args [], timeout 10800 s
- **threads (rugnux reports)**: 32
- **hardware (manifest)**: CPU AMD Ryzen 9 5950X 16-Core Processor, 16 cores / 32 threads, 125.3 GiB RAM, GPU NVIDIA GeForce RTX 5080 (memory 16303 MiB)
- **GPU (rugnux reports)**: NVIDIA GeForce RTX 5080 (1 visible)
- **conditions**: described by the owner as taken while the machine was heavily loaded by other agents (load 15-35); load during this run not recorded; its times are within 1% of the clean run
- **rugnux command, myob_x10sa**: `/data/battery/gpulock.sh /data/battery/runs/20261015-2326_e25876_rc175-r10-timing/bin/rugnux -o p --no-export-unmerged --report-resolution 1.742,50.000 --model /home/jungfrau/nextgendcu/tools/battery/models/AF-P68082-F1-model_v6.cif /ssd/data/inhouse/myob_x10sa/MyoB_13_110ee0_master.h5`
- **rugnux command, cytc_x10sa**: `/data/battery/gpulock.sh /data/battery/runs/20261015-2326_e25876_rc175-r10-timing/bin/rugnux -o p --no-export-unmerged --report-resolution 2.039,50.000 --model /home/jungfrau/nextgendcu/tools/battery/models/AF-P62894-F1-model_v6.cif /ssd/data/inhouse/cytc_x10sa/cytC_10_002_master.h5`
- **rugnux command, 4nwv**: `/data/battery/gpulock.sh /data/battery/runs/20261015-2326_e25876_rc175-r10-timing/bin/rugnux -o p --no-export-unmerged --model /data/battery/runs/20261015-2326_e25876_rc175-r10-timing/work/open/4nwv/4nwv_moved.cif.gz /ssd/data/open/4nwv/sbgrid9/formal.001`
- Same binary as the clean runs: identical sha256 (4ace4e1f...); at this run the source tree was still at e25876055.
## What stands out
- Every check passed on every platform and run (server and GB10 included) (6 of 6 checks on each of the 3 sets). The MR decisions are the same everywhere: myob and 4nwv AGREES. For cytc the data give P 31 2 1 and MR places the model in P 32 2 1 (ENANTIOMORPH); the Mac report gives the same hand but no MR_DECISION key.
- The steps cover rugnux's whole clock on every platform: on 4nwv the sum of the TIMING steps equals WALL_TIME to 0.1 s. Outside that clock, process launch to exit (elapsed_s) adds 0.5-1.0 s. There is no hidden time between steps.
- On Windows, the first set of a run (myob_x10sa) has 4.0-4.3 s between process launch and exit that rugnux's own clock does not cover; the later sets and every other platform have 0.1-1.0 s. What that time is (process or CUDA start-up before step 1, say) is not recorded.
- Workstation (RTX 5080): 4nwv takes 84 s. Scaling and merging is the biggest step (25 s), then MR (20 s), then integration (10.5 s). The run of 10-15 23:26, said to be on a loaded machine, is within 1% of the clean run. So load did not inflate that particular run, whatever it did to others.
- Workstation (RTX 5080): 4nwv takes 84 s. Scale & merge (P1 merge, symmetry, final merge, analyses) is the largest stage at 28 s. Structure & map follows at 27 s (MR 20 s of it), then post-refine at 8 s and the two per-image passes at 10.5 s together. The run of 10-15 23:26, said to be on a loaded machine, is within 1% of the clean run, and used the identical binary. So load did not inflate that particular run, whatever it did to others.
- Workstation CPU only: 4nwv takes 515 s, 6.2x the GPU run. Structure & map takes 331 s of it (MR 243 s, about 12x the GPU), and the per-image passes 83 s (8x). Scale & merge is only 2x slower (56 s). The two small sets are 7x slower.
- Mac M6 (CPU + Metal integration): 4nwv takes 431 s, 0.84x the workstation's CPU-only time. Its MR runs on the CPU and takes as long as the workstation's CPU-only MR (240 vs 243 s); it is 56% of the Mac's wall time. Metal brings the per-image passes to 55 s (CPU-only workstation: 83 s). Model validation (56 s) and scale & merge (49 s) also beat the 16-core CPU-only run. Caveat: the Mac binary has no -march flags, the workstation's has x86-64-v3.
- Windows laptop (RTX PRO 2000, 8 GB): 4nwv takes 167-206 s, 2.0-2.5x the workstation GPU run. Every stage is slower: per-image passes 27 s (2.6x), scale & merge 40-58 s, structure & map 71-87 s (MR 52-62 s, 2.7-3.1x). Back-to-back runs differ by 23%, spread over the GPU/CPU-heavy stages. The laptop also spends 2.6-5.6 s writing files and 3.3-4.4 s in the geometry-walk probe (0.5 and 0.1 s on the workstation).
- GB10 (DGX Spark, unified memory): 4nwv takes 123 s, 1.47x the RTX 5080 workstation and faster than the laptop (167-206 s). By stage against the workstation: scale & merge is nearly level (29.0 vs 27.9 s), the per-image passes are 1.4x (15.1 vs 10.5 s), and structure & map is 2.3x (61.0 vs 27.1 s; MR alone 2.4x, 46.6 vs 19.7 s). MR is its largest step, 38% of the wall time; per the pack's profile the GPU rotation function alone takes 25.7 s. The small sets lose more: myob 17.1 s and cytc 25.7 s, 1.9x the workstation. Everything ran on the GPU. With a 104.5 GB budget, model validation planned 22.1 GB with 10 rigid-body engines and MR 21.6 GB with 9; the 8 and 16 GB cards ran 1-2.
- Server (4x Xeon Gold 6146, 4x T4; rugnux uses the 24 CPUs of the GPUs' sockets and all four cards): 4nwv takes 248 s. That is 3.0x the RTX 5080 workstation and slower than the 8 GB laptop (167-206 s). The gap is almost all structure & map: 150 s, of which MR is 123 s (6.3x the workstation's 19.7 s, 2.0-2.4x the laptop's) and model validation 26 s (3.5x). Scale & merge (57 s) and post-refine (16 s) are about 2x the workstation. The two per-image passes, spread over four cards, are level with it (11.0 vs 10.5 s). The small sets match GB10: myob 16.9 s and cytc 25.8 s (GB10: 17.1 and 25.7 s), 1.8-2.0x the workstation, with pre-scan and indexing the largest stages. The run started 5 s after a full battery on the same machine ended; the load during it was not recorded.
- Peak host memory for 4nwv: workstation GPU 18.4 GiB RSS, workstation CPU-only 26.8 GiB, Mac 9.1 GiB RSS (~22 GiB physical footprint). The Windows, GB10 and server packs recorded none. The two numbers are not directly comparable: Mac RSS vs footprint, unified memory.
@@ -0,0 +1,244 @@
#!/usr/bin/env python3
"""Cross-platform report of the rugnux timing benchmark (battery.py timing).
python3 -I timing_table.py platforms.json [-o out.md]
platforms.json: {"title", "intro", "timing_json", "stands_out": [str], "platforms": [entry]}.
"timing_json" is a copy of tools/battery/timing.json (path relative to platforms.json), for the data
section. An entry is {"platform" (short name + CPU), "gpu", "role", "conditions", "os", "build",
"battery_cmd", "notes": [str], "peak_mem": {set: str}, "table2_note"} plus ONE source:
"run": a battery run directory (results.json + manifest.json; logs under logs/<set>/ or
work/<arm>/<set>/),
"archive": a .tar.gz/.tar plus "member", the run directory's path inside it; the archive is unpacked
once into unpacked/<archive name>/ next to this script (members with absolute paths, '..'
or links are refused),
"manual": typed in from a report with no run directory: {"sets": {set: {"verdict", "wall",
"mr_decision", "steps": {step: s}}}, "repro": {field: text}}.
Whatever a source does not record is printed as "not recorded". Nothing here judges: the checks are
the benchmark's own (bench_checks in results.json).
"""
import json
import os
import re
import sys
import tarfile
SETS = ["myob_x10sa", "cytc_x10sa", "4nwv"]
HERE = os.path.dirname(os.path.abspath(__file__))
NR = "not recorded"
def unpack(archive, member):
name = re.sub(r"\.tar(\.gz)?$", "", os.path.basename(archive))
dest = os.path.join(HERE, "unpacked", name)
if not os.path.isdir(dest):
os.makedirs(dest)
with tarfile.open(archive) as t:
safe = [m for m in t.getmembers()
if not m.name.startswith("/") and ".." not in m.name.split("/") and (m.isfile() or m.isdir())]
kw = {"filter": "data"} if hasattr(tarfile, "data_filter") else {}
t.extractall(dest, members=safe, **kw)
return os.path.join(dest, member)
def log_dir(run, row):
for d in (os.path.join(run, "logs", row["set"]), os.path.join(run, "work", row.get("arm", ""), row["set"])):
if os.path.isdir(d):
return d
return None
def from_log(d):
"""The binary's own header lines and where the work ran."""
out = {}
log = d and os.path.join(d, "p_log.txt")
if not log or not os.path.exists(log):
return out
text = open(log, errors="replace").read()
for key, pat in (("version", r"\] (rugnux Version [^\n]*)"), ("build_flags", r"\] Build flags: ([^\n]*)"),
("gpu", r"\] GPU: ([^\n]*)"), ("threads", r"\] Threads: (\d+)")):
m = re.search(pat, text)
out[key] = m.group(1).strip() if m else None
out["scaling"] = "GPU" if "RotationScaleMerge: GPU scaling" in text else "CPU"
m = re.search(r"Model validation: structure factors[^\n]*?([\d.]+ GB) held of a ([\d.]+ GB) budget", text)
out["mv"] = f"GPU ({m.group(1)} of a {m.group(2)} budget)" if m else "CPU"
rep = os.path.join(d, "p_report.txt")
if os.path.exists(rep):
for line in open(rep, errors="replace"):
if line.startswith("MR_SEARCH_DEVICE="):
out["mr_dev"] = line.split("=", 1)[1].strip()
return out
def load(p):
"""{set: row}, {repro field: text}"""
if "manual" in p:
return p["manual"]["sets"], dict(p["manual"].get("repro", {}))
run = p["run"] if "run" in p else unpack(p["archive"], p["member"])
man = json.load(open(os.path.join(run, "manifest.json")))
sets = {}
for r in json.load(open(os.path.join(run, "results.json"))):
bad = [k for k, v in (r.get("bench_checks") or {}).items() if not v[0]]
sets[r["set"]] = {"verdict": r.get("bench_verdict") or "-", "failed": bad, "wall": r.get("wall_s"),
"elapsed": r.get("elapsed_s"), "mr_decision": r.get("mr_decision"),
"steps": r.get("steps") or {}, "cmd": r.get("cmd"), **from_log(log_dir(run, r))}
b, o, hw = man.get("binary", {}), man.get("options", {}), man.get("hardware") or {}
first = sets.get("4nwv") or next(iter(sets.values()))
gpus = ", ".join(f"{g.get('name')} (memory {rec(g.get('memory'))})" for g in hw.get("gpus", [])) or None
repro = {
"pack": (f"{os.path.basename(p['archive'])}, {p['member']}" if "archive" in p else "run directory on the machine itself"),
"run directory": p.get("run_name") or os.path.basename(os.path.normpath(run)),
"date/time": f"{man.get('start')} to {man.get('end')} (the machine's local time)",
"host": man.get("host"),
"rugnux (as the binary reports)": first.get("version"),
"build flags (as the binary reports)": first.get("build_flags"),
"build (battery manifest)": f"{b.get('flags')}; CMakeCache {b.get('cmake_cache')}; source HEAD {b.get('source_head')}"
f"{' (tree dirty)' if b.get('source_dirty') else ''}; sha256 {b.get('sha256')}",
"battery runner": f"tools/battery at {man.get('runner_git')}{' (dirty)' if man.get('runner_dirty') else ''}",
"battery options (manifest)": f"label {man.get('label')}, threads {o.get('threads')} (0 = no -N), gpulock "
f"{o.get('gpulock')}, extra args {o.get('extra_args')}, timeout {o.get('timeout')} s",
"threads (rugnux reports)": "/".join(sorted({r.get("threads") or "?" for r in sets.values()})),
"hardware (manifest)": (f"CPU {rec(hw.get('cpu_model'))}, {rec(hw.get('physical_cores'))} cores / {rec(hw.get('threads'))} threads, "
f"{hw.get('memory_gib'):.1f} GiB RAM, GPU {gpus}") if hw else None,
"GPU (rugnux reports)": first.get("gpu"),
}
for s in SETS:
if s in sets:
repro[f"rugnux command, {s}"] = f"`{sets[s]['cmd']}`" if sets[s].get("cmd") else None
return sets, repro
def rec(x):
return NR if x in (None, "unknown", "[N/A]") else x
def stage_table(L, cfg, data, SET, num, title):
groups = [(g["box"], g["steps"]) for g in cfg["step_groups"]]
mapped = {k for _, ks in groups for k in ks}
for _, d, _ in data: # a step no group names keeps a row of its own, so nothing is dropped
for k in d.get(SET, {}).get("steps", {}):
if k not in mapped:
groups.append((f"(not in the figure) {k}", [k]))
mapped.add(k)
extra = cfg.get("step_extra_columns", []) # [label, step]: one step shown again on its own
L += ["", f"## Table {num}: {title}, time per pipeline stage (s)", "",
"rugnux's `TIMING step` lines of " + SET + "'s p_log.txt, grouped into the boxes of the workflow figure "
"(docs/images/rugnux_pipeline.svg); the mapping is " + ("below" if num == 2 else "under Table 2") + ". `-` = none of the stage's steps ran (from "
"the log); `n/r` = a pack without logs reports none of them; `*` = it reports only some of them, so a sum "
"marked `*` is partial. Wall - sum shows whether the steps cover rugnux's own "
"clock (WALL_TIME). Elapsed (the battery's `elapsed_s`, from process launch to exit) minus wall is the time "
"outside rugnux's clock: process start-up before step 1 and the exit after the last step.", ""]
logged = {k for p, d, _ in data if "manual" not in p for k in d.get(SET, {}).get("steps", {})}
hdr = (["Platform", "GPU", "run"] + [g for g, _ in groups] + [lab for lab, _ in extra]
+ ["**sum of steps**", "**wall (WALL_TIME)**", "wall - sum", "elapsed (elapsed_s)", "elapsed - wall"])
L += ["| " + " | ".join(hdr) + " |", "|:--|:--|:--|" + "--:|" * (len(hdr) - 3)]
for p, d, _ in data:
r = d.get(SET, {})
st = r.get("steps", {})
s = sum(st.values()) if st else None
w, e = r.get("wall"), r.get("elapsed")
cells = [p["platform"], p["gpu"], p.get("role", "")]
partial = False
for _, ks in groups:
have = [k for k in ks if k in st]
if "manual" in p: # a typed-in report: a step it does not list (but a log has) is unknown
ks = [k for k in ks if k in logged or k in st]
cells.append("n/r" if not have else f(sum(st[k] for k in have)) + ("*" if len(have) < len(ks) else ""))
partial = partial or len(have) < len(ks)
else: # from the log: a step that is not there did not run
cells.append(f(sum(st[k] for k in have)) if have else "-")
cells += [f(st[k]) if k in st else "n/r" for _, k in extra]
star = "*" if partial else ""
cells += [f(s) + star, f(w), (f"{w - s:+.1f}" + star) if s is not None and w is not None else "-",
f(e) if e else NR, f"{e - w:+.1f}" if e and w else NR]
L.append("| " + " | ".join(cells) + " |")
if num != 2:
L += ["", "Mapping of steps to figure boxes: as under Table 2."]
else:
L += ["", "Figure box <- rugnux steps (what each step covers, from rugnux/*.cpp):", ""]
L += [f"- **{g['box']}** <- {' + '.join(g['steps'])}{': ' + g['why'] if g.get('why') else ''}" for g in cfg["step_groups"]]
L += [f"- {n}" for n in cfg.get("step_notes", [])]
notes = [f"- {p['platform']} ({p['gpu']}): {p['table_notes'][SET]}" for p, _, _ in data if p.get("table_notes", {}).get(SET)]
if notes:
L += [""] + notes
def f(x):
return "-" if x is None else f"{x:.1f}"
def main():
cfg_path = sys.argv[1]
cfg = json.load(open(cfg_path))
out_path = sys.argv[sys.argv.index("-o") + 1] if "-o" in sys.argv else None
data = [(p, *load(p)) for p in cfg["platforms"]]
L = [f"# {cfg['title']}", "", cfg.get("intro", ""), ""]
L += ["## Table 1: wall time (s), timing benchmark", "",
"Wall = rugnux's own WALL_TIME. Checks = the benchmark's six checks on each set (space_group, placed, "
"mr_group, r_free, confirmed, placement_cc); a failing check would be named.", "",
"| Platform | GPU | run | myob_x10sa | cytc_x10sa | 4nwv | checks | MR decision (myob / cytc / 4nwv) |",
"|:--|:--|:--|--:|--:|--:|:--|:--|"]
for p, d, _ in data:
ver = [d[s]["verdict"] + (" (" + ", ".join(d[s]["failed"]) + ")" if d[s].get("failed") else "")
for s in SETS if s in d]
checks = "all pass" if len(ver) == 3 and all(v == "pass" for v in ver) else " / ".join(ver)
L.append(f"| {p['platform']} | {p['gpu']} | {p.get('role', '')} | "
+ " | ".join(f(d.get(s, {}).get("wall")) for s in SETS)
+ f" | {checks} | " + " / ".join(d.get(s, {}).get("mr_decision") or NR for s in SETS) + " |")
for num, s_, title in ((2, "4nwv", "4nwv"), (3, "cytc_x10sa", "cytochrome C (cytc_x10sa)"), (4, "myob_x10sa", "myoglobin (myob_x10sa)")):
stage_table(L, cfg, data, s_, num, title)
L += ["", "Where 4nwv's work ran and peak memory:", "",
"| Platform | GPU | run | scaling | model validation | MR search | peak memory (myob / cytc / 4nwv) |",
"|:--|:--|:--|:--|:--|:--|:--|"]
for p, d, _ in data:
r = d.get("4nwv", {})
dev = [r.get("scaling"), r.get("mv"), r.get("mr_dev")] if r.get("scaling") else p.get("devices", [NR] * 3)
pm = p.get("peak_mem")
L.append(f"| {p['platform']} | {p['gpu']} | {p.get('role', '')} | " + " | ".join(x or NR for x in dev)
+ " | " + (" / ".join(pm.get(s, NR) for s in SETS) if pm else NR) + " |")
tj = json.load(open(os.path.join(os.path.dirname(os.path.abspath(cfg_path)), cfg["timing_json"])))
L += ["", "## Data", "",
f"The three sets of tools/battery/timing.json (copy: `{cfg['timing_json']}` beside this report). Each "
"is started from a model it has to place by molecular replacement:", "",
"| set | arm | start model (--model) | expected: MR group (sgno), R_free max, placement CC min |",
"|:--|:--|:--|:--|"]
for t in tj["sets"]:
st = t["start"]
if "alphafold" in st:
sm = f"`tools/battery/{st['alphafold']}`: {st['why']}"
else:
mv = st["moved"]
sm = (f"deposited {mv['pdb'].upper()} from the site's pdb_cache, strict NCS expanded, turned {mv['deg']} deg "
f"about the unit axis {tuple(mv['axis'])} through the centroid c of the expanded asymmetric unit and "
f"shifted t = {tuple(mv['shift'])} A (x' = R (x - c) + c + t), written as 4nwv_moved.cif.gz")
e = t["expect"]
L.append(f"| {t['set']} | {t['arm']} | {sm} | {e['mr_sgno']}, {e['rfree_max']}, {e['cc_min']} |")
L += ["", "Each platform's input path for each set is in its rugnux commands below."]
L += ["", "## Reproducibility, per platform and run", ""]
order = ["pack", "run directory", "date/time", "host", "OS", "rugnux (as the binary reports)",
"build flags (as the binary reports)", "build (battery manifest)", "compiler / CUDA / arch",
"battery command", "battery runner", "battery options (manifest)", "threads (rugnux reports)",
"hardware (manifest)", "GPU (rugnux reports)", "conditions"] + [f"rugnux command, {s}" for s in SETS]
for p, d, repro in data:
for k, field in (("OS", "os"), ("compiler / CUDA / arch", "build"), ("battery command", "battery_cmd"),
("conditions", "conditions")):
repro.setdefault(k, p.get(field))
L += [f"### {p['platform']} | {p['gpu']} | {p.get('role', '')}", ""]
L += [f"- **{k}**: {repro.get(k) or NR}" for k in order if k in repro]
L += [f"- **{k}**: {v or NR}" for k, v in repro.items() if k not in order]
L += [f"- {n}" for n in p.get("notes", [])] + [""]
if cfg.get("stands_out"):
L += ["## What stands out", ""] + [f"- {x}" for x in cfg["stands_out"]]
text = "\n".join(L) + "\n"
if out_path:
open(out_path, "w").write(text)
print(text)
if __name__ == "__main__":
main()