How to Run Performance Benchmarks Using the Twinkle Eval Benchmark Command
Run comprehensive LLM performance benchmarks by executing twinkle-eval --benchmark, which measures latency, throughput, time-to-first-token (TTFT), and time-per-output-token (TPOT) through the BenchmarkRunner class in twinkle_eval/benchmark.py.
The ai-twinkle/eval repository provides a built-in benchmarking suite that evaluates Large Language Model (LLM) performance without requiring external tools. Whether you need to measure baseline latency or stress-test throughput under concurrent load, the Twinkle Eval benchmark command offers both burst and rate-limited execution modes. This guide explains how to run performance benchmarks using the Twinkle Eval benchmark command, configure test parameters, and interpret the resulting metrics.
What the Twinkle Eval Benchmark Measures
The benchmark engine captures four critical performance indicators for LLM inference:
- Latency: End-to-end request duration from submission to final token
- Throughput: Requests per second and tokens per second processed
- Time-to-First-Token (TTFT): Duration from request start until the first response token arrives
- Time-per-Output-Token (TPOT): Average generation time for each subsequent token after the first
These metrics are calculated in twinkle_eval/benchmark.py within the _calculate_metrics() method (lines 252-444), which processes raw RequestResult objects into a BenchmarkMetrics dataclass.
Prerequisites and Configuration
Before running benchmarks, ensure you have a valid config.yaml file that specifies the LLM provider and model parameters. The benchmark relies on twinkle_eval/config.py to load settings and twinkle_eval/models.py (specifically LLMFactory.create_llm()) to instantiate the client.
Minimal configuration example:
llm:
provider: openai
model: gpt-3.5-turbo
api_key: ${OPENAI_API_KEY}
temperature: 0.7
Running the Benchmark from the Command Line
Basic Benchmark Execution
Execute the simplest benchmark using default parameters:
twinkle-eval --benchmark
This command:
- Loads
config.yamlviaload_config()intwinkle_eval/main.py - Initializes
BenchmarkRunnerwith default values (100 requests, 10 concurrent workers) - Uses the default prompt: "台灣的首都是哪裡?" (What is the capital of Taiwan?)
- Outputs results to
benchmark_results_YYYYMMDD_HHMMSS.json
Advanced Options and Rate Limiting
For controlled load testing, specify concurrency limits, request rates, and custom prompts:
twinkle-eval \
--benchmark \
--benchmark-requests 50 \
--benchmark-concurrency 5 \
--benchmark-rate 2 \
--benchmark-duration 30 \
--benchmark-prompt "Explain quantum entanglement in one sentence."
Parameter explanations:
--benchmark-requests: Total number of requests to issue (default: 100)--benchmark-concurrency: Maximum simultaneous HTTP connections (default: 10)--benchmark-rate: Requests-per-second ceiling (enables rate-limited mode when specified)--benchmark-duration: Maximum wall-clock time in seconds (runner stops early if exceeded)--benchmark-prompt: Input text sent to the LLM for each request
When --benchmark-rate is provided, BenchmarkRunner.run_benchmark() (lines 106-145 in twinkle_eval/benchmark.py) invokes _run_rate_limited_benchmark() (lines 181-213), which uses a ThreadPoolExecutor combined with a Semaphore to enforce the rate limit. Without a rate limit, _run_burst_benchmark() (lines 145-179) executes requests at maximum speed.
Understanding the Benchmark Architecture
CLI Entry Point and Argument Parsing
The command-line interface is defined in twinkle_eval/main.py. Lines 73-100 define the argument parser, adding the --benchmark flag and its associated parameters. When --benchmark is detected, the main() function (around lines 604-646) branches to benchmark execution:
if args.benchmark:
config = load_config(args.config)
runner = BenchmarkRunner(
config,
prompt=args.benchmark_prompt,
num_requests=args.benchmark_requests,
concurrent_requests=args.benchmark_concurrency,
request_rate=args.benchmark_rate,
duration=args.benchmark_duration
)
metrics = runner.run_benchmark()
The BenchmarkRunner Class
Located in twinkle_eval/benchmark.py, the BenchmarkRunner class orchestrates the load test. The __init__ method (lines 96-100) stores configuration parameters, while _setup_llm() (lines 101-105) initializes the LLM client via LLMFactory.create_llm().
The core execution methods are:
run_benchmark(): Entry point that selects burst or rate-limited mode_run_burst_benchmark(): Maximum throughput testing without rate constraints_run_rate_limited_benchmark(): Controlled load withSemaphore-based throttling_send_request(): Individual request execution with timing instrumentation (lines 214-242)
Metrics Calculation and Results Export
After request completion, _calculate_metrics() (lines 252-444) aggregates raw results into statistical summaries. It computes:
- Throughput statistics (requests/second, tokens/second)
- Latency percentiles (mean, median, p95, p99)
- TTFT and TPOT distributions
The main.py module then handles persistence via save_benchmark_results(), which writes the sanitized BenchmarkMetrics dataclass to a timestamped JSON file, stripping live objects like llm_instance before serialization.
Interpreting Benchmark Results
JSON Output Structure
The benchmark generates a JSON file with the following structure:
{
"timestamp": "20240223_143200",
"config": { "provider": "openai", "model": "gpt-3.5-turbo" },
"metrics": {
"throughput": {
"requests_per_second": 9.85,
"tokens_per_second": 58.3
},
"latency": {
"mean": 0.103,
"median": 0.098,
"p95": 0.215,
"p99": 0.298
},
"time_to_first_token": { "mean": 0.042, "median": 0.039 },
"time_per_output_token": { "mean": 0.006, "median": 0.005 }
},
"summary": {
"total_requests": 100,
"successful_requests": 100,
"total_tokens": 587,
"total_duration": 10.14
}
}
Generating HTML Reports
Convert JSON results to a formatted HTML report using:
twinkle-eval --convert-to-html benchmark_results_20240223_143200.json
This command invokes convert_json_to_html() in twinkle_eval/main.py (lines 19-58) and produces a standalone HTML file with visualized metrics tables and charts.
Summary
- Execute
twinkle-eval --benchmarkto run performance benchmarks using the Twinkle Eval benchmark command with default settings (100 requests, 10 concurrent workers). - Customize load testing using flags like
--benchmark-concurrency,--benchmark-rate, and--benchmark-durationto control traffic patterns. - The
BenchmarkRunnerclass intwinkle_eval/benchmark.pyorchestrates execution, while_calculate_metrics()computes latency percentiles, TTFT, TPOT, and throughput statistics. - Results are automatically saved as timestamped JSON files and can be converted to HTML reports using
--convert-to-html.
Frequently Asked Questions
What metrics does the Twinkle Eval benchmark command measure?
The benchmark captures latency (total request duration), throughput (requests and tokens per second), Time-to-First-Token (TTFT), and Time-per-Output-Token (TPOT). These metrics are calculated in twinkle_eval/benchmark.py by the _calculate_metrics() method after raw request data is collected by _send_request().
How do I limit the request rate when running benchmarks?
Use the --benchmark-rate flag to enable rate-limited mode. For example, twinkle-eval --benchmark --benchmark-rate 2 --benchmark-concurrency 5 limits the test to 2 requests per second with 5 concurrent workers. According to the source code in twinkle_eval/benchmark.py, this triggers _run_rate_limited_benchmark(), which uses a Semaphore to throttle requests.
Where are benchmark results saved?
Results are automatically persisted to a JSON file named benchmark_results_YYYYMMDD_HHMMSS.json in the current working directory. The save_benchmark_results() function in twinkle_eval/main.py handles serialization, stripping live objects like llm_instance from the configuration before writing. You can convert these JSON files to HTML reports using twinkle-eval --convert-to-html.
Can I use a custom prompt for benchmarking?
Yes, specify the --benchmark-prompt flag followed by your desired text. If omitted, the benchmark defaults to the Chinese prompt "台灣的首都是哪裡?" (What is the capital of Taiwan?). The prompt is passed to the BenchmarkRunner constructor in twinkle_eval/main.py and sent with every request during the load test.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →