]>
Commit | Line | Data |
---|---|---|
064af421 | 1 | /* |
67a4917b | 2 | * Copyright (c) 2009, 2010 Nicira Networks. |
064af421 | 3 | * |
a14bc59f BP |
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: | |
064af421 | 7 | * |
a14bc59f BP |
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. | |
064af421 BP |
15 | */ |
16 | ||
17 | #include <config.h> | |
18 | #include "coverage.h" | |
19 | #include <inttypes.h> | |
20 | #include <stdlib.h> | |
064af421 BP |
21 | #include "dynamic-string.h" |
22 | #include "hash.h" | |
f5c6854a | 23 | #include "unixctl.h" |
064af421 | 24 | #include "util.h" |
064af421 BP |
25 | #include "vlog.h" |
26 | ||
d98e6007 | 27 | VLOG_DEFINE_THIS_MODULE(coverage); |
5136ce49 | 28 | |
d76f09ea BP |
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 | ||
064af421 BP |
48 | static unsigned int epoch; |
49 | ||
f5c6854a | 50 | static void |
c69ee87c BP |
51 | coverage_unixctl_log(struct unixctl_conn *conn, const char *args OVS_UNUSED, |
52 | void *aux OVS_UNUSED) | |
f5c6854a JP |
53 | { |
54 | coverage_log(VLL_WARN, false); | |
55 | unixctl_command_reply(conn, 200, NULL); | |
56 | } | |
57 | ||
f5c6854a JP |
58 | void |
59 | coverage_init(void) | |
60 | { | |
8ca79daa | 61 | unixctl_command_register("coverage/log", coverage_unixctl_log, NULL); |
f5c6854a JP |
62 | } |
63 | ||
064af421 BP |
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. */ | |
d76f09ea BP |
88 | c = xmalloc(n_coverage_counters * sizeof *c); |
89 | for (i = 0; i < n_coverage_counters; i++) { | |
064af421 BP |
90 | c[i] = coverage_counters[i]; |
91 | } | |
d76f09ea | 92 | qsort(c, n_coverage_counters, sizeof *c, compare_coverage_counters); |
064af421 BP |
93 | |
94 | /* Hash the names in each group along with the rank. */ | |
95 | n_groups = 0; | |
d76f09ea | 96 | for (i = 0; i < n_coverage_counters; ) { |
064af421 BP |
97 | int j; |
98 | ||
99 | if (!c[i]->count) { | |
100 | break; | |
101 | } | |
102 | n_groups++; | |
103 | hash = hash_int(i, hash); | |
d76f09ea | 104 | for (j = i; j < n_coverage_counters; j++) { |
064af421 BP |
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) { | |
c69ee87c | 130 | return true; |
064af421 BP |
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 | ||
f5c6854a | 143 | /* Logs the coverage counters at the given vlog 'level'. If |
d295e8e9 | 144 | * 'suppress_dups' is true, then duplicate events are not displayed. |
6bc995e4 JP |
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. */ | |
064af421 | 148 | void |
f5c6854a | 149 | coverage_log(enum vlog_level level, bool suppress_dups) |
064af421 BP |
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 | ||
e775da14 | 159 | hash = coverage_hash(); |
f5c6854a | 160 | if (suppress_dups) { |
f5c6854a JP |
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 | } | |
064af421 BP |
166 | } |
167 | ||
168 | n_never_hit = 0; | |
169 | VLOG(level, "Event coverage (epoch %u/entire run), hash=%08"PRIx32":", | |
170 | epoch, hash); | |
d76f09ea | 171 | for (i = 0; i < n_coverage_counters; i++) { |
064af421 BP |
172 | struct coverage_counter *c = coverage_counters[i]; |
173 | if (c->count) { | |
174 | coverage_log_counter(level, c); | |
175 | } | |
176 | } | |
d76f09ea | 177 | for (i = 0; i < n_coverage_counters; i++) { |
064af421 BP |
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++; | |
d76f09ea | 197 | for (i = 0; i < n_coverage_counters; i++) { |
064af421 BP |
198 | struct coverage_counter *c = coverage_counters[i]; |
199 | c->total += c->count; | |
200 | c->count = 0; | |
201 | } | |
202 | } |