Benchmark for



A few weeks back I promised Tim that I would come up with more
credible numbers for

        http://bugzilla.gnome.org/show_bug.cgi?id=121027

which was previously discussed here

        http://mail.gnome.org/archives/gtk-devel-list/2003-September/msg00049.html

So here is a benchmark. The benchmark contains an 'application'
loosely modelled after Gnumeric. with lots of widgets in it. One of
the widgets is a GtkHPaned, and the benchmark changes the position of
the handle 2000 times causing lots of resizing and redrawing.

The results:

Without patch:

        elapsed time: 49.964  (40.029 resizes per second)

With patch:

        elapsed time: 44.575  (44.868 resizes per second)

so the patch is a clear improvement: 12.1% better framerate.


The objections to the patch still stand: it adds an ugly and unsafe
piece of API to glib. Some possible solutions to that:


* Make the API libgtk_only

        This would allow us to get rid of the API later if something
        better is found.


* Owen mentions in 

        http://mail.gnome.org/archives/gtk-devel-list/2003-September/msg00159.html

        that the API could be a g_signal_emit_slow() function that
        returns FALSE if you can bypass the signal system.


* Try to do the speedup entirely within g_signal_emit()

        I think it might be possible to skip both marshalling and
        argument collection by using a platform specific hack to
        convert a vararg list to a regular function call in the case
        where we can determine that it will work.

        I am not totally sure this will work, though.



Attaching benchmark and patches.

Søren

Attachment: benchmark.tar.gz
Description: Benchmark

? gfreelist.c
? gfreelist.h
? glib-diff
? patches
? glib/gfreelist.c
? glib/gfreelist.h
? glib/memdiff
? gobject/core.469
? gobject/glib-signal.patch
? gobject/paramspec.patch
? gobject/signal.patch
Index: gobject/gsignal.c
===================================================================
RCS file: /cvs/gnome/glib/gobject/gsignal.c,v
retrieving revision 1.52
diff -u -r1.52 gsignal.c
--- gobject/gsignal.c	19 Aug 2003 02:15:40 -0000	1.52
+++ gobject/gsignal.c	5 Sep 2003 14:21:27 -0000
@@ -1135,7 +1135,7 @@
   va_end (args);
 
   /* optimize NOP emissions with NULL class handlers */
-  if (signal_id && G_TYPE_IS_INSTANTIATABLE (itype) && return_type == G_TYPE_NONE &&
+  if (signal_id && G_TYPE_IS_INSTANTIATABLE (itype) &&
       class_offset && class_offset < MAX_TEST_CLASS_OFFSET)
     {
       SignalNode *node;
@@ -1331,7 +1331,7 @@
   node->emission_hooks = NULL;
   if (class_closure)
     signal_add_class_closure (node, 0, class_closure);
-  else if (G_TYPE_IS_INSTANTIATABLE (itype) && return_type == G_TYPE_NONE)
+  else if (G_TYPE_IS_INSTANTIATABLE (itype))
     {
       /* optimize NOP emissions */
       node->test_class_offset = TEST_CLASS_MAGIC;
@@ -1978,9 +1978,9 @@
 }
 
 static inline gboolean
-signal_check_skip_emission (SignalNode *node,
-			    gpointer    instance,
-			    GQuark      detail)
+signal_check_class_closure_only (SignalNode *node,
+				 gpointer    instance,
+				 GQuark      detail)
 {
   HandlerList *hlist;
 
@@ -1992,15 +1992,6 @@
   if (node->emission_hooks && node->emission_hooks->hooks)
     return FALSE;
 
-  /* is there a non-NULL class handler? */
-  if (node->test_class_offset != TEST_CLASS_MAGIC)
-    {
-      GTypeClass *class = G_TYPE_INSTANCE_GET_CLASS (instance, G_TYPE_FROM_INSTANCE (instance), GTypeClass);
-
-      if (G_STRUCT_MEMBER (gpointer, class, node->test_class_offset))
-	return FALSE;
-    }
-
   /* are signals being debugged? */
 #ifdef  G_ENABLE_DEBUG
   IF_DEBUG (SIGNALS, g_trace_instance_signals || g_trap_instance_signals)
@@ -2017,8 +2008,47 @@
   if (hlist && hlist->handlers)
     return FALSE;
 
+  /* none of the above, only class closure need to run */
+  return TRUE;
+}
+
+static inline gboolean
+signal_check_skip_emission (SignalNode *node,
+			    gpointer    instance,
+			    GQuark      detail)
+{
+  if (node->return_type != G_TYPE_NONE)
+    return FALSE;
+  
+  /* is there a non-NULL class handler? */
+  if (node->test_class_offset != TEST_CLASS_MAGIC)
+    {
+      GTypeClass *class = G_TYPE_INSTANCE_GET_CLASS (instance, G_TYPE_FROM_INSTANCE (instance), GTypeClass);
+
+      if (G_STRUCT_MEMBER (gpointer, class, node->test_class_offset))
+	return FALSE;
+    }
+
+  if (!signal_check_class_closure_only (node, instance, detail))
+    return FALSE;
+  
   /* none of the above, no emission required */
   return TRUE;
+}
+
+gboolean
+g_signal_check_class_closure_only (gpointer instance,
+				   guint    id,
+				   GQuark   detail)
+{
+  gboolean result;
+  SignalNode *node;
+  
+  SIGNAL_LOCK ();
+  node = LOOKUP_SIGNAL_NODE (id);
+  result = signal_check_class_closure_only (node, instance, detail);
+  SIGNAL_UNLOCK ();
+  return result;
 }
 
 void
Index: gobject/gsignal.h
===================================================================
RCS file: /cvs/gnome/glib/gobject/gsignal.h,v
retrieving revision 1.35
diff -u -r1.35 gsignal.h
--- gobject/gsignal.h	3 Dec 2002 23:54:54 -0000	1.35
+++ gobject/gsignal.h	5 Sep 2003 14:21:28 -0000
@@ -139,6 +139,9 @@
 void                  g_signal_emit_by_name (gpointer            instance,
 					     const gchar        *detailed_signal,
 					     ...);
+gboolean	      g_signal_check_class_closure_only (gpointer instance,
+							 guint    id,
+							 GQuark   detail);
 guint                 g_signal_lookup       (const gchar        *name,
 					     GType               itype);
 G_CONST_RETURN gchar* g_signal_name         (guint               signal_id);
Index: gtk/gtkwidget.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkwidget.c,v
retrieving revision 1.358
diff -u -r1.358 gtkwidget.c
--- gtk/gtkwidget.c	7 Aug 2003 21:03:18 -0000	1.358
+++ gtk/gtkwidget.c	29 Aug 2003 14:13:00 -0000
@@ -2643,7 +2643,15 @@
   if (!alloc_needed && !size_changed && !position_changed)
     return;
   
-  g_signal_emit (widget, widget_signals[SIZE_ALLOCATE], 0, &real_allocation);
+  if (g_signal_check_class_closure_only (widget, widget_signals[SIZE_ALLOCATE], 0))
+    {
+      GtkWidgetClass *class = GTK_WIDGET_GET_CLASS (widget);
+
+      if (class->size_allocate)
+	class->size_allocate (widget, &real_allocation);
+    }
+  else
+    g_signal_emit (widget, widget_signals[SIZE_ALLOCATE], 0, &real_allocation);
 
   if (GTK_WIDGET_MAPPED (widget))
     {
@@ -3356,6 +3364,7 @@
 			   GdkEvent  *event)
 {
   gboolean return_val = FALSE;
+  GtkWidgetClass *class;
 
   /* We check only once for is-still-visible; if someone
    * hides the window in on of the signals on the widget,
@@ -3367,10 +3376,22 @@
 
   g_object_ref (widget);
 
-  g_signal_emit (widget, widget_signals[EVENT], 0, event, &return_val);
+  class = GTK_WIDGET_GET_CLASS (widget);
+  
+  if (g_signal_check_class_closure_only (widget,
+					 widget_signals[EVENT], 0))
+    {
+      if (class->event)
+	return_val = class->event (widget, event);
+    }
+  else
+    g_signal_emit (widget, widget_signals[EVENT], 0, event, &return_val);
+  
   return_val |= !WIDGET_REALIZED_FOR_EVENT (widget, event);
   if (!return_val)
     {
+      typedef gboolean (* EventFunc) (GtkWidget *widget, GdkEvent *event);
+      EventFunc event_func = NULL;
       gint signal_num;
 
       switch (event->type)
@@ -3382,78 +3403,104 @@
 	case GDK_2BUTTON_PRESS:
 	case GDK_3BUTTON_PRESS:
 	  signal_num = BUTTON_PRESS_EVENT;
+	  event_func = (EventFunc)class->button_press_event;
 	  break;
 	case GDK_SCROLL:
 	  signal_num = SCROLL_EVENT;
+	  event_func = (EventFunc)class->scroll_event;
 	  break;
 	case GDK_BUTTON_RELEASE:
 	  signal_num = BUTTON_RELEASE_EVENT;
+	  event_func = (EventFunc)class->button_release_event;
 	  break;
 	case GDK_MOTION_NOTIFY:
 	  signal_num = MOTION_NOTIFY_EVENT;
+	  event_func = (EventFunc)class->motion_notify_event;
 	  break;
 	case GDK_DELETE:
 	  signal_num = DELETE_EVENT;
+	  event_func = (EventFunc)class->delete_event;
 	  break;
 	case GDK_DESTROY:
 	  signal_num = DESTROY_EVENT;
+	  event_func = (EventFunc)class->destroy_event;
 	  break;
 	case GDK_KEY_PRESS:
 	  signal_num = KEY_PRESS_EVENT;
+	  event_func = (EventFunc)class->key_press_event;
 	  break;
 	case GDK_KEY_RELEASE:
 	  signal_num = KEY_RELEASE_EVENT;
+	  event_func = (EventFunc)class->key_release_event;
 	  break;
 	case GDK_ENTER_NOTIFY:
 	  signal_num = ENTER_NOTIFY_EVENT;
+	  event_func = (EventFunc)class->enter_notify_event;
 	  break;
 	case GDK_LEAVE_NOTIFY:
 	  signal_num = LEAVE_NOTIFY_EVENT;
+	  event_func = (EventFunc)class->leave_notify_event;
 	  break;
 	case GDK_FOCUS_CHANGE:
 	  signal_num = event->focus_change.in ? FOCUS_IN_EVENT : FOCUS_OUT_EVENT;
+	  event_func = (EventFunc)(event->focus_change.in ?
+				   class->focus_in_event : class->focus_out_event);
 	  break;
 	case GDK_CONFIGURE:
 	  signal_num = CONFIGURE_EVENT;
+	  event_func = (EventFunc)class->configure_event;
 	  break;
 	case GDK_MAP:
 	  signal_num = MAP_EVENT;
+	  event_func = (EventFunc)class->map_event;
 	  break;
 	case GDK_UNMAP:
 	  signal_num = UNMAP_EVENT;
+	  event_func = (EventFunc)class->unmap_event;
 	  break;
 	case GDK_WINDOW_STATE:
 	  signal_num = WINDOW_STATE_EVENT;
+	  event_func = (EventFunc)class->window_state_event;
 	  break;
 	case GDK_PROPERTY_NOTIFY:
 	  signal_num = PROPERTY_NOTIFY_EVENT;
+	  event_func = (EventFunc)class->property_notify_event;
 	  break;
 	case GDK_SELECTION_CLEAR:
 	  signal_num = SELECTION_CLEAR_EVENT;
+	  event_func = (EventFunc)class->selection_clear_event;
 	  break;
 	case GDK_SELECTION_REQUEST:
 	  signal_num = SELECTION_REQUEST_EVENT;
+	  event_func = (EventFunc)class->selection_request_event;
 	  break;
 	case GDK_SELECTION_NOTIFY:
 	  signal_num = SELECTION_NOTIFY_EVENT;
+	  event_func = (EventFunc)class->selection_notify_event;
 	  break;
 	case GDK_PROXIMITY_IN:
 	  signal_num = PROXIMITY_IN_EVENT;
+	  event_func = (EventFunc)class->proximity_in_event;
 	  break;
 	case GDK_PROXIMITY_OUT:
 	  signal_num = PROXIMITY_OUT_EVENT;
+	  event_func = (EventFunc)class->proximity_out_event;
 	  break;
 	case GDK_NO_EXPOSE:
 	  signal_num = NO_EXPOSE_EVENT;
+	  event_func = (EventFunc)class->no_expose_event;
 	  break;
 	case GDK_CLIENT_EVENT:
 	  signal_num = CLIENT_EVENT;
+	  event_func = (EventFunc)class->client_event;
 	  break;
 	case GDK_EXPOSE:
 	  signal_num = EXPOSE_EVENT;
+	  event_func = (EventFunc)class->expose_event;
 	  break;
 	case GDK_VISIBILITY_NOTIFY:
 	  signal_num = VISIBILITY_NOTIFY_EVENT;
+	  event_func = (EventFunc)class->visibility_notify_event;
 	  break;
 	default:
 	  g_warning ("gtk_widget_event(): unhandled event type: %d", event->type);
@@ -3461,8 +3508,17 @@
 	  break;
 	}
       if (signal_num != -1)
-	g_signal_emit (widget, widget_signals[signal_num], 0, event, &return_val);
+	{
+	  if (g_signal_check_class_closure_only (widget, widget_signals[signal_num], 0))
+	    {
+	      if (event_func)
+		return_val = event_func (widget, event);
+	    }
+	  else
+	    g_signal_emit (widget, widget_signals[signal_num], 0, event, &return_val);
+	}
     }
+
   if (WIDGET_REALIZED_FOR_EVENT (widget, event))
     g_signal_emit (widget, widget_signals[EVENT_AFTER], 0, event);
   else
Index: gtk/gtkcontainer.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkcontainer.c,v
retrieving revision 1.124
diff -u -r1.124 gtkcontainer.c
--- gtk/gtkcontainer.c	8 Jul 2003 22:49:35 -0000	1.124
+++ gtk/gtkcontainer.c	29 Aug 2003 14:13:00 -0000
@@ -1184,8 +1184,16 @@
 gtk_container_check_resize (GtkContainer *container)
 {
   g_return_if_fail (GTK_IS_CONTAINER (container));
-  
-  g_signal_emit (container, container_signals[CHECK_RESIZE], 0);
+
+  if (g_signal_check_class_closure_only (container, container_signals[CHECK_RESIZE], 0))
+    {
+      GtkContainerClass *class = GTK_CONTAINER_GET_CLASS (container);
+
+      if (class->check_resize)
+	class->check_resize (container);
+    }
+  else
+    g_signal_emit (container, container_signals[CHECK_RESIZE], 0);
 }
 
 static void


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]