From 00af6583d15038cfaa81a99632122b67d49de403 Mon Sep 17 00:00:00 2001 From: Bryan O'Donoghue Date: Tue, 21 Jul 2015 23:50:08 +0100 Subject: [PATCH] greybus: loopback: run operations a set number of times In order to extract a meaningful set of data out of loopback metrics it makes sense to have the ability to specify how many times a loopback operation should run and then to stop when the threshold is hit. This will allow exactly the same loopback data pattern to be run again and again, which is a fundamental prerequisite to instrumenting and characterizing the loopback interface over time. This patch introduces a simple sysfs controlled variable iteration_max. iteration_max is the maximum number of iterations to run for a given set. iteration_count is used internally to count from zero to iteration_max if-and-only-if iteration_max is non zero. If iteration_max is zero then the original behaviour of running the test command ad infinitum is maintained. User-space should incrementally poll the iteration_count to determine when the sequence is finished. To accomplish this we move away from running as many commands as possible in a one second window and instead run a fixed number of commands and log the time it takes for those commands to complete in aggregate. Since we are no longer resetting counters every one second, the tracker variables have been moved from u32 to u64 to allow for reasonably long tests to gather reasonably large amounts of data, without fear of over-flowing the data-points. Signed-off-by: Bryan O'Donoghue Signed-off-by: Greg Kroah-Hartman --- drivers/staging/greybus/loopback.c | 108 ++++++++++++++++++++----------------- 1 file changed, 58 insertions(+), 50 deletions(-) diff --git a/drivers/staging/greybus/loopback.c b/drivers/staging/greybus/loopback.c index 66385c9..6597394 100644 --- a/drivers/staging/greybus/loopback.c +++ b/drivers/staging/greybus/loopback.c @@ -18,11 +18,11 @@ #include "greybus.h" struct gb_loopback_stats { - u32 min; - u32 max; - u32 avg; - u32 sum; - u32 count; + u64 min; + u64 max; + u64 avg; + u64 sum; + u64 count; }; struct gb_loopback { @@ -34,6 +34,8 @@ struct gb_loopback { int type; u32 size; + u32 iteration_max; + u32 iteration_count; size_t size_max; int ms_wait; @@ -77,9 +79,9 @@ static ssize_t name##_##field##_show(struct device *dev, \ static DEVICE_ATTR_RO(name##_##field) #define gb_loopback_stats_attrs(field) \ - gb_loopback_ro_stats_attr(field, min, d); \ - gb_loopback_ro_stats_attr(field, max, d); \ - gb_loopback_ro_stats_attr(field, avg, d); + gb_loopback_ro_stats_attr(field, min, llu); \ + gb_loopback_ro_stats_attr(field, max, llu); \ + gb_loopback_ro_stats_attr(field, avg, llu); #define gb_loopback_attr(field, type) \ static ssize_t field##_show(struct device *dev, \ @@ -125,6 +127,7 @@ static void gb_loopback_check_attr(struct gb_loopback *gb) if (gb->size > gb->size_max) gb->size = gb->size_max; gb->error = 0; + gb->iteration_count = 0; gb_loopback_reset_stats(gb); } @@ -135,6 +138,7 @@ gb_loopback_stats_attrs(frequency); /* Quantity of data sent and received on this cport */ gb_loopback_stats_attrs(throughput); gb_loopback_ro_attr(error, d); +gb_loopback_ro_attr(iteration_count, u); /* * Type of loopback message to send based on protocol type definitions @@ -149,6 +153,8 @@ gb_loopback_attr(type, d); gb_loopback_attr(size, u); /* Time to wait between two messages: 0-1000 ms */ gb_loopback_attr(ms_wait, d); +/* Maximum iterations for a given operation: 1-(2^32-1), 0 implies infinite */ +gb_loopback_attr(iteration_max, u); #define dev_stats_attrs(name) \ &dev_attr_##name##_min.attr, \ @@ -162,6 +168,8 @@ static struct attribute *loopback_attrs[] = { &dev_attr_type.attr, &dev_attr_size.attr, &dev_attr_ms_wait.attr, + &dev_attr_iteration_count.attr, + &dev_attr_iteration_max.attr, &dev_attr_error.attr, NULL, }; @@ -313,38 +321,29 @@ static void gb_loopback_reset_stats(struct gb_loopback *gb) memset(&gb->ts, 0, sizeof(struct timeval)); } -static void gb_loopback_update_stats(struct gb_loopback_stats *stats, - u64 elapsed_nsecs) +static void gb_loopback_update_stats(struct gb_loopback_stats *stats, u64 val) { - u32 avg; - u64 tmp; - - if (elapsed_nsecs >= NSEC_PER_SEC) { - if (!stats->count) { - tmp = elapsed_nsecs; - do_div(tmp, NSEC_PER_SEC); - avg = stats->sum * tmp; - } else { - avg = stats->sum / stats->count; - } - if (stats->min > avg) - stats->min = avg; - if (stats->max < avg) - stats->max = avg; - stats->avg = avg; - stats->count = 0; - stats->sum = 0; - } + if (stats->min > val) + stats->min = val; + if (stats->max < val) + stats->max = val; + stats->sum += val; + stats->count++; + stats->avg = stats->sum; + do_div(stats->avg, stats->count); } -static void gb_loopback_freq_update(struct gb_loopback *gb) +static void gb_loopback_frequency_update(struct gb_loopback *gb, u32 latency) { - gb->frequency.sum++; - gb_loopback_update_stats(&gb->frequency, gb->elapsed_nsecs); + u32 freq = USEC_PER_SEC; + + do_div(freq, latency); + gb_loopback_update_stats(&gb->frequency, freq); } -static void gb_loopback_throughput_update(struct gb_loopback *gb) +static void gb_loopback_throughput_update(struct gb_loopback *gb, u32 latency) { + u32 throughput; u32 aggregate_size = sizeof(struct gb_operation_msg_hdr) * 2; switch (gb->type) { @@ -362,27 +361,31 @@ static void gb_loopback_throughput_update(struct gb_loopback *gb) default: return; } - gb->throughput.sum += aggregate_size; - gb_loopback_update_stats(&gb->throughput, gb->elapsed_nsecs); + + /* Calculate bytes per second */ + throughput = USEC_PER_SEC; + do_div(throughput, latency); + throughput *= aggregate_size; + gb_loopback_update_stats(&gb->throughput, throughput); } -static void gb_loopback_latency_update(struct gb_loopback *gb, +static void gb_loopback_calculate_stats(struct gb_loopback *gb, struct timeval *tlat) { u32 lat; u64 tmp; - tmp = timeval_to_ns(tlat); - do_div(tmp, NSEC_PER_MSEC); + /* Express latency in terms of microseconds */ + tmp = gb->elapsed_nsecs; + do_div(tmp, NSEC_PER_USEC); lat = tmp; - if (gb->latency.min > lat) - gb->latency.min = lat; - if (gb->latency.max < lat) - gb->latency.max = lat; - gb->latency.sum += lat; - gb->latency.count++; - gb_loopback_update_stats(&gb->latency, gb->elapsed_nsecs); + /* Log latency stastic */ + gb_loopback_update_stats(&gb->latency, lat); + + /* Log throughput and frequency using latency as benchmark */ + gb_loopback_throughput_update(gb, lat); + gb_loopback_frequency_update(gb, lat); } static int gb_loopback_fn(void *data) @@ -396,6 +399,14 @@ static int gb_loopback_fn(void *data) msleep(1000); continue; } + if (gb->iteration_max) { + if (gb->iteration_count < gb->iteration_max) { + gb->iteration_count++; + } else { + gb->type = 0; + continue; + } + } if (gb->ts.tv_usec == 0 && gb->ts.tv_sec == 0) do_gettimeofday(&gb->ts); if (gb->type == GB_LOOPBACK_TYPE_PING) @@ -409,11 +420,8 @@ static int gb_loopback_fn(void *data) do_gettimeofday(&gb->te); gb->elapsed_nsecs = timeval_to_ns(&gb->te) - timeval_to_ns(&gb->ts); - gb_loopback_freq_update(gb); - gb_loopback_throughput_update(gb); - gb_loopback_latency_update(gb, &tlat); - if (gb->elapsed_nsecs >= NSEC_PER_SEC) - gb->ts = gb->te; + gb_loopback_calculate_stats(gb, &tlat); + gb->ts = gb->te; if (gb->ms_wait) msleep(gb->ms_wait); -- 2.7.4