Wednesday, January 14, 2009

Gtk+ lessons

I learnt of a couple of interesting gtk+ quirks over the last couple of days while hacking on Sutekh. Both rather surprised me, so are thus worth noting for future reference.

The first quirk is something I still don't fully understand. For various reasons[1] Sutekh uses strings to display the numbers with markup in the interface. I recently added a tweak so that these would sort numerically, rather than lexically. Since this involves stripping off the markup and converting to an integer, the sort is not lightning fast, but still acceptable. Unfortunately, adding the tweak the obvious way doubled the length of time to run the tests on the model, despite the model being unsorted by default. I've been unable to track down why this affects the tests so badly, since we shouldn't be using that code path at all. Fortunately, a simple lazy work-around exists, which is to tweak the sorting in a slightly less obvious way, and avoid it impacting the test suit.

The second quirk is something I do now understand, although the behaviour did surprise me. Sutekh is capable of generating very large gtk+ models (using "show all cards, show expansions + card sets" and editable options, it's easy to end up with a gtk.TreeStore containing more than 100000 entries). Loading these was unacceptably slow, with most of the time spent adding rows to the model, despite using the usual recommended tricks of disabling notifications and such while adding the rows.

It turns out that the underlying data structure for the gtk.TreeStore is glib's n-ary tree, g_node.
g_node, however, represents each list of children as a singly linked list from the parent. Consequently, appends into long lists are slow, since you have to walk to the end of the list. There's the obvious work-around, which is to insert thing in reverse using prepend, and it is indeed significantly faster, but you'd think this would be mentioned prominently in the docs, rather than requiring one to grub around in the glib code.

[1] i.e. We haven't got around to fixing this the right way yet.

No comments: