Benchmarking
July 5, 2026 ยท View on GitHub
Full Benchmark Harness
The examples below replay the arxiv length trace. Generate it first (see scripts/traces/arxiv):
uv run python scripts/traces/arxiv/prepare_trace.py
This writes data/traces/arxiv_summarization_llada2_tokenizer_filtered_4k.csv.
Colocated Benchmark Example
uv run python -m sangam.benchmark.main \
--model GSAI-ML/LLaDA-8B-Instruct \
--mode colocated \
--gpus 0,1 \
--num-requests 200 \
--interval-type poisson --qps 2.0 \
--length-type trace \
--length-trace-file data/traces/arxiv_summarization_llada2_tokenizer_filtered_4k.csv \
--output-dir benchmark_output
Hybrid Benchmark Exmaple (requires atleast 2 GPUs)
uv run python -m sangam.benchmark.main \
--model GSAI-ML/LLaDA-8B-Instruct \
--mode hybrid \
--prefill-gpus 0 --hybrid-colocated-gpus 1 \
--num-requests 200 \
--interval-type poisson --qps 2.0 \
--length-type trace \
--length-trace-file data/traces/arxiv_summarization_llada2_tokenizer_filtered_4k.csv \
--output-dir benchmark_output
Auto-launched benchmark servers share the same launch surface as sangam.entrypoints.launch, including scheduler policies, distributed settings, and prefill/decode batching limits.
Trace Inputs
Full Request Trace
Use --request-generator-type trace --trace-file ... to replay requests with arrival times and token counts. The CSV is expected to contain:
Date: used with--trace-dateto select a single dayTime: arrival time in seconds within that date; scaled by--time-scale-factorPromptTokenCount: prompt length before scaling/clippingCompletionTokenCount: completion length before scaling/clipping
PromptTokenCount and CompletionTokenCount are scaled by the configured prefill/decode scale factors, clipped to at least 1 token each, and reduced as needed to satisfy the configured max-token cap.
Interval Trace
Use --interval-type trace --interval-trace-file ... to replay only arrival spacing. The CSV is expected to contain:
arrival_time: parseable timestamp column
Rows are filtered by --interval-trace-start-time and --interval-trace-end-time, normalized to seconds from the first retained request, then rescaled by --interval-trace-time-scale-factor.
Length Trace
Use --length-type trace --length-trace-file ... to replay only prompt/completion lengths. This is how the data/traces/arxiv_summarization_llada2_tokenizer_filtered_4k.csv trace used in the examples above (generated by scripts/traces/arxiv/prepare_trace.py) is consumed. The CSV is expected to contain:
prompt_len: requiredgen_len: required- optional
messages: a JSON list of chat messages, e.g.[{"role": "user", "content": "..."}] - optional
session_idandrequest_id_in_session: combined into a per-requestexternal_idof the form"{session_id}-{request_id_in_session}"
prompt_len and gen_len are scaled, clipped to at least 1 token each, and capped to the configured max-token limit. When messages is present, the runner tokenizes and submits the real chat payload instead of placeholder token ids; this requires --model to point at an instruct model with a chat template. Any additional columns (such as total_len) are ignored.
The number of rows replayed is bounded by --num-requests / --duration, so the full CSV is only replayed when --num-requests is at least the row count.
Example length-trace skeleton:
session_id,request_id_in_session,messages,prompt_len,gen_len
2,0,"[{""role"": ""user"", ""content"": ""Summarize the following arxiv paper...""}]",1024,256
Prompt-Bearing Trace Behavior
When a length trace includes messages, the harness tokenizes and submits that exact chat payload. Prompt-bearing trace requests also default to unmasking_strategy=conf_threshold with confidence_threshold=0.9 when sampling flags are otherwise left at implicit defaults.
Benchmark requests now carry an explicit stable request_seed that is preserved
through request normalization and prompt-text alignment. That keeps nonzero-temperature
sampling reproducible across scheduler modes and repeated benchmark runs.
Benchmark Outputs
Each run writes a timestamped directory under benchmark_output/ containing the most important artifacts below:
config.yaml: resolved benchmark configurationbenchmark_results.json: aggregate latency/throughput summary plus per-request records, includingprompt_textandgenerated_textwhen presentrequest_metrics.csv: per-request metrics such as latency, total scheduling delay,request_scheduling_delay_prefill,request_scheduling_delay_decode, and forward-pass countsworker_timeline.csv: worker queue-state visibilityworker_batch_metrics.csv: only when--enable-individual-batch-metricsis enabled; includesbatch_sampling_timeandbatch_phase, plusbatch_op_attn_timeandbatch_op_mlp_timewhen--enable-operation-metricsis enabledworker_plots/worker_batch_execution_time.{csv,png}: aggregate worker batch execution-time CDF across all batch phasesworker_plots/worker_decode_length_sum_time_series.{csv,png}: decode-batch timeseries of summed per-request sequence lengths per workerworker_plots/worker_batch_phase_time_totals.{csv,png}: total execution time each worker spent inprefill,decode, andmixedbatch phases
Timing values in request_metrics.csv, block_metrics.csv, and worker_batch_metrics.csv are exported with 4 decimal places.
Interpretation notes:
gen_tokensmeans generated/completion tokens only; prompt tokens are excluded- summary
tokens_per_secis total successful completion tokens divided by benchmark wall-clock time - failed requests are excluded from throughput summaries
- the harness runs one warmup request, then resets scheduler-side metrics so exported artifacts reflect only the measured run
Benchmark Timeout
Every benchmark run is bounded by --benchmark-timeout (default 900 seconds / 15 minutes), covering server startup, warmup, the main request loop, and teardown. On expiry the harness logs a warning, tears down the server, and exits with code 2. Pair with --export-partial-metrics to flush any metrics collected before the timeout fires. Pass --benchmark-timeout 0 to disable the cap.