skip to content

In JMeter, which properties decide that reports show the 90th, 95th and 99th percentiles?

level: juniorimportance: should knowfreq 34%

answer

  1. Three keys, not one
  2. Named for one listener, read by three
  3. Numbered suffixes with familiar defaults
  4. Values are floats, so tails are reachable

basics

~20 s

The three properties aggregate_rpt_pct1, aggregate_rpt_pct2 and aggregate_rpt_pct3, defaulting to 90, 95 and 99. Each takes a float between 0 and 100, so 99.9 is valid, and they move the GUI listeners and the HTML dashboard together.

solid answer

~40 s

`aggregate_rpt_pct1`, `aggregate_rpt_pct2` and `aggregate_rpt_pct3` default to `90`, `95` and `99`. They ship commented out in `bin/jmeter.properties` under the Aggregate Report section, and each accepts a float between 0 and 100, so `aggregate_rpt_pct3=99.9` is legal. Despite the `aggregate_rpt_` name they are read in **three** live places: `StatGraphVisualizer`, whose table model the GUI Aggregate Report reuses, the report generator's `StatisticsSummaryConsumer`, and `ResponseTimePercentilesOverTimeGraphConsumer`. One edit therefore moves the GUI Aggregate Report and Aggregate Graph, the dashboard's Statistics table and the dashboard's percentiles-over-time series at once. All three read into `static final` fields, so the change needs a JMeter restart, and it must be present in whichever JVM generates the report.

code

properties · 10 lines
properties
# bin/user.properties - ask for a deeper tail
aggregate_rpt_pct1=90
aggregate_rpt_pct2=99
aggregate_rpt_pct3=99.9

# read into static final fields by
#   StatGraphVisualizer            (GUI Aggregate Report / Aggregate Graph)
#   StatisticsSummaryConsumer      (HTML dashboard Statistics table)
#   ResponseTimePercentilesOverTimeGraphConsumer
# so a JMeter restart is required

go deeper

for a junior

Know the three key names and their defaults of 90, 95 and 99, and that you set them in a JMeter properties file rather than anywhere in the listener's own GUI.

for a middle

Explain that the values are floats parsed into static final fields by both the GUI listeners and the report generator, so one edit moves three surfaces and needs a restart to take effect.

for a senior

Make sure the change reaches the JVM that generates the report, and flag that a deeper level makes the estimator and window choices matter more to the printed figure.

for a principal

Decide which three levels the team's reports carry at all, and keep that decision in one distributed properties file rather than in each engineer's local install.

## The three keys ```properties # bin/jmeter.properties, shipped commented out #aggregate_rpt_pct1=90 #aggregate_rpt_pct2=95 #aggregate_rpt_pct3=99 ``` Each is a float between 0 and 100 read as a string and parsed, so fractional levels work: `aggregate_rpt_pct3=99.9` gives you a 99.9th percentile column. There are exactly three; there is no `pct4`, and no way to ask for a fourth percentile column without changing code. ## What they reach The `aggregate_rpt_` prefix undersells them. They are read by: - `StatGraphVisualizer` — the **Aggregate Graph** listener, and the **Aggregate Report** listener too, because `StatVisualizer` builds its table from `StatGraphVisualizer.createObjectTableModel()`; - `StatisticsSummaryConsumer` — the HTML dashboard's **Statistics** table; - `ResponseTimePercentilesOverTimeGraphConsumer` — the dashboard's percentiles-over-time series. (A fourth class, `ResponseTimePerSampleGraphConsumer`, reads the same keys but is dead code — its javadoc says "NOT USED FOR NOW as of 3.0", it is not registered in `bin/reportgenerator.properties`, and it reads them as an `int` at construction rather than into `static final` fields, so it renders nothing.) So the same three lines change what three surfaces compute. That is usually what you want, and it is worth stating explicitly when handing the change to someone who only looked at the dashboard. One surface they do **not** reach: the **Summary Report** listener has no percentile columns at all. It deliberately stores no individual samples so that it runs in constant memory, so there is nothing there for these properties to configure. ## When they are read All three hold them in `static final` fields, initialised when the class first loads. Practical consequences: 1. edit the properties file, then restart JMeter — a running instance will not pick the change up; 2. the JVM that **generates the report** needs the properties, which is not necessarily the injector that ran the test; 3. a report regenerated later from a saved JTL uses whatever the properties say *at regeneration time*, not what they said during the run. There is a small internal asymmetry worth knowing but not worrying about: the GUI path divides the value by 100 before calling `getPercentPoint`, while the report generator passes it through as a 0-to-100 index. You still write `90` in both cases. ## Choosing a level, and what comes with it Moving to a deeper tail level interacts with the other two settings this leaf covers: - the deeper the level, the fewer samples sit above it, and the more the choice between `LEGACY` and `R_3` in `backend_metrics_percentile_estimator` can move the printed figure; - the level is read off whatever is inside the dashboard's percentile window, so `jmeter.reportgenerator.statistic_window` decides which samples a 99.9th percentile is even drawn from. In other words, changing `aggregate_rpt_pct3` to `99.9` is one line, but the number it produces is only as meaningful as the estimator and window behind it. ## Checking you got it After a restart, the column headers themselves tell you: the dashboard's Statistics table and the GUI listener both label the columns from these values, and the dashboard's percentile graph series are named from them too. If the headers still read 90/95/99, the properties file JMeter actually loaded is not the one you edited.

  • Can you add a fourth percentile column?
    No. There are exactly three keys, `aggregate_rpt_pct1` to `aggregate_rpt_pct3`, and both the GUI table model and the report generator's summary consumer are wired for three. Getting a fourth level means repurposing one of the three, or reading the JTL with something other than these surfaces.
  • You set aggregate_rpt_pct3=99.9 and the column header still reads 99%. What went wrong?
    Either JMeter was not restarted, or the file you edited is not one JMeter loads for that JVM. The values are captured in `static final` fields at class initialisation, and the JVM that matters is the one producing the report, which may not be the injector.

saying these in an interview costs you the question

  • Looks for a percentile setting inside the listener's GUI
  • Assumes the keys only affect the GUI Aggregate Report
  • Expects a running JMeter to pick the change up
  • Thinks only whole-number percentile levels are allowed
  • Expects the Summary Report to gain percentile columns