How would you pin JMeter's percentile settings so every injector and every generated report agrees?
answer
- Three properties, one decision each
- The reporting JVM, not the injector
- Static fields, so startup-time only
- One file per install, not per laptop
basics
~10 sShip one properties file with every JMeter install carrying the estimator, the report window and the three percentile levels. All three are read at startup, and the JVM generating the report needs them too.
solid answer
~40 sThree JMeter properties decide what a percentile figure means: `backend_metrics_percentile_estimator`, `jmeter.reportgenerator.statistic_window`, and `aggregate_rpt_pct1` to `pct3`. All of them are read into `static final` fields at class initialisation, so they cannot be set from a plan and must be present in the properties files before the JVM starts. Put them in one `user.properties` distributed with the JMeter install rather than in each engineer's copy. Remember which JVM matters: a report generated from a saved JTL takes its estimator, window and levels from the machine doing the generation, not from the run that produced the file. Then decide honestly whether to leave the estimator at `LEGACY` or move it to `R_3`, and record which you chose — the choice changes the printed figure, and it also changes the Backend Listener's live percentiles.
go deeper
Know that these are JMeter properties in a file, not GUI settings, and that a colleague's report can differ from yours simply because their install carries different values.
Explain why a plan cannot set them: each is captured in a static final field at class initialisation, so the properties files must carry them before the JVM starts.
Cover the report-generating JVM, not only the injectors, and check what a fleet-wide estimator change does to Backend Listener dashboards that have been running for months.
Own the trade-offs and state them: LEGACY for out-of-the-box comparability against R_3 for observed values, window size against report-JVM memory, and the residual mismatch you accept.
## What there is to pin | Property | Default | What it decides | |---|---|---| | `backend_metrics_percentile_estimator` | `LEGACY` | how a percentile is read off the values in scope | | `jmeter.reportgenerator.statistic_window` | `20000` | which samples per dashboard row are in scope at all | | `aggregate_rpt_pct1` / `pct2` / `pct3` | `90` / `95` / `99` | which three levels are computed | All three groups are read through `JMeterUtils.getPropDefault` into `static final` fields. Nothing here is settable from a plan, a JSR223 element or a `__P` lookup at run time — the value that counts is whatever the properties files said when the JVM started. ## Where they have to be 1. **On every injector**, so a GUI-loaded Aggregate Report and any live Backend Listener use the same levels and estimator as everything else. 2. **On the machine that generates the report.** This is the one people miss. Generating a dashboard from a JTL saved last week reads the estimator, window and levels from *that* JVM. A pinned injector and an unpinned build agent will disagree. 3. **In one file, distributed with the install**, not hand-edited per laptop. A `user.properties` shipped alongside the JMeter directory, or baked into the container image, is the unit that actually keeps a fleet consistent. ## The estimator decision There is no single right answer, and that is the point of the question. - **Leave it at `LEGACY`.** It is what every untouched JMeter install produces, so a report from someone outside the team lines up with yours, and nobody has to know a property exists. - **Move it to `R_3`.** The dashboard then reports an elapsed time that a sample actually recorded, and stops disagreeing with the Aggregate Report listener people open in the GUI. This is what the manual suggests when you want the two to match. What you must not do is leave it unstated. Whichever you pick, write it next to the number: the same JTL yields 828 ms or 180 ms for one 90% Line depending on this one word. ## The window decision `statistic_window` is a memory-for-coverage trade, and it is spent in the report-generating JVM: - four windowed aggregators per label row, each holding up to `statistic_window` doubles — on the order of 160 KB apiece at the default; - a plan with a hundred labels is therefore already tens of megabytes before you raise anything; - raise it above the largest per-label sample count you expect if the percentiles must cover the whole run, and size the report JVM's heap for it. If you leave it at the default, say so, because the percentiles then describe the tail end of any long run rather than all of it. ## Blast radius to check before rolling it out - `backend_metrics_percentile_estimator` also feeds the Backend Listener's `SamplerMetric`, so a fleet-wide change moves the percentiles on any live metrics dashboard that has been running for months. - Changing `aggregate_rpt_pct*` renames columns and graph series, which breaks anything downstream that parses the report by column header. - Neither change is retroactive in the direction people assume: old reports keep their old numbers, but regenerating an old JTL produces new ones. ## What you cannot pin The GUI **Aggregate Report** has no estimator knob at all — `StatCalculator` is hard-wired — so the alignment only ever runs one way, by moving the dashboard onto `R_3`. Even then it is `rint` against `Math.round`, so a value where `N x p` lands exactly on a half can still differ by one order statistic. The manual's phrasing is "more or less the same", and a standard that promises exact equality is promising something JMeter does not offer.
- A build agent regenerates last month's JTL into a dashboard. Whose properties apply?The build agent's. The estimator, the window and the three levels are all read by the JVM doing the generation, so a report rebuilt on an unpinned agent can differ from the one produced on the injector at the time, from the identical file.
- Why not just require everyone to read the Aggregate Report listener instead?It has no window and keeps a map of every distinct elapsed time, so it costs memory on large runs, and it is a GUI listener rather than something a pipeline produces. Pinning the dashboard's estimator and window gets you the same figures from an artefact a build can generate.
- How would you make the settings visible to whoever reads the report?Put the three property values next to the artefact — in the job log, the report directory, or the ticket the numbers land in. JMeter does not print the estimator or window on the dashboard, so an unstated LEGACY at the default window is indistinguishable from a deliberate choice.
saying these in an interview costs you the question
- Pins the injectors but not the report-generating agent
- Assumes a plan or JSR223 element can set the estimator
- Promises the dashboard will exactly equal the listener
- Raises statistic_window without sizing the report JVM
- Changes the estimator without checking live Backend Listener dashboards
- Leaves each engineer to edit their own user.properties