How would you rescale every random pause in a JMeter plan without editing the .jmx?
answer
- A property, not a plan edit
- It reaches only one family of timers
- Its default value disables the multiply entirely
- Constant and scripted timers are left alone
basics
~10 sSet JMeter's timer.factor property. It multiplies the delay computed by the Gaussian, Uniform and Poisson Random Timers, defaults to 1.0f, and leaves the Constant, Synchronizing, JSR223 and BeanShell timers untouched.
solid answer
~40 s`JMeterThread` reads `timer.factor` once into a static field, defaulting to `1.0f`, and applies it only when the value differs from `1.0f` **and** the timer implements `ModifiableTimer`. In core JMeter that interface is implemented by `RandomTimer` alone, so only its three subclasses — Uniform, Gaussian and Poisson — are scaled; the delay becomes `Math.round(delay * TIMER_FACTOR)` before the per-sampler total is summed. The consequences are what make this a judgment call rather than a switch: it is a JMeter property, so it is JVM-wide, read at startup, identical for every timer in the plan, and in a distributed run it has to reach every engine. Anything you need to vary per timer has to be parameterised in the fields instead.
code
properties · 4 lines# bin/user.properties
# Multiply every Uniform, Gaussian and Poisson Random Timer delay by 0.5.
# Constant, Synchronizing, JSR223 and BeanShell timers are unaffected.
timer.factor=0.5go deeper
Know that JMeter has a property that multiplies computed pause times, and that it applies to the random timers rather than to every timer in the plan.
Explain the mechanism: a static value read once, compared against 1.0f, and applied only to timers implementing ModifiableTimer, which the Constant and scripted timers do not.
Weigh it against parameterising the fields. Point out that it is JVM-wide, invisible in the .jmx, uneven across mixed timer types, and must be present on every engine in a distributed run.
Own the policy. Decide whether pace changes are expressed in the plan or in the environment, make sure the factor in force is recorded with the results, and standardise on timer types so rescaling stays even.
## What the property does and does not reach The mechanism is four lines in `JMeterThread`: ```java private static final float TIMER_FACTOR = JMeterUtils.getPropDefault("timer.factor", 1.0f); private static final boolean APPLY_TIMER_FACTOR = Float.compare(TIMER_FACTOR, ONE_AS_FLOAT) != 0; // ... inside delay(List<? extends Timer> timers) if (APPLY_TIMER_FACTOR && timer.isModifiable()) { delay = Math.round(delay * TIMER_FACTOR); } ``` `isModifiable()` defaults to `false` on the `Timer` interface and is overridden to `true` only by `ModifiableTimer`, which in core JMeter is implemented by the abstract `RandomTimer`. So the reach is exactly: | Element | Scaled by `timer.factor`? | |---|---| | Uniform Random Timer | yes | | Gaussian Random Timer | yes | | Poisson Random Timer | yes | | Constant Timer | no | | Synchronizing Timer | no | | JSR223 Timer | no | | BeanShell Timer | no | The shipped `bin/jmeter.properties` documents it as a commented default, and the properties reference lists the same three timers. Note the scaling is applied per timer, before the delays of all the timers in one sampler's scope are added together. ## Why the choice is not obvious **In favour.** One number changes every random pause in every plan the JVM runs, without touching a `.jmx`. Nothing is edited, so nothing is accidentally committed, and a plan under review keeps the values its author wrote. It costs nothing at runtime when unset, because `APPLY_TIMER_FACTOR` short-circuits the multiply when the value is exactly `1.0f`. **Against.** 1. **It is all or nothing.** Every modifiable timer in the JVM gets the same factor. A plan where one journey should pause less and another more cannot be expressed. 2. **It is invisible in the plan.** Someone reading the `.jmx` sees the authored values and has no way to know the run applied a factor. Two runs of the same file are then not comparable unless the factor is recorded alongside the results. 3. **It misses half the timers.** A plan mixing Constant Timers with random ones is rescaled unevenly, which quietly changes the shape of the run rather than its size. 4. **It has to reach every JVM.** A distributed run needs the property present on each engine, since each engine reads its own properties at startup. 5. **It is read once, statically.** There is no way to change it part-way through a run. ## How I would actually decide - **If the pause values are themselves the thing under change**, parameterise the timer fields rather than using the factor: the plan then says what it does, and a reviewer can see it. - **If the plan is fixed and the *environment* varies** — a smaller shared environment, a soak variant of the same plan — the factor is the cheaper lever, provided the value is captured with the run's results. - **Either way, standardise on the random timers.** The factor's blind spot is the Constant Timer; a house rule that pauses are expressed with a Uniform Random Timer removes the uneven-rescale problem entirely. - **Record it.** Whatever the mechanism, the factor in force belongs next to the run output, because a run whose pauses were halved is not the same run. ## Checks before you rely on it 1. Confirm the property is actually loaded — it must reach JMeter's own properties before the run starts, on every JVM that will execute the plan. 2. Confirm the plan's pauses come from modifiable timers; grep for `ConstantTimer` elements that are not `UniformRandomTimer`, `GaussianRandomTimer` or `PoissonRandomTimer`. 3. Confirm every engine in a distributed run has the same value. 4. Remember the arithmetic is `Math.round`, so sub-millisecond results are rounded, not truncated.
- Which JMeter interface decides whether a timer is affected by timer.factor?ModifiableTimer. The base Timer interface declares isModifiable returning false, and ModifiableTimer overrides it to true. In core JMeter only the abstract RandomTimer implements it, which is why exactly the Uniform, Gaussian and Poisson timers are scaled and no others.
- What is the runtime cost of leaving timer.factor at its default?Effectively none. JMeterThread computes a static boolean by comparing the factor against 1.0f, and when they match the multiply is skipped entirely for every timer on every sampler. The property is read once when the class loads, not per delay.
- Why is a factor applied per run harder to defend than parameterised timer fields?Because it leaves no trace in the plan. The .jmx still shows the authored pauses, so two runs of the same file can differ without anything in the file explaining why. If you use the factor, the value in force has to be recorded with the results.
saying these in an interview costs you the question
- Claims timer.factor scales every timer in the plan.
- Thinks it can be changed while a test is running.
- Assumes a controller-level setting applies it to part of a plan.
- Forgets each engine in a distributed run reads its own properties.
- Believes the default of 1.0f still costs a multiply per delay.