hdr_histogram.h 17 KB

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