From: tianshan Date: Mon, 31 Aug 2015 10:37:42 +0000 (+0800) Subject: rados: make 'rados bench' support json format output X-Git-Tag: v9.1.0~178^2~1^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=08296dc0febc4ee3b1c5f860d8744bd04e9c2ff8;p=ceph.git rados: make 'rados bench' support json format output Fixes: #12864 rados bench add '[--format json]' and '[-o | --output outfile]' support. output option only take effect in json format. now we can use the bench result draw performance graph easily. Signed-off-by: Tianshan Qu --- diff --git a/src/common/obj_bencher.cc b/src/common/obj_bencher.cc index baaff266c9ae..3772eb865781 100644 --- a/src/common/obj_bencher.cc +++ b/src/common/obj_bencher.cc @@ -73,6 +73,8 @@ ostream& ObjBencher::out(ostream& os) void *ObjBencher::status_printer(void *_bencher) { ObjBencher *bencher = static_cast(_bencher); bench_data& data = bencher->data; + Formatter *formatter = bencher->formatter; + ostream *outstream = bencher->outstream; Cond cond; int i = 0; int previous_writes = 0; @@ -82,10 +84,12 @@ void *ObjBencher::status_printer(void *_bencher) { utime_t ONE_SECOND; ONE_SECOND.set_from_double(1.0); bencher->lock.Lock(); + if (formatter) + formatter->open_array_section("datas"); while(!data.done) { utime_t cur_time = ceph_clock_now(bencher->cct); - if (i % 20 == 0) { + if (i % 20 == 0 && !formatter) { if (i > 0) cur_time.localtime(cout) << " min lat: " << data.min_latency << " max lat: " << data.max_latency @@ -132,13 +136,17 @@ void *ObjBencher::status_printer(void *_bencher) { data.history.iops.push_back(iops); } + + if (formatter) + formatter->open_object_section("data"); double avg_bandwidth = (double) (data.object_size) * (data.finished) / (double)(cur_time - data.start_time) / (1024*1024); if (previous_writes != data.finished) { previous_writes = data.finished; cycleSinceChange = 0; - bencher->out(cout, cur_time) << setfill(' ') + if (!formatter) { + bencher->out(cout, cur_time) << setfill(' ') << setw(5) << i << setw(8) << data.in_flight << setw(10) << data.started @@ -147,9 +155,20 @@ void *ObjBencher::status_printer(void *_bencher) { << setw(10) << bandwidth << setw(10) << (double)data.cur_latency << setw(10) << data.avg_latency << std::endl; + } else { + formatter->dump_format("sec", "%d", i); + formatter->dump_format("cur_ops", "%d", data.in_flight); + formatter->dump_format("started", "%d", data.started); + formatter->dump_format("finished", "%d", data.finished); + formatter->dump_format("avg_bw", "%f", avg_bandwidth); + formatter->dump_format("cur_bw", "%f", bandwidth); + formatter->dump_format("last_lat", "%f", (double)data.cur_latency); + formatter->dump_format("avg_lat", "%f", data.avg_latency); + } } else { - bencher->out(cout, cur_time) << setfill(' ') + if (!formatter) { + bencher->out(cout, cur_time) << setfill(' ') << setw(5) << i << setw(8) << data.in_flight << setw(10) << data.started @@ -158,11 +177,27 @@ void *ObjBencher::status_printer(void *_bencher) { << setw(10) << '0' << setw(10) << '-' << setw(10) << data.avg_latency << std::endl; + } else { + formatter->dump_format("sec", "%d", i); + formatter->dump_format("cur_ops", "%d", data.in_flight); + formatter->dump_format("started", "%d", data.started); + formatter->dump_format("finished", "%d", data.finished); + formatter->dump_format("avg_bw", "%f", avg_bandwidth); + formatter->dump_format("cur_bw", "%f", 0); + formatter->dump_format("last_lat", "%f", 0); + formatter->dump_format("avg_lat", "%f", data.avg_latency); + } + } + if (formatter) { + formatter->close_section(); // data + formatter->flush(*outstream); } ++i; ++cycleSinceChange; cond.WaitInterval(bencher->cct, bencher->lock, ONE_SECOND); } + if (formatter) + formatter->close_section(); //datas bencher->lock.Unlock(); return NULL; } @@ -207,6 +242,9 @@ int ObjBencher::aio_bench( //fill in contentsChars deterministically so we can check returns sanitize_object_contents(&data, data.object_size); + if (formatter) + formatter->open_object_section("bench"); + if (OP_WRITE == operation) { r = write_bench(secondsToRun, concurrentios, run_name_meta); if (r != 0) goto out; @@ -237,6 +275,11 @@ int ObjBencher::aio_bench( } out: + if (formatter) { + formatter->close_section(); // bench + formatter->flush(*outstream); + *outstream << std::endl; + } delete[] contentsChars; return r; } @@ -303,15 +346,24 @@ int ObjBencher::write_bench(int secondsToRun, int concurrentios, const string& run_name_meta) { if (concurrentios <= 0) return -EINVAL; - - out(cout) << "Maintaining " << concurrentios << " concurrent writes of " - << data.object_size << " bytes for up to " - << secondsToRun << " seconds" - << std::endl; + + if (!formatter) { + out(cout) << "Maintaining " << concurrentios << " concurrent writes of " + << data.object_size << " bytes for up to " + << secondsToRun << " seconds" + << std::endl; + } else { + formatter->dump_format("concurrent_ios", "%d", concurrentios); + formatter->dump_format("object_size", "%d", data.object_size); + formatter->dump_format("seconds_to_run", "%d", secondsToRun); + } bufferlist* newContents = 0; std::string prefix = generate_object_prefix(); - out(cout) << "Object prefix: " << prefix << std::endl; + if (!formatter) + out(cout) << "Object prefix: " << prefix << std::endl; + else + formatter->dump_string("object_prefix", prefix); std::vector name(concurrentios); std::string newName; @@ -461,7 +513,8 @@ int ObjBencher::write_bench(int secondsToRun, bandwidth = ((double)data.finished)*((double)data.object_size)/(double)timePassed; bandwidth = bandwidth/(1024*1024); // we want it in MB/sec - out(cout) << "Total time run: " << timePassed << std::endl + if (!formatter) { + out(cout) << "Total time run: " << timePassed << std::endl << "Total writes made: " << data.finished << std::endl << "Write size: " << data.object_size << std::endl << "Bandwidth (MB/sec): " << setprecision(3) << bandwidth << std::endl @@ -476,7 +529,23 @@ int ObjBencher::write_bench(int secondsToRun, << "Stddev Latency: " << vec_stddev(data.history.latency) << std::endl << "Max latency: " << data.max_latency << std::endl << "Min latency: " << data.min_latency << std::endl; - + } else { + formatter->dump_format("total_time_run", "%f", (double)timePassed); + formatter->dump_format("total_writes_made", "%d", data.finished); + formatter->dump_format("write_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("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)); + formatter->dump_format("stddev_iops", "%d", vec_stddev(data.history.iops)); + 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("max_latency:", "%f", data.max_latency); + formatter->dump_format("min_latency", "%f", data.min_latency); + } //write object size/number data for read benchmarks ::encode(data.object_size, b_write); ::encode(data.finished, b_write); @@ -680,7 +749,8 @@ int ObjBencher::seq_read_bench(int seconds_to_run, int num_objects, int concurre bandwidth = ((double)data.finished)*((double)data.object_size)/(double)runtime; bandwidth = bandwidth/(1024*1024); // we want it in MB/sec - out(cout) << "Total time run: " << runtime << std::endl + if (!formatter) { + out(cout) << "Total time run: " << runtime << std::endl << "Total reads made: " << data.finished << std::endl << "Read size: " << data.object_size << std::endl << "Bandwidth (MB/sec): " << setprecision(3) << bandwidth << std::endl @@ -691,6 +761,19 @@ int ObjBencher::seq_read_bench(int seconds_to_run, int num_objects, int concurre << "Average Latency: " << data.avg_latency << std::endl << "Max latency: " << data.max_latency << std::endl << "Min latency: " << data.min_latency << std::endl; + } else { + formatter->dump_format("total_time_run", "%f", (double)runtime); + formatter->dump_format("total_reads_made", "%d", data.finished); + formatter->dump_format("read_size", "%d", data.object_size); + formatter->dump_format("bandwidth", "%f", bandwidth); + formatter->dump_format("average_iops", "%d", (int)(data.finished/runtime)); + formatter->dump_format("stddev_iops", "%d", vec_stddev(data.history.iops)); + 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("max_latency", "%f", data.max_latency); + formatter->dump_format("min_latency", "%f", data.min_latency); + } completions_done(); @@ -888,7 +971,8 @@ int ObjBencher::rand_read_bench(int seconds_to_run, int num_objects, int concurr bandwidth = ((double)data.finished)*((double)data.object_size)/(double)runtime; bandwidth = bandwidth/(1024*1024); // we want it in MB/sec - out(cout) << "Total time run: " << runtime << std::endl + if (!formatter) { + out(cout) << "Total time run: " << runtime << std::endl << "Total reads made: " << data.finished << std::endl << "Read size: " << data.object_size << std::endl << "Bandwidth (MB/sec): " << setprecision(3) << bandwidth << std::endl @@ -899,7 +983,19 @@ int ObjBencher::rand_read_bench(int seconds_to_run, int num_objects, int concurr << "Average Latency: " << data.avg_latency << std::endl << "Max latency: " << data.max_latency << std::endl << "Min latency: " << data.min_latency << std::endl; - + } else { + formatter->dump_format("total_time_run", "%f", (double)runtime); + formatter->dump_format("total_reads_made", "%d", data.finished); + formatter->dump_format("read_size", "%d", data.object_size); + formatter->dump_format("bandwidth", "%f", bandwidth); + formatter->dump_format("average_iops", "%d", (int)(data.finished/runtime)); + formatter->dump_format("stddev_iops", "%d", vec_stddev(data.history.iops)); + 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("max_latency", "%f", data.max_latency); + formatter->dump_format("min_latency", "%f", data.min_latency); + } completions_done(); return 0; diff --git a/src/common/obj_bencher.h b/src/common/obj_bencher.h index 9d40ccb0e180..34e22c2b599a 100644 --- a/src/common/obj_bencher.h +++ b/src/common/obj_bencher.h @@ -18,6 +18,7 @@ #include "common/config.h" #include "common/Cond.h" #include "common/ceph_context.h" +#include "common/Formatter.h" #include struct bench_interval_data { @@ -59,6 +60,8 @@ typedef std::pair Object; class ObjBencher { bool show_time; + Formatter *formatter = NULL; + ostream *outstream = NULL; public: CephContext *cct; protected: @@ -110,6 +113,12 @@ public: void set_show_time(bool dt) { show_time = dt; } + void set_formatter(Formatter *f) { + formatter = f; + } + void set_outstream(ostream& os) { + outstream = &os; + } int clean_up_slow(const std::string& prefix, int concurrentios); }; diff --git a/src/test/test_rados_tool.sh b/src/test/test_rados_tool.sh index 08756ed98e7c..bf51072f30bf 100755 --- a/src/test/test_rados_tool.sh +++ b/src/test/test_rados_tool.sh @@ -219,6 +219,11 @@ run_expect_fail "$RADOS_TOOL" mkpool delete_me_mkpool_test3 0 0k run_expect_succ "$RADOS_TOOL" --pool "$POOL" bench 1 write run_expect_fail "$RADOS_TOOL" --pool "$POOL" bench 1k write +run_expect_succ "$RADOS_TOOL" --pool "$POOL" bench 1 write --format json --output "$TDIR/bench.json" +run_expect_fail "$RADOS_TOOL" --pool "$POOL" bench 1 write --output "$TDIR/bench.json" +run_expect_succ "$RADOS_TOOL" --pool "$POOL" bench 5 write --format json --no-cleanup +run_expect_succ "$RADOS_TOOL" --pool "$POOL" bench 1 rand --format json +run_expect_succ "$RADOS_TOOL" --pool "$POOL" bench 1 seq --format json echo "SUCCESS!" diff --git a/src/tools/rados/rados.cc b/src/tools/rados/rados.cc index 82b88bbd7a78..c845d30027f7 100644 --- a/src/tools/rados/rados.cc +++ b/src/tools/rados/rados.cc @@ -1208,6 +1208,7 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts, Formatter *formatter = NULL; bool pretty_format = false; + const char *output = NULL; Rados rados; IoCtx io_ctx; @@ -1360,6 +1361,10 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts, if (i != opts.end()) { no_verify = true; } + i = opts.find("output"); + if (i != opts.end()) { + output = i->second.c_str(); + } // open rados @@ -2406,12 +2411,29 @@ static int rados_tool_common(const std::map < std::string, std::string > &opts, ret = -EINVAL; goto out; } + if (!formatter && output) { + cerr << "-o|--output option can be used only with '--format' option" + << std::endl; + ret = -EINVAL; + goto out; + } RadosBencher bencher(g_ceph_context, rados, io_ctx); bencher.set_show_time(show_time); + ostream *outstream = NULL; + if (formatter) { + bencher.set_formatter(formatter); + if (output) + outstream = new ofstream(output); + else + outstream = &cout; + bencher.set_outstream(*outstream); + } ret = bencher.aio_bench(operation, seconds, concurrent_ios, op_size, cleanup, run_name, no_verify); if (ret != 0) cerr << "error during benchmark: " << ret << std::endl; + if (formatter && output) + delete outstream; } else if (strcmp(nargs[0], "cleanup") == 0) { if (!pool_name) @@ -2926,6 +2948,8 @@ int main(int argc, const char **argv) opts["all"] = "true"; } else if (ceph_argparse_flag(args, i, "--default", (char*)NULL)) { opts["default"] = "true"; + } else if (ceph_argparse_witharg(args, i, &val, "-o", "--output", (char*)NULL)) { + opts["output"] = val; } else { if (val[0] == '-') usage_exit();