diff --git a/src/sdskv-benchmark.cc b/src/sdskv-benchmark.cc index 9f3dc77c9b774d3c93dbe7dc6f08f3ceeac6cba8..e610b4747c350180ae3c282b26c5e5921c67176c 100644 --- a/src/sdskv-benchmark.cc +++ b/src/sdskv-benchmark.cc @@ -692,6 +692,7 @@ static void run_server(MPI_Comm comm, Json::Value& config); static void run_client(MPI_Comm comm, Json::Value& config); static void run_single_node(Json::Value& config); static sdskv_db_type_t database_type_from_string(const std::string& type); +static void parse_extra_cmd_arg(Json::Value& config, const char* arg); /** * @brief Main function. @@ -703,9 +704,9 @@ int main(int argc, char** argv) { MPI_Comm_rank(MPI_COMM_WORLD, &rank); MPI_Comm_size(MPI_COMM_WORLD, &size); - if(argc != 2) { + if(argc < 2) { if(rank == 0) { - std::cerr << "Usage: " << argv[0] << " " << std::endl; + std::cerr << "Usage: " << argv[0] << " [ a.b.c=x ... ]" << std::endl; MPI_Abort(MPI_COMM_WORLD, -1); } } @@ -719,6 +720,10 @@ int main(int argc, char** argv) { Json::Value config; config_file >> config; + for(unsigned i = 2; i < argc; i++) { + parse_extra_cmd_arg(config, argv[i]); + } + MPI_Comm comm = MPI_COMM_WORLD; bool single_node = (size == 1); if(!single_node) { @@ -808,15 +813,27 @@ static void run_client(MPI_Comm comm, Json::Value& config) { std::vector> benchmarks; std::vector repetitions; std::vector types; - benchmarks.reserve(config["benchmarks"].size()); - repetitions.reserve(config["benchmarks"].size()); - types.reserve(config["benchmarks"].size()); - for(auto& bench_config : config["benchmarks"]) { + size_t num_benchmarks = 1; + if(config["benchmarks"].isArray()) + num_benchmarks = config["benchmarks"].size(); + benchmarks.reserve(num_benchmarks); + repetitions.reserve(num_benchmarks); + types.reserve(num_benchmarks); + if(config["benchmarks"].isArray()) { + for(auto& bench_config : config["benchmarks"]) { + std::string type = bench_config["type"].asString(); + types.push_back(type); + benchmarks.push_back(AbstractBenchmark::create(type, bench_config, comm, db)); + repetitions.push_back(bench_config["repetitions"].asUInt()); + } + } else { + auto& bench_config = config["benchmarks"]; std::string type = bench_config["type"].asString(); types.push_back(type); benchmarks.push_back(AbstractBenchmark::create(type, bench_config, comm, db)); repetitions.push_back(bench_config["repetitions"].asUInt()); } + // main execution loop for(unsigned i = 0; i < benchmarks.size(); i++) { auto& bench = benchmarks[i]; @@ -850,7 +867,10 @@ static void run_client(MPI_Comm comm, Json::Value& config) { if(rank == 0) { size_t n = global_timings.size(); std::cout << "================ " << types[i] << " ================" << std::endl; - styledStream.write(std::cout, config["benchmarks"][i]); + if(config["benchmarks"].isArray()) + styledStream.write(std::cout, config["benchmarks"][i]); + else + styledStream.write(std::cout, config["benchmarks"]); std::cout << "-----------------" << std::string(types[i].size(),'-') << "-----------------" << std::endl; double average = std::accumulate(global_timings.begin(), global_timings.end(), 0.0) / n; double variance = std::accumulate(global_timings.begin(), global_timings.end(), 0.0, [average](double acc, double x) { @@ -925,10 +945,21 @@ static void run_single_node(Json::Value& config) { std::vector> benchmarks; std::vector repetitions; std::vector types; - benchmarks.reserve(config["benchmarks"].size()); - repetitions.reserve(config["benchmarks"].size()); - types.reserve(config["benchmarks"].size()); - for(auto& bench_config : config["benchmarks"]) { + size_t num_benchmarks = 1; + if(config["benchmarks"].isArray()) + num_benchmarks = config["benchmarks"].size(); + benchmarks.reserve(num_benchmarks); + repetitions.reserve(num_benchmarks); + types.reserve(num_benchmarks); + if(config["benchmarks"].isArray()) { + for(auto& bench_config : config["benchmarks"]) { + std::string type = bench_config["type"].asString(); + types.push_back(type); + benchmarks.push_back(AbstractBenchmark::create(type, bench_config, MPI_COMM_WORLD, db)); + repetitions.push_back(bench_config["repetitions"].asUInt()); + } + } else { + auto& bench_config = config["benchmarks"]; std::string type = bench_config["type"].asString(); types.push_back(type); benchmarks.push_back(AbstractBenchmark::create(type, bench_config, MPI_COMM_WORLD, db)); @@ -957,7 +988,10 @@ static void run_single_node(Json::Value& config) { // print report size_t n = global_timings.size(); std::cout << "================ " << types[i] << " ================" << std::endl; - styledStream.write(std::cout, config["benchmarks"][i]); + if(config["benchmarks"].isArray()) + styledStream.write(std::cout, config["benchmarks"][i]); + else + styledStream.write(std::cout, config["benchmarks"]); std::cout << "-----------------" << std::string(types[i].size(),'-') << "-----------------" << std::endl; double average = std::accumulate(global_timings.begin(), global_timings.end(), 0.0) / n; double variance = std::accumulate(global_timings.begin(), global_timings.end(), 0.0, [average](double acc, double x) { @@ -998,3 +1032,39 @@ static sdskv_db_type_t database_type_from_string(const std::string& type) { } throw std::runtime_error(std::string("Unknown database type \"") + type + "\""); } + +static void parse_extra_cmd_arg(Json::Value& config, const char* arg) { + // find first instance of a point + const char* period = strchr(arg,'.'); + // period found, call recursively + if(period != NULL) { + std::string key(arg, (size_t)(period - arg)); + parse_extra_cmd_arg(config[key], period+1); + return; + } + // period not found, search for equal sign + const char* equal = strchr(arg, '='); + if(!equal) throw std::runtime_error("Syntax error in command line"); + std::string key = std::string(arg, (size_t)(equal - arg)); + std::string val = std::string(equal+1); + if(val[0] == '"' && val[val.size()-1] == '"') { + config[key] = val.substr(1,val.size()-2); + } else if(val == "true") { + config[key] = true; + } else if(val == "false") { + config[key] = false; + } else { + bool is_number = true; + for(auto& c : val) { + if(c < '0' || c > '9') { + is_number = false; + break; + } + } + if(is_number) { + config[key] = atoi(val.c_str()); + } else { + config[key] = val; + } + } +}