performance improvement

* pre-fill the buckets
* use LongObjHashMap to avoid boxing
This commit is contained in:
2022-11-20 16:37:05 +01:00
parent 65d4717c55
commit 7a82d4b09e
3 changed files with 58 additions and 17 deletions

View File

@@ -1,15 +1,13 @@
package org.lucares.pdb.plot.api; package org.lucares.pdb.plot.api;
import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map;
import java.util.UUID; import java.util.UUID;
import org.lucares.collections.LongObjHashMap;
import org.lucares.recommind.logs.GnuplotAxis; import org.lucares.recommind.logs.GnuplotAxis;
public class BoxAggregator implements CustomAggregator, IndexedAggregator { public class BoxAggregator implements CustomAggregator, IndexedAggregator {
private static final double SPACE_BETWEEN_BARS = 0.6;
private Long index = null; private Long index = null;
private Long numberOfDataSeries; private Long numberOfDataSeries;
@@ -17,19 +15,20 @@ public class BoxAggregator implements CustomAggregator, IndexedAggregator {
private final Interval interval; private final Interval interval;
private final Map<Long, PercentilesAggregator> buckets = new HashMap<>(); private final LongObjHashMap<PercentilesAggregator> buckets;
public BoxAggregator(final PlotSettings settings) { public BoxAggregator(final PlotSettings settings) {
this.interval = settings.getInterval().get(); this.interval = settings.getInterval().get();
this.buckets = interval.getMiddleTimeBuckets(PercentilesAggregator::new);
} }
@Override @Override
public void addValue(final long epochMilli, final long value) { public void addValue(final long epochMilli, final long value) {
final long bucketId = interval.toBucketMiddleTime(epochMilli); final long bucketId = interval.toBucketMiddleTime(epochMilli);
buckets.putIfAbsent(bucketId, new PercentilesAggregator()); final PercentilesAggregator bucket = buckets.get(bucketId);
buckets.get(bucketId).addValue(epochMilli, value); bucket.addValue(epochMilli, value);
} }
@Override @Override
@@ -76,9 +75,9 @@ public class BoxAggregator implements CustomAggregator, IndexedAggregator {
public String asCsv(final boolean renderLabels) { public String asCsv(final boolean renderLabels) {
final StringBuilder csv = new StringBuilder(); final StringBuilder csv = new StringBuilder();
int i = 0;
for (final long bucketId : buckets.keySet()) { buckets.forEachOrdered((final long bucketId, final PercentilesAggregator percentilesAggregator) -> {
final Percentiles percentiles = buckets.get(bucketId).getPercentiles(); final Percentiles percentiles = percentilesAggregator.getPercentiles();
csv.append(String.format(Locale.US, "%d,%d,%d,%d,%d,%d", // csv.append(String.format(Locale.US, "%d,%d,%d,%d,%d,%d", //
bucketId / 1000, // bucketId / 1000, //
percentiles.get("0.000"), // percentiles.get("0.000"), //
@@ -88,8 +87,8 @@ public class BoxAggregator implements CustomAggregator, IndexedAggregator {
percentiles.get("100.000")// percentiles.get("100.000")//
)); ));
csv.append("\n"); csv.append("\n");
i++; });
}
return csv.toString(); return csv.toString();
} }

View File

@@ -5,6 +5,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Supplier; import java.util.function.Supplier;
import org.lucares.collections.LongObjHashMap;
import org.lucares.pdb.api.DateTimeRange; import org.lucares.pdb.api.DateTimeRange;
import org.lucares.pdb.datastore.internal.LongToDateBucket; import org.lucares.pdb.datastore.internal.LongToDateBucket;
@@ -61,12 +62,15 @@ public class Interval {
return epochMilli - epochMilli % 3600000 + 1800000; return epochMilli - epochMilli % 3600000 + 1800000;
case DAY: case DAY:
return epochMilli - epochMilli % 86400000 + 43200000; return epochMilli - epochMilli % 86400000 + 43200000;
// case WEEK: case WEEK:
// return "YYYY-ww"; // use week based year! Otherwise intervals over the year boundary will be wrong return epochMilli - epochMilli % (7 * 24 * 3600 * 1000) + 7 * 24 * 3600 * 500; // use week based year!
// case MONTH: // Otherwise intervals over
// return "yyyy-MM"; // the year boundary will be
// case YEAR: // wrong
// return "yyyy"; 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: default:
throw new IllegalArgumentException("Unexpected value: " + intervalTimeUnit); throw new IllegalArgumentException("Unexpected value: " + intervalTimeUnit);
} }
@@ -104,4 +108,21 @@ public class Interval {
return result; return result;
} }
public <T> LongObjHashMap<T> getMiddleTimeBuckets(final Supplier<T> initialValueSupplier) {
final LongObjHashMap<T> 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;
}
} }

View File

@@ -34,4 +34,25 @@ public enum IntervalTimeUnit {
throw new IllegalArgumentException("Unexpected value: " + this); 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);
}
}
} }