Comprehensive guide to benchmarking LLM training and inference workloads on AWS Trainium and Inferentia2.
- Introduction
- Training Benchmarking Methodology
- Inference Benchmarking Methodology
- Tools and Scripts
- Metrics to Collect
- How to Interpret Results
- Comparison with GPU Baselines
- Reporting Templates
- Best Practices
Benchmarking is essential for:
- Performance validation: Verify that your deployment meets SLAs
- Cost optimization: Identify the most cost-effective configuration
- Capacity planning: Determine how many instances you need
- Regression detection: Catch performance degradation early
- Comparison: Evaluate Neuron vs GPU performance
| Benchmark Type | Measures | Use Case |
|---|---|---|
| Synthetic | Theoretical max performance | Hardware evaluation, upper bound |
| Micro | Single operation (e.g., attention layer) | Algorithm optimization |
| Model-level | Full model training/inference | Real-world performance |
| End-to-end | Application with preprocessing | Production readiness |
| Load testing | Performance under sustained load | Capacity planning |
Hardware:
- trn1.32xlarge or trn1n.32xlarge
- Multiple instances for distributed training benchmarks
Software:
# Install Neuron SDK
pip install torch-neuronx==2.1.2.1.0 \
--extra-index-url=https://pip.repos.neuron.amazonaws.com
pip install neuronx-distributed==0.6.0
pip install transformers==4.36.0
# Install benchmarking tools
pip install datasets==2.16.0
pip install accelerate==0.25.0
pip install wandb==0.16.0 # For logging# benchmark_training.py
import argparse
import time
import torch
import torch_xla.core.xla_model as xm
from transformers import AutoTokenizer, AutoModelForCausalLM, TrainingArguments
from datasets import load_dataset
from neuronx_distributed.trainer import NeuronTrainer
from neuronx_distributed.parallel_layers import parallel_state
import wandb
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument("--model_id", type=str, default="meta-llama/Llama-2-7b-hf")
parser.add_argument("--batch_size", type=int, default=8)
parser.add_argument("--sequence_length", type=int, default=2048)
parser.add_argument("--num_steps", type=int, default=100)
parser.add_argument("--tensor_parallel_degree", type=int, default=8)
parser.add_argument("--gradient_accumulation_steps", type=int, default=4)
parser.add_argument("--bf16", action="store_true")
parser.add_argument("--log_wandb", action="store_true")
return parser.parse_args()
def benchmark_training(args):
# Initialize parallel state
parallel_state.initialize_model_parallel(
tensor_model_parallel_size=args.tensor_parallel_degree
)
# Initialize W&B
if args.log_wandb and xm.get_ordinal() == 0:
wandb.init(
project="neuron-training-benchmark",
config=vars(args)
)
# Load model and tokenizer
device = xm.xla_device()
print(f"Loading model: {args.model_id}")
model = AutoModelForCausalLM.from_pretrained(
args.model_id,
torch_dtype=torch.bfloat16 if args.bf16 else torch.float32
)
model = model.to(device)
tokenizer = AutoTokenizer.from_pretrained(args.model_id)
tokenizer.pad_token = tokenizer.eos_token
# Prepare dataset
dataset = load_dataset("wikitext", "wikitext-2-raw-v1", split="train[:1000]")
def tokenize(examples):
return tokenizer(
examples["text"],
truncation=True,
max_length=args.sequence_length,
padding="max_length"
)
dataset = dataset.map(tokenize, batched=True, remove_columns=["text"])
dataset.set_format(type="torch", columns=["input_ids", "attention_mask"])
# Training arguments
training_args = TrainingArguments(
output_dir="/tmp/benchmark_output",
per_device_train_batch_size=args.batch_size,
gradient_accumulation_steps=args.gradient_accumulation_steps,
max_steps=args.num_steps,
bf16=args.bf16,
logging_steps=10,
save_strategy="no",
dataloader_drop_last=True,
)
# Initialize trainer
trainer = NeuronTrainer(
model=model,
args=training_args,
train_dataset=dataset,
tokenizer=tokenizer,
)
# Warmup (first few steps are slow due to compilation)
print("Warming up... (compiling model)")
warmup_start = time.time()
for _ in range(5):
trainer.training_step(model, next(iter(trainer.get_train_dataloader())))
xm.mark_step()
warmup_time = time.time() - warmup_start
print(f"Warmup complete: {warmup_time:.2f}s")
# Actual benchmark
print(f"Starting benchmark: {args.num_steps} steps")
start_time = time.time()
step_times = []
for step in range(args.num_steps):
step_start = time.time()
# Training step
trainer.training_step(model, next(iter(trainer.get_train_dataloader())))
xm.mark_step()
step_time = time.time() - step_start
step_times.append(step_time)
if step % 10 == 0 and xm.get_ordinal() == 0:
print(f"Step {step}: {step_time:.3f}s")
total_time = time.time() - start_time
# Calculate metrics
global_batch_size = args.batch_size * args.gradient_accumulation_steps * xm.xrt_world_size()
tokens_per_batch = global_batch_size * args.sequence_length
avg_step_time = sum(step_times) / len(step_times)
throughput = tokens_per_batch / avg_step_time
# Report results
if xm.get_ordinal() == 0:
print("\n" + "="*60)
print("BENCHMARK RESULTS")
print("="*60)
print(f"Model: {args.model_id}")
print(f"Total steps: {args.num_steps}")
print(f"Total time: {total_time:.2f}s")
print(f"Avg step time: {avg_step_time:.3f}s")
print(f"Global batch size: {global_batch_size}")
print(f"Tokens per batch: {tokens_per_batch}")
print(f"Throughput: {throughput:,.0f} tokens/s")
print(f"Throughput: {throughput/1e6:.2f}M tokens/s")
print("="*60)
if args.log_wandb:
wandb.log({
"avg_step_time": avg_step_time,
"throughput_tokens_per_sec": throughput,
"global_batch_size": global_batch_size,
})
return {
"throughput": throughput,
"avg_step_time": avg_step_time,
"total_time": total_time
}
if __name__ == "__main__":
args = parse_args()
results = benchmark_training(args)Run benchmark:
# Single trn1.32xlarge (16 NeuronCores)
python benchmark_training.py \
--model_id meta-llama/Llama-2-7b-hf \
--batch_size 8 \
--sequence_length 2048 \
--num_steps 100 \
--tensor_parallel_degree 8 \
--gradient_accumulation_steps 4 \
--bf16 \
--log_wandb
# Expected output:
# ============================================================
# BENCHMARK RESULTS
# ============================================================
# Model: meta-llama/Llama-2-7b-hf
# Total steps: 100
# Total time: 95.3s
# Avg step time: 0.953s
# Global batch size: 64
# Tokens per batch: 131,072
# Throughput: 137,570 tokens/s
# Throughput: 0.14M tokens/s
# ============================================================# Multi-node training (4× trn1.32xlarge = 64 NeuronCores)
# On each node, run:
export MASTER_ADDR=<master-node-ip>
export MASTER_PORT=29500
export WORLD_SIZE=4
export RANK=<0,1,2,3> # Unique per node
torchrun \
--nnodes 4 \
--nproc_per_node 16 \
--node_rank $RANK \
--master_addr $MASTER_ADDR \
--master_port $MASTER_PORT \
benchmark_training.py \
--model_id meta-llama/Llama-2-70b-hf \
--batch_size 4 \
--tensor_parallel_degree 16 \
--pipeline_parallel_degree 4 \
--num_steps 100 \
--bf16Hardware:
- inf2.xlarge, inf2.24xlarge, or inf2.48xlarge
- Multiple instances for load testing
Software:
# Install vLLM-Neuron
pip install vllm-neuron==0.6.3
pip install torch-neuronx==2.1.2.1.0 \
--extra-index-url=https://pip.repos.neuron.amazonaws.com
# Install load testing tools
pip install locust==2.20.0
pip install aiohttp==3.9.0# benchmark_inference.py
import argparse
import time
import asyncio
import aiohttp
import numpy as np
from concurrent.futures import ThreadPoolExecutor
import json
def parse_args():
parser = argparse.ArgumentParser()
parser.add_argument("--endpoint", type=str, default="http://localhost:8000")
parser.add_argument("--model", type=str, default="meta-llama/Meta-Llama-3-8B")
parser.add_argument("--num_requests", type=int, default=100)
parser.add_argument("--concurrent_users", type=int, default=10)
parser.add_argument("--input_length", type=int, default=512)
parser.add_argument("--output_length", type=int, default=128)
return parser.parse_args()
async def send_request(session, endpoint, model, prompt, max_tokens):
url = f"{endpoint}/v1/completions"
payload = {
"model": model,
"prompt": prompt,
"max_tokens": max_tokens,
"temperature": 0.7
}
start = time.time()
async with session.post(url, json=payload) as response:
result = await response.json()
end = time.time()
latency = (end - start) * 1000 # Convert to ms
# Extract metrics
output_text = result['choices'][0]['text']
output_tokens = len(output_text.split()) # Rough estimate
return {
"latency_ms": latency,
"output_tokens": output_tokens,
"success": response.status == 200
}
async def benchmark_async(args):
# Generate test prompts of varying lengths
prompts = [
f"Prompt {i}: " + " ".join(["test"] * args.input_length)
for i in range(args.num_requests)
]
# Run benchmark
print(f"Benchmarking: {args.num_requests} requests, {args.concurrent_users} concurrent")
results = []
async with aiohttp.ClientSession() as session:
# Create semaphore to limit concurrency
semaphore = asyncio.Semaphore(args.concurrent_users)
async def throttled_request(prompt):
async with semaphore:
return await send_request(
session,
args.endpoint,
args.model,
prompt,
args.output_length
)
start_time = time.time()
# Send all requests
tasks = [throttled_request(p) for p in prompts]
results = await asyncio.gather(*tasks)
total_time = time.time() - start_time
# Calculate metrics
latencies = [r['latency_ms'] for r in results if r['success']]
output_tokens = [r['output_tokens'] for r in results if r['success']]
success_rate = sum(1 for r in results if r['success']) / len(results)
# Latency percentiles
p50 = np.percentile(latencies, 50)
p90 = np.percentile(latencies, 90)
p95 = np.percentile(latencies, 95)
p99 = np.percentile(latencies, 99)
# Throughput
total_tokens = sum(output_tokens)
throughput = total_tokens / total_time
requests_per_sec = len(results) / total_time
# Time to First Token (TTFT) - estimated from first 10% of latency
ttft_estimate = np.percentile(latencies, 10)
# Time per Output Token (TPOT)
tpot_estimate = (np.mean(latencies) - ttft_estimate) / args.output_length
# Print results
print("\n" + "="*60)
print("BENCHMARK RESULTS")
print("="*60)
print(f"Total requests: {len(results)}")
print(f"Success rate: {success_rate:.1%}")
print(f"Total time: {total_time:.2f}s")
print(f"Requests/sec: {requests_per_sec:.1f}")
print(f"Throughput: {throughput:.0f} tokens/s")
print("")
print("Latency (ms):")
print(f" P50: {p50:.1f}")
print(f" P90: {p90:.1f}")
print(f" P95: {p95:.1f}")
print(f" P99: {p99:.1f}")
print("")
print(f"TTFT (estimated): {ttft_estimate:.1f}ms")
print(f"TPOT (estimated): {tpot_estimate:.1f}ms")
print("="*60)
return {
"throughput": throughput,
"requests_per_sec": requests_per_sec,
"latency_p50": p50,
"latency_p99": p99,
"ttft": ttft_estimate,
"tpot": tpot_estimate,
"success_rate": success_rate
}
def main():
args = parse_args()
asyncio.run(benchmark_async(args))
if __name__ == "__main__":
main()Run benchmark:
# Start vLLM server first
python -m vllm.entrypoints.openai.api_server \
--model meta-llama/Meta-Llama-3-8B \
--tensor-parallel-size 2 \
--port 8000
# Run benchmark
python benchmark_inference.py \
--endpoint http://localhost:8000 \
--model meta-llama/Meta-Llama-3-8B \
--num_requests 100 \
--concurrent_users 10 \
--input_length 512 \
--output_length 128
# Expected output:
# ============================================================
# BENCHMARK RESULTS
# ============================================================
# Total requests: 100
# Success rate: 100.0%
# Total time: 31.2s
# Requests/sec: 3.2
# Throughput: 410 tokens/s
#
# Latency (ms):
# P50: 45.2
# P90: 68.4
# P95: 82.1
# P99: 105.3
#
# TTFT (estimated): 24.3ms
# TPOT (estimated): 6.8ms
# ============================================================# locustfile.py
from locust import HttpUser, task, between
import random
class VLLMUser(HttpUser):
wait_time = between(1, 3) # Wait 1-3 seconds between requests
@task
def generate_completion(self):
prompts = [
"Explain machine learning in simple terms.",
"What is quantum computing?",
"How does a neural network work?",
"What are the benefits of cloud computing?",
]
self.client.post("/v1/completions", json={
"model": "meta-llama/Meta-Llama-3-8B",
"prompt": random.choice(prompts),
"max_tokens": 100,
"temperature": 0.7
})Run load test:
# Start Locust
locust -f locustfile.py --host http://localhost:8000
# Open browser: http://localhost:8089
# Configure:
# - Number of users: 50
# - Spawn rate: 10 users/s
# Start test and monitor:
# - Requests/s
# - Response time (P50, P95, P99)
# - Failure rate# Real-time hardware monitoring
neuron-top
# Sample output:
# ┌─────────────────────────────────────────────────────────────┐
# │ NeuronCore 0: Utilization: 92%, Memory: 28.5 GB / 32 GB │
# │ NeuronCore 1: Utilization: 91%, Memory: 27.8 GB / 32 GB │
# │ ... │
# └─────────────────────────────────────────────────────────────┘
# Export metrics to file
neuron-monitor -o metrics.json
# Key metrics:
# - neuroncore_utilization_ratio
# - neuroncore_memory_used_bytes
# - execution_latency_seconds# Profile a training run
NEURON_PROFILE=profile.json python train.py
# Analyze profile
neuron-profile view profile.json
# Output:
# Operation Time (ms) % Total
# MatMul 1250.4 45.2%
# Attention 824.1 29.8%
# LayerNorm 312.5 11.3%
# GELU 198.3 7.2%
# Other 164.7 6.5%#!/bin/bash
# run_benchmarks.sh
set -e
# Configuration
MODELS=("meta-llama/Llama-2-7b-hf" "meta-llama/Llama-2-13b-hf")
BATCH_SIZES=(4 8 16)
TENSOR_PARALLEL_DEGREES=(8 16)
# Output directory
mkdir -p benchmark_results
# Run training benchmarks
for model in "${MODELS[@]}"; do
for bs in "${BATCH_SIZES[@]}"; do
for tp in "${TENSOR_PARALLEL_DEGREES[@]}"; do
echo "Benchmarking: model=$model, bs=$bs, tp=$tp"
output_file="benchmark_results/${model//\//_}_bs${bs}_tp${tp}.json"
python benchmark_training.py \
--model_id "$model" \
--batch_size "$bs" \
--tensor_parallel_degree "$tp" \
--num_steps 100 \
--bf16 \
> "$output_file"
echo "Results saved to $output_file"
done
done
done
# Generate summary report
python generate_report.py benchmark_results/*.json > summary_report.md
echo "Benchmark complete! See summary_report.md"| Metric | Definition | Target | Command |
|---|---|---|---|
| Throughput | Tokens processed per second | >100K tok/s (7B model) | tokens / step_time |
| Step time | Time per training step | <1s (single node) | time.time() |
| Scaling efficiency | Speedup / num_nodes | >90% | (throughput_N / throughput_1) / N |
| Memory usage | HBM utilization | 70-90% | neuron-monitor |
| NeuronCore utilization | Compute utilization | >85% | neuron-top |
| Compilation time | First-run compile time | <10 min | First step time |
| Loss convergence | Training loss over time | Match GPU baseline | Log loss per step |
| Metric | Definition | Target | Command |
|---|---|---|---|
| Throughput | Output tokens per second | >3000 tok/s (vLLM) | total_tokens / total_time |
| Latency P50 | Median latency | <50ms | np.percentile(latencies, 50) |
| Latency P99 | 99th percentile latency | <200ms | np.percentile(latencies, 99) |
| TTFT | Time to first token | <30ms | First token time - request time |
| TPOT | Time per output token | <10ms | (Total time - TTFT) / num_tokens |
| Requests/sec | Request throughput | >100 req/s | num_requests / total_time |
| Success rate | Non-error rate | >99.9% | successful_requests / total_requests |
| Memory efficiency | KV cache utilization | >80% | used_hbm / total_hbm |
Good performance indicators:
- Throughput within 10-20% of GPU baseline
- Scaling efficiency >90% (single node), >80% (multi-node)
- NeuronCore utilization >85%
- Loss convergence matches GPU
Red flags:
- Throughput <50% of expected: Check batch size, compilation flags
- Low utilization (<60%): CPU bottleneck or small batch size
- High memory usage (>95%): Risk of OOM, reduce batch or sequence length
- Loss divergence: Check learning rate, gradient clipping
Example comparison (Llama 2 7B):
GPU (8× A100):
- Throughput: 1,250K tok/s
- Step time: 0.85s
- Cost: $256/hour
Trainium (8× trn1.32xlarge):
- Throughput: 1,050K tok/s (-16% vs GPU)
- Step time: 1.00s
- Cost: $198/hour (-23% vs GPU)
Verdict: ✅ Good - 16% slower but 23% cheaper = net positive ROI
Good performance indicators:
- Throughput 3-4× higher than baseline (with vLLM)
- P99 latency <200ms for chatbot use cases
- TTFT <50ms (prompt processing fast)
- TPOT <10ms (token generation fast)
Red flags:
- Throughput <2× baseline: vLLM not working, check continuous batching
- High P99 latency (>500ms): Overloaded, reduce max_num_seqs
- Success rate <99%: Timeouts or OOM, check KV cache size
Example comparison (Llama 3 8B):
GPU (A10G):
- Throughput: 850 tok/s
- P99 latency: 95ms
- Cost: $1.01/hour
Inferentia2 (inf2.xlarge + vLLM):
- Throughput: 3,200 tok/s (+276% vs GPU)
- P99 latency: 52ms (-45% vs GPU)
- Cost: $0.76/hour (-25% vs GPU)
Verdict: ✅ Excellent - 3.8× faster and 25% cheaper
| Workload | GPU Setup | GPU Cost/hr | Neuron Setup | Neuron Cost/hr | Speedup | Cost Savings |
|---|---|---|---|---|---|---|
| Llama 2 7B | 1× A100 | $32.77 | 1× trn1.32xlarge | $24.78 | 0.84× | 24% |
| Llama 2 13B | 2× A100 | $65.54 | 1× trn1.32xlarge | $24.78 | 0.78× | 62% |
| Llama 2 70B | 8× A100 | $262.16 | 8× trn1.32xlarge | $198.24 | 0.92× | 24% |
| GPT-NeoX 20B | 4× A100 | $131.08 | 4× trn1.32xlarge | $99.12 | 0.88× | 24% |
Interpretation:
- Trainium is 15-25% slower per dollar spent
- BUT: 24-62% cheaper total cost
- Net benefit: Train 20-40% more for same budget
| Workload | GPU Setup | GPU Cost/hr | Neuron Setup | Neuron Cost/hr | Speedup | Cost Savings |
|---|---|---|---|---|---|---|
| Llama 3 8B | 1× A10G | $1.01 | 1× inf2.xlarge | $0.76 | 3.8× | 25% |
| Llama 2 13B | 1× A100 | $32.77 | 1× inf2.24xlarge | $6.49 | 2.1× | 80% |
| Llama 2 70B | 8× A100 | $262.16 | 12× inf2.48xlarge | $155.76 | 1.2× | 41% |
| Mistral 7B | 1× A10G | $1.01 | 1× inf2.xlarge | $0.76 | 4.1× | 25% |
Interpretation:
- Inferentia2 is 1.2-4× faster
- AND: 25-80% cheaper
- Net benefit: 50-400% better price/performance
# Training Benchmark Report: [Model Name] on Trainium
**Date**: 2026-04-04
**Engineer**: [Your Name]
**Model**: meta-llama/Llama-2-7b-hf
**Hardware**: 1× trn1.32xlarge (16 NeuronCores)
## Configuration
- Batch size: 8 per core
- Sequence length: 2048 tokens
- Gradient accumulation: 4 steps
- Tensor parallelism: 8-way
- Precision: BF16
- Optimizer: AdamW
## Results
| Metric | Value |
|--------|-------|
| **Throughput** | 137,570 tokens/s |
| **Step time (avg)** | 0.953s |
| **Global batch size** | 64 |
| **NeuronCore utilization** | 91% |
| **HBM usage** | 28 GB / 32 GB (88%) |
| **Compilation time** | 8.2 minutes (first run) |
## Comparison with GPU Baseline
| Metric | A100 (baseline) | Trainium | Delta |
|--------|-----------------|----------|-------|
| **Throughput** | 156,250 tok/s | 137,570 tok/s | -12% |
| **Step time** | 0.84s | 0.95s | +13% |
| **Cost/hour** | $32.77 | $24.78 | **-24%** |
| **Cost/1M tokens** | $0.21 | $0.18 | **-14%** |
## Recommendations
1. ✅ **Deploy to production**: 24% cost savings with acceptable 12% slowdown
2. 🔍 **Optimization opportunity**: Increase batch size to 12 (utilize remaining 4 GB HBM)
3. 📊 **Monitor**: Track loss convergence to ensure quality matches GPU
## Loss Convergence

Epoch 1: 2.134 (GPU: 2.132) - ✅ Within 0.1%
Epoch 2: 1.892 (GPU: 1.889) - ✅ Within 0.2%
Epoch 3: 1.756 (GPU: 1.754) - ✅ Within 0.1%
**Conclusion**: Model quality matches GPU baseline.# Inference Benchmark Report: [Model Name] on Inferentia2
**Date**: 2026-04-04
**Engineer**: [Your Name]
**Model**: meta-llama/Meta-Llama-3-8B
**Hardware**: 1× inf2.xlarge (2 NeuronCores)
**Serving**: vLLM-Neuron 0.6.3
## Configuration
- Tensor parallelism: 2-way
- Max sequence length: 4096 tokens
- Max concurrent requests: 16
- Precision: BF16
- Batching: Continuous (PagedAttention)
## Results
| Metric | Value |
|--------|-------|
| **Throughput** | 3,200 tokens/s |
| **Requests/sec** | 25 req/s |
| **Latency P50** | 45ms |
| **Latency P95** | 68ms |
| **Latency P99** | 78ms |
| **TTFT** | 24ms |
| **TPOT** | 6.8ms |
| **Success rate** | 100% |
## Load Test (50 concurrent users)
| Duration | Requests | Throughput | P99 Latency | Error Rate |
|----------|----------|------------|-------------|------------|
| **10 min** | 15,000 | 3,180 tok/s | 125ms | 0% |
## Comparison with GPU Baseline
| Metric | A10G (baseline) | Inferentia2 | Delta |
|--------|-----------------|-------------|-------|
| **Throughput** | 850 tok/s | 3,200 tok/s | **+276%** |
| **Latency P99** | 95ms | 78ms | **-18%** |
| **Cost/hour** | $1.01 | $0.76 | **-25%** |
| **Cost/1M tokens** | $1.19 | $0.24 | **-80%** |
## Recommendations
1. ✅ **Deploy to production**: 3.8× faster and 25% cheaper than GPU
2. 📈 **Scale up**: Can handle 50+ concurrent users with P99 <150ms
3. 🔧 **Tune**: Consider increasing max_num_seqs to 24 for even higher throughput
## SLA Compliance
| SLA Requirement | Target | Actual | Status |
|-----------------|--------|--------|--------|
| **P99 latency** | <200ms | 78ms | ✅ Pass |
| **Throughput** | >1000 tok/s | 3200 tok/s | ✅ Pass |
| **Availability** | >99.9% | 100% | ✅ Pass |
**Conclusion**: Exceeds all SLA requirements. Ready for production.# ❌ Don't benchmark on dev instance
python benchmark.py --model llama-7b --batch_size 1
# ✅ Do benchmark on same hardware as production
python benchmark.py \
--model llama-7b \
--batch_size 8 \
--sequence_length 2048 \
--num_steps 100 \ # Representative workload
--bf16 \
--tensor_parallel_degree 8# ❌ Don't include compilation in benchmark
start = time.time()
model = load_model()
outputs = model.generate(inputs) # First run = compilation!
throughput = calculate_throughput(time.time() - start)
# ✅ Do warm up model first
model = load_model()
# Warmup (discard results)
for _ in range(10):
model.generate(dummy_inputs)
# Now measure
start = time.time()
for _ in range(100):
model.generate(inputs)
throughput = calculate_throughput(time.time() - start)# ❌ Don't rely on single run
throughput = benchmark_once()
# ✅ Do collect multiple runs and report statistics
throughputs = [benchmark_once() for _ in range(10)]
mean = np.mean(throughputs)
std = np.std(throughputs)
print(f"Throughput: {mean:.0f} ± {std:.0f} tok/s")# ❌ Don't change multiple variables at once
result1 = benchmark(batch_size=8, seq_len=2048, tp=8)
result2 = benchmark(batch_size=16, seq_len=4096, tp=16) # What caused change?
# ✅ Do change one variable at a time
baseline = benchmark(batch_size=8, seq_len=2048, tp=8)
result1 = benchmark(batch_size=16, seq_len=2048, tp=8) # Only batch changed
result2 = benchmark(batch_size=8, seq_len=4096, tp=8) # Only seq_len changed
result3 = benchmark(batch_size=8, seq_len=2048, tp=16) # Only tp changed# Save benchmark metadata
metadata = {
"date": "2026-04-04",
"model": "meta-llama/Llama-2-7b-hf",
"hardware": "trn1.32xlarge",
"neuron_sdk_version": "2.18.1",
"batch_size": 8,
"sequence_length": 2048,
"tensor_parallel_degree": 8,
"throughput": 137570,
"avg_step_time": 0.953,
}
with open("benchmark_results.json", "w") as f:
json.dump(metadata, f, indent=2)Next Steps:
- Run your first benchmark with scripts from this guide
- Compare results with baselines in benchmarks/
- Optimize based on findings
- Share results with the community!