1 /* testtreemodel.c
2  * Copyright (C) 2004  Red Hat, Inc.,  Matthias Clasen <mclasen@redhat.com>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 
20 #include "config.h"
21 
22 #include <string.h>
23 
24 #ifdef HAVE_MALLINFO
25 #include <malloc.h>
26 #endif
27 
28 #include <gtk/gtk.h>
29 
30 static gint repeats = 2;
31 static gint max_size = 8;
32 
33 static GOptionEntry entries[] = {
34   { "repeats", 'r', 0, G_OPTION_ARG_INT, &repeats, "Average over N repetitions", "N" },
35   { "max-size", 'm', 0, G_OPTION_ARG_INT, &max_size, "Test up to 2^M items", "M" },
36   { NULL }
37 };
38 
39 
40 typedef void (ClearFunc)(GtkTreeModel *model);
41 typedef void (InsertFunc)(GtkTreeModel *model,
42 			  gint          items,
43 			  gint          i);
44 
45 static void
list_store_append(GtkTreeModel * model,gint items,gint i)46 list_store_append (GtkTreeModel *model,
47 		   gint          items,
48 		   gint          i)
49 {
50   GtkListStore *store = GTK_LIST_STORE (model);
51   GtkTreeIter iter;
52   gchar *text;
53 
54   text = g_strdup_printf ("row %d", i);
55   gtk_list_store_append (store, &iter);
56   gtk_list_store_set (store, &iter, 0, i, 1, text, -1);
57   g_free (text);
58 }
59 
60 static void
list_store_prepend(GtkTreeModel * model,gint items,gint i)61 list_store_prepend (GtkTreeModel *model,
62 		    gint          items,
63 		    gint          i)
64 {
65   GtkListStore *store = GTK_LIST_STORE (model);
66   GtkTreeIter iter;
67   gchar *text;
68 
69   text = g_strdup_printf ("row %d", i);
70   gtk_list_store_prepend (store, &iter);
71   gtk_list_store_set (store, &iter, 0, i, 1, text, -1);
72   g_free (text);
73 }
74 
75 static void
list_store_insert(GtkTreeModel * model,gint items,gint i)76 list_store_insert (GtkTreeModel *model,
77 		   gint          items,
78 		   gint          i)
79 {
80   GtkListStore *store = GTK_LIST_STORE (model);
81   GtkTreeIter iter;
82   gchar *text;
83   gint n;
84 
85   text = g_strdup_printf ("row %d", i);
86   n = g_random_int_range (0, i + 1);
87   gtk_list_store_insert (store, &iter, n);
88   gtk_list_store_set (store, &iter, 0, i, 1, text, -1);
89   g_free (text);
90 }
91 
92 static gint
compare(GtkTreeModel * model,GtkTreeIter * a,GtkTreeIter * b,gpointer data)93 compare (GtkTreeModel *model,
94 	 GtkTreeIter  *a,
95 	 GtkTreeIter  *b,
96 	 gpointer      data)
97 {
98   gchar *str_a, *str_b;
99   gint result;
100 
101   gtk_tree_model_get (model, a, 1, &str_a, -1);
102   gtk_tree_model_get (model, b, 1, &str_b, -1);
103 
104   result = strcmp (str_a, str_b);
105 
106   g_free (str_a);
107   g_free (str_b);
108 
109   return result;
110 }
111 
112 static void
tree_store_append(GtkTreeModel * model,gint items,gint i)113 tree_store_append (GtkTreeModel *model,
114 		   gint          items,
115 		   gint          i)
116 {
117   GtkTreeStore *store = GTK_TREE_STORE (model);
118   GtkTreeIter iter;
119   gchar *text;
120 
121   text = g_strdup_printf ("row %d", i);
122   gtk_tree_store_append (store, &iter, NULL);
123   gtk_tree_store_set (store, &iter, 0, i, 1, text, -1);
124   g_free (text);
125 }
126 
127 static void
tree_store_prepend(GtkTreeModel * model,gint items,gint i)128 tree_store_prepend (GtkTreeModel *model,
129 		    gint          items,
130 		    gint          i)
131 {
132   GtkTreeStore *store = GTK_TREE_STORE (model);
133   GtkTreeIter iter;
134   gchar *text;
135 
136   text = g_strdup_printf ("row %d", i);
137   gtk_tree_store_prepend (store, &iter, NULL);
138   gtk_tree_store_set (store, &iter, 0, i, 1, text, -1);
139   g_free (text);
140 }
141 
142 static void
tree_store_insert_flat(GtkTreeModel * model,gint items,gint i)143 tree_store_insert_flat (GtkTreeModel *model,
144 			gint          items,
145 			gint          i)
146 {
147   GtkTreeStore *store = GTK_TREE_STORE (model);
148   GtkTreeIter iter;
149   gchar *text;
150   gint n;
151 
152   text = g_strdup_printf ("row %d", i);
153   n = g_random_int_range (0, i + 1);
154   gtk_tree_store_insert (store, &iter, NULL, n);
155   gtk_tree_store_set (store, &iter, 0, i, 1, text, -1);
156   g_free (text);
157 }
158 
159 typedef struct {
160   gint i;
161   gint n;
162   gboolean found;
163   GtkTreeIter iter;
164 } FindData;
165 
166 static gboolean
find_nth(GtkTreeModel * model,GtkTreePath * path,GtkTreeIter * iter,gpointer data)167 find_nth (GtkTreeModel *model,
168 	  GtkTreePath  *path,
169 	  GtkTreeIter  *iter,
170 	  gpointer      data)
171 {
172   FindData *fdata = (FindData *)data;
173 
174   if (fdata->i >= fdata->n)
175     {
176       fdata->iter = *iter;
177       fdata->found = TRUE;
178       return TRUE;
179     }
180 
181   fdata->i++;
182 
183   return FALSE;
184 }
185 
186 static void
tree_store_insert_deep(GtkTreeModel * model,gint items,gint i)187 tree_store_insert_deep (GtkTreeModel *model,
188 			gint          items,
189 			gint          i)
190 {
191   GtkTreeStore *store = GTK_TREE_STORE (model);
192   GtkTreeIter iter;
193   gchar *text;
194   FindData data;
195 
196   text = g_strdup_printf ("row %d", i);
197   data.n = g_random_int_range (0, items);
198   data.i = 0;
199   data.found = FALSE;
200   if (data.n < i)
201     gtk_tree_model_foreach (model, find_nth, &data);
202   gtk_tree_store_insert (store, &iter, data.found ? &(data.iter) : NULL, data.n);
203   gtk_tree_store_set (store, &iter, 0, i, 1, text, -1);
204   g_free (text);
205 }
206 
207 
208 static void
test_run(gchar * title,GtkTreeModel * store,ClearFunc * clear,InsertFunc * insert)209 test_run (gchar        *title,
210 	  GtkTreeModel *store,
211 	  ClearFunc    *clear,
212 	  InsertFunc   *insert)
213 {
214   gint i, k, d, items;
215   GTimer *timer;
216   gdouble elapsed;
217   int uordblks_before = 0, memused;
218 
219   g_print ("%s (average over %d runs, time in milliseconds)\n"
220 	   "items \ttime      \ttime/item \tused memory\n", title, repeats);
221 
222   timer = g_timer_new ();
223 
224   for (k = 0; k < max_size; k++)
225     {
226       items = 1 << k;
227       elapsed = 0.0;
228       for (d = 0; d < repeats; d++)
229 	{
230 	  (*clear)(store);
231 #ifdef HAVE_MALLINFO
232 	  /* Peculiar location of this, btw.  -- MW.  */
233 	  uordblks_before = mallinfo().uordblks;
234 #endif
235 	  g_timer_reset (timer);
236 	  g_timer_start (timer);
237 	  for (i = 0; i < items; i++)
238 	    (*insert) (store, items, i);
239 	  g_timer_stop (timer);
240 	  elapsed += g_timer_elapsed (timer, NULL);
241 	}
242 
243       elapsed = elapsed * 1000 / repeats;
244 #ifdef HAVE_MALLINFO
245       memused = (mallinfo().uordblks - uordblks_before) / 1024;
246 #else
247       memused = 0;
248 #endif
249       g_print ("%d \t%f \t%f  \t%dk\n",
250 	       items, elapsed, elapsed/items, memused);
251     }
252 }
253 
254 int
main(int argc,char * argv[])255 main (int argc, char *argv[])
256 {
257   GtkTreeModel *model;
258 
259   gtk_init_with_args (&argc, &argv, NULL, entries, NULL, NULL);
260 
261   model = GTK_TREE_MODEL (gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING));
262 
263   test_run ("list store append",
264 	    model,
265 	    (ClearFunc*)gtk_list_store_clear,
266 	    (InsertFunc*)list_store_append);
267 
268   test_run ("list store prepend",
269 	    model,
270 	    (ClearFunc*)gtk_list_store_clear,
271 	    (InsertFunc*)list_store_prepend);
272 
273   test_run ("list store insert",
274 	    model,
275 	    (ClearFunc*)gtk_list_store_clear,
276 	    (InsertFunc*)list_store_insert);
277 
278   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (model),
279 					   compare, NULL, NULL);
280   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
281 					GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
282 					GTK_SORT_ASCENDING);
283 
284   test_run ("list store insert (sorted)",
285 	    model,
286 	    (ClearFunc*)gtk_list_store_clear,
287 	    (InsertFunc*)list_store_insert);
288 
289   g_object_unref (model);
290 
291   model = GTK_TREE_MODEL (gtk_tree_store_new (2, G_TYPE_INT, G_TYPE_STRING));
292 
293   test_run ("tree store append",
294 	    model,
295 	    (ClearFunc*)gtk_tree_store_clear,
296 	    (InsertFunc*)tree_store_append);
297 
298   test_run ("tree store prepend",
299 	    model,
300 	    (ClearFunc*)gtk_tree_store_clear,
301 	    (InsertFunc*)tree_store_prepend);
302 
303   test_run ("tree store insert (flat)",
304 	    model,
305 	    (ClearFunc*)gtk_tree_store_clear,
306 	    (InsertFunc*)tree_store_insert_flat);
307 
308   test_run ("tree store insert (deep)",
309 	    model,
310 	    (ClearFunc*)gtk_tree_store_clear,
311 	    (InsertFunc*)tree_store_insert_deep);
312 
313   gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (model),
314 					   compare, NULL, NULL);
315   gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model),
316 					GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
317 					GTK_SORT_ASCENDING);
318 
319   test_run ("tree store insert (flat, sorted)",
320 	    model,
321 	    (ClearFunc*)gtk_tree_store_clear,
322 	    (InsertFunc*)tree_store_insert_flat);
323 
324   test_run ("tree store insert (deep, sorted)",
325 	    model,
326 	    (ClearFunc*)gtk_tree_store_clear,
327 	    (InsertFunc*)tree_store_insert_deep);
328 
329   return 0;
330 }
331