YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/util/hdr_histogram.h
Line
Count
Source (jump to first uncovered line)
1
// Licensed to the Apache Software Foundation (ASF) under one
2
// or more contributor license agreements.  See the NOTICE file
3
// distributed with this work for additional information
4
// regarding copyright ownership.  The ASF licenses this file
5
// to you under the Apache License, Version 2.0 (the
6
// "License"); you may not use this file except in compliance
7
// with the License.  You may obtain a copy of the License at
8
//
9
//   http://www.apache.org/licenses/LICENSE-2.0
10
//
11
// Unless required by applicable law or agreed to in writing,
12
// software distributed under the License is distributed on an
13
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
// KIND, either express or implied.  See the License for the
15
// specific language governing permissions and limitations
16
// under the License.
17
//
18
// The following only applies to changes made to this file as part of YugaByte development.
19
//
20
// Portions Copyright (c) YugaByte, Inc.
21
//
22
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
23
// in compliance with the License.  You may obtain a copy of the License at
24
//
25
// http://www.apache.org/licenses/LICENSE-2.0
26
//
27
// Unless required by applicable law or agreed to in writing, software distributed under the License
28
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
29
// or implied.  See the License for the specific language governing permissions and limitations
30
// under the License.
31
//
32
#ifndef YB_UTIL_HDR_HISTOGRAM_H
33
#define YB_UTIL_HDR_HISTOGRAM_H
34
35
// C++ (TR1) port of HdrHistogram.
36
// Original java implementation: http://giltene.github.io/HdrHistogram/
37
//
38
// A High Dynamic Range (HDR) Histogram
39
//
40
// HdrHistogram supports the recording and analyzing sampled data value counts
41
// across a configurable integer value range with configurable value precision
42
// within the range. Value precision is expressed as the number of significant
43
// digits in the value recording, and provides control over value quantization
44
// behavior across the value range and the subsequent value resolution at any
45
// given level.
46
//
47
// For example, a Histogram could be configured to track the counts of observed
48
// integer values between 0 and 3,600,000,000 while maintaining a value
49
// precision of 3 significant digits across that range. Value quantization
50
// within the range will thus be no larger than 1/1,000th (or 0.1%) of any
51
// value. This example Histogram could be used to track and analyze the counts
52
// of observed response times ranging between 1 microsecond and 1 hour in
53
// magnitude, while maintaining a value resolution of 1 microsecond up to 1
54
// millisecond, a resolution of 1 millisecond (or better) up to one second, and
55
// a resolution of 1 second (or better) up to 1,000 seconds. At it's maximum
56
// tracked value (1 hour), it would still maintain a resolution of 3.6 seconds
57
// (or better).
58
59
#include <iosfwd>
60
#include <memory>
61
62
#include "yb/gutil/atomicops.h"
63
#include "yb/gutil/macros.h"
64
65
#include "yb/util/status_fwd.h"
66
67
namespace yb {
68
69
class AbstractHistogramIterator;
70
class Status;
71
class RecordedValuesIterator;
72
73
// This implementation allows you to specify a range and accuracy (significant
74
// digits) to support in an instance of a histogram. The class takes care of
75
// the rest. At this time, only uint64_t values are supported.
76
//
77
// An HdrHistogram consists of a set of buckets, which bucket the magnitude of
78
// a value stored, and a set of sub-buckets, which implement the tunable
79
// precision of the storage. So if you specify 3 significant digits of
80
// precision, then you will get about 10^3 sub-buckets (as a power of 2) for
81
// each level of magnitude. Magnitude buckets are tracked in powers of 2.
82
//
83
// This class is thread-safe.
84
class HdrHistogram {
85
 public:
86
  // Specify the highest trackable value so that the class has a bound on the
87
  // number of buckets, and # of significant digits (in decimal) so that the
88
  // class can determine the granularity of those buckets.
89
  HdrHistogram(uint64_t highest_trackable_value, int num_significant_digits);
90
91
  // Copy-construct a (non-consistent) snapshot of other.
92
  explicit HdrHistogram(const HdrHistogram& other);
93
94
  // Validate your params before trying to construct the object.
95
  static bool IsValidHighestTrackableValue(uint64_t highest_trackable_value);
96
  static bool IsValidNumSignificantDigits(int num_significant_digits);
97
98
  // Record new data.
99
  void Increment(int64_t value);
100
  void IncrementBy(int64_t value, int64_t count);
101
102
  // Record new data, correcting for "coordinated omission".
103
  //
104
  // See https://groups.google.com/d/msg/mechanical-sympathy/icNZJejUHfE/BfDekfBEs_sJ
105
  // for more details.
106
  void IncrementWithExpectedInterval(int64_t value,
107
                                     int64_t expected_interval_between_samples);
108
109
  // Fetch configuration params.
110
4
  uint64_t highest_trackable_value() const { return highest_trackable_value_; }
111
0
  int num_significant_digits() const { return num_significant_digits_; }
112
113
  // Get indexes into histogram based on value.
114
  int BucketIndex(uint64_t value) const;
115
  int SubBucketIndex(uint64_t value, int bucket_index) const;
116
117
  // Count of all events recorded.
118
5.00M
  uint64_t TotalCount() const { return base::subtle::NoBarrier_Load(&total_count_); }
119
120
  // Count of all events recorded since last Reset. Resets to 0 after
121
  // ResetPercentiles.
122
580M
  uint64_t CurrentCount() const {
123
580M
    return base::subtle::NoBarrier_Load(&current_count_);
124
580M
  }
125
126
  // Sum of all events recorded.
127
4.92M
  uint64_t TotalSum() const { return base::subtle::NoBarrier_Load(&total_sum_); }
128
129
  // Sum of all events recorded since last Reset. Resets to 0 after
130
  // ResetPercentiles.
131
177k
  uint64_t CurrentSum() const {
132
177k
    return base::subtle::NoBarrier_Load(&current_sum_);
133
177k
  }
134
135
  // Return number of items at index.
136
  uint64_t CountAt(int bucket_index, int sub_bucket_index) const;
137
138
  // Return count of values in bucket with values equivalent to value.
139
  uint64_t CountInBucketForValue(uint64_t) const;
140
141
  // Return representative value based on index.
142
  static uint64_t ValueFromIndex(int bucket_index, int sub_bucket_index);
143
144
  // Get the size (in value units) of the range of values that are equivalent
145
  // to the given value within the histogram's resolution. Where "equivalent"
146
  // means that value samples recorded for any two equivalent values are
147
  // counted in a common total count.
148
  uint64_t SizeOfEquivalentValueRange(uint64_t value) const;
149
150
  // Get the lowest value that is equivalent to the given value within the
151
  // histogram's resolution. Where "equivalent" means that value samples
152
  // recorded for any two equivalent values are counted in a common total
153
  // count.
154
  uint64_t LowestEquivalentValue(uint64_t value) const;
155
156
  // Get the highest value that is equivalent to the given value within the
157
  // histogram's resolution.
158
  uint64_t HighestEquivalentValue(uint64_t value) const;
159
160
  // Get a value that lies in the middle (rounded up) of the range of values
161
  // equivalent the given value.
162
  uint64_t MedianEquivalentValue(uint64_t value) const;
163
164
  // Get the next value that is not equivalent to the given value within the
165
  // histogram's resolution.
166
  uint64_t NextNonEquivalentValue(uint64_t value) const;
167
168
  // Determine if two values are equivalent with the histogram's resolution.
169
  bool ValuesAreEquivalent(uint64_t value1, uint64_t value2) const;
170
171
  // Get the exact minimum value (may lie outside the histogram).
172
  uint64_t MinValue() const;
173
174
  // Get the exact maximum value (may lie outside the histogram).
175
  uint64_t MaxValue() const;
176
177
  // Get the exact mean value of all recorded values in the histogram.
178
  double MeanValue() const;
179
180
  // Get the value at a given percentile.
181
  // This is a percentile in percents, i.e. 99.99 percentile.
182
  uint64_t ValueAtPercentile(double percentile) const;
183
184
  // Resets the counts_ array to reset the percentiles information.
185
  // Preserves the values for TotalSum and TotalCount.
186
  void ResetPercentiles();
187
188
  // Get the percentile at a given value
189
  // TODO: implement
190
  // double PercentileAtOrBelowValue(uint64_t value) const;
191
192
  // Get the count of recorded values within a range of value levels.
193
  // (inclusive to within the histogram's resolution)
194
  // TODO: implement
195
  // uint64_t CountBetweenValues(uint64_t low_value, uint64_t high_value) const;
196
197
  // Dump a formatted, multiline string describing this histogram to 'out'.
198
  void DumpHumanReadable(std::ostream* out) const;
199
200
 private:
201
  friend class AbstractHistogramIterator;
202
203
  static const uint64_t kMinHighestTrackableValue = 2;
204
  static const int kMinValidNumSignificantDigits = 1;
205
  static const int kMaxValidNumSignificantDigits = 5;
206
207
  void Init();
208
  int CountsArrayIndex(int bucket_index, int sub_bucket_index) const;
209
210
  uint64_t highest_trackable_value_;
211
  int num_significant_digits_;
212
  int counts_array_length_;
213
  int bucket_count_;
214
  int sub_bucket_count_;
215
216
  // "Hot" fields in the write path.
217
  uint8_t sub_bucket_half_count_magnitude_;
218
  int sub_bucket_half_count_;
219
  uint32_t sub_bucket_mask_;
220
221
  // Also hot.
222
  // Non-resetting sum and counts.
223
  base::subtle::Atomic64 total_count_;
224
  base::subtle::Atomic64 total_sum_;
225
  // Resetting values
226
  base::subtle::Atomic64 current_count_;
227
  base::subtle::Atomic64 current_sum_;
228
  base::subtle::Atomic64 min_value_;
229
  base::subtle::Atomic64 max_value_;
230
  std::unique_ptr<base::subtle::Atomic64[]> counts_;
231
232
  HdrHistogram& operator=(const HdrHistogram& other); // Disable assignment operator.
233
};
234
235
// Value returned from iterators.
236
struct HistogramIterationValue {
237
  HistogramIterationValue()
238
    : value_iterated_to(0),
239
      value_iterated_from(0),
240
      count_at_value_iterated_to(0),
241
      count_added_in_this_iteration_step(0),
242
      total_count_to_this_value(0),
243
      total_value_to_this_value(0),
244
      percentile(0.0),
245
101
      percentile_level_iterated_to(0.0) {
246
101
  }
247
248
0
  void Reset() {
249
0
    value_iterated_to = 0;
250
0
    value_iterated_from = 0;
251
0
    count_at_value_iterated_to = 0;
252
0
    count_added_in_this_iteration_step = 0;
253
0
    total_count_to_this_value = 0;
254
0
    total_value_to_this_value = 0;
255
0
    percentile = 0.0;
256
0
    percentile_level_iterated_to = 0.0;
257
0
  }
258
259
  uint64_t value_iterated_to;
260
  uint64_t value_iterated_from;
261
  uint64_t count_at_value_iterated_to;
262
  uint64_t count_added_in_this_iteration_step;
263
  uint64_t total_count_to_this_value;
264
  uint64_t total_value_to_this_value;
265
  double percentile;
266
  double percentile_level_iterated_to;
267
};
268
269
// Base class for iterating through histogram values.
270
//
271
// The underlying histogram must not be modified or destroyed while this class
272
// is iterating over it.
273
//
274
// This class is not thread-safe.
275
class AbstractHistogramIterator {
276
 public:
277
  // Create iterator with new histogram.
278
  // The histogram must not be mutated while the iterator is in use.
279
  explicit AbstractHistogramIterator(const HdrHistogram* histogram);
280
1
  virtual ~AbstractHistogramIterator() {
281
1
  }
282
283
  // Returns true if the iteration has more elements.
284
  virtual bool HasNext() const;
285
286
  // Returns the next element in the iteration.
287
  CHECKED_STATUS Next(HistogramIterationValue* value);
288
289
  virtual double PercentileIteratedTo() const;
290
  virtual double PercentileIteratedFrom() const;
291
  uint64_t ValueIteratedTo() const;
292
293
 protected:
294
  // Implementations must override these methods.
295
  virtual void IncrementIterationLevel() = 0;
296
  virtual bool ReachedIterationLevel() const = 0;
297
298
  const HdrHistogram* histogram_;
299
  HistogramIterationValue cur_iter_val_;
300
301
  uint64_t histogram_total_count_;
302
303
  int current_bucket_index_;
304
  int current_sub_bucket_index_;
305
  uint64_t current_value_at_index_;
306
307
  int next_bucket_index_;
308
  int next_sub_bucket_index_;
309
  uint64_t next_value_at_index_;
310
311
  uint64_t prev_value_iterated_to_;
312
  uint64_t total_count_to_prev_index_;
313
314
  uint64_t total_count_to_current_index_;
315
  uint64_t total_value_to_current_index_;
316
317
  uint64_t count_at_this_value_;
318
319
 private:
320
  bool ExhaustedSubBuckets() const;
321
  void IncrementSubBucket();
322
323
  bool fresh_sub_bucket_;
324
325
  DISALLOW_COPY_AND_ASSIGN(AbstractHistogramIterator);
326
};
327
328
// Used for iterating through all recorded histogram values using the finest
329
// granularity steps supported by the underlying representation. The iteration
330
// steps through all non-zero recorded value counts, and terminates when all
331
// recorded histogram values are exhausted.
332
//
333
// The underlying histogram must not be modified or destroyed while this class
334
// is iterating over it.
335
//
336
// This class is not thread-safe.
337
class RecordedValuesIterator : public AbstractHistogramIterator {
338
 public:
339
  explicit RecordedValuesIterator(const HdrHistogram* histogram);
340
341
 protected:
342
  virtual void IncrementIterationLevel() override;
343
  virtual bool ReachedIterationLevel() const override;
344
345
 private:
346
  int visited_sub_bucket_index_;
347
  int visited_bucket_index_;
348
349
  DISALLOW_COPY_AND_ASSIGN(RecordedValuesIterator);
350
};
351
352
// Used for iterating through histogram values according to percentile levels.
353
// The iteration is performed in steps that start at 0% and reduce their
354
// distance to 100% according to the percentileTicksPerHalfDistance parameter,
355
// ultimately reaching 100% when all recorded histogram values are exhausted.
356
//
357
// The underlying histogram must not be modified or destroyed while this class
358
// is iterating over it.
359
//
360
// This class is not thread-safe.
361
class PercentileIterator : public AbstractHistogramIterator {
362
 public:
363
  // TODO: Explain percentile_ticks_per_half_distance.
364
  PercentileIterator(const HdrHistogram* histogram,
365
                     int percentile_ticks_per_half_distance);
366
  virtual bool HasNext() const override;
367
  virtual double PercentileIteratedTo() const override;
368
  virtual double PercentileIteratedFrom() const override;
369
370
 protected:
371
  virtual void IncrementIterationLevel() override;
372
  virtual bool ReachedIterationLevel() const override;
373
374
 private:
375
  int percentile_ticks_per_half_distance_;
376
  double percentile_level_to_iterate_to_;
377
  double percentile_level_to_iterate_from_;
378
  bool reached_last_recorded_value_;
379
380
  DISALLOW_COPY_AND_ASSIGN(PercentileIterator);
381
};
382
383
} // namespace yb
384
385
#endif // YB_UTIL_HDR_HISTOGRAM_H