Thanks!
On Fri, Aug 16, 2013 at 11:10 AM, Andy Zhou <az...@nicira.com> wrote: > Thanks Alex. > > Acked-by: Andy Zhou <az...@nicira.com> > > > > On Fri, Aug 16, 2013 at 10:48 AM, Alex Wang <al...@nicira.com> wrote: > >> This commit changes the "ovs-appclt coverage/show" command to show the >> secondly, minutely and hourly 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> >> --- >> >> v3 -> v4: >> - refine code and comments. >> - add unit test. >> >> v2 -> v3: >> - rebase to current master. >> >> v1 -> v2: >> - abandon the wakeup timer and coverage_wait() function. >> - now the coverage_run() will run only when more than 5 seconds have >> passed >> since last run. >> >> --- >> lib/coverage-unixctl.man | 3 +- >> lib/coverage.c | 94 >> +++++++++++++++++++++++++++++++++++++++------- >> lib/coverage.h | 22 +++++++++-- >> lib/timeval.c | 1 - >> tests/ofproto-dpif.at | 32 ++++++++++++++++ >> vswitchd/ovs-vswitchd.c | 2 + >> 6 files changed, 135 insertions(+), 19 deletions(-) >> >> diff --git a/lib/coverage-unixctl.man b/lib/coverage-unixctl.man >> index 9718894..a97653f 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 secondly, minutely and hourly rates, and total count >> +of all of the coverage counters. >> diff --git a/lib/coverage.c b/lib/coverage.c >> index f152474..1261f63 100644 >> --- a/lib/coverage.c >> +++ b/lib/coverage.c >> @@ -47,9 +47,19 @@ struct coverage_counter *coverage_counters[] = { >> #define n_coverage_counters ARRAY_SIZE(coverage_counters) >> #endif /* !USE_LINKER_SECTIONS */ >> >> -static unsigned int epoch; >> +static long long int coverage_run_time = LLONG_MIN; >> + >> +/* Defines the moving average array index variables. */ >> +static unsigned int min_idx = 0; >> +static unsigned int 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 *); >> +static unsigned int coverage_array_sum(const unsigned int *arr, >> + const unsigned int len); >> + >> >> static void >> coverage_unixctl_show(struct unixctl_conn *conn, int argc OVS_UNUSED, >> @@ -170,7 +180,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 +199,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 secondly rate is calculated via averaging the counts in >> + * the most recent COVERAGE_RUN_INTERVAL interval. */ >> + svec_add_nocopy(lines, >> + xasprintf("%-24s %5.1f/sec %7u/min " >> + "%9u/hr total: %llu", >> + c->name, >> + ((float) c->min[(idx_count - 1) % MIN_AVG_LEN]) >> + * 1000 / COVERAGE_RUN_INTERVAL, >> + coverage_array_sum(c->min, MIN_AVG_LEN), >> + coverage_array_sum(c->hr, HR_AVG_LEN), >> + c->count + c->total)); >> } >> >> /* Adds coverage counter information to 'lines'. */ >> @@ -204,8 +223,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 +244,65 @@ 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. */ >> +/* Runs approximately every COVERAGE_RUN_INTERVAL seconds to update the >> + * coverage counters' 'min' and 'hr' array. 'min' array is for >> cumulating >> + * secondly counts into minutely count. 'hr' array is for cumulating >> minutely >> + * counts into hourly count. */ >> void >> -coverage_clear(void) >> +coverage_run(void) >> { >> + long long int now = time_msec(); >> + >> + /* Initialize the coverage_run_time. */ >> + if (coverage_run_time == LLONG_MIN) { >> + coverage_run_time = now; >> + } >> + >> + if (now >= coverage_run_time) { >> + size_t i, j; >> + /* Computes the number of COVERAGE_RUN_INTERVAL slots, since >> + * it is possible that the actual run interval is multiple of >> + * COVERAGE_RUN_INTERVAL. */ >> + int slots = (now - coverage_run_time) / COVERAGE_RUN_INTERVAL + >> 1; >> + >> + for (i = 0; i < slots; i++) { >> + /* Updates the index variables. */ >> + /* The min_idx is increased from 0 to MIN_AVG_LEN - 1. Every >> + * time the min_idx finishes a cycle (a cycle is one minute), >> + * the hr_idx is incremented by 1. */ >> + min_idx = idx_count % MIN_AVG_LEN; >> + hr_idx = idx_count / MIN_AVG_LEN; >> + >> + for (j = 0; j < n_coverage_counters; j++) { >> + struct coverage_counter *c = coverage_counters[j]; >> + int portion; >> + >> + /* The count over the time interval is evenly distributed >> + * among slots by calculating the portion. */ >> + portion = c->count / slots + (i == (slots - 1) ? >> + c->count % slots : 0); >> + c->total += portion; >> + c->count = (i == (slots - 1) ? 0 : c->count); >> + c->min[min_idx] = portion; >> + c->hr[hr_idx] = min_idx == 0 ? portion >> + : (c->hr[hr_idx] + portion); >> + } >> + /* This is to guarantee that hr_idx ranges from 0 to 59. */ >> + idx_count = (idx_count + 1) % (MIN_AVG_LEN * HR_AVG_LEN); >> + } >> + /* Updates the run time. */ >> + coverage_run_time = now + COVERAGE_RUN_INTERVAL; >> + } >> +} >> + >> +static unsigned int >> +coverage_array_sum(const unsigned int *arr, const unsigned int len) >> +{ >> + unsigned int sum = 0; >> size_t i; >> >> - epoch++; >> - for (i = 0; i < n_coverage_counters; i++) { >> - struct coverage_counter *c = coverage_counters[i]; >> - c->total += c->count; >> - c->count = 0; >> + for (i = 0; i < len; i++) { >> + sum += arr[i]; >> } >> + return sum; >> } >> diff --git a/lib/coverage.h b/lib/coverage.h >> index 968c489..7af2cb1 100644 >> --- a/lib/coverage.h >> +++ b/lib/coverage.h >> @@ -29,11 +29,24 @@ >> >> #include "vlog.h" >> >> +/* Makes coverage_run run every 5000 ms (5 seconds). >> + * If this value is redefined, the new value must >> + * divide 60000. */ >> +#define COVERAGE_RUN_INTERVAL 5000 >> + >> +/* Defines the moving average array length. */ >> +#define MIN_AVG_LEN (60000/COVERAGE_RUN_INTERVAL) >> +#define HR_AVG_LEN 60 >> + >> /* 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 min[MIN_AVG_LEN]; >> + unsigned int hr[HR_AVG_LEN]; >> }; >> >> /* Defines COUNTER. There must be exactly one such definition at file >> scope >> @@ -57,11 +70,12 @@ struct coverage_counter { >> >> void coverage_init(void); >> void coverage_log(void); >> -void coverage_clear(void); >> +void coverage_run(void); >> >> /* 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} } >> >> #endif /* coverage.h */ >> diff --git a/lib/timeval.c b/lib/timeval.c >> index faf8e7b..2380a0a 100644 >> --- a/lib/timeval.c >> +++ b/lib/timeval.c >> @@ -304,7 +304,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/tests/ofproto-dpif.at b/tests/ofproto-dpif.at >> index b093998..a6e9e12 100644 >> --- a/tests/ofproto-dpif.at >> +++ b/tests/ofproto-dpif.at >> @@ -2689,3 +2689,35 @@ AT_CHECK([tail -1 stdout], [0], [Datapath actions: >> 5 >> ]) >> OVS_VSWITCHD_STOP >> AT_CLEANUP >> + >> +# Unit test for appctl coverage/show command >> +AT_SETUP([ofproto-dpif - coverage/show]) >> +OVS_VSWITCHD_START >> + >> +ovs-appctl time/stop >> +# before the first 5 seconds, nothing can be calculated but the total >> count. >> +AT_CHECK([ovs-appctl coverage/show | sed -n '/^unixctl_received.*/p'], >> [], [dnl >> +unixctl_received 0.0/sec 0/min 0/hr total: 2 >> +]) >> + >> +ovs-appctl time/warp 5000 >> +# at first 5 second time instant, should have stats. >> +AT_CHECK([ovs-appctl coverage/show | sed -n '/^unixctl_received.*/p'], >> [], [dnl >> +unixctl_received 0.6/sec 3/min 3/hr total: 4 >> +]) >> + >> +for i in `seq 0 10`; do ovs-appctl time/warp 5000; done >> +# advance to first 1 minute time instant. >> +AT_CHECK([ovs-appctl coverage/show | sed -n '/^unixctl_received.*/p'], >> [], [dnl >> +unixctl_received 0.2/sec 15/min 15/hr total: 16 >> +]) >> + >> +ovs-appctl time/warp 60000 >> +# advance to next 1 minute time instant directly, should observe the >> minutely >> +# rate drop. >> +AT_CHECK([ovs-appctl coverage/show | sed -n '/^unixctl_received.*/p'], >> [], [dnl >> +unixctl_received 0.4/sec 2/min 17/hr total: 18 >> +]) >> + >> +OVS_VSWITCHD_STOP >> +AT_CLEANUP >> diff --git a/vswitchd/ovs-vswitchd.c b/vswitchd/ovs-vswitchd.c >> index bc45dac..a9db1fd 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" >> @@ -119,6 +120,7 @@ main(int argc, char *argv[]) >> bridge_run_fast(); >> unixctl_server_run(unixctl); >> netdev_run(); >> + coverage_run(); >> >> signal_wait(sighup); >> memory_wait(); >> -- >> 1.7.9.5 >> >> _______________________________________________ >> dev mailing list >> dev@openvswitch.org >> http://openvswitch.org/mailman/listinfo/dev >> > >
_______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev