Intro
(See the next iteration A tiny Java framework for gathering running time statistics - Take II.)
I have this tiny Java framework that allows users to gather running time statistics of a piece of code. It gathers:
- minimum running time of a
Runnable, - maximum running time,
- mean time,
- median time,
- standard deviation.
Code
package io.github.coderodde.statistics.run; import java.text.NumberFormat; /** * This class encapsulates the run statistics. * * @author Rodion "rodde" Efremov */ public final class RunStatistics { private final long minimumDuration; private final long maximumDuration; private final double meanDuration; private final double medianDuration; private final double standardDeviation; RunStatistics(final long minimumDuration, final long maximumDuration, final double meanDuration, final double medianDuration, final double standardDeviation) { this.minimumDuration = minimumDuration; this.maximumDuration = maximumDuration; this.meanDuration = meanDuration; this.medianDuration = medianDuration; this.standardDeviation = standardDeviation; } public long getMinimumDuration() { return minimumDuration; } public long getMaximumDuration() { return maximumDuration; } public double getMeanDuration() { return meanDuration; } public double getMedianDuration() { return medianDuration; } public double getStandardDeviation() { return standardDeviation; } @Override public String toString() { final NumberFormat nf = NumberFormat.getInstance(); return new StringBuilder("min = ") .append(nf.format(minimumDuration)) .append(" ns, max = ") .append(nf.format(maximumDuration)) .append(" ns, mean = ") .append(meanDuration) .append(" ns, median = ") .append(medianDuration) .append(" ns, sd = ") .append(standardDeviation) .append(" ns") .toString(); } } package io.github.coderodde.statistics.run; import java.util.ArrayList; import java.util.List; import java.util.Objects; /** * This class provides methods for obtaining the running time statistics. * * @author Rodion "rodde" Efremov */ public final class Runner { private static final int MINIMUM_ITERATIONS = 1; public static RunStatistics measure(final Runnable runnable, final int iterations) { Objects.requireNonNull(runnable, "The input runnable is null"); checkIterations(iterations); long minimumDuration = Long.MAX_VALUE; long maximumDuration = Long.MIN_VALUE; long meanDuration = 0; double medianDuration; double standardDeviation; final List<Long> durations = new ArrayList<>(iterations); for (int iteration = 0; iteration < iterations; iteration++) { final long ta = System.nanoTime(); runnable.run(); final long tb = System.nanoTime(); final long duration = tb - ta; minimumDuration = Math.min(minimumDuration, duration); maximumDuration = Math.max(maximumDuration, duration); meanDuration += duration; durations.add(duration); } meanDuration /= iterations; medianDuration = computeMedianDuration(durations); standardDeviation = computeStandardDeviation(durations, meanDuration); return new RunStatistics(minimumDuration, maximumDuration, meanDuration, medianDuration, standardDeviation); } public static RunStatistics measure(final List<Runnable> runnables) { Objects.requireNonNull(runnables, "The input runnables is null"); if (runnables.isEmpty()) { throw new IllegalArgumentException("Nothing to measure"); } long minimumDuration = Long.MAX_VALUE; long maximumDuration = Long.MIN_VALUE; long meanDuration = 0; double medianDuration; double standardDeviation; final List<Long> durations = new ArrayList<>(runnables.size()); for (final Runnable runnable : runnables) { final long ta = System.nanoTime(); runnable.run(); final long tb = System.nanoTime(); final long duration = tb - ta; minimumDuration = Math.min(minimumDuration, duration); maximumDuration = Math.max(maximumDuration, duration); meanDuration += duration; durations.add(duration); } meanDuration /= runnables.size(); medianDuration = computeMedianDuration(durations); standardDeviation = computeStandardDeviation(durations, meanDuration); return new RunStatistics(minimumDuration, maximumDuration, meanDuration, medianDuration, standardDeviation); } private static double computeMedianDuration(final List<Long> durations) { if (durations.size() % 2 == 1) { return durations.get(durations.size() / 2); } else { final int loIndex = durations.size() / 2 - 1; final int hiIndex = durations.size() / 2; return (durations.get(loIndex) + durations.get(hiIndex)) / 2.0; } } private static double computeStandardDeviation(final List<Long> durations, final long meanDuration) { double sum = 0.0; for (final Long duration : durations) { sum += Math.pow(duration - meanDuration, 2.0); } return Math.sqrt(sum / durations.size()); } private static void checkIterations(final int iterations) { if (iterations < MINIMUM_ITERATIONS) { final String exceptionMessage = String.format("Number of iterations (%d) is too small. " + "Must be at least %d.", iterations, MINIMUM_ITERATIONS); throw new IllegalArgumentException(exceptionMessage); } } } package io.github.coderodde.statistics.run.demo; import io.github.coderodde.statistics.run.RunStatistics; import io.github.coderodde.statistics.run.Runner; import java.util.Random; public class Demo { private static final Random RANDOM = new Random(13L); public static void main(String[] args) { final RunStatistics runStatistics = Runner.measure(() -> { try { Thread.sleep(RANDOM.nextInt(1_000)); } catch (InterruptedException ex) {} }, 10); System.out.println(runStatistics); } } Typical output
min = 101 821 100 ns, max = 998 058 800 ns, mean = 4.9199821E8 ns, median = 5.369435E8 ns, sd = 2.965745976223299E8 ns Critique request
Please, tell me anything that comes to mind.