1 // Copyright The OpenTelemetry Authors
2 // SPDX-License-Identifier: Apache-2.0
4 #ifdef ENABLE_METRICS_PREVIEW
5 # include "opentelemetry/sdk/_metrics/aggregator/sketch_aggregator.h"
7 # include <gtest/gtest.h>
12 namespace metrics_api
= opentelemetry::metrics
;
14 OPENTELEMETRY_BEGIN_NAMESPACE
20 // Test updating with a uniform set of updates
21 TEST(Sketch
, UniformValues
)
23 SketchAggregator
<int> alpha(metrics_api::InstrumentKind::ValueRecorder
, .000005);
25 EXPECT_EQ(alpha
.get_aggregator_kind(), AggregatorKind::Sketch
);
28 EXPECT_EQ(alpha
.get_checkpoint().size(), 2);
29 EXPECT_EQ(alpha
.get_boundaries().size(), 0);
30 EXPECT_EQ(alpha
.get_counts().size(), 0);
32 for (int i
= 0; i
< 60; i
++)
39 EXPECT_EQ(alpha
.get_boundaries().size(), 60);
40 EXPECT_EQ(alpha
.get_counts().size(), 60);
42 EXPECT_EQ(alpha
.get_checkpoint()[0], 1770);
43 EXPECT_EQ(alpha
.get_checkpoint()[1], 60);
46 // Test updating with a normal distribution
47 TEST(Sketch
, NormalValues
)
49 SketchAggregator
<int> alpha(metrics_api::InstrumentKind::ValueRecorder
, .0005);
51 std::vector
<int> vals
{1, 3, 3, 5, 5, 5, 7, 7, 7, 7, 9, 9, 9, 11, 11, 13};
58 EXPECT_EQ(alpha
.get_checkpoint()[0], std::accumulate(vals
.begin(), vals
.end(), 0));
59 EXPECT_EQ(alpha
.get_checkpoint()[1], vals
.size());
61 std::vector
<int> correct
= {1, 2, 3, 4, 3, 2, 1};
62 EXPECT_EQ(alpha
.get_counts(), correct
);
64 std::vector
<double> captured_bounds
= alpha
.get_boundaries();
65 for (size_t i
= 0; i
< captured_bounds
.size(); i
++)
67 captured_bounds
[i
] = round(captured_bounds
[i
]);
70 // It is not guaranteed that bounds are correct once the bucket sizes pass 1000
71 std::vector
<double> correct_bounds
= {1, 3, 5, 7, 9, 11, 13};
72 EXPECT_EQ(captured_bounds
, correct_bounds
);
77 return rand() % 100000;
80 /** Note that in this case, "Large" refers to a number of distinct values which exceed the maximum
81 * number of allowed buckets.
83 TEST(Sketch
, QuantileSmall
)
85 SketchAggregator
<int> alpha(metrics_api::InstrumentKind::ValueRecorder
, .00005);
87 std::vector
<int> vals1(2048);
88 std::generate(vals1
.begin(), vals1
.end(), randVal
);
90 std::vector
<int> vals2(2048);
91 std::generate(vals1
.begin(), vals1
.end(), randVal
);
98 std::sort(vals1
.begin(), vals1
.end());
100 EXPECT_TRUE(abs(alpha
.get_quantiles(.25) - vals1
[2048 * .25 - 1]) <= 10);
101 EXPECT_TRUE(abs(alpha
.get_quantiles(.50) - vals1
[2048 * .50 - 1]) <= 10);
102 EXPECT_TRUE(abs(alpha
.get_quantiles(.75) - vals1
[2048 * .75 - 1]) <= 10);
105 TEST(Sketch
, UpdateQuantileLarge
)
107 SketchAggregator
<int> alpha(metrics_api::InstrumentKind::ValueRecorder
, .0005, 7);
108 std::vector
<int> vals
{1, 3, 3, 5, 5, 5, 7, 7, 7, 7, 9, 9, 9, 11, 11, 13};
114 // This addition should trigger the "1" and "3" buckets to merge
118 std::vector
<int> correct
= {3, 3, 4, 3, 2, 1, 1};
119 EXPECT_EQ(alpha
.get_counts(), correct
);
129 correct
= {6, 4, 3, 2, 1, 1, 1};
130 EXPECT_EQ(alpha
.get_counts(), correct
);
133 TEST(Sketch
, MergeSmall
)
135 SketchAggregator
<int> alpha(metrics_api::InstrumentKind::ValueRecorder
, .0005);
136 SketchAggregator
<int> beta(metrics_api::InstrumentKind::ValueRecorder
, .0005);
138 std::vector
<int> vals
{1, 3, 3, 5, 5, 5, 7, 7, 7, 7, 9, 9, 9, 11, 11, 13};
144 std::vector
<int> otherVals
{1, 1, 1, 1, 11, 11, 13, 13, 13, 15};
145 for (int i
: otherVals
)
153 EXPECT_EQ(alpha
.get_checkpoint()[0], std::accumulate(vals
.begin(), vals
.end(), 0) +
154 std::accumulate(otherVals
.begin(), otherVals
.end(), 0));
155 EXPECT_EQ(alpha
.get_checkpoint()[1], vals
.size() + otherVals
.size());
157 std::vector
<int> correct
= {5, 2, 3, 4, 3, 4, 4, 1};
158 EXPECT_EQ(alpha
.get_counts(), correct
);
161 TEST(Sketch
, MergeLarge
)
163 SketchAggregator
<int> alpha(metrics_api::InstrumentKind::ValueRecorder
, .0005, 7);
164 SketchAggregator
<int> beta(metrics_api::InstrumentKind::ValueRecorder
, .0005, 7);
166 std::vector
<int> vals
{1, 3, 3, 5, 5, 5, 7, 7, 7, 7, 9, 9, 9, 11, 11, 13};
172 std::vector
<int> otherVals
{1, 1, 1, 1, 11, 11, 13, 13, 13, 15};
173 for (int i
: otherVals
)
181 EXPECT_EQ(alpha
.get_checkpoint()[0], std::accumulate(vals
.begin(), vals
.end(), 0) +
182 std::accumulate(otherVals
.begin(), otherVals
.end(), 0));
183 EXPECT_EQ(alpha
.get_checkpoint()[1], vals
.size() + otherVals
.size());
185 std::vector
<int> correct
= {7, 3, 4, 3, 4, 4, 1};
186 EXPECT_EQ(alpha
.get_counts(), correct
);
189 // Update callback used to validate multi-threaded performance
190 void sketchUpdateCallback(Aggregator
<int> &agg
, std::vector
<int> vals
)
198 TEST(Sketch
, Concurrency
)
200 SketchAggregator
<int> alpha(metrics_api::InstrumentKind::ValueRecorder
, .0005, 20);
202 std::vector
<int> vals1(1000);
203 std::generate(vals1
.begin(), vals1
.end(), randVal
);
205 std::vector
<int> vals2(1000);
206 std::generate(vals2
.begin(), vals2
.end(), randVal
);
208 std::thread
first(sketchUpdateCallback
, std::ref(alpha
), vals1
);
209 std::thread
second(sketchUpdateCallback
, std::ref(alpha
), vals2
);
214 SketchAggregator
<int> beta(metrics_api::InstrumentKind::ValueRecorder
, .0005, 20);
228 EXPECT_EQ(alpha
.get_checkpoint(), beta
.get_checkpoint());
229 EXPECT_EQ(alpha
.get_counts(), beta
.get_counts());
230 EXPECT_EQ(alpha
.get_boundaries(), beta
.get_boundaries());
238 SketchAggregator
<int> tol1(metrics_api::InstrumentKind::ValueRecorder
, .000005);
239 SketchAggregator
<int> tol2(metrics_api::InstrumentKind::ValueRecorder
, .005);
240 SketchAggregator
<int> sz1(metrics_api::InstrumentKind::ValueRecorder
, .000005, 2938);
241 SketchAggregator
<int> sz2(metrics_api::InstrumentKind::ValueRecorder
, .000005);
243 EXPECT_ANY_THROW(tol1
.merge(tol2
));
244 EXPECT_ANY_THROW(sz1
.merge(sz2
));
245 EXPECT_ANY_THROW(tol1
.get_quantiles(-.000001));
246 EXPECT_ANY_THROW(tol1
.get_quantiles(1.000001));
251 } // namespace metrics
253 OPENTELEMETRY_END_NAMESPACE