This looks good to me,
The only issue may be that some comments need to be changed:
-/* Sorts coverage counters in descending order by count, within equal
counts
- * alphabetically by name. */
+/* Sorts coverage counters in descending order by total count,
+ * within equal total counts alphabetically by name. */
static int
compare_coverage_counters(const void *a_, const void *b_)
{
@@ -108,7 +108,7 @@ coverage_hash(void)
uint32_t hash = 0;
int n_groups, i;
- /* Sort coverage counters into groups with equal counts. */
+ /* Sort coverage counters into groups with equal total counts. */
c = xmalloc(n_coverage_counters * sizeof *c);
ovs_mutex_lock(&coverage_mutex);
for (i = 0; i < n_coverage_counters; i++) {
On Fri, Aug 16, 2013 at 3:47 PM, Ben Pfaff <[email protected]> wrote:
> This makes each of the coverage counters per-thread. It abandons the
> idea of trying to keep track of the number of hits in the "current" poll
> loop, since there are many poll loops running, each in its own thread, as
> well as the idea of numbering epochs for the same reason. Instead, we
> just keep track of overall totals for the process for each coverage
> counter, accumulating per-thread counts into the global total each time
> a thread's main loop passes through poll_block().
>
> Signed-off-by: Ben Pfaff <[email protected]>
> ---
> lib/coverage.c | 73
> +++++++++++++++++++++++++++++++-------------------------
> lib/coverage.h | 41 ++++++++++++++++++++++---------
> 2 files changed, 71 insertions(+), 43 deletions(-)
>
> diff --git a/lib/coverage.c b/lib/coverage.c
> index f152474..ac5dd67 100644
> --- a/lib/coverage.c
> +++ b/lib/coverage.c
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
> + * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
> *
> * Licensed under the Apache License, Version 2.0 (the "License");
> * you may not use this file except in compliance with the License.
> @@ -35,7 +35,19 @@ 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);
> +#define COVERAGE_COUNTER(COUNTER) \
> + DECLARE_EXTERN_PER_THREAD_DATA(unsigned int, \
> + counter_##COUNTER); \
> + DEFINE_EXTERN_PER_THREAD_DATA(counter_##COUNTER, 0); \
> + static unsigned int COUNTER##_count(void) \
> + { \
> + unsigned int *countp = counter_##COUNTER##_get(); \
> + unsigned int count = *countp; \
> + *countp = 0; \
> + return count; \
> + } \
> + struct coverage_counter counter_##COUNTER \
> + = { #COUNTER, COUNTER##_count, 0 };
> #include "coverage.def"
> #undef COVERAGE_COUNTER
>
> @@ -47,7 +59,7 @@ struct coverage_counter *coverage_counters[] = {
> #define n_coverage_counters ARRAY_SIZE(coverage_counters)
> #endif /* !USE_LINKER_SECTIONS */
>
> -static unsigned int epoch;
> +static struct ovs_mutex coverage_mutex = OVS_MUTEX_INITIALIZER;
>
> static void coverage_read(struct svec *);
>
> @@ -82,8 +94,8 @@ compare_coverage_counters(const void *a_, const void *b_)
> const struct coverage_counter *const *bp = b_;
> const struct coverage_counter *a = *ap;
> const struct coverage_counter *b = *bp;
> - if (a->count != b->count) {
> - return a->count < b->count ? 1 : -1;
> + if (a->total != b->total) {
> + return a->total < b->total ? 1 : -1;
> } else {
> return strcmp(a->name, b->name);
> }
> @@ -98,9 +110,11 @@ coverage_hash(void)
>
> /* Sort coverage counters into groups with equal counts. */
> c = xmalloc(n_coverage_counters * sizeof *c);
> + ovs_mutex_lock(&coverage_mutex);
> for (i = 0; i < n_coverage_counters; i++) {
> c[i] = coverage_counters[i];
> }
> + ovs_mutex_unlock(&coverage_mutex);
> qsort(c, n_coverage_counters, sizeof *c, compare_coverage_counters);
>
> /* Hash the names in each group along with the rank. */
> @@ -108,13 +122,13 @@ coverage_hash(void)
> for (i = 0; i < n_coverage_counters; ) {
> int j;
>
> - if (!c[i]->count) {
> + if (!c[i]->total) {
> break;
> }
> n_groups++;
> hash = hash_int(i, hash);
> for (j = i; j < n_coverage_counters; j++) {
> - if (c[j]->count != c[i]->count) {
> + if (c[j]->total != c[i]->total) {
> break;
> }
> hash = hash_string(c[j]->name, hash);
> @@ -170,7 +184,7 @@ coverage_log(void)
> uint32_t hash = coverage_hash();
> if (coverage_hit(hash)) {
> VLOG_INFO("Skipping details of duplicate event coverage for "
> - "hash=%08"PRIx32" in epoch %u", hash, epoch);
> + "hash=%08"PRIx32, hash);
> } else {
> struct svec lines;
> const char *line;
> @@ -186,17 +200,11 @@ coverage_log(void)
> }
> }
>
> -static void
> -coverage_read_counter(struct svec *lines, const struct coverage_counter
> *c)
> -{
> - svec_add_nocopy(lines, xasprintf("%-24s %5u / %9llu",
> - c->name, c->count, c->count +
> c->total));
> -}
> -
> /* Adds coverage counter information to 'lines'. */
> static void
> coverage_read(struct svec *lines)
> {
> + unsigned long long int *totals;
> size_t n_never_hit;
> uint32_t hash;
> size_t i;
> @@ -204,37 +212,38 @@ coverage_read(struct svec *lines)
> hash = coverage_hash();
>
> n_never_hit = 0;
> - svec_add_nocopy(lines, xasprintf("Event coverage (epoch %u/entire
> run), "
> - "hash=%08"PRIx32":", epoch, hash));
> + svec_add_nocopy(lines,
> + xasprintf("Event coverage, hash=%08"PRIx32":", hash));
> +
> + totals = xmalloc(n_coverage_counters * sizeof *totals);
> + ovs_mutex_lock(&coverage_mutex);
> for (i = 0; i < n_coverage_counters; i++) {
> - struct coverage_counter *c = coverage_counters[i];
> - if (c->count) {
> - coverage_read_counter(lines, c);
> - }
> + totals[i] = coverage_counters[i]->total;
> }
> + ovs_mutex_unlock(&coverage_mutex);
> +
> for (i = 0; i < n_coverage_counters; i++) {
> - struct coverage_counter *c = coverage_counters[i];
> - if (!c->count) {
> - if (c->total) {
> - coverage_read_counter(lines, c);
> - } else {
> - n_never_hit++;
> - }
> + if (totals[i]) {
> + svec_add_nocopy(lines, xasprintf("%-24s %9llu",
> + coverage_counters[i]->name,
> + totals[i]));
> + } else {
> + n_never_hit++;
> }
> }
> svec_add_nocopy(lines, xasprintf("%zu events never hit",
> n_never_hit));
> + free(totals);
> }
>
> -/* Advances to the next epoch of coverage, resetting all the counters to
> 0. */
> void
> coverage_clear(void)
> {
> size_t i;
>
> - epoch++;
> + ovs_mutex_lock(&coverage_mutex);
> for (i = 0; i < n_coverage_counters; i++) {
> struct coverage_counter *c = coverage_counters[i];
> - c->total += c->count;
> - c->count = 0;
> + c->total += c->count();
> }
> + ovs_mutex_unlock(&coverage_mutex);
> }
> diff --git a/lib/coverage.h b/lib/coverage.h
> index 968c489..73b027a 100644
> --- a/lib/coverage.h
> +++ b/lib/coverage.h
> @@ -1,5 +1,5 @@
> /*
> - * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
> + * Copyright (c) 2009, 2010, 2011, 2012, 2013 Nicira, Inc.
> *
> * Licensed under the Apache License, Version 2.0 (the "License");
> * you may not use this file except in compliance with the License.
> @@ -27,33 +27,54 @@
> * for traditional coverage instrumentation with e.g. "gcov", but it is
> still
> * a useful debugging tool. */
>
> +#include "ovs-thread.h"
> #include "vlog.h"
>
> /* A coverage counter. */
> struct coverage_counter {
> - const char *name; /* Textual name. */
> - unsigned int count; /* Count within the current epoch. */
> - unsigned long long int total; /* Total count over all epochs. */
> + const char *const name; /* Textual name. */
> + unsigned int (*const count)(void); /* Gets, zeros this thread's
> count. */
> + unsigned long long int total; /* Total count. */
> };
>
> /* 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); \
> + DEFINE_STATIC_PER_THREAD_DATA(unsigned int, \
> + counter_##COUNTER, 0); \
> + static unsigned int COUNTER##_count(void) \
> + { \
> + unsigned int *countp = counter_##COUNTER##_get(); \
> + unsigned int count = *countp; \
> + *countp = 0; \
> + return count; \
> + } \
> + static inline void COUNTER##_add(unsigned int n) \
> + { \
> + *counter_##COUNTER##_get() += n; \
> + } \
> + struct coverage_counter counter_##COUNTER \
> + = { #COUNTER, COUNTER##_count, 0 }; \
> extern struct coverage_counter *counter_ptr_##COUNTER; \
> struct coverage_counter *counter_ptr_##COUNTER \
> __attribute__((section("coverage"))) = &counter_##COUNTER
> #else
> -#define COVERAGE_DEFINE(MODULE) \
> - extern struct coverage_counter counter_##MODULE
> +#define COVERAGE_DEFINE(COUNTER) \
> + DECLARE_EXTERN_PER_THREAD_DATA(unsigned int, \
> + counter_##COUNTER); \
> + static inline void COUNTER##_add(unsigned int n) \
> + { \
> + *counter_##COUNTER##_get() += n; \
> + } \
> + extern struct coverage_counter counter_##COUNTER
> #endif
>
> /* Adds 1 to COUNTER. */
> -#define COVERAGE_INC(COUNTER) counter_##COUNTER.count++;
> +#define COVERAGE_INC(COUNTER) COVERAGE_ADD(COUNTER, 1)
>
> /* Adds AMOUNT to COUNTER. */
> -#define COVERAGE_ADD(COUNTER, AMOUNT) counter_##COUNTER.count += (AMOUNT);
> +#define COVERAGE_ADD(COUNTER, AMOUNT) COUNTER##_add(AMOUNT)
>
> void coverage_init(void);
> void coverage_log(void);
> @@ -61,7 +82,5 @@ void coverage_clear(void);
>
> /* Implementation detail. */
> #define COVERAGE_DEFINE__(COUNTER) \
> - extern struct coverage_counter counter_##COUNTER; \
> - struct coverage_counter counter_##COUNTER = { #COUNTER, 0, 0 }
>
> #endif /* coverage.h */
> --
> 1.7.10.4
>
> _______________________________________________
> dev mailing list
> [email protected]
> http://openvswitch.org/mailman/listinfo/dev
>
_______________________________________________
dev mailing list
[email protected]
http://openvswitch.org/mailman/listinfo/dev