This commit changes the "ovs-appctl 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> --- lib/coverage-unixctl.man | 3 +- lib/coverage.c | 106 ++++++++++++++++++++++++++++++++++++++++++++-- lib/coverage.h | 16 ++++++- tests/ofproto-dpif.at | 34 +++++++++++++++ vswitchd/ovs-vswitchd.c | 2 + 5 files changed, 155 insertions(+), 6 deletions(-) diff --git a/lib/coverage-unixctl.man b/lib/coverage-unixctl.man index 9718894..31935cc 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 counts +of all of the coverage counters. diff --git a/lib/coverage.c b/lib/coverage.c index 23e2997..153b6ac 100644 --- a/lib/coverage.c +++ b/lib/coverage.c @@ -63,7 +63,17 @@ struct coverage_counter *coverage_counters[] = { static struct ovs_mutex coverage_mutex = OVS_MUTEX_INITIALIZER; +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, @@ -206,6 +216,7 @@ coverage_log(void) static void coverage_read(struct svec *lines) { + struct coverage_counter **c = coverage_counters; unsigned long long int *totals; size_t n_never_hit; uint32_t hash; @@ -220,15 +231,24 @@ coverage_read(struct svec *lines) totals = xmalloc(n_coverage_counters * sizeof *totals); ovs_mutex_lock(&coverage_mutex); for (i = 0; i < n_coverage_counters; i++) { - totals[i] = coverage_counters[i]->total; + totals[i] = c[i]->total; } ovs_mutex_unlock(&coverage_mutex); for (i = 0; i < n_coverage_counters; i++) { if (totals[i]) { - svec_add_nocopy(lines, xasprintf("%-24s %9llu", - coverage_counters[i]->name, - totals[i])); + /* The per second rate is calculated via averaging the count in + * the most recent COVERAGE_RUN_INTERVAL interval. */ + svec_add_nocopy(lines, + xasprintf("%-24s %5.1f/sec %7u/min " + "%9u/hr total: %llu", + c[i]->name, + ((double) c[i]->min[(idx_count - 1) % MIN_AVG_LEN]) + * 1000 / COVERAGE_RUN_INTERVAL, + coverage_array_sum(c[i]->min, MIN_AVG_LEN), + coverage_array_sum(c[i]->hr, HR_AVG_LEN), + totals[i])); + } else { n_never_hit++; } @@ -249,3 +269,81 @@ coverage_clear(void) } ovs_mutex_unlock(&coverage_mutex); } + +/* Runs approximately every COVERAGE_RUN_INTERVAL amount of time to update the + * coverage counters' 'min' and 'hr' array. 'min' array is for cumulating + * per second counts into per minute count. 'hr' array is for cumulating per + * minute counts into per hour count. */ +void +coverage_run(void) +{ + struct coverage_counter **c = coverage_counters; + long long int now; + + /* Initialize the coverage_run_time. */ + if (coverage_run_time == LLONG_MIN) { + coverage_run_time = time_msec() + COVERAGE_RUN_INTERVAL; + } + + ovs_mutex_lock(&coverage_mutex); + now = time_msec(); + 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 < n_coverage_counters; i++) { + unsigned int count, portion; + unsigned int m_idx = min_idx; + unsigned int h_idx = hr_idx; + unsigned int idx = idx_count; + + /* Computes the differences between the current total and the one + * recorded in last invocation of coverage_run(). */ + count = c[i]->total - c[i]->last_total; + c[i]->last_total = c[i]->total; + /* The count over the time interval is evenly distributed + * among slots by calculating the portion. */ + portion = count / slots; + + for (j = 0; j < slots; j++) { + /* Updates the index variables. */ + /* The m_idx is increased from 0 to MIN_AVG_LEN - 1. Every + * time the m_idx finishes a cycle (a cycle is one minute), + * the h_idx is incremented by 1. */ + m_idx = idx % MIN_AVG_LEN; + h_idx = idx / MIN_AVG_LEN; + + c[i]->min[m_idx] = portion + (j == (slots - 1) + ? count % slots : 0); + c[i]->hr[h_idx] = m_idx == 0 ? c[i]->min[m_idx] + : (c[i]->hr[h_idx] + c[i]->min[m_idx]); + + /* This is to guarantee that h_idx ranges from 0 to 59. */ + idx = (idx + 1) % (MIN_AVG_LEN * HR_AVG_LEN); + } + } + + /* Updates the global index variables. */ + idx_count = (idx_count + slots) % (MIN_AVG_LEN * HR_AVG_LEN); + min_idx = idx_count % MIN_AVG_LEN; + hr_idx = idx_count / MIN_AVG_LEN; + /* Updates the run time. */ + coverage_run_time = now + COVERAGE_RUN_INTERVAL; + } + ovs_mutex_unlock(&coverage_mutex); +} + +static unsigned int +coverage_array_sum(const unsigned int *arr, const unsigned int len) +{ + unsigned int sum = 0; + size_t i; + + for (i = 0; i < len; i++) { + sum += arr[i]; + } + return sum; +} diff --git a/lib/coverage.h b/lib/coverage.h index 3d1a115..a01b2c1 100644 --- a/lib/coverage.h +++ b/lib/coverage.h @@ -30,11 +30,24 @@ #include "ovs-thread.h" #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 *const name; /* Textual name. */ unsigned int (*const count)(void); /* Gets, zeros this thread's count. */ unsigned long long int total; /* Total count. */ + unsigned long long int last_total; + /* 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 @@ -56,7 +69,7 @@ struct coverage_counter { } \ extern struct coverage_counter counter_##COUNTER; \ struct coverage_counter counter_##COUNTER \ - = { #COUNTER, COUNTER##_count, 0 }; \ + = { #COUNTER, COUNTER##_count, 0, 0, {0}, {0} }; \ extern struct coverage_counter *counter_ptr_##COUNTER; \ struct coverage_counter *counter_ptr_##COUNTER \ __attribute__((section("coverage"))) = &counter_##COUNTER @@ -80,6 +93,7 @@ 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) \ diff --git a/tests/ofproto-dpif.at b/tests/ofproto-dpif.at index 32e282d..e0aedaa 100644 --- a/tests/ofproto-dpif.at +++ b/tests/ofproto-dpif.at @@ -2770,3 +2770,37 @@ AT_CHECK([ovs-appctl bond/show | sed -n '/^.*may_enable:.*/p'], [0], [dnl 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. +# there should be two unixctl commands received, but the count of the "appctl +# coverage/show" command is not updated to the total. so there show only 1. +AT_CHECK([ovs-appctl coverage/show | sed -n '/^unixctl_received.*/p'], [], [dnl +unixctl_received 0.0/sec 0/min 0/hr total: 1 +]) + +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.4/sec 2/min 2/hr total: 3 +]) + +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 14/min 14/hr total: 15 +]) + +ovs-appctl time/warp 60000 +# advance to next 1 minute time instant directly, should observe the per-minute +# rate drop. +AT_CHECK([ovs-appctl coverage/show | sed -n '/^unixctl_received.*/p'], [], [dnl +unixctl_received 0.4/sec 2/min 16/hr total: 17 +]) + +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