# Runtime study: existing workloads and separate native scaling

Public reproduction note: archive aliases and `SIMCOMPARE_ROOT` are portable placeholders; use your own archive and checkout locations. Private deployment identifiers are omitted.

Follow-up trajectory validation: `RUNTIME-EQUIVALENCE-2026-09-25.md`.
Genesis and native MJWarp drop agree across batch sizes to numerical precision;
native MJWarp sliding has small positional but larger transient velocity
differences and is not numerically identical. Keep this caveat with scaling plots.

Instance 52582439, RTX PRO 5000 Blackwell (48 GB), driver 595.58.03,
AMD Ryzen 9 9900X host name, 16 visible logical CPUs. This is a new machine:
do not merge older compression timings into its repeat statistics.
Pinned Linux environments restored from the September 24 checkpoint; no engine
updates or physics retuning. Serial workers prevent self-induced GPU contention.
This is a rented/shared host, not a controlled bare-metal benchmark.

## A. Existing single-scene diagnostic harness

`runtime_probe.py` calls the original scenario adapter and wraps its outer
duration/dt loop **in memory**, via a small AST transformation. It does not edit
the production modules or replace solver calls. The transformer requires exactly
one recognized duration loop and records the original function's SHA-256.
`runtime_measure.py` has tests for unchanged loop output, `continue`, and early
termination. An early failure is not ranked as a fast successful run.

Included work: physics stepping, existing control, host/device state and force
readback, validation and in-memory replay-record construction. Excluded from
loop timing: scene setup and output JSON serialization. This is **not pure
solver performance**. Per-step synchronization/readback particularly penalizes
GPU adapters; the number and cost of queries differ by implementation.

Metrics:

- Full loop wall time, including first-use overhead encountered inside the loop.
- Post-first-0.1-s segment: steps/wall-second and simulated-seconds/wall-second
  (real-time factor). GPU synchronization at timing boundaries.
- Whole `run()` call time, including setup/import audits inside that call but
  excluding earlier Python imports. Subprocess time is recorded separately.
- Three independent-process repeats, same seed and scene. Compilation caches
  persist across processes. Median and range, not a statistical confidence interval.

The excluded 0.1 simulated seconds is a **scene phase**, not a universal guarantee
that every kernel/contact branch is compiled. Report both loop and segment
times; do not present the segment as a rigorous steady-state peak benchmark.
All runs are headless with rendering disabled. “Physics steps/s” is not rendered
FPS, replay FPS, or policy/control frequency. At dt=1 ms, 1,000 steps/s = 1× real
time. Deformable routes have different existing timesteps, so compare real-time
factor alongside steps/s and disclose the fidelity/solver differences.

Scenarios:

| Workload | Variant |
| --- | --- |
| Sliding / drop | 0.4 friction, 1 s, dt=1 ms |
| Multi-object collision | Original three-object scene, 1 s, dt=1 ms |
| Hinge | Original effort pulse, 1 s, dt=1 ms |
| Panda motion | Frozen tracking tape, 2.5 s, dt=1 ms |
| Grasp | Original rigid cube, frozen tape, dt=1 ms |
| Stack | 20 mm placement, perturbation 0, frozen tape, 6 s |
| Push | 90 mm channel, layout 0, frozen tape, 5 s |
| Soft compression | Original 1.5 s capability control; existing per-engine dt |

Rigid PhysX runs retain **CPU PhysX** as in the accepted study; soft compression
uses **GPU PhysX**. Do not combine them under an ambiguous “PhysX GPU” label.
Soft native MuJoCo-Warp and standalone VBD are separate routes. This study does
not add timing claims for failed/unstable deformable Panda grasps.

## B. Native primitive batching probe

`runtime_batch_scale.py` measures the same sliding/drop primitive inputs with
no in-loop rendering, controller, force extraction or trace recording. CPU MuJoCo
uses one world. Native MuJoCo-Warp and Genesis use 1, 16 and 128 worlds.
Each case performs a full unmeasured warm-up trial, then resets before each of
three timed full trials. Synchronization brackets whole trials; endpoint states
are read afterwards. Setup and first full-trial warm-up time are retained.

Report both aggregate **world-steps/s** and per-world real-time factor. The former
can increase with batching even as individual-world speed decreases.

Important route differences: this GPU MuJoCo path uses native MJCF/MJWarp,
**not Newton's importer**. Genesis uses native `n_envs`. CPU uses one native
`mj_step`, rather than the split-step/force-recording harness. Consequently this
table must remain separate from A, not be spliced into an engine leaderboard.
No batched PhysX, Newton-importer or coupled VBD performance has been measured
by this probe. Finite endpoint checks are not full trajectory/contact validation.

## Execution and evidence

`setup/runtime_batch.py` / `.conf`: 111 serial harness runs, fresh output paths,
300 s subprocess timeout and result-existence checks (Isaac sometimes exits 0
after an exception). OMP/OpenBLAS/MKL thread limits are 1; no claim that every
engine's internal worker pool obeys these variables.

`setup/runtime_scale_batch.py` / `.conf` waits for the harness completion marker
before starting its GPU jobs; 14 cases with three internal repeats each.
All workers are supervised and not exposed as network services.

Remote evidence: `SIMCOMPARE_ROOT/results/runtime-01/` and
`runtime-scale-01/`. Local backup target: `output/archive-runtime/results/`.
Summary generator: `runtime_report.py ROOT --output NEW.md`. Invalid or missing
results are listed explicitly rather than replaced with zeros or partial speeds.
Completion markers are required before describing the full matrix as finished.
