This commit changes the "ovs-appclt coverage/show" command to show the per-second, per-minute and per-hour rates of function invocation. More importantly, this makes using coverage counter an easy way to monitor the execution of specific functions.
Signed-off-by: Alex Wang <al...@nicira.com> --- Possible Issue: The "coverage_run" runs every second. And the number of addition operations is not very large. If it is still considered to be time-consuming, I'll adjust further. --- lib/coverage-unixctl.man | 3 +- lib/coverage.c | 76 +++++++++++++++++++++++++++++++++++++--------- lib/coverage.h | 33 +++++++++++++++++--- lib/timeval.c | 1 - vswitchd/ovs-vswitchd.c | 3 ++ 5 files changed, 96 insertions(+), 20 deletions(-) diff --git a/lib/coverage-unixctl.man b/lib/coverage-unixctl.man index 9718894..2d283dc 100644 --- a/lib/coverage-unixctl.man +++ b/lib/coverage-unixctl.man @@ -8,4 +8,5 @@ main loop takes unusually long to run. Coverage counters are useful mainly for performance analysis and debugging. .IP "\fBcoverage/show\fR" -Displays the values of all of the coverage counters. +Displays the per-second, per-minute and per-hour rates, and total count +of all of the coverage counters. diff --git a/lib/coverage.c b/lib/coverage.c index f152474..814c741 100644 --- a/lib/coverage.c +++ b/lib/coverage.c @@ -47,7 +47,19 @@ struct coverage_counter *coverage_counters[] = { #define n_coverage_counters ARRAY_SIZE(coverage_counters) #endif /* !USE_LINKER_SECTIONS */ -static unsigned int epoch; +/* Makes coverage_run run every second. */ +#define COVERAGE_WAKEUP_INTERVAL 1000 +static long long int coverage_wakeup_timer = LLONG_MIN; + +#define HR_TIME 3600 /* 3600 seconds in one hour. */ + +/* Defines the moving average array index variables. */ +static unsigned int mov_avg_sec_idx = 0; +static unsigned int mov_avg_min_idx = 0; +static unsigned int mov_avg_hr_idx = 0; + +/* Index counter used to compute the moving average array's index. */ +static unsigned int idx_count = 0; static void coverage_read(struct svec *); @@ -170,7 +182,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; @@ -189,8 +201,17 @@ 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)); + /* The per second rate is calculated via averaging the counts in recent + * five seconds. */ + svec_add_nocopy(lines, + xasprintf("%-24s %5.1f/sec %7u/min " + "%9u/hr total: %llu", + c->name, + coverage_array_sum(c->mov_avg_sec, MOV_AVG_SEC_LEN) + / (float) MOV_AVG_SEC_LEN, + coverage_array_sum(c->mov_avg_min, MOV_AVG_MIN_LEN), + coverage_array_sum(c->mov_avg_hr, MOV_AVG_HR_LEN), + c->count + c->total)); } /* Adds coverage counter information to 'lines'. */ @@ -204,8 +225,8 @@ 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 (frequency), " + "hash=%08"PRIx32":", hash)); for (i = 0; i < n_coverage_counters; i++) { struct coverage_counter *c = coverage_counters[i]; if (c->count) { @@ -225,16 +246,43 @@ coverage_read(struct svec *lines) svec_add_nocopy(lines, xasprintf("%zu events never hit", n_never_hit)); } -/* Advances to the next epoch of coverage, resetting all the counters to 0. */ +/* Causes the following call to poll_block() to wake up every second. */ void -coverage_clear(void) +coverage_wait(void) { - size_t i; + poll_timer_wait_until(coverage_wakeup_timer); +} - epoch++; - for (i = 0; i < n_coverage_counters; i++) { - struct coverage_counter *c = coverage_counters[i]; - c->total += c->count; - c->count = 0; +/* Runs every second to update the coverage counters' mov_avg_sec array, + * mov_avg_min array and mov_avg_hr array. */ +void +coverage_run(void) +{ + if (time_msec() >= coverage_wakeup_timer) { + size_t i; + + /* Updates the index variables. */ + mov_avg_sec_idx = idx_count % MOV_AVG_SEC_LEN; + mov_avg_min_idx = (idx_count / MOV_AVG_SEC_LEN) % MOV_AVG_MIN_LEN; + mov_avg_hr_idx = idx_count / MOV_AVG_HR_LEN; + + for (i = 0; i < n_coverage_counters; i++) { + struct coverage_counter *c = coverage_counters[i]; + + c->total += c->count; + c->mov_avg_sec[mov_avg_sec_idx] = c->count; + /* Note, only adds up the latest count here. */ + c->mov_avg_min[mov_avg_min_idx] = mov_avg_sec_idx == 0 ? + c->count : (c->mov_avg_min[mov_avg_min_idx] + c->count); + /* The summation here is for fast sync change to per-hour rate. + * should be modified when it becomes very time consuming. */ + c->mov_avg_hr[mov_avg_hr_idx] = + coverage_array_sum(c->mov_avg_min, mov_avg_min_idx + 1); + c->count = 0; + } + + /* Always updates the wakeup timer and idx_count. */ + coverage_wakeup_timer = time_msec() + COVERAGE_WAKEUP_INTERVAL; + idx_count = (idx_count + 1) % HR_TIME; } } diff --git a/lib/coverage.h b/lib/coverage.h index 968c489..60c5107 100644 --- a/lib/coverage.h +++ b/lib/coverage.h @@ -27,13 +27,24 @@ * for traditional coverage instrumentation with e.g. "gcov", but it is still * a useful debugging tool. */ +#include "poll-loop.h" #include "vlog.h" +/* Defines the moving average array length. */ +#define MOV_AVG_SEC_LEN 5 /* 1 * 5 second = 5 seconds */ +#define MOV_AVG_MIN_LEN 12 /* 12 * 5 seconds = 1 minute */ +#define MOV_AVG_HR_LEN 60 /* 60 * 1 minute = 1 hour */ + /* 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. */ + unsigned int count; /* Count within the current second. */ + unsigned long long int total; /* Total count over all time. */ + + /* The moving average arrays. */ + unsigned int mov_avg_sec[MOV_AVG_SEC_LEN]; + unsigned int mov_avg_min[MOV_AVG_MIN_LEN]; + unsigned int mov_avg_hr[MOV_AVG_HR_LEN]; }; /* Defines COUNTER. There must be exactly one such definition at file scope @@ -57,11 +68,25 @@ struct coverage_counter { void coverage_init(void); void coverage_log(void); -void coverage_clear(void); +void coverage_wait(void); +void coverage_run(void); + +static inline unsigned int +coverage_array_sum(const unsigned int arr[], unsigned int len) +{ + unsigned int sum = 0; + size_t i; + + for (i = 0; i < len; i++) { + sum += arr[i]; + } + return sum; +} /* Implementation detail. */ #define COVERAGE_DEFINE__(COUNTER) \ extern struct coverage_counter counter_##COUNTER; \ - struct coverage_counter counter_##COUNTER = { #COUNTER, 0, 0 } + struct coverage_counter counter_##COUNTER = { #COUNTER, 0, 0, \ + {0}, {0}, {0} } #endif /* coverage.h */ diff --git a/lib/timeval.c b/lib/timeval.c index 5ff59bc..fe4f2a7 100644 --- a/lib/timeval.c +++ b/lib/timeval.c @@ -333,7 +333,6 @@ time_poll(struct pollfd *pollfds, int n_pollfds, long long int timeout_when, if (last_wakeup) { log_poll_interval(last_wakeup); } - coverage_clear(); start = time_msec(); blocked = false; diff --git a/vswitchd/ovs-vswitchd.c b/vswitchd/ovs-vswitchd.c index e11febd..9bf4664 100644 --- a/vswitchd/ovs-vswitchd.c +++ b/vswitchd/ovs-vswitchd.c @@ -28,6 +28,7 @@ #include "bridge.h" #include "command-line.h" #include "compiler.h" +#include "coverage.h" #include "daemon.h" #include "dirs.h" #include "dpif.h" @@ -126,6 +127,7 @@ main(int argc, char *argv[]) bridge_run_fast(); unixctl_server_run(unixctl); netdev_run(); + coverage_run(); worker_wait(); signal_wait(sighup); @@ -133,6 +135,7 @@ main(int argc, char *argv[]) bridge_wait(); unixctl_server_wait(unixctl); netdev_wait(); + coverage_wait(); if (exiting) { poll_immediate_wake(); } -- 1.7.9.5 _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev