• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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, &current_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, &current_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