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