From bea6096441d7ee4adf7e294bf9626f84f338f3e3 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Sun, 9 Oct 2022 17:01:53 +0200 Subject: [PATCH] extract computation of percentiles so that I can reuse the code for box plots --- ...umulativeDistributionCustomAggregator.java | 80 ++--------------- .../pdb/plot/api/PercentilesAggregator.java | 86 +++++++++++++++++++ 2 files changed, 93 insertions(+), 73 deletions(-) create mode 100644 pdb-plotting/src/main/java/org/lucares/pdb/plot/api/PercentilesAggregator.java diff --git a/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/CumulativeDistributionCustomAggregator.java b/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/CumulativeDistributionCustomAggregator.java index 23bbc7b..4f83468 100644 --- a/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/CumulativeDistributionCustomAggregator.java +++ b/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/CumulativeDistributionCustomAggregator.java @@ -8,90 +8,27 @@ import java.io.OutputStreamWriter; import java.io.Writer; import java.nio.charset.StandardCharsets; import java.nio.file.Path; -import java.util.Locale; -import org.lucares.collections.LongLongConsumer; -import org.lucares.collections.LongLongHashMap; import org.lucares.pdb.api.RuntimeIOException; public class CumulativeDistributionCustomAggregator implements CustomAggregator { - private final static int POINTS = 500; - - private static final class ToPercentiles implements LongLongConsumer { - - private long cumulativeCount = 0; - - private long maxValue = 0; - - private final Percentiles percentiles = new Percentiles(POINTS); - - private final double stepSize; - - private double lastPercentile; - private double nextPercentile; - - private final long totalValues; - - public ToPercentiles(final long totalValues) { - this.totalValues = totalValues; - stepSize = 100.0 / POINTS; - nextPercentile = stepSize; - } - - @Override - public void accept(final long duration, final long count) { - maxValue = duration; - - cumulativeCount += count; - final double newPercentile = cumulativeCount * 100.0 / totalValues; - - if (newPercentile >= nextPercentile) { - double currentPercentile = lastPercentile + stepSize; - while (currentPercentile <= newPercentile) { - final String percentile = String.format(Locale.US, "%.3f", currentPercentile); - percentiles.put(percentile, duration); - currentPercentile += stepSize; - } - nextPercentile = currentPercentile; - lastPercentile = currentPercentile - stepSize; - } - } - - public Percentiles getPercentiles() { - return percentiles; - } - - public void collect(final LongLongHashMap map) { - map.forEachOrdered(this); - percentiles.put("100.000", maxValue); - } - - } - - // the rather large initial capacity should prevent too many grow&re-hash phases - private final LongLongHashMap map = new LongLongHashMap(5_000, 0.75); - - private long totalValues = 0; - private final Path tmpDir; + private final PercentilesAggregator percentilesAggregator; + public CumulativeDistributionCustomAggregator(final Path tmpDir) { this.tmpDir = tmpDir; + percentilesAggregator = new PercentilesAggregator(); } @Override public void addValue(final long epochMilli, final long value) { - map.compute(value, 0, (__, l) -> l + 1); - totalValues++; + percentilesAggregator.addValue(epochMilli, value); } public Percentiles getPercentiles() { - final ToPercentiles toPercentiles = new ToPercentiles(totalValues); - toPercentiles.collect(map); - - final Percentiles result = toPercentiles.getPercentiles(); - return result; + return percentilesAggregator.getPercentiles(); } @Override @@ -100,17 +37,14 @@ public class CumulativeDistributionCustomAggregator implements CustomAggregator final char separator = ','; final char newline = '\n'; - final ToPercentiles toPercentiles = new ToPercentiles(totalValues); - toPercentiles.collect(map); - final File dataFile = File.createTempFile("data", ".dat", tmpDir.toFile()); try (final Writer output = new BufferedWriter( new OutputStreamWriter(new FileOutputStream(dataFile), StandardCharsets.US_ASCII));) { final StringBuilder data = new StringBuilder(); - if (map.size() > 0) { + if (percentilesAggregator.hasValues()) { // compute the percentiles - toPercentiles.getPercentiles().forEach((percentile, value) -> { + percentilesAggregator.getPercentiles().forEach((percentile, value) -> { data.append(percentile); data.append(separator); diff --git a/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/PercentilesAggregator.java b/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/PercentilesAggregator.java new file mode 100644 index 0000000..618d6d7 --- /dev/null +++ b/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/PercentilesAggregator.java @@ -0,0 +1,86 @@ +package org.lucares.pdb.plot.api; + +import java.util.Locale; + +import org.lucares.collections.LongLongConsumer; +import org.lucares.collections.LongLongHashMap; + +public class PercentilesAggregator { + private final static int POINTS = 500; + + private static final class ToPercentiles implements LongLongConsumer { + + private long cumulativeCount = 0; + + private long maxValue = 0; + + private final Percentiles percentiles = new Percentiles(POINTS); + + private final double stepSize; + + private double lastPercentile; + private double nextPercentile; + + private final long totalValues; + + public ToPercentiles(final long totalValues) { + this.totalValues = totalValues; + stepSize = 100.0 / POINTS; + nextPercentile = stepSize; + } + + @Override + public void accept(final long duration, final long count) { + maxValue = duration; + + cumulativeCount += count; + final double newPercentile = cumulativeCount * 100.0 / totalValues; + + if (newPercentile >= nextPercentile) { + double currentPercentile = lastPercentile + stepSize; + while (currentPercentile <= newPercentile) { + final String percentile = String.format(Locale.US, "%.3f", currentPercentile); + percentiles.put(percentile, duration); + currentPercentile += stepSize; + } + nextPercentile = currentPercentile; + lastPercentile = currentPercentile - stepSize; + } + } + + public Percentiles getPercentiles() { + return percentiles; + } + + public void collect(final LongLongHashMap map) { + map.forEachOrdered(this); + percentiles.put("100.000", maxValue); + } + + } + + // the rather large initial capacity should prevent too many grow&re-hash phases + private final LongLongHashMap map = new LongLongHashMap(5_000, 0.75); + + private long totalValues = 0; + + public PercentilesAggregator() { + } + + public void addValue(final long epochMilli, final long value) { + map.compute(value, 0, (__, l) -> l + 1); + totalValues++; + } + + public Percentiles getPercentiles() { + final ToPercentiles toPercentiles = new ToPercentiles(totalValues); + toPercentiles.collect(map); + + final Percentiles result = toPercentiles.getPercentiles(); + return result; + } + + public boolean hasValues() { + return map.size() > 0; + } +}