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;
 };
 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)
 {
        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) {
                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);
 
                gb->iteration_count++;
                op_async->pending = false;
                gb_loopback_async_operation_put(op_async);
+               gb_loopback_calculate_stats(gb, true);
        }
        mutex_unlock(&gb->mutex);
 
        /* 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)
        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:
                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;
 
        /* 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);
                                 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))
 
                /* 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 */
 
                        if (error)
                                gb->error++;
-                       else
-                               gb_loopback_calculate_stats(gb);
                        gb->iteration_count++;
+                       gb_loopback_calculate_stats(gb, !!error);
                }
                send_count++;
                if (us_wait)