1 /* Licensed under LGPLv2.1+ - 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.h>
8 static struct htable
*htable
;
15 unsigned long count
, right
;
18 /* We hash the pointers, which will be identical for same call. */
19 static unsigned long hash_trace(const struct trace
*trace
)
21 return hash_pointer(trace
->condstr
,
22 hash_pointer(trace
->file
,
23 trace
->line
+ trace
->expect
));
26 static bool hash_cmp(const void *htelem
, void *cmpdata
)
28 const struct trace
*t1
= htelem
, *t2
= cmpdata
;
29 return t1
->condstr
== t2
->condstr
30 && t1
->file
== t2
->file
31 && t1
->line
== t2
->line
32 && t1
->expect
== t2
->expect
;
35 static size_t rehash(const void *elem
, void *priv
)
37 return hash_trace(elem
);
40 static void init_trace(struct trace
*trace
,
41 const char *condstr
, const char *file
, unsigned int line
,
44 trace
->condstr
= condstr
;
47 trace
->expect
= expect
;
48 trace
->count
= trace
->right
= 0;
51 static struct trace
*add_trace(const char *condstr
,
52 const char *file
, unsigned int line
, bool expect
)
54 struct trace
*trace
= malloc(sizeof(*trace
));
55 init_trace(trace
, condstr
, file
, line
, expect
);
56 htable_add(htable
, hash_trace(trace
), trace
);
60 long _likely_trace(bool cond
, bool expect
,
62 const char *file
, unsigned int line
)
64 struct trace
*p
, trace
;
67 htable
= htable_new(rehash
, NULL
);
69 init_trace(&trace
, condstr
, file
, line
, expect
);
70 p
= htable_get(htable
, hash_trace(&trace
), hash_cmp
, &trace
);
72 p
= add_trace(condstr
, file
, line
, expect
);
81 struct get_stats_info
{
83 unsigned int min_hits
;
87 static double right_ratio(const struct trace
*t
)
89 return (double)t
->right
/ t
->count
;
92 static void get_stats(struct trace
*trace
, struct get_stats_info
*info
)
94 if (trace
->count
< info
->min_hits
)
97 if (right_ratio(trace
) < info
->worst_ratio
) {
99 info
->worst_ratio
= right_ratio(trace
);
103 const char *likely_stats(unsigned int min_hits
, unsigned int percent
)
105 struct get_stats_info info
;
106 struct htable_iter i
;
113 info
.min_hits
= min_hits
;
115 info
.worst_ratio
= 2;
117 /* This is O(n), but it's not likely called that often. */
118 for (trace
= htable_first(htable
, &i
);
120 trace
= htable_next(htable
,&i
)) {
121 get_stats(trace
, &info
);
124 if (info
.worst_ratio
* 100 > percent
)
127 ret
= malloc(strlen(info
.worst
->condstr
) +
128 strlen(info
.worst
->file
) +
129 sizeof(long int) * 8 +
130 sizeof("%s:%u:%slikely(%s) correct %u%% (%lu/%lu)"));
131 sprintf(ret
, "%s:%u:%slikely(%s) correct %u%% (%lu/%lu)",
132 info
.worst
->file
, info
.worst
->line
,
133 info
.worst
->expect
? "" : "un", info
.worst
->condstr
,
134 (unsigned)(info
.worst_ratio
* 100),
135 info
.worst
->right
, info
.worst
->count
);
137 htable_del(htable
, hash_trace(info
.worst
), info
.worst
);
142 #endif /*CCAN_LIKELY_DEBUG*/