From c28a00cfa5a67267243ce0c5a81d88fe1cb613e5 Mon Sep 17 00:00:00 2001 From: Albert H Chen Date: Sun, 15 Sep 2019 19:40:55 +0000 Subject: [PATCH] tools/rados: Fix rand & seq read bench to use num ops instead of num objs when issuing and tracking outstanding IO ObjBencher::seq_read_bench() is using "num_objects > data.started" to make sure we don't issue more reads than what was written during ObjBencher::write_bench(). However, this does not work op_size != object_size as data.started is number of read ops issued, not number of objects read. This fix modifies ObjBencher::seq_read_bench() to use "num_ops > data.started" instead. Where "num_ops" is metadata saved at the end of ObjBencher::write_bench(). ObjBencher::rand_read_bench() is using "rand() % num_objects" for rand_id and "rand_id / reads_per_object" to generate object name. This will not work correctly when reads_per_object != 1 (i.e. when op_size != object_size). For example, if reads_per_object = 100 and num_objects = 2, then all generated reads will be directed towards the first object, with no read for the second object. This fix modifies ObjBencher::rand_read_bench() to use "rand() % num_ops" for rand_id instead. Where "num_ops" is metadata saved at the end of ObjBencher::write_bench(). This patch also modifies ObjBencher::write_bench() to save number of write operations issued (num_ops above), rather than number of objects written (num_objects). We can always derive num_objects based on "(num_ops + ops_per_object - 1) / ops_per_object" where "ops_per_object" is simply object_size / op_size. Signed-off-by: Albert H Chen --- src/common/obj_bencher.cc | 42 ++++++++++++++++++++++++--------------- src/common/obj_bencher.h | 6 +++--- 2 files changed, 29 insertions(+), 19 deletions(-) mode change 100644 => 100755 src/common/obj_bencher.cc diff --git a/src/common/obj_bencher.cc b/src/common/obj_bencher.cc old mode 100644 new mode 100755 index 3539abfed47..44c99b362f3 --- a/src/common/obj_bencher.cc +++ b/src/common/obj_bencher.cc @@ -244,6 +244,7 @@ int ObjBencher::aio_bench( if (concurrentios <= 0) return -EINVAL; + int num_ops = 0; int num_objects = 0; int r = 0; int prev_pid = 0; @@ -256,7 +257,7 @@ int ObjBencher::aio_bench( if (operation != OP_WRITE || reuse_bench) { uint64_t prev_op_size, prev_object_size; r = fetch_bench_metadata(run_name_meta, &prev_op_size, &prev_object_size, - &num_objects, &prev_pid); + &num_ops, &num_objects, &prev_pid); if (r < 0) { if (r == -ENOENT) { if (reuse_bench) @@ -297,17 +298,17 @@ int ObjBencher::aio_bench( if (r != 0) goto out; } else if (OP_SEQ_READ == operation) { - r = seq_read_bench(secondsToRun, num_objects, concurrentios, prev_pid, no_verify); + r = seq_read_bench(secondsToRun, num_ops, num_objects, concurrentios, prev_pid, no_verify); if (r != 0) goto out; } else if (OP_RAND_READ == operation) { - r = rand_read_bench(secondsToRun, num_objects, concurrentios, prev_pid, no_verify); + r = rand_read_bench(secondsToRun, num_ops, num_objects, concurrentios, prev_pid, no_verify); if (r != 0) goto out; } if (OP_WRITE == operation && cleanup) { r = fetch_bench_metadata(run_name_meta, &op_size, &object_size, - &num_objects, &prev_pid); + &num_ops, &num_objects, &prev_pid); if (r < 0) { if (r == -ENOENT) cerr << "Should never happen: bench metadata missing for current run!" << std::endl; @@ -353,7 +354,7 @@ void _aio_cb(void *cb, void *arg) { int ObjBencher::fetch_bench_metadata(const std::string& metadata_file, uint64_t *op_size, uint64_t* object_size, - int* num_objects, int* prevPid) { + int* num_ops, int* num_objects, int* prevPid) { int r = 0; bufferlist object_data; @@ -368,13 +369,19 @@ int ObjBencher::fetch_bench_metadata(const std::string& metadata_file, } auto p = object_data.cbegin(); decode(*object_size, p); - decode(*num_objects, p); + decode(*num_ops, p); decode(*prevPid, p); if (!p.end()) { decode(*op_size, p); } else { *op_size = *object_size; } + unsigned ops_per_object = 1; + // make sure *op_size value is reasonable + if (*op_size > 0 && *object_size > *op_size) { + ops_per_object = *object_size / *op_size; + } + *num_objects = (*num_ops + ops_per_object - 1) / ops_per_object; return 0; } @@ -458,7 +465,6 @@ int ObjBencher::write_bench(int secondsToRun, //keep on adding new writes as old ones complete until we've passed minimum time int slot; - int num_objects; //don't need locking for reads because other thread doesn't write @@ -627,8 +633,7 @@ int ObjBencher::write_bench(int secondsToRun, } //write object size/number data for read benchmarks encode(data.object_size, b_write); - num_objects = (data.finished + writes_per_object - 1) / writes_per_object; - encode(num_objects, b_write); + encode(data.finished, b_write); encode(prev_pid ? prev_pid : getpid(), b_write); encode(data.op_size, b_write); @@ -647,7 +652,10 @@ int ObjBencher::write_bench(int secondsToRun, return r; } -int ObjBencher::seq_read_bench(int seconds_to_run, int num_objects, int concurrentios, int pid, bool no_verify) { +int ObjBencher::seq_read_bench( + int seconds_to_run, int num_ops, int num_objects, + int concurrentios, int pid, bool no_verify) { + lock_cond lc(&lock); if (concurrentios <= 0) @@ -713,7 +721,7 @@ int ObjBencher::seq_read_bench(int seconds_to_run, int num_objects, int concurre slot = 0; while ((seconds_to_run && mono_clock::now() < finish_time) && - num_objects > data.started) { + num_ops > data.started) { locker.lock(); int old_slot = slot; bool found = false; @@ -881,8 +889,10 @@ int ObjBencher::seq_read_bench(int seconds_to_run, int num_objects, int concurre return r; } -int ObjBencher::rand_read_bench(int seconds_to_run, int num_objects, int concurrentios, int pid, bool no_verify) -{ +int ObjBencher::rand_read_bench( + int seconds_to_run, int num_ops, int num_objects, + int concurrentios, int pid, bool no_verify) { + lock_cond lc(&lock); if (concurrentios <= 0) @@ -1006,7 +1016,7 @@ int ObjBencher::rand_read_bench(int seconds_to_run, int num_objects, int concurr } } - rand_id = rand() % num_objects; + rand_id = rand() % num_ops; newName = generate_object_name_fast(rand_id / reads_per_object, pid); index[slot] = rand_id; release_completion(slot); @@ -1124,7 +1134,7 @@ int ObjBencher::rand_read_bench(int seconds_to_run, int num_objects, int concurr int ObjBencher::clean_up(const std::string& orig_prefix, int concurrentios, const std::string& run_name) { int r = 0; uint64_t op_size, object_size; - int num_objects; + int num_ops, num_objects; int prevPid; // default meta object if user does not specify one @@ -1171,7 +1181,7 @@ int ObjBencher::clean_up(const std::string& orig_prefix, int concurrentios, cons continue; } - r = fetch_bench_metadata(run_name_meta, &op_size, &object_size, &num_objects, &prevPid); + r = fetch_bench_metadata(run_name_meta, &op_size, &object_size, &num_ops, &num_objects, &prevPid); if (r < 0) { return r; } diff --git a/src/common/obj_bencher.h b/src/common/obj_bencher.h index f2b6e173d77..f23e2d6354c 100644 --- a/src/common/obj_bencher.h +++ b/src/common/obj_bencher.h @@ -75,11 +75,11 @@ protected: struct bench_data data; int fetch_bench_metadata(const std::string& metadata_file, uint64_t* op_size, - uint64_t* object_size, int* num_objects, int* prev_pid); + uint64_t* object_size, int* num_ops, int* num_objects, int* prev_pid); int write_bench(int secondsToRun, int concurrentios, const string& run_name_meta, unsigned max_objects, int prev_pid); - int seq_read_bench(int secondsToRun, int num_objects, int concurrentios, int writePid, bool no_verify=false); - int rand_read_bench(int secondsToRun, int num_objects, int concurrentios, int writePid, bool no_verify=false); + int seq_read_bench(int secondsToRun, int num_ops, int num_objects, int concurrentios, int writePid, bool no_verify=false); + int rand_read_bench(int secondsToRun, int num_ops, int num_objects, int concurrentios, int writePid, bool no_verify=false); int clean_up(int num_objects, int prevPid, int concurrentios); bool more_objects_matching_prefix(const std::string& prefix, std::list* name); -- 2.39.5