Performance regression checks
TABASCAL’s runtime and memory use are guarded by
ReFrame checks in
ci/reframe/tabascal_perf_check.py.
The checks themselves are system-generic — they declare a generic:default
partition and run anywhere ReFrame does, a dev machine included (see Running
the checks directly); it is the reference
values that belong to a node type. In this project’s CI they run on, and their
references were measured on, the CSCS Daint GH200 partition defined in
ci/cscs.yml.
They complement the pipeline tests: the pipeline tests catch a change in what TABASCAL infers, these catch a change in how long it takes.
What is checked
Two test classes, each parameterised over variant (Riemann, RiemannFFI)
and precision (single, double):
TabascalPerfCheck— single GPU.TabascalMultiGpuPerfCheck— every GPU on the node. It unsets theCUDA_VISIBLE_DEVICES=0default that the rest of the pipeline pins, so it exercises the sharded solve.
The metrics compared against references are total_runtime,
optimizer_runtime and memory_usage. Metrics without a reference entry are
reported but not asserted.
The Riemann references describe a deliberate trade rather than a target: that
component bounds its peak memory by scanning the baseline axis and recomputing
each block in the backward pass (see
baseline_block_size), which on the GH200 references
above is roughly an order of magnitude less memory for an optimiser step 1.2 to
1.7 times longer. A run that comes out faster and hungrier than these numbers has
probably lost the scan, not gained a speed-up.
References are keyed by (variant, precision) and are only meaningful on the
node type they were measured on. Sanity therefore requires the run to have used
exactly the expected number of GPUs of exactly the expected kind (GH200) —
anything else fails rather than being silently compared against timings it
cannot be compared against. That gate is on the comparison, not on running the
checks: elsewhere, run them with -S strict_check=0 (below) to get the metrics
reported without being asserted.
Reproducing a regression locally
When CI reports a regression, reproduce it on a smaller dataset with 8 antennas. This is fast enough to simulate and run on any dev machine, so you do not need GH200 access to bisect the cause:
# Generate an 8-antenna simulation from the standard 96A config
sim-vis -c ci/reframe/data/sim_target_96A.yaml -a 8
# Run tabascal with timing output against the generated dataset
tabascal run -c ci/reframe/data/tab_target.yaml -od ci/reframe/data/data/pnt_src_obs_08A_090T-0000-0890_001I_001F-1.500e+08-1.500e+08_050PAST_000GAST_000EAST_32SAT_0GRD_1.0e+00RFI -t
The -t flag prints a per-function timing table identical to the CI output.
The absolute numbers from an 8-antenna run on a laptop are not comparable to the GH200 references — use it to find which function got slower, then confirm the magnitude on the real configuration.
Running the checks directly
With the dev environment installed (see Developer install),
ReFrame is available as reframe:
reframe -C ci/reframe/settings.py \
-c ci/reframe/tabascal_perf_check.py \
--system=generic:default \
--exec-policy=serial \
--run --performance-report
Add -S strict_check=0 to report the metrics without failing on the reference
comparison, which is what the nightly cron job does.
Updating the references
A reference change and a regression look identical in the diff, so treat the references the same way as the pipeline test references: when a change intentionally alters performance, re-measure rather than widening the tolerances, and record in the commit message why the numbers moved, with the before/after values.
The comments in tabascal_perf_check.py are part of that record. For example
the current values note that #103 replaced the real-space
rfi_signal:ComplexRFI with the scanned Fourier ComplexRFIVarAnt, a
deliberate accuracy-for-runtime trade (see issue #107) that made the optimiser
slower where the RFI-signal component dominates the step and slightly faster
where RFI-vis does. Those older, faster numbers describe a component that no
longer exists and must not be “restored”.
Benchmark history
The nightly cron run converts the ReFrame report with
ci/reframe/reframe_to_bmf.py
and uploads it to bencher.dev under the tabascal
project, testbed cscs-daint-gh200. The gpu_mode variable keeps the
single- and multi-GPU series apart: anything other than single is appended to
the benchmark name, so the existing single-GPU series keep their historical
names.