This describes an idea to improve the display performance of the tree_views, based on the sources of gtk+-2.10.11, and suggests possible solutions.

Consider the subprogram attached. It shows a simple tree_view displaying a list_store (5000 columns and 50 rows containing integers). The display performance is very poor: when displaying the last columns, the vertical scollbar takes between 5 and 10 seconds to respond.

Preliminary note: a tree of 50 columns and 5000 rows displays better performance (scrollbars take between 0 and 1 seconds to respond).

Using the Apple Shark profiler gave me the following tree showing where the time is spent while simply scrolling the scrollbar. In this tree, line N+1 calls line N.

        Self    Total   Library

        0.0%    80.3%   bigtree main    
        0.0%    80.3%   libgtk-x11-2.0.0.dylib  gtk_main        
        0.0%    80.3%   libglib-2.0.0.dylib     g_main_loop_run 
        0.0%    80.3%   libglib-2.0.0.dylib     g_main_context_iterate  
        0.0%    80.3%   libglib-2.0.0.dylib     g_main_context_dispatch 
        0.0%    80.3%   libglib-2.0.0.dylib     g_main_dispatch 
        0.0%    79.8%   libglib-2.0.0.dylib     g_idle_dispatch 
        0.0%    79.8%   libgdk-x11-2.0.0.dylib  gdk_window_update_idle  
        0.0%    79.8%   libgdk-x11-2.0.0.dylib  gdk_window_process_all_updates  
        0.0%    79.8%   libgdk-x11-2.0.0.dylib  
gdk_window_process_updates_internal     
        0.0%    79.8%   libgtk-x11-2.0.0.dylib  gtk_main_do_event       
        0.0%    79.8%   libgtk-x11-2.0.0.dylib  gtk_widget_send_expose  
        0.0%    79.8%   libgtk-x11-2.0.0.dylib  gtk_widget_event_internal       
        0.0%    79.8%   libgobject-2.0.0.dylib  g_signal_emit   
        0.0%    79.8%   libgobject-2.0.0.dylib  g_signal_emit_valist    
        0.0%    79.8%   libgobject-2.0.0.dylib  signal_emit_unlocked_R  
        0.0%    79.8%   libgobject-2.0.0.dylib  g_closure_invoke        
        0.0%    79.8%   libgobject-2.0.0.dylib  g_type_class_meta_marshal       
        0.0%    79.8%   libgtk-x11-2.0.0.dylib  _gtk_marshal_BOOLEAN__BOXED     
        0.0%    79.8%   libgtk-x11-2.0.0.dylib  gtk_tree_view_expose    
        0.2%    79.6%   libgtk-x11-2.0.0.dylib  gtk_tree_view_bin_expose
0.4% 26.4% libgtk-x11-2.0.0.dylib gtk_tree_view_column_cell_set_cell_data
        0.0%    18.4%   libgtk-x11-2.0.0.dylib  gtk_tree_model_get_value        
        17.5%   18.0%   libgtk-x11-2.0.0.dylib  gtk_list_store_get_value        

I have two comments to make about this tree:

A) it seems strange that 18% of the time is spent in gtk_list_store_get_value.

B) it seems very strange that gtk_tree_view_bin_expose calls gtk_tree_view_column_cell_set_cell_data.

Investigating further in the direction given by comment A), I saw that the following lines in gtkliststore.c were consuming the biggest amount of time:

        Self    Total   Line    Code

                        451     static void                     
                        452     gtk_list_store_get_value (GtkTreeModel 
*tree_model,                     
                        453                               GtkTreeIter  *iter,   
                
                        454                               gint          column, 
                
                        455                               GValue       *value)  
                
        0.0%    0.1%    456     {                       
                        457       GtkListStore *list_store = (GtkListStore *) 
tree_model;                       
                        458       GtkTreeDataList *list;                        
                        459       gint tmp_column = column;                     
                        460                             
        0.0%    0.0%    461       g_return_if_fail (column < 
list_store->n_columns);                      
        0.0%    0.4%    462       g_return_if_fail (VALID_ITER (iter, 
list_store));                     
                        463                                             
        0.0%    0.4%    464       list = _gtk_sequence_ptr_get_data 
(iter->user_data);                       
                        465                             
        53.2%   51.8%   466       while (tmp_column-- > 0 && list)              
     
        46.5%   45.3%   467         list = list->next;                       
                        468                             
        0.0%    0.0%    469       if (list == NULL)                     
                        470         g_value_init (value, 
list_store->column_headers[column]);                        
                        471       else                  
        0.1%    1.9%    472         _gtk_tree_data_list_node_to_value (list,    
                
                        473                                            
list_store->column_headers[column],                   
                        474                                            value);  
                
        0.1%    0.1%    475     }                       


So, it seems that we spend most of our time traversing the list of columns. Note that this explains why a tree of 5000 columns x 50 rows has such bad performance compared to a tree of 50 columns x 5000 rows.

First suggestion: we'd be better off in this subprogram if the data was implemented as an array instead of as a linked list.


Let's turn now to comment B). Why is gtk_tree_view_bin_expose calling gtk_tree_view_column_cell_set_cell_data ?

The code doing this is the following:

      /* we *need* to set cell data on all cells before the call
       * to _has_special_cell, else _has_special_cell() does not
       * return a correct value.
       */
for (list = (rtl ? g_list_last (tree_view->priv->columns) : g_list_first (tree_view->priv->columns));
           list;
           list = (rtl ? list->prev : list->next))
        {
          GtkTreeViewColumn *column = list->data;
          gtk_tree_view_column_cell_set_cell_data (column,
                                                   tree_view->priv->model,
                                                   &iter,
                                                   GTK_RBNODE_FLAG_SET (node, 
GTK_RBNODE_IS_PARENT),
                                                   node->children?TRUE:FALSE);
        }

      has_special_cell = gtk_tree_view_has_special_cell (tree_view);


I'm not familiar with this area yet, so I'm puzzled: is the call to gtk_tree_view_column_cell_set_cell_data really needed for the purposes of gtk_tree_view_bin_expose, or is it just needed for the call to gtk_tree_view_has_special_cell?

In any case, I suggest we cache this - probably there is no need to do it in every expose call, only after the model data has changed.

To sum up (thanks for reading me), would you accept a patch along those lines?

Nicolas

Attachment: bigtree.c
Description: Binary data

_______________________________________________
gtk-devel-list mailing list
gtk-devel-list@gnome.org
http://mail.gnome.org/mailman/listinfo/gtk-devel-list

Reply via email to