You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

272 lines
5.1 KiB

  1. // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file. See the AUTHORS file for names of contributors.
  4. #include "util/histogram.h"
  5. #include <math.h>
  6. #include <stdio.h>
  7. #include "port/port.h"
  8. namespace leveldb {
  9. const double Histogram::kBucketLimit[kNumBuckets] = {
  10. 1,
  11. 2,
  12. 3,
  13. 4,
  14. 5,
  15. 6,
  16. 7,
  17. 8,
  18. 9,
  19. 10,
  20. 12,
  21. 14,
  22. 16,
  23. 18,
  24. 20,
  25. 25,
  26. 30,
  27. 35,
  28. 40,
  29. 45,
  30. 50,
  31. 60,
  32. 70,
  33. 80,
  34. 90,
  35. 100,
  36. 120,
  37. 140,
  38. 160,
  39. 180,
  40. 200,
  41. 250,
  42. 300,
  43. 350,
  44. 400,
  45. 450,
  46. 500,
  47. 600,
  48. 700,
  49. 800,
  50. 900,
  51. 1000,
  52. 1200,
  53. 1400,
  54. 1600,
  55. 1800,
  56. 2000,
  57. 2500,
  58. 3000,
  59. 3500,
  60. 4000,
  61. 4500,
  62. 5000,
  63. 6000,
  64. 7000,
  65. 8000,
  66. 9000,
  67. 10000,
  68. 12000,
  69. 14000,
  70. 16000,
  71. 18000,
  72. 20000,
  73. 25000,
  74. 30000,
  75. 35000,
  76. 40000,
  77. 45000,
  78. 50000,
  79. 60000,
  80. 70000,
  81. 80000,
  82. 90000,
  83. 100000,
  84. 120000,
  85. 140000,
  86. 160000,
  87. 180000,
  88. 200000,
  89. 250000,
  90. 300000,
  91. 350000,
  92. 400000,
  93. 450000,
  94. 500000,
  95. 600000,
  96. 700000,
  97. 800000,
  98. 900000,
  99. 1000000,
  100. 1200000,
  101. 1400000,
  102. 1600000,
  103. 1800000,
  104. 2000000,
  105. 2500000,
  106. 3000000,
  107. 3500000,
  108. 4000000,
  109. 4500000,
  110. 5000000,
  111. 6000000,
  112. 7000000,
  113. 8000000,
  114. 9000000,
  115. 10000000,
  116. 12000000,
  117. 14000000,
  118. 16000000,
  119. 18000000,
  120. 20000000,
  121. 25000000,
  122. 30000000,
  123. 35000000,
  124. 40000000,
  125. 45000000,
  126. 50000000,
  127. 60000000,
  128. 70000000,
  129. 80000000,
  130. 90000000,
  131. 100000000,
  132. 120000000,
  133. 140000000,
  134. 160000000,
  135. 180000000,
  136. 200000000,
  137. 250000000,
  138. 300000000,
  139. 350000000,
  140. 400000000,
  141. 450000000,
  142. 500000000,
  143. 600000000,
  144. 700000000,
  145. 800000000,
  146. 900000000,
  147. 1000000000,
  148. 1200000000,
  149. 1400000000,
  150. 1600000000,
  151. 1800000000,
  152. 2000000000,
  153. 2500000000.0,
  154. 3000000000.0,
  155. 3500000000.0,
  156. 4000000000.0,
  157. 4500000000.0,
  158. 5000000000.0,
  159. 6000000000.0,
  160. 7000000000.0,
  161. 8000000000.0,
  162. 9000000000.0,
  163. 1e200,
  164. };
  165. void Histogram::Clear() {
  166. min_ = kBucketLimit[kNumBuckets - 1];
  167. max_ = 0;
  168. num_ = 0;
  169. sum_ = 0;
  170. sum_squares_ = 0;
  171. for (int i = 0; i < kNumBuckets; i++) {
  172. buckets_[i] = 0;
  173. }
  174. }
  175. void Histogram::Add(double value) {
  176. // Linear search is fast enough for our usage in db_bench
  177. int b = 0;
  178. while (b < kNumBuckets - 1 && kBucketLimit[b] <= value) {
  179. b++;
  180. }
  181. buckets_[b] += 1.0;
  182. if (min_ > value) min_ = value;
  183. if (max_ < value) max_ = value;
  184. num_++;
  185. sum_ += value;
  186. sum_squares_ += (value * value);
  187. }
  188. void Histogram::Merge(const Histogram& other) {
  189. if (other.min_ < min_) min_ = other.min_;
  190. if (other.max_ > max_) max_ = other.max_;
  191. num_ += other.num_;
  192. sum_ += other.sum_;
  193. sum_squares_ += other.sum_squares_;
  194. for (int b = 0; b < kNumBuckets; b++) {
  195. buckets_[b] += other.buckets_[b];
  196. }
  197. }
  198. double Histogram::Median() const { return Percentile(50.0); }
  199. double Histogram::Percentile(double p) const {
  200. double threshold = num_ * (p / 100.0);
  201. double sum = 0;
  202. for (int b = 0; b < kNumBuckets; b++) {
  203. sum += buckets_[b];
  204. if (sum >= threshold) {
  205. // Scale linearly within this bucket
  206. double left_point = (b == 0) ? 0 : kBucketLimit[b - 1];
  207. double right_point = kBucketLimit[b];
  208. double left_sum = sum - buckets_[b];
  209. double right_sum = sum;
  210. double pos = (threshold - left_sum) / (right_sum - left_sum);
  211. double r = left_point + (right_point - left_point) * pos;
  212. if (r < min_) r = min_;
  213. if (r > max_) r = max_;
  214. return r;
  215. }
  216. }
  217. return max_;
  218. }
  219. double Histogram::Average() const {
  220. if (num_ == 0.0) return 0;
  221. return sum_ / num_;
  222. }
  223. double Histogram::StandardDeviation() const {
  224. if (num_ == 0.0) return 0;
  225. double variance = (sum_squares_ * num_ - sum_ * sum_) / (num_ * num_);
  226. return sqrt(variance);
  227. }
  228. std::string Histogram::ToString() const {
  229. std::string r;
  230. char buf[200];
  231. snprintf(buf, sizeof(buf), "Count: %.0f Average: %.4f StdDev: %.2f\n", num_,
  232. Average(), StandardDeviation());
  233. r.append(buf);
  234. snprintf(buf, sizeof(buf), "Min: %.4f Median: %.4f Max: %.4f\n",
  235. (num_ == 0.0 ? 0.0 : min_), Median(), max_);
  236. r.append(buf);
  237. r.append("------------------------------------------------------\n");
  238. const double mult = 100.0 / num_;
  239. double sum = 0;
  240. for (int b = 0; b < kNumBuckets; b++) {
  241. if (buckets_[b] <= 0.0) continue;
  242. sum += buckets_[b];
  243. snprintf(buf, sizeof(buf), "[ %7.0f, %7.0f ) %7.0f %7.3f%% %7.3f%% ",
  244. ((b == 0) ? 0.0 : kBucketLimit[b - 1]), // left
  245. kBucketLimit[b], // right
  246. buckets_[b], // count
  247. mult * buckets_[b], // percentage
  248. mult * sum); // cumulative percentage
  249. r.append(buf);
  250. // Add hash marks based on percentage; 20 marks for 100%.
  251. int marks = static_cast<int>(20 * (buckets_[b] / num_) + 0.5);
  252. r.append(marks, '#');
  253. r.push_back('\n');
  254. }
  255. return r;
  256. }
  257. } // namespace leveldb