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)