1 /** 2 * hdr_histogram.h 3 * Written by Michael Barker and released to the public domain, 4 * as explained at http://creativecommons.org/publicdomain/zero/1.0/ 5 * 6 * The source for the hdr_histogram utilises a few C99 constructs, specifically 7 * the use of stdint/stdbool and inline variable declaration. 8 */ 9 10 #ifndef HDR_HISTOGRAM_H 11 #define HDR_HISTOGRAM_H 1 12 13 #include <stdint.h> 14 #include <stdbool.h> 15 #include <stdio.h> 16 17 struct hdr_histogram 18 { 19 int64_t lowest_discernible_value; 20 int64_t highest_trackable_value; 21 int32_t unit_magnitude; 22 int32_t significant_figures; 23 int32_t sub_bucket_half_count_magnitude; 24 int32_t sub_bucket_half_count; 25 int64_t sub_bucket_mask; 26 int32_t sub_bucket_count; 27 int32_t bucket_count; 28 int64_t min_value; 29 int64_t max_value; 30 int32_t normalizing_index_offset; 31 double conversion_ratio; 32 int32_t counts_len; 33 int64_t total_count; 34 int64_t* counts; 35 }; 36 37 #ifdef __cplusplus 38 extern "C" { 39 #endif 40 41 /** 42 * Allocate the memory and initialise the hdr_histogram. 43 * 44 * Due to the size of the histogram being the result of some reasonably 45 * involved math on the input parameters this function it is tricky to stack allocate. 46 * The histogram should be released with hdr_close 47 * 48 * @param lowest_discernible_value The smallest possible value that is distinguishable from 0. 49 * Must be a positive integer that is >= 1. May be internally rounded down to nearest power of 2. 50 * @param highest_trackable_value The largest possible value to be put into the 51 * histogram. 52 * @param significant_figures The level of precision for this histogram, i.e. the number 53 * of figures in a decimal number that will be maintained. E.g. a value of 3 will mean 54 * the results from the histogram will be accurate up to the first three digits. Must 55 * be a value between 1 and 5 (inclusive). 56 * @param result Output parameter to capture allocated histogram. 57 * @return 0 on success, EINVAL if lowest_discernible_value is < 1 or the 58 * significant_figure value is outside of the allowed range, ENOMEM if malloc 59 * failed. 60 */ 61 int hdr_init( 62 int64_t lowest_discernible_value, 63 int64_t highest_trackable_value, 64 int significant_figures, 65 struct hdr_histogram** result); 66 67 /** 68 * Free the memory and close the hdr_histogram. 69 * 70 * @param h The histogram you want to close. 71 */ 72 void hdr_close(struct hdr_histogram* h); 73 74 /** 75 * Allocate the memory and initialise the hdr_histogram. This is the equivalent of calling 76 * hdr_init(1, highest_trackable_value, significant_figures, result); 77 * 78 * @deprecated use hdr_init. 79 */ 80 int hdr_alloc(int64_t highest_trackable_value, int significant_figures, struct hdr_histogram** result); 81 82 83 /** 84 * Reset a histogram to zero - empty out a histogram and re-initialise it 85 * 86 * If you want to re-use an existing histogram, but reset everything back to zero, this 87 * is the routine to use. 88 * 89 * @param h The histogram you want to reset to empty. 90 * 91 */ 92 void hdr_reset(struct hdr_histogram* h); 93 94 /** 95 * Get the memory size of the hdr_histogram. 96 * 97 * @param h "This" pointer 98 * @return The amount of memory used by the hdr_histogram in bytes 99 */ 100 size_t hdr_get_memory_size(struct hdr_histogram* h); 101 102 /** 103 * Records a value in the histogram, will round this value of to a precision at or better 104 * than the significant_figure specified at construction time. 105 * 106 * @param h "This" pointer 107 * @param value Value to add to the histogram 108 * @return false if the value is larger than the highest_trackable_value and can't be recorded, 109 * true otherwise. 110 */ 111 bool hdr_record_value(struct hdr_histogram* h, int64_t value); 112 113 /** 114 * Records a value in the histogram, will round this value of to a precision at or better 115 * than the significant_figure specified at construction time. 116 * 117 * Will record this value atomically, however the whole structure may appear inconsistent 118 * when read concurrently with this update. Do NOT mix calls to this method with calls 119 * to non-atomic updates. 120 * 121 * @param h "This" pointer 122 * @param value Value to add to the histogram 123 * @return false if the value is larger than the highest_trackable_value and can't be recorded, 124 * true otherwise. 125 */ 126 bool hdr_record_value_atomic(struct hdr_histogram* h, int64_t value); 127 128 /** 129 * Records count values in the histogram, will round this value of to a 130 * precision at or better than the significant_figure specified at construction 131 * time. 132 * 133 * @param h "This" pointer 134 * @param value Value to add to the histogram 135 * @param count Number of 'value's to add to the histogram 136 * @return false if any value is larger than the highest_trackable_value and can't be recorded, 137 * true otherwise. 138 */ 139 bool hdr_record_values(struct hdr_histogram* h, int64_t value, int64_t count); 140 141 /** 142 * Records count values in the histogram, will round this value of to a 143 * precision at or better than the significant_figure specified at construction 144 * time. 145 * 146 * Will record this value atomically, however the whole structure may appear inconsistent 147 * when read concurrently with this update. Do NOT mix calls to this method with calls 148 * to non-atomic updates. 149 * 150 * @param h "This" pointer 151 * @param value Value to add to the histogram 152 * @param count Number of 'value's to add to the histogram 153 * @return false if any value is larger than the highest_trackable_value and can't be recorded, 154 * true otherwise. 155 */ 156 bool hdr_record_values_atomic(struct hdr_histogram* h, int64_t value, int64_t count); 157 158 /** 159 * Record a value in the histogram and backfill based on an expected interval. 160 * 161 * Records a value in the histogram, will round this value of to a precision at or better 162 * than the significant_figure specified at construction time. This is specifically used 163 * for recording latency. If the value is larger than the expected_interval then the 164 * latency recording system has experienced co-ordinated omission. This method fills in the 165 * values that would have occurred had the client providing the load not been blocked. 166 167 * @param h "This" pointer 168 * @param value Value to add to the histogram 169 * @param expected_interval The delay between recording values. 170 * @return false if the value is larger than the highest_trackable_value and can't be recorded, 171 * true otherwise. 172 */ 173 bool hdr_record_corrected_value(struct hdr_histogram* h, int64_t value, int64_t expected_interval); 174 175 /** 176 * Record a value in the histogram and backfill based on an expected interval. 177 * 178 * Records a value in the histogram, will round this value of to a precision at or better 179 * than the significant_figure specified at construction time. This is specifically used 180 * for recording latency. If the value is larger than the expected_interval then the 181 * latency recording system has experienced co-ordinated omission. This method fills in the 182 * values that would have occurred had the client providing the load not been blocked. 183 * 184 * Will record this value atomically, however the whole structure may appear inconsistent 185 * when read concurrently with this update. Do NOT mix calls to this method with calls 186 * to non-atomic updates. 187 * 188 * @param h "This" pointer 189 * @param value Value to add to the histogram 190 * @param expected_interval The delay between recording values. 191 * @return false if the value is larger than the highest_trackable_value and can't be recorded, 192 * true otherwise. 193 */ 194 bool hdr_record_corrected_value_atomic(struct hdr_histogram* h, int64_t value, int64_t expected_interval); 195 196 /** 197 * Record a value in the histogram 'count' times. Applies the same correcting logic 198 * as 'hdr_record_corrected_value'. 199 * 200 * @param h "This" pointer 201 * @param value Value to add to the histogram 202 * @param count Number of 'value's to add to the histogram 203 * @param expected_interval The delay between recording values. 204 * @return false if the value is larger than the highest_trackable_value and can't be recorded, 205 * true otherwise. 206 */ 207 bool hdr_record_corrected_values(struct hdr_histogram* h, int64_t value, int64_t count, int64_t expected_interval); 208 209 /** 210 * Record a value in the histogram 'count' times. Applies the same correcting logic 211 * as 'hdr_record_corrected_value'. 212 * 213 * Will record this value atomically, however the whole structure may appear inconsistent 214 * when read concurrently with this update. Do NOT mix calls to this method with calls 215 * to non-atomic updates. 216 * 217 * @param h "This" pointer 218 * @param value Value to add to the histogram 219 * @param count Number of 'value's to add to the histogram 220 * @param expected_interval The delay between recording values. 221 * @return false if the value is larger than the highest_trackable_value and can't be recorded, 222 * true otherwise. 223 */ 224 bool hdr_record_corrected_values_atomic(struct hdr_histogram* h, int64_t value, int64_t count, int64_t expected_interval); 225 226 /** 227 * Adds all of the values from 'from' to 'this' histogram. Will return the 228 * number of values that are dropped when copying. Values will be dropped 229 * if they around outside of h.lowest_discernible_value and 230 * h.highest_trackable_value. 231 * 232 * @param h "This" pointer 233 * @param from Histogram to copy values from. 234 * @return The number of values dropped when copying. 235 */ 236 int64_t hdr_add(struct hdr_histogram* h, const struct hdr_histogram* from); 237 238 /** 239 * Adds all of the values from 'from' to 'this' histogram. Will return the 240 * number of values that are dropped when copying. Values will be dropped 241 * if they around outside of h.lowest_discernible_value and 242 * h.highest_trackable_value. 243 * 244 * @param h "This" pointer 245 * @param from Histogram to copy values from. 246 * @return The number of values dropped when copying. 247 */ 248 int64_t hdr_add_while_correcting_for_coordinated_omission( 249 struct hdr_histogram* h, struct hdr_histogram* from, int64_t expected_interval); 250 251 /** 252 * Get minimum value from the histogram. Will return 2^63-1 if the histogram 253 * is empty. 254 * 255 * @param h "This" pointer 256 */ 257 int64_t hdr_min(const struct hdr_histogram* h); 258 259 /** 260 * Get maximum value from the histogram. Will return 0 if the histogram 261 * is empty. 262 * 263 * @param h "This" pointer 264 */ 265 int64_t hdr_max(const struct hdr_histogram* h); 266 267 /** 268 * Get the value at a specific percentile. 269 * 270 * @param h "This" pointer. 271 * @param percentile The percentile to get the value for 272 */ 273 int64_t hdr_value_at_percentile(const struct hdr_histogram* h, double percentile); 274 275 /** 276 * Get the values at the given percentiles. 277 * 278 * @param h "This" pointer. 279 * @param percentiles The ordered percentiles array to get the values for. 280 * @param length Number of elements in the arrays. 281 * @param values Destination array containing the values at the given percentiles. 282 * The values array should be allocated by the caller. 283 * @return 0 on success, ENOMEM if the provided destination array is null. 284 */ 285 int hdr_value_at_percentiles(const struct hdr_histogram *h, const double *percentiles, int64_t *values, size_t length); 286 287 /** 288 * Gets the standard deviation for the values in the histogram. 289 * 290 * @param h "This" pointer 291 * @return The standard deviation 292 */ 293 double hdr_stddev(const struct hdr_histogram* h); 294 295 /** 296 * Gets the mean for the values in the histogram. 297 * 298 * @param h "This" pointer 299 * @return The mean 300 */ 301 double hdr_mean(const struct hdr_histogram* h); 302 303 /** 304 * Determine if two values are equivalent with the histogram's resolution. 305 * Where "equivalent" means that value samples recorded for any two 306 * equivalent values are counted in a common total count. 307 * 308 * @param h "This" pointer 309 * @param a first value to compare 310 * @param b second value to compare 311 * @return 'true' if values are equivalent with the histogram's resolution. 312 */ 313 bool hdr_values_are_equivalent(const struct hdr_histogram* h, int64_t a, int64_t b); 314 315 /** 316 * Get the lowest value that is equivalent to the given value within the histogram's resolution. 317 * Where "equivalent" means that value samples recorded for any two 318 * equivalent values are counted in a common total count. 319 * 320 * @param h "This" pointer 321 * @param value The given value 322 * @return The lowest value that is equivalent to the given value within the histogram's resolution. 323 */ 324 int64_t hdr_lowest_equivalent_value(const struct hdr_histogram* h, int64_t value); 325 326 /** 327 * Get the count of recorded values at a specific value 328 * (to within the histogram resolution at the value level). 329 * 330 * @param h "This" pointer 331 * @param value The value for which to provide the recorded count 332 * @return The total count of values recorded in the histogram within the value range that is 333 * {@literal >=} lowestEquivalentValue(<i>value</i>) and {@literal <=} highestEquivalentValue(<i>value</i>) 334 */ 335 int64_t hdr_count_at_value(const struct hdr_histogram* h, int64_t value); 336 337 int64_t hdr_count_at_index(const struct hdr_histogram* h, int32_t index); 338 339 int64_t hdr_value_at_index(const struct hdr_histogram* h, int32_t index); 340 341 struct hdr_iter_percentiles 342 { 343 bool seen_last_value; 344 int32_t ticks_per_half_distance; 345 double percentile_to_iterate_to; 346 double percentile; 347 }; 348 349 struct hdr_iter_recorded 350 { 351 int64_t count_added_in_this_iteration_step; 352 }; 353 354 struct hdr_iter_linear 355 { 356 int64_t value_units_per_bucket; 357 int64_t count_added_in_this_iteration_step; 358 int64_t next_value_reporting_level; 359 int64_t next_value_reporting_level_lowest_equivalent; 360 }; 361 362 struct hdr_iter_log 363 { 364 double log_base; 365 int64_t count_added_in_this_iteration_step; 366 int64_t next_value_reporting_level; 367 int64_t next_value_reporting_level_lowest_equivalent; 368 }; 369 370 /** 371 * The basic iterator. This is a generic structure 372 * that supports all of the types of iteration. Use 373 * the appropriate initialiser to get the desired 374 * iteration. 375 * 376 * @ 377 */ 378 struct hdr_iter 379 { 380 const struct hdr_histogram* h; 381 /** raw index into the counts array */ 382 int32_t counts_index; 383 /** snapshot of the length at the time the iterator is created */ 384 int64_t total_count; 385 /** value directly from array for the current counts_index */ 386 int64_t count; 387 /** sum of all of the counts up to and including the count at this index */ 388 int64_t cumulative_count; 389 /** The current value based on counts_index */ 390 int64_t value; 391 int64_t highest_equivalent_value; 392 int64_t lowest_equivalent_value; 393 int64_t median_equivalent_value; 394 int64_t value_iterated_from; 395 int64_t value_iterated_to; 396 397 union 398 { 399 struct hdr_iter_percentiles percentiles; 400 struct hdr_iter_recorded recorded; 401 struct hdr_iter_linear linear; 402 struct hdr_iter_log log; 403 } specifics; 404 405 bool (* _next_fp)(struct hdr_iter* iter); 406 407 }; 408 409 /** 410 * Initalises the basic iterator. 411 * 412 * @param itr 'This' pointer 413 * @param h The histogram to iterate over 414 */ 415 void hdr_iter_init(struct hdr_iter* iter, const struct hdr_histogram* h); 416 417 /** 418 * Initialise the iterator for use with percentiles. 419 */ 420 void hdr_iter_percentile_init(struct hdr_iter* iter, const struct hdr_histogram* h, int32_t ticks_per_half_distance); 421 422 /** 423 * Initialise the iterator for use with recorded values. 424 */ 425 void hdr_iter_recorded_init(struct hdr_iter* iter, const struct hdr_histogram* h); 426 427 /** 428 * Initialise the iterator for use with linear values. 429 */ 430 void hdr_iter_linear_init( 431 struct hdr_iter* iter, 432 const struct hdr_histogram* h, 433 int64_t value_units_per_bucket); 434 435 /** 436 * Initialise the iterator for use with logarithmic values 437 */ 438 void hdr_iter_log_init( 439 struct hdr_iter* iter, 440 const struct hdr_histogram* h, 441 int64_t value_units_first_bucket, 442 double log_base); 443 444 /** 445 * Iterate to the next value for the iterator. If there are no more values 446 * available return faluse. 447 * 448 * @param itr 'This' pointer 449 * @return 'false' if there are no values remaining for this iterator. 450 */ 451 bool hdr_iter_next(struct hdr_iter* iter); 452 453 typedef enum 454 { 455 CLASSIC, 456 CSV 457 } format_type; 458 459 /** 460 * Print out a percentile based histogram to the supplied stream. Note that 461 * this call will not flush the FILE, this is left up to the user. 462 * 463 * @param h 'This' pointer 464 * @param stream The FILE to write the output to 465 * @param ticks_per_half_distance The number of iteration steps per half-distance to 100% 466 * @param value_scale Scale the output values by this amount 467 * @param format_type Format to use, e.g. CSV. 468 * @return 0 on success, error code on failure. EIO if an error occurs writing 469 * the output. 470 */ 471 int hdr_percentiles_print( 472 struct hdr_histogram* h, FILE* stream, int32_t ticks_per_half_distance, 473 double value_scale, format_type format); 474 475 /** 476 * Internal allocation methods, used by hdr_dbl_histogram. 477 */ 478 struct hdr_histogram_bucket_config 479 { 480 int64_t lowest_discernible_value; 481 int64_t highest_trackable_value; 482 int64_t unit_magnitude; 483 int64_t significant_figures; 484 int32_t sub_bucket_half_count_magnitude; 485 int32_t sub_bucket_half_count; 486 int64_t sub_bucket_mask; 487 int32_t sub_bucket_count; 488 int32_t bucket_count; 489 int32_t counts_len; 490 }; 491 492 int hdr_calculate_bucket_config( 493 int64_t lowest_discernible_value, 494 int64_t highest_trackable_value, 495 int significant_figures, 496 struct hdr_histogram_bucket_config* cfg); 497 498 void hdr_init_preallocated(struct hdr_histogram* h, struct hdr_histogram_bucket_config* cfg); 499 500 int64_t hdr_size_of_equivalent_value_range(const struct hdr_histogram* h, int64_t value); 501 502 int64_t hdr_next_non_equivalent_value(const struct hdr_histogram* h, int64_t value); 503 504 int64_t hdr_median_equivalent_value(const struct hdr_histogram* h, int64_t value); 505 506 /** 507 * Used to reset counters after importing data manually into the histogram, used by the logging code 508 * and other custom serialisation tools. 509 */ 510 void hdr_reset_internal_counters(struct hdr_histogram* h); 511 512 #ifdef __cplusplus 513 } 514 #endif 515 516 #endif 517