summaryrefslogtreecommitdiffstats
path: root/glib
diff options
context:
space:
mode:
authorHavoc Pennington <hp@redhat.com>2003-05-11 07:59:08 +0000
committerHavoc Pennington <hp@redhat.com>2003-05-11 07:59:08 +0000
commitab10ae902d8aa7c2b98fd080a7458127b1b8e648 (patch)
treeb566d610ee13aa1a4ab9013eb7d19eb3dd7ad1c8 /glib
parent27b694f6e109c78c633ddb8d96f524e46e536f4e (diff)
2003-05-11 Havoc Pennington <hp@pobox.com>
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()
Diffstat (limited to 'glib')
-rw-r--r--glib/Makefile.am33
-rw-r--r--glib/test-profile.c215
2 files changed, 237 insertions, 11 deletions
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 <config.h>
+#include <glib.h>
+#include "dbus-glib.h"
+#include <stdlib.h>
+
+#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;
+}
+