#include #include #include #include #include #include #include // This is a re-implementation of a member function "Gio::DBus::Connection::send_message_with_reply_sync()" // in Glibmm. The Glibmm version always produces a runtime warning (see comment below. I believe this is a bug). Glib::RefPtr connection_send_message_with_reply_sync( Glib::RefPtr connection, Glib::RefPtr message, gint timeout_msec) { volatile guint32 out_serial = 0; GError* gerror = nullptr; GDBusMessage* result = g_dbus_connection_send_message_with_reply_sync(connection->gobj(), Glib::unwrap(message), static_cast(message->get_flags()), timeout_msec, &out_serial, nullptr, &gerror); if (gerror) ::Glib::Error::throw_exception(gerror); // setting serial is not possible because message is already locked. // the following will just emit a warning and does nothing: // message->set_serial(out_serial); return Glib::wrap(result); } ///////////////////////////////////////////////////////// // METHOD 1: // Get an array from a DBus service call // The array is sent over a unix pipe where the pipe // file descriptors are sent via DBus call. ///////////////////////////////////////////////////////// std::vector get_vector_pipe(Glib::RefPtr connection) { // connect to the C++ (Gio::DBus) server Glib::RefPtr message = Gio::DBus::Message::create_method_call( "org.glibmm.DBusExample", // service name "/org/glibmm/DBus/TestObject", // object path "org.glibmm.DBusExample.Machine", // interface name "GetArray" // method name ); gint timeout = -1; // [ms] Glib::RefPtr reply = connection_send_message_with_reply_sync(connection, message, timeout); GUnixFDList *fd_list = g_dbus_message_get_unix_fd_list(reply->gobj()); if (fd_list == 0) { std::cerr << "didn't get fd_list ..." << std::endl; exit(1); } // Getting the reading end of the pipe creates an open file descriptor. Rembember to close after using it. gint fd = g_unix_fd_list_get(fd_list,0,0); // First, read the size of the array (By convention, sending arrays throug a pipe starts with an integer that holds the size of the array) guint size; read(fd,&size,sizeof(size)); // Create a vector that will hold the data std::vector block(size,size); // Read the data though the pipe. int nbytes = read(fd,&block[0],sizeof(guint32)*(block.size())); // Close the open file descriptor close(fd); return block; } ///////////////////////////////////////////////////////// // METHOD 2: // Get an array from a DBus service call // This is the normal DBus way of sending array data ///////////////////////////////////////////////////////// std::vector get_vector_array(Glib::RefPtr proxy) { Glib::RefPtr cancellable; const Glib::VariantContainerBase& response = proxy->call_sync("GetArrayNoPipe", cancellable); Glib::Variant< std::vector< guint32 > > array; response.get_child(array, 0); return array.get(); } // calculate duration in miliseconds from two points in time double delta_t_ms(timespec ts_start, timespec ts_stop) { return 1e3*(ts_stop.tv_sec - ts_start.tv_sec) + (ts_stop.tv_nsec - ts_start.tv_nsec) / 1e6; } /////////////////////////////////////////////////////////////////// // do lots of array transfers (with arrays of different size) // through a pipe and as normal DBus arrays, and write the // measured transfer times into a file. /////////////////////////////////////////////////////////////////// int main(int, char**) { Gio::init(); // Get the bus connection. Glib::RefPtr connection = Gio::DBus::Connection::get_sync(Gio::DBus::BUS_TYPE_SESSION); // Create a proxy object Glib::RefPtr cancellable; auto proxy = Gio::DBus::Proxy::create_sync( connection, "org.glibmm.DBusExample", "/org/glibmm/DBus/TestObject", "org.glibmm.DBusExample.Machine", cancellable); // open two files for the measured timing data // To plot the data in gnuplot: Start gnuplot and type // plot "measurment_array.dat" using 1:2 w p, "measurment_pipe.dat" using 1:2 w p std::ofstream data_pipe ("measurment_pipe.dat"); std::ofstream data_array("measurment_array.dat"); // make lots of measurements for (int i = 0; i < 1000; ++i) { if (i && !(i%100)) std::cerr << i/10 << "\%"<< std::endl; timespec ts_start, ts_stop; //////////////////////////////////////////// // measurement with pipe via file descriptor //////////////////////////////////////////// { clock_gettime(CLOCK_REALTIME, &ts_start); std::vector block = get_vector_pipe(connection); clock_gettime(CLOCK_REALTIME, &ts_stop); data_pipe << block.size() << " " << delta_t_ms(ts_start,ts_stop) << std::endl; } //////////////////////////// // measurement without pipe //////////////////////////// { clock_gettime(CLOCK_REALTIME, &ts_start); std::vector block = get_vector_array(proxy); clock_gettime(CLOCK_REALTIME, &ts_stop); data_array << block.size() << " " << delta_t_ms(ts_start,ts_stop) << std::endl; } } return 0; }