greybus: loopback: Fix throughput calculations
authorAlexandre Bailon <abailon@baylibre.com>
Thu, 25 Feb 2016 17:19:15 +0000 (18:19 +0100)
committerGreg Kroah-Hartman <gregkh@google.com>
Fri, 26 Feb 2016 01:05:31 +0000 (17:05 -0800)
Throughput and requests per second calculations are broken for
asynchronous request.
Instead of calculate the throughput for each iteration,
calculate it once at the end of the test.
In addition, update every seconds the min and the max
for throughput and requests per second.

Signed-off-by: Alexandre Bailon <abailon@baylibre.com>
Reviewed-by: Johan Hovold <johan@hovoldconsulting.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
drivers/staging/greybus/loopback.c

index a1f878b..85d3e35 100644 (file)
@@ -81,6 +81,7 @@ struct gb_loopback {
        atomic_t outstanding_operations;
 
        /* Per connection stats */
+       struct timeval ts;
        struct gb_loopback_stats latency;
        struct gb_loopback_stats throughput;
        struct gb_loopback_stats requests_per_second;
@@ -351,7 +352,7 @@ static struct attribute *loopback_attrs[] = {
 };
 ATTRIBUTE_GROUPS(loopback);
 
-static void gb_loopback_calculate_stats(struct gb_loopback *gb);
+static void gb_loopback_calculate_stats(struct gb_loopback *gb, bool error);
 
 static u32 gb_loopback_nsec_to_usec_latency(u64 elapsed_nsecs)
 {
@@ -517,11 +518,9 @@ static void gb_loopback_async_operation_callback(struct gb_operation *operation)
        if (err) {
                gb->error++;
        } else {
-               gb->requests_completed++;
                gb_loopback_push_latency_ts(gb, &op_async->ts, &te);
                gb->elapsed_nsecs = gb_loopback_calc_latency(&op_async->ts,
                                                             &te);
-               gb_loopback_calculate_stats(gb);
        }
 
        if (op_async->pending) {
@@ -529,6 +528,7 @@ static void gb_loopback_async_operation_callback(struct gb_operation *operation)
                op_async->pending = false;
                del_timer_sync(&op_async->timer);
                gb_loopback_async_operation_put(op_async);
+               gb_loopback_calculate_stats(gb, err);
        }
        mutex_unlock(&gb->mutex);
 
@@ -555,6 +555,7 @@ static void gb_loopback_async_operation_work(struct work_struct *work)
                gb->iteration_count++;
                op_async->pending = false;
                gb_loopback_async_operation_put(op_async);
+               gb_loopback_calculate_stats(gb, true);
        }
        mutex_unlock(&gb->mutex);
 
@@ -847,6 +848,7 @@ static void gb_loopback_reset_stats(struct gb_loopback *gb)
        /* Should be initialized at least once per transaction set */
        gb->apbridge_latency_ts = 0;
        gb->gpbridge_latency_ts = 0;
+       memset(&gb->ts, 0, sizeof(struct timeval));
 }
 
 static void gb_loopback_update_stats(struct gb_loopback_stats *stats, u32 val)
@@ -859,18 +861,29 @@ static void gb_loopback_update_stats(struct gb_loopback_stats *stats, u32 val)
        stats->count++;
 }
 
+static void gb_loopback_update_stats_window(struct gb_loopback_stats *stats,
+                                           u64 val, u32 count)
+{
+       stats->sum += val;
+       stats->count += count;
+
+       do_div(val, count);
+       if (stats->min > val)
+               stats->min = val;
+       if (stats->max < val)
+               stats->max = val;
+}
+
 static void gb_loopback_requests_update(struct gb_loopback *gb, u32 latency)
 {
-       u32 req = USEC_PER_SEC;
+       u64 req = gb->requests_completed * USEC_PER_SEC;
 
-       do_div(req, latency);
-       gb_loopback_update_stats(&gb->requests_per_second, req);
+       gb_loopback_update_stats_window(&gb->requests_per_second, req, latency);
 }
 
 static void gb_loopback_throughput_update(struct gb_loopback *gb, u32 latency)
 {
-       u32 throughput;
-       u32 aggregate_size = sizeof(struct gb_operation_msg_hdr) * 2;
+       u64 aggregate_size = sizeof(struct gb_operation_msg_hdr) * 2;
 
        switch (gb->type) {
        case GB_LOOPBACK_TYPE_PING:
@@ -888,14 +901,13 @@ static void gb_loopback_throughput_update(struct gb_loopback *gb, u32 latency)
                return;
        }
 
-       /* Calculate bytes per second */
-       throughput = USEC_PER_SEC;
-       do_div(throughput, latency);
-       throughput *= aggregate_size;
-       gb_loopback_update_stats(&gb->throughput, throughput);
+       aggregate_size *= gb->requests_completed;
+       aggregate_size *= USEC_PER_SEC;
+       gb_loopback_update_stats_window(&gb->throughput, aggregate_size,
+                                       latency);
 }
 
-static void gb_loopback_calculate_stats(struct gb_loopback *gb)
+static void gb_loopback_calculate_latency_stats(struct gb_loopback *gb)
 {
        u32 lat;
 
@@ -908,10 +920,6 @@ static void gb_loopback_calculate_stats(struct gb_loopback *gb)
        /* Raw latency log on a per thread basis */
        kfifo_in(&gb->kfifo_lat, (unsigned char *)&lat, sizeof(lat));
 
-       /* Log throughput and requests using latency as benchmark */
-       gb_loopback_throughput_update(gb, lat);
-       gb_loopback_requests_update(gb, lat);
-
        /* Log the firmware supplied latency values */
        gb_loopback_update_stats(&gb->apbridge_unipro_latency,
                                 gb->apbridge_latency_ts);
@@ -919,6 +927,32 @@ static void gb_loopback_calculate_stats(struct gb_loopback *gb)
                                 gb->gpbridge_latency_ts);
 }
 
+static void gb_loopback_calculate_stats(struct gb_loopback *gb, bool error)
+{
+       u64 nlat;
+       u32 lat;
+       struct timeval te;
+
+       if (!error) {
+               gb->requests_completed++;
+               gb_loopback_calculate_latency_stats(gb);
+       }
+
+       do_gettimeofday(&te);
+       nlat = gb_loopback_calc_latency(&gb->ts, &te);
+       if (nlat >= NSEC_PER_SEC || gb->iteration_count == gb->iteration_max) {
+               lat = gb_loopback_nsec_to_usec_latency(nlat);
+
+               gb_loopback_throughput_update(gb, lat);
+               gb_loopback_requests_update(gb, lat);
+
+               if (gb->iteration_count != gb->iteration_max) {
+                       gb->ts = te;
+                       gb->requests_completed = 0;
+               }
+       }
+}
+
 static void gb_loopback_async_wait_to_send(struct gb_loopback *gb)
 {
        if (!(gb->async && gb->outstanding_operations_max))
@@ -956,14 +990,18 @@ static int gb_loopback_fn(void *data)
 
                /* Optionally terminate */
                if (send_count == gb->iteration_max) {
-                       gb->type = 0;
-                       send_count = 0;
+                       if (gb->iteration_count == gb->iteration_max) {
+                               gb->type = 0;
+                               send_count = 0;
+                       }
                        mutex_unlock(&gb->mutex);
                        continue;
                }
                size = gb->size;
                us_wait = gb->us_wait;
                type = gb->type;
+               if (gb->ts.tv_usec == 0 && gb->ts.tv_sec == 0)
+                       do_gettimeofday(&gb->ts);
                mutex_unlock(&gb->mutex);
 
                /* Else operations to perform */
@@ -989,9 +1027,8 @@ static int gb_loopback_fn(void *data)
 
                        if (error)
                                gb->error++;
-                       else
-                               gb_loopback_calculate_stats(gb);
                        gb->iteration_count++;
+                       gb_loopback_calculate_stats(gb, !!error);
                }
                send_count++;
                if (us_wait)