Skip to content

Commit 8b01dfb

Browse files
committed
test summary update
1 parent 8559829 commit 8b01dfb

14 files changed

Lines changed: 230 additions & 47 deletions

tests/integration/conftest.py

Lines changed: 92 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,10 @@
4242

4343
@dataclass
4444
class TimingRecord:
45+
task: str
46+
model: str
4547
entry_point: str
48+
device: str
4649
scenario: str
4750
run: int
4851
duration: float
@@ -60,8 +63,48 @@ def add(
6063
run: int,
6164
duration: float,
6265
output_dir: str = "",
66+
*,
67+
task: str | None = None,
68+
model: str | None = None,
69+
device: str | None = None,
6370
) -> None:
64-
self.records.append(TimingRecord(entry_point, scenario, run, duration, output_dir))
71+
resolved_task, resolved_entry_point = _normalise_task_entrypoint(task, entry_point)
72+
self.records.append(
73+
TimingRecord(
74+
task=resolved_task,
75+
model=model or scenario,
76+
entry_point=resolved_entry_point,
77+
device=device or _default_device_for_task(resolved_task),
78+
scenario=scenario,
79+
run=run,
80+
duration=duration,
81+
output_dir=output_dir,
82+
)
83+
)
84+
85+
86+
def _normalise_task_entrypoint(task: str | None, entry_point: str) -> tuple[str, str]:
87+
if task:
88+
return task, entry_point
89+
if entry_point.startswith("Scale "):
90+
return "Scale Observation", entry_point.removeprefix("Scale ")
91+
if entry_point.startswith("Stereo "):
92+
return "Stereo Depth", entry_point.removeprefix("Stereo ")
93+
return "Unknown", entry_point
94+
95+
96+
def _default_device_for_task(task: str) -> str:
97+
if task == "Scale Observation":
98+
return "CPU"
99+
try:
100+
import torch
101+
except ImportError:
102+
return "CPU"
103+
if torch.cuda.is_available():
104+
return "CUDA"
105+
if hasattr(torch.backends, "mps") and torch.backends.mps.is_available():
106+
return "MPS"
107+
return "CPU"
65108

66109

67110
# Module-level singleton — pytest_terminal_summary reads from it after the session
@@ -315,12 +358,14 @@ def pytest_terminal_summary(terminalreporter, exitstatus, config): # noqa: ARG0
315358
if not records:
316359
return
317360

318-
W = 82
319-
EP = 10 # entry-point col width
320-
SC = 16 # scenario col width
321-
RN = 4 # run col width
322-
DU = 10 # duration col width
323-
ST = 20 # status col width
361+
W = 120
362+
TASK = 28
363+
MODEL = 16
364+
EP = 10
365+
DEV = 7
366+
COLD = 17
367+
WARM = 17
368+
FPS = 13
324369

325370
def _write(line: str = "") -> None:
326371
terminalreporter.write_line(line)
@@ -329,52 +374,67 @@ def _thick() -> None:
329374
_write("━" * W)
330375

331376
def _thin() -> None:
332-
_write(f" {'─' * EP}─┼─{'─' * SC}─┼─{'─' * RN}─┼─{'─' * (DU)}─┼─{'─' * ST}")
377+
_write(
378+
f" {'─' * TASK}─┼─{'─' * MODEL}─┼─{'─' * EP}─┼─{'─' * DEV}─┼─"
379+
f"{'─' * COLD}─┼─{'─' * WARM}─┼─{'─' * FPS}"
380+
)
333381

334-
def _row(ep="", sc="", run="", dur="", status="") -> None:
335-
_write(f" {ep:<{EP}}{sc:<{SC}}{run:^{RN}}{dur:>{DU}}{status}")
382+
def _row(task="", model="", entrypoint="", device="", cold="", warm="", fps="") -> None:
383+
_write(
384+
f" {task:<{TASK}}{model:<{MODEL}}{entrypoint:<{EP}}{device:<{DEV}} │ "
385+
f"{cold:>{COLD}}{warm:>{WARM}}{fps:>{FPS}}"
386+
)
336387

337388
_write()
338389
_thick()
339390
_write(f" {'VIZION3D · INTEGRATION INFERENCE TIMING REPORT':^{W - 4}}")
340391
_thick()
341392
_write()
342-
_row("Entry Point", "Scenario", "Run", "Duration", "Status")
393+
_row(
394+
"Task",
395+
"Model",
396+
"Entrypoint",
397+
"Device",
398+
"Cold run duration",
399+
"Warm run duration",
400+
"Estimated FPS",
401+
)
343402
_thin()
344403

345404
def sort_key(r):
346-
return (r.entry_point, r.scenario, r.run)
405+
return (r.task, r.model, r.entry_point, r.device, r.run)
347406

348407
def group_key(r):
349-
return (r.entry_point, r.scenario)
408+
return (r.task, r.model, r.entry_point, r.device)
350409

351410
first_loads: list[float] = []
352411
warm_times: list[float] = []
353412

354413
sorted_records = sorted(records, key=sort_key)
355414
groups = [(k, list(v)) for k, v in groupby(sorted_records, key=group_key)]
356415

357-
for g_idx, ((ep, sc), recs) in enumerate(groups):
416+
for g_idx, ((task, model, entrypoint, device), recs) in enumerate(groups):
417+
recs = sorted(recs, key=lambda r: r.run)
418+
cold_runs = [r.duration for r in recs if r.run == 1]
419+
warm_runs = [r.duration for r in recs if r.run != 1]
420+
cold = min(cold_runs) if cold_runs else recs[0].duration
421+
warm = sum(warm_runs) / len(warm_runs) if warm_runs else 0.0
422+
fps = 1.0 / warm if warm > 0 else 0.0
423+
first_loads.append(cold)
424+
if warm_runs:
425+
warm_times.extend(warm_runs)
426+
358427
if g_idx > 0:
359428
_thin()
360-
361-
recs = sorted(recs, key=lambda r: r.run)
362-
first_dur = recs[0].duration
363-
364-
for i, rec in enumerate(recs):
365-
ep_label = ep if i == 0 else ""
366-
sc_label = sc if i == 0 else ""
367-
dur_str = f"{rec.duration:7.3f}s"
368-
369-
if rec.run == 1:
370-
status = "◉ COLD LOAD"
371-
first_loads.append(rec.duration)
372-
else:
373-
pct = (1.0 - rec.duration / first_dur) * 100.0
374-
status = f"⚡ {pct:4.1f}% faster"
375-
warm_times.append(rec.duration)
376-
377-
_row(ep_label, sc_label, str(rec.run), dur_str, status)
429+
_row(
430+
task,
431+
model,
432+
entrypoint,
433+
device,
434+
f"{cold:.3f}s",
435+
f"{warm:.3f}s" if warm_runs else "n/a",
436+
f"{fps:.2f}" if warm_runs else "n/a",
437+
)
378438

379439
_write()
380440
_thick()

tests/integration/test_depth_estimation_direct.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,15 @@ def _run_group(
8686
timings.append(elapsed)
8787

8888
_save_outputs(result, run_dir, run)
89-
timing_collector.add(entry_point, scenario, run, elapsed, str(run_dir))
89+
timing_collector.add(
90+
entry_point,
91+
scenario,
92+
run,
93+
elapsed,
94+
str(run_dir),
95+
task="Depth Estimation",
96+
model=scenario,
97+
)
9098

9199
# ── per-run assertions ────────────────────────────────────────────────
92100
assert isinstance(result.depth_map, list) and len(result.depth_map) > 0

tests/integration/test_depth_estimation_grpc.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,15 @@ def _run_group(
7676
timings.append(elapsed)
7777

7878
_save_outputs(response, run_dir, run)
79-
timing_collector.add("gRPC", scenario, run, elapsed, str(run_dir))
79+
timing_collector.add(
80+
"gRPC",
81+
scenario,
82+
run,
83+
elapsed,
84+
str(run_dir),
85+
task="Depth Estimation",
86+
model=scenario,
87+
)
8088

8189
# ── per-run assertions ────────────────────────────────────────────────
8290
assert len(response.depth_map) > 0, "depth_map rows are missing"

tests/integration/test_depth_estimation_rest.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,15 @@ def _run_group(
8181

8282
data = response.json()
8383
_save_outputs(data, run_dir, run)
84-
timing_collector.add("REST", scenario, run, elapsed, str(run_dir))
84+
timing_collector.add(
85+
"REST",
86+
scenario,
87+
run,
88+
elapsed,
89+
str(run_dir),
90+
task="Depth Estimation",
91+
model=scenario,
92+
)
8593

8694
# ── per-run assertions ────────────────────────────────────────────────
8795
assert isinstance(data["depth_map"], list) and len(data["depth_map"]) > 0

tests/integration/test_object_mask_annotation_3d_direct.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,15 @@ def _run_group(
9191
elapsed = time.perf_counter() - t0
9292
timings.append(elapsed)
9393
_save_outputs(result, run_dir, run)
94-
timing_collector.add(entry_point, scenario, run, elapsed, str(run_dir))
94+
timing_collector.add(
95+
entry_point,
96+
scenario,
97+
run,
98+
elapsed,
99+
str(run_dir),
100+
task="Object Mask Annotation 3D",
101+
model=scenario,
102+
)
95103

96104
assert isinstance(result.annotations, list)
97105
assert isinstance(result.backend_used, str) and result.backend_used

tests/integration/test_object_mask_annotation_3d_grpc.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,15 @@ def test_grpc_basic_annotation(
5959
response = grpc_client_stub.RunObjectMaskAnnotation3D(request)
6060
elapsed = time.perf_counter() - t0
6161
timings.append(elapsed)
62-
timing_collector.add("gRPC", "Default model", run, elapsed, str(tmp_path))
62+
timing_collector.add(
63+
"gRPC",
64+
"Default model",
65+
run,
66+
elapsed,
67+
str(tmp_path),
68+
task="Object Mask Annotation 3D",
69+
model="Default model",
70+
)
6371

6472
assert isinstance(response.backend_used, str) and response.backend_used
6573
for item in response.annotations:

tests/integration/test_object_mask_annotation_3d_rest.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,15 @@ def _run_group(
8888
assert response.status_code == 200, response.text[:300]
8989
data = response.json()
9090
_save_outputs(data, run_dir, run)
91-
timing_collector.add("REST", scenario, run, elapsed, str(run_dir))
91+
timing_collector.add(
92+
"REST",
93+
scenario,
94+
run,
95+
elapsed,
96+
str(run_dir),
97+
task="Object Mask Annotation 3D",
98+
model=scenario,
99+
)
92100

93101
assert "annotations" in data and "backend_used" in data
94102
for ann in data["annotations"]:

tests/integration/test_scale_observation.py

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,16 @@ def test_scale_observation_direct_outputs_params_advanced_config_and_timing(
191191
)
192192
elapsed = time.perf_counter() - t0
193193
timings.append(elapsed)
194-
timing_collector.add("Scale Direct", "Indoor asset", run, elapsed, str(run_dir))
194+
timing_collector.add(
195+
"Direct",
196+
"Indoor asset",
197+
run,
198+
elapsed,
199+
str(run_dir),
200+
task="Scale Observation",
201+
model="V4.1",
202+
device="CPU",
203+
)
195204
_save_direct_outputs(result, run_dir, run)
196205

197206
_assert_scale_output(result)
@@ -244,7 +253,16 @@ def test_scale_observation_rest_outputs_params_advanced_config_and_timing(
244253
)
245254
elapsed = time.perf_counter() - t0
246255
timings.append(elapsed)
247-
timing_collector.add("Scale REST", "Indoor asset", run, elapsed, str(run_dir))
256+
timing_collector.add(
257+
"REST",
258+
"Indoor asset",
259+
run,
260+
elapsed,
261+
str(run_dir),
262+
task="Scale Observation",
263+
model="V4.1",
264+
device="CPU",
265+
)
248266

249267
assert response.status_code == 200, response.text[:300]
250268
data = response.json()
@@ -303,7 +321,16 @@ def test_scale_observation_grpc_outputs_params_advanced_config_and_timing(
303321
response = grpc_client_stub.RunScaleObservation(request)
304322
elapsed = time.perf_counter() - t0
305323
timings.append(elapsed)
306-
timing_collector.add("Scale gRPC", "Indoor asset", run, elapsed, str(run_dir))
324+
timing_collector.add(
325+
"gRPC",
326+
"Indoor asset",
327+
run,
328+
elapsed,
329+
str(run_dir),
330+
task="Scale Observation",
331+
model="V4.1",
332+
device="CPU",
333+
)
307334

308335
Path(run_dir / f"run_{run:02d}.json").write_text(
309336
json.dumps(

tests/integration/test_scene_mask_annotation_3d_direct.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,15 @@ def test_direct_default_model(
8686
elapsed = time.perf_counter() - t0
8787
timings.append(elapsed)
8888
_save_outputs(result, run_dir, run)
89-
timing_collector.add("Direct", "Scene default", run, elapsed, str(run_dir))
89+
timing_collector.add(
90+
"Direct",
91+
"Scene default",
92+
run,
93+
elapsed,
94+
str(run_dir),
95+
task="Scene Mask Annotation 3D",
96+
model="SegFormer-B4 ADE20K",
97+
)
9098

9199
assert isinstance(result.annotations, list)
92100
assert len(result.annotations) >= 1

tests/integration/test_scene_mask_annotation_3d_grpc.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,15 @@ def test_grpc_basic_scene_annotation(
5959
response = grpc_client_stub.RunSceneMaskAnnotation3D(request)
6060
elapsed = time.perf_counter() - t0
6161
timings.append(elapsed)
62-
timing_collector.add("gRPC", "Scene default", run, elapsed, str(tmp_path))
62+
timing_collector.add(
63+
"gRPC",
64+
"Scene default",
65+
run,
66+
elapsed,
67+
str(tmp_path),
68+
task="Scene Mask Annotation 3D",
69+
model="SegFormer-B4 ADE20K",
70+
)
6371

6472
assert isinstance(response.backend_used, str) and response.backend_used
6573
assert len(response.annotations) >= 1

0 commit comments

Comments
 (0)