Skip to content

Commit 019b7b8

Browse files
xin2anceci3
andauthored
Add scripts for accuracy and performance evaluation. (#86)
Add scripts for accuracy and performance evaluation. ### PR Category <!-- One of [Core | Vendor | OP | Tools | Others] --> Others ### PR Type <!-- One of [User Experience | New Features | Bug Fixes | Improvements | Performance | Breaking Change | Deprecations | Test Case | Docs | Others] --> Test Case ### Description <!-- Describe what this PR does and why. --> Add scripts for accuracy and performance evaluation. ### Related Issues <!-- Link any related issues: Fixes #issue, Closes #issue, or Related to #issue --> ### Changes <!-- List the key changes made in this PR. --> - ### Testing <!-- How has this change been tested? Include test commands, hardware used, etc. --> - ### Checklist - [ ] I have run the existing tests and they pass - [ ] I have added tests for my changes (if applicable) - [ ] I have updated the documentation (if applicable) --------- Co-authored-by: ceci3 <ceci3@users.noreply.github.com>
1 parent eb2b12c commit 019b7b8

5 files changed

Lines changed: 694 additions & 0 deletions

File tree

benchmarks/flagos_eval/README.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# FlagOS Evaluation Suite
2+
3+
Evaluation toolkit for large language models with LM Eval and vLLM Benchmark.
4+
5+
## Quick Start
6+
7+
### 1. Dependencies
8+
9+
* **[lm-evaluation-harness](https://github.com/EleutherAI/lm-evaluation-harness)**
10+
```bash
11+
git clone https://github.com/EleutherAI/lm-evaluation-harness.git
12+
cd lm-evaluation-harness
13+
git checkout ee7e8f4fe58e13d6760c066474f0d01477317d1d
14+
pip install -e .
15+
pip install "lm_eval[hf,vllm,api]"
16+
pip install datasets==2.14.7
17+
```
18+
19+
* **[vllm](https://github.com/vllm-project/vllm)**
20+
```
21+
Version: 0.13.0
22+
Commit ID: 72506c98349d6bcd32b4e33eec7b5513453c1502
23+
```
24+
25+
* **[vllm-plugin-FL](https://github.com/flagos-ai/vllm-plugin-FL)**
26+
```
27+
Commit ID: af1e0b2adfb0061df9699b23e8837b36333cec41
28+
```
29+
30+
* **Python 3.10+**
31+
32+
### 2. Run Evaluation
33+
34+
```bash
35+
cd benchmarks/flagos_eval
36+
37+
# LM Evaluation (~35 minutes)
38+
./run_eval.sh /path/to/model/ hf_xxxxxxxxxxxxx
39+
40+
# Performance Benchmark
41+
./run_benchmark.sh /path/to/model/
42+
```
43+
44+
## Evaluation Tasks
45+
46+
### LM Evaluation
47+
48+
Tasks:
49+
- **General**: BBH
50+
- **Math**: GSM8K
51+
- **Coding**: HumanEval, MBPP
52+
- **Multilingual**: MGSM (Chinese)
53+
54+
Output Files:
55+
- `results_summary.csv` - Summary
56+
- `output/*/results*.json` - Detailed results
57+
58+
### Performance Benchmark
59+
60+
Metrics:
61+
- **Throughput**: tokens/s, requests/s
62+
- **Latency**: Mean, P50, P90, P99 (ms)
63+
64+
Output Files:
65+
- `bench_summary.csv` - Summary
66+
- `bench_results/*.json` - Detailed results
67+
68+
## Project Structure
69+
70+
```
71+
flagos_eval/
72+
├── run_eval.sh # LM evaluation script
73+
├── run_benchmark.sh # Performance benchmark script
74+
├── collect_eval_results.py # LM evaluation result collector
75+
├── collect_benchmark_results.py # Performance benchmark result collector
76+
├── output/ # LM evaluation results
77+
├── bench_results/ # Performance benchmark results
78+
├── results_summary.csv # LM evaluation summary
79+
└── bench_summary.csv # Performance benchmark summary
80+
```
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
#!/usr/bin/env python3
2+
"""Collect and summarize vLLM benchmark results"""
3+
4+
import csv
5+
import glob
6+
import json
7+
import os
8+
from pathlib import Path
9+
10+
11+
def load_json(path):
12+
"""Load JSON file"""
13+
try:
14+
with open(path, "r") as f:
15+
return json.load(f)
16+
except Exception as e:
17+
print(f"Error loading {path}: {e}")
18+
return None
19+
20+
21+
def extract_throughput_metrics(data):
22+
"""Extract throughput metrics from JSON data"""
23+
metrics = {
24+
"num_prompts": data.get("num_requests") or data.get("num_prompts"),
25+
"total_tokens": data.get("total_num_tokens") or data.get("total_output_tokens"),
26+
"elapsed_time": data.get("elapsed_time"),
27+
"tokens_per_sec": data.get("tokens_per_second")
28+
or data.get("output_throughput"),
29+
"requests_per_sec": data.get("requests_per_second")
30+
or data.get("request_throughput"),
31+
}
32+
return metrics
33+
34+
35+
def extract_latency_metrics(data):
36+
"""Extract latency metrics from JSON data"""
37+
# Get percentiles if available
38+
percentiles = data.get("percentiles", {})
39+
40+
metrics = {
41+
"num_iters": len(data.get("latencies", [])) or data.get("num_iters"),
42+
"mean_latency": data.get("avg_latency") or data.get("mean_latency"),
43+
"median_latency": percentiles.get("50")
44+
or data.get("median_latency")
45+
or data.get("p50_latency"),
46+
"p90_latency": percentiles.get("90") or data.get("p90_latency"),
47+
"p99_latency": percentiles.get("99") or data.get("p99_latency"),
48+
"ttft": data.get("time_to_first_token") or data.get("avg_ttft"),
49+
}
50+
51+
# Convert seconds to milliseconds if values are in seconds (< 100)
52+
for key in ["mean_latency", "median_latency", "p90_latency", "p99_latency", "ttft"]:
53+
if metrics[key] is not None and metrics[key] < 100:
54+
metrics[key] *= 1000
55+
56+
return metrics
57+
58+
59+
def print_throughput_results(results_dir):
60+
"""Print throughput test results"""
61+
print("\n" + "=" * 80)
62+
print("THROUGHPUT TEST RESULTS")
63+
print("=" * 80)
64+
65+
files = sorted(glob.glob(os.path.join(results_dir, "throughput_*.json")))
66+
if not files:
67+
print("No throughput results found")
68+
return []
69+
70+
print(
71+
f"\n{'Scenario':<15} {'Prompts':<8} {'Tokens':<10} {'Time(s)':<9} {'Tokens/s':<12} {'Req/s':<10}"
72+
)
73+
print("-" * 80)
74+
75+
results = []
76+
for path in files:
77+
data = load_json(path)
78+
if not data:
79+
continue
80+
81+
scenario = Path(path).stem.replace("throughput_", "")
82+
metrics = extract_throughput_metrics(data)
83+
results.append({"scenario": scenario, "type": "throughput", **metrics})
84+
85+
print(
86+
f"{scenario:<15} "
87+
f"{metrics['num_prompts'] or 'N/A':<8} "
88+
f"{metrics['total_tokens'] or 'N/A':<10} "
89+
f"{metrics['elapsed_time'] or 0:>7.1f}s "
90+
f"{metrics['tokens_per_sec'] or 0:>10.1f} "
91+
f"{metrics['requests_per_sec'] or 0:>9.2f}"
92+
)
93+
94+
print("-" * 80)
95+
return results
96+
97+
98+
def print_latency_results(results_dir):
99+
"""Print latency test results"""
100+
print("\n" + "=" * 80)
101+
print("LATENCY TEST RESULTS")
102+
print("=" * 80)
103+
104+
files = sorted(glob.glob(os.path.join(results_dir, "latency_*.json")))
105+
if not files:
106+
print("No latency results found")
107+
return []
108+
109+
print(
110+
f"\n{'Scenario':<15} {'Iters':<6} {'Mean(ms)':<12} {'P50(ms)':<12} {'P90(ms)':<12} {'P99(ms)':<12}"
111+
)
112+
print("-" * 80)
113+
114+
results = []
115+
for path in files:
116+
data = load_json(path)
117+
if not data:
118+
continue
119+
120+
scenario = Path(path).stem.replace("latency_", "")
121+
metrics = extract_latency_metrics(data)
122+
results.append({"scenario": scenario, "type": "latency", **metrics})
123+
124+
def fmt(v):
125+
return f"{v:.2f}" if v else "N/A"
126+
127+
print(
128+
f"{scenario:<15} "
129+
f"{metrics['num_iters'] or 'N/A':<6} "
130+
f"{fmt(metrics['mean_latency']):<12} "
131+
f"{fmt(metrics['median_latency']):<12} "
132+
f"{fmt(metrics['p90_latency']):<12} "
133+
f"{fmt(metrics['p99_latency']):<12}"
134+
)
135+
136+
print("-" * 80)
137+
return results
138+
139+
140+
def print_summary(throughput_results, latency_results):
141+
"""Print key metrics summary"""
142+
print("\n" + "=" * 80)
143+
print("KEY METRICS SUMMARY")
144+
print("=" * 80)
145+
146+
# Best throughput
147+
if throughput_results:
148+
best_tp = max(throughput_results, key=lambda x: x.get("tokens_per_sec") or 0)
149+
print(
150+
f"\nBest Throughput: {best_tp.get('tokens_per_sec', 0):.1f} tokens/s ({best_tp['scenario']})"
151+
)
152+
153+
# Latency results
154+
if latency_results:
155+
print("\nLatency Results:")
156+
for r in latency_results:
157+
mean = r.get("mean_latency") or 0
158+
p99 = r.get("p99_latency") or 0
159+
print(f" {r['scenario']:<15} Mean={mean:.1f}ms, P99={p99:.1f}ms")
160+
161+
print("-" * 80)
162+
163+
164+
def export_csv(throughput_results, latency_results, output_file):
165+
"""Export all results to CSV"""
166+
rows = []
167+
168+
for r in throughput_results:
169+
rows.append(
170+
{
171+
"type": "throughput",
172+
"scenario": r["scenario"],
173+
"num_prompts": r.get("num_prompts"),
174+
"total_tokens": r.get("total_tokens"),
175+
"elapsed_time_s": r.get("elapsed_time"),
176+
"tokens_per_sec": r.get("tokens_per_sec"),
177+
"requests_per_sec": r.get("requests_per_sec"),
178+
"mean_latency_ms": "",
179+
"p50_latency_ms": "",
180+
"p90_latency_ms": "",
181+
"p99_latency_ms": "",
182+
}
183+
)
184+
185+
for r in latency_results:
186+
rows.append(
187+
{
188+
"type": "latency",
189+
"scenario": r["scenario"],
190+
"num_prompts": r.get("num_iters"),
191+
"total_tokens": "",
192+
"elapsed_time_s": "",
193+
"tokens_per_sec": "",
194+
"requests_per_sec": "",
195+
"mean_latency_ms": r.get("mean_latency"),
196+
"p50_latency_ms": r.get("median_latency"),
197+
"p90_latency_ms": r.get("p90_latency"),
198+
"p99_latency_ms": r.get("p99_latency"),
199+
}
200+
)
201+
202+
if rows:
203+
with open(output_file, "w", newline="") as f:
204+
writer = csv.DictWriter(f, fieldnames=rows[0].keys())
205+
writer.writeheader()
206+
writer.writerows(rows)
207+
print(f"\nResults exported to: {output_file}")
208+
209+
210+
def export_json(throughput_results, latency_results, output_file):
211+
"""Export all results to JSON"""
212+
data = {
213+
"throughput": throughput_results,
214+
"latency": latency_results,
215+
}
216+
with open(output_file, "w") as f:
217+
json.dump(data, f, indent=2)
218+
print(f"Results exported to: {output_file}")
219+
220+
221+
def main():
222+
import sys
223+
224+
results_dir = sys.argv[1] if len(sys.argv) > 1 else "bench_results"
225+
226+
if not os.path.isdir(results_dir):
227+
print(f"Error: Directory not found: {results_dir}")
228+
print(f"Usage: python {sys.argv[0]} [results_dir]")
229+
return 1
230+
231+
print(f"Collecting results from: {results_dir}/")
232+
233+
# Collect and print results
234+
throughput_results = print_throughput_results(results_dir)
235+
latency_results = print_latency_results(results_dir)
236+
237+
# Print summary
238+
print_summary(throughput_results, latency_results)
239+
240+
# Export to files
241+
export_csv(throughput_results, latency_results, "bench_summary.csv")
242+
# export_json(throughput_results, latency_results, "bench_summary.json")
243+
244+
return 0
245+
246+
247+
if __name__ == "__main__":
248+
exit(main())

0 commit comments

Comments
 (0)