Use a wrapper of primitive long array for histogram counts. (#3854)
* Use a wrapper of primitive long array for histogram counts. * Fix * Better
This commit is contained in:
parent
85d705d841
commit
966c358ef1
|
|
@ -179,6 +179,18 @@ public abstract class Serializer implements AutoCloseable {
|
|||
writeEndRepeatedPrimitive();
|
||||
}
|
||||
|
||||
/** Serializes a {@code repeated fixed64} field. */
|
||||
public void serializeRepeatedFixed64(ProtoFieldInfo field, long[] values) throws IOException {
|
||||
if (values.length == 0) {
|
||||
return;
|
||||
}
|
||||
writeStartRepeatedPrimitive(field, WireFormat.FIXED64_SIZE, values.length);
|
||||
for (long value : values) {
|
||||
writeFixed64Value(value);
|
||||
}
|
||||
writeEndRepeatedPrimitive();
|
||||
}
|
||||
|
||||
/** Serializes a {@code repeated double} field. */
|
||||
public void serializeRepeatedDouble(ProtoFieldInfo field, List<Double> values)
|
||||
throws IOException {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import io.opentelemetry.exporter.otlp.internal.MarshalerUtil;
|
|||
import io.opentelemetry.exporter.otlp.internal.MarshalerWithSize;
|
||||
import io.opentelemetry.exporter.otlp.internal.Serializer;
|
||||
import io.opentelemetry.proto.metrics.v1.internal.HistogramDataPoint;
|
||||
import io.opentelemetry.sdk.internal.PrimitiveLongList;
|
||||
import io.opentelemetry.sdk.metrics.data.DoubleHistogramPointData;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
|
|
@ -85,7 +86,8 @@ final class HistogramDataPointMarshaler extends MarshalerWithSize {
|
|||
output.serializeFixed64(HistogramDataPoint.TIME_UNIX_NANO, timeUnixNano);
|
||||
output.serializeFixed64(HistogramDataPoint.COUNT, count);
|
||||
output.serializeDouble(HistogramDataPoint.SUM, sum);
|
||||
output.serializeRepeatedFixed64(HistogramDataPoint.BUCKET_COUNTS, bucketCounts);
|
||||
output.serializeRepeatedFixed64(
|
||||
HistogramDataPoint.BUCKET_COUNTS, PrimitiveLongList.toArray(bucketCounts));
|
||||
output.serializeRepeatedDouble(HistogramDataPoint.EXPLICIT_BOUNDS, explicitBounds);
|
||||
output.serializeRepeatedMessage(HistogramDataPoint.EXEMPLARS, exemplars);
|
||||
output.serializeRepeatedMessage(HistogramDataPoint.ATTRIBUTES, attributes);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.sdk.internal;
|
||||
|
||||
import java.util.AbstractList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A list of longs backed by, and exposing, an array of primitives. Values will be boxed on demand
|
||||
* when using standard List operations. Operations should generally use the static methods in this
|
||||
* class to operate directly on the backing array instead. The idea is that in almost all apps, the
|
||||
* list will only be accessed by our internal code, and if it does happen to be used elsewhere,
|
||||
* performance of on-demand boxing isn't prohibitive while still providing expected ergonomics.
|
||||
*
|
||||
* <p>This class is internal and is hence not for public use. Its APIs are unstable and can change
|
||||
* at any time.
|
||||
*/
|
||||
public final class PrimitiveLongList {
|
||||
|
||||
/**
|
||||
* Returns a list that wraps the primitive array. Modifications in the array will be visible in
|
||||
* the list.
|
||||
*/
|
||||
public static List<Long> wrap(long[] values) {
|
||||
return new LongListImpl(values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a primitive array with the values of the list. The list should generally have been
|
||||
* created with {@link PrimitiveLongList#wrap(long[])}.
|
||||
*/
|
||||
public static long[] toArray(List<Long> list) {
|
||||
if (list instanceof LongListImpl) {
|
||||
return ((LongListImpl) list).values;
|
||||
}
|
||||
|
||||
long[] values = new long[list.size()];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
values[i] = list.get(i);
|
||||
}
|
||||
return values;
|
||||
}
|
||||
|
||||
private static class LongListImpl extends AbstractList<Long> {
|
||||
|
||||
private final long[] values;
|
||||
|
||||
LongListImpl(long[] values) {
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long get(int index) {
|
||||
// If out of bounds, the array access will produce a perfectly fine IndexOutOfBoundsException.
|
||||
return values[index];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return values.length;
|
||||
}
|
||||
}
|
||||
|
||||
private PrimitiveLongList() {}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
/*
|
||||
* Copyright The OpenTelemetry Authors
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
package io.opentelemetry.sdk.internal;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatThrownBy;
|
||||
import static org.assertj.core.api.Assertions.catchThrowable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class PrimitiveLongListTest {
|
||||
|
||||
@Test
|
||||
void wrap() {
|
||||
long[] array = new long[] {1, 2};
|
||||
List<Long> wrapped = PrimitiveLongList.wrap(array);
|
||||
// Standard List operations
|
||||
assertThat(wrapped).containsExactly(1L, 2L);
|
||||
assertThat(wrapped).hasSize(2);
|
||||
// Message can change between Java versions, so instead check it's the same as a normal List's
|
||||
// exception.
|
||||
Throwable referenceException = catchThrowable(() -> Arrays.asList(1, 2).get(3));
|
||||
assertThatThrownBy(() -> wrapped.get(3))
|
||||
.isInstanceOf(IndexOutOfBoundsException.class)
|
||||
.hasMessage(referenceException.getMessage());
|
||||
|
||||
assertThat(PrimitiveLongList.toArray(wrapped)).isSameAs(array).containsExactly(1L, 2L);
|
||||
}
|
||||
|
||||
@Test
|
||||
void notWrapped() {
|
||||
List<Long> list = Arrays.asList(1L, 2L);
|
||||
assertThat(PrimitiveLongList.toArray(list)).containsExactly(1L, 2L);
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ package io.opentelemetry.sdk.metrics.data;
|
|||
|
||||
import com.google.auto.value.AutoValue;
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.sdk.internal.PrimitiveLongList;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
|
@ -69,7 +70,7 @@ public abstract class DoubleHistogramPointData implements PointData {
|
|||
}
|
||||
|
||||
long totalCount = 0;
|
||||
for (long c : counts) {
|
||||
for (long c : PrimitiveLongList.toArray(counts)) {
|
||||
totalCount += c;
|
||||
}
|
||||
return new AutoValue_DoubleHistogramPointData(
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
package io.opentelemetry.sdk.metrics.internal.aggregator;
|
||||
|
||||
import io.opentelemetry.api.common.Attributes;
|
||||
import io.opentelemetry.sdk.internal.PrimitiveLongList;
|
||||
import io.opentelemetry.sdk.metrics.common.InstrumentType;
|
||||
import io.opentelemetry.sdk.metrics.data.DoubleHistogramPointData;
|
||||
import io.opentelemetry.sdk.metrics.data.DoublePointData;
|
||||
|
|
@ -77,10 +78,7 @@ final class MetricDataUtils {
|
|||
List<DoubleHistogramPointData> points = new ArrayList<>(accumulationMap.size());
|
||||
accumulationMap.forEach(
|
||||
(labels, aggregator) -> {
|
||||
List<Long> counts = new ArrayList<>(aggregator.getCounts().length);
|
||||
for (long v : aggregator.getCounts()) {
|
||||
counts.add(v);
|
||||
}
|
||||
List<Long> counts = PrimitiveLongList.wrap(aggregator.getCounts().clone());
|
||||
points.add(
|
||||
DoubleHistogramPointData.create(
|
||||
startEpochNanos,
|
||||
|
|
|
|||
Loading…
Reference in New Issue