You have run your test. JMeter has finished. Now you are staring at an HTML report with twenty-plus charts and tables, and you have no idea where to start. Relax -- most of those charts are variations of the same three questions: How fast was it? How many requests got through? How many broke? The trick is knowing which charts answer each question and in what order to read them. Think of a JMeter HTML report like a medical check-up report. The doctor does not read every line -- she goes straight to blood pressure, heart rate, and cholesterol. If those are fine, the rest is context. If one is off, she digs into the related details.
Before we read the report, let us make sure you know how to generate it. There are two ways: generate it as the test runs, or generate it from a saved .jtl file after the test. The second approach is more common in real projects because you can re-generate reports with different settings without re-running the test.
# Method 1: Generate during test run
# -n = non-GUI mode, -t = test plan, -l = results file, -e = generate report, -o = output dir
jmeter -n -t load_test.jmx -l results.jtl -e -o ./html-report
# Method 2: Generate from existing .jtl file (re-analyze without re-running)
jmeter -g results.jtl -o ./html-report-v2
# IMPORTANT: The output directory must be empty or non-existent
# If you get "directory not empty" error:
rm -rf ./html-report && jmeter -g results.jtl -o ./html-report
# Tip: Always save the raw .jtl file. You can re-generate reports
# with different thresholds, filters, or even compare runs later.The first thing you see when you open the report is the Dashboard tab. It shows the big-picture numbers: total requests, failure percentage, overall throughput, and average/min/max response times. Think of it as the headline of a newspaper -- it tells you if the story is good or bad, but not the details. If your failure rate is 0% and average response time is under your SLA, you are probably fine. If either number looks alarming, the remaining tabs will tell you where things went wrong.
| Dashboard Metric | What It Tells You | Red Flag |
|---|---|---|
| Total Requests | Volume of traffic generated | Too low = test ended early or ramp-up was too slow |
| Error % | Percentage of failed requests | Anything above 1% needs investigation |
| Throughput (req/sec) | Requests the server processed per second | Lower than expected = bottleneck somewhere |
| Avg Response Time | Mean time to get a response | Misleading with outliers -- check percentiles instead |
| 90th Percentile | 90% of requests were faster than this | Your realistic user experience metric |
| 99th Percentile | 1 in 100 users experienced this or worse | If this is 10x the median, you have tail latency problems |
| Min / Max | Best and worst single response | Max > 30 seconds usually means timeouts |
Never use Average Response Time as your primary metric. If 99 requests take 100ms and 1 takes 60 seconds, the average is 697ms -- which sounds "fine" but hides a horrible experience for that 1 user. Always look at percentiles (p90, p95, p99) instead.
This is arguably the single most important chart in the entire report. It plots response time on the Y-axis against test duration on the X-axis. A healthy system shows a flat line -- response times stay constant regardless of load. An unhealthy system shows an upward curve. The shape of the curve tells you what kind of problem you have.
Throughput measures how many requests the server processed per second. In a healthy ramp-up, throughput increases proportionally with users -- double the users, roughly double the throughput. At some point, throughput plateaus. That plateau is your system's maximum capacity. What happens after the plateau is the interesting part.
The throughput plateau is your answer to "how many requests per second can this system handle?" Write this number down -- it is one of the most valuable outputs of your entire test. When someone asks "can our system handle Black Friday?", you compare projected peak traffic against this throughput ceiling.
The Aggregate Report is a table that breaks down metrics by sampler (request). This is where you find out which specific API endpoint or page is the bottleneck. Sort by 99th percentile response time (descending) to find your slowest requests. Do not sort by average -- a single outlier distorts it. In most applications, you will find that 80% of the latency comes from 20% of the endpoints. The Aggregate Report helps you identify that 20%.
Sampler #Samples Avg p50 p90 p95 p99 Max Error% Throughput
─────────────────────────────────────────────────────────────────────────────────
Search Products 5,200 342 210 820 1,450 4,800 12,340 0.4% 17.3/sec
Checkout 1,800 890 650 1,900 3,200 8,500 30,100 2.1% 6.0/sec
Product Detail 10,400 120 85 280 420 950 3,200 0.0% 34.7/sec
Homepage 15,600 45 32 95 140 310 980 0.0% 52.0/sec
Login 2,600 180 140 380 520 1,200 5,600 0.5% 8.7/sec
# Reading this:
# - Checkout is the slowest (p99 = 8.5 seconds!) and has the highest error rate
# - Search is second-worst -- p99 is 4.8 seconds
# - Homepage and Product Detail are healthy
# - Checkout should be the FIRST thing you investigatePercentiles tell you about the distribution of response times. The gap between p50 (median) and p99 tells you how consistent your system is. If p50 is 100ms and p99 is 150ms, performance is very consistent -- every user gets a similar experience. If p50 is 100ms and p99 is 5,000ms, performance is wildly inconsistent -- most users are fine, but 1 in 100 waits 50 times longer. That inconsistency usually points to garbage collection pauses, lock contention, or occasional slow database queries.
| p99/p50 Ratio | What It Means | Likely Cause |
|---|---|---|
| < 2x | Very consistent performance | Well-tuned system, no contention issues |
| 2x - 5x | Moderate variance, acceptable for most apps | Minor contention under load, occasional slow queries |
| 5x - 10x | Significant inconsistency, investigate | GC pauses, connection pool waits, lock contention |
| > 10x | Severe tail latency, fix immediately | Resource exhaustion, timeouts, downstream failures |
Q: You ran a load test and the average response time is 200ms, but users are complaining about slow performance. How would you investigate?
A: I would stop looking at the average and check the percentile distribution instead. The average can be misleading -- if 95% of requests are 50ms but 5% are 3 seconds, the average might look "okay" at 200ms, but 1 in 20 users is having a terrible experience. I would check p90, p95, and p99 response times. I would also look at the Response Times Over Time chart to see if the slowness is constant or happens in bursts. If it is burst-based, it could be GC pauses or periodic background jobs. If it is constant, it is more likely a consistently slow endpoint. The Aggregate Report would show me which specific endpoints are contributing to the tail latency.
Key Point: Read a JMeter report in this order: Dashboard (pass/fail), Response Times Over Time (trend), Throughput (capacity), Aggregate Report (which endpoint), Percentiles (consistency). This top-down approach takes you from "is there a problem?" to "what exactly is the problem?" in five minutes.
Key Point: Read JMeter reports top-down: Dashboard for pass/fail, Response Times Over Time for trends, Throughput for capacity, Aggregate Report for per-endpoint breakdown, and percentiles for consistency.