sparse: Suppress sparse warnings for global variables.
[sliver-openvswitch.git] / lib / coverage.c
1 /*
2  * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <config.h>
18 #include "coverage.h"
19 #include <inttypes.h>
20 #include <stdlib.h>
21 #include "dynamic-string.h"
22 #include "hash.h"
23 #include "svec.h"
24 #include "timeval.h"
25 #include "unixctl.h"
26 #include "util.h"
27 #include "vlog.h"
28
29 VLOG_DEFINE_THIS_MODULE(coverage);
30
31 /* The coverage counters. */
32 #if USE_LINKER_SECTIONS
33 extern struct coverage_counter *__start_coverage[];
34 extern struct coverage_counter *__stop_coverage[];
35 #define coverage_counters __start_coverage
36 #define n_coverage_counters  (__stop_coverage - __start_coverage)
37 #else  /* !USE_LINKER_SECTIONS */
38 #define COVERAGE_COUNTER(COUNTER)                                       \
39         DECLARE_EXTERN_PER_THREAD_DATA(unsigned int,                    \
40                                        counter_##COUNTER);              \
41         DEFINE_EXTERN_PER_THREAD_DATA(counter_##COUNTER, 0);            \
42         static unsigned int COUNTER##_count(void)                       \
43         {                                                               \
44             unsigned int *countp = counter_##COUNTER##_get();           \
45             unsigned int count = *countp;                               \
46             *countp = 0;                                                \
47             return count;                                               \
48         }                                                               \
49         extern struct coverage_counter counter_##COUNTER;               \
50         struct coverage_counter counter_##COUNTER                       \
51             = { #COUNTER, COUNTER##_count, 0 };
52 #include "coverage.def"
53 #undef COVERAGE_COUNTER
54
55 extern struct coverage_counter *coverage_counters[];
56 struct coverage_counter *coverage_counters[] = {
57 #define COVERAGE_COUNTER(NAME) &counter_##NAME,
58 #include "coverage.def"
59 #undef COVERAGE_COUNTER
60 };
61 #define n_coverage_counters ARRAY_SIZE(coverage_counters)
62 #endif  /* !USE_LINKER_SECTIONS */
63
64 static struct ovs_mutex coverage_mutex = OVS_MUTEX_INITIALIZER;
65
66 static void coverage_read(struct svec *);
67
68 static void
69 coverage_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED,
70                      const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
71 {
72     struct svec lines;
73     char *reply;
74
75     svec_init(&lines);
76     coverage_read(&lines);
77     reply = svec_join(&lines, "\n", "\n");
78     unixctl_command_reply(conn, reply);
79     free(reply);
80     svec_destroy(&lines);
81 }
82
83 void
84 coverage_init(void)
85 {
86     unixctl_command_register("coverage/show", "", 0, 0,
87                              coverage_unixctl_show, NULL);
88 }
89
90 /* Sorts coverage counters in descending order by total, within equal
91  * totals alphabetically by name. */
92 static int
93 compare_coverage_counters(const void *a_, const void *b_)
94 {
95     const struct coverage_counter *const *ap = a_;
96     const struct coverage_counter *const *bp = b_;
97     const struct coverage_counter *a = *ap;
98     const struct coverage_counter *b = *bp;
99     if (a->total != b->total) {
100         return a->total < b->total ? 1 : -1;
101     } else {
102         return strcmp(a->name, b->name);
103     }
104 }
105
106 static uint32_t
107 coverage_hash(void)
108 {
109     struct coverage_counter **c;
110     uint32_t hash = 0;
111     int n_groups, i;
112
113     /* Sort coverage counters into groups with equal totals. */
114     c = xmalloc(n_coverage_counters * sizeof *c);
115     ovs_mutex_lock(&coverage_mutex);
116     for (i = 0; i < n_coverage_counters; i++) {
117         c[i] = coverage_counters[i];
118     }
119     ovs_mutex_unlock(&coverage_mutex);
120     qsort(c, n_coverage_counters, sizeof *c, compare_coverage_counters);
121
122     /* Hash the names in each group along with the rank. */
123     n_groups = 0;
124     for (i = 0; i < n_coverage_counters; ) {
125         int j;
126
127         if (!c[i]->total) {
128             break;
129         }
130         n_groups++;
131         hash = hash_int(i, hash);
132         for (j = i; j < n_coverage_counters; j++) {
133             if (c[j]->total != c[i]->total) {
134                 break;
135             }
136             hash = hash_string(c[j]->name, hash);
137         }
138         i = j;
139     }
140
141     free(c);
142
143     return hash_int(n_groups, hash);
144 }
145
146 static bool
147 coverage_hit(uint32_t hash)
148 {
149     enum { HIT_BITS = 1024, BITS_PER_WORD = 32 };
150     static uint32_t hit[HIT_BITS / BITS_PER_WORD];
151     BUILD_ASSERT_DECL(IS_POW2(HIT_BITS));
152
153     static long long int next_clear = LLONG_MIN;
154
155     unsigned int bit_index = hash & (HIT_BITS - 1);
156     unsigned int word_index = bit_index / BITS_PER_WORD;
157     unsigned int word_mask = 1u << (bit_index % BITS_PER_WORD);
158
159     /* Expire coverage hash suppression once a day. */
160     if (time_msec() >= next_clear) {
161         memset(hit, 0, sizeof hit);
162         next_clear = time_msec() + 60 * 60 * 24 * 1000LL;
163     }
164
165     if (hit[word_index] & word_mask) {
166         return true;
167     } else {
168         hit[word_index] |= word_mask;
169         return false;
170     }
171 }
172
173 /* Logs the coverage counters, unless a similar set of events has already been
174  * logged.
175  *
176  * This function logs at log level VLL_INFO.  Use care before adjusting this
177  * level, because depending on its configuration, syslogd can write changes
178  * synchronously, which can cause the coverage messages to take several seconds
179  * to write. */
180 void
181 coverage_log(void)
182 {
183     static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 3);
184
185     if (!VLOG_DROP_INFO(&rl)) {
186         uint32_t hash = coverage_hash();
187         if (coverage_hit(hash)) {
188             VLOG_INFO("Skipping details of duplicate event coverage for "
189                       "hash=%08"PRIx32, hash);
190         } else {
191             struct svec lines;
192             const char *line;
193             size_t i;
194
195             svec_init(&lines);
196             coverage_read(&lines);
197             SVEC_FOR_EACH (i, line, &lines) {
198                 VLOG_INFO("%s", line);
199             }
200             svec_destroy(&lines);
201         }
202     }
203 }
204
205 /* Adds coverage counter information to 'lines'. */
206 static void
207 coverage_read(struct svec *lines)
208 {
209     unsigned long long int *totals;
210     size_t n_never_hit;
211     uint32_t hash;
212     size_t i;
213
214     hash = coverage_hash();
215
216     n_never_hit = 0;
217     svec_add_nocopy(lines,
218                     xasprintf("Event coverage, hash=%08"PRIx32":", hash));
219
220     totals = xmalloc(n_coverage_counters * sizeof *totals);
221     ovs_mutex_lock(&coverage_mutex);
222     for (i = 0; i < n_coverage_counters; i++) {
223         totals[i] = coverage_counters[i]->total;
224     }
225     ovs_mutex_unlock(&coverage_mutex);
226
227     for (i = 0; i < n_coverage_counters; i++) {
228         if (totals[i]) {
229             svec_add_nocopy(lines, xasprintf("%-24s %9llu",
230                                              coverage_counters[i]->name,
231                                              totals[i]));
232         } else {
233             n_never_hit++;
234         }
235     }
236     svec_add_nocopy(lines, xasprintf("%zu events never hit", n_never_hit));
237     free(totals);
238 }
239
240 void
241 coverage_clear(void)
242 {
243     size_t i;
244
245     ovs_mutex_lock(&coverage_mutex);
246     for (i = 0; i < n_coverage_counters; i++) {
247         struct coverage_counter *c = coverage_counters[i];
248         c->total += c->count();
249     }
250     ovs_mutex_unlock(&coverage_mutex);
251 }