Re: Fast handling of class-closure-only signals



Owen Taylor <otaylor redhat com> writes:

> Do we have a profile of a micro-benchmark that just does class-closure 
> only signal emissions, to see where the time is going?

I am attaching a benchmark that emits class-closure-only signals with
prototypes like GtkContainer::check_resize, GtkWidget::event, and
GtkWidget::size_allocate.


Søren

#include <glib-object.h>
#include <gtk/gtk.h>

typedef struct _BenchmarkClass BenchmarkClass;
typedef struct _Benchmark Benchmark;

enum {
    EVENT,
    SIZE_ALLOCATE,
    CHECK_RESIZE,
    LAST_SIGNAL,
};

struct _Benchmark
{
    GObject parent;
};

struct _BenchmarkClass
{
    GObjectClass parent;
    
    gboolean (* event)     (Benchmark *b, GdkEvent *event);
    void (* size_allocate) (Benchmark *b, GtkAllocation *allocation);
    void (* check_resize)  (Benchmark *b);
};

static guint benchmark_signals [LAST_SIGNAL] = { 0 } ;

static void     benchmark_class_init    (GObjectClass  *class);
static gboolean benchmark_event         (Benchmark     *b,
					 GdkEvent      *e);
static void     benchmark_size_allocate (Benchmark     *b,
					 GtkAllocation *a);
static void     benchmark_check_resize  (Benchmark     *b);

#define TYPE_BENCHMARK (benchmark_get_type())

GType
benchmark_get_type (void)
{
    static GType object_type = 0;
    
    if (!object_type)
    {
	static const GTypeInfo object_info = {
	    sizeof (BenchmarkClass),
	    (GBaseInitFunc) NULL,
	    (GBaseFinalizeFunc) NULL,
	    (GClassInitFunc) benchmark_class_init,
	    NULL,           /* class_finalize */
	    NULL,           /* class_data */
	    sizeof (Benchmark),
	    0,              /* n_preallocs */
	    (GInstanceInitFunc) NULL,
	};
	
	object_type = g_type_register_static (G_TYPE_OBJECT,
					      "Benchmark",
					      &object_info, 0);
    }
    
    return object_type;
}

#define g_marshal_value_peek_boxed(v)    g_value_get_boxed (v)

void
marshal_BOOLEAN__BOXED (GClosure     *closure,
			GValue       *return_value,
			guint         n_param_values,
			const GValue *param_values,
			gpointer      invocation_hint,
			gpointer      marshal_data)
{
    typedef gboolean (*GMarshalFunc_BOOLEAN__BOXED) (gpointer     data1,
						     gpointer     arg_1,
						     gpointer     data2);
    register GMarshalFunc_BOOLEAN__BOXED callback;
    register GCClosure *cc = (GCClosure*) closure;
    register gpointer data1, data2;
    gboolean v_return;
    
    g_return_if_fail (return_value != NULL);
    g_return_if_fail (n_param_values == 2);
    
    if (G_CCLOSURE_SWAP_DATA (closure))
    {
	data1 = closure->data;
	data2 = g_value_peek_pointer (param_values + 0);
    }
    else
    {
	data1 = g_value_peek_pointer (param_values + 0);
	data2 = closure->data;
    }
    callback = (GMarshalFunc_BOOLEAN__BOXED) (marshal_data ? marshal_data : cc->callback);
    
    v_return = callback (data1,
			 g_marshal_value_peek_boxed (param_values + 1),
			 data2);
    
    g_value_set_boolean (return_value, v_return);
}

static void
benchmark_class_init (GObjectClass *class)
{
    BenchmarkClass *benchmark_class = (BenchmarkClass *)class;
    
    benchmark_signals[SIZE_ALLOCATE] = 
	g_signal_new ("size_allocate",
		      G_TYPE_FROM_CLASS (class),
		      G_SIGNAL_RUN_FIRST,
		      G_STRUCT_OFFSET (BenchmarkClass, size_allocate),
		      NULL, NULL,
		      g_cclosure_marshal_VOID__BOXED,
		      G_TYPE_NONE, 1,
		      GDK_TYPE_RECTANGLE | G_SIGNAL_TYPE_STATIC_SCOPE);
    
    benchmark_signals[CHECK_RESIZE] =
	g_signal_new ("check_resize",
		      G_OBJECT_CLASS_TYPE (class),
		      G_SIGNAL_RUN_LAST,
		      G_STRUCT_OFFSET (BenchmarkClass, check_resize),
		      NULL, NULL,
		      g_cclosure_marshal_VOID__VOID,
		      G_TYPE_NONE, 0);
    
    benchmark_signals[EVENT] =
	g_signal_new ("event",
		      G_TYPE_FROM_CLASS (class),
		      G_SIGNAL_RUN_LAST,
		      G_STRUCT_OFFSET (BenchmarkClass, event),
		      _gtk_boolean_handled_accumulator, NULL,
		      marshal_BOOLEAN__BOXED,
		      G_TYPE_BOOLEAN, 1,
		      GDK_TYPE_EVENT | G_SIGNAL_TYPE_STATIC_SCOPE);

    benchmark_class->event = benchmark_event;
    benchmark_class->size_allocate = benchmark_size_allocate;
    benchmark_class->check_resize = benchmark_check_resize;
}

static gboolean
benchmark_event (Benchmark *b,
		 GdkEvent *e)
{
    return FALSE;
}

static void
benchmark_size_allocate (Benchmark *b,
			 GtkAllocation *a)
{
    return;
}

static void
benchmark_check_resize (Benchmark *b)
{
    return;
}

#define N_SIGNALS 5000000

int
main ()
{
    Benchmark *b;
    int i;
    GTimer *timer;

    g_type_init ();

    b = g_object_new (TYPE_BENCHMARK, NULL);

    timer = g_timer_new ();
    
    for (i = 0; i < N_SIGNALS; ++i)
    {
	GtkAllocation alloc = { 0, 0, 100, 100 };
	
	g_signal_emit (b, benchmark_signals[SIZE_ALLOCATE],
		       0, &alloc);
    }

    g_print ("time to emit %d dummy \"size_allocate\" signals: %f\n",
	     N_SIGNALS, g_timer_elapsed (timer, NULL));

    g_timer_reset (timer);
    
    for (i = 0; i < N_SIGNALS; ++i)
    {
	gboolean retval;
	GdkEvent event;

	event.type = GDK_EXPOSE;

	g_signal_emit (b, benchmark_signals[EVENT], 0, &event, &retval);
    }
    
    g_print ("time to emit %d dummy \"event\" signals: %f\n",
	     N_SIGNALS, g_timer_elapsed (timer, NULL));

    g_timer_reset (timer);

    for (i = 0; i < N_SIGNALS; ++i)
    {
	g_signal_emit (b, benchmark_signals[CHECK_RESIZE], 0);
    }

    g_print ("time to emit %d dummy \"check_resize\" signals: %f\n",
	     N_SIGNALS, g_timer_elapsed (timer, NULL));

    for (i = 0; i < 3452345; ++i)
	sleep (10);
    
    return 0;
}


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