1 /**
2 * hdr_histogram.c
3 * Written by Michael Barker and released to the public domain,
4 * as explained at http://creativecommons.org/publicdomain/zero/1.0/
5 */
6
7 #include <stdlib.h>
8 #include <stdbool.h>
9 #include <math.h>
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdint.h>
13 #include <errno.h>
14 #include <inttypes.h>
15
16 #include "hdr_histogram.h"
17 #include "hdr_tests.h"
18 #include "hdr_atomic.h"
19
20 /* ###### ####### ## ## ## ## ######## ###### */
21 /* ## ## ## ## ## ## ### ## ## ## ## */
22 /* ## ## ## ## ## #### ## ## ## */
23 /* ## ## ## ## ## ## ## ## ## ###### */
24 /* ## ## ## ## ## ## #### ## ## */
25 /* ## ## ## ## ## ## ## ### ## ## ## */
26 /* ###### ####### ####### ## ## ## ###### */
27
normalize_index(const struct hdr_histogram * h,int32_t index)28 static int32_t normalize_index(const struct hdr_histogram* h, int32_t index)
29 {
30 int32_t normalized_index;
31 int32_t adjustment = 0;
32 if (h->normalizing_index_offset == 0)
33 {
34 return index;
35 }
36
37 normalized_index = index - h->normalizing_index_offset;
38
39 if (normalized_index < 0)
40 {
41 adjustment = h->counts_len;
42 }
43 else if (normalized_index >= h->counts_len)
44 {
45 adjustment = -h->counts_len;
46 }
47
48 return normalized_index + adjustment;
49 }
50
counts_get_direct(const struct hdr_histogram * h,int32_t index)51 static int64_t counts_get_direct(const struct hdr_histogram* h, int32_t index)
52 {
53 return h->counts[index];
54 }
55
counts_get_normalised(const struct hdr_histogram * h,int32_t index)56 static int64_t counts_get_normalised(const struct hdr_histogram* h, int32_t index)
57 {
58 return counts_get_direct(h, normalize_index(h, index));
59 }
60
counts_inc_normalised(struct hdr_histogram * h,int32_t index,int64_t value)61 static void counts_inc_normalised(
62 struct hdr_histogram* h, int32_t index, int64_t value)
63 {
64 int32_t normalised_index = normalize_index(h, index);
65 h->counts[normalised_index] += value;
66 h->total_count += value;
67 }
68
counts_inc_normalised_atomic(struct hdr_histogram * h,int32_t index,int64_t value)69 static void counts_inc_normalised_atomic(
70 struct hdr_histogram* h, int32_t index, int64_t value)
71 {
72 int32_t normalised_index = normalize_index(h, index);
73
74 hdr_atomic_add_fetch_64(&h->counts[normalised_index], value);
75 hdr_atomic_add_fetch_64(&h->total_count, value);
76 }
77
update_min_max(struct hdr_histogram * h,int64_t value)78 static void update_min_max(struct hdr_histogram* h, int64_t value)
79 {
80 h->min_value = (value < h->min_value && value != 0) ? value : h->min_value;
81 h->max_value = (value > h->max_value) ? value : h->max_value;
82 }
83
update_min_max_atomic(struct hdr_histogram * h,int64_t value)84 static void update_min_max_atomic(struct hdr_histogram* h, int64_t value)
85 {
86 int64_t current_min_value;
87 int64_t current_max_value;
88 do
89 {
90 current_min_value = hdr_atomic_load_64(&h->min_value);
91
92 if (0 == value || current_min_value <= value)
93 {
94 break;
95 }
96 }
97 while (!hdr_atomic_compare_exchange_64(&h->min_value, ¤t_min_value, value));
98
99 do
100 {
101 current_max_value = hdr_atomic_load_64(&h->max_value);
102
103 if (value <= current_max_value)
104 {
105 break;
106 }
107 }
108 while (!hdr_atomic_compare_exchange_64(&h->max_value, ¤t_max_value, value));
109 }
110
111
112 /* ## ## ######## #### ## #### ######## ## ## */
113 /* ## ## ## ## ## ## ## ## ## */
114 /* ## ## ## ## ## ## ## #### */
115 /* ## ## ## ## ## ## ## ## */
116 /* ## ## ## ## ## ## ## ## */
117 /* ## ## ## ## ## ## ## ## */
118 /* ####### ## #### ######## #### ## ## */
119
power(int64_t base,int64_t exp)120 static int64_t power(int64_t base, int64_t exp)
121 {
122 int64_t result = 1;
123 while(exp)
124 {
125 result *= base; exp--;
126 }
127 return result;
128 }
129
130 #if defined(_MSC_VER)
131 # if defined(_WIN64)
132 # pragma intrinsic(_BitScanReverse64)
133 # else
134 # pragma intrinsic(_BitScanReverse)
135 # endif
136 #endif
137
count_leading_zeros_64(int64_t value)138 static int32_t count_leading_zeros_64(int64_t value)
139 {
140 #if defined(_MSC_VER)
141 uint32_t leading_zero = 0;
142 #if defined(_WIN64)
143 _BitScanReverse64(&leading_zero, value);
144 #else
145 uint32_t high = value >> 32;
146 if (_BitScanReverse(&leading_zero, high))
147 {
148 leading_zero += 32;
149 }
150 else
151 {
152 uint32_t low = value & 0x00000000FFFFFFFF;
153 _BitScanReverse(&leading_zero, low);
154 }
155 #endif
156 return 63 - leading_zero; /* smallest power of 2 containing value */
157 #else
158 return __builtin_clzll(value); /* smallest power of 2 containing value */
159 #endif
160 }
161
get_bucket_index(const struct hdr_histogram * h,int64_t value)162 static int32_t get_bucket_index(const struct hdr_histogram* h, int64_t value)
163 {
164 int32_t pow2ceiling = 64 - count_leading_zeros_64(value | h->sub_bucket_mask); /* smallest power of 2 containing value */
165 return pow2ceiling - h->unit_magnitude - (h->sub_bucket_half_count_magnitude + 1);
166 }
167
get_sub_bucket_index(int64_t value,int32_t bucket_index,int32_t unit_magnitude)168 static int32_t get_sub_bucket_index(int64_t value, int32_t bucket_index, int32_t unit_magnitude)
169 {
170 return (int32_t)(value >> (bucket_index + unit_magnitude));
171 }
172
counts_index(const struct hdr_histogram * h,int32_t bucket_index,int32_t sub_bucket_index)173 static int32_t counts_index(const struct hdr_histogram* h, int32_t bucket_index, int32_t sub_bucket_index)
174 {
175 /* Calculate the index for the first entry in the bucket: */
176 /* (The following is the equivalent of ((bucket_index + 1) * subBucketHalfCount) ): */
177 int32_t bucket_base_index = (bucket_index + 1) << h->sub_bucket_half_count_magnitude;
178 /* Calculate the offset in the bucket: */
179 int32_t offset_in_bucket = sub_bucket_index - h->sub_bucket_half_count;
180 /* The following is the equivalent of ((sub_bucket_index - subBucketHalfCount) + bucketBaseIndex; */
181 return bucket_base_index + offset_in_bucket;
182 }
183
value_from_index(int32_t bucket_index,int32_t sub_bucket_index,int32_t unit_magnitude)184 static int64_t value_from_index(int32_t bucket_index, int32_t sub_bucket_index, int32_t unit_magnitude)
185 {
186 return ((int64_t) sub_bucket_index) << (bucket_index + unit_magnitude);
187 }
188
counts_index_for(const struct hdr_histogram * h,int64_t value)189 int32_t counts_index_for(const struct hdr_histogram* h, int64_t value)
190 {
191 int32_t bucket_index = get_bucket_index(h, value);
192 int32_t sub_bucket_index = get_sub_bucket_index(value, bucket_index, h->unit_magnitude);
193
194 return counts_index(h, bucket_index, sub_bucket_index);
195 }
196
hdr_value_at_index(const struct hdr_histogram * h,int32_t index)197 int64_t hdr_value_at_index(const struct hdr_histogram *h, int32_t index)
198 {
199 int32_t bucket_index = (index >> h->sub_bucket_half_count_magnitude) - 1;
200 int32_t sub_bucket_index = (index & (h->sub_bucket_half_count - 1)) + h->sub_bucket_half_count;
201
202 if (bucket_index < 0)
203 {
204 sub_bucket_index -= h->sub_bucket_half_count;
205 bucket_index = 0;
206 }
207
208 return value_from_index(bucket_index, sub_bucket_index, h->unit_magnitude);
209 }
210
hdr_size_of_equivalent_value_range(const struct hdr_histogram * h,int64_t value)211 int64_t hdr_size_of_equivalent_value_range(const struct hdr_histogram* h, int64_t value)
212 {
213 int32_t bucket_index = get_bucket_index(h, value);
214 int32_t sub_bucket_index = get_sub_bucket_index(value, bucket_index, h->unit_magnitude);
215 int32_t adjusted_bucket = (sub_bucket_index >= h->sub_bucket_count) ? (bucket_index + 1) : bucket_index;
216 return INT64_C(1) << (h->unit_magnitude + adjusted_bucket);
217 }
218
lowest_equivalent_value(const struct hdr_histogram * h,int64_t value)219 static int64_t lowest_equivalent_value(const struct hdr_histogram* h, int64_t value)
220 {
221 int32_t bucket_index = get_bucket_index(h, value);
222 int32_t sub_bucket_index = get_sub_bucket_index(value, bucket_index, h->unit_magnitude);
223 return value_from_index(bucket_index, sub_bucket_index, h->unit_magnitude);
224 }
225
hdr_next_non_equivalent_value(const struct hdr_histogram * h,int64_t value)226 int64_t hdr_next_non_equivalent_value(const struct hdr_histogram *h, int64_t value)
227 {
228 return lowest_equivalent_value(h, value) + hdr_size_of_equivalent_value_range(h, value);
229 }
230
highest_equivalent_value(const struct hdr_histogram * h,int64_t value)231 static int64_t highest_equivalent_value(const struct hdr_histogram* h, int64_t value)
232 {
233 return hdr_next_non_equivalent_value(h, value) - 1;
234 }
235
hdr_median_equivalent_value(const struct hdr_histogram * h,int64_t value)236 int64_t hdr_median_equivalent_value(const struct hdr_histogram *h, int64_t value)
237 {
238 return lowest_equivalent_value(h, value) + (hdr_size_of_equivalent_value_range(h, value) >> 1);
239 }
240
non_zero_min(const struct hdr_histogram * h)241 static int64_t non_zero_min(const struct hdr_histogram* h)
242 {
243 if (INT64_MAX == h->min_value)
244 {
245 return INT64_MAX;
246 }
247
248 return lowest_equivalent_value(h, h->min_value);
249 }
250
hdr_reset_internal_counters(struct hdr_histogram * h)251 void hdr_reset_internal_counters(struct hdr_histogram* h)
252 {
253 int min_non_zero_index = -1;
254 int max_index = -1;
255 int64_t observed_total_count = 0;
256 int i;
257
258 for (i = 0; i < h->counts_len; i++)
259 {
260 int64_t count_at_index;
261
262 if ((count_at_index = counts_get_direct(h, i)) > 0)
263 {
264 observed_total_count += count_at_index;
265 max_index = i;
266 if (min_non_zero_index == -1 && i != 0)
267 {
268 min_non_zero_index = i;
269 }
270 }
271 }
272
273 if (max_index == -1)
274 {
275 h->max_value = 0;
276 }
277 else
278 {
279 int64_t max_value = hdr_value_at_index(h, max_index);
280 h->max_value = highest_equivalent_value(h, max_value);
281 }
282
283 if (min_non_zero_index == -1)
284 {
285 h->min_value = INT64_MAX;
286 }
287 else
288 {
289 h->min_value = hdr_value_at_index(h, min_non_zero_index);
290 }
291
292 h->total_count = observed_total_count;
293 }
294
buckets_needed_to_cover_value(int64_t value,int32_t sub_bucket_count,int32_t unit_magnitude)295 static int32_t buckets_needed_to_cover_value(int64_t value, int32_t sub_bucket_count, int32_t unit_magnitude)
296 {
297 int64_t smallest_untrackable_value = ((int64_t) sub_bucket_count) << unit_magnitude;
298 int32_t buckets_needed = 1;
299 while (smallest_untrackable_value <= value)
300 {
301 if (smallest_untrackable_value > INT64_MAX / 2)
302 {
303 return buckets_needed + 1;
304 }
305 smallest_untrackable_value <<= 1;
306 buckets_needed++;
307 }
308
309 return buckets_needed;
310 }
311
312 /* ## ## ######## ## ## ####### ######## ## ## */
313 /* ### ### ## ### ### ## ## ## ## ## ## */
314 /* #### #### ## #### #### ## ## ## ## #### */
315 /* ## ### ## ###### ## ### ## ## ## ######## ## */
316 /* ## ## ## ## ## ## ## ## ## ## */
317 /* ## ## ## ## ## ## ## ## ## ## */
318 /* ## ## ######## ## ## ####### ## ## ## */
319
hdr_calculate_bucket_config(int64_t lowest_trackable_value,int64_t highest_trackable_value,int significant_figures,struct hdr_histogram_bucket_config * cfg)320 int hdr_calculate_bucket_config(
321 int64_t lowest_trackable_value,
322 int64_t highest_trackable_value,
323 int significant_figures,
324 struct hdr_histogram_bucket_config* cfg)
325 {
326 int32_t sub_bucket_count_magnitude;
327 int64_t largest_value_with_single_unit_resolution;
328
329 if (lowest_trackable_value < 1 ||
330 significant_figures < 1 || 5 < significant_figures ||
331 lowest_trackable_value * 2 > highest_trackable_value)
332 {
333 return EINVAL;
334 }
335
336 cfg->lowest_trackable_value = lowest_trackable_value;
337 cfg->significant_figures = significant_figures;
338 cfg->highest_trackable_value = highest_trackable_value;
339
340 largest_value_with_single_unit_resolution = 2 * power(10, significant_figures);
341 sub_bucket_count_magnitude = (int32_t) ceil(log((double)largest_value_with_single_unit_resolution) / log(2));
342 cfg->sub_bucket_half_count_magnitude = ((sub_bucket_count_magnitude > 1) ? sub_bucket_count_magnitude : 1) - 1;
343
344 double unit_magnitude = log((double)lowest_trackable_value) / log(2);
345 if (INT32_MAX < unit_magnitude)
346 {
347 return EINVAL;
348 }
349
350 cfg->unit_magnitude = (int32_t) unit_magnitude;
351 cfg->sub_bucket_count = (int32_t) pow(2, (cfg->sub_bucket_half_count_magnitude + 1));
352 cfg->sub_bucket_half_count = cfg->sub_bucket_count / 2;
353 cfg->sub_bucket_mask = ((int64_t) cfg->sub_bucket_count - 1) << cfg->unit_magnitude;
354
355 if (cfg->unit_magnitude + cfg->sub_bucket_half_count_magnitude > 61)
356 {
357 return EINVAL;
358 }
359
360 cfg->bucket_count = buckets_needed_to_cover_value(highest_trackable_value, cfg->sub_bucket_count, (int32_t)cfg->unit_magnitude);
361 cfg->counts_len = (cfg->bucket_count + 1) * (cfg->sub_bucket_count / 2);
362
363 return 0;
364 }
365
hdr_init_preallocated(struct hdr_histogram * h,struct hdr_histogram_bucket_config * cfg)366 void hdr_init_preallocated(struct hdr_histogram* h, struct hdr_histogram_bucket_config* cfg)
367 {
368 h->lowest_trackable_value = cfg->lowest_trackable_value;
369 h->highest_trackable_value = cfg->highest_trackable_value;
370 h->unit_magnitude = (int32_t)cfg->unit_magnitude;
371 h->significant_figures = (int32_t)cfg->significant_figures;
372 h->sub_bucket_half_count_magnitude = cfg->sub_bucket_half_count_magnitude;
373 h->sub_bucket_half_count = cfg->sub_bucket_half_count;
374 h->sub_bucket_mask = cfg->sub_bucket_mask;
375 h->sub_bucket_count = cfg->sub_bucket_count;
376 h->min_value = INT64_MAX;
377 h->max_value = 0;
378 h->normalizing_index_offset = 0;
379 h->conversion_ratio = 1.0;
380 h->bucket_count = cfg->bucket_count;
381 h->counts_len = cfg->counts_len;
382 h->total_count = 0;
383 }
384
hdr_init(int64_t lowest_trackable_value,int64_t highest_trackable_value,int significant_figures,struct hdr_histogram ** result)385 int hdr_init(
386 int64_t lowest_trackable_value,
387 int64_t highest_trackable_value,
388 int significant_figures,
389 struct hdr_histogram** result)
390 {
391 int64_t* counts;
392 struct hdr_histogram_bucket_config cfg;
393 struct hdr_histogram* histogram;
394
395 int r = hdr_calculate_bucket_config(lowest_trackable_value, highest_trackable_value, significant_figures, &cfg);
396 if (r)
397 {
398 return r;
399 }
400
401 counts = (int64_t*) calloc((size_t) cfg.counts_len, sizeof(int64_t));
402 if (!counts)
403 {
404 return ENOMEM;
405 }
406
407 histogram = (struct hdr_histogram*) calloc(1, sizeof(struct hdr_histogram));
408 if (!histogram)
409 {
410 free(counts);
411 return ENOMEM;
412 }
413
414 histogram->counts = counts;
415
416 hdr_init_preallocated(histogram, &cfg);
417 *result = histogram;
418
419 return 0;
420 }
421
hdr_close(struct hdr_histogram * h)422 void hdr_close(struct hdr_histogram* h)
423 {
424 if (h) {
425 free(h->counts);
426 free(h);
427 }
428 }
429
hdr_alloc(int64_t highest_trackable_value,int significant_figures,struct hdr_histogram ** result)430 int hdr_alloc(int64_t highest_trackable_value, int significant_figures, struct hdr_histogram** result)
431 {
432 return hdr_init(1, highest_trackable_value, significant_figures, result);
433 }
434
435 /* reset a histogram to zero. */
hdr_reset(struct hdr_histogram * h)436 void hdr_reset(struct hdr_histogram *h)
437 {
438 h->total_count=0;
439 h->min_value = INT64_MAX;
440 h->max_value = 0;
441 memset(h->counts, 0, (sizeof(int64_t) * h->counts_len));
442 }
443
hdr_get_memory_size(struct hdr_histogram * h)444 size_t hdr_get_memory_size(struct hdr_histogram *h)
445 {
446 return sizeof(struct hdr_histogram) + h->counts_len * sizeof(int64_t);
447 }
448
449 /* ## ## ######## ######## ### ######## ######## ###### */
450 /* ## ## ## ## ## ## ## ## ## ## ## ## */
451 /* ## ## ## ## ## ## ## ## ## ## ## */
452 /* ## ## ######## ## ## ## ## ## ###### ###### */
453 /* ## ## ## ## ## ######### ## ## ## */
454 /* ## ## ## ## ## ## ## ## ## ## ## */
455 /* ####### ## ######## ## ## ## ######## ###### */
456
457
hdr_record_value(struct hdr_histogram * h,int64_t value)458 bool hdr_record_value(struct hdr_histogram* h, int64_t value)
459 {
460 return hdr_record_values(h, value, 1);
461 }
462
hdr_record_value_atomic(struct hdr_histogram * h,int64_t value)463 bool hdr_record_value_atomic(struct hdr_histogram* h, int64_t value)
464 {
465 return hdr_record_values_atomic(h, value, 1);
466 }
467
hdr_record_values(struct hdr_histogram * h,int64_t value,int64_t count)468 bool hdr_record_values(struct hdr_histogram* h, int64_t value, int64_t count)
469 {
470 int32_t counts_index;
471
472 if (value < 0)
473 {
474 return false;
475 }
476
477 counts_index = counts_index_for(h, value);
478
479 if (counts_index < 0 || h->counts_len <= counts_index)
480 {
481 return false;
482 }
483
484 counts_inc_normalised(h, counts_index, count);
485 update_min_max(h, value);
486
487 return true;
488 }
489
hdr_record_values_atomic(struct hdr_histogram * h,int64_t value,int64_t count)490 bool hdr_record_values_atomic(struct hdr_histogram* h, int64_t value, int64_t count)
491 {
492 int32_t counts_index;
493
494 if (value < 0)
495 {
496 return false;
497 }
498
499 counts_index = counts_index_for(h, value);
500
501 if (counts_index < 0 || h->counts_len <= counts_index)
502 {
503 return false;
504 }
505
506 counts_inc_normalised_atomic(h, counts_index, count);
507 update_min_max_atomic(h, value);
508
509 return true;
510 }
511
hdr_record_corrected_value(struct hdr_histogram * h,int64_t value,int64_t expected_interval)512 bool hdr_record_corrected_value(struct hdr_histogram* h, int64_t value, int64_t expected_interval)
513 {
514 return hdr_record_corrected_values(h, value, 1, expected_interval);
515 }
516
hdr_record_corrected_value_atomic(struct hdr_histogram * h,int64_t value,int64_t expected_interval)517 bool hdr_record_corrected_value_atomic(struct hdr_histogram* h, int64_t value, int64_t expected_interval)
518 {
519 return hdr_record_corrected_values_atomic(h, value, 1, expected_interval);
520 }
521
hdr_record_corrected_values(struct hdr_histogram * h,int64_t value,int64_t count,int64_t expected_interval)522 bool hdr_record_corrected_values(struct hdr_histogram* h, int64_t value, int64_t count, int64_t expected_interval)
523 {
524 int64_t missing_value;
525
526 if (!hdr_record_values(h, value, count))
527 {
528 return false;
529 }
530
531 if (expected_interval <= 0 || value <= expected_interval)
532 {
533 return true;
534 }
535
536 missing_value = value - expected_interval;
537 for (; missing_value >= expected_interval; missing_value -= expected_interval)
538 {
539 if (!hdr_record_values(h, missing_value, count))
540 {
541 return false;
542 }
543 }
544
545 return true;
546 }
547
hdr_record_corrected_values_atomic(struct hdr_histogram * h,int64_t value,int64_t count,int64_t expected_interval)548 bool hdr_record_corrected_values_atomic(struct hdr_histogram* h, int64_t value, int64_t count, int64_t expected_interval)
549 {
550 int64_t missing_value;
551
552 if (!hdr_record_values_atomic(h, value, count))
553 {
554 return false;
555 }
556
557 if (expected_interval <= 0 || value <= expected_interval)
558 {
559 return true;
560 }
561
562 missing_value = value - expected_interval;
563 for (; missing_value >= expected_interval; missing_value -= expected_interval)
564 {
565 if (!hdr_record_values_atomic(h, missing_value, count))
566 {
567 return false;
568 }
569 }
570
571 return true;
572 }
573
hdr_add(struct hdr_histogram * h,const struct hdr_histogram * from)574 int64_t hdr_add(struct hdr_histogram* h, const struct hdr_histogram* from)
575 {
576 struct hdr_iter iter;
577 int64_t dropped = 0;
578 hdr_iter_recorded_init(&iter, from);
579
580 while (hdr_iter_next(&iter))
581 {
582 int64_t value = iter.value;
583 int64_t count = iter.count;
584
585 if (!hdr_record_values(h, value, count))
586 {
587 dropped += count;
588 }
589 }
590
591 return dropped;
592 }
593
hdr_add_while_correcting_for_coordinated_omission(struct hdr_histogram * h,struct hdr_histogram * from,int64_t expected_interval)594 int64_t hdr_add_while_correcting_for_coordinated_omission(
595 struct hdr_histogram* h, struct hdr_histogram* from, int64_t expected_interval)
596 {
597 struct hdr_iter iter;
598 int64_t dropped = 0;
599 hdr_iter_recorded_init(&iter, from);
600
601 while (hdr_iter_next(&iter))
602 {
603 int64_t value = iter.value;
604 int64_t count = iter.count;
605
606 if (!hdr_record_corrected_values(h, value, count, expected_interval))
607 {
608 dropped += count;
609 }
610 }
611
612 return dropped;
613 }
614
615
616
617 /* ## ## ### ## ## ## ######## ###### */
618 /* ## ## ## ## ## ## ## ## ## ## */
619 /* ## ## ## ## ## ## ## ## ## */
620 /* ## ## ## ## ## ## ## ###### ###### */
621 /* ## ## ######### ## ## ## ## ## */
622 /* ## ## ## ## ## ## ## ## ## ## */
623 /* ### ## ## ######## ####### ######## ###### */
624
625
hdr_max(const struct hdr_histogram * h)626 int64_t hdr_max(const struct hdr_histogram* h)
627 {
628 if (0 == h->max_value)
629 {
630 return 0;
631 }
632
633 return highest_equivalent_value(h, h->max_value);
634 }
635
hdr_min(const struct hdr_histogram * h)636 int64_t hdr_min(const struct hdr_histogram* h)
637 {
638 if (0 < hdr_count_at_index(h, 0))
639 {
640 return 0;
641 }
642
643 return non_zero_min(h);
644 }
645
hdr_value_at_percentile(const struct hdr_histogram * h,double percentile)646 int64_t hdr_value_at_percentile(const struct hdr_histogram* h, double percentile)
647 {
648 struct hdr_iter iter;
649 int64_t total = 0;
650 double requested_percentile = percentile < 100.0 ? percentile : 100.0;
651 int64_t count_at_percentile =
652 (int64_t) (((requested_percentile / 100) * h->total_count) + 0.5);
653 count_at_percentile = count_at_percentile > 1 ? count_at_percentile : 1;
654
655 hdr_iter_init(&iter, h);
656
657 while (hdr_iter_next(&iter))
658 {
659 total += iter.count;
660
661 if (total >= count_at_percentile)
662 {
663 int64_t value_from_index = iter.value;
664 return highest_equivalent_value(h, value_from_index);
665 }
666 }
667
668 return 0;
669 }
670
hdr_mean(const struct hdr_histogram * h)671 double hdr_mean(const struct hdr_histogram* h)
672 {
673 struct hdr_iter iter;
674 int64_t total = 0;
675
676 hdr_iter_init(&iter, h);
677
678 while (hdr_iter_next(&iter))
679 {
680 if (0 != iter.count)
681 {
682 total += iter.count * hdr_median_equivalent_value(h, iter.value);
683 }
684 }
685
686 return (total * 1.0) / h->total_count;
687 }
688
hdr_stddev(const struct hdr_histogram * h)689 double hdr_stddev(const struct hdr_histogram* h)
690 {
691 double mean = hdr_mean(h);
692 double geometric_dev_total = 0.0;
693
694 struct hdr_iter iter;
695 hdr_iter_init(&iter, h);
696
697 while (hdr_iter_next(&iter))
698 {
699 if (0 != iter.count)
700 {
701 double dev = (hdr_median_equivalent_value(h, iter.value) * 1.0) - mean;
702 geometric_dev_total += (dev * dev) * iter.count;
703 }
704 }
705
706 return sqrt(geometric_dev_total / h->total_count);
707 }
708
hdr_values_are_equivalent(const struct hdr_histogram * h,int64_t a,int64_t b)709 bool hdr_values_are_equivalent(const struct hdr_histogram* h, int64_t a, int64_t b)
710 {
711 return lowest_equivalent_value(h, a) == lowest_equivalent_value(h, b);
712 }
713
hdr_lowest_equivalent_value(const struct hdr_histogram * h,int64_t value)714 int64_t hdr_lowest_equivalent_value(const struct hdr_histogram* h, int64_t value)
715 {
716 return lowest_equivalent_value(h, value);
717 }
718
hdr_count_at_value(const struct hdr_histogram * h,int64_t value)719 int64_t hdr_count_at_value(const struct hdr_histogram* h, int64_t value)
720 {
721 return counts_get_normalised(h, counts_index_for(h, value));
722 }
723
hdr_count_at_index(const struct hdr_histogram * h,int32_t index)724 int64_t hdr_count_at_index(const struct hdr_histogram* h, int32_t index)
725 {
726 return counts_get_normalised(h, index);
727 }
728
729
730 /* #### ######## ######## ######## ### ######## ####### ######## ###### */
731 /* ## ## ## ## ## ## ## ## ## ## ## ## ## ## */
732 /* ## ## ## ## ## ## ## ## ## ## ## ## ## */
733 /* ## ## ###### ######## ## ## ## ## ## ######## ###### */
734 /* ## ## ## ## ## ######### ## ## ## ## ## ## */
735 /* ## ## ## ## ## ## ## ## ## ## ## ## ## ## */
736 /* #### ## ######## ## ## ## ## ## ####### ## ## ###### */
737
738
has_buckets(struct hdr_iter * iter)739 static bool has_buckets(struct hdr_iter* iter)
740 {
741 return iter->counts_index < iter->h->counts_len;
742 }
743
has_next(struct hdr_iter * iter)744 static bool has_next(struct hdr_iter* iter)
745 {
746 return iter->cumulative_count < iter->total_count;
747 }
748
move_next(struct hdr_iter * iter)749 static bool move_next(struct hdr_iter* iter)
750 {
751 iter->counts_index++;
752
753 if (!has_buckets(iter))
754 {
755 return false;
756 }
757
758 iter->count = counts_get_normalised(iter->h, iter->counts_index);
759 iter->cumulative_count += iter->count;
760
761 iter->value = hdr_value_at_index(iter->h, iter->counts_index);
762 iter->highest_equivalent_value = highest_equivalent_value(iter->h, iter->value);
763 iter->lowest_equivalent_value = lowest_equivalent_value(iter->h, iter->value);
764 iter->median_equivalent_value = hdr_median_equivalent_value(iter->h, iter->value);
765
766 return true;
767 }
768
peek_next_value_from_index(struct hdr_iter * iter)769 static int64_t peek_next_value_from_index(struct hdr_iter* iter)
770 {
771 return hdr_value_at_index(iter->h, iter->counts_index + 1);
772 }
773
next_value_greater_than_reporting_level_upper_bound(struct hdr_iter * iter,int64_t reporting_level_upper_bound)774 static bool next_value_greater_than_reporting_level_upper_bound(
775 struct hdr_iter *iter, int64_t reporting_level_upper_bound)
776 {
777 if (iter->counts_index >= iter->h->counts_len)
778 {
779 return false;
780 }
781
782 return peek_next_value_from_index(iter) > reporting_level_upper_bound;
783 }
784
basic_iter_next(struct hdr_iter * iter)785 static bool basic_iter_next(struct hdr_iter *iter)
786 {
787 if (!has_next(iter) || iter->counts_index >= iter->h->counts_len)
788 {
789 return false;
790 }
791
792 move_next(iter);
793
794 return true;
795 }
796
update_iterated_values(struct hdr_iter * iter,int64_t new_value_iterated_to)797 static void update_iterated_values(struct hdr_iter* iter, int64_t new_value_iterated_to)
798 {
799 iter->value_iterated_from = iter->value_iterated_to;
800 iter->value_iterated_to = new_value_iterated_to;
801 }
802
all_values_iter_next(struct hdr_iter * iter)803 static bool all_values_iter_next(struct hdr_iter* iter)
804 {
805 bool result = move_next(iter);
806
807 if (result)
808 {
809 update_iterated_values(iter, iter->value);
810 }
811
812 return result;
813 }
814
hdr_iter_init(struct hdr_iter * iter,const struct hdr_histogram * h)815 void hdr_iter_init(struct hdr_iter* iter, const struct hdr_histogram* h)
816 {
817 iter->h = h;
818
819 iter->counts_index = -1;
820 iter->total_count = h->total_count;
821 iter->count = 0;
822 iter->cumulative_count = 0;
823 iter->value = 0;
824 iter->highest_equivalent_value = 0;
825 iter->value_iterated_from = 0;
826 iter->value_iterated_to = 0;
827
828 iter->_next_fp = all_values_iter_next;
829 }
830
hdr_iter_next(struct hdr_iter * iter)831 bool hdr_iter_next(struct hdr_iter* iter)
832 {
833 return iter->_next_fp(iter);
834 }
835
836 /* ######## ######## ######## ###### ######## ## ## ######## #### ## ######## ###### */
837 /* ## ## ## ## ## ## ## ## ### ## ## ## ## ## ## ## */
838 /* ## ## ## ## ## ## ## #### ## ## ## ## ## ## */
839 /* ######## ###### ######## ## ###### ## ## ## ## ## ## ###### ###### */
840 /* ## ## ## ## ## ## ## #### ## ## ## ## ## */
841 /* ## ## ## ## ## ## ## ## ### ## ## ## ## ## ## */
842 /* ## ######## ## ## ###### ######## ## ## ## #### ######## ######## ###### */
843
percentile_iter_next(struct hdr_iter * iter)844 static bool percentile_iter_next(struct hdr_iter* iter)
845 {
846 int64_t temp, half_distance, percentile_reporting_ticks;
847
848 struct hdr_iter_percentiles* percentiles = &iter->specifics.percentiles;
849
850 if (!has_next(iter))
851 {
852 if (percentiles->seen_last_value)
853 {
854 return false;
855 }
856
857 percentiles->seen_last_value = true;
858 percentiles->percentile = 100.0;
859
860 return true;
861 }
862
863 if (iter->counts_index == -1 && !basic_iter_next(iter))
864 {
865 return false;
866 }
867
868 do
869 {
870 double current_percentile = (100.0 * (double) iter->cumulative_count) / iter->h->total_count;
871 if (iter->count != 0 &&
872 percentiles->percentile_to_iterate_to <= current_percentile)
873 {
874 update_iterated_values(iter, highest_equivalent_value(iter->h, iter->value));
875
876 percentiles->percentile = percentiles->percentile_to_iterate_to;
877 temp = (int64_t)(log(100 / (100.0 - (percentiles->percentile_to_iterate_to))) / log(2)) + 1;
878 half_distance = (int64_t) pow(2, (double) temp);
879 percentile_reporting_ticks = percentiles->ticks_per_half_distance * half_distance;
880 percentiles->percentile_to_iterate_to += 100.0 / percentile_reporting_ticks;
881
882 return true;
883 }
884 }
885 while (basic_iter_next(iter));
886
887 return true;
888 }
889
hdr_iter_percentile_init(struct hdr_iter * iter,const struct hdr_histogram * h,int32_t ticks_per_half_distance)890 void hdr_iter_percentile_init(struct hdr_iter* iter, const struct hdr_histogram* h, int32_t ticks_per_half_distance)
891 {
892 iter->h = h;
893
894 hdr_iter_init(iter, h);
895
896 iter->specifics.percentiles.seen_last_value = false;
897 iter->specifics.percentiles.ticks_per_half_distance = ticks_per_half_distance;
898 iter->specifics.percentiles.percentile_to_iterate_to = 0.0;
899 iter->specifics.percentiles.percentile = 0.0;
900
901 iter->_next_fp = percentile_iter_next;
902 }
903
format_line_string(char * str,size_t len,int significant_figures,format_type format)904 static void format_line_string(char* str, size_t len, int significant_figures, format_type format)
905 {
906 #if defined(_MSC_VER)
907 #define snprintf _snprintf
908 #pragma warning(push)
909 #pragma warning(disable: 4996)
910 #endif
911 const char* format_str = "%s%d%s";
912
913 switch (format)
914 {
915 case CSV:
916 snprintf(str, len, format_str, "%.", significant_figures, "f,%f,%d,%.2f\n");
917 break;
918 case CLASSIC:
919 snprintf(str, len, format_str, "%12.", significant_figures, "f %12f %12d %12.2f\n");
920 break;
921 default:
922 snprintf(str, len, format_str, "%12.", significant_figures, "f %12f %12d %12.2f\n");
923 }
924 #if defined(_MSC_VER)
925 #undef snprintf
926 #pragma warning(pop)
927 #endif
928 }
929
930
931 /* ######## ######## ###### ####### ######## ######## ######## ######## */
932 /* ## ## ## ## ## ## ## ## ## ## ## ## ## ## */
933 /* ## ## ## ## ## ## ## ## ## ## ## ## ## */
934 /* ######## ###### ## ## ## ######## ## ## ###### ## ## */
935 /* ## ## ## ## ## ## ## ## ## ## ## ## ## */
936 /* ## ## ## ## ## ## ## ## ## ## ## ## ## ## */
937 /* ## ## ######## ###### ####### ## ## ######## ######## ######## */
938
939
recorded_iter_next(struct hdr_iter * iter)940 static bool recorded_iter_next(struct hdr_iter* iter)
941 {
942 while (basic_iter_next(iter))
943 {
944 if (iter->count != 0)
945 {
946 update_iterated_values(iter, iter->value);
947
948 iter->specifics.recorded.count_added_in_this_iteration_step = iter->count;
949 return true;
950 }
951 }
952
953 return false;
954 }
955
hdr_iter_recorded_init(struct hdr_iter * iter,const struct hdr_histogram * h)956 void hdr_iter_recorded_init(struct hdr_iter* iter, const struct hdr_histogram* h)
957 {
958 hdr_iter_init(iter, h);
959
960 iter->specifics.recorded.count_added_in_this_iteration_step = 0;
961
962 iter->_next_fp = recorded_iter_next;
963 }
964
965 /* ## #### ## ## ######## ### ######## */
966 /* ## ## ### ## ## ## ## ## ## */
967 /* ## ## #### ## ## ## ## ## ## */
968 /* ## ## ## ## ## ###### ## ## ######## */
969 /* ## ## ## #### ## ######### ## ## */
970 /* ## ## ## ### ## ## ## ## ## */
971 /* ######## #### ## ## ######## ## ## ## ## */
972
973
iter_linear_next(struct hdr_iter * iter)974 static bool iter_linear_next(struct hdr_iter* iter)
975 {
976 struct hdr_iter_linear* linear = &iter->specifics.linear;
977
978 linear->count_added_in_this_iteration_step = 0;
979
980 if (has_next(iter) ||
981 next_value_greater_than_reporting_level_upper_bound(
982 iter, linear->next_value_reporting_level_lowest_equivalent))
983 {
984 do
985 {
986 if (iter->value >= linear->next_value_reporting_level_lowest_equivalent)
987 {
988 update_iterated_values(iter, linear->next_value_reporting_level);
989
990 linear->next_value_reporting_level += linear->value_units_per_bucket;
991 linear->next_value_reporting_level_lowest_equivalent =
992 lowest_equivalent_value(iter->h, linear->next_value_reporting_level);
993
994 return true;
995 }
996
997 if (!move_next(iter))
998 {
999 return true;
1000 }
1001
1002 linear->count_added_in_this_iteration_step += iter->count;
1003 }
1004 while (true);
1005 }
1006
1007 return false;
1008 }
1009
1010
hdr_iter_linear_init(struct hdr_iter * iter,const struct hdr_histogram * h,int64_t value_units_per_bucket)1011 void hdr_iter_linear_init(struct hdr_iter* iter, const struct hdr_histogram* h, int64_t value_units_per_bucket)
1012 {
1013 hdr_iter_init(iter, h);
1014
1015 iter->specifics.linear.count_added_in_this_iteration_step = 0;
1016 iter->specifics.linear.value_units_per_bucket = value_units_per_bucket;
1017 iter->specifics.linear.next_value_reporting_level = value_units_per_bucket;
1018 iter->specifics.linear.next_value_reporting_level_lowest_equivalent = lowest_equivalent_value(h, value_units_per_bucket);
1019
1020 iter->_next_fp = iter_linear_next;
1021 }
1022
1023 /* ## ####### ###### ### ######## #### ######## ## ## ## ## #### ###### */
1024 /* ## ## ## ## ## ## ## ## ## ## ## ## ## ### ### ## ## ## */
1025 /* ## ## ## ## ## ## ## ## ## ## ## ## #### #### ## ## */
1026 /* ## ## ## ## #### ## ## ######## ## ## ######### ## ### ## ## ## */
1027 /* ## ## ## ## ## ######### ## ## ## ## ## ## ## ## ## ## */
1028 /* ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## ## */
1029 /* ######## ####### ###### ## ## ## ## #### ## ## ## ## ## #### ###### */
1030
log_iter_next(struct hdr_iter * iter)1031 static bool log_iter_next(struct hdr_iter *iter)
1032 {
1033 struct hdr_iter_log* logarithmic = &iter->specifics.log;
1034
1035 logarithmic->count_added_in_this_iteration_step = 0;
1036
1037 if (has_next(iter) ||
1038 next_value_greater_than_reporting_level_upper_bound(
1039 iter, logarithmic->next_value_reporting_level_lowest_equivalent))
1040 {
1041 do
1042 {
1043 if (iter->value >= logarithmic->next_value_reporting_level_lowest_equivalent)
1044 {
1045 update_iterated_values(iter, logarithmic->next_value_reporting_level);
1046
1047 logarithmic->next_value_reporting_level *= (int64_t)logarithmic->log_base;
1048 logarithmic->next_value_reporting_level_lowest_equivalent = lowest_equivalent_value(iter->h, logarithmic->next_value_reporting_level);
1049
1050 return true;
1051 }
1052
1053 if (!move_next(iter))
1054 {
1055 return true;
1056 }
1057
1058 logarithmic->count_added_in_this_iteration_step += iter->count;
1059 }
1060 while (true);
1061 }
1062
1063 return false;
1064 }
1065
hdr_iter_log_init(struct hdr_iter * iter,const struct hdr_histogram * h,int64_t value_units_first_bucket,double log_base)1066 void hdr_iter_log_init(
1067 struct hdr_iter* iter,
1068 const struct hdr_histogram* h,
1069 int64_t value_units_first_bucket,
1070 double log_base)
1071 {
1072 hdr_iter_init(iter, h);
1073 iter->specifics.log.count_added_in_this_iteration_step = 0;
1074 iter->specifics.log.log_base = log_base;
1075 iter->specifics.log.next_value_reporting_level = value_units_first_bucket;
1076 iter->specifics.log.next_value_reporting_level_lowest_equivalent = lowest_equivalent_value(h, value_units_first_bucket);
1077
1078 iter->_next_fp = log_iter_next;
1079 }
1080
1081 /* Printing. */
1082
format_head_string(format_type format)1083 static const char* format_head_string(format_type format)
1084 {
1085 switch (format)
1086 {
1087 case CSV:
1088 return "%s,%s,%s,%s\n";
1089 case CLASSIC:
1090 default:
1091 return "%12s %12s %12s %12s\n\n";
1092 }
1093 }
1094
1095 static const char CLASSIC_FOOTER[] =
1096 "#[Mean = %12.3f, StdDeviation = %12.3f]\n"
1097 "#[Max = %12.3f, Total count = %12" PRIu64 "]\n"
1098 "#[Buckets = %12d, SubBuckets = %12d]\n";
1099
hdr_percentiles_print(struct hdr_histogram * h,FILE * stream,int32_t ticks_per_half_distance,double value_scale,format_type format)1100 int hdr_percentiles_print(
1101 struct hdr_histogram* h, FILE* stream, int32_t ticks_per_half_distance,
1102 double value_scale, format_type format)
1103 {
1104 char line_format[25];
1105 const char* head_format;
1106 int rc = 0;
1107 struct hdr_iter iter;
1108 struct hdr_iter_percentiles * percentiles;
1109
1110 format_line_string(line_format, 25, h->significant_figures, format);
1111 head_format = format_head_string(format);
1112
1113 hdr_iter_percentile_init(&iter, h, ticks_per_half_distance);
1114
1115 if (fprintf(
1116 stream, head_format,
1117 "Value", "Percentile", "TotalCount", "1/(1-Percentile)") < 0)
1118 {
1119 rc = EIO;
1120 goto cleanup;
1121 }
1122
1123 percentiles = &iter.specifics.percentiles;
1124 while (hdr_iter_next(&iter))
1125 {
1126 double value = iter.highest_equivalent_value / value_scale;
1127 double percentile = percentiles->percentile / 100.0;
1128 int64_t total_count = iter.cumulative_count;
1129 double inverted_percentile = (1.0 / (1.0 - percentile));
1130
1131 if (fprintf(
1132 stream, line_format, value, percentile, total_count, inverted_percentile) < 0)
1133 {
1134 rc = EIO;
1135 goto cleanup;
1136 }
1137 }
1138
1139 if (CLASSIC == format)
1140 {
1141 double mean = hdr_mean(h) / value_scale;
1142 double stddev = hdr_stddev(h) / value_scale;
1143 double max = hdr_max(h) / value_scale;
1144
1145 if (fprintf(
1146 stream, CLASSIC_FOOTER, mean, stddev, max,
1147 h->total_count, h->bucket_count, h->sub_bucket_count) < 0)
1148 {
1149 rc = EIO;
1150 goto cleanup;
1151 }
1152 }
1153
1154 cleanup:
1155 return rc;
1156 }
1157