likely.c 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. /* CC0 (Public domain) - see LICENSE file for details. */
  2. #ifdef CCAN_LIKELY_DEBUG
  3. #include <ccan/likely/likely.h>
  4. #include <ccan/hash/hash.h>
  5. #include <ccan/htable/htable_type.h>
  6. #include <stdlib.h>
  7. #include <stdio.h>
  8. struct trace {
  9. const char *condstr;
  10. const char *file;
  11. unsigned int line;
  12. bool expect;
  13. unsigned long count, right;
  14. };
  15. static size_t hash_trace(const struct trace *trace)
  16. {
  17. return hash(trace->condstr, strlen(trace->condstr),
  18. hash(trace->file, strlen(trace->file),
  19. trace->line + trace->expect));
  20. }
  21. static bool trace_eq(const struct trace *t1, const struct trace *t2)
  22. {
  23. return t1->condstr == t2->condstr
  24. && t1->file == t2->file
  25. && t1->line == t2->line
  26. && t1->expect == t2->expect;
  27. }
  28. /* struct thash */
  29. HTABLE_DEFINE_TYPE(struct trace, (const struct trace *), hash_trace, trace_eq,
  30. thash);
  31. static struct thash htable
  32. = { HTABLE_INITIALIZER(htable.raw, thash_hash, NULL) };
  33. static void init_trace(struct trace *trace,
  34. const char *condstr, const char *file, unsigned int line,
  35. bool expect)
  36. {
  37. trace->condstr = condstr;
  38. trace->file = file;
  39. trace->line = line;
  40. trace->expect = expect;
  41. trace->count = trace->right = 0;
  42. }
  43. static struct trace *add_trace(const struct trace *t)
  44. {
  45. struct trace *trace = malloc(sizeof(*trace));
  46. *trace = *t;
  47. thash_add(&htable, trace);
  48. return trace;
  49. }
  50. long _likely_trace(bool cond, bool expect,
  51. const char *condstr,
  52. const char *file, unsigned int line)
  53. {
  54. struct trace *p, trace;
  55. init_trace(&trace, condstr, file, line, expect);
  56. p = thash_get(&htable, &trace);
  57. if (!p)
  58. p = add_trace(&trace);
  59. p->count++;
  60. if (cond == expect)
  61. p->right++;
  62. return cond;
  63. }
  64. static double right_ratio(const struct trace *t)
  65. {
  66. return (double)t->right / t->count;
  67. }
  68. char *likely_stats(unsigned int min_hits, unsigned int percent)
  69. {
  70. struct trace *worst;
  71. double worst_ratio;
  72. struct thash_iter i;
  73. char *ret;
  74. struct trace *t;
  75. worst = NULL;
  76. worst_ratio = 2;
  77. /* This is O(n), but it's not likely called that often. */
  78. for (t = thash_first(&htable, &i); t; t = thash_next(&htable, &i)) {
  79. if (t->count >= min_hits) {
  80. if (right_ratio(t) < worst_ratio) {
  81. worst = t;
  82. worst_ratio = right_ratio(t);
  83. }
  84. }
  85. }
  86. if (worst_ratio * 100 > percent)
  87. return NULL;
  88. ret = malloc(strlen(worst->condstr) +
  89. strlen(worst->file) +
  90. sizeof(long int) * 8 +
  91. sizeof("%s:%u:%slikely(%s) correct %u%% (%lu/%lu)"));
  92. sprintf(ret, "%s:%u:%slikely(%s) correct %u%% (%lu/%lu)",
  93. worst->file, worst->line,
  94. worst->expect ? "" : "un", worst->condstr,
  95. (unsigned)(worst_ratio * 100),
  96. worst->right, worst->count);
  97. thash_del(&htable, worst);
  98. free(worst);
  99. return ret;
  100. }
  101. void likely_stats_reset(void)
  102. {
  103. struct thash_iter i;
  104. struct trace *t;
  105. /* This is a bit better than O(n^2), but we have to loop since
  106. * first/next during delete is unreliable. */
  107. while ((t = thash_first(&htable, &i)) != NULL) {
  108. for (; t; t = thash_next(&htable, &i)) {
  109. thash_del(&htable, t);
  110. free(t);
  111. }
  112. }
  113. thash_clear(&htable);
  114. }
  115. #endif /*CCAN_LIKELY_DEBUG*/