gobject bench



Hi,

I wrote a little program and did some timings (celeron 400):

Creating lots of objects...
Created 1000000 GObject instances in 0.86 seconds (8.6e-07 secs per object)
Finalized 1000000 GObject instances in 1.01 seconds (1.01e-06 secs per object)
Creating lots of zero-filled structs...
Created 1000000 struct instances in 0.47 seconds (4.7e-07 secs per object)
Finalized 1000000 struct instances in 0.59 seconds (5.9e-07 secs per object)

Oddly, per the comment in the source, using G_OBJECT(g_object_new())
instead of (GObject*)g_type_create_instance() halves the speed of
object creation. Removing the G_OBJECT() typecast from the unref()
loop doesn't make any noticeable difference, so it must just be the
set_valist() and other stuff in g_object_new(). Could likely optimize
the common case where first_param_name == NULL by returning
immediately.

So anyway, this seems to demonstrate that the time overhead of GObject
creation is pretty low, about a constant factor of 2 more than a plain
calloc() struct, including custom init/finalize methods. This suggests
that speed should not be a concern when deciding whether to make a
type a GObject or a plain struct; probably the size of the struct is
the only real issue, if you have a huge number of instances and only a
couple fields then GObject could cause some bloat. Also of course
GObject prevents static allocation, which can matter for something
like PangoFontDescription.

I can check in the bench program if you want, I don't guess it's that
exciting though.

Havoc

#include "config.h"

#include <glib-object.h>
#include <time.h>
#include <stdio.h>

typedef struct _GBench GBench;
typedef struct _GBenchClass GBenchClass;

#define G_TYPE_BENCH              (g_bench_get_type ())
#define G_BENCH(object)           (G_TYPE_CHECK_INSTANCE_CAST
#((object), G_TYPE_BENCH, GBench))
#define G_BENCH_CLASS(klass)      (G_TYPE_CHECK_CLASS_CAST ((klass),
#G_TYPE_BENCH, GBenchClass))
#define G_IS_BENCH(object)        (G_TYPE_CHECK_INSTANCE_TYPE
#((object), G_TYPE_BENCH))
#define G_IS_BENCH_CLASS(klass)   (G_TYPE_CHECK_CLASS_TYPE ((klass),
#G_TYPE_BENCH))
#define G_BENCH_GET_CLASS(obj)    (G_TYPE_INSTANCE_GET_CLASS ((obj),
#G_TYPE_BENCH, GBenchClass))

struct _GBench
{
  GObject parent_instance;

  gint some_member_data;
  gpointer other_data;
};

struct _GBenchClass
{
  GObjectClass parent_class;
  
};

GType g_bench_get_type (void);

#define ITERATIONS 1000000

int
main (gint   argc,
      gchar *argv[])
{
  clock_t start;
  clock_t end;
  gint i;
  GBench *benches[ITERATIONS];
  
  g_type_init ();

  printf ("Creating lots of objects...\n");
  
  start = clock ();
  i = 0;
  while (i < ITERATIONS)
    {
      /* writing this as "G_OBJECT (g_object_new(G_TYPE_OBJECT,
  NULL))"
       * results in nearly doubling the time this loop takes to run.
       * Go figure.
       */
      benches[i] = (GBench*)g_type_create_instance (G_TYPE_OBJECT);
      
      ++i;
    }

  end = clock ();

  printf ("Created %d GObject instances in %g seconds (%g secs per
  object)\n",
          ITERATIONS,
          (end - start)/(double)CLOCKS_PER_SEC,
          (end - start)/(double)CLOCKS_PER_SEC/(double)ITERATIONS);
  
  start = clock ();
  i = 0;
  while (i < ITERATIONS)
    {
      g_object_unref (G_OBJECT (benches[i]));
      
      ++i;
    }

  end = clock ();

  printf ("Finalized %d GObject instances in %g seconds (%g secs per
  object)\n",
          ITERATIONS,
          (end - start)/(double)CLOCKS_PER_SEC,
          (end - start)/(double)CLOCKS_PER_SEC/(double)ITERATIONS);


  printf ("Creating lots of zero-filled structs...\n");
  
  start = clock ();
  i = 0;
  while (i < ITERATIONS)
    {
      benches[i] = g_new0(GBench, 1);
      
      ++i;
    }

  end = clock ();

  printf ("Created %d struct instances in %g seconds (%g secs per
  object)\n",
          ITERATIONS,
          (end - start)/(double)CLOCKS_PER_SEC,
          (end - start)/(double)CLOCKS_PER_SEC/(double)ITERATIONS);
  
  start = clock ();
  i = 0;
  while (i < ITERATIONS)
    {
      g_free (benches[i]);
      
      ++i;
    }

  end = clock ();

  printf ("Finalized %d struct instances in %g seconds (%g secs per
  object)\n",
          ITERATIONS,
          (end - start)/(double)CLOCKS_PER_SEC,
          (end - start)/(double)CLOCKS_PER_SEC/(double)ITERATIONS);
  
  return 0;
}

static void g_bench_init        (GBench      *bench);
static void g_bench_class_init  (GBenchClass *klass);
static void g_bench_finalize    (GObject     *object);

static gpointer parent_class;

GType
g_bench_get_type (void)
{
  static GType object_type = 0;

  if (!object_type)
    {
      static const GTypeInfo object_info =
      {
        sizeof (GBenchClass),
        (GBaseInitFunc) NULL,
        (GBaseFinalizeFunc) NULL,
        (GClassInitFunc) g_bench_class_init,
        NULL,           /* class_finalize */
        NULL,           /* class_data */
        sizeof (GBench),
        0,              /* n_preallocs */
        (GInstanceInitFunc) g_bench_init,
      };
      
      object_type = g_type_register_static (G_TYPE_OBJECT,
                                            "GBench",
                                            &object_info);
    }
  
  return object_type;
}

static void
g_bench_init (GBench *bench)
{
  bench->some_member_data = 100;
  bench->other_data = NULL;
}

static void
g_bench_class_init (GBenchClass *klass)
{
  GObjectClass *object_class = G_OBJECT_CLASS (klass);
  
  parent_class = g_type_class_peek_parent (klass);
  
  object_class->finalize = g_bench_finalize;
}

static void
g_bench_finalize (GObject *object)
{
  GBench *bench;

  bench = G_BENCH (object);
  
  G_OBJECT_CLASS (parent_class)->finalize (object);
}






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