Skip to content

Instantly share code, notes, and snippets.

@andsel
Created July 10, 2025 14:24
Show Gist options
  • Select an option

  • Save andsel/b56ba80e9bef1aaa95cf435f2366109b to your computer and use it in GitHub Desktop.

Select an option

Save andsel/b56ba80e9bef1aaa95cf435f2366109b to your computer and use it in GitHub Desktop.
HdrHistogram Record usage in multithreaded context
///usr/bin/env jbang "$0" "$@" ; exit $?
//DEPS info.picocli:picocli:4.6.3
//DEPS org.hdrhistogram:HdrHistogram:2.2.2
import picocli.CommandLine;
import picocli.CommandLine.Command;
import picocli.CommandLine.Option;
import picocli.CommandLine.Parameters;
import java.security.SecureRandom;
import java.time.Duration;
import java.util.List;
import java.util.ArrayList;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import org.HdrHistogram.Recorder;
import org.HdrHistogram.Histogram;
@Command(name = "hdrhistogram_cli", mixinStandardHelpOptions = true, version = "hdrhistogram_cli 0.1",
description = "hdrhistogram_cli made with jbang")
class hdrhistogram_cli implements Callable<Integer> {
@Option(names = {"-t", "--threads"}, description = "Number of concurrent writer to the HDR recorder instance")
private int numWriters;
public static void main(String... args) {
int exitCode = new CommandLine(new hdrhistogram_cli()).execute(args);
System.exit(exitCode);
}
@Override
public Integer call() throws Exception {
System.out.println("HdrHistoragm test start");
SecureRandom random = new SecureRandom();
Recorder recorder = new Recorder(1_000_000, 2);
if (numWriters == 0) {
numWriters = 1;
}
CountDownLatch recordersFinished = new CountDownLatch(numWriters);
List<Thread> writers = new ArrayList<>();
for (int j = 0; j < numWriters; j++) {
Thread metricWriter = new Thread(() -> {
metricRecroderLoop(recorder, random, recordersFinished);
});
metricWriter.start();
writers.add(metricWriter);
}
Thread reporter = new Thread(() -> {
Histogram intervalHistogram = recorder.getIntervalHistogram();
System.out.println("Estimation of histogram in bytes: " + intervalHistogram.getEstimatedFootprintInBytes());
printHistogram(intervalHistogram);
try {
System.out.println("thread | min | max | 50p | 90p |\n");
// till some recorder is around
while (!recordersFinished.await(10, TimeUnit.MILLISECONDS)) {
intervalHistogram.add(recorder.getIntervalHistogram());
printHistogram(intervalHistogram);
}
} catch (InterruptedException e) {
//somebody interrupted, exit
return;
}
});
reporter.setName("reporter");
reporter.start();
writers.stream().forEach(w -> joinInterruptable(w));
reporter.join(20_000);
return 0;
}
private static void metricRecroderLoop(Recorder recorder, SecureRandom random, CountDownLatch recordersFinished) {
try {
for (int i = 0; i < 1_000_000; i++) {
recorder.recordValue(random.nextInt(1_000_000));
Thread.sleep(Duration.ofNanos(1_000)); // 1 microsecond
}
recordersFinished.countDown();
} catch (InterruptedException e) {
//somebody interrupted, exit
return;
}
}
private static void joinInterruptable(Thread w) {
try {
w.join(20_000);
} catch (InterruptedException e) {
//somebody interrupted, exit
return;
}
}
private static void printHistogram(Histogram intervalHistogram) {
System.out.printf("%s | %d | %d | %d |%d |\n",
Thread.currentThread().getName(),
intervalHistogram.getMinValue(),
intervalHistogram.getMaxValue(),
intervalHistogram.getValueAtPercentile(50),
intervalHistogram.getValueAtPercentile(90));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment