Incremental summary: flush summary.csv/xlsx after every benchmark
Previously both were written only after ALL benches finished -- a multi-hour mmlu_pro left the summary stale for hours, and a crashed run left the PREVIOUS run's files in place. Now each completed bench (including failed ones) rewrites the summaries with everything so far. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
0d925fc46f
commit
97c4eef8fb
@ -621,6 +621,54 @@ def _cmd_eval_run(args) -> int:
|
||||
|
||||
rows = []
|
||||
all_reports = []
|
||||
|
||||
def _flush_summaries():
|
||||
"""Rewrite summary.csv/xlsx from the benches finished SO FAR.
|
||||
|
||||
Called after every benchmark instead of only at the very end:
|
||||
multi-hour runs (mmlu_pro 12k samples) leave the summary stale for
|
||||
hours otherwise -- and a crashed run would leave the LAST run's
|
||||
corpses in place instead of partial results."""
|
||||
if not out_dir:
|
||||
return
|
||||
if all_reports:
|
||||
try:
|
||||
from evalharness.viz import render as _render
|
||||
|
||||
_render(all_reports, style='excel', out=f'{out_dir}/summary.xlsx')
|
||||
except Exception as e:
|
||||
print(f'excel export skipped: {type(e).__name__}: {str(e)[:80]}',
|
||||
file=sys.stderr)
|
||||
if not rows:
|
||||
return
|
||||
import csv as _csv
|
||||
|
||||
with open(f'{out_dir}/summary.csv', 'w', newline='', encoding='utf-8') as f:
|
||||
w = _csv.writer(f)
|
||||
w.writerow(['benchmark', 'score', 'metric', 'num_samples',
|
||||
'time_h', 'time_s', 'extract_fail',
|
||||
'success_rate', 'latency_mean_s', 'output_tps', 'request_qps',
|
||||
'input_tokens_mean', 'output_tokens_mean', 'total_tokens',
|
||||
'ttft_mean_s', 'ttft_p90_s', 'ttft_p99_s',
|
||||
'tpot_mean_s', 'tpot_p90_s', 'tpot_p99_s',
|
||||
'categories'])
|
||||
for r in rows:
|
||||
perf = (r.get('groups') or {}).get('perf') or {}
|
||||
cats = '; '.join(f'{g}={_f3(v)}'
|
||||
for gname, gv in (r.get('groups') or {}).items()
|
||||
if gname != 'perf'
|
||||
for g, v in (gv or {}).items()
|
||||
if isinstance(v, (int, float)))[:2000]
|
||||
w.writerow([r['name'], _f3(r.get('value')), r['metric'], r.get('n', ''),
|
||||
r.get('hours', ''), r.get('secs', ''),
|
||||
r.get('extract_fail', 0)] +
|
||||
[perf.get(k, '') for k in (
|
||||
'success_rate', 'latency_mean_s', 'output_tps', 'request_qps',
|
||||
'input_tokens_mean', 'output_tokens_mean', 'total_tokens',
|
||||
'ttft_mean_s', 'ttft_p90_s', 'ttft_p99_s',
|
||||
'tpot_mean_s', 'tpot_p90_s', 'tpot_p99_s')] +
|
||||
[cats])
|
||||
|
||||
run_started = _time.time()
|
||||
total_runs = len(args.datasets)
|
||||
model_spec = _compose_model_spec(args)
|
||||
@ -908,49 +956,17 @@ def _cmd_eval_run(args) -> int:
|
||||
border_style='red', expand=False), justify='center')
|
||||
_print_benchmark_result(console, i + 1, total_runs, name,
|
||||
'failed', _time.time() - t0)
|
||||
# incremental summary: partial results are visible (and survive a
|
||||
# crash) after EVERY benchmark, not only when the whole run ends
|
||||
_flush_summaries()
|
||||
|
||||
if _shared_reporter is not None:
|
||||
_shared_reporter.close()
|
||||
if all_reports and out_dir:
|
||||
try:
|
||||
from evalharness.viz import render as _render
|
||||
|
||||
xb = _render(all_reports, style='excel',
|
||||
out=f'{out_dir}/summary.xlsx')
|
||||
print(f'excel -> {xb}', flush=True)
|
||||
except Exception as e:
|
||||
print(f'excel export skipped: {type(e).__name__}: {str(e)[:80]}',
|
||||
file=sys.stderr)
|
||||
_flush_summaries() # final state (benches already flushed per-bench)
|
||||
print(f'excel -> {out_dir}/summary.xlsx', flush=True)
|
||||
if rows:
|
||||
_print_summary_table(console, rows)
|
||||
if out_dir:
|
||||
import csv as _csv
|
||||
|
||||
with open(f'{out_dir}/summary.csv', 'w', newline='', encoding='utf-8') as f:
|
||||
w = _csv.writer(f)
|
||||
w.writerow(['benchmark', 'score', 'metric', 'num_samples',
|
||||
'time_h', 'time_s', 'extract_fail',
|
||||
'success_rate', 'latency_mean_s', 'output_tps', 'request_qps',
|
||||
'input_tokens_mean', 'output_tokens_mean', 'total_tokens',
|
||||
'ttft_mean_s', 'ttft_p90_s', 'ttft_p99_s',
|
||||
'tpot_mean_s', 'tpot_p90_s', 'tpot_p99_s',
|
||||
'categories'])
|
||||
for r in rows:
|
||||
perf = (r.get('groups') or {}).get('perf') or {}
|
||||
cats = '; '.join(f'{g}={_f3(v)}'
|
||||
for gname, gv in (r.get('groups') or {}).items()
|
||||
if gname != 'perf'
|
||||
for g, v in (gv or {}).items()
|
||||
if isinstance(v, (int, float)))[:2000]
|
||||
w.writerow([r['name'], _f3(r.get('value')), r['metric'], r.get('n', ''),
|
||||
r.get('hours', ''), r.get('secs', ''),
|
||||
r.get('extract_fail', 0)] +
|
||||
[perf.get(k, '') for k in (
|
||||
'success_rate', 'latency_mean_s', 'output_tps', 'request_qps',
|
||||
'input_tokens_mean', 'output_tokens_mean', 'total_tokens',
|
||||
'ttft_mean_s', 'ttft_p90_s', 'ttft_p99_s',
|
||||
'tpot_mean_s', 'tpot_p90_s', 'tpot_p99_s')] +
|
||||
[cats])
|
||||
|
||||
# artifacts notice: tell the user where everything landed (or how to save);
|
||||
# rich terminals get clickable file:// links (iTerm2/kitty/WezTerm/WT...)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user