From: Ben Pfaff Date: Mon, 1 Nov 2010 21:14:27 +0000 (-0700) Subject: coverage: Make the coverage counters catalog program-specific. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=d76f09ea77e03ee5a3a7bb67bcab1ac4bb54172b;p=openvswitch coverage: Make the coverage counters catalog program-specific. Until now, the collection of coverage counters supported by a given OVS program was not specific to that program. That means that, for example, even though ovs-dpctl does not have anything to do with mac_learning, it still has a coverage counter for it. This is confusing, at best. This commit fixes the problem on some systems, in particular on ones that use GCC and the GNU linker. It uses the feature of the GNU linker described in its manual as: If an orphaned section's name is representable as a C identifier then the linker will automatically see PROVIDE two symbols: __start_SECNAME and __end_SECNAME, where SECNAME is the name of the section. These indicate the start address and end address of the orphaned section respectively. Systems that don't support these features retain the earlier behavior. This commit also fixes the annoyance that files that include coverage counters must be listed on COVERAGE_FILES in lib/automake.mk. This commit also fixes the annoyance that modifying any source file that includes a coverage counter caused all programs that link against libopenvswitch.a to relink, even programs that the source file was not linked into. For example, modifying ofproto/ofproto.c (which includes coverage counters) caused tests/test-aes128 to relink, even though test-aes128 does not link again ofproto.o. --- diff --git a/lib/automake.mk b/lib/automake.mk index 65556611..91d8fff2 100644 --- a/lib/automake.mk +++ b/lib/automake.mk @@ -26,7 +26,6 @@ lib_libopenvswitch_a_SOURCES = \ lib/compiler.h \ lib/coverage.c \ lib/coverage.h \ - lib/coverage-counters.h \ lib/csum.c \ lib/csum.h \ lib/daemon.c \ @@ -159,7 +158,6 @@ lib_libopenvswitch_a_SOURCES = \ lib/vlog.c \ lib/vlog.h nodist_lib_libopenvswitch_a_SOURCES = \ - lib/coverage-counters.c \ lib/dirs.c CLEANFILES += $(nodist_lib_libopenvswitch_a_SOURCES) @@ -246,6 +244,7 @@ lib-install-data-local: $(MKDIR_P) $(DESTDIR)$(PKIDIR) $(MKDIR_P) $(DESTDIR)$(LOGDIR) +if !USE_LINKER_SECTIONS # All distributed sources, with names adjust properly for referencing # from $(builddir). all_sources = \ @@ -257,37 +256,11 @@ all_sources = \ fi; \ done` -# All the source files that have coverage counters. -COVERAGE_FILES = \ - lib/dpif.c \ - lib/flow.c \ - lib/lockfile.c \ - lib/hmap.c \ - lib/mac-learning.c \ - lib/netdev.c \ - lib/netdev-linux.c \ - lib/netlink.c \ - lib/odp-util.c \ - lib/poll-loop.c \ - lib/process.c \ - lib/rconn.c \ - lib/rtnetlink.c \ - lib/stream.c \ - lib/stream-ssl.c \ - lib/timeval.c \ - lib/unixctl.c \ - lib/util.c \ - lib/vconn.c \ - ofproto/ofproto.c \ - ofproto/pktbuf.c \ - vswitchd/bridge.c \ - vswitchd/ovs-brcompatd.c -lib/coverage-counters.c: $(COVERAGE_FILES) lib/coverage-scan.pl - (cd $(srcdir) && $(PERL) lib/coverage-scan.pl $(COVERAGE_FILES)) > $@.tmp - mv $@.tmp $@ -EXTRA_DIST += lib/coverage-scan.pl +lib/coverage.$(OBJEXT): lib/coverage.def +lib/coverage.def: $(DIST_SOURCES) + sed -n 's|^COVERAGE_DEFINE(\([_a-zA-Z0-9]\{1,\}\)).*$$|COVERAGE_COUNTER(\1)|p' $(all_sources) | LC_ALL=C sort -u > $@ +CLEANFILES += lib/coverage.def -if !USE_LINKER_SECTIONS lib/vlog.$(OBJEXT): lib/vlog-modules.def lib/vlog-modules.def: $(DIST_SOURCES) sed -n 's|^VLOG_DEFINE_\(THIS_\)\{0,1\}MODULE(\([_a-zA-Z0-9]\{1,\}\)).*$$|VLOG_MODULE(\2)|p' $(all_sources) | LC_ALL=C sort -u > $@ diff --git a/lib/coverage-counters.h b/lib/coverage-counters.h deleted file mode 100644 index 8bf595cb..00000000 --- a/lib/coverage-counters.h +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (c) 2009 Nicira Networks. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef COVERAGE_COUNTERS_H -#define COVERAGE_COUNTERS_H 1 - -#include - -extern struct coverage_counter *coverage_counters[]; -extern size_t coverage_n_counters; - -#endif /* coverage.h */ diff --git a/lib/coverage-scan.pl b/lib/coverage-scan.pl deleted file mode 100755 index caea0b70..00000000 --- a/lib/coverage-scan.pl +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright (c) 2009 Nicira Networks. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at: -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -use strict; -use warnings; - -my %counters; -while (<>) { - my ($counter) = /^\s*COVERAGE_(?:INC|ADD)\s*\(\s*([a-zA-Z_][a-zA-Z_0-9]*)/ - or next; - push (@{$counters{$counter}}, "$ARGV:$."); -} continue { - # This magic resets $. from one file to the next. See "perldoc -f eof". - close ARGV if eof; -} - -print < -#include "coverage.h" -#include "util.h" - -EOF - -for my $counter (sort(keys(%counters))) { - my $locations = join(', ', @{$counters{$counter}}); - print < #include -#include "coverage-counters.h" #include "dynamic-string.h" #include "hash.h" #include "unixctl.h" @@ -27,6 +26,25 @@ VLOG_DEFINE_THIS_MODULE(coverage); +/* The coverage counters. */ +#if USE_LINKER_SECTIONS +extern struct coverage_counter *__start_coverage[]; +extern struct coverage_counter *__stop_coverage[]; +#define coverage_counters __start_coverage +#define n_coverage_counters (__stop_coverage - __start_coverage) +#else /* !USE_LINKER_SECTIONS */ +#define COVERAGE_COUNTER(NAME) COVERAGE_DEFINE__(NAME); +#include "coverage.def" +#undef COVERAGE_COUNTER + +struct coverage_counter *coverage_counters[] = { +#define COVERAGE_COUNTER(NAME) &counter_##NAME, +#include "coverage.def" +#undef COVERAGE_COUNTER +}; +#define n_coverage_counters ARRAY_SIZE(coverage_counters) +#endif /* !USE_LINKER_SECTIONS */ + static unsigned int epoch; static void @@ -67,15 +85,15 @@ coverage_hash(void) int n_groups, i; /* Sort coverage counters into groups with equal counts. */ - c = xmalloc(coverage_n_counters * sizeof *c); - for (i = 0; i < coverage_n_counters; i++) { + c = xmalloc(n_coverage_counters * sizeof *c); + for (i = 0; i < n_coverage_counters; i++) { c[i] = coverage_counters[i]; } - qsort(c, coverage_n_counters, sizeof *c, compare_coverage_counters); + qsort(c, n_coverage_counters, sizeof *c, compare_coverage_counters); /* Hash the names in each group along with the rank. */ n_groups = 0; - for (i = 0; i < coverage_n_counters; ) { + for (i = 0; i < n_coverage_counters; ) { int j; if (!c[i]->count) { @@ -83,7 +101,7 @@ coverage_hash(void) } n_groups++; hash = hash_int(i, hash); - for (j = i; j < coverage_n_counters; j++) { + for (j = i; j < n_coverage_counters; j++) { if (c[j]->count != c[i]->count) { break; } @@ -150,13 +168,13 @@ coverage_log(enum vlog_level level, bool suppress_dups) n_never_hit = 0; VLOG(level, "Event coverage (epoch %u/entire run), hash=%08"PRIx32":", epoch, hash); - for (i = 0; i < coverage_n_counters; i++) { + for (i = 0; i < n_coverage_counters; i++) { struct coverage_counter *c = coverage_counters[i]; if (c->count) { coverage_log_counter(level, c); } } - for (i = 0; i < coverage_n_counters; i++) { + for (i = 0; i < n_coverage_counters; i++) { struct coverage_counter *c = coverage_counters[i]; if (!c->count) { if (c->total) { @@ -176,7 +194,7 @@ coverage_clear(void) size_t i; epoch++; - for (i = 0; i < coverage_n_counters; i++) { + for (i = 0; i < n_coverage_counters; i++) { struct coverage_counter *c = coverage_counters[i]; c->total += c->count; c->count = 0; diff --git a/lib/coverage.h b/lib/coverage.h index aa93630b..d816fb61 100644 --- a/lib/coverage.h +++ b/lib/coverage.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009 Nicira Networks. + * Copyright (c) 2009, 2010 Nicira Networks. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,24 +36,30 @@ struct coverage_counter { unsigned long long int total; /* Total count over all epochs. */ }; -/* Increments the counter with the given NAME. Coverage counters need not be - * declared explicitly, but when you add the first coverage counter to a given - * file, you must also add that file to COVERAGE_FILES in lib/automake.mk. */ -#define COVERAGE_INC(NAME) \ - do { \ - extern struct coverage_counter NAME##_count; \ - NAME##_count.count++; \ - } while (0) - -/* Adds AMOUNT to the coverage counter with the given NAME. */ -#define COVERAGE_ADD(NAME, AMOUNT) \ - do { \ - extern struct coverage_counter NAME##_count; \ - NAME##_count.count += AMOUNT; \ - } while (0) +/* Defines COUNTER. There must be exactly one such definition at file scope + * within a program. */ +#if USE_LINKER_SECTIONS +#define COVERAGE_DEFINE(COUNTER) \ + COVERAGE_DEFINE__(COUNTER); \ + struct coverage_counter *counter_ptr_##COUNTER \ + __attribute__((section("coverage"))) = &counter_##COUNTER +#else +#define COVERAGE_DEFINE(MODULE) \ + extern struct coverage_counter counter_##MODULE +#endif + +/* Adds 1 to COUNTER. */ +#define COVERAGE_INC(COUNTER) counter_##COUNTER.count++; + +/* Adds AMOUNT to COUNTER. */ +#define COVERAGE_ADD(COUNTER, AMOUNT) counter_##COUNTER.count += (AMOUNT); void coverage_init(void); void coverage_log(enum vlog_level, bool suppress_dups); void coverage_clear(void); +/* Implementation detail. */ +#define COVERAGE_DEFINE__(COUNTER) \ + struct coverage_counter counter_##COUNTER = { #COUNTER, 0, 0 } + #endif /* coverage.h */ diff --git a/lib/dpif.c b/lib/dpif.c index ea806dc1..5402033d 100644 --- a/lib/dpif.c +++ b/lib/dpif.c @@ -42,6 +42,18 @@ VLOG_DEFINE_THIS_MODULE(dpif); +COVERAGE_DEFINE(dpif_destroy); +COVERAGE_DEFINE(dpif_port_add); +COVERAGE_DEFINE(dpif_port_del); +COVERAGE_DEFINE(dpif_flow_flush); +COVERAGE_DEFINE(dpif_flow_get); +COVERAGE_DEFINE(dpif_flow_put); +COVERAGE_DEFINE(dpif_flow_del); +COVERAGE_DEFINE(dpif_flow_query_list); +COVERAGE_DEFINE(dpif_flow_query_list_n); +COVERAGE_DEFINE(dpif_execute); +COVERAGE_DEFINE(dpif_purge); + static const struct dpif_class *base_dpif_classes[] = { #ifdef HAVE_NETLINK &dpif_linux_class, @@ -375,6 +387,7 @@ dpif_get_all_names(const struct dpif *dpif, struct svec *all_names) } } + /* Destroys the datapath that 'dpif' is connected to, first removing all of its * ports. After calling this function, it does not make sense to pass 'dpif' * to any functions other than dpif_name() or dpif_close(). */ diff --git a/lib/flow.c b/lib/flow.c index 099740dc..89225628 100644 --- a/lib/flow.c +++ b/lib/flow.c @@ -34,6 +34,8 @@ VLOG_DEFINE_THIS_MODULE(flow); +COVERAGE_DEFINE(flow_extract); + static struct arp_eth_header * pull_arp(struct ofpbuf *packet) { diff --git a/lib/hmap.c b/lib/hmap.c index 6bc5ea74..6b850fdd 100644 --- a/lib/hmap.c +++ b/lib/hmap.c @@ -23,6 +23,11 @@ #include "random.h" #include "util.h" +COVERAGE_DEFINE(hmap_pathological); +COVERAGE_DEFINE(hmap_expand); +COVERAGE_DEFINE(hmap_shrink); +COVERAGE_DEFINE(hmap_reserve); + /* Initializes 'hmap' as an empty hash table. */ void hmap_init(struct hmap *hmap) diff --git a/lib/lockfile.c b/lib/lockfile.c index f056502d..771ad70c 100644 --- a/lib/lockfile.c +++ b/lib/lockfile.c @@ -33,6 +33,11 @@ VLOG_DEFINE_THIS_MODULE(lockfile); +COVERAGE_DEFINE(lockfile_lock); +COVERAGE_DEFINE(lockfile_timeout); +COVERAGE_DEFINE(lockfile_error); +COVERAGE_DEFINE(lockfile_unlock); + struct lockfile { struct hmap_node hmap_node; char *name; diff --git a/lib/mac-learning.c b/lib/mac-learning.c index 9de338c6..af46e3cc 100644 --- a/lib/mac-learning.c +++ b/lib/mac-learning.c @@ -33,6 +33,9 @@ VLOG_DEFINE_THIS_MODULE(mac_learning); +COVERAGE_DEFINE(mac_learning_learned); +COVERAGE_DEFINE(mac_learning_expired); + /* Returns the number of seconds since 'e' was last learned. */ int mac_entry_age(const struct mac_entry *e) diff --git a/lib/netdev-linux.c b/lib/netdev-linux.c index d04eb715..bcd1633e 100644 --- a/lib/netdev-linux.c +++ b/lib/netdev-linux.c @@ -64,6 +64,14 @@ #include "vlog.h" VLOG_DEFINE_THIS_MODULE(netdev_linux); + +COVERAGE_DEFINE(netdev_get_vlan_vid); +COVERAGE_DEFINE(netdev_set_policing); +COVERAGE_DEFINE(netdev_arp_lookup); +COVERAGE_DEFINE(netdev_get_ifindex); +COVERAGE_DEFINE(netdev_get_hwaddr); +COVERAGE_DEFINE(netdev_set_hwaddr); +COVERAGE_DEFINE(netdev_ethtool); /* These were introduced in Linux 2.6.14, so they might be missing if we have * old headers. */ diff --git a/lib/netdev.c b/lib/netdev.c index 34cb1e9b..d108e9ca 100644 --- a/lib/netdev.c +++ b/lib/netdev.c @@ -42,6 +42,11 @@ VLOG_DEFINE_THIS_MODULE(netdev); +COVERAGE_DEFINE(netdev_received); +COVERAGE_DEFINE(netdev_sent); +COVERAGE_DEFINE(netdev_add_router); +COVERAGE_DEFINE(netdev_get_stats); + static struct shash netdev_classes = SHASH_INITIALIZER(&netdev_classes); /* All created network devices. */ diff --git a/lib/netlink.c b/lib/netlink.c index 0d072d08..8806f91d 100644 --- a/lib/netlink.c +++ b/lib/netlink.c @@ -35,6 +35,12 @@ VLOG_DEFINE_THIS_MODULE(netlink); +COVERAGE_DEFINE(netlink_overflow); +COVERAGE_DEFINE(netlink_received); +COVERAGE_DEFINE(netlink_recv_retry); +COVERAGE_DEFINE(netlink_send); +COVERAGE_DEFINE(netlink_sent); + /* Linux header file confusion causes this to be undefined. */ #ifndef SOL_NETLINK #define SOL_NETLINK 270 diff --git a/lib/poll-loop.c b/lib/poll-loop.c index 653fdd92..e47cccc3 100644 --- a/lib/poll-loop.c +++ b/lib/poll-loop.c @@ -32,6 +32,9 @@ VLOG_DEFINE_THIS_MODULE(poll_loop); +COVERAGE_DEFINE(poll_fd_wait); +COVERAGE_DEFINE(poll_zero_timeout); + /* An event that will wake the following call to poll_block(). */ struct poll_waiter { /* Set when the waiter is created. */ diff --git a/lib/process.c b/lib/process.c index a5f83b46..6e9ea8ec 100644 --- a/lib/process.c +++ b/lib/process.c @@ -36,6 +36,11 @@ VLOG_DEFINE_THIS_MODULE(process); +COVERAGE_DEFINE(process_run); +COVERAGE_DEFINE(process_run_capture); +COVERAGE_DEFINE(process_sigchld); +COVERAGE_DEFINE(process_start); + struct process { struct list node; char *name; diff --git a/lib/rconn.c b/lib/rconn.c index 45df35db..c21b7e84 100644 --- a/lib/rconn.c +++ b/lib/rconn.c @@ -34,6 +34,11 @@ VLOG_DEFINE_THIS_MODULE(rconn); +COVERAGE_DEFINE(rconn_discarded); +COVERAGE_DEFINE(rconn_overflow); +COVERAGE_DEFINE(rconn_queued); +COVERAGE_DEFINE(rconn_sent); + #define STATES \ STATE(VOID, 1 << 0) \ STATE(BACKOFF, 1 << 1) \ diff --git a/lib/rtnetlink.c b/lib/rtnetlink.c index bce95ce5..9beddb13 100644 --- a/lib/rtnetlink.c +++ b/lib/rtnetlink.c @@ -31,6 +31,8 @@ VLOG_DEFINE_THIS_MODULE(rtnetlink); +COVERAGE_DEFINE(rtnetlink_changed); + /* rtnetlink socket. */ static struct nl_sock *notify_sock; diff --git a/lib/stream-ssl.c b/lib/stream-ssl.c index b2a9f845..1fc7446f 100644 --- a/lib/stream-ssl.c +++ b/lib/stream-ssl.c @@ -47,6 +47,9 @@ VLOG_DEFINE_THIS_MODULE(stream_ssl); +COVERAGE_DEFINE(ssl_session); +COVERAGE_DEFINE(ssl_session_reused); + /* Active SSL. */ enum ssl_state { diff --git a/lib/stream.c b/lib/stream.c index 44d94d79..540597f1 100644 --- a/lib/stream.c +++ b/lib/stream.c @@ -39,6 +39,9 @@ VLOG_DEFINE_THIS_MODULE(stream); +COVERAGE_DEFINE(pstream_open); +COVERAGE_DEFINE(stream_open); + /* State of an active stream.*/ enum stream_state { SCS_CONNECTING, /* Underlying stream is not connected. */ diff --git a/lib/unixctl.c b/lib/unixctl.c index 161374e0..6e0b19ff 100644 --- a/lib/unixctl.c +++ b/lib/unixctl.c @@ -43,6 +43,9 @@ #endif VLOG_DEFINE_THIS_MODULE(unixctl); + +COVERAGE_DEFINE(unixctl_received); +COVERAGE_DEFINE(unixctl_replied); struct unixctl_command { unixctl_cb_func *cb; diff --git a/lib/util.c b/lib/util.c index 4f1b9f75..d6e470c9 100644 --- a/lib/util.c +++ b/lib/util.c @@ -27,6 +27,8 @@ VLOG_DEFINE_THIS_MODULE(util); +COVERAGE_DEFINE(util_xalloc); + const char *program_name; void diff --git a/lib/vconn.c b/lib/vconn.c index 3804061b..fc1aff6b 100644 --- a/lib/vconn.c +++ b/lib/vconn.c @@ -40,6 +40,10 @@ VLOG_DEFINE_THIS_MODULE(vconn); +COVERAGE_DEFINE(vconn_open); +COVERAGE_DEFINE(vconn_received); +COVERAGE_DEFINE(vconn_sent); + /* State of an active vconn.*/ enum vconn_state { /* This is the ordinary progression of states. */ diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index c2c48e12..c3214c59 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -63,6 +63,37 @@ VLOG_DEFINE_THIS_MODULE(ofproto); +COVERAGE_DEFINE(odp_overflow); +COVERAGE_DEFINE(ofproto_add_wc_flow); +COVERAGE_DEFINE(ofproto_agg_request); +COVERAGE_DEFINE(ofproto_costly_flags); +COVERAGE_DEFINE(ofproto_ctlr_action); +COVERAGE_DEFINE(ofproto_del_wc_flow); +COVERAGE_DEFINE(ofproto_dp_missed); +COVERAGE_DEFINE(ofproto_error); +COVERAGE_DEFINE(ofproto_expiration); +COVERAGE_DEFINE(ofproto_expired); +COVERAGE_DEFINE(ofproto_flows_req); +COVERAGE_DEFINE(ofproto_flush); +COVERAGE_DEFINE(ofproto_invalidated); +COVERAGE_DEFINE(ofproto_mod_wc_flow); +COVERAGE_DEFINE(ofproto_no_packet_in); +COVERAGE_DEFINE(ofproto_odp_unchanged); +COVERAGE_DEFINE(ofproto_ofconn_stuck); +COVERAGE_DEFINE(ofproto_ofp2odp); +COVERAGE_DEFINE(ofproto_packet_in); +COVERAGE_DEFINE(ofproto_packet_out); +COVERAGE_DEFINE(ofproto_queue_req); +COVERAGE_DEFINE(ofproto_recv_openflow); +COVERAGE_DEFINE(ofproto_reinit_ports); +COVERAGE_DEFINE(ofproto_revalidate); +COVERAGE_DEFINE(ofproto_revalidate_moved); +COVERAGE_DEFINE(ofproto_revalidate_rule); +COVERAGE_DEFINE(ofproto_subrule_create); +COVERAGE_DEFINE(ofproto_unexpected_rule); +COVERAGE_DEFINE(ofproto_uninstallable); +COVERAGE_DEFINE(ofproto_update_port); + #include "sflow_api.h" struct ofport { diff --git a/ofproto/pktbuf.c b/ofproto/pktbuf.c index 14781c11..b8698021 100644 --- a/ofproto/pktbuf.c +++ b/ofproto/pktbuf.c @@ -28,6 +28,11 @@ VLOG_DEFINE_THIS_MODULE(pktbuf); +COVERAGE_DEFINE(pktbuf_buffer_unknown); +COVERAGE_DEFINE(pktbuf_null_cookie); +COVERAGE_DEFINE(pktbuf_retrieved); +COVERAGE_DEFINE(pktbuf_reuse_error); + /* Buffers are identified by a 32-bit opaque ID. We divide the ID * into a buffer number (low bits) and a cookie (high bits). The buffer number * is an index into an array of buffers. The cookie distinguishes between diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index 0103eb99..bf34535a 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -72,6 +72,10 @@ VLOG_DEFINE_THIS_MODULE(bridge); +COVERAGE_DEFINE(bridge_flush); +COVERAGE_DEFINE(bridge_process_flow); +COVERAGE_DEFINE(bridge_reconfigure); + struct dst { uint16_t vlan; uint16_t dp_ifidx;