Analyzing Results in JMeter
A beginner-friendly but production-minded guide to turning a pile of numbers into a clear story: what each measurement means, how to read the charts, how to find the cause of a problem, and how to report it honestly.
Imagine a doctor who runs a full set of blood tests on a patient and then simply hands over a printout of two hundred numbers. The patient stares at the page, none the wiser. What matters is not the printout but the reading of it: which numbers are normal, which are worrying, which belong together, and what to do next. The tests gather the data, and the analysis turns it into advice.
A JMeter test works the same way. Running the test is the easy part. JMeter can fire thousands of requests and record every one of them without complaint. The hard and valuable part comes afterwards, when you must decide whether the system passed or failed, where it started to struggle, why it struggled, and what the team should do about it. A tester who cannot analyse results can only report that a test was run. A tester who can analyse results can tell the team something they can act on.
This guide teaches result analysis from zero. You will learn where results come from, what each column and chart means, how to read averages, medians, and percentiles without being fooled, how to spot healthy and unhealthy shapes, how to generate and read the HTML report, how to study errors systematically, how to compare runs, and how to write up your findings. Then we go deeper into scale, security, design patterns, anti-patterns, and troubleshooting. Every new term is explained the first time it appears, and every big idea comes with an everyday comparison.
WWhat Does Analyzing Results Mean?
Analysis is the step that turns measurements into decisions.
Apache JMeter is a free, open-source tool from the Apache Software Foundation. It pretends to be many users at the same time and measures how a system behaves under that crowd. Each request it sends produces a record called a sample, which holds the time taken, whether the request passed, how many bytes came back, and more. Analyzing results means studying those samples to answer questions about the health of the system.
The questions analysis answers
Did it pass?
Were the response times and error rates within the targets the team agreed before the test?
Where did it bend?
At what load did response times begin to climb or errors begin to appear?
Why did it bend?
Which part of the system, such as the database or a service, was the bottleneck?
Is it better or worse than before?
How does this run compare with earlier runs and with the baseline?
What should we do?
Which fix, change, or decision follows from the evidence?
A football coach watching a match does not just count goals. The coach studies where the team lost the ball, which players tired, and when the opponent found gaps. Analysis is that kind of watching, applied to a load test.
A response time is the time between sending a request and receiving the complete answer, measured in milliseconds. One millisecond is one thousandth of a second, so a value of 250 means a quarter of a second.
WWhy Raw Numbers Are Not Enough
A number without context can mislead as easily as it can inform.
Suppose your test reports an average response time of 800 milliseconds. Is that good? It depends. It depends on the target, on how many users were running, on whether the first minute of warm-up was included, on whether errors were counted, and on whether a few extreme requests dragged the figure up. Without context, the number has no meaning.
Four traps for the careless reader
- The average trap: a few very slow requests can hide behind a pleasant average.
- The error trap: failed requests often return quickly, so a failing system can look fast.
- The warm-up trap: the first minutes of a test behave differently from the steady period, and mixing them blurs the picture.
- The single-run trap: one run can be affected by chance, other users, or a busy machine, so one result is not proof.
Careful analysis
- Reads several measurements together
- Separates warm-up from steady state
- Checks errors before reading speed
- Repeats important runs
- States conclusions with evidence
Careless analysis
- Quotes one average from one run
- Includes warm-up and shutdown in the figures
- Ignores failed requests
- Compares runs that used different settings
- Reports hopes as findings
A weather report that says “average temperature today: 15 degrees” hides a freezing night and a hot afternoon. The average is true and almost useless for deciding what coat to wear.
Many expensive production incidents begin with a test report that looked good and was read carelessly. Time spent learning to read results is cheap insurance.
WWhere Results Come From
Every sample flows from a sampler to listeners, and optionally to a file.
When a virtual user sends a request, the sampler records the outcome as a sample. JMeter hands that sample to every listener in scope, which is an element that displays or saves results. A listener can draw a table, draw a chart, or write the sample to a file. Understanding this flow explains why the same data can appear in many forms.
flowchart LR
S["Sampler sends request"] --> R["Sample: time, status, bytes, label"]
R --> L1["Listeners: live tables and charts"]
R --> L2["Results file: JTL on disk"]
L2 --> H["HTML dashboard report"]
L2 --> X["Spreadsheet or script analysis"]
R --> B["Backend Listener: external dashboard"]
| Route | Best for | Cost during the test |
|---|---|---|
| Live listeners in the window | Debugging and small runs | High at scale |
| Results file written during the run | The permanent record of every sample | Low |
| HTML report built from the file | Reading and sharing after the run | None during the run |
| Backend Listener to a dashboard | Live team viewing on a screen | Moderate |
A cashier records every sale in the till. The shop can watch the till display live, keep the paper roll as a record, or feed the roll into accounting software for end-of-month reports. The sales are the same, and the views differ.
For any run that matters, write a results file. A file can be analysed again tomorrow in new ways. A window that was closed cannot.
TThe Results File: Rows and Columns
The JTL file is a plain table with one row for every request.
The results file is often called a JTL file, short for JMeter test log. It commonly uses the CSV format, which means comma-separated values: a plain text table where each line is a row and commas separate the columns. You can open it in a spreadsheet, a text editor, or a script. The exact columns depend on your settings, but a typical file includes the ones in the table.
| Column | Plain meaning |
|---|---|
| timeStamp | When the request started, as a number of milliseconds since a fixed date in 1970 |
| elapsed | How long the request took from start to the last byte of the answer |
| label | The name of the sampler, which becomes the row name in reports |
| responseCode | The status number the server returned, or an error name when none arrived |
| responseMessage | The short text that goes with the status |
| threadName | Which virtual user sent the request |
| success | True or false: did the sample pass, including any assertions? |
| failureMessage | Why an assertion failed, when one did |
| bytes and sentBytes | The size of the answer and of the request |
| grpThreads and allThreads | How many virtual users were active in the group and in total at that moment |
| Latency | Time until the first byte of the answer arrived |
| Connect | Time taken to open the connection |
Imagine a visitor book at a museum that records the time of arrival, the name, the exhibit visited, how long they stayed, and whether they were satisfied. The JTL file is that visitor book for every request.
Which columns appear is controlled by settings, and defaults can differ between versions. Open the first lines of your own file to see exactly what you have.
TElapsed Time, Latency, and Connect Time
Three clocks tick during every request, and they measure different things.
A web request is not one single moment. It is a short sequence: open a connection, send the request, wait for the server to start answering, and receive the whole answer. JMeter records several times along that sequence.
Connect time
The time to open the connection to the server. For secure connections, setting up the encryption may be counted as part of it.
Latency
The time from sending the request until the first byte of the answer arrives. It shows how quickly the server began to respond.
Elapsed time
The time from the start of the request until the last byte of the answer arrives. This is the response time that most reports show.
What the gaps tell you
| Pattern | Likely meaning |
|---|---|
| High connect time | Slow network, a busy server not accepting connections, or heavy encryption setup |
| High latency, small gap to elapsed | The server took a long time to think, then answered quickly |
| Low latency, large gap to elapsed | The answer started quickly but was large or slow to transfer |
| All three low | A healthy, quick exchange |
Ordering at a restaurant: the connect time is getting a waiter’s attention, the latency is the wait until the first dish appears, and the elapsed time is until the last plate is on the table. A slow kitchen and a slow delivery are different problems.
When response times rise, look at latency and connect time before blaming the application. A busy network or a connection limit can look exactly like a slow application.
LLabels, Transactions, and Sub-Results
Names decide how your numbers are grouped.
Every sample has a label, which is normally the name of the sampler that produced it. Reports group samples by label, so each row in a summary is one label. This makes good naming essential: two requests with the same name are merged into one row, and requests with vague names produce reports nobody can read.
Transaction Controllers
A Transaction Controller groups several requests into one business step, such as “Checkout”, and reports their combined time under one label. It can produce one parent sample that holds the total, or it can add the total alongside the individual requests, depending on its settings. This is how business people prefer to read results: not “request 14 took 300 milliseconds” but “checkout took 1.2 seconds”.
One clear name per step
Name every sampler for what it does, and keep names stable between runs so results can be compared.
Group by business step
Wrap related requests in a transaction, so reports show steps that people recognise.
Mind the double count
When both transactions and their inner requests appear in a total, the same time is counted twice.
An airline reports the journey time from home to hotel, not just the length of each taxi, queue, and flight. Transactions give your report the same door-to-door view.
When a report mixes transaction rows with their inner request rows, totals such as overall throughput and overall average can be inflated or skewed. Read the settings that say how transactions are reported, and filter if needed.
SSuccess, Failure, and Failure Messages
A sample fails for more reasons than a bad status code.
Each sample carries a success flag. By default, JMeter’s web sampler marks a response as failed when the status code is in the error range, such as 404 for a missing page or 500 for a server error. Assertions can mark a sample as failed even when the status code looked normal, because the content was wrong. When a sample fails, the file records a failure message explaining which check failed.
Four kinds of failure
| Kind | Example | What it usually means |
|---|---|---|
| Error status code | A server error number in the response code column | The application or a service behind it failed |
| Assertion failure | Expected text was missing from the page | The response was fast but wrong |
| Connection problem | The response code names an exception instead of a number | The request never reached the server, or the connection broke |
| Timeout | The request exceeded a time limit you set | The server was too slow or stopped answering |
A parcel can fail to arrive because the courier never left, because it was delivered to the wrong house, or because the box was empty. All three are failures, and the fix is different each time.
Always group failures by label and by message before drawing conclusions. A hundred failures with one message point to one cause. A hundred failures with a hundred messages point to something messier.
TThe Basic Statistics: Count, Minimum, and Maximum
The simplest numbers answer the simplest questions.
Before any clever calculation, three plain numbers deserve a look. The count of samples tells you how much evidence you have. The minimum is the fastest response in the run, and the maximum is the slowest. Together they give the outer limits of the experience.
Reading them well
- Count: compare it with what you expected, which is users times loops times requests per journey. A shortfall means requests were skipped or threads stopped early.
- Minimum: shows the best case when everything is quick. It rarely matters on its own, but it gives a floor for what the system can do.
- Maximum: shows the worst single request. A very large maximum with a normal average points to a rare stall, such as a pause for housekeeping, a retry, or a time-out.
| What you see | Reading |
|---|---|
| Count lower than expected | A thread stopped early or a request was skipped |
| Minimum and maximum close together | Very consistent behaviour |
| Maximum hundreds of times the average | Rare, extreme outliers worth investigating |
| Maximum equals a timeout setting | Some requests ran until the limit and were cut off |
Checking the shortest and longest journey times on your daily commute tells you the range of your mornings. The shortest tells you what a clear road feels like, and the longest tells you what the worst day looked like.
A maximum that equals your configured timeout is a strong clue. It means some requests did not finish at all, so the real slowest time is unknown.
TThe Average and Its Weakness
The average is the first number everyone quotes, and the first one that misleads.
The average, also called the mean, is the sum of all response times divided by the number of samples. It is easy to calculate and easy to understand, which is why it is so popular. Its weakness is that extreme values pull it strongly.
A small example
Take five response times: 100, 100, 100, 100, and 1,100 milliseconds. The total is 1,500, and the average is 300. Four of five users had a pleasant 100 millisecond experience. One had an unpleasant one-second wait. The average of 300 describes nobody.
If a billionaire walks into a small cafe, the average wealth in the room jumps enormously, though nobody else became richer. Slow outliers drag a response time average in just the same way.
When the average is still useful
- As a quick first impression of a run.
- For tracking a stable trend across many similar runs.
- When the distribution is tight, with few outliers.
Never judge a system by its average alone. Always read it beside the median and a high percentile, and look at the maximum. If they disagree, the average is probably being pulled by outliers.
TThe Median: The Typical Experience
The middle value ignores extremes and shows what most users felt.
The median is found by sorting all response times from smallest to largest and picking the one in the middle. Half the requests were faster than the median, and half were slower. In the earlier example the sorted times are 100, 100, 100, 100, 1,100, and the middle one is 100. The median says 100, which matches what most users experienced.
| Average versus median | What it suggests |
|---|---|
| Close together | Even times, with few extreme values |
| Average much higher than median | A group of slow requests is pulling the average up |
| Both rising together over time | The whole system is slowing down |
| Median steady, average rising | Most users are fine, but a growing minority suffers |
Line up your classmates by height and take the person in the exact middle. It does not matter whether the tallest student is two metres or three. The median is that middle person.
The gap between the average and the median is a quick health signal. A widening gap means a tail of slow requests is growing, and that is the moment to look at percentiles.
PPercentiles: Describing the Slow Tail
A percentile says what share of requests finished within a given time.
A percentile answers the question: below what time did this share of requests finish? The 90th percentile is the time below which ninety percent of requests finished. If the 90th percentile is 800 milliseconds, nine out of ten requests were faster, and one out of ten was slower. Percentiles describe the slow tail that the average hides.
The usual ones
Nine in ten
A good general measure of the experience of almost everyone, but the slowest tenth is hidden.
Nineteen in twenty
A common target in service agreements, which says how bad the bad days are.
Ninety-nine in a hundred
Focuses on the slow tail, which often matters for heavy users and busy systems.
An airline that says “ninety-five percent of our flights arrive within fifteen minutes of schedule” tells you much more than one that says “our average delay is five minutes”. The first describes your worst likely day. The second hides it.
Why teams set targets as percentiles
- They protect almost every user, not just the typical one.
- They are not distorted by one freak outlier.
- They reflect what people remember: the slow experiences.
Percentiles cannot be averaged across runs or labels without care. The average of two 95th percentiles is not the 95th percentile of the combined data. Calculate them from the full samples when you can.
TStandard Deviation: How Scattered Are the Times?
The spread of the times is a measure of consistency, and users feel consistency.
Standard deviation is a number that describes how far response times typically stray from their average. A small value means most requests took about the same time. A large value means they were scattered widely. It is measured in the same unit as the response time, so a deviation of 50 means the typical stray was about fifty milliseconds.
Why consistency matters
Two systems can both average 200 milliseconds. In the first, every request takes between 190 and 210. In the second, half take 20 and half take 380. The averages match, but the second system feels erratic, and users notice erratic behaviour more than steady slowness.
| Deviation compared with the average | What it suggests |
|---|---|
| Much smaller than the average | Steady, predictable behaviour |
| About the same as the average | Quite scattered, a mix of fast and slow requests |
| Larger than the average | Very uneven, probably a few extreme outliers |
| Rising as the test goes on | Increasing contention or queueing in the system |
Two commuters both spend an average of forty minutes travelling to work. One always takes between thirty-eight and forty-two. The other takes anywhere from fifteen to ninety. The second cannot plan the morning, and that unpredictability is what a large deviation measures.
When a label mixes different requests, its deviation may look large simply because the requests differ naturally. Check that rows describe comparable things before worrying about the spread.
TThroughput: How Much Work Gets Done
Throughput counts finished requests over time and speaks about capacity.
Throughput is the number of requests completed in a given period, such as per second or per minute. JMeter reports it for each label and for the whole test. In essence it is the number of samples divided by the time between the start of the first request and the end of the last. Because it includes any pauses in your plan, it describes what the system actually handled in your test, not an idealised maximum.
Reading throughput with other numbers
| Observation | Likely reading |
|---|---|
| More users, higher throughput, steady response times | The system has capacity to spare |
| More users, flat throughput, rising response times | A bottleneck has been reached |
| More users, falling throughput | Overload: the system is doing wasted work |
| High throughput with high error rate | Quick failures are inflating the count |
Think of a toll booth on a motorway. Response time is how long one car waits. Throughput is how many cars pass in an hour. A booth may serve each car quickly, yet still be limited by how many lanes are open.
Throughput counts failed requests as well as passed ones. A system that fails instantly can show impressive throughput. Always read it next to the error rate.
EError Rate: The Number to Read First
Speed means nothing if the requests are failing.
The error rate, shown as Error % in the reports, is the share of samples that failed. It is the first number a careful analyst reads, because a high error rate changes the meaning of every other number. Failed requests often return quickly, so a failing system can show excellent response times and high throughput.
How to read it
- Zero: good, but check that your assertions are strong enough to catch wrong content.
- A small steady rate: may be acceptable if your targets allow it, but find out what the errors are.
- A rate that begins at a certain load: shows the point where the system starts to fail, which is a key finding.
- A sudden burst: suggests an event such as a restart, a deployment, or a dependent service failing.
A restaurant that closes its doors has no waiting queue and a service time of zero seconds. The numbers look wonderful, and the business is failing. The error rate is the sign on the door.
An error rate of zero from a test with no content assertions is weak evidence. The system may be returning polite error pages with normal status codes. Strong assertions make the error rate trustworthy.
BBytes and Bandwidth
The size of the traffic shows whether the network is the limit.
JMeter records how many bytes each response contained, and reports data rates, such as kilobytes received per second and sent per second. A byte is a small unit of data, and a kilobyte is about a thousand bytes. These figures tell you how much traffic the test generated and help you notice when the network, not the application, is the bottleneck.
| Figure | What it tells you |
|---|---|
| Average bytes per response | Whether pages are heavy, and whether sizes change under load |
| Received KB per second | How much data flowed back to the load generator |
| Sent KB per second | How much data the requests carried to the server |
Useful clues in the sizes
- A sudden drop in average bytes with a rise in speed often means pages have become error messages.
- A flat data rate while users rise suggests a bandwidth ceiling somewhere in the path.
- Very large responses may explain a large gap between latency and elapsed time.
A water pipe has a fixed width. Opening more taps will not increase the flow once the pipe is full. A flat data rate under rising load is that full pipe.
Compare the bytes of the same label between a good run and a bad run. If the sizes differ, the responses were not the same, and the speed comparison may not be fair.
LLinking Users, Response Time, and Throughput
A simple rule ties three numbers together, and it is a powerful sanity check.
Users, response time, think time, and throughput are not independent. A well-known rule, often called Little’s Law, says that the number of users in a steady system equals the throughput multiplied by the time each user spends in one cycle. A cycle is the response time plus the think time. In plain words: if each user completes one request every ten seconds, then a hundred users produce about ten requests per second.
flowchart LR
U["Number of active users"] --> C["Each user's cycle: response time plus think time"]
C --> T["Throughput: requests completed per second"]
T --> CHK["Check: users divided by cycle time should match throughput"]
CHK --> OK["Match: results are consistent"]
CHK --> BAD["Mismatch: suspect warm-up, errors, or a faulty plan"]
A worked idea with numbers
Suppose a run has one hundred users, an average response time of one second, and a think time of nine seconds. Each cycle lasts about ten seconds. The expected throughput is about ten requests per second. If the report shows two requests per second, something is wrong: users may be stuck waiting, many requests may be failing slowly, or the plan may not do what you think.
If a hundred people each visit a shop once every ten minutes, the shop sees about ten customers per minute. If the till records only two, either the shop has a long queue outside, or the people are not visiting as often as you thought.
Use this rule as a quick check on every run. A report that violates it is not a reason to celebrate or panic, but a reason to investigate before trusting any of the numbers.
SSteady State and Warm-Up
Judge the system when it is settled, not while it is still waking up.
Every test has three stages. During the ramp-up, users arrive and the load climbs. During the steady state, all users are running and the load is constant. During the ramp-down, users finish and leave. Systems behave differently in each stage. Caches are empty at the start, connections are still opening, and code may still be warming up, so the first minute is often slower than the rest.
Ramp-up
Throughput climbs and response times may creep up as the system warms. Do not judge the system by this stage.
Steady state
Everything is running at full load. This is the stage worth measuring and reporting.
Ramp-down
Users leave and throughput falls. Do not mistake this fall for a problem.
A stadium filling for a match looks different from a stadium full and seated, which looks different again from a stadium emptying. You would not judge the crowd’s behaviour by the hour when the gates opened.
Practical habits
- Make the steady state long enough to contain thousands of samples, and several times longer than the ramp-up.
- When you build a report, exclude the early and late periods, or read statistics for the steady period only.
- Always note the length of each stage when you compare runs.
If the ramp-up lasts as long as the whole test, there is no steady state to measure. Every figure then mixes a changing load into one blurred number.
RReading the Shape of a Healthy Run
A healthy chart is boring, and boring is the goal.
Charts show things that tables hide: trends, steps, spikes, and drifts. Learning the look of a healthy run helps you notice quickly when a run departs from it.
Signs of health
- Response times form a narrow band that stays at about the same height during the steady state.
- The average and the median lie close together and move very little.
- Throughput rises during ramp-up, then levels off at a steady figure.
- The number of active users matches the plan, flat at the top.
- Error counts stay at zero, or at a flat, low level.
A calm lake reflects the sky with no ripples. A healthy chart is the same: smooth, flat, and predictable. A stone dropped in the lake makes ripples, and a burst of slow requests makes a spike.
A flat chart proves the system is steady. It does not prove the system is correct. If every request returns a fast error page, the chart can look beautifully calm. Always pair charts with error rates.
UUnhealthy Shapes: A Pattern Guide
Most problems draw one of a few familiar shapes.
Experienced analysts recognise shapes the way a doctor recognises rashes. The table lists common shapes, what they often mean, and what to try next. Treat these as clues, not verdicts, because many different causes can produce the same picture.
| Shape on the chart | Common meaning | What to try next |
|---|---|---|
| Response times climb steadily during steady state | A resource is slowly filling, such as memory, connections, or a queue | Watch server memory, connection counts, and queue lengths |
| A sudden step up, then flat | A limit was reached, such as a pool size | Check pool and thread limits at that load level |
| Regular spikes at even intervals | A scheduled job, memory clean-up, or cache expiry | Compare spike times with server logs |
| Wide, fuzzy band that keeps widening | Contention: requests fighting for a shared resource | Look at locks, database waits, and shared services |
| Rare huge outliers, band otherwise flat | Occasional stalls, retries, or time-outs | Inspect the slowest requests one by one |
| Throughput falls while users rise | Overload with wasted work | Reduce the load and find where the fall began |
| Errors begin at one load level | A capacity limit or a failing dependency | Study the error types at that moment |
| Everything drops to near zero | Requests stopped completing, or the test ended | Check whether the server crashed or the test stopped |
A doctor who sees a fever knows it could be a hundred illnesses. It tells her something is wrong and where to look next. A chart shape works the same way: it directs your attention, and then you investigate.
Do not blame the server before checking the load generator. A test machine short of memory or processor power can draw the same sluggish shapes, and you would then be measuring your own computer.
FFinding the Knee: Capacity and Saturation
Every system has a load level where it stops coping gracefully.
If you raise the load step by step and plot response time against users, a typical system shows three zones. At light load, response times are low and flat. As load grows, a point arrives where response times begin to curve upward. This point is called the knee. Beyond it, response times rise steeply and throughput stops growing or falls. The load at the knee is a practical measure of capacity, and finding it is one of the main goals of a load test.
flowchart LR
A["Light load: response time flat, throughput rising"] --> B["Approaching the knee: response time begins to curve upward"]
B --> C["The knee: throughput stops growing"]
C --> D["Saturation: response time rises steeply, errors appear"]
D --> E["Overload: throughput falls, failures dominate"]
| Zone | Response time | Throughput | Errors |
|---|---|---|---|
| Comfortable | Low and flat | Rising with users | None |
| Near the knee | Starting to rise | Rising more slowly | Rare |
| Saturated | High and climbing | Flat | Appearing |
| Overloaded | Very high or timing out | Falling | Many |
Cars on a motorway flow freely until the road fills. Past a certain density, every extra car slows everyone, and eventually traffic crawls. The knee is the density at which the flow stops improving.
Plan your capacity from a load comfortably below the knee, not at it. Real systems need headroom for bursts, failures, and growth.
LLive Listeners: A Quick Tour
Several listeners show results while the test runs, each with a different strength.
View Results Tree
Shows every request and response in detail. Excellent for debugging a few users, and too heavy for large runs.
Summary Report
One row per label, with counts, times, error percentage, and throughput. Light and quick to read.
Aggregate Report
Like the summary, but adds the median and the 90th, 95th, and 99th percentiles.
Graph Results
A live line chart of response times with average, median, deviation, and throughput. Fun and heavy, for small runs.
Aggregate Graph
Draws bar charts of aggregate figures for each label, which makes comparing requests easy.
Response Times Graph
Plots response times over time for each label, so you can see which requests change as the test runs.
A car has a speedometer, a fuel gauge, a trip counter, and a warning light. Each answers a different question about the same journey. Listeners are the gauges of a load test.
A rule of thumb
Use the lightest listener that can answer your question, and disable the heavy ones before big runs. For any run that matters, write a results file and do the real analysis afterwards, when the machine is not busy generating load.
Several listeners keep every sample in memory. Leaving them enabled in a large run can slow or crash the load generator, and the numbers they show will then be unreliable.
RReading the Summary Report
A short routine turns a table of numbers into a verdict.
| Column | Plain meaning | What to look for |
|---|---|---|
| # Samples | How many requests of this kind were sent | Does it match the plan’s expectation? |
| Average | The mean response time | Compare with target and median |
| Min and Max | The fastest and slowest times | A huge maximum signals outliers |
| Std. Dev. | The spread of times | Large relative to average means uneven behaviour |
| Error % | The share of failed requests | Read this first |
| Throughput | Requests handled per unit of time | Does it match what the plan should produce? |
| Received and Sent KB/sec | Data rates | A flat rate under rising load hints at a bandwidth limit |
| Avg. Bytes | Average size of an answer | Sudden shrinking can mean error pages |
A calm reading routine
Read Error % first
If it is not near zero, find out why before reading anything else.
Check the sample counts
Confirm they match users times loops times requests per journey.
Compare average and maximum
A wide gap suggests outliers worth studying.
Look at each label separately
The total row hides which request is the slow one.
Write a one-line verdict
For example: passed the targets for all labels, with no errors and steady times.
A school report card lists every subject plus an overall result. A good teacher reads each subject, not just the total, because the total can hide the one subject where the child is failing.
The summary table has no percentiles. For targets stated as percentiles, move to the Aggregate Report or the HTML dashboard.
RReading the Aggregate Report
The aggregate table adds the median and the percentiles that targets are written in.
The Aggregate Report looks like the Summary Report but replaces some columns with the median and three percentiles: the 90th, 95th, and 99th. Because many service targets are stated as percentiles, this is often the first table that gets copied into a report.
| Column | Plain meaning |
|---|---|
| Label | The request or transaction name |
| # Samples | The number of requests of this kind |
| Average and Median | The mean and the middle response times |
| 90%, 95%, and 99% Line | Response times below which that share of requests finished |
| Min and Max | The fastest and slowest times |
| Error % | The share of failed requests |
| Throughput | Requests per unit of time, scaled to a convenient unit |
| Received and Sent KB/sec | Data rates in each direction |
Reading across a row
Read each row from left to right as a story. The median tells you the typical experience. The 90th percentile says how bad it gets for most unlucky users. The 99th says how bad the worst days are. The maximum is the single worst moment. If these figures rise gently, the system is consistent. If they jump sharply between the median and the 99th, there is a slow tail to investigate.
A bus company can report the typical journey time, the time that nine out of ten journeys beat, and the time of the worst journey of the month. The three together describe the service far better than any single figure.
Save the aggregate table to a file at the end of a run, or read it from the results file with the report generator. A table on screen is gone when the window closes.
MMore Charts: Core Graphs and Plugin Graphs
Several extra charts answer questions that tables cannot.
Charts show how numbers move over time, which tables cannot. JMeter has core chart listeners, and an optional add-on collection, installed through the JMeter Plugins Manager, adds many more. The exact set depends on your version, so use the table as a map.
| Chart | Question it answers | Source |
|---|---|---|
| Response times over time | Did response times drift or spike during the run? | Core, and the HTML report |
| Active threads over time | Did the load follow the plan? | Plugin, and the HTML report |
| Transactions per second | How much work finished each second? | Plugin, and the HTML report |
| Response time versus threads | How do times change as load rises? | Plugin, and the HTML report |
| Response time distribution | How many requests fell in each time band? | HTML report and plugin |
| Bytes throughput over time | Was the network the limit? | HTML report and plugin |
| Latency over time | Did the server start answering later? | HTML report and plugin |
A weather app shows temperature curves, rain maps, and wind arrows. Nobody asks which is the single correct view, because each answers a different question about the same sky.
Many of these charts also appear in the HTML dashboard report with no add-on at all. For most analysis, the report is the better home for them.
TThe HTML Dashboard Report: An Overview
The best way to read a finished run is to turn the results file into a small website.
JMeter can turn a results file into an HTML dashboard report, a folder of web pages you open in a browser. It contains summary tables, response-time charts over time, throughput charts, percentile charts, and error breakdowns, all built from the saved samples. It costs nothing during the test, because it is generated afterwards.
Rich and shareable
One folder of pages that anyone can open in a browser, attach to a ticket, or archive.
No cost during the run
The report is built after the test, so it never slows the load generator.
Percentiles and charts built in
Everything an aggregate report offers, plus charts over time and error summaries.
Needs a results file
It can only be built from a saved file with the right columns.
A sports commentator calls the match live with quick impressions. The next morning a journalist publishes a full match report with statistics and photographs. The dashboard report is the journalist.
Get into the habit of producing a dashboard report even for small runs. The ritual becomes automatic, and your history of reports becomes your best evidence over time.
GGenerating the Report Step by Step
Two routes lead to the same report: during the run, or from an existing file.
JMeter supports two ways of producing the report. One builds it automatically at the end of a non-GUI run, when you tell JMeter to write a report folder. The other builds it from an existing results file at any time later. In both cases, the report folder must be new or empty, and the results file must be in the CSV form with the columns the generator needs, such as the time stamp and the elapsed time. Check the documentation for your version for the exact command options.
flowchart TD
A["Run the test in non-GUI mode"] --> B["Results file written to disk"]
B --> C{"Build report now or later?"}
C -->|"Now"| D["Ask JMeter to build the report at the end of the run"]
C -->|"Later"| E["Run the report generator on the saved results file"]
D --> F["Report folder with index page"]
E --> F
F --> G["Open the index page in a browser"]
G --> H["Read, compare, and share"]
Save a results file
Run in non-GUI mode with a results file, and keep the default fields the report needs.
Choose a fresh folder
Give the report an empty or non-existent folder, so old files do not mix in.
Generate
Ask JMeter to build the report, either at the end of the run or from the saved file.
Open the index page
Open the main page of the folder in a browser and explore.
Developing a photograph from a film roll can be done at the end of a trip or any day later. The film, the results file, is what matters. Keep it safe, and you can develop it again whenever you like.
If the report folder already contains files, generation may refuse to run or produce confusing mixtures. Use a new folder for every report, named by date and purpose.
AA Tour of the Dashboard
The report has a few main areas, and most analysis starts on the first page.
| Area | What it shows | Why it helps |
|---|---|---|
| Test and report information | Source file, start and end times, and filters in use | Confirms which run you are reading |
| Apdex table | A satisfaction score for each label | A quick view of which requests make users unhappy |
| Requests summary | The share of passed and failed requests | A one-glance success rate |
| Statistics table | Counts, errors, averages, percentiles, and throughput per label | The main reading table |
| Errors table | Types of errors and their counts | Shows what is failing and how often |
| Top 5 errors by sampler | The labels with the most errors | Points to the worst offenders |
| Charts section | Over time, throughput, and response time charts | Shows how the run evolved |
A car dashboard puts the speed, the fuel, and the warning lights at the front, and the detailed service history in the glove box. The first page of the report is the front dashboard, and the charts are the service history.
A sensible reading order
- Check the test information, so you know which run it is.
- Check the requests summary and the errors table.
- Read the statistics table, label by label.
- Open the charts to see the shape of the run.
Resist the urge to jump straight to the colourful charts. The tables give the verdict, and the charts give the explanation.
AApdex: A Satisfaction Score
One number between zero and one that says how happy users probably were.
Apdex stands for Application Performance Index. It turns response times into a single satisfaction score between zero and one. You choose two thresholds. Responses faster than the first are called satisfied. Responses between the first and the second are tolerating. Slower ones are frustrated. The score counts satisfied responses fully, tolerating ones as half, and frustrated ones as nothing, divided by the total.
A worked idea
Imagine one hundred requests. Seventy are satisfied, twenty are tolerating, and ten are frustrated. The score is seventy plus half of twenty, which is eighty, divided by one hundred, giving 0.80. A higher score means a happier crowd.
| Score range | Reading |
|---|---|
| 0.94 to 1.00 | Excellent |
| 0.85 to 0.93 | Good |
| 0.70 to 0.84 | Fair |
| 0.50 to 0.69 | Poor |
| Below 0.50 | Unacceptable |
A restaurant survey might count a meal that arrived quickly as a happy customer, a slightly slow meal as an indifferent one, and a very slow meal as an angry one. The Apdex is the happiness score from that survey.
The thresholds are set in properties, and a single pair rarely suits every request. A search and a report download deserve different expectations. Agree on thresholds before the test, and do not change them to flatter a result.
TThe Statistics and Errors Tables
Two tables carry most of the verdict.
The statistics table
This table has one row per label, plus a total. Typical columns include the sample count, the error count and percentage, the average, minimum, and maximum, the median, three percentiles, and the throughput, with the data rates. It is the main reading table of the report. Compare each label with its target, and look for rows that stand out: a much higher percentile, an error percentage above zero, or an unusually low throughput.
The errors table
This table groups failures by type and shows how many times each occurred, and what share of all errors it represents. It is the fastest way to answer the question “what is failing?”. A single dominant row means one cause. Many rows with small counts mean several different problems.
| What you see | What to do |
|---|---|
| One error type dominates | Fix or investigate that one cause first |
| Many different error types | Look for a shared cause, such as an overloaded dependency |
| Errors concentrated in one label | Study that request and its dependencies |
| Errors spread across all labels | Suspect a system-wide issue, such as the network or a restart |
A complaints book at a shop shows what customers complain about most. A hundred complaints about one broken door is a different problem from a hundred different small complaints.
The errors table shows what failed, not why. Follow it with a look at the failing requests in a small debugging run, and with the server’s own logs for the same period.
CReading the Charts Over Time
Charts tell you when something changed, which is half the clue to why.
The charts section of the report plots measurements against time. The time axis is divided into slices, whose size is set by a property and is often one minute by default. Each slice shows a summary of the samples that fell inside it. Smaller slices show more detail and more noise. Larger slices smooth the picture and hide short spikes.
Response times over time
Shows whether response times stayed flat, drifted upward, or spiked at a particular moment.
Active threads over time
Shows whether the number of users followed the plan. Use it to line up other charts with load.
Hits and transactions per second
Shows the rate of finished work, and whether it levelled off as users rose.
Codes per second
Shows when errors appeared and what kinds they were over time.
Percentiles over time and distribution
Show how the slow tail evolved and how times were spread across bands.
A heart monitor in a hospital draws a line against time. The doctor reads not only the height of the beats but when a change began. The time axis of a chart turns a number into a story.
Lining charts up
Always read charts together, on the same time range. If response times rose at the moment active users reached a level, load is the likely cause. If response times rose while users were flat, something else changed, such as a background job, a restart, or a failing dependency.
Note the clock times of any event during the run, such as a deployment or a restart. You can then find it on the charts, and it explains many mysterious spikes at once.
FFiltering and Focusing
Sometimes the useful answer sits inside a slice of the data.
A full results file may contain the ramp-up, the steady state, the ramp-down, debug requests, and requests you do not care about. Reports let you narrow the data. You can include or exclude samples by label, using patterns, and settings let you skip early and late periods. Narrowing helps in several ways.
Why filter
- Remove warm-up and shutdown so statistics describe the steady period only.
- Remove noise, such as images and advertising requests, when you want to study your own pages.
- Focus on one business step, such as checkout, to understand it in depth.
- Exclude debugging requests that you added only to inspect values.
| Filter | Use it to | Caution |
|---|---|---|
| By label pattern | Focus on or exclude certain requests | A wrong pattern silently hides real data |
| By time range | Skip warm-up and shutdown | Record the range, so others can reproduce it |
| By success | Study only passed or only failed samples | Hiding failures can flatter the numbers |
When studying traffic, you might look at weekday rush hours only, or only at one junction. Narrowing the view clarifies the question, but you must say what you removed, or the reader will assume you showed everything.
Filtering is also the easiest way to fool yourself. Always state in the report which filters were applied, and keep a copy of the unfiltered numbers.
AAnalysing Errors Systematically
A short decision path turns a list of errors into a cause.
When errors appear, panic is a poor guide. A calm sequence of questions narrows the cause quickly. The diagram shows the path. At each step you ask what the data says, then follow the answer.
flowchart TD
A["Errors appear in the report"] --> B{"Are they from the test itself?"}
B -->|"Yes: bad data, missing values, wrong plan"| C["Fix the plan and run again"]
B -->|"No"| D{"Do they start at a certain load or time?"}
D -->|"At a load level"| E["Capacity limit: study response times and server resources"]
D -->|"At a clock time"| F["Event: deployment, restart, scheduled job, dependency failure"]
D -->|"From the very start"| G["Environment or configuration problem"]
E --> H["Check server metrics for that moment"]
F --> H
G --> H
H --> I["Record cause, evidence, and recommended action"]
Group by message and label
Find the dominant error type and the requests affected.
Find when they began
Use the over-time charts to see whether errors began at a load level or a clock time.
Reproduce small
Try the failing request with one user and the results tree. Does it fail alone?
Check the server side
Read the server logs and metrics for the same period.
Write the finding
State the cause, the evidence, and the suggested action.
A detective does not arrest the first person seen near the scene. She gathers the facts, establishes a timeline, and tests each theory against the evidence. Error analysis is detective work.
TTypes of Errors and What They Usually Mean
The response code and message are strong clues to the cause.
| What you see | Usual meaning | First thing to check |
|---|---|---|
| Server error codes in the five-hundred range | The server or something behind it failed | Application logs and dependency health at that moment |
| Not found codes | The request asked for something missing, often a wrong path or test data issue | The request address and the test data |
| Unauthorised or forbidden codes | Sign-in or permission problems, often expired sessions or tokens | Cookies, tokens, and session length |
| Too many requests codes | The system or a gateway is limiting the rate | Rate limit settings |
| Gateway or service unavailable codes | A front door could not reach the service behind it | Load balancer and back-end health |
| Connection refused or reset | The server did not accept, or dropped, the connection | Connection limits and the server process |
| Timeouts | The server did not answer in time | Server load, slow queries, and timeout settings |
| Assertion failure message | Content was wrong although the code looked normal | The real response in a debugging run |
| Non-HTTP response codes naming exceptions | A network or client-side problem | The load generator and the network path |
When a phone call fails, you hear a busy tone, a wrong-number message, or silence. Each means something different and suggests a different next step. Error codes are those tones.
Keep a short team cheat sheet of what each error usually meant in your own system. After a few runs, patterns repeat, and diagnosis becomes quick.
Exact wording of messages differs between samplers and versions. Use the table as a map of ideas, and read your own report for the real texts.
CCorrelating With Server Metrics
JMeter shows what users felt. Server metrics show why.
JMeter measures from the outside. It knows how long a request took and whether it succeeded, but it does not see inside the server. To explain a slow or failing run, you need the server’s own measurements for the same period: processor use, memory, disk activity, network traffic, database connections, queue lengths, and application logs. Putting the two sets side by side on a common clock is called correlation.
| JMeter symptom | Server metric to inspect | Possible reading |
|---|---|---|
| Response times climb as users rise | Processor use on the application servers | Processing is saturated |
| Slow tail grows, average steady | Garbage collection pauses, disk waits, lock waits | Occasional stalls inside the server |
| Connect time grows | Connection limits, network device load | New connections are queuing |
| Throughput flat while users rise | Database connections, thread pools | A shared resource is exhausted |
| Errors begin at a clock time | Deployments, restarts, scheduled jobs | An event, not load, caused the damage |
| Times drift up over a long run | Memory, open files, queue sizes | A leak or a growing backlog |
A patient says “I feel tired”, which is JMeter’s view. The doctor adds a blood test and a heart trace, which are the server’s view. Only together do they point to a diagnosis.
Clocks must agree. If the load generator and the server disagree by a few minutes, every correlation will be misleading. Synchronise clocks before the test, and note the start and end times.
BComparing Runs: Baselines and Regression
A number means little alone. Compared with an earlier run, it means a lot.
A single run tells you how the system behaved once. The real power of testing comes from comparison. A baseline is a trusted earlier run you compare later runs against. When a new version performs worse than the baseline, you have found a regression. When it performs better, you have found an improvement worth recording.
What makes a fair comparison
- Same test plan: the same requests, think times, and data.
- Same load shape: the same users, ramp-up, and duration.
- Same environment: comparable servers, data volume, and network.
- Same period of analysis: the steady state, not the warm-up of one and the whole of the other.
- Same generator: similar machine capacity and the same tool version.
| Compare | Why it matters |
|---|---|
| Median and 90th percentile per label | Shows both typical and slow-end changes |
| Throughput at the same load | Shows capacity changes |
| Error rate | A faster system that fails more is not better |
| Resource use on servers | A change may trade processor for speed |
| Knee position | Shows whether the capacity limit moved |
A runner who records every race time can see progress or decline over months. A single time of twenty-five minutes means nothing until it is compared with last month’s twenty-seven.
Store the results file, the report folder, and a short note about the environment and version for every important run. A baseline you cannot find or explain is not a baseline.
VVariance and Repeatability
Two identical runs never give identical numbers. The question is how different.
Even with the same plan and system, two runs differ slightly. Random think times, cache states, background activity, and network noise all play a part. This natural wobble is called variance. Before declaring a regression, you must know how large the normal wobble is. A five percent change inside a ten percent wobble proves nothing.
Measuring the wobble
- Run the same test three to five times and compare the key numbers.
- Note the range of each number, such as the lowest and highest median.
- Treat changes smaller than that range as inconclusive.
- Look for causes of large variance: shared environments, uneven data, caches, and noisy neighbours.
Weighing yourself each morning gives slightly different numbers because of water, clothing, and timing. A change of a few hundred grams means nothing. A steady drop of several kilos over weeks does. Know your scale’s wobble before you celebrate.
The slow tail has the highest variance. The 99th percentile and maximum can change a lot between identical runs. Base decisions on the median and 90th percentile, and use the tail as a signal to investigate.
SUsing Spreadsheets and Scripts for Your Own Analysis
The results file is plain data, so any analysis tool can read it.
Because the results file is a simple table of values separated by commas, you can open it in a spreadsheet, a database, or a data analysis script. This is useful when the built-in report does not answer your question, or when you want to combine results with other data. No special knowledge of JMeter’s insides is needed, only an understanding of the columns.
Spreadsheet
Open the file, filter by label, and compute percentiles with built-in functions. Good for small and medium files.
Database
Load the file into a table and ask questions with queries, such as slowest labels per minute.
Analysis script
Use a data analysis language to compute custom statistics, draw charts, and compare many runs automatically.
Dashboard tool
Feed the data to a monitoring system so the team can watch trends across weeks.
A shop’s till roll is a plain list of sales. The owner can read it by hand, type it into a spreadsheet, or give it to an accountant with software. The list is the same. Only the tool changes.
When computing percentiles yourself, use the same method for every run, and state it. Different tools use slightly different calculation rules, so numbers may differ in the last digits.
LLive Monitoring With the Backend Listener
For long tests, watch the numbers on a dashboard while the test runs.
The Backend Listener sends results to an external system while the test runs, in batches, so you can watch live dashboards without opening the results file. A common setup uses a time-series database and a charting tool. The listener sends summaries such as counts, response times, and error counts for each label at regular intervals.
Advantages
- Live view during long tests
- History of many runs in one place
- Easy sharing with the whole team
- Can be shown next to server metrics
Disadvantages
- Extra systems to set up and maintain
- Summaries, not every sample
- Adds a small amount of work on the generator
- Needs care with network access and secrets
A live scoreboard at a stadium lets everyone follow the match without asking the referee. The final report is still written afterwards, but the scoreboard keeps the crowd informed during play.
Even with live dashboards, still save the results file. Live summaries are for watching. The full file is for proof and later analysis.
PPerformance Cost of Collecting and Analysing Results
Measuring a test must not disturb the test.
Every result you keep costs memory, processor time, and disk space on the load generator. If the generator is busy recording, it may become the bottleneck, and the numbers will describe the generator, not the system under test. A good analyst keeps collection light and does the heavy work afterwards.
| Choice | Light option | Heavy option |
|---|---|---|
| Where you run | Non-GUI mode | GUI mode with listeners open |
| What you save | Compact fields to a file | Full response bodies for everything |
| Listeners in the plan | Results file and one backend listener | Many tree and table listeners |
| When you analyse | After the run, from the file | During the run, in the same process |
| Keeping failures | Save details only for failures | Save details for every sample |
A runner who stops every hundred metres to write notes will run slowly, and the notes will describe a stopping runner. A coach with a stopwatch at the side records without disturbing the race.
If the load generator’s own processor use is high during a run, treat the results with suspicion. Check the generator’s health as carefully as the server’s.
SScalability: Large Files and Distributed Runs
Big tests produce big files, and the analysis must scale with them.
A long test with many users can produce millions of rows. Opening such a file in a spreadsheet may fail, and the report generator needs memory. When tests are spread over several load generators, each one writes its own file, and results must be combined before analysis.
Ideas that help
- Save only needed columns, so files stay smaller.
- Use the report generator or a database instead of a spreadsheet for large files.
- Merge files from several generators carefully, keeping their time stamps intact and unique thread names or generator labels.
- Use a larger time slice in reports for very long runs, so charts stay readable.
- Archive old results and keep reports and summaries for the long term.
A town that grows from one hundred to one million people cannot keep its records on index cards. It needs filing systems, summaries, and archives. Large test results need the same grown-up handling.
When combining files from several generators, check that the total thread count and throughput add up as expected. A missing file quietly halves the apparent load.
SSecurity of Result Files
Results can hold secrets, so treat them like any sensitive data.
A results file is not just numbers. It may contain request addresses with tokens in them, response bodies with personal details, sign-in names, and error messages that reveal internal structure. Sharing such a file carelessly can leak information.
| Risk | Where it hides | Protection |
|---|---|---|
| Tokens and keys | Request addresses, headers, and response bodies | Avoid saving them, or remove them before sharing |
| Personal data | Response bodies and test data files | Use fake data and do not save full bodies |
| Internal details | Error messages, host names, and stack traces | Review before sending outside the team |
| Shared reports | Report folders sent by email or chat | Share through controlled storage with access limits |
| Old archives | Forgotten files on shared drives | Set retention rules and delete what is no longer needed |
A hospital’s records are shared on a need-to-know basis, and old files are shredded after a set time. A test file full of customer-like data deserves similar respect, even when the data is only test data.
Test data copied from production is still real personal data. Use invented data in tests wherever you can, and your files become much safer to share.
RReporting Findings to Stakeholders
The best analysis is wasted if the reader cannot act on it.
Different readers need different things. A manager wants a verdict and a risk. An engineer wants evidence and clues. A product owner wants to know whether users will be happy. A short, honest report that answers these needs is worth more than a hundred pages of charts.
Start with the verdict
Say in one or two sentences whether the system met its targets, and by what margin.
State the scenario
Describe the load, duration, environment, and version so the numbers have context.
Show a few key figures
Percentiles, throughput, error rate, and the knee, ideally beside targets and the baseline.
Explain the causes
Give evidence from charts and server metrics for each problem found.
Recommend actions
List what to fix, what to monitor, and what to retest, in priority order.
State limits honestly
Mention what the test did not cover and any filters applied.
A doctor handing over a test result says first “you are fine” or “we need to act”, and only then shows the numbers. Leading with the verdict respects the reader’s time.
AAdvantages, Disadvantages, and Trade-offs
Every way of reading results has strengths and weaknesses.
Advantages of a disciplined analysis
- Decisions rest on evidence, not feelings
- Problems are found before users find them
- Comparisons across versions become possible
- Capacity planning gets real numbers
- The team shares one language for performance
Disadvantages and costs
- It takes time and skill to do well
- Numbers can give false confidence if the test was unrealistic
- Large files and many charts can overwhelm readers
- Results describe a test environment, not production itself
| Trade-off | One side | Other side |
|---|---|---|
| Detail versus speed | Save everything for deep analysis | Save little to keep the generator light |
| Live versus afterwards | Watch in real time | Analyse calmly with the full file |
| Simple versus rich | One verdict number for managers | Many charts for engineers |
| Small slices versus large | See short spikes | Smooth out noise |
Keeping a diary in great detail gives rich memories but costs an hour each evening. A short note costs a minute but loses colour. Pick the level of detail that matches how you will use it.
DDesign Patterns for Good Analysis
A few habits make analysis calmer and more reliable.
Targets first
Write the pass and fail targets before running, so the data cannot bend the goalposts.
Verdict, then evidence
Read the summary, then the tables, then the charts, then the server metrics.
Steady-state window
Always cut warm-up and shutdown before computing the headline numbers.
Always a baseline
Compare every important run with a trusted earlier run.
Repeat before concluding
Run a close call three times before calling it a regression.
Archive with context
Keep the file, the report, and the notes together in a clearly named folder.
A good cook has habits: tidy the workspace, taste as you go, write down what worked. None of the habits is exciting, but together they make every meal better.
AAnti-Patterns to Avoid
These mistakes appear again and again in real reports.
Quoting only the average
The average hides the slow tail, and the slow tail is what users remember. Report the median and at least the 90th and 95th percentiles.
Including the warm-up in headline numbers
The first minutes are not typical. Cut them, and state that you did.
Ignoring errors because response times look good
Failed requests are often very fast. A low average with a high error rate is a bad result, not a good one.
Analysing in the GUI under heavy load
The tool itself becomes the bottleneck. Run in non-GUI mode and analyse afterwards.
Judging from a single run
One run cannot show variance. Repeat close calls before drawing a conclusion.
Changing thresholds after seeing the result
Moving the targets to match the data defeats the purpose of testing. Fix them in advance.
Sharing raw files without review
Result files may contain tokens and personal data. Check before sending outside the team.
Driving with a cracked mirror, skipping seatbelts, and ignoring warning lights may work for a while. Each shortcut is a small risk, and together they make a trip unsafe.
TTroubleshooting Analysis Problems
When the results themselves look wrong, check the basics first.
| Symptom | Likely cause | What to try |
|---|---|---|
| Report generation fails | Missing columns, bad file, or non-empty folder | Check the file header and use a new report folder |
| Charts are empty | Wrong time range or filters hide all data | Remove filters and check the time stamps |
| Throughput looks far too low | Generator saturated or long think times | Check generator resources and the plan’s timers |
| Everything fails with very short times | The test cannot reach or sign in to the system | Run one user with the results tree and read the response |
| Transaction numbers look doubled | Parent and child samples counted together | Filter by label or use the parent only |
| Numbers differ between tools | Different percentile methods or filters | Use one method and document it |
| Result file is enormous | Too many saved fields or full bodies | Save fewer fields and details only on failure |
| Times change wildly between runs | Shared environment or cache effects | Control the environment and repeat the run |
When a car will not start, you check the fuel and the battery before suspecting the engine. When the results look odd, check the file, the filters, and the test itself before blaming the system.
WA Worked Example: From Raw Run to Verdict
Follow one imaginary run from file to recommendation.
A team tests an online shop before a sale. The target is that ninety percent of checkout requests finish in under three seconds, with fewer than one percent errors, at five hundred concurrent users. The numbers below are invented for teaching.
flowchart TD
A["Run: 500 users, 30 minutes, non-GUI"] --> B["Build report from the results file"]
B --> C["Cut ramp-up and ramp-down"]
C --> D["Check totals: errors 0.4 percent"]
D --> E["Read table: checkout 90th percentile 3.8 s"]
E --> F["Charts: times rise after minute 12"]
F --> G["Server metrics: database connections at limit"]
G --> H["Verdict: target missed; raise pool and retest"]
Totals first
Errors are low at 0.4 percent, inside the target, so the system mostly worked.
Table next
Checkout’s 90th percentile is 3.8 seconds. Other labels meet their targets.
Charts for timing
Response times were flat until minute twelve, then climbed while users stayed constant.
Server clues
Database connections reached their limit at that moment, and requests queued.
Recommendation
Increase the connection pool, then repeat the run and compare with this baseline.
A mechanic finds the car overheats after twelve minutes of driving, checks the coolant, and finds a slow leak. The story has a clear order: symptom, timing, cause, fix.
MCommon Misunderstandings
A few false beliefs cause most of the bad reports.
| Belief | Reality |
|---|---|
| A low average means users are happy | The slow tail may still be serious |
| Zero errors means a perfect test | The test may be too gentle or check too little |
| The throughput number is the same as users | Throughput is work finished per time, not people |
| More charts mean better analysis | A few well-chosen views beat many unread ones |
| Test results describe production exactly | They describe the test environment and plan only |
| A response code of 200 means success | The content may still be wrong without an assertion |
| The maximum is the key figure | It is one unlucky sample, useful as a clue only |
| One good run proves the system is fast | Repeatability must be shown |
Believing that a restaurant is good because the average wait is ten minutes ignores the table that waited an hour. Averages are comfortable. Individual experiences decide reputations.
BBest Practices and Common Mistakes
Keep these in mind before, during, and after every run.
Best practices
- Define targets before the test
- Run in non-GUI mode and save a results file
- Analyse the steady state only
- Report percentiles, throughput, and errors together
- Correlate with server metrics
- Compare with a baseline and repeat close calls
- Keep the file, report, and notes together
- Protect and clean up result files
Common mistakes
- Looking only at the average
- Reading the first run as final truth
- Ignoring generator health
- Forgetting to record the environment
- Hiding filters and exclusions
- Counting transactions twice
- Sharing files containing secrets
- Reporting numbers without a verdict
Turn the best practices list into a short checklist stored with your test plans. Checklists are boring and extremely effective.
UReal-World Scenarios
Four short stories show analysis in action.
Before a big sale
An online shop runs a load test at the expected sale peak. The report shows the checkout’s slow tail grows after minutes of steady load. Correlation with server metrics points to a small database pool. The team fixes it and retests with the first run as baseline.
After a new release
A bank runs the same test on every release. A new version shows a median twelve percent higher, outside the usual wobble. The comparison pinpoints one label, and developers find an added query. A regression is caught before customers see it.
Capacity planning
A booking platform steps up users in stages and finds the knee at two thousand users, where throughput flattens and errors begin. The business plans to add servers before expected growth reaches that level.
A mysterious night slowdown
Long soak tests show slow responses at the same clock time every night. Time-based charts and server schedules reveal a backup job competing for disk. Moving the job solves it, and no code changed.
Doctors, mechanics, and weather forecasters all do the same thing: measure, compare with normal, and find the cause. Analysing test results is the same craft applied to software.
QQuick Reference
A one-page memory aid for results analysis.
| Topic | Remember |
|---|---|
| Where results live | A results file; build reports from it afterwards |
| Elapsed time | Full request time, from start to the end of the response |
| Latency | Time until the first byte comes back |
| Typical experience | Median |
| Slow tail | 90th, 95th, and 99th percentiles |
| Throughput | Finished requests per time unit |
| Little’s Law | Users equal throughput times total time per cycle |
| Steady state | The period to analyse; cut warm-up and shutdown |
| Knee | The load where times rise sharply and throughput flattens |
| Apdex | A score from zero to one for satisfaction |
| Correlation | Match JMeter data with server data on one clock |
| Baseline | A trusted earlier run for comparison |
| Variance | Know the normal wobble before calling a regression |
Report options, property names, and listener choices change between versions. Check the documentation of the version you use before depending on a detail.
GGlossary
Short definitions of the words used in this guide.
| Term | Meaning |
|---|---|
| Sample | One recorded request and its response |
| Label | The name given to a sample or transaction |
| Results file | A saved table of samples, one per row |
| Elapsed time | Total time of a sample |
| Latency | Time to the first byte of the response |
| Connect time | Time to open the connection |
| Median | The middle value of the sorted times |
| Percentile | The time under which a given share of samples finished |
| Standard deviation | A measure of how spread out values are |
| Throughput | Completed requests per unit of time |
| Error rate | Share of samples that failed |
| Steady state | The stable middle part of a run |
| Warm-up | The early period before the system settles |
| Knee | The point where performance starts to degrade quickly |
| Saturation | A resource being fully used so work queues up |
| Apdex | A satisfaction score from response times |
| Baseline | A reference run for comparisons |
| Regression | A change that makes performance worse |
| Correlation | Linking two data sets by time to find causes |
| Dashboard report | A set of web pages generated from a results file |
FFrequently Asked Questions
Quick answers to questions beginners ask most often.
No single number does. Read the error rate, the median, the 90th or 95th percentile, and throughput together. Each hides what another reveals.
A few very slow requests can hide among many fast ones. The average blends them, so users with bad experiences vanish from the figure.
Latency is the wait until the first byte of the response arrives. Elapsed time continues until the whole response is received.
Use the GUI for building and debugging, with small loads. For real load tests, run in non-GUI mode, save a file, and analyse afterwards.
Run a test in non-GUI mode with a results file, then ask JMeter to build a report in a new folder, either at the end of the run or from the file later. Check your version’s documentation for the options.
It depends on the business. Many teams set targets on the 90th or 95th percentile for each important action, agreed with product owners before testing.
An assertion may have failed because the content was wrong. A normal code does not guarantee a correct response.
You have probably reached a capacity limit somewhere. Additional users only wait in queues, so response times rise instead.
The first minutes are not typical. Caches are cold and load is still rising. Including them distorts the headline numbers.
For important comparisons, three to five runs show the normal variation. For quick checks, one run may do, but treat it as a hint.
Be careful. A saturated generator adds its own delays, so the results may describe the generator. Check its processor and memory, and add machines if needed.
No. They describe the test environment, data, and plan. The closer these are to production, the more the results can be trusted.
Keep baselines and key reports for as long as they are useful for comparison. Archive or delete the raw files according to your team’s retention rules and security needs.
Group them by message and label, find when they started, reproduce one with a single user, and check the server logs for the same time.
SSummary and Key Takeaways
The essentials of reading JMeter results with confidence.
Analysing results turns thousands of rows into a decision. You learned where results come from, how to read the columns, how to describe typical and slow experiences with the median and percentiles, how throughput and errors complete the picture, and how to tell steady state from warm-up. You saw healthy and unhealthy shapes, how to find the knee, how to use the Summary and Aggregate reports and the HTML dashboard, how to investigate errors, correlate with server metrics, compare runs, and report clearly.
Key takeaways
- Save a results file in non-GUI mode, and build reports from it afterwards.
- Prefer the median and percentiles over the average, and never ignore the slow tail.
- Read response times, throughput, and errors together, never alone.
- Analyse the steady state, and say which filters you applied.
- Correlate JMeter data with server metrics on a shared clock to find causes.
- Compare with a baseline, and know the normal variance before calling a regression.
- Lead reports with a verdict, support it with evidence, and protect the result files.