You've already forked opentelemetry-go
mirror of
https://github.com/open-telemetry/opentelemetry-go.git
synced 2025-11-23 22:34:47 +02:00
Fixes https://github.com/open-telemetry/opentelemetry-go/issues/7035 Benchmarks with a default value of 2000. Parallel ``` goos: linux goarch: amd64 pkg: go.opentelemetry.io/otel/sdk/metric cpu: Intel(R) Xeon(R) CPU @ 2.20GHz │ main24.txt │ newwithlimit24.txt │ │ sec/op │ sec/op vs base │ SyncMeasure/NoView/ExemplarsDisabled/Int64Counter/Attributes/0-24 272.4n ± 6% 287.6n ± 11% ~ (p=0.310 n=6) SyncMeasure/NoView/ExemplarsDisabled/Int64Counter/Attributes/1-24 318.1n ± 9% 289.9n ± 11% ~ (p=0.093 n=6) SyncMeasure/NoView/ExemplarsDisabled/Int64Counter/Attributes/10-24 305.5n ± 13% 273.4n ± 9% ~ (p=0.180 n=6) SyncMeasure/NoView/ExemplarsDisabled/Float64Counter/Attributes/0-24 263.4n ± 14% 273.1n ± 12% ~ (p=0.485 n=6) SyncMeasure/NoView/ExemplarsDisabled/Float64Counter/Attributes/1-24 276.8n ± 8% 284.3n ± 10% ~ (p=0.310 n=6) SyncMeasure/NoView/ExemplarsDisabled/Float64Counter/Attributes/10-24 266.2n ± 10% 285.9n ± 16% ~ (p=0.394 n=6) SyncMeasure/NoView/ExemplarsDisabled/Int64UpDownCounter/Attributes/0-24 265.9n ± 11% 286.4n ± 14% ~ (p=0.310 n=6) SyncMeasure/NoView/ExemplarsDisabled/Int64UpDownCounter/Attributes/1-24 301.6n ± 16% 286.1n ± 6% ~ (p=0.310 n=6) SyncMeasure/NoView/ExemplarsDisabled/Int64UpDownCounter/Attributes/10-24 256.1n ± 16% 282.7n ± 14% +10.41% (p=0.041 n=6) SyncMeasure/NoView/ExemplarsDisabled/Float64UpDownCounter/Attributes/0-24 269.1n ± 19% 272.0n ± 6% ~ (p=0.485 n=6) SyncMeasure/NoView/ExemplarsDisabled/Float64UpDownCounter/Attributes/1-24 299.5n ± 12% 261.6n ± 16% -12.67% (p=0.013 n=6) SyncMeasure/NoView/ExemplarsDisabled/Float64UpDownCounter/Attributes/10-24 286.3n ± 16% 275.8n ± 10% ~ (p=0.310 n=6) SyncMeasure/NoView/ExemplarsDisabled/Int64Gauge/Attributes/0-24 265.4n ± 4% 243.1n ± 11% ~ (p=0.093 n=6) SyncMeasure/NoView/ExemplarsDisabled/Int64Gauge/Attributes/1-24 260.6n ± 10% 258.7n ± 17% ~ (p=0.818 n=6) SyncMeasure/NoView/ExemplarsDisabled/Int64Gauge/Attributes/10-24 266.6n ± 15% 251.8n ± 16% ~ (p=0.699 n=6) SyncMeasure/NoView/ExemplarsDisabled/Float64Gauge/Attributes/0-24 265.4n ± 9% 263.3n ± 13% ~ (p=0.818 n=6) SyncMeasure/NoView/ExemplarsDisabled/Float64Gauge/Attributes/1-24 271.7n ± 15% 305.4n ± 21% ~ (p=0.132 n=6) SyncMeasure/NoView/ExemplarsDisabled/Float64Gauge/Attributes/10-24 287.4n ± 13% 265.7n ± 9% ~ (p=0.093 n=6) SyncMeasure/NoView/ExemplarsDisabled/Int64Histogram/Attributes/0-24 276.6n ± 9% 300.4n ± 25% ~ (p=0.180 n=6) SyncMeasure/NoView/ExemplarsDisabled/Int64Histogram/Attributes/1-24 294.9n ± 11% 276.8n ± 21% ~ (p=0.818 n=6) SyncMeasure/NoView/ExemplarsDisabled/Int64Histogram/Attributes/10-24 308.3n ± 8% 281.4n ± 20% ~ (p=0.180 n=6) SyncMeasure/NoView/ExemplarsDisabled/Float64Histogram/Attributes/0-24 296.1n ± 13% 286.5n ± 14% ~ (p=0.937 n=6) SyncMeasure/NoView/ExemplarsDisabled/Float64Histogram/Attributes/1-24 329.0n ± 19% 299.6n ± 8% ~ (p=0.240 n=6) SyncMeasure/NoView/ExemplarsDisabled/Float64Histogram/Attributes/10-24 288.1n ± 28% 309.9n ± 14% ~ (p=0.937 n=6) SyncMeasure/NoView/ExemplarsDisabled/ExponentialInt64Histogram/Attributes/0-24 298.3n ± 12% 282.9n ± 9% ~ (p=0.240 n=6) SyncMeasure/NoView/ExemplarsDisabled/ExponentialInt64Histogram/Attributes/1-24 309.7n ± 4% 355.2n ± 11% +14.67% (p=0.002 n=6) SyncMeasure/NoView/ExemplarsDisabled/ExponentialInt64Histogram/Attributes/10-24 308.5n ± 12% 307.6n ± 15% ~ (p=1.000 n=6) SyncMeasure/NoView/ExemplarsDisabled/ExponentialFloat64Histogram/Attributes/0-24 294.1n ± 17% 289.1n ± 24% ~ (p=0.818 n=6) SyncMeasure/NoView/ExemplarsDisabled/ExponentialFloat64Histogram/Attributes/1-24 326.6n ± 13% 299.2n ± 14% ~ (p=0.240 n=6) SyncMeasure/NoView/ExemplarsDisabled/ExponentialFloat64Histogram/Attributes/10-24 329.8n ± 19% 283.7n ± 15% ~ (p=0.132 n=6) SyncMeasure/NoView/ExemplarsEnabled/Int64Counter/Attributes/0-24 269.9n ± 15% 266.7n ± 6% ~ (p=0.818 n=6) SyncMeasure/NoView/ExemplarsEnabled/Int64Counter/Attributes/1-24 297.4n ± 9% 271.9n ± 5% -8.59% (p=0.009 n=6) SyncMeasure/NoView/ExemplarsEnabled/Int64Counter/Attributes/10-24 326.4n ± 20% 276.3n ± 5% -15.32% (p=0.002 n=6) SyncMeasure/NoView/ExemplarsEnabled/Float64Counter/Attributes/0-24 298.1n ± 10% 259.6n ± 10% -12.92% (p=0.009 n=6) SyncMeasure/NoView/ExemplarsEnabled/Float64Counter/Attributes/1-24 311.4n ± 6% 276.8n ± 7% -11.11% (p=0.002 n=6) SyncMeasure/NoView/ExemplarsEnabled/Float64Counter/Attributes/10-24 312.4n ± 7% 264.1n ± 8% -15.45% (p=0.002 n=6) SyncMeasure/NoView/ExemplarsEnabled/Int64UpDownCounter/Attributes/0-24 286.2n ± 8% 272.9n ± 13% ~ (p=0.180 n=6) SyncMeasure/NoView/ExemplarsEnabled/Int64UpDownCounter/Attributes/1-24 310.1n ± 4% 289.2n ± 11% ~ (p=0.065 n=6) SyncMeasure/NoView/ExemplarsEnabled/Int64UpDownCounter/Attributes/10-24 329.8n ± 8% 277.1n ± 11% -15.95% (p=0.002 n=6) SyncMeasure/NoView/ExemplarsEnabled/Float64UpDownCounter/Attributes/0-24 261.4n ± 17% 262.8n ± 7% ~ (p=0.965 n=6) SyncMeasure/NoView/ExemplarsEnabled/Float64UpDownCounter/Attributes/1-24 292.3n ± 10% 271.2n ± 8% -7.22% (p=0.026 n=6) SyncMeasure/NoView/ExemplarsEnabled/Float64UpDownCounter/Attributes/10-24 306.6n ± 12% 271.9n ± 7% ~ (p=0.065 n=6) SyncMeasure/NoView/ExemplarsEnabled/Int64Gauge/Attributes/0-24 263.2n ± 22% 254.7n ± 6% ~ (p=0.240 n=6) SyncMeasure/NoView/ExemplarsEnabled/Int64Gauge/Attributes/1-24 284.8n ± 5% 285.0n ± 11% ~ (p=0.937 n=6) SyncMeasure/NoView/ExemplarsEnabled/Int64Gauge/Attributes/10-24 285.7n ± 17% 296.6n ± 10% ~ (p=0.485 n=6) SyncMeasure/NoView/ExemplarsEnabled/Float64Gauge/Attributes/0-24 272.3n ± 11% 261.4n ± 8% ~ (p=0.093 n=6) SyncMeasure/NoView/ExemplarsEnabled/Float64Gauge/Attributes/1-24 281.9n ± 21% 287.8n ± 11% ~ (p=0.937 n=6) SyncMeasure/NoView/ExemplarsEnabled/Float64Gauge/Attributes/10-24 283.3n ± 15% 254.3n ± 12% -10.24% (p=0.041 n=6) SyncMeasure/NoView/ExemplarsEnabled/Int64Histogram/Attributes/0-24 296.1n ± 13% 295.5n ± 9% ~ (p=0.937 n=6) SyncMeasure/NoView/ExemplarsEnabled/Int64Histogram/Attributes/1-24 310.0n ± 19% 301.7n ± 11% ~ (p=0.485 n=6) SyncMeasure/NoView/ExemplarsEnabled/Int64Histogram/Attributes/10-24 298.8n ± 17% 297.1n ± 3% ~ (p=0.937 n=6) SyncMeasure/NoView/ExemplarsEnabled/Float64Histogram/Attributes/0-24 303.4n ± 7% 280.9n ± 8% ~ (p=0.093 n=6) SyncMeasure/NoView/ExemplarsEnabled/Float64Histogram/Attributes/1-24 292.2n ± 14% 290.7n ± 13% ~ (p=1.000 n=6) SyncMeasure/NoView/ExemplarsEnabled/Float64Histogram/Attributes/10-24 313.9n ± 20% 314.4n ± 8% ~ (p=1.000 n=6) SyncMeasure/NoView/ExemplarsEnabled/ExponentialInt64Histogram/Attributes/0-24 289.8n ± 3% 287.3n ± 3% ~ (p=1.000 n=6) SyncMeasure/NoView/ExemplarsEnabled/ExponentialInt64Histogram/Attributes/1-24 321.0n ± 6% 308.7n ± 8% -3.82% (p=0.041 n=6) SyncMeasure/NoView/ExemplarsEnabled/ExponentialInt64Histogram/Attributes/10-24 313.1n ± 9% 315.4n ± 5% ~ (p=0.818 n=6) SyncMeasure/NoView/ExemplarsEnabled/ExponentialFloat64Histogram/Attributes/0-24 318.9n ± 13% 285.8n ± 24% ~ (p=0.180 n=6) SyncMeasure/NoView/ExemplarsEnabled/ExponentialFloat64Histogram/Attributes/1-24 319.0n ± 9% 317.0n ± 12% ~ (p=0.937 n=6) SyncMeasure/NoView/ExemplarsEnabled/ExponentialFloat64Histogram/Attributes/10-24 396.8n ± 15% 300.3n ± 5% -24.30% (p=0.002 n=6) geomean 294.1n 282.9n -3.80% ``` Single-threaded: ``` goos: linux goarch: amd64 pkg: go.opentelemetry.io/otel/sdk/metric cpu: Intel(R) Xeon(R) CPU @ 2.20GHz │ main1.txt │ newwithlimit1.txt │ │ sec/op │ sec/op vs base │ SyncMeasure/NoView/ExemplarsDisabled/Int64Counter/Attributes/0 117.5n ± 5% 109.8n ± 20% ~ (p=0.089 n=6) SyncMeasure/NoView/ExemplarsDisabled/Int64Counter/Attributes/1 128.5n ± 35% 118.5n ± 3% -7.79% (p=0.002 n=6) SyncMeasure/NoView/ExemplarsDisabled/Int64Counter/Attributes/10 126.4n ± 4% 117.3n ± 4% -7.16% (p=0.004 n=6) SyncMeasure/NoView/ExemplarsDisabled/Float64Counter/Attributes/0 110.4n ± 1% 112.2n ± 3% +1.59% (p=0.028 n=6) SyncMeasure/NoView/ExemplarsDisabled/Float64Counter/Attributes/1 119.8n ± 2% 118.4n ± 4% ~ (p=0.171 n=6) SyncMeasure/NoView/ExemplarsDisabled/Float64Counter/Attributes/10 120.1n ± 2% 121.9n ± 3% ~ (p=0.394 n=6) SyncMeasure/NoView/ExemplarsDisabled/Int64UpDownCounter/Attributes/0 117.3n ± 38% 109.5n ± 2% ~ (p=0.093 n=6) SyncMeasure/NoView/ExemplarsDisabled/Int64UpDownCounter/Attributes/1 120.8n ± 28% 119.9n ± 8% ~ (p=1.000 n=6) SyncMeasure/NoView/ExemplarsDisabled/Int64UpDownCounter/Attributes/10 121.1n ± 3% 117.0n ± 2% -3.38% (p=0.009 n=6) SyncMeasure/NoView/ExemplarsDisabled/Float64UpDownCounter/Attributes/0 111.8n ± 11% 111.0n ± 2% ~ (p=0.331 n=6) SyncMeasure/NoView/ExemplarsDisabled/Float64UpDownCounter/Attributes/1 121.7n ± 9% 117.5n ± 1% -3.49% (p=0.002 n=6) SyncMeasure/NoView/ExemplarsDisabled/Float64UpDownCounter/Attributes/10 126.5n ± 4% 122.3n ± 8% ~ (p=0.290 n=6) SyncMeasure/NoView/ExemplarsDisabled/Int64Gauge/Attributes/0 125.5n ± 25% 109.2n ± 3% -12.98% (p=0.002 n=6) SyncMeasure/NoView/ExemplarsDisabled/Int64Gauge/Attributes/1 121.7n ± 6% 116.5n ± 6% -4.31% (p=0.022 n=6) SyncMeasure/NoView/ExemplarsDisabled/Int64Gauge/Attributes/10 119.9n ± 4% 120.8n ± 4% ~ (p=0.838 n=6) SyncMeasure/NoView/ExemplarsDisabled/Float64Gauge/Attributes/0 112.5n ± 6% 109.7n ± 40% ~ (p=0.310 n=6) SyncMeasure/NoView/ExemplarsDisabled/Float64Gauge/Attributes/1 121.2n ± 6% 121.4n ± 3% ~ (p=0.727 n=6) SyncMeasure/NoView/ExemplarsDisabled/Float64Gauge/Attributes/10 118.6n ± 2% 120.5n ± 2% +1.69% (p=0.045 n=6) SyncMeasure/NoView/ExemplarsDisabled/Int64Histogram/Attributes/0 97.38n ± 14% 96.56n ± 10% ~ (p=0.240 n=6) SyncMeasure/NoView/ExemplarsDisabled/Int64Histogram/Attributes/1 107.1n ± 4% 105.6n ± 5% ~ (p=0.240 n=6) SyncMeasure/NoView/ExemplarsDisabled/Int64Histogram/Attributes/10 109.7n ± 5% 108.4n ± 3% ~ (p=0.221 n=6) SyncMeasure/NoView/ExemplarsDisabled/Float64Histogram/Attributes/0 98.30n ± 4% 96.02n ± 2% -2.31% (p=0.015 n=6) SyncMeasure/NoView/ExemplarsDisabled/Float64Histogram/Attributes/1 107.9n ± 9% 106.2n ± 14% ~ (p=0.180 n=6) SyncMeasure/NoView/ExemplarsDisabled/Float64Histogram/Attributes/10 107.6n ± 1% 107.0n ± 1% ~ (p=0.485 n=6) SyncMeasure/NoView/ExemplarsDisabled/ExponentialInt64Histogram/Attributes/0 151.5n ± 3% 149.7n ± 2% ~ (p=0.071 n=6) SyncMeasure/NoView/ExemplarsDisabled/ExponentialInt64Histogram/Attributes/1 161.2n ± 2% 158.5n ± 3% -1.67% (p=0.035 n=6) SyncMeasure/NoView/ExemplarsDisabled/ExponentialInt64Histogram/Attributes/10 162.3n ± 2% 159.9n ± 37% ~ (p=0.240 n=6) SyncMeasure/NoView/ExemplarsDisabled/ExponentialFloat64Histogram/Attributes/0 154.7n ± 10% 149.0n ± 1% -3.68% (p=0.002 n=6) SyncMeasure/NoView/ExemplarsDisabled/ExponentialFloat64Histogram/Attributes/1 161.0n ± 2% 160.5n ± 3% ~ (p=0.732 n=6) SyncMeasure/NoView/ExemplarsDisabled/ExponentialFloat64Histogram/Attributes/10 162.9n ± 1% 162.6n ± 27% ~ (p=0.838 n=6) SyncMeasure/NoView/ExemplarsEnabled/Int64Counter/Attributes/0 180.1n ± 4% 174.0n ± 7% ~ (p=0.065 n=6) SyncMeasure/NoView/ExemplarsEnabled/Int64Counter/Attributes/1 193.2n ± 12% 198.7n ± 10% ~ (p=1.000 n=6) SyncMeasure/NoView/ExemplarsEnabled/Int64Counter/Attributes/10 191.4n ± 43% 183.8n ± 3% -4.02% (p=0.004 n=6) SyncMeasure/NoView/ExemplarsEnabled/Float64Counter/Attributes/0 182.7n ± 5% 179.8n ± 4% ~ (p=0.132 n=6) SyncMeasure/NoView/ExemplarsEnabled/Float64Counter/Attributes/1 199.4n ± 3% 185.1n ± 2% -7.17% (p=0.002 n=6) SyncMeasure/NoView/ExemplarsEnabled/Float64Counter/Attributes/10 198.5n ± 6% 193.0n ± 5% ~ (p=0.589 n=6) SyncMeasure/NoView/ExemplarsEnabled/Int64UpDownCounter/Attributes/0 184.7n ± 19% 173.5n ± 5% ~ (p=0.058 n=6) SyncMeasure/NoView/ExemplarsEnabled/Int64UpDownCounter/Attributes/1 183.2n ± 7% 180.7n ± 2% -1.39% (p=0.037 n=6) SyncMeasure/NoView/ExemplarsEnabled/Int64UpDownCounter/Attributes/10 185.3n ± 21% 183.6n ± 3% ~ (p=0.180 n=6) SyncMeasure/NoView/ExemplarsEnabled/Float64UpDownCounter/Attributes/0 187.4n ± 7% 183.8n ± 6% ~ (p=0.310 n=6) SyncMeasure/NoView/ExemplarsEnabled/Float64UpDownCounter/Attributes/1 194.6n ± 4% 189.2n ± 2% -2.75% (p=0.004 n=6) SyncMeasure/NoView/ExemplarsEnabled/Float64UpDownCounter/Attributes/10 199.9n ± 5% 189.4n ± 3% -5.23% (p=0.026 n=6) SyncMeasure/NoView/ExemplarsEnabled/Int64Gauge/Attributes/0 179.2n ± 5% 187.7n ± 4% ~ (p=0.065 n=6) SyncMeasure/NoView/ExemplarsEnabled/Int64Gauge/Attributes/1 188.6n ± 2% 192.1n ± 4% ~ (p=0.221 n=6) SyncMeasure/NoView/ExemplarsEnabled/Int64Gauge/Attributes/10 186.2n ± 1% 189.9n ± 3% +2.04% (p=0.009 n=6) SyncMeasure/NoView/ExemplarsEnabled/Float64Gauge/Attributes/0 179.4n ± 4% 183.6n ± 8% ~ (p=0.093 n=6) SyncMeasure/NoView/ExemplarsEnabled/Float64Gauge/Attributes/1 188.0n ± 2% 190.6n ± 2% ~ (p=0.180 n=6) SyncMeasure/NoView/ExemplarsEnabled/Float64Gauge/Attributes/10 197.1n ± 6% 188.3n ± 6% ~ (p=0.180 n=6) SyncMeasure/NoView/ExemplarsEnabled/Int64Histogram/Attributes/0 222.6n ± 10% 227.8n ± 5% ~ (p=0.310 n=6) SyncMeasure/NoView/ExemplarsEnabled/Int64Histogram/Attributes/1 224.2n ± 7% 230.8n ± 6% ~ (p=0.937 n=6) SyncMeasure/NoView/ExemplarsEnabled/Int64Histogram/Attributes/10 240.6n ± 10% 233.6n ± 6% ~ (p=0.394 n=6) SyncMeasure/NoView/ExemplarsEnabled/Float64Histogram/Attributes/0 216.9n ± 4% 222.0n ± 5% ~ (p=0.937 n=6) SyncMeasure/NoView/ExemplarsEnabled/Float64Histogram/Attributes/1 223.3n ± 3% 221.4n ± 4% ~ (p=0.372 n=6) SyncMeasure/NoView/ExemplarsEnabled/Float64Histogram/Attributes/10 240.8n ± 5% 224.5n ± 19% ~ (p=0.093 n=6) SyncMeasure/NoView/ExemplarsEnabled/ExponentialInt64Histogram/Attributes/0 224.5n ± 2% 218.2n ± 2% -2.83% (p=0.030 n=6) SyncMeasure/NoView/ExemplarsEnabled/ExponentialInt64Histogram/Attributes/1 230.9n ± 2% 228.8n ± 1% -0.95% (p=0.026 n=6) SyncMeasure/NoView/ExemplarsEnabled/ExponentialInt64Histogram/Attributes/10 231.5n ± 4% 242.1n ± 5% ~ (p=0.093 n=6) SyncMeasure/NoView/ExemplarsEnabled/ExponentialFloat64Histogram/Attributes/0 237.1n ± 3% 221.8n ± 6% -6.47% (p=0.004 n=6) SyncMeasure/NoView/ExemplarsEnabled/ExponentialFloat64Histogram/Attributes/1 245.3n ± 0% 234.4n ± 4% -4.46% (p=0.002 n=6) SyncMeasure/NoView/ExemplarsEnabled/ExponentialFloat64Histogram/Attributes/10 249.3n ± 11% 240.9n ± 17% ~ (p=0.589 n=6) geomean 159.1n 156.0n -1.97% ``` --------- Co-authored-by: Robert Pająk <pellared@hotmail.com>
484 lines
12 KiB
Go
484 lines
12 KiB
Go
// Copyright The OpenTelemetry Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package aggregate // import "go.opentelemetry.io/otel/sdk/metric/internal/aggregate"
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"math"
|
|
"sync"
|
|
"time"
|
|
|
|
"go.opentelemetry.io/otel"
|
|
"go.opentelemetry.io/otel/attribute"
|
|
"go.opentelemetry.io/otel/sdk/metric/metricdata"
|
|
)
|
|
|
|
const (
|
|
expoMaxScale = 20
|
|
expoMinScale = -10
|
|
|
|
smallestNonZeroNormalFloat64 = 0x1p-1022
|
|
|
|
// These redefine the Math constants with a type, so the compiler won't coerce
|
|
// them into an int on 32 bit platforms.
|
|
maxInt64 int64 = math.MaxInt64
|
|
minInt64 int64 = math.MinInt64
|
|
)
|
|
|
|
// expoHistogramDataPoint is a single data point in an exponential histogram.
|
|
type expoHistogramDataPoint[N int64 | float64] struct {
|
|
attrs attribute.Set
|
|
res FilteredExemplarReservoir[N]
|
|
|
|
count uint64
|
|
min N
|
|
max N
|
|
sum N
|
|
|
|
maxSize int
|
|
noMinMax bool
|
|
noSum bool
|
|
|
|
scale int32
|
|
|
|
posBuckets expoBuckets
|
|
negBuckets expoBuckets
|
|
zeroCount uint64
|
|
}
|
|
|
|
func newExpoHistogramDataPoint[N int64 | float64](
|
|
attrs attribute.Set,
|
|
maxSize int,
|
|
maxScale int32,
|
|
noMinMax, noSum bool,
|
|
) *expoHistogramDataPoint[N] { // nolint:revive // we need this control flag
|
|
f := math.MaxFloat64
|
|
ma := N(f) // if N is int64, max will overflow to -9223372036854775808
|
|
mi := N(-f)
|
|
if N(maxInt64) > N(f) {
|
|
ma = N(maxInt64)
|
|
mi = N(minInt64)
|
|
}
|
|
return &expoHistogramDataPoint[N]{
|
|
attrs: attrs,
|
|
min: ma,
|
|
max: mi,
|
|
maxSize: maxSize,
|
|
noMinMax: noMinMax,
|
|
noSum: noSum,
|
|
scale: maxScale,
|
|
}
|
|
}
|
|
|
|
// record adds a new measurement to the histogram. It will rescale the buckets if needed.
|
|
func (p *expoHistogramDataPoint[N]) record(v N) {
|
|
p.count++
|
|
|
|
if !p.noMinMax {
|
|
if v < p.min {
|
|
p.min = v
|
|
}
|
|
if v > p.max {
|
|
p.max = v
|
|
}
|
|
}
|
|
if !p.noSum {
|
|
p.sum += v
|
|
}
|
|
|
|
absV := math.Abs(float64(v))
|
|
|
|
if float64(absV) == 0.0 {
|
|
p.zeroCount++
|
|
return
|
|
}
|
|
|
|
bin := p.getBin(absV)
|
|
|
|
bucket := &p.posBuckets
|
|
if v < 0 {
|
|
bucket = &p.negBuckets
|
|
}
|
|
|
|
// If the new bin would make the counts larger than maxScale, we need to
|
|
// downscale current measurements.
|
|
if scaleDelta := p.scaleChange(bin, bucket.startBin, len(bucket.counts)); scaleDelta > 0 {
|
|
if p.scale-scaleDelta < expoMinScale {
|
|
// With a scale of -10 there is only two buckets for the whole range of float64 values.
|
|
// This can only happen if there is a max size of 1.
|
|
otel.Handle(errors.New("exponential histogram scale underflow"))
|
|
return
|
|
}
|
|
// Downscale
|
|
p.scale -= scaleDelta
|
|
p.posBuckets.downscale(scaleDelta)
|
|
p.negBuckets.downscale(scaleDelta)
|
|
|
|
bin = p.getBin(absV)
|
|
}
|
|
|
|
bucket.record(bin)
|
|
}
|
|
|
|
// getBin returns the bin v should be recorded into.
|
|
func (p *expoHistogramDataPoint[N]) getBin(v float64) int32 {
|
|
frac, expInt := math.Frexp(v)
|
|
// 11-bit exponential.
|
|
exp := int32(expInt) // nolint: gosec
|
|
if p.scale <= 0 {
|
|
// Because of the choice of fraction is always 1 power of two higher than we want.
|
|
var correction int32 = 1
|
|
if frac == .5 {
|
|
// If v is an exact power of two the frac will be .5 and the exp
|
|
// will be one higher than we want.
|
|
correction = 2
|
|
}
|
|
return (exp - correction) >> (-p.scale)
|
|
}
|
|
return exp<<p.scale + int32(math.Log(frac)*scaleFactors[p.scale]) - 1
|
|
}
|
|
|
|
// scaleFactors are constants used in calculating the logarithm index. They are
|
|
// equivalent to 2^index/log(2).
|
|
var scaleFactors = [21]float64{
|
|
math.Ldexp(math.Log2E, 0),
|
|
math.Ldexp(math.Log2E, 1),
|
|
math.Ldexp(math.Log2E, 2),
|
|
math.Ldexp(math.Log2E, 3),
|
|
math.Ldexp(math.Log2E, 4),
|
|
math.Ldexp(math.Log2E, 5),
|
|
math.Ldexp(math.Log2E, 6),
|
|
math.Ldexp(math.Log2E, 7),
|
|
math.Ldexp(math.Log2E, 8),
|
|
math.Ldexp(math.Log2E, 9),
|
|
math.Ldexp(math.Log2E, 10),
|
|
math.Ldexp(math.Log2E, 11),
|
|
math.Ldexp(math.Log2E, 12),
|
|
math.Ldexp(math.Log2E, 13),
|
|
math.Ldexp(math.Log2E, 14),
|
|
math.Ldexp(math.Log2E, 15),
|
|
math.Ldexp(math.Log2E, 16),
|
|
math.Ldexp(math.Log2E, 17),
|
|
math.Ldexp(math.Log2E, 18),
|
|
math.Ldexp(math.Log2E, 19),
|
|
math.Ldexp(math.Log2E, 20),
|
|
}
|
|
|
|
// scaleChange returns the magnitude of the scale change needed to fit bin in
|
|
// the bucket. If no scale change is needed 0 is returned.
|
|
func (p *expoHistogramDataPoint[N]) scaleChange(bin, startBin int32, length int) int32 {
|
|
if length == 0 {
|
|
// No need to rescale if there are no buckets.
|
|
return 0
|
|
}
|
|
|
|
low := int(startBin)
|
|
high := int(bin)
|
|
if startBin >= bin {
|
|
low = int(bin)
|
|
high = int(startBin) + length - 1
|
|
}
|
|
|
|
var count int32
|
|
for high-low >= p.maxSize {
|
|
low >>= 1
|
|
high >>= 1
|
|
count++
|
|
if count > expoMaxScale-expoMinScale {
|
|
return count
|
|
}
|
|
}
|
|
return count
|
|
}
|
|
|
|
// expoBuckets is a set of buckets in an exponential histogram.
|
|
type expoBuckets struct {
|
|
startBin int32
|
|
counts []uint64
|
|
}
|
|
|
|
// record increments the count for the given bin, and expands the buckets if needed.
|
|
// Size changes must be done before calling this function.
|
|
func (b *expoBuckets) record(bin int32) {
|
|
if len(b.counts) == 0 {
|
|
b.counts = []uint64{1}
|
|
b.startBin = bin
|
|
return
|
|
}
|
|
|
|
endBin := int(b.startBin) + len(b.counts) - 1
|
|
|
|
// if the new bin is inside the current range
|
|
if bin >= b.startBin && int(bin) <= endBin {
|
|
b.counts[bin-b.startBin]++
|
|
return
|
|
}
|
|
// if the new bin is before the current start add spaces to the counts
|
|
if bin < b.startBin {
|
|
origLen := len(b.counts)
|
|
newLength := endBin - int(bin) + 1
|
|
shift := b.startBin - bin
|
|
|
|
if newLength > cap(b.counts) {
|
|
b.counts = append(b.counts, make([]uint64, newLength-len(b.counts))...)
|
|
}
|
|
|
|
copy(b.counts[shift:origLen+int(shift)], b.counts)
|
|
b.counts = b.counts[:newLength]
|
|
for i := 1; i < int(shift); i++ {
|
|
b.counts[i] = 0
|
|
}
|
|
b.startBin = bin
|
|
b.counts[0] = 1
|
|
return
|
|
}
|
|
// if the new is after the end add spaces to the end
|
|
if int(bin) > endBin {
|
|
if int(bin-b.startBin) < cap(b.counts) {
|
|
b.counts = b.counts[:bin-b.startBin+1]
|
|
for i := endBin + 1 - int(b.startBin); i < len(b.counts); i++ {
|
|
b.counts[i] = 0
|
|
}
|
|
b.counts[bin-b.startBin] = 1
|
|
return
|
|
}
|
|
|
|
end := make([]uint64, int(bin-b.startBin)-len(b.counts)+1)
|
|
b.counts = append(b.counts, end...)
|
|
b.counts[bin-b.startBin] = 1
|
|
}
|
|
}
|
|
|
|
// downscale shrinks a bucket by a factor of 2*s. It will sum counts into the
|
|
// correct lower resolution bucket.
|
|
func (b *expoBuckets) downscale(delta int32) {
|
|
// Example
|
|
// delta = 2
|
|
// Original offset: -6
|
|
// Counts: [ 3, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
|
|
// bins: -6 -5, -4, -3, -2, -1, 0, 1, 2, 3, 4
|
|
// new bins:-2, -2, -1, -1, -1, -1, 0, 0, 0, 0, 1
|
|
// new Offset: -2
|
|
// new Counts: [4, 14, 30, 10]
|
|
|
|
if len(b.counts) <= 1 || delta < 1 {
|
|
b.startBin >>= delta
|
|
return
|
|
}
|
|
|
|
steps := int32(1) << delta
|
|
offset := b.startBin % steps
|
|
offset = (offset + steps) % steps // to make offset positive
|
|
for i := 1; i < len(b.counts); i++ {
|
|
idx := i + int(offset)
|
|
if idx%int(steps) == 0 {
|
|
b.counts[idx/int(steps)] = b.counts[i]
|
|
continue
|
|
}
|
|
b.counts[idx/int(steps)] += b.counts[i]
|
|
}
|
|
|
|
lastIdx := (len(b.counts) - 1 + int(offset)) / int(steps)
|
|
b.counts = b.counts[:lastIdx+1]
|
|
b.startBin >>= delta
|
|
}
|
|
|
|
// newExponentialHistogram returns an Aggregator that summarizes a set of
|
|
// measurements as an exponential histogram. Each histogram is scoped by attributes
|
|
// and the aggregation cycle the measurements were made in.
|
|
func newExponentialHistogram[N int64 | float64](
|
|
maxSize, maxScale int32,
|
|
noMinMax, noSum bool,
|
|
limit int,
|
|
r func(attribute.Set) FilteredExemplarReservoir[N],
|
|
) *expoHistogram[N] {
|
|
return &expoHistogram[N]{
|
|
noSum: noSum,
|
|
noMinMax: noMinMax,
|
|
maxSize: int(maxSize),
|
|
maxScale: maxScale,
|
|
|
|
newRes: r,
|
|
limit: newLimiter[*expoHistogramDataPoint[N]](limit),
|
|
values: make(map[attribute.Distinct]*expoHistogramDataPoint[N]),
|
|
|
|
start: now(),
|
|
}
|
|
}
|
|
|
|
// expoHistogram summarizes a set of measurements as an histogram with exponentially
|
|
// defined buckets.
|
|
type expoHistogram[N int64 | float64] struct {
|
|
noSum bool
|
|
noMinMax bool
|
|
maxSize int
|
|
maxScale int32
|
|
|
|
newRes func(attribute.Set) FilteredExemplarReservoir[N]
|
|
limit limiter[*expoHistogramDataPoint[N]]
|
|
values map[attribute.Distinct]*expoHistogramDataPoint[N]
|
|
valuesMu sync.Mutex
|
|
|
|
start time.Time
|
|
}
|
|
|
|
func (e *expoHistogram[N]) measure(
|
|
ctx context.Context,
|
|
value N,
|
|
fltrAttr attribute.Set,
|
|
droppedAttr []attribute.KeyValue,
|
|
) {
|
|
// Ignore NaN and infinity.
|
|
if math.IsInf(float64(value), 0) || math.IsNaN(float64(value)) {
|
|
return
|
|
}
|
|
|
|
e.valuesMu.Lock()
|
|
defer e.valuesMu.Unlock()
|
|
|
|
v, ok := e.values[fltrAttr.Equivalent()]
|
|
if !ok {
|
|
fltrAttr = e.limit.Attributes(fltrAttr, e.values)
|
|
// If we overflowed, make sure we add to the existing overflow series
|
|
// if it already exists.
|
|
v, ok = e.values[fltrAttr.Equivalent()]
|
|
if !ok {
|
|
v = newExpoHistogramDataPoint[N](fltrAttr, e.maxSize, e.maxScale, e.noMinMax, e.noSum)
|
|
v.res = e.newRes(fltrAttr)
|
|
|
|
e.values[fltrAttr.Equivalent()] = v
|
|
}
|
|
}
|
|
v.record(value)
|
|
v.res.Offer(ctx, value, droppedAttr)
|
|
}
|
|
|
|
func (e *expoHistogram[N]) delta(
|
|
dest *metricdata.Aggregation, //nolint:gocritic // The pointer is needed for the ComputeAggregation interface
|
|
) int {
|
|
t := now()
|
|
|
|
// If *dest is not a metricdata.ExponentialHistogram, memory reuse is missed.
|
|
// In that case, use the zero-value h and hope for better alignment next cycle.
|
|
h, _ := (*dest).(metricdata.ExponentialHistogram[N])
|
|
h.Temporality = metricdata.DeltaTemporality
|
|
|
|
e.valuesMu.Lock()
|
|
defer e.valuesMu.Unlock()
|
|
|
|
n := len(e.values)
|
|
hDPts := reset(h.DataPoints, n, n)
|
|
|
|
var i int
|
|
for _, val := range e.values {
|
|
hDPts[i].Attributes = val.attrs
|
|
hDPts[i].StartTime = e.start
|
|
hDPts[i].Time = t
|
|
hDPts[i].Count = val.count
|
|
hDPts[i].Scale = val.scale
|
|
hDPts[i].ZeroCount = val.zeroCount
|
|
hDPts[i].ZeroThreshold = 0.0
|
|
|
|
hDPts[i].PositiveBucket.Offset = val.posBuckets.startBin
|
|
hDPts[i].PositiveBucket.Counts = reset(
|
|
hDPts[i].PositiveBucket.Counts,
|
|
len(val.posBuckets.counts),
|
|
len(val.posBuckets.counts),
|
|
)
|
|
copy(hDPts[i].PositiveBucket.Counts, val.posBuckets.counts)
|
|
|
|
hDPts[i].NegativeBucket.Offset = val.negBuckets.startBin
|
|
hDPts[i].NegativeBucket.Counts = reset(
|
|
hDPts[i].NegativeBucket.Counts,
|
|
len(val.negBuckets.counts),
|
|
len(val.negBuckets.counts),
|
|
)
|
|
copy(hDPts[i].NegativeBucket.Counts, val.negBuckets.counts)
|
|
|
|
if !e.noSum {
|
|
hDPts[i].Sum = val.sum
|
|
}
|
|
if !e.noMinMax {
|
|
hDPts[i].Min = metricdata.NewExtrema(val.min)
|
|
hDPts[i].Max = metricdata.NewExtrema(val.max)
|
|
}
|
|
|
|
collectExemplars(&hDPts[i].Exemplars, val.res.Collect)
|
|
|
|
i++
|
|
}
|
|
// Unused attribute sets do not report.
|
|
clear(e.values)
|
|
|
|
e.start = t
|
|
h.DataPoints = hDPts
|
|
*dest = h
|
|
return n
|
|
}
|
|
|
|
func (e *expoHistogram[N]) cumulative(
|
|
dest *metricdata.Aggregation, //nolint:gocritic // The pointer is needed for the ComputeAggregation interface
|
|
) int {
|
|
t := now()
|
|
|
|
// If *dest is not a metricdata.ExponentialHistogram, memory reuse is missed.
|
|
// In that case, use the zero-value h and hope for better alignment next cycle.
|
|
h, _ := (*dest).(metricdata.ExponentialHistogram[N])
|
|
h.Temporality = metricdata.CumulativeTemporality
|
|
|
|
e.valuesMu.Lock()
|
|
defer e.valuesMu.Unlock()
|
|
|
|
n := len(e.values)
|
|
hDPts := reset(h.DataPoints, n, n)
|
|
|
|
var i int
|
|
for _, val := range e.values {
|
|
hDPts[i].Attributes = val.attrs
|
|
hDPts[i].StartTime = e.start
|
|
hDPts[i].Time = t
|
|
hDPts[i].Count = val.count
|
|
hDPts[i].Scale = val.scale
|
|
hDPts[i].ZeroCount = val.zeroCount
|
|
hDPts[i].ZeroThreshold = 0.0
|
|
|
|
hDPts[i].PositiveBucket.Offset = val.posBuckets.startBin
|
|
hDPts[i].PositiveBucket.Counts = reset(
|
|
hDPts[i].PositiveBucket.Counts,
|
|
len(val.posBuckets.counts),
|
|
len(val.posBuckets.counts),
|
|
)
|
|
copy(hDPts[i].PositiveBucket.Counts, val.posBuckets.counts)
|
|
|
|
hDPts[i].NegativeBucket.Offset = val.negBuckets.startBin
|
|
hDPts[i].NegativeBucket.Counts = reset(
|
|
hDPts[i].NegativeBucket.Counts,
|
|
len(val.negBuckets.counts),
|
|
len(val.negBuckets.counts),
|
|
)
|
|
copy(hDPts[i].NegativeBucket.Counts, val.negBuckets.counts)
|
|
|
|
if !e.noSum {
|
|
hDPts[i].Sum = val.sum
|
|
}
|
|
if !e.noMinMax {
|
|
hDPts[i].Min = metricdata.NewExtrema(val.min)
|
|
hDPts[i].Max = metricdata.NewExtrema(val.max)
|
|
}
|
|
|
|
collectExemplars(&hDPts[i].Exemplars, val.res.Collect)
|
|
|
|
i++
|
|
// TODO (#3006): This will use an unbounded amount of memory if there
|
|
// are unbounded number of attribute sets being aggregated. Attribute
|
|
// sets that become "stale" need to be forgotten so this will not
|
|
// overload the system.
|
|
}
|
|
|
|
h.DataPoints = hDPts
|
|
*dest = h
|
|
return n
|
|
}
|