unixctl: Implement quoting.
[openvswitch] / lib / coverage.c
1 /*
2  * Copyright (c) 2009, 2010, 2011 Nicira Networks.
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 "unixctl.h"
24 #include "util.h"
25 #include "vlog.h"
26
27 VLOG_DEFINE_THIS_MODULE(coverage);
28
29 /* The coverage counters. */
30 #if USE_LINKER_SECTIONS
31 extern struct coverage_counter *__start_coverage[];
32 extern struct coverage_counter *__stop_coverage[];
33 #define coverage_counters __start_coverage
34 #define n_coverage_counters  (__stop_coverage - __start_coverage)
35 #else  /* !USE_LINKER_SECTIONS */
36 #define COVERAGE_COUNTER(NAME) COVERAGE_DEFINE__(NAME);
37 #include "coverage.def"
38 #undef COVERAGE_COUNTER
39
40 struct coverage_counter *coverage_counters[] = {
41 #define COVERAGE_COUNTER(NAME) &counter_##NAME,
42 #include "coverage.def"
43 #undef COVERAGE_COUNTER
44 };
45 #define n_coverage_counters ARRAY_SIZE(coverage_counters)
46 #endif  /* !USE_LINKER_SECTIONS */
47
48 static unsigned int epoch;
49
50 static void
51 coverage_unixctl_log(struct unixctl_conn *conn, int argc OVS_UNUSED,
52                      const char *argv[] OVS_UNUSED, void *aux OVS_UNUSED)
53 {
54     coverage_log(VLL_WARN, false);
55     unixctl_command_reply(conn, 200, NULL);
56 }
57
58 void
59 coverage_init(void)
60 {
61     unixctl_command_register("coverage/log", "", 0, 0,
62                              coverage_unixctl_log, NULL);
63 }
64
65 /* Sorts coverage counters in descending order by count, within equal counts
66  * alphabetically by name. */
67 static int
68 compare_coverage_counters(const void *a_, const void *b_)
69 {
70     const struct coverage_counter *const *ap = a_;
71     const struct coverage_counter *const *bp = b_;
72     const struct coverage_counter *a = *ap;
73     const struct coverage_counter *b = *bp;
74     if (a->count != b->count) {
75         return a->count < b->count ? 1 : -1;
76     } else {
77         return strcmp(a->name, b->name);
78     }
79 }
80
81 static uint32_t
82 coverage_hash(void)
83 {
84     struct coverage_counter **c;
85     uint32_t hash = 0;
86     int n_groups, i;
87
88     /* Sort coverage counters into groups with equal counts. */
89     c = xmalloc(n_coverage_counters * sizeof *c);
90     for (i = 0; i < n_coverage_counters; i++) {
91         c[i] = coverage_counters[i];
92     }
93     qsort(c, n_coverage_counters, sizeof *c, compare_coverage_counters);
94
95     /* Hash the names in each group along with the rank. */
96     n_groups = 0;
97     for (i = 0; i < n_coverage_counters; ) {
98         int j;
99
100         if (!c[i]->count) {
101             break;
102         }
103         n_groups++;
104         hash = hash_int(i, hash);
105         for (j = i; j < n_coverage_counters; j++) {
106             if (c[j]->count != c[i]->count) {
107                 break;
108             }
109             hash = hash_string(c[j]->name, hash);
110         }
111         i = j;
112     }
113
114     free(c);
115
116     return hash_int(n_groups, hash);
117 }
118
119 static bool
120 coverage_hit(uint32_t hash)
121 {
122     enum { HIT_BITS = 1024, BITS_PER_WORD = 32 };
123     static uint32_t hit[HIT_BITS / BITS_PER_WORD];
124     BUILD_ASSERT_DECL(IS_POW2(HIT_BITS));
125
126     unsigned int bit_index = hash & (HIT_BITS - 1);
127     unsigned int word_index = bit_index / BITS_PER_WORD;
128     unsigned int word_mask = 1u << (bit_index % BITS_PER_WORD);
129
130     if (hit[word_index] & word_mask) {
131  return true;
132     } else {
133         hit[word_index] |= word_mask;
134         return false;
135     }
136 }
137
138 static void
139 coverage_log_counter(enum vlog_level level, const struct coverage_counter *c)
140 {
141     VLOG(level, "%-24s %5u / %9llu", c->name, c->count, c->count + c->total);
142 }
143
144 /* Logs the coverage counters at the given vlog 'level'.  If
145  * 'suppress_dups' is true, then duplicate events are not displayed.
146  * Care should be taken in the value used for 'level'.  Depending on the
147  * configuration, syslog can write changes synchronously, which can
148  * cause the coverage messages to take several seconds to write. */
149 void
150 coverage_log(enum vlog_level level, bool suppress_dups)
151 {
152     size_t n_never_hit;
153     uint32_t hash;
154     size_t i;
155
156     if (!vlog_is_enabled(THIS_MODULE, level)) {
157         return;
158     }
159
160     hash = coverage_hash();
161     if (suppress_dups) {
162         if (coverage_hit(hash)) {
163             VLOG(level, "Skipping details of duplicate event coverage for "
164                  "hash=%08"PRIx32" in epoch %u", hash, epoch);
165             return;
166         }
167     }
168
169     n_never_hit = 0;
170     VLOG(level, "Event coverage (epoch %u/entire run), hash=%08"PRIx32":",
171          epoch, hash);
172     for (i = 0; i < n_coverage_counters; i++) {
173         struct coverage_counter *c = coverage_counters[i];
174         if (c->count) {
175             coverage_log_counter(level, c);
176         }
177     }
178     for (i = 0; i < n_coverage_counters; i++) {
179         struct coverage_counter *c = coverage_counters[i];
180         if (!c->count) {
181             if (c->total) {
182                 coverage_log_counter(level, c);
183             } else {
184                 n_never_hit++;
185             }
186         }
187     }
188     VLOG(level, "%zu events never hit", n_never_hit);
189 }
190
191 /* Advances to the next epoch of coverage, resetting all the counters to 0. */
192 void
193 coverage_clear(void)
194 {
195     size_t i;
196
197     epoch++;
198     for (i = 0; i < n_coverage_counters; i++) {
199         struct coverage_counter *c = coverage_counters[i];
200         c->total += c->count;
201         c->count = 0;
202     }
203 }