- Rewrite myread.md with proper markdown and four download sources: code, data, evalscope-complete-py312 image, execution images. - Add bash/collect_results.py, perf_backup.py, pull_swe_bench_images.py for result aggregation, breakpoint perf recovery, and SWE-bench image pre-pulling. - Update bash/run.py with multi-run suites, perf backup/restore, and whitelist-based summary. - Update config/dpv4-int8_nothinking.yaml benchmark parameters. - Ignore /docker_images and /results in .gitignore.
180 lines
7.7 KiB
Python
180 lines
7.7 KiB
Python
#!/usr/bin/env python3
|
|
"""End-to-end offline test for bash/run.py + collect_results + perf_backup.
|
|
|
|
This script does NOT call any model API. It uses an existing benchmark
|
|
directory (aime24/seed_42) and walks through every code path that the real
|
|
``run.py`` would touch:
|
|
|
|
1. backup_perf_stats — confirm a perf summary snapshot is written
|
|
2. archive_predictions — confirm per-sample records are deduplicated into
|
|
the archive
|
|
3. restore_from_backup — confirm a fresh work_dir can be rehydrated from
|
|
the backup files
|
|
4. collect_results aggregation — confirm correct metrics are produced
|
|
5. Whitelist mode — confirm only the requested benchmarks appear in the
|
|
summary
|
|
6. hle_low alias — confirm hle_low directory maps to canonical "hle"
|
|
7. Reset recovery — confirm that even after wiping the predictions file
|
|
and the report summary, the archive+backup still recover the metrics
|
|
|
|
Run from the project root:
|
|
|
|
python bash/test_e2e.py
|
|
"""
|
|
|
|
import json
|
|
import shutil
|
|
import sys
|
|
import tempfile
|
|
from pathlib import Path
|
|
|
|
sys.path.insert(0, str(Path(__file__).parent))
|
|
|
|
import collect_results as cr # noqa: E402
|
|
import perf_backup as pb # noqa: E402
|
|
|
|
|
|
PROJECT_ROOT = Path('/data1/sora/evalscope')
|
|
SOURCE_OUTPUT = PROJECT_ROOT / 'output'
|
|
|
|
|
|
def banner(msg):
|
|
print('\n' + '=' * 60)
|
|
print(f' {msg}')
|
|
print('=' * 60)
|
|
|
|
|
|
def assert_close(actual, expected, name, tol=1e-3):
|
|
if abs(actual - expected) > tol:
|
|
raise AssertionError(f'{name}: expected ~{expected}, got {actual}')
|
|
print(f' OK {name}={actual:.4f}')
|
|
|
|
|
|
def main():
|
|
banner('Setting up isolated test output dir')
|
|
test_root = PROJECT_ROOT / 'output_e2e_test'
|
|
if test_root.exists():
|
|
shutil.rmtree(test_root)
|
|
test_root.mkdir(parents=True)
|
|
|
|
# Copy the canonical aime24 data into the isolated dir
|
|
src = SOURCE_OUTPUT / 'aime24' / 'seed_42'
|
|
dst = test_root / 'aime24' / 'seed_42'
|
|
shutil.copytree(src, dst)
|
|
|
|
# And copy hle_low as hle_low under the test dir (so we exercise the
|
|
# alias code path).
|
|
hle_src = SOURCE_OUTPUT / 'hle_low' / 'seed_42'
|
|
hle_dst = test_root / 'hle_low' / 'seed_42'
|
|
if hle_src.exists():
|
|
shutil.copytree(hle_src, hle_dst)
|
|
|
|
benchmark = 'aime24'
|
|
model_name = 'DeepSeek-V4-Flash-Int8'
|
|
|
|
banner('1) backup_perf_stats — snapshot summary')
|
|
report_json = dst / 'reports' / model_name / f'{benchmark}.json'
|
|
backup_path = pb.backup_perf_stats(test_root, benchmark, model_name, report_json)
|
|
assert backup_path.exists(), 'backup file was not created'
|
|
payload = json.loads(backup_path.read_text())
|
|
assert payload['n_samples'] == 30, f'expected 30 samples, got {payload["n_samples"]}'
|
|
print(f' OK backup written: {backup_path}, n_samples={payload["n_samples"]}')
|
|
|
|
banner('2) archive_predictions — deduplicate into archive')
|
|
preds = dst / 'predictions' / model_name
|
|
archive_path = pb.archive_predictions(test_root, benchmark, model_name, preds)
|
|
assert archive_path.exists(), 'archive file was not created'
|
|
n_lines = sum(1 for line in archive_path.read_text().splitlines() if line.strip())
|
|
assert n_lines == 30, f'expected 30 archived samples, got {n_lines}'
|
|
print(f' OK archive written: {archive_path}, samples={n_lines}')
|
|
|
|
banner('3) restore_from_backup — rehydrate a fresh work_dir')
|
|
fresh_dir = test_root / 'fresh_work' / 'seed_42'
|
|
fresh_report = fresh_dir / 'reports' / model_name / f'{benchmark}.json'
|
|
fresh_preds = fresh_dir / 'predictions' / model_name
|
|
# Pre-create empty structure to mimic what eval_task would do
|
|
fresh_report.parent.mkdir(parents=True, exist_ok=True)
|
|
fresh_report.write_text(json.dumps({
|
|
'name': f'{model_name}@{benchmark}',
|
|
'perf_metrics': {'summary': {'n_samples': 1}},
|
|
}))
|
|
restored = pb.restore_from_backup(
|
|
test_root, benchmark, model_name, fresh_preds, fresh_report,
|
|
)
|
|
assert restored, 'restore_from_backup returned False'
|
|
restored_report = json.loads(fresh_report.read_text())
|
|
assert restored_report['perf_metrics']['summary']['n_samples'] == 30, \
|
|
f'restored n_samples={restored_report["perf_metrics"]["summary"]["n_samples"]}'
|
|
print(' OK restored report n_samples=30 (matches backup)')
|
|
|
|
banner('4) collect_results — aggregate metrics')
|
|
csv, xlsx = cr.eval_benchmark([benchmark], test_root, model_name)
|
|
import pandas as pd
|
|
df = pd.read_csv(csv)
|
|
aime24 = df[df['Benchmark'] == 'aime24'].iloc[0]
|
|
# Single seed_42 run, so values match the report directly (no multi-run
|
|
# averaging). The full-summary CSV averages across run_1..run_11.
|
|
assert_close(aime24['得分'], 0.6333, 'aime24 score (single seed)')
|
|
assert_close(aime24['实测时间(h)'], 0.1469, 'aime24 duration (h)')
|
|
assert_close(aime24['总样本数'], 30, 'aime24 sample count')
|
|
assert_close(aime24['延迟_mean(s)'], 35.24971, 'aime24 latency mean')
|
|
assert_close(aime24['TTFT_mean(s)'], 0.26301, 'aime24 TTFT mean')
|
|
assert_close(aime24['TPOT_mean(s)'], 0.02165, 'aime24 TPOT mean')
|
|
assert_close(aime24['输入tokens_mean'], 119.33, 'aime24 input_tokens_mean')
|
|
assert_close(aime24['输出tokens_mean'], 1609.8, 'aime24 output_tokens_mean')
|
|
|
|
banner('5) Whitelist mode — only the requested benchmarks appear')
|
|
csv2, _ = cr.eval_benchmark([benchmark], test_root, model_name)
|
|
df2 = pd.read_csv(csv2)
|
|
assert df2['Benchmark'].dropna().tolist() == ['aime24'], \
|
|
f'whitelist did not limit benchmarks: {df2["Benchmark"].tolist()}'
|
|
print(' OK summary only contains aime24 + total')
|
|
|
|
banner('6) hle_low → hle alias')
|
|
if hle_src.exists():
|
|
csv3, _ = cr.eval_benchmark(['hle'], test_root, model_name)
|
|
df3 = pd.read_csv(csv3)
|
|
assert 'hle' in df3['Benchmark'].tolist(), \
|
|
f'hle canonical name missing from: {df3["Benchmark"].tolist()}'
|
|
assert 'hle_low' not in df3['Benchmark'].tolist(), \
|
|
f'hle_low should be aliased away: {df3["Benchmark"].tolist()}'
|
|
print(' OK hle_low directory maps to canonical "hle"')
|
|
|
|
banner('7) Reset recovery — wipe report+predictions, expect archive to restore')
|
|
# Wipe the current predictions
|
|
shutil.rmtree(preds)
|
|
# Reset report.json
|
|
data = json.loads(report_json.read_text())
|
|
data['perf_metrics']['summary']['n_samples'] = 1
|
|
data['perf_metrics']['summary']['latency']['mean'] = 0.0
|
|
report_json.write_text(json.dumps(data, indent=2))
|
|
|
|
csv4, _ = cr.eval_benchmark([benchmark], test_root, model_name)
|
|
df4 = pd.read_csv(csv4)
|
|
aime24_after = df4[df4['Benchmark'] == 'aime24'].iloc[0]
|
|
assert_close(aime24_after['得分'], 0.6333, 'aime24 score (post-reset)')
|
|
assert_close(aime24_after['总样本数'], 30, 'aime24 sample count (post-reset)')
|
|
assert_close(aime24_after['延迟_mean(s)'], 35.24971, 'aime24 latency mean (post-reset)')
|
|
assert_close(aime24_after['TTFT_mean(s)'], 0.26301, 'aime24 TTFT mean (post-reset)')
|
|
print(' OK archive fully recovered metrics after predictions wipe')
|
|
|
|
banner('8) Backup monotonicity — new backup must not overwrite a larger one')
|
|
# We have a backup with n_samples=30. Now write a fresh report with
|
|
# n_samples=2 and call backup_perf_stats again — the backup should NOT
|
|
# be overwritten.
|
|
data = json.loads(report_json.read_text())
|
|
data['perf_metrics']['summary']['n_samples'] = 2
|
|
report_json.write_text(json.dumps(data, indent=2))
|
|
pb.backup_perf_stats(test_root, benchmark, model_name, report_json)
|
|
payload2 = json.loads(backup_path.read_text())
|
|
assert payload2['n_samples'] == 30, \
|
|
f'backup was clobbered: n_samples now {payload2["n_samples"]}'
|
|
print(' OK backup preserved n_samples=30 even after a reset run')
|
|
|
|
banner('All checks passed')
|
|
print(f'Test artifacts under {test_root} (kept for inspection)')
|
|
|
|
|
|
if __name__ == '__main__':
|
|
main()
|