k4bench.remote¶
k4bench.remote ¶
Discover and download benchmark run data from a WebEOS HTTP endpoint.
The WebEOS site serves an Apache-style directory listing at K4BENCH_DATA_URL,
laid out as :mod:k4bench.layout defines::
{base_url}/
runs/{suite}/ e.g. runs/sim/
{concept}/ e.g. ALLEGRO/
{detector}/ e.g. ALLEGRO_o1_v03/
{platform}/ e.g. x86_64-el9-gcc16-opt/
{stack}/ e.g. key4hep-2026-05-19/
{sample}/ e.g. single_e-_10GeV/
{YYYY-MM-DD}/ e.g. 2026-05-23/
run_info.json
machine_info.json
{config}_results.csv
{config}_events.json
{config}_regions.json
{config}.log
reports/{suite}/{YYYY-MM-DD}/report.json, blame.json
Every function reading runs takes the suite it reads right after base_url.
A run is downloaded into a local cache either whole (:func:ensure_run_cached)
or file by file, only the files a reader asks for (:func:ensure_run_artifacts).
IncompleteFetch ¶
Bases: RequestException
A read that could not be completed because the server did not answer.
Raised only to callers passing strict=True. By default those functions
skip what they could not read (logged) and return the rest, or None;
:attr:partial is what had been read when the strict call stopped, so a
caller that can use an incomplete result still may — deliberately. The
dashboard caches every result, and one missing items only because WebEOS
stalled must be read again, not remembered as the answer.
A :class:requests.RequestException, so a caller that already falls back
on a failed request falls back on this too, rather than mistaking a partial
listing for a complete one.
Source code in k4bench/remote.py
list_detectors ¶
Return the detector names benchmarked in suite, sorted.
One listing for the suite's concepts, then one per concept. A suite with no
run tree yet (a 404) has no detectors. A concept listing the server does
not answer raises :class:IncompleteFetch carrying the detectors listed so
far: a detector missing from the answer would read as one no longer run.
Source code in k4bench/remote.py
list_platforms ¶
list_samples ¶
Return available physics samples for (detector, platform, stack).
scan_stack_samples ¶
scan_stack_samples(base_url: str, suite: str, detector: str, platform: str, *, strict: bool = False) -> dict[str, list[str]]
Return {stack: [samples]} for (detector, platform), newest stack first.
Single source of truth for both the cross-release sample union and the
per-sample stack list, so the sidebar scans the release tree only once
(one listing per stack) instead of twice. A sample may be added or dropped
between Key4hep releases; callers derive the union and the per-sample stacks
from this map. Stacks whose listing fails are skipped (logged); with
strict, the first that fails without an answer stops the scan and raises
:class:IncompleteFetch carrying what was listed.
Source code in k4bench/remote.py
list_runs ¶
list_runs(base_url: str, suite: str, detector: str, platform: str, stack: str, sample: str) -> list[str]
Return available run dates for a (detector, platform, stack, sample) combination, newest first.
Source code in k4bench/remote.py
list_run_dates_all_stacks ¶
list_run_dates_all_stacks(base_url: str, suite: str, detector: str, platform: str, sample: str, *, strict: bool = False) -> dict[str, list[str]]
Return {stack: [run_dates]} for (detector, platform, sample).
Discovery only — issues directory listings and no file downloads. The
run-date directory names are YYYY-MM-DD, so the full set of available
dates per stack is obtained cheaply; this populates the trend-window control
and lets the caller download only the runs inside the selected window.
Stacks that do not contain sample (a 404) or whose listing fails are
skipped; with strict, the first that fails without an answer stops the
scan and raises :class:IncompleteFetch carrying what was listed.
Source code in k4bench/remote.py
ensure_run_cached ¶
ensure_run_cached(base_url: str, suite: str, detector: str, platform: str, stack: str, sample: str, date: str, cache_root: str | None = None) -> Path
Download one run into a stable cache path and return it.
The cache mirrors the store layout (:mod:k4bench.layout) below cache_root.
Historical runs are immutable, so a run whose .complete sentinel exists is
returned without any HTTP. To stay correct across concurrent reruns and
processes, files are downloaded into a private temp dir and the finished run
is published with a single atomic rename: a reader therefore never sees a
half-written run_dir, and an interrupted download leaves no partial run
behind (the temp dir is discarded) rather than a dir that looks cached.
Source code in k4bench/remote.py
ensure_run_artifacts ¶
ensure_run_artifacts(base_url: str, suite: str, detector: str, platform: str, stack: str, sample: str, date: str, artifacts: Iterable[str], cache_root: str | None = None) -> Path
Download the files of one run that artifacts match, and return the directory holding them.
For a reader that needs only part of a run. artifacts are file names or
patterns over them (:func:k4bench.artifacts.matching), matched against
the run's listing, so a label's file is fetched only where the run has it.
A run :func:ensure_run_cached already holds whole is returned as it is.
Otherwise the files land in the run's directory below :data:SUBSET_TREE,
whose manifest (:data:ARTIFACT_MANIFEST) keeps the run's listing and,
for each listed file asked for, whether it was fetched, is absent, or failed.
A file fetched or known absent costs no request, so asking again for what
is there is free, and asking for more fetches only the rest.
Each file is published with one atomic rename, so a reader never sees
half of one, and the manifest is written under a lock on the directory,
so concurrent callers asking for different files of one run each end with
theirs. Nothing here writes .complete: a run's directory here never
holds all of it by contract, whatever it happens to hold.
A listing that does not answer raises and records nothing. A file that
does not answer raises too, recorded as failed after those fetched before
it; the next call asks for it again. A 404 is an answer: the file is
absent. An unsafe name in the listing raises ValueError and records
nothing, as in :func:ensure_run_cached.
Source code in k4bench/remote.py
fetch_runs_windowed ¶
fetch_runs_windowed(base_url: str, suite: str, detector: str, platform: str, sample: str, stacks_dates: dict[str, list[str]], cache_root: str | None = None, *, strict: bool = False, artifacts: tuple[str, ...] | None = None) -> list[dict]
Fetch every (stack, date) in stacks_dates in parallel, returning a
list of {"stack", "date", "run_dir"} for the runs successfully cached.
Each run is fetched at most once (see :func:ensure_run_cached); callers pass
an already date-windowed stacks_dates so only in-window runs are downloaded.
Given artifacts, only the files of each run they match are
(:func:ensure_run_artifacts), and a run counts as cached once those are.
Runs that fail to download are logged and skipped rather than aborting the load.
With strict, no download starts after the first failure that makes the
result incomplete, and the call raises once those in flight have finished —
so every run that landed stays in the on-disk cache and a retry fetches
only what is missing. A run the server did not answer for raises
:class:IncompleteFetch carrying the runs that landed; a local error — the
cache directory full or unwritable — raises that OSError itself, since
it is neither EOS's fault nor fixed by asking EOS again. A run whose listing
names an unsafe file is skipped either way: it will be just as unsafe next
time.
At most :data:_POOL_MAXSIZE downloads run at once — the connection
pool's own ceiling (see :func:_get_session). More workers would add no
throughput, only threads blocked waiting for a connection, and a blocked
worker's download already counts as started: it could no longer be
cancelled, and would run into the same failing server once a connection
freed up. Work beyond the ceiling therefore waits in the executor's queue,
where cancelling it stops it.
Source code in k4bench/remote.py
540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 | |
list_stacks ¶
Return the Key4hep releases benchmarked for (detector, platform), newest first.
Directory names as stored (key4hep-{YYYY-MM-DD}). Discovery only — one
listing, no downloads.
Source code in k4bench/remote.py
fetch_stack_packages ¶
fetch_stack_packages(base_url: str, suite: str, detector: str, platform: str, stack: str, *, strict: bool = False) -> dict | None
Return the k4h_packages map of a release, or None.
Every detector benchmarked against a given release sourced the same
stack, so any one run under it answers the question — this walks to the
first run it finds and reads only that run_info.json (two listings and
one small GET), rather than downloading a run directory.
None covers both "no run found" and "that run predates provenance
capture": in either case the release's packages are unknown, which a caller
must not confuse with an empty stack. With strict, the first read the
server does not answer stops the walk and raises :class:IncompleteFetch
instead: the None it would otherwise end in might not be the answer.
Source code in k4bench/remote.py
fetch_stack_snapshot ¶
fetch_stack_snapshot(base_url: str, suite: str, detector: str, platform: str, stack: str, sample: str | None, *, strict: bool = False)
Latest available run's stack for one scope, skipping partial uploads.
Only captured runs need the two compressed manifests and machine snapshot. A complete newest run costs one listing and four GETs. Other detectors cannot stand in for this scope's measured loaded set.
Source code in k4bench/remote.py
fetch_run_provenance ¶
fetch_run_provenance(base_url: str, suite: str, detector: str, platform: str, stack: str, sample: str, run_id: str)
Only the small, run-specific loaded facts needed by blame (two GETs).
Source code in k4bench/remote.py
fetch_run_info ¶
fetch_run_info(base_url: str, suite: str, detector: str, platform: str, stack: str, sample: str, run_id: str) -> dict | None
Return one exact run's parsed run_info.json, or None.
There is deliberately no directory walk or same-release shortcut: manual dispatches and partial re-runs can leave neighbouring run directories with different workloads and harness commits.
Source code in k4bench/remote.py
fetch_run_commit ¶
fetch_run_commit(base_url: str, suite: str, detector: str, platform: str, stack: str, sample: str, run_id: str) -> tuple[str, str | None] | None
Return k4Bench's own (commit_sha, github_run_url) at one exact run,
or None.
The run-keyed sibling of :func:fetch_stack_packages, for the one
provenance field that varies per run rather than per release: the commit of
the harness that produced the run. Unlike the release-keyed read there is
no walk and no "any run answers" shortcut — a same-day manual dispatch or
partial re-run can leave sibling groups carrying different commits, so only
the named run's own run_info.json is read (one small GET).
None covers "no such run" and "that run predates the field" — the
harness's position is unknown either way.
Source code in k4bench/remote.py
list_report_dates ¶
Return suite's nightly regression-report dates (newest first).
Reports live at {base_url}/reports/{suite}/{YYYY-MM-DD}/report.json,
written by the nightly regression-report CI job. An absent report tree
(a 404: no report generated yet) is not an error — it returns an empty
list. Any other failure raises: a listing the server did not answer says
nothing about whether reports exist, and must not read as "none yet".
Source code in k4bench/remote.py
fetch_report ¶
Fetch and parse one of suite's nightly regression reports, or None
on failure.
With strict, a transient failure raises :class:IncompleteFetch instead
of returning None.
Source code in k4bench/remote.py
fetch_blame ¶
Fetch and parse one night's blame sidecar, or None when absent.
Blame lives beside the report at reports/{suite}/{date}/blame.json, written
best-effort by the nightly regression-report job only on nights with a
confirmed regression it could attribute — so most nights have none, and a
404 here is the common case, not an error (logged at debug, returns None).
Uses the same shared, connection-pooled session as every other WebEOS read
(see :func:_get_session) rather than a bare requests.get, so it shares
the one real concurrency ceiling instead of opening its own connections.
With strict, a transient failure raises :class:IncompleteFetch instead
of returning None.