/* -*- mode: C; c-file-style: "gnu" -*- */ /* test-profile.c Program that does basic message-response for timing; doesn't really use glib bindings * * Copyright (C) 2003, 2004 Red Hat Inc. * * Licensed under the Academic Free License version 2.1 * * 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 2 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, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #ifndef HAVE_SOCKLEN_T #define socklen_t int #endif #define _DBUS_ZERO(object) (memset (&(object), '\0', sizeof ((object)))) #define _DBUS_MAX_SUN_PATH_LENGTH 99 /* Note that if you set threads > 1 you get a bogus profile since the * clients start blocking on the server, so the client write() will go * higher in the profile the larger the number of threads. */ #define N_CLIENT_THREADS 1 /* It seems like at least 750000 or so iterations reduces the variability to sane levels */ #define N_ITERATIONS 2000 #define N_PROGRESS_UPDATES 20 /* Don't make PAYLOAD_SIZE too huge because it gets used as a static buffer size */ #define PAYLOAD_SIZE 0 #define ECHO_SERVICE "org.freedesktop.EchoTestServer" #define ECHO_PATH "/org/freedesktop/EchoTest" #define ECHO_INTERFACE "org.freedesktop.EchoTest" #define ECHO_PING_METHOD "Ping" static const char *messages_address; static const char *plain_sockets_address; static unsigned char *payload; static int echo_call_size; static int echo_return_size; typedef struct ProfileRunVTable ProfileRunVTable; typedef struct { const ProfileRunVTable *vtable; int iterations; GMainLoop *loop; } ClientData; typedef struct { const ProfileRunVTable *vtable; int handled; GMainLoop *loop; int n_clients; } ServerData; struct ProfileRunVTable { const char *name; gboolean fake_malloc_overhead; void* (* init_server) (ServerData *sd); void (* stop_server) (ServerData *sd, void *server); void* (* client_thread_func) (void *data); /* Data has to be the vtable */ /* this is so different runs show up in the profiler with * different backtrace */ void (* main_loop_run_func) (GMainLoop *loop); }; /* Note, this is all crack-a-rific; it isn't using DBusGProxy and thus is * a major pain */ static void send_echo_method_call (DBusConnection *connection) { DBusMessage *message; const char *hello = "Hello World!"; dbus_int32_t i32 = 123456; message = dbus_message_new_method_call (ECHO_SERVICE, ECHO_PATH, ECHO_INTERFACE, ECHO_PING_METHOD); dbus_message_append_args (message, DBUS_TYPE_STRING, &hello, DBUS_TYPE_INT32, &i32, #if PAYLOAD_SIZE > 0 DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &payload, PAYLOAD_SIZE, #endif DBUS_TYPE_INVALID); dbus_connection_send (connection, message, NULL); dbus_message_unref (message); dbus_connection_flush (connection); } static void send_echo_method_return (DBusConnection *connection, DBusMessage *call_message) { DBusMessage *message; message = dbus_message_new_method_return (call_message); dbus_connection_send (connection, message, NULL); dbus_message_unref (message); dbus_connection_flush (connection); } static DBusHandlerResult with_or_without_bus_client_filter (DBusConnection *connection, DBusMessage *message, ClientData *cd) { if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected")) { g_printerr ("Client thread disconnected\n"); exit (1); } else if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_METHOD_RETURN) { cd->iterations += 1; if (cd->iterations >= N_ITERATIONS) { g_printerr ("\nCompleted %d iterations\n", N_ITERATIONS); g_main_loop_quit (cd->loop); } else if (cd->iterations % (N_ITERATIONS/N_PROGRESS_UPDATES) == 0) { g_printerr ("%d%% ", (int) (cd->iterations/(double)N_ITERATIONS * 100.0)); } send_echo_method_call (connection); return DBUS_HANDLER_RESULT_HANDLED; } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static DBusHandlerResult no_bus_client_filter (DBusConnection *connection, DBusMessage *message, void *user_data) { ClientData *cd = user_data; return with_or_without_bus_client_filter (connection, message, cd); } static void* no_bus_thread_func (void *data) { DBusError error; GMainContext *context; DBusConnection *connection; ClientData cd; g_printerr ("Starting client thread %p\n", g_thread_self()); dbus_error_init (&error); connection = dbus_connection_open_private (messages_address, &error); if (connection == NULL) { g_printerr ("could not open connection: %s\n", error.message); dbus_error_free (&error); exit (1); } context = g_main_context_new (); cd.iterations = 1; cd.loop = g_main_loop_new (context, FALSE); if (!dbus_connection_add_filter (connection, no_bus_client_filter, &cd, NULL)) g_error ("no memory"); dbus_connection_setup_with_g_main (connection, context); g_printerr ("Client thread sending message to prime pingpong\n"); send_echo_method_call (connection); g_printerr ("Client thread sent message\n"); g_printerr ("Client thread entering main loop\n"); g_main_loop_run (cd.loop); g_printerr ("Client thread %p exiting main loop\n", g_thread_self()); dbus_connection_close (connection); g_main_loop_unref (cd.loop); g_main_context_unref (context); return NULL; } static DBusHandlerResult no_bus_server_filter (DBusConnection *connection, DBusMessage *message, void *user_data) { ServerData *sd = user_data; if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected")) { g_printerr ("Client disconnected from server\n"); sd->n_clients -= 1; if (sd->n_clients == 0) g_main_loop_quit (sd->loop); } else if (dbus_message_is_method_call (message, ECHO_INTERFACE, ECHO_PING_METHOD)) { sd->handled += 1; send_echo_method_return (connection, message); return DBUS_HANDLER_RESULT_HANDLED; } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static void no_bus_new_connection_callback (DBusServer *server, DBusConnection *new_connection, void *user_data) { ServerData *sd = user_data; dbus_connection_ref (new_connection); dbus_connection_setup_with_g_main (new_connection, NULL); if (!dbus_connection_add_filter (new_connection, no_bus_server_filter, sd, NULL)) g_error ("no memory"); sd->n_clients += 1; /* FIXME we leak the handler */ } static void* no_bus_init_server (ServerData *sd) { DBusServer *server; DBusError error; dbus_error_init (&error); server = dbus_server_listen ("unix:tmpdir="DBUS_TEST_SOCKET_DIR, &error); if (server == NULL) { g_printerr ("Could not start server: %s\n", error.message); exit (1); } messages_address = dbus_server_get_address (server); dbus_server_set_new_connection_function (server, no_bus_new_connection_callback, sd, NULL); dbus_server_setup_with_g_main (server, NULL); return server; } static void no_bus_stop_server (ServerData *sd, void *server) { dbus_server_disconnect (server); dbus_server_unref (server); } static void no_bus_main_loop_run (GMainLoop *loop) { g_main_loop_run (loop); } static const ProfileRunVTable no_bus_vtable = { "dbus direct without bus", FALSE, no_bus_init_server, no_bus_stop_server, no_bus_thread_func, no_bus_main_loop_run }; typedef struct { const ProfileRunVTable *vtable; ServerData *sd; GHashTable *client_names; DBusConnection *connection; } WithBusServer; static DBusHandlerResult with_bus_client_filter (DBusConnection *connection, DBusMessage *message, void *user_data) { ClientData *cd = user_data; return with_or_without_bus_client_filter (connection, message, cd); } static void* with_bus_thread_func (void *data) { DBusError error; DBusConnection *connection; ClientData cd; const char *address; GMainContext *context; g_printerr ("Starting client thread %p\n", g_thread_self()); address = g_getenv ("DBUS_SESSION_BUS_ADDRESS"); if (address == NULL) { g_printerr ("DBUS_SESSION_BUS_ADDRESS not set\n"); exit (1); } dbus_error_init (&error); connection = dbus_connection_open_private (address, &error); if (connection == NULL) { g_printerr ("could not open connection to bus: %s\n", error.message); dbus_error_free (&error); exit (1); } if (!dbus_bus_register (connection, &error)) { g_printerr ("could not register with bus: %s\n", error.message); dbus_error_free (&error); exit (1); } context = g_main_context_new (); cd.iterations = 1; cd.loop = g_main_loop_new (context, FALSE); if (!dbus_connection_add_filter (connection, with_bus_client_filter, &cd, NULL)) g_error ("no memory"); dbus_connection_setup_with_g_main (connection, context); g_printerr ("Client thread sending message to prime pingpong\n"); send_echo_method_call (connection); g_printerr ("Client thread sent message\n"); g_printerr ("Client thread entering main loop\n"); g_main_loop_run (cd.loop); g_printerr ("Client thread %p exiting main loop\n", g_thread_self()); dbus_connection_close (connection); g_main_loop_unref (cd.loop); g_main_context_unref (context); return NULL; } static DBusHandlerResult with_bus_server_filter (DBusConnection *connection, DBusMessage *message, void *user_data) { WithBusServer *server = user_data; if (dbus_message_is_signal (message, DBUS_INTERFACE_LOCAL, "Disconnected")) { g_printerr ("Server disconnected from message bus\n"); exit (1); } else if (dbus_message_has_sender (message, DBUS_SERVICE_DBUS) && dbus_message_is_signal (message, DBUS_INTERFACE_DBUS, "NameOwnerChanged")) { const char *name, *old_owner, *new_owner; DBusError error; name = NULL; old_owner = NULL; new_owner = NULL; dbus_error_init (&error); if (!dbus_message_get_args (message, &error, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &old_owner, DBUS_TYPE_STRING, &new_owner, DBUS_TYPE_INVALID)) { g_printerr ("dbus_message_get_args(): %s\n", error.message); exit (1); } if (g_hash_table_lookup (server->client_names, name) && *old_owner != '\0' && *new_owner == '\0') { g_hash_table_remove (server->client_names, name); server->sd->n_clients -= 1; if (server->sd->n_clients == 0) g_main_loop_quit (server->sd->loop); } } else if (dbus_message_is_method_call (message, ECHO_INTERFACE, ECHO_PING_METHOD)) { const char *sender; sender = dbus_message_get_sender (message); if (!g_hash_table_lookup (server->client_names, sender)) { g_printerr ("First message from new client %s on bus\n", sender); g_hash_table_replace (server->client_names, g_strdup (sender), GINT_TO_POINTER (1)); server->sd->n_clients += 1; } server->sd->handled += 1; send_echo_method_return (connection, message); return DBUS_HANDLER_RESULT_HANDLED; } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } static void* with_bus_init_server (ServerData *sd) { DBusGConnection *gconnection; DBusConnection *connection; GError *gerror; const char *s; WithBusServer *server; char *rule; server = g_new0 (WithBusServer, 1); server->vtable = sd->vtable; server->sd = sd; s = g_getenv ("DBUS_TEST_GLIB_RUN_TEST_SCRIPT"); if (s == NULL || *s != '1') { g_printerr ("You have to run with_bus mode with the run-test.sh script\n"); exit (1); } /* Note that we use the standard global bus connection for the * server, and the clients open their own connections so they can * have their own main loops and because I'm not sure "talking to * yourself" really works yet */ gerror = NULL; gconnection = dbus_g_bus_get (DBUS_BUS_SESSION, &gerror); if (gconnection == NULL) { g_printerr ("could not open connection to bus: %s\n", gerror->message); g_error_free (gerror); exit (1); } server->client_names = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); connection = dbus_g_connection_get_connection (gconnection); dbus_bus_request_name (connection, ECHO_SERVICE, 0, NULL); /* ignore errors because we suck */ rule = g_strdup_printf ("type='signal',sender='%s',member='%s'", DBUS_SERVICE_DBUS, "NameOwnerChanged"); /* ignore errors because we suck */ dbus_bus_add_match (connection, rule, NULL); g_free (rule); if (!dbus_connection_add_filter (connection, with_bus_server_filter, server, NULL)) g_error ("no memory"); server->connection = connection; server->client_names = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); return server; } static void with_bus_stop_server (ServerData *sd, void *serverv) { WithBusServer *server = serverv; dbus_connection_remove_filter (server->connection, with_bus_server_filter, server); g_hash_table_destroy (server->client_names); dbus_connection_unref (server->connection); g_free (server); } static void with_bus_main_loop_run (GMainLoop *loop) { g_main_loop_run (loop); } static const ProfileRunVTable with_bus_vtable = { "routing via a bus", FALSE, with_bus_init_server, with_bus_stop_server, with_bus_thread_func, with_bus_main_loop_run }; typedef struct { const ProfileRunVTable *vtable; int listen_fd; ServerData *sd; unsigned int source_id; } PlainSocketServer; static void read_and_drop_on_floor (int fd, int count, gboolean fake_malloc_overhead) { int bytes_read; int val; char *buf; char *allocated; char not_allocated[512+PAYLOAD_SIZE]; g_assert (count < (int) sizeof(not_allocated)); if (fake_malloc_overhead) { allocated = g_malloc (count); buf = allocated; } else { allocated = NULL; buf = not_allocated; } bytes_read = 0; while (bytes_read < count) { again: val = read (fd, buf + bytes_read, count - bytes_read); if (val < 0) { if (errno == EINTR) goto again; else { g_printerr ("read() failed thread %p: %s\n", g_thread_self(), strerror (errno)); exit (1); } } else { bytes_read += val; } } if (fake_malloc_overhead) g_free (allocated); #if 0 g_printerr ("%p read %d bytes from fd %d\n", g_thread_self(), bytes_read, fd); #endif } static void write_junk (int fd, int count, gboolean fake_malloc_overhead) { int bytes_written; int val; char *buf; char *allocated; char not_allocated[512+PAYLOAD_SIZE] = { '\0', }; g_assert (count < (int) sizeof(not_allocated)); if (fake_malloc_overhead) { int i; allocated = g_malloc (count); buf = allocated; /* Write some stuff into the allocated buffer to simulate * creating some sort of data */ i = 0; while (i < count) { allocated[i] = (char) i; ++i; } } else { allocated = NULL; buf = not_allocated; } bytes_written = 0; while (bytes_written < count) { again: val = write (fd, buf + bytes_written, count - bytes_written); if (val < 0) { if (errno == EINTR) goto again; else { g_printerr ("write() failed thread %p: %s\n", g_thread_self(), strerror (errno)); exit (1); } } else { bytes_written += val; } } if (fake_malloc_overhead) g_free (allocated); #if 0 g_printerr ("%p wrote %d bytes to fd %d\n", g_thread_self(), bytes_written, fd); #endif } static gboolean plain_sockets_talk_to_client_watch (GIOChannel *source, GIOCondition condition, gpointer data) { PlainSocketServer *server = data; int client_fd = g_io_channel_unix_get_fd (source); if (condition & G_IO_HUP) { g_printerr ("Client disconnected from server\n"); server->sd->n_clients -= 1; if (server->sd->n_clients == 0) g_main_loop_quit (server->sd->loop); return FALSE; /* remove watch */ } else if (condition & G_IO_IN) { server->sd->handled += 1; read_and_drop_on_floor (client_fd, echo_call_size, server->vtable->fake_malloc_overhead); write_junk (client_fd, echo_return_size, server->vtable->fake_malloc_overhead); } else { g_printerr ("Unexpected IO condition in server thread\n"); exit (1); } return TRUE; } static gboolean plain_sockets_new_client_watch (GIOChannel *source, GIOCondition condition, gpointer data) { int client_fd; struct sockaddr addr; socklen_t addrlen; GIOChannel *channel; PlainSocketServer *server = data; if (!(condition & G_IO_IN)) { g_printerr ("Unexpected IO condition on server socket\n"); exit (1); } addrlen = sizeof (addr); retry: client_fd = accept (server->listen_fd, &addr, &addrlen); if (client_fd < 0) { if (errno == EINTR) goto retry; else { g_printerr ("Failed to accept() connection from client: %s\n", strerror (errno)); exit (1); } } channel = g_io_channel_unix_new (client_fd); g_io_add_watch (channel, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL | G_IO_PRI, plain_sockets_talk_to_client_watch, server); g_io_channel_unref (channel); server->sd->n_clients += 1; return TRUE; } static void* plain_sockets_init_server (ServerData *sd) { PlainSocketServer *server; struct sockaddr_un addr; static char path[] = "/tmp/dbus-test-profile-XXXXXX"; char *p; GIOChannel *channel; server = g_new0 (PlainSocketServer, 1); server->sd = sd; server->vtable = sd->vtable; /* for convenience */ p = path; while (*p) { if (*p == 'X') *p = 'a' + (int) (26.0*rand()/(RAND_MAX+1.0)); ++p; } g_printerr ("Socket is %s\n", path); server->listen_fd = socket (PF_UNIX, SOCK_STREAM, 0); if (server->listen_fd < 0) { g_printerr ("Failed to create socket: %s", strerror (errno)); exit (1); } _DBUS_ZERO (addr); addr.sun_family = AF_UNIX; #ifdef HAVE_ABSTRACT_SOCKETS /* remember that abstract names aren't nul-terminated so we rely * on sun_path being filled in with zeroes above. */ addr.sun_path[0] = '\0'; /* this is what says "use abstract" */ strncpy (&addr.sun_path[1], path, _DBUS_MAX_SUN_PATH_LENGTH - 2); /* _dbus_verbose_bytes (addr.sun_path, sizeof (addr.sun_path)); */ #else /* HAVE_ABSTRACT_SOCKETS */ { struct stat sb; if (stat (path, &sb) == 0 && S_ISSOCK (sb.st_mode)) unlink (path); } strncpy (addr.sun_path, path, _DBUS_MAX_SUN_PATH_LENGTH - 1); #endif /* ! HAVE_ABSTRACT_SOCKETS */ if (bind (server->listen_fd, (struct sockaddr*) &addr, sizeof (addr)) < 0) { g_printerr ("Failed to bind socket \"%s\": %s", path, strerror (errno)); exit (1); } if (listen (server->listen_fd, 30 /* backlog */) < 0) { g_printerr ("Failed to listen on socket \"%s\": %s", path, strerror (errno)); exit (1); } plain_sockets_address = path; channel = g_io_channel_unix_new (server->listen_fd); server->source_id = g_io_add_watch (channel, G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL | G_IO_PRI, plain_sockets_new_client_watch, server); g_io_channel_unref (channel); return server; } static void plain_sockets_stop_server (ServerData *sd, void *server_v) { PlainSocketServer *server = server_v; g_source_remove (server->source_id); close (server->listen_fd); g_free (server); { struct stat sb; if (stat (plain_sockets_address, &sb) == 0 && S_ISSOCK (sb.st_mode)) unlink (plain_sockets_address); } } static gboolean plain_sockets_client_side_watch (GIOChannel *source, GIOCondition condition, gpointer data) { ClientData *cd = data; int fd = g_io_channel_unix_get_fd (source); if (condition & G_IO_IN) { read_and_drop_on_floor (fd, echo_return_size, cd->vtable->fake_malloc_overhead); } else if (condition & G_IO_OUT) { cd->iterations += 1; if (cd->iterations >= N_ITERATIONS) { g_printerr ("\nCompleted %d iterations\n", N_ITERATIONS); g_main_loop_quit (cd->loop); } else if (cd->iterations % (N_ITERATIONS/N_PROGRESS_UPDATES) == 0) { g_printerr ("%d%% ", (int) (cd->iterations/(double)N_ITERATIONS * 100.0)); } write_junk (fd, echo_call_size, cd->vtable->fake_malloc_overhead); } else { g_printerr ("Unexpected IO condition in client thread\n"); exit (1); } return TRUE; } static void* plain_sockets_thread_func (void *data) { GMainContext *context; ClientData cd; int fd; struct sockaddr_un addr; GIOChannel *channel; GSource *gsource; g_printerr ("Starting client thread %p\n", g_thread_self()); fd = socket (PF_UNIX, SOCK_STREAM, 0); if (fd < 0) { g_printerr ("Failed to create socket: %s", strerror (errno)); exit (1); } _DBUS_ZERO (addr); addr.sun_family = AF_UNIX; #ifdef HAVE_ABSTRACT_SOCKETS /* remember that abstract names aren't nul-terminated so we rely * on sun_path being filled in with zeroes above. */ addr.sun_path[0] = '\0'; /* this is what says "use abstract" */ strncpy (&addr.sun_path[1], plain_sockets_address, _DBUS_MAX_SUN_PATH_LENGTH - 2); /* _dbus_verbose_bytes (addr.sun_path, sizeof (addr.sun_path)); */ #else /* HAVE_ABSTRACT_SOCKETS */ strncpy (addr.sun_path, plain_sockets_address, _DBUS_MAX_SUN_PATH_LENGTH - 1); #endif /* ! HAVE_ABSTRACT_SOCKETS */ if (connect (fd, (struct sockaddr*) &addr, sizeof (addr)) < 0) { g_printerr ("Failed to connect to socket %s: %s", plain_sockets_address, strerror (errno)); exit (1); } context = g_main_context_new (); cd.iterations = 1; cd.loop = g_main_loop_new (context, FALSE); cd.vtable = data; channel = g_io_channel_unix_new (fd); gsource = g_io_create_watch (channel, G_IO_IN | G_IO_OUT | G_IO_ERR | G_IO_HUP | G_IO_NVAL | G_IO_PRI); g_source_set_callback (gsource, (GSourceFunc)plain_sockets_client_side_watch, &cd, NULL); g_source_attach (gsource, context); g_io_channel_unref (channel); g_printerr ("Client thread writing to prime pingpong\n"); write_junk (fd, echo_call_size, cd.vtable->fake_malloc_overhead); g_printerr ("Client thread done writing primer\n"); g_printerr ("Client thread entering main loop\n"); g_main_loop_run (cd.loop); g_printerr ("Client thread %p exiting main loop\n", g_thread_self()); g_source_destroy (gsource); close (fd); g_main_loop_unref (cd.loop); g_main_context_unref (context); return NULL; } static void plain_sockets_main_loop_run (GMainLoop *loop) { g_main_loop_run (loop); } static const ProfileRunVTable plain_sockets_vtable = { "plain sockets", FALSE, plain_sockets_init_server, plain_sockets_stop_server, plain_sockets_thread_func, plain_sockets_main_loop_run }; static const ProfileRunVTable plain_sockets_with_malloc_vtable = { "plain sockets with malloc overhead", TRUE, plain_sockets_init_server, plain_sockets_stop_server, plain_sockets_thread_func, plain_sockets_main_loop_run }; static double do_profile_run (const ProfileRunVTable *vtable) { GTimer *timer; int i; double secs; ServerData sd; void *server; g_printerr ("Profiling %s\n", vtable->name); sd.handled = 0; sd.n_clients = 0; sd.loop = g_main_loop_new (NULL, FALSE); sd.vtable = vtable; server = (* vtable->init_server) (&sd); for (i = 0; i < N_CLIENT_THREADS; i++) { g_thread_create (vtable->client_thread_func, (void*) vtable, FALSE, NULL); } timer = g_timer_new (); g_printerr ("Server thread %p entering main loop\n", g_thread_self()); (* vtable->main_loop_run_func) (sd.loop); g_printerr ("Server thread %p exiting main loop\n", g_thread_self()); secs = g_timer_elapsed (timer, NULL); g_timer_destroy (timer); g_printerr ("%s: %g seconds, %d round trips, %f seconds per pingpong\n", vtable->name, secs, sd.handled, secs/sd.handled); (* vtable->stop_server) (&sd, server); g_main_loop_unref (sd.loop); return secs; } static void print_result (const ProfileRunVTable *vtable, double seconds, double baseline) { g_printerr (" %g times slower for %s (%g seconds, %f per iteration)\n", seconds/baseline, vtable->name, seconds, seconds / N_ITERATIONS); } int main (int argc, char *argv[]) { g_thread_init (NULL); dbus_g_thread_init (); #ifndef DBUS_DISABLE_ASSERT g_printerr ("You should probably --disable-asserts before you profile as they have noticeable overhead\n"); #endif #if DBUS_ENABLE_VERBOSE_MODE g_printerr ("You should probably --disable-verbose-mode before you profile as verbose has noticeable overhead\n"); #endif payload = g_malloc (PAYLOAD_SIZE); /* The actual size of the DBusMessage on the wire, as of Nov 23 2004, * without the payload */ echo_call_size = 140 + PAYLOAD_SIZE; echo_return_size = 32; if (argc > 1 && strcmp (argv[1], "plain_sockets") == 0) do_profile_run (&plain_sockets_vtable); else if (argc > 1 && strcmp (argv[1], "plain_sockets_with_malloc") == 0) do_profile_run (&plain_sockets_with_malloc_vtable); else if (argc > 1 && strcmp (argv[1], "no_bus") == 0) do_profile_run (&no_bus_vtable); else if (argc > 1 && strcmp (argv[1], "with_bus") == 0) do_profile_run (&with_bus_vtable); else if (argc > 1 && strcmp (argv[1], "all") == 0) { double e1, e2, e3, e4; e1 = do_profile_run (&plain_sockets_vtable); e2 = do_profile_run (&plain_sockets_with_malloc_vtable); e3 = do_profile_run (&no_bus_vtable); e4 = do_profile_run (&with_bus_vtable); g_printerr ("Baseline plain sockets time %g seconds for %d iterations\n", e1, N_ITERATIONS); print_result (&plain_sockets_vtable, e1, e1); print_result (&plain_sockets_with_malloc_vtable, e2, e1); print_result (&no_bus_vtable, e3, e1); print_result (&with_bus_vtable, e4, e1); } else { g_printerr ("Specify profile type plain_sockets, plain_sockets_with_malloc, no_bus, with_bus, all\n"); exit (1); } /* Make valgrind happy */ dbus_shutdown (); return 0; }