From 7a82d4b09eeaa6af038201c6392cc5c536898915 Mon Sep 17 00:00:00 2001 From: Andreas Huber Date: Sun, 20 Nov 2022 16:37:05 +0100 Subject: [PATCH] performance improvement * pre-fill the buckets * use LongObjHashMap to avoid boxing --- .../lucares/pdb/plot/api/BoxAggregator.java | 21 ++++++------ .../org/lucares/pdb/plot/api/Interval.java | 33 +++++++++++++++---- .../pdb/plot/api/IntervalTimeUnit.java | 21 ++++++++++++ 3 files changed, 58 insertions(+), 17 deletions(-) diff --git a/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/BoxAggregator.java b/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/BoxAggregator.java index f76bd27..25dcf4a 100644 --- a/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/BoxAggregator.java +++ b/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/BoxAggregator.java @@ -1,15 +1,13 @@ package org.lucares.pdb.plot.api; -import java.util.HashMap; import java.util.Locale; -import java.util.Map; import java.util.UUID; +import org.lucares.collections.LongObjHashMap; import org.lucares.recommind.logs.GnuplotAxis; public class BoxAggregator implements CustomAggregator, IndexedAggregator { - private static final double SPACE_BETWEEN_BARS = 0.6; private Long index = null; private Long numberOfDataSeries; @@ -17,19 +15,20 @@ public class BoxAggregator implements CustomAggregator, IndexedAggregator { private final Interval interval; - private final Map buckets = new HashMap<>(); + private final LongObjHashMap buckets; public BoxAggregator(final PlotSettings settings) { this.interval = settings.getInterval().get(); + this.buckets = interval.getMiddleTimeBuckets(PercentilesAggregator::new); } @Override public void addValue(final long epochMilli, final long value) { final long bucketId = interval.toBucketMiddleTime(epochMilli); - buckets.putIfAbsent(bucketId, new PercentilesAggregator()); - buckets.get(bucketId).addValue(epochMilli, value); + final PercentilesAggregator bucket = buckets.get(bucketId); + bucket.addValue(epochMilli, value); } @Override @@ -76,9 +75,9 @@ public class BoxAggregator implements CustomAggregator, IndexedAggregator { public String asCsv(final boolean renderLabels) { final StringBuilder csv = new StringBuilder(); - int i = 0; - for (final long bucketId : buckets.keySet()) { - final Percentiles percentiles = buckets.get(bucketId).getPercentiles(); + + buckets.forEachOrdered((final long bucketId, final PercentilesAggregator percentilesAggregator) -> { + final Percentiles percentiles = percentilesAggregator.getPercentiles(); csv.append(String.format(Locale.US, "%d,%d,%d,%d,%d,%d", // bucketId / 1000, // percentiles.get("0.000"), // @@ -88,8 +87,8 @@ public class BoxAggregator implements CustomAggregator, IndexedAggregator { percentiles.get("100.000")// )); csv.append("\n"); - i++; - } + }); + return csv.toString(); } diff --git a/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/Interval.java b/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/Interval.java index 3eefc60..6407593 100644 --- a/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/Interval.java +++ b/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/Interval.java @@ -5,6 +5,7 @@ import java.util.List; import java.util.Map; import java.util.function.Supplier; +import org.lucares.collections.LongObjHashMap; import org.lucares.pdb.api.DateTimeRange; import org.lucares.pdb.datastore.internal.LongToDateBucket; @@ -61,12 +62,15 @@ public class Interval { return epochMilli - epochMilli % 3600000 + 1800000; case DAY: return epochMilli - epochMilli % 86400000 + 43200000; -// case WEEK: -// return "YYYY-ww"; // use week based year! Otherwise intervals over the year boundary will be wrong -// case MONTH: -// return "yyyy-MM"; -// case YEAR: -// return "yyyy"; + case WEEK: + return epochMilli - epochMilli % (7 * 24 * 3600 * 1000) + 7 * 24 * 3600 * 500; // use week based year! + // Otherwise intervals over + // the year boundary will be + // wrong + case MONTH: + return epochMilli - epochMilli % (30 * 24 * 3600 * 1000L) + 30 * 24 * 3600 * 500L; + case YEAR: + return epochMilli - epochMilli % (365 * 24 * 3600 * 1000L) + 365 * 24 * 3600 * 500L; default: throw new IllegalArgumentException("Unexpected value: " + intervalTimeUnit); } @@ -104,4 +108,21 @@ public class Interval { return result; } + + public LongObjHashMap getMiddleTimeBuckets(final Supplier initialValueSupplier) { + final LongObjHashMap result = new LongObjHashMap<>(); + + long current = dateTimeRange.getStart().toInstant().toEpochMilli(); + final long end = dateTimeRange.getEnd().toInstant().toEpochMilli() + intervalTimeUnit.toMillis(); + + while (current <= end) { + + final long id = toBucketMiddleTime(current); + System.out.println("add bucket: " + id); + result.put(id, initialValueSupplier.get()); + current += intervalTimeUnit.toMillis(); + } + + return result; + } } diff --git a/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/IntervalTimeUnit.java b/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/IntervalTimeUnit.java index d903f13..9653f1b 100644 --- a/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/IntervalTimeUnit.java +++ b/pdb-plotting/src/main/java/org/lucares/pdb/plot/api/IntervalTimeUnit.java @@ -34,4 +34,25 @@ public enum IntervalTimeUnit { throw new IllegalArgumentException("Unexpected value: " + this); } } + + public long toMillis() { + switch (this) { + case SECOND: + return 1000; + case MINUTE: + return 60 * 1000; + case HOUR: + return 3600 * 1000; + case DAY: + return 24 * 3600 * 1000; + case WEEK: + return 7 * 24 * 3600 * 1000; + case MONTH: + return 30 * 24 * 3600 * 1000L; + case YEAR: + return 365 * 24 * 3600 * 1000L; + default: + throw new IllegalArgumentException("Unexpected value: " + this); + } + } } \ No newline at end of file