summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/staging/greybus/loopback.c81
1 files changed, 59 insertions, 22 deletions
diff --git a/drivers/staging/greybus/loopback.c b/drivers/staging/greybus/loopback.c
index a1f878b24e74..85d3e35e6a5f 100644
--- a/drivers/staging/greybus/loopback.c
+++ b/drivers/staging/greybus/loopback.c
@@ -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)