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