likely.c 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. #ifdef CCAN_LIKELY_DEBUG
  2. #include <ccan/likely/likely.h>
  3. #include <ccan/hash/hash.h>
  4. #include <ccan/htable/htable.h>
  5. #include <stdlib.h>
  6. #include <stdio.h>
  7. static struct htable *htable;
  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. /* We hash the pointers, which will be identical for same call. */
  16. static unsigned long hash_trace(const struct trace *trace)
  17. {
  18. return hash_pointer(trace->condstr,
  19. hash_pointer(trace->file,
  20. trace->line + trace->expect));
  21. }
  22. static bool hash_cmp(const void *htelem, void *cmpdata)
  23. {
  24. const struct trace *t1 = htelem, *t2 = cmpdata;
  25. return t1->condstr == t2->condstr
  26. && t1->file == t2->file
  27. && t1->line == t2->line
  28. && t1->expect == t2->expect;
  29. }
  30. static size_t rehash(const void *elem, void *priv)
  31. {
  32. return hash_trace(elem);
  33. }
  34. static void init_trace(struct trace *trace,
  35. const char *condstr, const char *file, unsigned int line,
  36. bool expect)
  37. {
  38. trace->condstr = condstr;
  39. trace->file = file;
  40. trace->line = line;
  41. trace->expect = expect;
  42. trace->count = trace->right = 0;
  43. }
  44. static struct trace *add_trace(const char *condstr,
  45. const char *file, unsigned int line, bool expect)
  46. {
  47. struct trace *trace = malloc(sizeof(*trace));
  48. init_trace(trace, condstr, file, line, expect);
  49. htable_add(htable, hash_trace(trace), trace);
  50. return trace;
  51. }
  52. long _likely_trace(bool cond, bool expect,
  53. const char *condstr,
  54. const char *file, unsigned int line)
  55. {
  56. struct trace *p, trace;
  57. if (!htable)
  58. htable = htable_new(rehash, NULL);
  59. init_trace(&trace, condstr, file, line, expect);
  60. p = htable_get(htable, hash_trace(&trace), hash_cmp, &trace);
  61. if (!p)
  62. p = add_trace(condstr, file, line, expect);
  63. p->count++;
  64. if (cond == expect)
  65. p->right++;
  66. return cond;
  67. }
  68. struct get_stats_info {
  69. struct trace *worst;
  70. unsigned int min_hits;
  71. double worst_ratio;
  72. };
  73. static double right_ratio(const struct trace *t)
  74. {
  75. return (double)t->right / t->count;
  76. }
  77. static void get_stats(struct trace *trace, struct get_stats_info *info)
  78. {
  79. if (trace->count < info->min_hits)
  80. return;
  81. if (right_ratio(trace) < info->worst_ratio) {
  82. info->worst = trace;
  83. info->worst_ratio = right_ratio(trace);
  84. }
  85. }
  86. const char *likely_stats(unsigned int min_hits, unsigned int percent)
  87. {
  88. struct get_stats_info info;
  89. struct htable_iter i;
  90. char *ret;
  91. struct trace *trace;
  92. if (!htable)
  93. return NULL;
  94. info.min_hits = min_hits;
  95. info.worst = NULL;
  96. info.worst_ratio = 2;
  97. /* This is O(n), but it's not likely called that often. */
  98. for (trace = htable_first(htable, &i);
  99. trace;
  100. trace = htable_next(htable,&i)) {
  101. get_stats(trace, &info);
  102. }
  103. if (info.worst_ratio * 100 > percent)
  104. return NULL;
  105. ret = malloc(strlen(info.worst->condstr) +
  106. strlen(info.worst->file) +
  107. sizeof(long int) * 8 +
  108. sizeof("%s:%u:%slikely(%s) correct %u%% (%lu/%lu)"));
  109. sprintf(ret, "%s:%u:%slikely(%s) correct %u%% (%lu/%lu)",
  110. info.worst->file, info.worst->line,
  111. info.worst->expect ? "" : "un", info.worst->condstr,
  112. (unsigned)(info.worst_ratio * 100),
  113. info.worst->right, info.worst->count);
  114. htable_del(htable, hash_trace(info.worst), info.worst);
  115. free(info.worst);
  116. return ret;
  117. }
  118. #endif /*CCAN_LIKELY_DEBUG*/