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