From ab10ae902d8aa7c2b98fd080a7458127b1b8e648 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Sun, 11 May 2003 07:59:08 +0000 Subject: 2003-05-11 Havoc Pennington Write a "test-profile" that does echo client-server with threads; profile reveals lock contention, memcpy/realloc of buffers, and UTF-8 validation as hot spots. 20% of lock contention eliminated with dbus_atomic_inc/dec implementation on x86. Much remaining contention is global mempool locks for GList and DBusList. * dbus/dbus-sysdeps.c (_dbus_atomic_inc, _dbus_atomic_dec): add x86 implementation * dbus/dbus-connection.c (struct DBusConnection): use dbus_atomic_t for the reference count * dbus/dbus-message.c (struct DBusMessage): declare dbus_atomic_t values as volatile * configure.in: code to detect ability to use atomic integer operations in assembly, from GLib patch * dbus/dbus-internals.c (_dbus_verbose_real): call getpid every time, tired of it being wrong in threads and forked processes * glib/test-profile.c: a little program to bounce messages back and forth between threads and eat CPU * dbus/dbus-connection.c: add debug spew macros for debugging thread locks; include config.h at top; fix deadlock in dbus_connection_flush() --- glib/Makefile.am | 33 +++++--- glib/test-profile.c | 215 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 237 insertions(+), 11 deletions(-) create mode 100644 glib/test-profile.c (limited to 'glib') diff --git a/glib/Makefile.am b/glib/Makefile.am index d9edf6f5..ebdb932f 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -13,21 +13,11 @@ libdbus_glib_1_la_SOURCES = \ libdbus_glib_1_la_LIBADD= $(DBUS_GLIB_LIBS) $(top_builddir)/dbus/libdbus-1.la - if DBUS_BUILD_TESTS if HAVE_GLIB_THREADS - THREAD_APPS=test-thread-server test-thread-client -endif - -noinst_PROGRAMS= test-dbus-glib $(THREAD_APPS) - -test_dbus_glib_SOURCES= \ - test-dbus-glib.c - -test_dbus_glib_LDADD= $(top_builddir)/glib/libdbus-glib-1.la +THREAD_APPS=test-thread-server test-thread-client test-profile -if HAVE_GLIB_THREADS test_thread_server_SOURCES= \ test-thread-server.c \ test-thread.h @@ -41,4 +31,25 @@ test_thread_client_SOURCES= \ test_thread_client_LDADD= $(DBUS_GLIB_THREADS_LIBS) $(top_builddir)/glib/libdbus-glib-1.la endif +noinst_PROGRAMS= test-dbus-glib $(THREAD_APPS) + +test_dbus_glib_SOURCES= \ + test-dbus-glib.c + +test_dbus_glib_LDADD= $(top_builddir)/glib/libdbus-glib-1.la + +else +### not building tests + +if HAVE_GLIB_THREADS +noinst_PROGRAMS=test-profile +endif + endif + +if HAVE_GLIB_THREADS +test_profile_SOURCES= \ + test-profile.c + +test_profile_LDADD= $(DBUS_GLIB_THREADS_LIBS) $(top_builddir)/glib/libdbus-glib-1.la +endif \ No newline at end of file diff --git a/glib/test-profile.c b/glib/test-profile.c new file mode 100644 index 00000000..6173f3a5 --- /dev/null +++ b/glib/test-profile.c @@ -0,0 +1,215 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* test-profile.c Program that does basic message-response for timing + * + * Copyright (C) 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * 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 "dbus-glib.h" +#include + +#define N_CLIENT_THREADS 1 +#define N_ITERATIONS 2000 +#define ECHO_MESSAGE "org.freedesktop.DBus.Test.EchoProfile" +static const char *address; + +static void +send_echo_message (DBusConnection *connection) +{ + DBusMessage *message; + + message = dbus_message_new (ECHO_MESSAGE, NULL); + dbus_message_append_args (message, + DBUS_TYPE_STRING, "Hello World!", + DBUS_TYPE_INT32, 123456, + DBUS_TYPE_INVALID); + dbus_connection_send (connection, message, NULL); + dbus_message_unref (message); + dbus_connection_flush (connection); +} + +static DBusHandlerResult +client_filter (DBusMessageHandler *handler, + DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + int *iterations = user_data; + + if (dbus_message_has_name (message, DBUS_MESSAGE_LOCAL_DISCONNECT)) + { + g_printerr ("Client thread disconnected\n"); + exit (1); + } + else if (dbus_message_has_name (message, + ECHO_MESSAGE)) + { + *iterations += 1; + send_echo_message (connection); + if (*iterations > N_ITERATIONS) + { + g_print ("Completed %d iterations\n", N_ITERATIONS); + exit (0); + } + } + + return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; +} + +static void* +thread_func (void *data) +{ + DBusError error; + GMainContext *context; + GMainLoop *loop; + DBusMessageHandler *handler; + DBusConnection *connection; + int iterations; + + g_printerr ("Starting client thread\n"); + + dbus_error_init (&error); + connection = dbus_connection_open (address, &error); + if (connection == NULL) + { + g_printerr ("could not open connection: %s\n", error.message); + dbus_error_free (&error); + exit (1); + } + + iterations = 0; + + handler = dbus_message_handler_new (client_filter, + &iterations, NULL); + + if (!dbus_connection_add_filter (connection, + handler)) + g_error ("no memory"); + + /* FIXME we leak the handler */ + + context = g_main_context_new (); + loop = g_main_loop_new (context, FALSE); + + dbus_connection_setup_with_g_main (connection, context); + + g_printerr ("Client thread sending message to prime pingpong\n"); + send_echo_message (connection); + g_printerr ("Client thread sent message\n"); + + g_printerr ("Client thread entering main loop\n"); + g_main_loop_run (loop); + g_printerr ("Client thread exiting main loop\n"); + + g_main_loop_unref (loop); + g_main_context_unref (context); + + return NULL; +} + +static DBusHandlerResult +server_filter (DBusMessageHandler *handler, + DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + if (dbus_message_has_name (message, DBUS_MESSAGE_LOCAL_DISCONNECT)) + { + g_printerr ("Server thread disconnected\n"); + exit (1); + } + else if (dbus_message_has_name (message, + ECHO_MESSAGE)) + { + send_echo_message (connection); + } + + return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; +} + +static void +new_connection_callback (DBusServer *server, + DBusConnection *new_connection, + void *user_data) +{ + DBusMessageHandler *handler; + + dbus_connection_ref (new_connection); + dbus_connection_setup_with_g_main (new_connection, NULL); + + handler = dbus_message_handler_new (server_filter, + NULL, NULL); + + if (!dbus_connection_add_filter (new_connection, + handler)) + g_error ("no memory"); + + + /* FIXME we leak the handler */ +} + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + DBusError error; + DBusServer *server; + int i; + + g_thread_init (NULL); + dbus_gthread_init (); + + 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); + return 1; + } + + address = dbus_server_get_address (server); + + dbus_server_set_new_connection_function (server, + new_connection_callback, + NULL, NULL); + + loop = g_main_loop_new (NULL, FALSE); + + dbus_server_setup_with_g_main (server, NULL); + + for (i = 0; i < N_CLIENT_THREADS; i++) + { + g_thread_create (thread_func, NULL, FALSE, NULL); + } + + g_printerr ("Server thread entering main loop\n"); + g_main_loop_run (loop); + g_printerr ("Server thread exiting main loop\n"); + + dbus_server_unref (server); + + g_main_loop_unref (loop); + + return 0; +} + -- cgit