Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions docs/OFFLOADING_DECISION_EVENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ python scripts/analysis/offloading_decision_summary.py \
The summary includes selected layer, strategy, estimated total milliseconds,
observed total milliseconds, and error milliseconds.

> Note: with segment splitting enabled the base `offloading_decisions.csv` is not
> written. Point the script at a specific segment, or disable splitting for a
> single-file run.
The script reads a whole run via `iter_run_offloading_decisions`, so pointing
it at the base name (e.g. `offloading_decisions.csv`) covers every split
segment for that run, even though the base file itself is never written once
splitting is enabled.
18 changes: 15 additions & 3 deletions scripts/analysis/offloading_decision_summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from server.commons import EvaluationFiles
from server.telemetry.offloading_decisions import (
iter_offloading_decisions,
iter_run_offloading_decisions,
summarize_prediction_error,
)

Expand All @@ -27,7 +27,16 @@


def summarize_file(path: str | Path) -> list[dict]:
return [summarize_prediction_error(event) for event in iter_offloading_decisions(path)]
"""Summarize one run's offloading decisions, across all split segments.

``path`` may point at a single legacy file or at any segment's base name
(e.g. ``offloading_decisions.csv``); ``iter_run_offloading_decisions``
discovers and reads every ``.segNNNN_*`` segment for that run, in order.
"""
return [
summarize_prediction_error(event)
for event in iter_run_offloading_decisions(path)
]


def main(argv: list[str] | None = None) -> int:
Expand All @@ -38,7 +47,10 @@ def main(argv: list[str] | None = None) -> int:
"input",
nargs="?",
default=EvaluationFiles.offloading_decisions_file_path,
help="Path to offloading_decisions.csv or a legacy JSONL file.",
help=(
"Path to offloading_decisions.csv (or a legacy JSONL file). "
"All split segments for the run are read automatically."
),
)
parser.add_argument(
"--output",
Expand Down
21 changes: 21 additions & 0 deletions tests/unit/test_offloading_decision_summary.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,24 @@ def test_offloading_decision_summary_reads_csv(tmp_path):
"error_ms": 5.0,
}
]


def test_offloading_decision_summary_reads_all_split_segments(tmp_path):
base = tmp_path / "offloading_decisions.csv"
for i in range(3):
event = build_offloading_decision_event(
device_id="device-1",
model_dir="model",
request_id=f"REQ{i}",
selected_layer=i,
selection_reason="lowest_estimated_cost",
avg_speed_bytes_per_second=1,
)
append_offloading_decision(base, event, max_rows=1)

# Splitting keeps segments and never writes the base file directly.
assert not base.exists()

rows = summarize_file(base)

assert [row["request_id"] for row in rows] == ["REQ0", "REQ1", "REQ2"]
Loading