graph LR
A[Setup] --> B(Warmup);
B --> C{Execution Per Run};
C --> D[Reporting];
D --> E[Cleanup];
A typical JLBH (Java Latency Benchmark Harness) execution follows a distinct lifecycle designed to ensure accurate and repeatable latency measurements. The key phases are:
This initial phase prepares the benchmark environment:
-
JLBH Configuration: The user instantiates
JLBHOptionsto define all benchmark parameters (e.g., iterations, throughput, runs, coordinated omission settings). An instance ofJLBHis then created using these options. -
Task Initialization: The
JLBHTask.init(JLBH jlbh)method of the user-provided task is invoked.-
This allows the benchmark task to perform its own one-time setup, such as initializing resources or fixtures.
-
Crucially, this is where additional measurement probes can be registered by calling
jlbh.addProbe("probeName")to getNanoSamplerinstances for specific sub-sections of the task.
-
-
OS Jitter Monitoring: Jitter tracking is enabled by default (
recordOSJitterdefaults to true); unless disabled viarecordOSJitter(false), theOSJitterMonitorbackground thread starts to measure operating system scheduling jitter independently. -
Affinity: If an
acquireLocksupplier is configured inJLBHOptions, an attempt to acquire CPU affinity for the main benchmark thread might occur.
Before any measurements are formally recorded, the harness executes a warm-up phase:
-
Warmup Iterations: The
JLBHTask.run(long startTimeNs)method is calledwarmUpIterationstimes (as specified inJLBHOptions). ThestartTimeNspassed is typically justSystem.nanoTime()for this phase.-
The primary goal is to allow the Java Virtual Machine (JVM) to perform Just-In-Time (JIT) compilation and optimize the benchmarked code paths.
-
It also helps in bringing caches to a "warm" state and letting the system reach a more stable performance profile.
-
-
Sample Discarding: Latency samples generated during the warmup phase are usually recorded into the histograms but are not part of the final reported results. The histograms are reset after this phase.
-
Task Notification: After all warmup iterations are complete, the
JLBHTask.warmedUp()method is called. -
Optional Pause: If
JLBHOptions.pauseAfterWarmupMSis greater than zero, JLBH will pause for the specified duration before proceeding to the execution phase.
This is the core phase where timed iterations are performed and latency data is collected. This phase consists of one or more "runs" (as configured by JLBHOptions.runs):
-
Per Run:
-
The following steps are repeated for each configured run.
-
Iteration Loop: The
JLBHorchestrator executes a loop for the number ofiterationsspecified inJLBHOptions.-
Start Time Calculation: For each iteration, JLBH calculates an ideal
startTimeNs. This calculation considers:-
The configured
throughput(e.g., messages per second). -
The
LatencyDistributorstrategy, if one is set, to potentially vary the inter-iteration delay. -
If
accountForCoordinatedOmissionis true (the default),startTimeNsrepresents the ideal scheduled time for the operation. JLBH will then busy-wait (spin) untilSystem.nanoTime()reaches thisstartTimeNs, ensuring the task is dispatched as close as possible to its intended schedule, thus accounting for delays that might otherwise be missed.
-
-
Task Invocation: The
JLBHTask.run(startTimeNs)method is invoked with the calculated (and potentially waited-for)startTimeNs. -
Sample Recording:
-
Within the
JLBHTask.run()method, the user’s code is executed. -
To record the primary end-to-end latency for the iteration, the task must call
jlbh.sample(System.nanoTime() - startTimeNs). -
For any custom probes registered during setup, the task can call
myProbe.sampleNanos(duration)to record latencies for specific sub-stages. -
Each recorded sample is added to the respective
Histogramassociated with the sampler (either the main JLBH sampler or a custom probe’s sampler).
-
-
-
Run Completion: After all iterations for the current run are finished:
-
The
JLBHTask.runComplete()method is invoked. -
Statistics for this specific run (e.g., percentiles derived from the histograms) are typically printed to the configured
PrintStream. -
The collected histogram data for this run is processed and stored internally for the final
JLBHResult. -
All probe histograms are then reset to ensure that measurements for the next run (if any) are independent.
-
-
After all measurement runs are completed, the aggregated results are finalized and made available:
-
Final Summary: A comprehensive summary, often comparing results across all runs and highlighting percentile variations, is printed to the
PrintStream. -
Result Object Creation: The final, immutable
JLBHResultobject is constructed. This object encapsulates all recorded data for all probes across all runs. -
Result Consumption: If a
JLBHResultConsumerwas provided during JLBH setup, itsaccept(JLBHResult)method is called, passing theJLBHResultobject. This allows for programmatic access to the detailed results, for example, for assertion in automated tests or for custom serialization. -
External Tools: Users can further process the
JLBHResultusing utilities like:-
JLBHResultSerializerto write results to a CSV file for analysis in spreadsheets or other tools. -
TeamCityHelperto output statistics in a format suitable for TeamCity CI server integration.
-
The final phase ensures that any resources are properly released:
-
Task Cleanup: The
JLBHTask.complete()method is called, allowing the user’s benchmark task to perform any necessary cleanup (e.g., closing files, releasing network connections). -
OS Jitter Monitor: If the
OSJitterMonitorthread was started, it is signaled to terminate. -
Affinity Release: If a CPU affinity lock was acquired by JLBH at the start, it is released.