From e0a6e64fc765cbe95ffe29ee4b90cbcf2e12b4ad Mon Sep 17 00:00:00 2001 From: Eugene Ma Date: Mon, 18 Nov 2024 13:56:03 -0800 Subject: [PATCH] lazily initialize ReservoirCells (#6851) Co-authored-by: jack-berg <34418638+jack-berg@users.noreply.github.com> --- .../exemplar/FixedSizeExemplarReservoir.java | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/FixedSizeExemplarReservoir.java b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/FixedSizeExemplarReservoir.java index 05dfdd1afd..20254de599 100644 --- a/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/FixedSizeExemplarReservoir.java +++ b/sdk/metrics/src/main/java/io/opentelemetry/sdk/metrics/internal/exemplar/FixedSizeExemplarReservoir.java @@ -13,13 +13,16 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.function.BiFunction; +import javax.annotation.Nullable; /** Base for fixed-size reservoir sampling of Exemplars. */ abstract class FixedSizeExemplarReservoir implements ExemplarReservoir { - private final ReservoirCell[] storage; + @Nullable private ReservoirCell[] storage; private final ReservoirCellSelector reservoirCellSelector; private final BiFunction mapAndResetCell; + private final int size; + private final Clock clock; private volatile boolean hasMeasurements = false; /** Instantiates an exemplar reservoir of fixed size. */ @@ -28,16 +31,18 @@ abstract class FixedSizeExemplarReservoir implements Exe int size, ReservoirCellSelector reservoirCellSelector, BiFunction mapAndResetCell) { - this.storage = new ReservoirCell[size]; - for (int i = 0; i < size; ++i) { - this.storage[i] = new ReservoirCell(clock); - } + this.storage = null; // lazily initialize to avoid allocations + this.size = size; + this.clock = clock; this.reservoirCellSelector = reservoirCellSelector; this.mapAndResetCell = mapAndResetCell; } @Override public void offerLongMeasurement(long value, Attributes attributes, Context context) { + if (storage == null) { + storage = initStorage(); + } int bucket = reservoirCellSelector.reservoirCellIndexFor(storage, value, attributes, context); if (bucket != -1) { this.storage[bucket].recordLongMeasurement(value, attributes, context); @@ -47,6 +52,9 @@ abstract class FixedSizeExemplarReservoir implements Exe @Override public void offerDoubleMeasurement(double value, Attributes attributes, Context context) { + if (storage == null) { + storage = initStorage(); + } int bucket = reservoirCellSelector.reservoirCellIndexFor(storage, value, attributes, context); if (bucket != -1) { this.storage[bucket].recordDoubleMeasurement(value, attributes, context); @@ -54,9 +62,17 @@ abstract class FixedSizeExemplarReservoir implements Exe } } + private ReservoirCell[] initStorage() { + ReservoirCell[] storage = new ReservoirCell[this.size]; + for (int i = 0; i < size; ++i) { + storage[i] = new ReservoirCell(this.clock); + } + return storage; + } + @Override public List collectAndReset(Attributes pointAttributes) { - if (!hasMeasurements) { + if (!hasMeasurements || storage == null) { return Collections.emptyList(); } // Note: we are collecting exemplars from buckets piecemeal, but we