/* * Copyright (C) 2014-2023 Savoir-faire Linux Inc. * * Author: Adrien Béraud * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "tools_common.h" #include extern "C" { #include } #include #include #include void print_usage() { std::cout << "Usage: perftest" << std::endl << std::endl; std::cout << "perftest, a simple OpenDHT basic performance tester." << std::endl; std::cout << "Report bugs to: https://opendht.net" << std::endl; } constexpr unsigned PINGPONG_MAX = 2048; using namespace dht; namespace tests { using clock = std::chrono::high_resolution_clock; using duration = clock::duration; duration benchPingPong(unsigned netSize, unsigned n_parallel) { DhtRunner::Config config {}; config.dht_config.node_config.max_peer_req_per_sec = -1; config.dht_config.node_config.max_req_per_sec = -1; DhtRunner ping_node, pong_node; std::vector> locs; locs.reserve(n_parallel); for (unsigned i=0; i> nodes; nodes.reserve(netSize); for (unsigned i=0; i(); node->run(0, config); node->bootstrap(bindAddr); nodes.emplace_back(std::move(node)); } // std::this_thread::sleep_for(std::chrono::seconds(1)); std::condition_variable cv; unsigned i {0}; std::mutex m; unsigned max = PINGPONG_MAX * n_parallel; auto ping = [&](DhtRunner& node, InfoHash h) { std::lock_guard lk(m); if (i < max) { i++; node.put(h, Value("hey")); } cv.notify_one(); }; for (unsigned i=0; i&){ ping(pong_node, locs[i].second); return true; }); pong_node.listen(locs[i].second, [&,i](const std::shared_ptr&){ ping(ping_node, locs[i].first); return true; }); } auto start = clock::now(); for (unsigned i=0; i lk(m); if (not cv.wait_for(lk, std::chrono::minutes(1), [&](){ return i == max; })) { throw std::runtime_error(std::string("Timeout: ") + std::to_string(i)); } } auto end = clock::now(); for (auto& node : nodes) node->shutdown(); ping_node.shutdown(); pong_node.shutdown(); for (auto& node : nodes) node->join(); ping_node.join(); pong_node.join(); return end-start; } } int main(int argc, char **argv) { #ifdef _MSC_VER gnutls_global_init(); #endif auto params = parseArgs(argc, argv); if (params.help) { print_usage(); return 0; } duration totalTime {0}; unsigned totalOps {0}; for (unsigned nparallel = 1; nparallel <= 32; nparallel *= 2) { unsigned max = PINGPONG_MAX * nparallel; std::vector results {}; results.reserve(8); duration total {0}; for (unsigned i=2; i<32; i *= 2) { auto dt = tests::benchPingPong(i - 2, nparallel); std::cout << "Network size: " << i << std::endl; std::cout << max << " ping-pong done, took " << print_duration(dt) << std::endl; std::cout << print_duration(dt/max) << " per rt, " << max/std::chrono::duration(dt).count() << " ping per s" << std::endl << std::endl; total += dt; totalOps += max; results.emplace_back(dt); } totalTime += total; std::cout << "Total for " << nparallel << std::endl; auto totNum = max*results.size(); std::cout << totNum << " ping-pong done, took " << print_duration(total) << std::endl; std::cout << print_duration(total/totNum) << " per rt, " << totNum/std::chrono::duration(total).count() << " ping per s" << std::endl << std::endl; } std::cout << std::endl << "Grand total: " << print_duration(totalTime) << " for " << totalOps << std::endl; std::cout << print_duration(totalTime/totalOps) << " per rt, " << totalOps/std::chrono::duration(totalTime).count() << " ping per s" << std::endl << std::endl; #ifdef _MSC_VER gnutls_global_deinit(); #endif return 0; }