Skip to content

k4bench.regression.regions

k4bench.regression.regions

Where inside the detector a timing step landed.

A confirmed run-level regression is one number, and one number names no mechanism: "ALLEGRO got 21% slower" and "the HCAL barrel got fourteen times slower while everything else stood still" are the same measurement, but only the second can be matched against a diff. The k4BenchRegionTimingAction plugin records per-event time per top-level detector region on every run, so the second form is already measured — it has simply never been read by anything that attributes a regression.

This module reads it: for one benchmark configuration and one change window, how each region's per-event time differs between the two releases the change entered between. It judges nothing (the engine has already decided that the metric stepped) and it introduces no thresholds of its own; it reports the decomposition, largest movement first, and leaves the reading to whoever asked.

Two costs shape the implementation. Region files are per configuration and hold per-event arrays, so loading a whole trend window across every label is expensive — this loads exactly the two releases of one window, for one label, and only when something actually regressed there. And a release that recorded no region file is absent, never zero: a region that appears on one side of a window only is a real event (a detector added, removed or renamed) and must stay distinguishable from one that stood still.

region_deltas

region_deltas(run_dirs: Sequence[str], *, label: str, base_release: str, onset_release: str, limit: int = MAX_REGIONS) -> tuple[RegionDelta, ...]

How each region's per-event time moved across (base, onset], largest movement first.

Returns () when either end recorded no region timing at all — with only one side measured there is no comparison to make, and inventing one (treating the missing side as zero) would report every region of the detector as newly appearing.

Source code in k4bench/regression/regions.py
def region_deltas(
    run_dirs: Sequence[str],
    *,
    label: str,
    base_release: str,
    onset_release: str,
    limit: int = MAX_REGIONS,
) -> tuple[RegionDelta, ...]:
    """How each region's per-event time moved across ``(base, onset]``, largest
    movement first.

    Returns ``()`` when either end recorded no region timing at all — with only
    one side measured there is no comparison to make, and inventing one (treating
    the missing side as zero) would report every region of the detector as newly
    appearing.
    """
    grouped = _dirs_by_release(run_dirs)
    base_dirs, onset_dirs = grouped.get(base_release, []), grouped.get(onset_release, [])
    if not base_dirs or not onset_dirs:
        return ()

    base = _release_medians(base_dirs, label)
    onset = _release_medians(onset_dirs, label)
    if not base or not onset:
        return ()

    deltas = []
    for region in sorted(set(base) | set(onset)):
        before, after = base.get(region), onset.get(region)
        # A region present on one side only genuinely appeared or disappeared;
        # its whole time is the movement, and saying so is the point.
        delta = (after or 0.0) - (before or 0.0)
        if not math.isfinite(delta):
            continue
        deltas.append(RegionDelta(region=region, base=before, onset=after, delta=delta))
    deltas.sort(key=lambda d: (-abs(d.delta), d.region))
    return tuple(deltas[:limit])