From: Michal Bloch Date: Mon, 3 Jan 2022 16:37:29 +0000 (+0100) Subject: libdbus p2p benchmark: style and minor tweaks X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=fb76f54ca9dcb751ffa16848ab4b7cf8cc438180;p=platform%2Fcore%2Fsystem%2Fdbus-tools.git libdbus p2p benchmark: style and minor tweaks Change-Id: Icdb65ed4b875827b32b19c930cfe1749bae9f2c0 Signed-off-by: Michal Bloch --- diff --git a/benchmark/libdbus-p2p-client.cpp b/benchmark/libdbus-p2p-client.cpp index 3f6d780..9788265 100644 --- a/benchmark/libdbus-p2p-client.cpp +++ b/benchmark/libdbus-p2p-client.cpp @@ -138,7 +138,7 @@ int main (int argc, char ** argv) , DBUS_TYPE_INVALID ); - dbus_uint64_t ts = std::chrono::duration_cast + dbus_uint64_t ts = std::chrono::duration_cast (std::chrono::high_resolution_clock::now().time_since_epoch()) .count() ; diff --git a/benchmark/libdbus-p2p-server.cpp b/benchmark/libdbus-p2p-server.cpp index 05d2e29..0a80407 100644 --- a/benchmark/libdbus-p2p-server.cpp +++ b/benchmark/libdbus-p2p-server.cpp @@ -27,39 +27,19 @@ #include #include -#include #include -#include -#include +#include #include +#include #include +#include #include #include -#include #include #include static constexpr const char * TEST_PATH = "/org/test"; -static DBusServer * server; - -void exit_func () -{ - /* `server` guaranteed non-null - * via atexit() timing. */ - - dbus_server_disconnect (server); - dbus_server_unref (server); -} - -extern "C" void sig_handler (int sig) -{ - /* SIG_DFL doesn't seem to run - * the atexit() handlers. */ - - std::exit (EXIT_SUCCESS); -} - struct run_opts { bool show_help = false; @@ -88,8 +68,9 @@ struct run_opts { bool busy_wait = false; /* When enabled, the server collects all method call times and - * writes them out to a CSV file. Useful for distribution charts. */ - bool raw_data_on = false; + * writes them out to a CSV file under the specified path. Useful + * for distribution charts. */ + std::optional raw_data_path = std::nullopt; }; run_opts get_opt (int argc, char ** argv) @@ -97,24 +78,31 @@ run_opts get_opt (int argc, char ** argv) run_opts ret; int opt; - while ((opt = getopt(argc, argv, "wit:p:rh")) != -1) + while ((opt = getopt(argc, argv, ":ihp:r:t:w")) != -1) switch (opt) { - case 't': - ret.warmup_tries = std::stoi(optarg); - break; - case 'w': - ret.busy_wait = true; - break; case 'i': ret.infinite_listening = true; break; case 'p': ret.sock_path = optarg; break; + case 't': + ret.warmup_tries = std::stoi(optarg); + break; case 'r': - ret.raw_data_on = true; + ret.raw_data_path.emplace(optarg); break; + case 'w': + ret.busy_wait = true; + break; + case ':': + if (optopt == 'r') { + ret.raw_data_path.emplace("libdbus-p2p-latency.csv"); + break; + } + + [[fallthrough]]; case 'h': default: ret.show_help = true; @@ -124,7 +112,7 @@ run_opts get_opt (int argc, char ** argv) return ret; } -struct DBusConnection_destructor { +struct DBusConnection_deleter { void operator () (DBusConnection * conn) { dbus_connection_unregister_object_path (conn, TEST_PATH); dbus_connection_close (conn); @@ -141,24 +129,20 @@ struct conn_with_metadata { size_t warmup_tries; - bool raw_data_on; - - std::ofstream &raw_data_out_file; + static std::ofstream raw_data_out_file; - std::unique_ptr conn; + std::unique_ptr conn; bool finished; static DBusObjectPathVTable vtable; - conn_with_metadata (const run_opts & ro, DBusConnection * c, std::ofstream & rdof) + conn_with_metadata (const run_opts & ro, DBusConnection * c) : total_time (0) , total_count (0) , min_time (std::numeric_limits :: max ()) , max_time (std::numeric_limits :: min ()) , warmup_tries (ro.warmup_tries) - , raw_data_on(ro.raw_data_on) - , raw_data_out_file(rdof) , conn (c) , finished (false) { @@ -178,8 +162,6 @@ struct conn_with_metadata { , min_time (std::move(x.min_time)) , max_time (std::move(x.max_time)) , warmup_tries (std::move(x.warmup_tries)) - , raw_data_on (std::move(x.raw_data_on)) - , raw_data_out_file (x.raw_data_out_file) , conn (std::move(x.conn)) , finished (std::move(x.finished)) { @@ -209,8 +191,6 @@ struct conn_with_metadata { min_time = std::move(x.min_time); max_time = std::move(x.max_time); warmup_tries = std::move(x.warmup_tries); - raw_data_on = std::move(x.raw_data_on); - raw_data_out_file = std::move(x.raw_data_out_file); conn = std::move(x.conn); finished = std::move(x.finished); @@ -231,6 +211,8 @@ struct conn_with_metadata { ~ conn_with_metadata () = default; }; +std::ofstream conn_with_metadata::raw_data_out_file; + DBusObjectPathVTable conn_with_metadata::vtable = { [] (DBusConnection * c, void * userdata) -> void { /* Unregistering and disconnection handler. @@ -242,16 +224,16 @@ DBusObjectPathVTable conn_with_metadata::vtable = /* Couldn't use the real `this`, even if this was inside the class proper, * because that would be capturing a variable, which prevents the lambda - * from being convertible to a function pointer (as required by the vtable),*/ + * from being convertible to a function pointer (as required by the vtable). */ auto THIS = reinterpret_cast (userdata); - dbus_uint64_t now = std::chrono::duration_cast + dbus_uint64_t now = std::chrono::duration_cast (std::chrono::high_resolution_clock::now().time_since_epoch()) .count() ; /* These two are garbage that we don't care about, - * but `dbus_message_get_args` doesn't accept nulls */ + * but `dbus_message_get_args` doesn't accept nulls. */ char * arr_ptr; int arr_size; @@ -270,10 +252,8 @@ DBusObjectPathVTable conn_with_metadata::vtable = THIS->min_time = std::min (THIS->min_time, diff); THIS->max_time = std::max (THIS->max_time, diff); - if (THIS->raw_data_on) { - THIS->raw_data_out_file << std::setprecision(4); - THIS->raw_data_out_file << (double)diff << std::endl; - } + if (THIS->raw_data_out_file.is_open()) + THIS->raw_data_out_file << diff / 1000.0 << std::endl; } else { -- THIS->warmup_tries; } @@ -286,11 +266,11 @@ DBusObjectPathVTable conn_with_metadata::vtable = void show_help (const char * argv0) { std::cout << "Usage: " << argv0 - << " [-t warmup_tries] " - << " [-p sock_path] " - << " [-i (infinite listening)] " - << " [-w (busy wait)] " - << " [-r (raw data dump)] " + << " [-t warmup_tries]" + " [-p sock_path]" + " [-i (infinite listening)]" + " [-w (busy wait)]" + " [-r [dump_csv_file_path]]" << std::endl ; } @@ -302,14 +282,26 @@ void dispatch_connection (conn_with_metadata & cwm, bool busy_wait) cwm.finished = true; - auto avg_time = double(cwm.total_time) / cwm.total_count; + if (! cwm.total_count) { + std::cerr << "connection broken during warm-up phase" << std::endl; + return; + } + + auto avg_time = cwm.total_time / cwm.total_count; std::cout - << "min: " << cwm.min_time << "us, " - << "max: " << cwm.max_time << "us, " - << "avg: " << avg_time << "us" + << "min: " << cwm.min_time / 1000.0 << "us, " + << "max: " << cwm.max_time / 1000.0 << "us, " + << "avg: " << avg_time / 1000.0 << "us" << std::endl; } +struct DBusServer_deleter { + void operator () (DBusServer * server) { + dbus_server_disconnect (server); + dbus_server_unref (server); + } +}; + void read_from_watch (DBusWatch * watch, bool wait_infinitely) { struct pollfd pfd; @@ -325,50 +317,59 @@ void read_from_watch (DBusWatch * watch, bool wait_infinitely) dbus_watch_handle (watch, DBUS_WATCH_READABLE); } +extern "C" void sig_handler (int sig) +{ + /* Ensures RAII by replacing std::terminate, which + * is the default but does not destroy objects (but + * see the thread_local note below). */ + + std::exit (EXIT_SUCCESS); +} + int main (int argc, char ** argv) { + std::signal (SIGINT , sig_handler); + std::signal (SIGTERM, sig_handler); + run_opts opt = get_opt (argc, argv); - std::ofstream raw_data_out_file; if (opt.show_help) { show_help (argv[0]); return EXIT_FAILURE; } - server = dbus_server_listen (("unix:path=" + opt.sock_path).c_str(), nullptr); + /* thread_local ensures the destructor runs, the destructor doesn't + * run on std::exit without it as per the std::exit specification. + * Otherwise it makes no difference since we're single-threaded. */ + thread_local std::unique_ptr server (dbus_server_listen (("unix:path=" + opt.sock_path).c_str(), nullptr)); if (!server) { std::cerr << "listening on " << opt.sock_path << "failed" << std::endl; return EXIT_FAILURE; } - if (opt.raw_data_on) { - raw_data_out_file.open("libdbus-p2p-latency.csv"); - if (!raw_data_out_file.is_open()) { + if (opt.raw_data_path) { + conn_with_metadata::raw_data_out_file.open(opt.raw_data_path.value()); + if (!conn_with_metadata::raw_data_out_file.is_open()) { std::cerr << "cannot create raw data output file" << std::endl; return EXIT_FAILURE; } - raw_data_out_file << "Latency" << std::endl; - raw_data_out_file << std::fixed; + conn_with_metadata::raw_data_out_file << "Latency" << std::endl + << std::fixed << std::setprecision(3); } - // Set up cleanup functions for `server` - std::atexit (exit_func); - std::signal (SIGINT , sig_handler); - std::signal (SIGTERM, sig_handler); - - std::vector conns; - auto ud = std::make_tuple (std::ref(opt), std::ref (conns), std::ref(raw_data_out_file)); - dbus_server_set_new_connection_function (server + thread_local std::vector conns; + auto ud = std::make_pair (std::ref(opt), std::ref (conns)); + dbus_server_set_new_connection_function (server.get() , [] (DBusServer * s, DBusConnection * c, void * data) { - auto [opts, connz, rdof] = *(reinterpret_cast (data)); - connz.emplace_back (opts, c, rdof); + auto [opts, connz] = *(reinterpret_cast (data)); + connz.emplace_back (opts, c); } , & ud // userdata , nullptr // userdata free func ); DBusWatch * watch; - dbus_server_set_watch_functions (server + dbus_server_set_watch_functions (server.get() , [] (DBusWatch * w, void * data) -> dbus_bool_t { auto main_watch = reinterpret_cast (data); *main_watch = w; @@ -381,6 +382,10 @@ int main (int argc, char ** argv) , nullptr // userdata free func ); + /* Parser tools expect microseconds, but we calculate + * from nanoseconds, so have 3 decimal digits. */ + std::cout << std::fixed << std::setprecision(3); + do { read_from_watch (watch, conns.empty ()); @@ -391,6 +396,6 @@ int main (int argc, char ** argv) } while (opt.infinite_listening || ! conns.empty ()); - return 0; + return EXIT_SUCCESS; }