Skip to content

Commit 81ea997

Browse files
committed
move diff and merge to use union of all buckets approach
1 parent e4daa7b commit 81ea997

File tree

1 file changed

+108
-54
lines changed

1 file changed

+108
-54
lines changed

sdk/src/metrics/aggregation/base2_exponential_histogram_aggregation.cc

+108-54
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#include <algorithm>
88
#include <limits>
99
#include <memory>
10+
#include <iostream>
1011
#include <mutex>
1112
#include <utility>
1213
#include "opentelemetry/common/spin_lock_mutex.h"
@@ -186,6 +187,41 @@ void Base2ExponentialHistogramAggregation::Downscale(uint32_t by) noexcept
186187
indexer_ = Base2ExponentialHistogramIndexer(point_data_.scale_);
187188
}
188189

190+
// Merge A and B into a new circular buffer C.
191+
// Caller must ensure that A and B are used as buckets at the same scale.
192+
AdaptingCircularBufferCounter MergeBuckets(size_t max_buckets, const AdaptingCircularBufferCounter &A, const AdaptingCircularBufferCounter &B)
193+
{
194+
AdaptingCircularBufferCounter C = AdaptingCircularBufferCounter(max_buckets);
195+
C.Clear();
196+
197+
if (A.Empty() && B.Empty())
198+
{
199+
return C;
200+
}
201+
if (A.Empty())
202+
{
203+
return B;
204+
}
205+
if (B.Empty())
206+
{
207+
return A;
208+
}
209+
210+
auto min_index = (std::min)(A.StartIndex(), B.StartIndex());
211+
auto max_index = (std::max)(A.EndIndex(), B.EndIndex());
212+
213+
for (int i = min_index; i <= max_index; i++)
214+
{
215+
auto count = A.Get(i) + B.Get(i);
216+
if (count > 0)
217+
{
218+
C.Increment(i, count);
219+
}
220+
}
221+
222+
return C;
223+
}
224+
189225
std::unique_ptr<Aggregation> Base2ExponentialHistogramAggregation::Merge(
190226
const Aggregation &delta) const noexcept
191227
{
@@ -197,44 +233,50 @@ std::unique_ptr<Aggregation> Base2ExponentialHistogramAggregation::Merge(
197233
auto high_res = left.scale_ < right.scale_ ? right : left;
198234
auto scale_reduction = high_res.scale_ - low_res.scale_;
199235

200-
if (scale_reduction > 0)
201-
{
202-
DownscaleBuckets(&high_res.positive_buckets_, scale_reduction);
203-
DownscaleBuckets(&high_res.negative_buckets_, scale_reduction);
204-
high_res.scale_ -= scale_reduction;
205-
}
206-
207236
Base2ExponentialHistogramPointData result_value;
208237
result_value.count_ = low_res.count_ + high_res.count_;
209238
result_value.sum_ = low_res.sum_ + high_res.sum_;
210239
result_value.zero_count_ = low_res.zero_count_ + high_res.zero_count_;
211240
result_value.scale_ = (std::min)(low_res.scale_, high_res.scale_);
212-
result_value.max_buckets_ = low_res.max_buckets_;
241+
result_value.max_buckets_ = low_res.max_buckets_ >= high_res.max_buckets_
242+
? low_res.max_buckets_
243+
: high_res.max_buckets_;
213244
result_value.record_min_max_ = low_res.record_min_max_ && high_res.record_min_max_;
214245
if (result_value.record_min_max_)
215246
{
216247
result_value.min_ = (std::min)(low_res.min_, high_res.min_);
217248
result_value.max_ = (std::max)(low_res.max_, high_res.max_);
218249
}
219-
if (!high_res.positive_buckets_.Empty())
250+
251+
if (scale_reduction > 0)
220252
{
221-
for (int i = high_res.positive_buckets_.StartIndex();
222-
i <= high_res.positive_buckets_.EndIndex(); i++)
223-
{
224-
low_res.positive_buckets_.Increment(i, high_res.positive_buckets_.Get(i));
225-
}
253+
DownscaleBuckets(&high_res.positive_buckets_, scale_reduction);
254+
DownscaleBuckets(&high_res.negative_buckets_, scale_reduction);
255+
high_res.scale_ -= scale_reduction;
226256
}
227-
result_value.positive_buckets_ = std::move(low_res.positive_buckets_);
228257

229-
if (!high_res.negative_buckets_.Empty())
258+
auto pos_min_index = (std::min)(low_res.positive_buckets_.StartIndex(), high_res.positive_buckets_.StartIndex());
259+
auto pos_max_index = (std::max)(low_res.positive_buckets_.EndIndex(), high_res.positive_buckets_.EndIndex());
260+
auto neg_min_index = (std::min)(low_res.negative_buckets_.StartIndex(), high_res.negative_buckets_.StartIndex());
261+
auto neg_max_index = (std::max)(low_res.negative_buckets_.EndIndex(), high_res.negative_buckets_.EndIndex());
262+
263+
if (pos_max_index > pos_min_index + result_value.max_buckets_ || neg_max_index > neg_min_index + result_value.max_buckets_)
230264
{
231-
for (int i = high_res.negative_buckets_.StartIndex();
232-
i <= high_res.negative_buckets_.EndIndex(); i++)
233-
{
234-
low_res.negative_buckets_.Increment(i, high_res.negative_buckets_.Get(i));
235-
}
265+
// We need to downscale the buckets to fit into the new max_buckets_.
266+
const uint32_t scale_reduction = GetScaleReduction(pos_min_index, pos_max_index, result_value.max_buckets_);
267+
DownscaleBuckets(&low_res.positive_buckets_, scale_reduction);
268+
DownscaleBuckets(&high_res.positive_buckets_, scale_reduction);
269+
DownscaleBuckets(&low_res.negative_buckets_, scale_reduction);
270+
DownscaleBuckets(&high_res.negative_buckets_, scale_reduction);
271+
low_res.scale_ -= scale_reduction;
272+
high_res.scale_ -= scale_reduction;
273+
result_value.scale_ -= scale_reduction;
236274
}
237-
result_value.negative_buckets_ = std::move(low_res.negative_buckets_);
275+
276+
result_value.positive_buckets_ = MergeBuckets(result_value.max_buckets_, low_res.positive_buckets_,
277+
high_res.positive_buckets_);
278+
result_value.negative_buckets_ = MergeBuckets(result_value.max_buckets_, low_res.negative_buckets_,
279+
high_res.negative_buckets_);
238280

239281
return std::unique_ptr<Base2ExponentialHistogramAggregation>{
240282
new Base2ExponentialHistogramAggregation(std::move(result_value))};
@@ -258,58 +300,70 @@ std::unique_ptr<Aggregation> Base2ExponentialHistogramAggregation::Diff(
258300
high_res.scale_ -= scale_reduction;
259301
}
260302

303+
auto pos_min_index = (std::min)(left.positive_buckets_.StartIndex(), right.positive_buckets_.StartIndex());
304+
auto pos_max_index = (std::max)(left.positive_buckets_.EndIndex(), right.positive_buckets_.EndIndex());
305+
auto neg_min_index = (std::min)(left.negative_buckets_.StartIndex(), right.negative_buckets_.StartIndex());
306+
auto neg_max_index = (std::max)(left.negative_buckets_.EndIndex(), right.negative_buckets_.EndIndex());
307+
308+
if (pos_max_index > pos_min_index + low_res.max_buckets_ || neg_max_index > neg_min_index + low_res.max_buckets_)
309+
{
310+
// We need to downscale the buckets to fit into the new max_buckets_.
311+
const uint32_t scale_reduction = GetScaleReduction(pos_min_index, pos_max_index, low_res.max_buckets_);
312+
DownscaleBuckets(&left.positive_buckets_, scale_reduction);
313+
DownscaleBuckets(&right.positive_buckets_, scale_reduction);
314+
DownscaleBuckets(&left.negative_buckets_, scale_reduction);
315+
DownscaleBuckets(&right.negative_buckets_, scale_reduction);
316+
left.scale_ -= scale_reduction;
317+
right.scale_ -= scale_reduction;
318+
}
319+
261320
Base2ExponentialHistogramPointData result_value;
262321
result_value.scale_ = low_res.scale_;
263322
result_value.max_buckets_ = low_res.max_buckets_;
264323
result_value.record_min_max_ = false;
265324
// caution for underflow
266-
result_value.count_ = (left.count_ >= right.count_) ? (left.count_ - right.count_) : 0;
267-
result_value.sum_ = (left.sum_ >= right.sum_) ? (left.sum_ - right.sum_) : 0.0;
325+
// expect right.{sum, count} >= left.{sum, count} since metric points should be monotonically increasing
326+
result_value.count_ = (right.count_ >= left.count_) ? (right.count_ - left.count_) : 0.0;
327+
result_value.sum_ = (right.sum_ >= left.sum_) ? (right.sum_ - left.sum_) : 0.0;
268328
result_value.zero_count_ =
269-
(left.zero_count_ >= right.zero_count_) ? (left.zero_count_ - right.zero_count_) : 0;
270-
if (!high_res.positive_buckets_.Empty())
329+
(right.zero_count_ >= left.zero_count_) ? (right.zero_count_ - left.zero_count_) : 0;
330+
result_value.positive_buckets_ = AdaptingCircularBufferCounter{right.max_buckets_};
331+
result_value.negative_buckets_ = AdaptingCircularBufferCounter{right.max_buckets_};
332+
333+
if (!left.positive_buckets_.Empty() && !right.positive_buckets_.Empty())
271334
{
272-
for (int i = high_res.positive_buckets_.StartIndex();
273-
i <= high_res.positive_buckets_.EndIndex(); i++)
335+
for (auto i = pos_min_index; i <= pos_max_index; i++)
274336
{
275-
low_res.positive_buckets_.Increment(i, 0 - high_res.positive_buckets_.Get(i));
337+
auto l_cnt = left.positive_buckets_.Get(i);
338+
auto r_cnt = right.positive_buckets_.Get(i);
339+
// expect right >= left since metric points should be monotonically increasing
340+
auto delta = (std::max)((uint64_t)(0), r_cnt - l_cnt);
341+
if (l_cnt > 0)
342+
{
343+
result_value.positive_buckets_.Increment(i, delta);
344+
}
276345
}
277346
}
278-
result_value.positive_buckets_ = std::move(low_res.positive_buckets_);
279347

280-
if (!high_res.negative_buckets_.Empty())
348+
if (!left.negative_buckets_.Empty() && !right.negative_buckets_.Empty())
281349
{
282-
for (int i = high_res.negative_buckets_.StartIndex();
283-
i <= high_res.negative_buckets_.EndIndex(); i++)
350+
for (auto i = neg_min_index; i <= neg_max_index; i++)
284351
{
285-
low_res.negative_buckets_.Increment(i, 0 - high_res.negative_buckets_.Get(i));
352+
auto l_cnt = left.negative_buckets_.Get(i);
353+
auto r_cnt = right.negative_buckets_.Get(i);
354+
// expect right >= left since metric points should be monotonically increasing
355+
auto delta = (std::max)((uint64_t)(0), r_cnt - l_cnt);
356+
if (delta > 0)
357+
{
358+
result_value.negative_buckets_.Increment(i, delta);
359+
}
286360
}
287361
}
288-
result_value.negative_buckets_ = std::move(low_res.negative_buckets_);
289362

290363
return std::unique_ptr<Base2ExponentialHistogramAggregation>{
291364
new Base2ExponentialHistogramAggregation(std::move(result_value))};
292365
}
293366

294-
// std::unique_ptr<Aggregation> Base2ExponentialHistogramAggregation::Diff(
295-
// const Aggregation &next) const noexcept
296-
// {
297-
// auto curr_value = nostd::get<Base2ExponentialHistogramPointData>(ToPoint());
298-
// auto next_value = nostd::get<Base2ExponentialHistogramPointData>(
299-
// (static_cast<const Base2ExponentialHistogramAggregation &>(next).ToPoint()));
300-
301-
// Base2ExponentialHistogramPointData result_value;
302-
// result_value.scale_ = curr_value.scale_;
303-
// result_value.max_buckets_ = curr_value.max_buckets_;
304-
// result_value.record_min_max_ = false;
305-
// result_value.count_ = next_value.count_ - curr_value.count_;
306-
// result_value.sum_ = next_value.sum_ - curr_value.sum_;
307-
// result_value.zero_count_ = next_value.zero_count_ - curr_value.zero_count_;
308-
309-
// return std::unique_ptr<Base2ExponentialHistogramAggregation>{
310-
// new Base2ExponentialHistogramAggregation(std::move(result_value))};
311-
// }
312-
313367
PointType Base2ExponentialHistogramAggregation::ToPoint() const noexcept
314368
{
315369
const std::lock_guard<opentelemetry::common::SpinLockMutex> locked(lock_);

0 commit comments

Comments
 (0)