Commit ab10ae90 authored by Havoc Pennington's avatar Havoc Pennington

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()
parent 27b694f6
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()
2003-05-08 Havoc Pennington <hp@pobox.com>
* dbus/dbus-spawn.c: s/_exit/exit/ because it was keeping gcov
......
......@@ -292,9 +292,9 @@ connection_watch_callback (DBusWatch *watch,
void *data)
{
/* FIXME this can be done in dbus-mainloop.c
* if the code in activation.c for the babysitter
* watch handler is fixed.
*/
* if the code in activation.c for the babysitter
* watch handler is fixed.
*/
#if 0
_dbus_verbose ("Calling handle_watch\n");
......
......@@ -205,6 +205,28 @@ AC_SUBST(DBUS_HAVE_INT64)
## byte order
AC_C_BIGENDIAN
#### Atomic integers (checks by Sebastian Wilhelmi for GLib)
AC_MSG_CHECKING([whether to use inline assembler routines for atomic integers])
have_atomic_inc=no
if test x"$GCC" = xyes; then
case $host_cpu in
i386)
AC_MSG_RESULT([no])
;;
i?86)
AC_MSG_RESULT([i486])
AC_DEFINE_UNQUOTED(DBUS_USE_ATOMIC_INT_486, 1, [Use atomic integer implementation for 486])
have_atomic_inc=yes
;;
*)
AC_MSG_RESULT([no])
;;
esac
fi
if test x$have_atomic_inc = xyes ; then
AC_DEFINE_UNQUOTED(DBUS_HAVE_ATOMIC_INT, 1, [Some atomic integer implementation present])
fi
#### Various functions
AC_CHECK_LIB(socket,socket)
AC_CHECK_LIB(nsl,gethostbyname)
......@@ -598,6 +620,7 @@ else
TEST_SOCKET_DIR=$DEFAULT_SOCKET_DIR
fi
AC_SUBST(TEST_SOCKET_DIR)
AC_DEFINE_UNQUOTED(DBUS_TEST_SOCKET_DIR, "$TEST_SOCKET_DIR", [Where to put test sockets])
if ! test -z "$with_session_socket_dir" ; then
DBUS_SESSION_SOCKET_DIR="$with_session_socket_dir"
......
......@@ -39,9 +39,6 @@
* is first established, and also manage any encryption used over a
* connection.
*
* The file doc/dbus-sasl-profile.txt documents the network protocol
* used for authentication.
*
* @todo some SASL profiles require sending the empty string as a
* challenge/response, but we don't currently allow that in our
* protocol.
......
This diff is collapsed.
......@@ -190,7 +190,6 @@ _dbus_verbose_real (const char *format,
{
va_list args;
static dbus_bool_t verbose = TRUE;
static unsigned long pid;
/* things are written a bit oddly here so that
* in the non-verbose case we just have the one
......@@ -202,13 +201,12 @@ _dbus_verbose_real (const char *format,
if (!verbose_initted)
{
verbose = _dbus_getenv ("DBUS_VERBOSE") != NULL;
pid = _dbus_getpid ();
verbose_initted = TRUE;
if (!verbose)
return;
}
fprintf (stderr, "%lu: ", pid);
fprintf (stderr, "%lu: ", _dbus_getpid ());
va_start (args, format);
vfprintf (stderr, format, args);
......
......@@ -81,7 +81,7 @@ typedef struct
*/
struct DBusMessage
{
dbus_atomic_t refcount; /**< Reference count */
volatile dbus_atomic_t refcount; /**< Reference count */
DBusString header; /**< Header network data, stored
* separately from body so we can
......@@ -1134,7 +1134,7 @@ dbus_message_copy (const DBusMessage *message)
void
dbus_message_ref (DBusMessage *message)
{
dbus_atomic_t refcount;
volatile dbus_atomic_t refcount;
_dbus_return_if_fail (message != NULL);
......@@ -1163,7 +1163,7 @@ free_size_counter (void *element,
void
dbus_message_unref (DBusMessage *message)
{
dbus_atomic_t refcount;
volatile dbus_atomic_t refcount;
_dbus_return_if_fail (message != NULL);
......
......@@ -31,6 +31,7 @@
#include <signal.h>
#include <sys/wait.h>
#include <errno.h>
#include <stdlib.h>
/**
* @addtogroup DBusInternalsUtils
......
......@@ -1790,9 +1790,25 @@ _dbus_getgid (void)
return getgid ();
}
_DBUS_DEFINE_GLOBAL_LOCK (atomic);
#ifdef DBUS_USE_ATOMIC_INT_486
/* Taken from CVS version 1.7 of glibc's sysdeps/i386/i486/atomicity.h */
/* Since the asm stuff here is gcc-specific we go ahead and use "inline" also */
static inline dbus_atomic_t
atomic_exchange_and_add (volatile dbus_atomic_t *atomic,
volatile dbus_atomic_t val)
{
register dbus_atomic_t result;
__asm__ __volatile__ ("lock; xaddl %0,%1"
: "=r" (result), "=m" (*atomic)
: "0" (val), "m" (*atomic));
return result;
}
#endif
/**
* Atomically increments an integer
*
......@@ -1802,8 +1818,11 @@ _DBUS_DEFINE_GLOBAL_LOCK (atomic);
* @todo implement arch-specific faster atomic ops
*/
dbus_atomic_t
_dbus_atomic_inc (dbus_atomic_t *atomic)
_dbus_atomic_inc (volatile dbus_atomic_t *atomic)
{
#ifdef DBUS_USE_ATOMIC_INT_486
return atomic_exchange_and_add (atomic, 1);
#else
dbus_atomic_t res;
_DBUS_LOCK (atomic);
......@@ -1811,6 +1830,7 @@ _dbus_atomic_inc (dbus_atomic_t *atomic)
res = *atomic;
_DBUS_UNLOCK (atomic);
return res;
#endif
}
/**
......@@ -1822,8 +1842,11 @@ _dbus_atomic_inc (dbus_atomic_t *atomic)
* @todo implement arch-specific faster atomic ops
*/
dbus_atomic_t
_dbus_atomic_dec (dbus_atomic_t *atomic)
_dbus_atomic_dec (volatile dbus_atomic_t *atomic)
{
#ifdef DBUS_USE_ATOMIC_INT_486
return atomic_exchange_and_add (atomic, -1);
#else
dbus_atomic_t res;
_DBUS_LOCK (atomic);
......@@ -1831,6 +1854,7 @@ _dbus_atomic_dec (dbus_atomic_t *atomic)
res = *atomic;
_DBUS_UNLOCK (atomic);
return res;
#endif
}
/**
......
......@@ -169,10 +169,10 @@ unsigned long _dbus_getpid (void);
dbus_uid_t _dbus_getuid (void);
dbus_gid_t _dbus_getgid (void);
typedef int dbus_atomic_t;
typedef dbus_int32_t dbus_atomic_t;
dbus_atomic_t _dbus_atomic_inc (dbus_atomic_t *atomic);
dbus_atomic_t _dbus_atomic_dec (dbus_atomic_t *atomic);
dbus_atomic_t _dbus_atomic_inc (volatile dbus_atomic_t *atomic);
dbus_atomic_t _dbus_atomic_dec (volatile dbus_atomic_t *atomic);
#define _DBUS_POLLIN 0x0001 /* There is data to read */
#define _DBUS_POLLPRI 0x0002 /* There is urgent data to read */
......
......@@ -458,7 +458,7 @@ dbus_fake_condvar_free (DBusCondVar *cond)
static void
dbus_fake_condvar_wait (DBusCondVar *cond,
DBusMutex *mutex)
DBusMutex *mutex)
{
}
......
......@@ -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
/* -*- 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;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment