From: Yao Zongyou Date: Tue, 17 Apr 2018 08:41:08 +0000 (+0800) Subject: common: calculate stddev on the fly X-Git-Tag: v14.0.0~219^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=65902ac409e6974885f4019fc4a1b657747d6aba;p=ceph.git common: calculate stddev on the fly 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 --- diff --git a/src/common/obj_bencher.cc b/src/common/obj_bencher.cc index 9a7547b01be8..bf817e439e08 100644 --- a/src/common/obj_bencher.cc +++ b/src/common/obj_bencher.cc @@ -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 -static T vec_stddev(vector& v) -{ - T mean = 0; - - if (v.size() < 2) - return 0; - - typename vector::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); diff --git a/src/common/obj_bencher.h b/src/common/obj_bencher.h index 7f8363cab11b..e1ddc832c31e 100644 --- a/src/common/obj_bencher.h +++ b/src/common/obj_bencher.h @@ -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 bandwidth; - vector latency; - vector 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 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