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