skip to content

Which JMeter property selects the HTML report's percentile estimator, and what values does it take?

level: middleimportance: nice to knowfreq 27%

answer

  1. Not prefixed like the other report keys
  2. Named for a listener it outgrew
  3. Value is an enum constant name
  4. Absent from the shipped jmeter.properties

basics

~10 s

The key is backend_metrics_percentile_estimator, with no jmeter.reportgenerator prefix. It accepts a commons-math3 Percentile.EstimationType constant name: LEGACY (the default) or R_1 through R_9. Nothing else parses.

solid answer

~40 s

`backend_metrics_percentile_estimator` is a plain JMeter property, read by `DescriptiveStatisticsFactory` through `JMeterUtils.getPropDefault` with a default of `LEGACY`. The manual is explicit that it takes **no** `jmeter.reportgenerator.` prefix even though it governs the HTML report. Its value is passed to `EstimationType.valueOf`, so it must be exactly one of `LEGACY`, `R_1`, `R_2` ... `R_9` — case sensitive, and a typo such as `R3` or `r_3` raises rather than falling back. It is not present in the shipped `bin/jmeter.properties`, so you add the line to `user.properties` yourself. It is read once into a `static final` field, which makes it a JVM-wide choice fixed before the run, and it governs every `DescriptiveStatistics` the factory builds — the report generator's `PercentileAggregator` and the Backend Listener's `SamplerMetric` alike.

code

properties · 9 lines
properties
# bin/user.properties
# no jmeter.reportgenerator. prefix on this key
backend_metrics_percentile_estimator=R_3

# WRONG - sets a property nothing reads, default LEGACY stays in force
#jmeter.reportgenerator.backend_metrics_percentile_estimator=R_3

# WRONG - EstimationType.valueOf is exact and case sensitive
#backend_metrics_percentile_estimator=r_3

go deeper

for a junior

Know that the estimator is a JMeter property, not a checkbox in the GUI, and that its name is backend_metrics_percentile_estimator with LEGACY as the default value.

for a middle

Explain the parsing: the value goes to an enum lookup, so only LEGACY and R_1 to R_9 parse, and it is read once into a static field before the run starts.

for a senior

Point out the blast radius. The same key drives the Backend Listener's live percentiles, so setting it on a shared install changes an existing live dashboard as well as the report.

for a principal

Decide where the property lives so every injector and every report-generating JVM has it, and say what you accept when the value changes on installs already publishing live percentiles.

## The key itself ```properties # in bin/user.properties backend_metrics_percentile_estimator=R_3 ``` Three things about that line trip people up. - **The name is misleading.** The `backend_metrics_` prefix suggests it only concerns the Backend Listener, but the class that reads it, `org.apache.jmeter.report.processor.DescriptiveStatisticsFactory`, is what the HTML report generator uses too. One key, both surfaces. - **It takes no report-generator prefix.** Most report settings are `jmeter.reportgenerator.<something>`. The manual spells the exception out when it tells you to set `backend_metrics_percentile_estimator=R_3` "this time without any prefix". Writing `jmeter.reportgenerator.backend_metrics_percentile_estimator=R_3` sets a property nothing reads, and the run silently keeps the default. - **It is not in the shipped property file.** Grep `bin/jmeter.properties` for it and you get nothing; only `backend_metrics_window`, `backend_metrics_large_window` and `backend_metrics_window_mode` are there as commented examples. The estimator key exists in the code and in the manual, and you write it yourself. ## Accepted values The value is handed straight to `EstimationType.valueOf(...)`, the commons-math3 enum: | Value | Behaviour worth knowing | |---|---| | `LEGACY` | The default. Index `p x (N + 1)`, linear interpolation between neighbours. | | `R_3` | Index `rint(N x p)`, an integer, so an observed order statistic comes back. The value the manual names for lining the dashboard up with the Aggregate Report. | | `R_1`, `R_2`, `R_4` ... `R_9` | The rest of the Hyndman-and-Fan family commons-math3 implements; selectable, rarely selected. | Because `valueOf` is exact and case sensitive, `r_3`, `R3` and `R-3` are all rejected with an `IllegalArgumentException` out of the class initialiser rather than quietly falling back to `LEGACY`. Treat a bad value as a hard failure, not as a no-op — but not necessarily an early one. `DescriptiveStatisticsFactory` initialises lazily, on the first `PercentileAggregator` or Backend Listener metric built, so `-g` and a plan carrying a Backend Listener blow up within seconds, while a plain `-n ... -e` run finishes in full and only then raises `ExceptionInInitializerError` out of report generation. ## When it is read ```java private static final EstimationType ESTIMATION_TYPE = EstimationType .valueOf(JMeterUtils.getPropDefault("backend_metrics_percentile_estimator", "LEGACY")); ``` That is a `static final` initialiser. Practical consequences: 1. the property must be in place before the class loads — a properties file JMeter reads at startup, not something set from inside a plan; 2. it is one setting for the whole JVM, so a plan cannot use one estimator for one label and another elsewhere; 3. the JVM that **generates the report** is the one that has to carry the property, which matters when the report is produced from a saved JTL on a different machine from the injector. ## What it reaches Everything built through `DescriptiveStatisticsFactory`: - the report generator's `PercentileAggregator`, i.e. the dashboard's Median and its three percentile columns, plus the percentile graph series; - the Backend Listener's `SamplerMetric` and `UserMetric`, i.e. the percentiles streamed live to a metrics backend. So the property is not a report-only switch. Changing it to match the GUI listener also changes what a live dashboard has been showing, which is worth saying out loud before you push it to a shared install. ## What it does not reach The GUI **Aggregate Report** and **Aggregate Graph** never consult it — they go through `StatCalculator`, which has no pluggable estimator at all. There is no property that changes the listener's formula; the alignment is always done by moving the dashboard toward the listener, never the other way round.

  • What happens if the value is misspelled?
    `EstimationType.valueOf` throws `IllegalArgumentException` from a `static final` initialiser, so the failure surfaces as a class-initialisation error rather than a silent fallback to `LEGACY`. The lesson is that a bad estimator value is loud: treat it as a hard fault that fires when the factory is first touched — a Backend Listener starting, or report generation at the end of the run — and fix the spelling, which must be one of `LEGACY` or `R_1` to `R_9`.
  • Is there an equivalent property for the GUI Aggregate Report's formula?
    No. The listener computes through `StatCalculator.getPercentPoint`, which has no pluggable estimator. Alignment is always achieved by moving the dashboard onto `R_3`, never by reconfiguring the listener.

saying these in an interview costs you the question

  • Prefixes the key with jmeter.reportgenerator
  • Expects a bad value to fall back to LEGACY
  • Thinks the key only affects the Backend Listener
  • Looks for the key in the shipped jmeter.properties
  • Believes a plan or JSR223 element can switch it mid-run