YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/yb/rocksdb/util/histogram.cc
Line
Count
Source (jump to first uncovered line)
1
//  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
2
//  This source code is licensed under the BSD-style license found in the
3
//  LICENSE file in the root directory of this source tree. An additional grant
4
//  of patent rights can be found in the PATENTS file in the same directory.
5
//
6
// The following only applies to changes made to this file as part of YugaByte development.
7
//
8
// Portions Copyright (c) YugaByte, Inc.
9
//
10
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
11
// in compliance with the License.  You may obtain a copy of the License at
12
//
13
// http://www.apache.org/licenses/LICENSE-2.0
14
//
15
// Unless required by applicable law or agreed to in writing, software distributed under the License
16
// is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
17
// or implied.  See the License for the specific language governing permissions and limitations
18
// under the License.
19
//
20
// Copyright (c) 2011 The LevelDB Authors. All rights reserved.
21
// Use of this source code is governed by a BSD-style license that can be
22
// found in the LICENSE file. See the AUTHORS file for names of contributors.
23
24
#include "yb/rocksdb/util/histogram.h"
25
26
#include <math.h>
27
28
#include "yb/gutil/port.h"
29
30
namespace rocksdb {
31
32
HistogramBucketMapper::HistogramBucketMapper()
33
    :
34
      // Add newer bucket index here.
35
      // Should be always added in sorted order.
36
      // If you change this, you also need to change the size of array buckets_ and the initial
37
      // value of min_ in HistogramImpl.
38
      bucketValues_(
39
          {1,         2,         3,         4,         5,         6,
40
           7,         8,         9,         10,        12,        14,
41
           16,        18,        20,        25,        30,        35,
42
           40,        45,        50,        60,        70,        80,
43
           90,        100,       120,       140,       160,       180,
44
           200,       250,       300,       350,       400,       450,
45
           500,       600,       700,       800,       900,       1000,
46
           1200,      1400,      1600,      1800,      2000,      2500,
47
           3000,      3500,      4000,      4500,      5000,      6000,
48
           7000,      8000,      9000,      10000,     12000,     14000,
49
           16000,     18000,     20000,     25000,     30000,     35000,
50
           40000,     45000,     50000,     60000,     70000,     80000,
51
           90000,     100000,    120000,    140000,    160000,    180000,
52
           200000,    250000,    300000,    350000,    400000,    450000,
53
           500000,    600000,    700000,    800000,    900000,    1000000,
54
           1200000,   1400000,   1600000,   1800000,   2000000,   2500000,
55
           3000000,   3500000,   4000000,   4500000,   5000000,   6000000,
56
           7000000,   8000000,   9000000,   10000000,  12000000,  14000000,
57
           16000000,  18000000,  20000000,  25000000,  30000000,  35000000,
58
           40000000,  45000000,  50000000,  60000000,  70000000,  80000000,
59
           90000000,  100000000, 120000000, 140000000, 160000000, 180000000,
60
           200000000, 250000000, 300000000, 350000000, 400000000, 450000000,
61
           500000000, 600000000, 700000000, 800000000, 900000000, 1000000000}),
62
      maxBucketValue_(bucketValues_.back()),
63
17.1k
      minBucketValue_(bucketValues_.front()) {
64
17.1k
  assert(kHistogramNumBuckets == BucketCount());
65
2.37M
  for (size_t i =0; i < bucketValues_.size(); ++i) {
66
2.36M
    valueIndexMap_[bucketValues_[i]] = i;
67
2.36M
  }
68
17.1k
}
69
70
4.65M
size_t HistogramBucketMapper::IndexForValue(const uint64_t value) const {
71
4.65M
  if (value >= maxBucketValue_) {
72
2
    return bucketValues_.size() - 1;
73
4.65M
  } else if ( value >= minBucketValue_ ) {
74
3.34M
    std::map<uint64_t, uint64_t>::const_iterator lowerBound =
75
3.34M
      valueIndexMap_.lower_bound(value);
76
3.34M
    if (lowerBound != valueIndexMap_.end()) {
77
3.34M
      return static_cast<size_t>(lowerBound->second);
78
18.4E
    } else {
79
18.4E
      return 0;
80
18.4E
    }
81
1.30M
  } else {
82
1.30M
    return 0;
83
1.30M
  }
84
4.65M
}
85
86
namespace {
87
  const HistogramBucketMapper bucketMapper;
88
}
89
90
37
void HistogramImpl::Clear() {
91
37
  set_min(static_cast<double>(bucketMapper.LastValue()));
92
37
  set_max(0);
93
37
  num_ = 0;
94
37
  sum_ = 0;
95
37
  sum_squares_ = 0;
96
5.14k
  for (int i = 0; i < kHistogramNumBuckets; ++i) {
97
5.10k
    set_bucket(i, 0);
98
5.10k
  }
99
37
}
100
101
28
bool HistogramImpl::Empty() { return num_ == 0; }
102
103
4.65M
void HistogramImpl::Add(uint64_t value) {
104
4.65M
  update_min(value);
105
4.65M
  update_max(value);
106
107
4.65M
  add_to_num(1);
108
4.65M
  add_to_sum(value);
109
4.65M
  add_to_sum_squares(static_cast<double>(value) * value);
110
111
  // TODO: maybe we should use int for IndexForValue's return value?
112
  // There are only 200 or so buckets.
113
4.65M
  add_to_bucket(static_cast<int>(bucketMapper.IndexForValue(value)), 1);
114
4.65M
}
115
116
0
void HistogramImpl::Merge(const HistogramImpl& other) {
117
0
  update_min(other.min());
118
0
  update_max(other.max());
119
0
  add_to_num(other.num_);
120
0
  add_to_sum(other.sum_);
121
0
  add_to_sum_squares(other.sum_squares_);
122
0
  for (unsigned int b = 0; b < bucketMapper.BucketCount(); b++) {
123
0
    add_to_bucket(b, other.bucket(b));
124
0
  }
125
0
}
126
127
3.90k
double HistogramImpl::Median() const {
128
3.90k
  return Percentile(50.0);
129
3.90k
}
130
131
23.4k
double HistogramImpl::Percentile(double p) const {
132
23.4k
  double threshold = num_ * (p / 100.0);
133
23.4k
  double sum = 0;
134
23.4k
  const double current_min = min();
135
23.4k
  const double current_max = max();
136
140k
  for (unsigned int b = 0; b < bucketMapper.BucketCount(); b++) {
137
140k
    sum += buckets_[b];
138
140k
    if (sum >= threshold) {
139
      // Scale linearly within this bucket
140
23.4k
      double left_point =
141
16.1k
        static_cast<double>((b == 0) ? 0 : bucketMapper.BucketLimit(b-1));
142
23.4k
      double right_point =
143
23.4k
        static_cast<double>(bucketMapper.BucketLimit(b));
144
23.4k
      double left_sum = sum - bucket(b);
145
23.4k
      double right_sum = sum;
146
23.4k
      double pos = 0;
147
23.4k
      double right_left_diff = right_sum - left_sum;
148
23.4k
      if (right_left_diff != 0) {
149
23.4k
       pos = (threshold - left_sum) / (right_sum - left_sum);
150
23.4k
      }
151
23.4k
      double r = left_point + (right_point - left_point) * pos;
152
23.4k
      if (r < current_min) r = current_min;
153
23.4k
      if (r > current_max) r = current_max;
154
23.4k
      return r;
155
23.4k
    }
156
140k
  }
157
1
  return current_max;
158
23.4k
}
159
160
3.92k
double HistogramImpl::Average() const {
161
3.92k
  if (num_ == 0.0) return 0;
162
3.92k
  return sum_ / num_;
163
3.92k
}
164
165
3.90k
double HistogramImpl::StandardDeviation() const {
166
3.90k
  if (num_ == 0.0) return 0;
167
3.90k
  double variance = (sum_squares_ * num_ - sum_ * sum_) / (num_ * num_);
168
3.90k
  return sqrt(variance);
169
3.90k
}
170
171
3.90k
std::string HistogramImpl::ToString() const {
172
3.90k
  std::string r;
173
3.90k
  char buf[200];
174
3.90k
  auto current_num = num();
175
3.90k
  snprintf(buf, sizeof(buf),
176
3.90k
           "Count: %.0f  Average: %.4f  StdDev: %.2f\n",
177
3.90k
           static_cast<double>(current_num), Average(), StandardDeviation());
178
3.90k
  r.append(buf);
179
3.90k
  snprintf(buf, sizeof(buf),
180
3.90k
           "Min: %.4f  Median: %.4f  Max: %.4f\n",
181
3.90k
           (current_num == 0.0 ? 0.0 : min()), Median(), max());
182
3.90k
  r.append(buf);
183
3.90k
  snprintf(buf, sizeof(buf),
184
3.90k
           "Percentiles: "
185
3.90k
           "P50: %.2f P75: %.2f P99: %.2f P99.9: %.2f P99.99: %.2f\n",
186
3.90k
           Percentile(50), Percentile(75), Percentile(99), Percentile(99.9),
187
3.90k
           Percentile(99.99));
188
3.90k
  r.append(buf);
189
3.90k
  r.append("------------------------------------------------------\n");
190
3.90k
  const double mult = 100.0 / current_num;
191
3.90k
  double sum = 0;
192
541k
  for (unsigned int b = 0; b < bucketMapper.BucketCount(); b++) {
193
538k
    const auto bucket_value = bucket(b);
194
538k
    if (bucket_value <= 0) continue;
195
6.76k
    sum += bucket_value;
196
6.76k
    snprintf(buf, sizeof(buf),
197
6.76k
             "[ %7" PRIu64 ", %7" PRIu64 " ) %8" PRIu64 " %7.3f%% %7.3f%% ",
198
3.72k
             b == 0 ? 0 : bucketMapper.BucketLimit(b - 1),  // left
199
6.76k
             bucketMapper.BucketLimit(b),                   // right
200
6.76k
             bucket_value,         // count
201
6.76k
             mult * bucket_value,  // percentage
202
6.76k
             mult * sum);          // cumulative percentage
203
6.76k
    r.append(buf);
204
205
    // Add hash marks based on percentage; 20 marks for 100%.
206
6.76k
    int marks = static_cast<int>(20*(bucket_value / current_num) + 0.5);
207
6.76k
    r.append(marks, '#');
208
6.76k
    r.push_back('\n');
209
6.76k
  }
210
3.90k
  return r;
211
3.90k
}
212
213
0
void HistogramImpl::Data(HistogramData * const data) const {
214
0
  assert(data);
215
0
  data->count = num_;
216
0
  data->sum = sum_;
217
0
  data->min = min();
218
0
  data->max = max();
219
0
  data->median = Median();
220
0
  data->percentile95 = Percentile(95);
221
0
  data->percentile99 = Percentile(99);
222
0
  data->average = Average();
223
0
  data->standard_deviation = StandardDeviation();
224
0
}
225
226
} // namespace rocksdb