16 Software
Breevy: A text expander that lets you insert long words or phrases and launch apps, websites, and more just by typing abbreviations.
IcyScreen: Automatic screenshots. Have them saved, e-mailed, and uploaded.

Even faster row-insertion in GTK+: Sort it yourself!

A little followup to my last blog post, I actually discovered that temporarily disabling sorting in your list or tree store before populating it:

     gtk_tree_sortable_get_sort_column_id(sortable, &sort_col, &sort_order);
gtk_tree_sortable_set_sort_column_id(sortable, GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID,

... and resetting the sort column after populating:

     gtk_tree_sortable_set_sort_column_id(sortable, sort_col, sort_order);

... is slightly faster than just calling gtk_list_store_insert_with_values()... about 8-10% faster by my calculation, actually. So it's definitely worth doing.

But still, even with this optimization, and the optimization I talked about in my last blog post, populating a sorted store with thousands of rows was just still way too slow IMO. Unacceptably slow.

So the other day I wondered if it would be faster to:

  • Turn off sorting permanently by setting the sort column ID to GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID.
  • Manually sort the data in memory before populating the store.
  • Insert the rows into the unsorted store in the order that the data was sorted in memory.

I figured it was worth a shot... it didn't take too long to implement at all, and I was happy to find I was right: This method is just barely slower than populating an unsorted store without sorting the abbreviations in memory first, and about 10x faster overall -- very, very noticeable -- than when letting GTK+ do the sorting for me. A *huge* speedup. Totally sweet.

Of course, it's slightly more inconvenient, and there's also small bit of work involved, to visually simulate what GTK+ does when you click a sortable column's button, but it's not difficult at all... it's basically a matter of manipulating the TreeViewColumn's arrow widget with gtk_widget_show() and gtk_arrow_set().

Another benefit to handling the sorting yourself: By default, GTK+ darkens the sort column if there are more than 3 sortable columns in a tree view, and there's not any way to avoid this yet (though I submitted a patch that created a style property that would let you disable this). Handling the sorting yourself means no darkened sort column.

I'm really happy about this major speedup, because I had a long list of abbreviations (over 13,500) for medical transcriptionists that I really wanted to include with Breevy, but before this optimization (<= 2.05), they took far too long to load in the main window, so I put off including them until I could find a way to speed things up.

But now, with this speedup included in version 2.06 (out now), they load in about half a second on a 6+ year old Pentium 4 @ 2.8GHz... so the medical transcription list is now included with Breevy. 8)

So to wrap this post up: If you're going to be inserting thousands of rows into a GtkTreeStore or GtkListStore, and need some sort of sorting, I would definitely recommend handling the sorting yourself instead of letting GTK+ do it. I love GTK+, but this is one area where I think GTK+ could use some improvement, performance wise. hahahah

Side note: GTK+'s default column sort function uses g_utf8_collate() when comparing string data. This function is pretty darn slow (it's the nature of the beast, apparently). If you don't need any of it's features, I would definitely implement your own sorting function for your sorted columns and use strcmp/strcasecmp instead. You'll get a pretty noticeable speedup from this optimization alone, though not nearly as much as if you were to handle all of the sorting yourself.

You might check out the g_utf8_collate_key() function if you still want to use g_utf8_collate().

Posted by Patrick on November 17, 2009 at 3:32pm | 0 Comments
Tagged: , and

Faster sorted-store row insertion in GTK+.

So I was adding a huge list of abbreviations (over 15K) to Breevy about a week ago and noticed that it took *way* too long for the GtkListStore to be populated. Way too long, as in over a minute on a 3GHz P4.

After a bit of investigating I finally figured out that the bottleneck was the fact that the list store was a sorted store, and that it appeared GTK+ was resorting the store after each row insertion. I turned off sorting, and populating the store was almost instant.

So first I worked around this issue by setting the sort column ID for the list store to GTK_TREE_SORTABLE_UNSORTED_SORT_COLUMN_ID before populating. This disabled any sorting during the insertions. Then, after the insertions, I set the sort column ID back to what it was before, triggering a final sort of all of the inserted rows. I knew this was a bit hackish, but it worked.

But then I found out how to do it The Right Way: by calling the gtk_list_store_insert_with_values() function. Basically, you should use this instead of a gtk_list_store_append() and gtk_list_store_set() when inserting rows into a sorted store because these two latter functions basically tell the list store to resort itself after each new row is inserted (i.e., number of sorts == number of rows inserted)... something that's not necessary, and something that takes a heckuva long time.

The speedup I experienced using the insert_with_values() function was absolutely massive. Thanks to the folks on #gtk+ on irc.gnome.org for pointing the function out to me.

Posted by Patrick on November 10, 2009 at 4:03pm | 0 Comments
Tagged: and