GProperty status



hi all;

tl;dr: over the past year and half I've been working on and off on
GProperty, a GParamSpec that provides some nice features for
implementing properties in GObject[0]. the code is in the
wip/gproperty branch of GLib and it works well enough.

• history
after a bunch of proposals on how to make property access through
g_object_set/get faster, as well as trying to encapsulate the best
practices of GObject development into something that can be
macro-ized, a couple of years ago I started working on a new property
definition API for GObject. the few requirements I had were: the code
should be saner; if at all possible it should not require a full
overhaul of the GParamSpec in GObject to avoid breaking existing
users; if at all possible, it should provide a decent way to describe
the object properties so that a simple parser should be able to
synthesize a serializable description; it should be faster to set and
get properties using the generic GObject code; it should be easier to
get, set, and override the default value of a property.

• GProperty
GProperty is a GParamSpec, which means that it integrates inside the
current GObject and GValue machinery pretty much transparently.
instead of creating GParamSpec instances, you create GProperty ones,
and you can decide to either pass an offset from the private data
structure associated to your GObject instance, or you can pass a
specialised accessor pair. the API entry points have been simplified
from GParamSpec — they have the same signature, for one, and the
default range and value are determined by the type, not by additional
arguments (though you can add ranges and default values if needed).

properties defined with GProperty have a bunch of additional
meta-flags associated with them — whether the property access should
be atomic, whether the access is direct or through separate functions,
whether the value is copied on set and get — which should at least
allow better interaction with language bindings and introspection.

by using a bunch of shortcuts, GProperty avoids using GValue *a lot*;
boxing and unboxing of values is done using C pointers, instead of
touching GValue and the system allocator — and using correct copy
semantics (the default ones), it's possible to avoid memory allocation
completely. removing GValue boxing and unboxing gives us a pretty nice
win, like it did for GSignal marshalling.

• accessors generation macros
one of the naff things to do in GObject code is to define properties
and the write the accessor functions for them. since we don't have
cute little language facilities like the @synthesize and @property
descriptors or Objective C 2.0, we have to make do pre-processor
directives — which boy do they suck, but at least they can be used to
remove a bunch of boilerplate, like we did with the G_DEFINE_* macros.
GProperty provides a bunch of macros that do the same job — except
they generate the declaration and definition of the property
accessors. I do have a bunch of macros that also take care of the
property definition and installation, but they require ancillary
files, and multiple conditional inclusions, so I think they ought to
be discussed separately.

• what improved
well, less boilerplate. no more gigantic set_property() and
get_property() implementations. accessors using the correct best
practices. default values are overridable without going insane. the
possibility for parsers to actually use the macros instead of parsing
random pieces of C code. plus, g_object_set()/g_object_get() become
about 50% faster.

• what sucks
autogenerated accessors are slower than just setting and getting the
value on the private data structure. a simple accessor like this:

  float
  test_object_get_foo (TestObject *obj)
  {
    return obj->priv->foo;
  }

is optimized to death by the compiler (assuming it doesn't cross file
boundaries). the equivalent generated code is:

  float
  test_object_get_foo (TestObject *obj)
  {
     float retval;

     g_property_get (obj, obj_props[PROP_FOO], &retval);

     return retval;
  }

which yields about a third of the speed. again, and to be fair: I'd
have to measure the cross-file optimization; pretty sure that the
compiler would still kick our ass, but not by 2/3rds. setters are,
again, slower by a factor or 33%, but, again, I'd have to check
cross-file optimizations.

as I said above, g_object_set() and g_object_get() become faster
because we go through the va_list directly without allocating and
clearing a ton of GValues — access goes from 350k/sec to 500k/sec, on
my Core i7.

yes, I tried making the generated code use direct field access by
using offsets and pointer deref, but it turns out that it doesn't buy
us anything: the numbers are pretty much the same.

• status
the code lives in the wip/gproperty branch of GLib. it's a single
commit, because rebasing 50+ commits was becoming a hassle, and
because the intermediate history is pretty pointless. I know that Ryan
really wants to have direct access getters for this code to land —
hopefully, I demonstrated that it's pointless, and that if you really
care about getters being fast, you can write your own getter function.

if somebody has better ideas, improvements over the code, or simply
wants to mock me for my implementation, feel free to reply to this
email or pick the branch up.

ciao,
 Emmanuele.

[0] no, GParamSpec is not a way to implement properties; GParamSpec is
a way to validate GValues. the fact that it's used to implement
properties in GObject is a side effect.

--
W: http://www.emmanuelebassi.name
B: http://blogs.gnome.org/ebassi/


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