]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
common: calculate stddev on the fly 21461/head
authorYao Zongyou <yaozongyou@vip.qq.com>
Tue, 17 Apr 2018 08:41:08 +0000 (16:41 +0800)
committerYao Zongyou <yaozongyou@vip.qq.com>
Tue, 17 Apr 2018 08:41:08 +0000 (16:41 +0800)
Calculate stddev on the fly using rapid calculation methods:
https://en.wikipedia.org/wiki/Standard_deviation#Rapid_calculation_methods
no need to keep bench history.

Signed-off-by: Yao Zongyou <yaozongyou@vip.qq.com>
src/common/obj_bencher.cc
src/common/obj_bencher.h

index 9a7547b01be802d1a8c49ebfc4f158a10754b1e9..bf817e439e08d818dd6747de0d054987f5406f05 100644 (file)
@@ -122,7 +122,10 @@ void *ObjBencher::status_printer(void *_bencher) {
       if (bandwidth < data.idata.min_bandwidth)
         data.idata.min_bandwidth = bandwidth;
 
-      data.history.bandwidth.push_back(bandwidth);
+      ++data.idata.bandwidth_cycles;
+      double delta = bandwidth - data.idata.avg_bandwidth;
+      data.idata.avg_bandwidth += delta / data.idata.bandwidth_cycles;
+      data.idata.bandwidth_diff_sum += delta * (bandwidth - data.idata.avg_bandwidth);
     }
 
     if (cycleSinceChange)
@@ -137,7 +140,10 @@ void *ObjBencher::status_printer(void *_bencher) {
       if (iops < data.idata.min_iops)
         data.idata.min_iops = iops;
 
-      data.history.iops.push_back(iops);
+      ++data.idata.iops_cycles;
+      double delta = iops - data.idata.avg_iops;
+      data.idata.avg_iops += delta / data.idata.iops_cycles;
+      data.idata.iops_diff_sum += delta * (iops - data.idata.avg_iops);
     }
     
     if (formatter)
@@ -258,6 +264,7 @@ int ObjBencher::aio_bench(
   data.min_latency = 9999.0; // this better be higher than initial latency!
   data.max_latency = 0;
   data.avg_latency = 0;
+  data.latency_diff_sum = 0;
   data.object_contents = contentsChars;
   lock.Unlock();
 
@@ -326,31 +333,6 @@ void _aio_cb(void *cb, void *arg) {
   lc->lock->Unlock();
 }
 
-template<class T>
-static T vec_stddev(vector<T>& v)
-{
-  T mean = 0;
-
-  if (v.size() < 2)
-    return 0;
-
-  typename vector<T>::iterator iter;
-  for (iter = v.begin(); iter != v.end(); ++iter) {
-    mean += *iter;
-  }
-
-  mean /= v.size();
-
-  T stddev = 0;
-  for (iter = v.begin(); iter != v.end(); ++iter) {
-    T dev = *iter - mean;
-    dev *= dev;
-    stddev += dev;
-  }
-  stddev /= (v.size() - 1);
-  return sqrt(stddev);
-}
-
 int ObjBencher::fetch_bench_metadata(const std::string& metadata_file,
                                     uint64_t *op_size, uint64_t* object_size,
                                     int* num_objects, int* prevPid) {
@@ -499,14 +481,15 @@ int ObjBencher::write_bench(int secondsToRun,
       goto ERR;
     }
     data.cur_latency = mono_clock::now() - start_times[slot];
-    data.history.latency.push_back(data.cur_latency.count());
     total_latency += data.cur_latency.count();
     if( data.cur_latency.count() > data.max_latency)
       data.max_latency = data.cur_latency.count();
     if (data.cur_latency.count() < data.min_latency)
       data.min_latency = data.cur_latency.count();
     ++data.finished;
+    double delta = data.cur_latency.count() - data.avg_latency;
     data.avg_latency = total_latency / data.finished;
+    data.latency_diff_sum += delta * (data.cur_latency.count() - data.avg_latency);
     --data.in_flight;
     lock.Unlock();
     release_completion(slot);
@@ -544,14 +527,15 @@ int ObjBencher::write_bench(int secondsToRun,
       goto ERR;
     }
     data.cur_latency = mono_clock::now() - start_times[slot];
-    data.history.latency.push_back(data.cur_latency.count());
     total_latency += data.cur_latency.count();
     if (data.cur_latency.count() > data.max_latency)
       data.max_latency = data.cur_latency.count();
     if (data.cur_latency.count() < data.min_latency)
       data.min_latency = data.cur_latency.count();
     ++data.finished;
+    double delta = data.cur_latency.count() - data.avg_latency;
     data.avg_latency = total_latency / data.finished;
+    data.latency_diff_sum += delta * (data.cur_latency.count() - data.avg_latency);
     --data.in_flight;
     lock.Unlock();
     release_completion(slot);
@@ -571,21 +555,40 @@ int ObjBencher::write_bench(int secondsToRun,
        timePassed.count();
   bandwidth = bandwidth/(1024*1024); // we want it in MB/sec
 
+  double bandwidth_stddev;
+  double iops_stddev;
+  double latency_stddev;
+  if (data.idata.bandwidth_cycles > 1) {
+    bandwidth_stddev = std::sqrt(data.idata.bandwidth_diff_sum / (data.idata.bandwidth_cycles - 1));
+  } else {
+    bandwidth_stddev = 0;
+  }
+  if (data.idata.iops_cycles > 1) {
+    iops_stddev = std::sqrt(data.idata.iops_diff_sum / (data.idata.iops_cycles - 1));
+  } else {
+    iops_stddev = 0;
+  }
+  if (data.finished > 1) {
+    latency_stddev = std::sqrt(data.latency_diff_sum / (data.finished - 1));
+  } else {
+    latency_stddev = 0;
+  }
+
   if (!formatter) {
     out(cout) << "Total time run:         " << timePassed.count() << std::endl
        << "Total writes made:      " << data.finished << std::endl
        << "Write size:             " << data.op_size << std::endl
        << "Object size:            " << data.object_size << std::endl      
        << "Bandwidth (MB/sec):     " << setprecision(6) << bandwidth << std::endl
-       << "Stddev Bandwidth:       " << vec_stddev(data.history.bandwidth) << std::endl
+       << "Stddev Bandwidth:       " << bandwidth_stddev << std::endl
        << "Max bandwidth (MB/sec): " << data.idata.max_bandwidth << std::endl
        << "Min bandwidth (MB/sec): " << data.idata.min_bandwidth << std::endl
        << "Average IOPS:           " << (int)(data.finished/timePassed.count()) << std::endl
-       << "Stddev IOPS:            " << vec_stddev(data.history.iops) << std::endl
+       << "Stddev IOPS:            " << iops_stddev << std::endl
        << "Max IOPS:               " << data.idata.max_iops << std::endl
        << "Min IOPS:               " << data.idata.min_iops << std::endl
        << "Average Latency(s):     " << data.avg_latency << std::endl
-       << "Stddev Latency(s):      " << vec_stddev(data.history.latency) << std::endl
+       << "Stddev Latency(s):      " << latency_stddev << std::endl
        << "Max latency(s):         " << data.max_latency << std::endl
        << "Min latency(s):         " << data.min_latency << std::endl;
   } else {
@@ -594,15 +597,15 @@ int ObjBencher::write_bench(int secondsToRun,
     formatter->dump_format("write_size", "%d", data.op_size);
     formatter->dump_format("object_size", "%d", data.object_size);
     formatter->dump_format("bandwidth", "%f", bandwidth);
-    formatter->dump_format("stddev_bandwidth", "%f", vec_stddev(data.history.bandwidth));
+    formatter->dump_format("stddev_bandwidth", "%f", bandwidth_stddev);
     formatter->dump_format("max_bandwidth", "%f", data.idata.max_bandwidth);
     formatter->dump_format("min_bandwidth", "%f", data.idata.min_bandwidth);
     formatter->dump_format("average_iops", "%d", (int)(data.finished/timePassed.count()));
-    formatter->dump_format("stddev_iops", "%d", vec_stddev(data.history.iops));
+    formatter->dump_format("stddev_iops", "%d", iops_stddev);
     formatter->dump_format("max_iops", "%d", data.idata.max_iops);
     formatter->dump_format("min_iops", "%d", data.idata.min_iops);
     formatter->dump_format("average_latency", "%f", data.avg_latency);
-    formatter->dump_format("stddev_latency", "%f", vec_stddev(data.history.latency));
+    formatter->dump_format("stddev_latency", "%f", latency_stddev);
     formatter->dump_format("max_latency:", "%f", data.max_latency);
     formatter->dump_format("min_latency", "%f", data.min_latency);
   }
@@ -821,6 +824,13 @@ int ObjBencher::seq_read_bench(int seconds_to_run, int num_objects, int concurre
   double bandwidth;
   bandwidth = ((double)data.finished)*((double)data.op_size)/timePassed.count();
   bandwidth = bandwidth/(1024*1024); // we want it in MB/sec
+  
+  double iops_stddev;
+  if (data.idata.iops_cycles > 1) {
+    iops_stddev = std::sqrt(data.idata.iops_diff_sum / (data.idata.iops_cycles - 1));
+  } else {
+    iops_stddev = 0;
+  }
 
   if (!formatter) {
     out(cout) << "Total time run:       " << timePassed.count() << std::endl
@@ -829,7 +839,7 @@ int ObjBencher::seq_read_bench(int seconds_to_run, int num_objects, int concurre
        << "Object size:          " << data.object_size << std::endl
        << "Bandwidth (MB/sec):   " << setprecision(6) << bandwidth << std::endl
        << "Average IOPS:         " << (int)(data.finished/timePassed.count()) << std::endl
-       << "Stddev IOPS:          " << vec_stddev(data.history.iops) << std::endl
+       << "Stddev IOPS:          " << iops_stddev << std::endl
        << "Max IOPS:             " << data.idata.max_iops << std::endl
        << "Min IOPS:             " << data.idata.min_iops << std::endl
        << "Average Latency(s):   " << data.avg_latency << std::endl
@@ -842,7 +852,7 @@ int ObjBencher::seq_read_bench(int seconds_to_run, int num_objects, int concurre
     formatter->dump_format("object_size", "%d", data.object_size);
     formatter->dump_format("bandwidth", "%f", bandwidth);
     formatter->dump_format("average_iops", "%d", (int)(data.finished/timePassed.count()));
-    formatter->dump_format("stddev_iops", "%d", vec_stddev(data.history.iops));
+    formatter->dump_format("stddev_iops", "%f", iops_stddev);
     formatter->dump_format("max_iops", "%d", data.idata.max_iops);
     formatter->dump_format("min_iops", "%d", data.idata.min_iops);
     formatter->dump_format("average_latency", "%f", data.avg_latency);
@@ -1056,6 +1066,13 @@ int ObjBencher::rand_read_bench(int seconds_to_run, int num_objects, int concurr
   double bandwidth;
   bandwidth = ((double)data.finished)*((double)data.op_size)/timePassed.count();
   bandwidth = bandwidth/(1024*1024); // we want it in MB/sec
+  
+  double iops_stddev;
+  if (data.idata.iops_cycles > 1) {
+    iops_stddev = std::sqrt(data.idata.iops_diff_sum / (data.idata.iops_cycles - 1));
+  } else {
+    iops_stddev = 0;
+  }
 
   if (!formatter) {
     out(cout) << "Total time run:       " << timePassed.count() << std::endl
@@ -1064,7 +1081,7 @@ int ObjBencher::rand_read_bench(int seconds_to_run, int num_objects, int concurr
        << "Object size:          " << data.object_size << std::endl
        << "Bandwidth (MB/sec):   " << setprecision(6) << bandwidth << std::endl
        << "Average IOPS:         " << (int)(data.finished/timePassed.count()) << std::endl
-       << "Stddev IOPS:          " << vec_stddev(data.history.iops) << std::endl
+       << "Stddev IOPS:          " << iops_stddev << std::endl
        << "Max IOPS:             " << data.idata.max_iops << std::endl
        << "Min IOPS:             " << data.idata.min_iops << std::endl
        << "Average Latency(s):   " << data.avg_latency << std::endl
@@ -1077,7 +1094,7 @@ int ObjBencher::rand_read_bench(int seconds_to_run, int num_objects, int concurr
     formatter->dump_format("object_size", "%d", data.object_size);
     formatter->dump_format("bandwidth", "%f", bandwidth);
     formatter->dump_format("average_iops", "%d", (int)(data.finished/timePassed.count()));
-    formatter->dump_format("stddev_iops", "%d", vec_stddev(data.history.iops));
+    formatter->dump_format("stddev_iops", "%f", iops_stddev);
     formatter->dump_format("max_iops", "%d", data.idata.max_iops);
     formatter->dump_format("min_iops", "%d", data.idata.min_iops);
     formatter->dump_format("average_latency", "%f", data.avg_latency);
index 7f8363cab11bd1d6f19e17a4ca6dcc70d9e69a58..e1ddc832c31e40ffc3064abd668fa2c56ebb6700 100644 (file)
@@ -25,14 +25,14 @@ using ceph::mono_clock;
 struct bench_interval_data {
   double min_bandwidth = DBL_MAX;
   double max_bandwidth = 0;
+  double avg_bandwidth = 0;
+  int bandwidth_cycles = 0;
+  double bandwidth_diff_sum = 0;
   int min_iops = INT_MAX;
   int max_iops = 0;
-};
-
-struct bench_history {
-  vector<double> bandwidth;
-  vector<double> latency;
-  vector<long> iops;
+  double avg_iops = 0;
+  int iops_cycles = 0;
+  double iops_diff_sum = 0;
 };
 
 struct bench_data {
@@ -48,7 +48,7 @@ struct bench_data {
   double max_latency;
   double avg_latency;
   struct bench_interval_data idata; // data that is updated by time intervals and not by events
-  struct bench_history history; // data history, used to calculate stddev
+  double latency_diff_sum;
   std::chrono::duration<double> cur_latency; //latency of last completed transaction - in seconds by default
   mono_time start_time; //start time for benchmark - use the monotonic clock as we'll measure the passage of time
   char *object_contents; //pointer to the contents written to each object