libdbus p2p benchmark: style and minor tweaks 41/268841/3
authorMichal Bloch <m.bloch@samsung.com>
Mon, 3 Jan 2022 16:37:29 +0000 (17:37 +0100)
committerMichal Bloch <m.bloch@samsung.com>
Wed, 5 Jan 2022 14:41:15 +0000 (15:41 +0100)
Change-Id: Icdb65ed4b875827b32b19c930cfe1749bae9f2c0
Signed-off-by: Michal Bloch <m.bloch@samsung.com>
benchmark/libdbus-p2p-client.cpp
benchmark/libdbus-p2p-server.cpp

index 3f6d7809d08d8a430a00cb0b40356e29fafc6d28..97882656ad581a99402a4875976b7221fa3fd04c 100644 (file)
@@ -138,7 +138,7 @@ int main (int argc, char ** argv)
                        , DBUS_TYPE_INVALID
                );
 
-               dbus_uint64_t ts = std::chrono::duration_cast <std::chrono::microseconds>
+               dbus_uint64_t ts = std::chrono::duration_cast <std::chrono::nanoseconds>
                        (std::chrono::high_resolution_clock::now().time_since_epoch())
                        .count()
                ;
index 05d2e2936620730b6bde07b9b11bc422be7df21e..0a80407c714327a6784d5ee599224de74fbb2b29 100644 (file)
 
 #include <algorithm>
 #include <chrono>
-#include <cstdlib>
 #include <csignal>
-#include <functional>
-#include <iostream>
+#include <cstdlib>
 #include <fstream>
+#include <functional>
 #include <iomanip>
+#include <iostream>
 #include <limits>
 #include <memory>
-#include <tuple>
 #include <utility>
 #include <vector>
 
 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 <std::string> 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 <DBusConnection, DBusConnection_destructor> conn;
+       std::unique_ptr <DBusConnection, DBusConnection_deleter> 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 <uint64_t> :: max ())
                , max_time (std::numeric_limits <uint64_t> :: 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 <conn_with_metadata *> (userdata);
 
-               dbus_uint64_t now = std::chrono::duration_cast <std::chrono::microseconds>
+               dbus_uint64_t now = std::chrono::duration_cast <std::chrono::nanoseconds>
                        (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 <DBusServer, DBusServer_deleter> 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 <conn_with_metadata> 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 <conn_with_metadata> 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 <decltype (&ud)> (data));
-                       connz.emplace_back (opts, c, rdof);
+                       auto [opts, connz] = *(reinterpret_cast <decltype (&ud)> (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 <DBusWatch **> (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;
 }