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, see <http://www.gnu.org/licenses/>. |
16 | */ |
17 | |
18 | #include "config.h" |
19 | |
20 | #include <string.h> |
21 | |
22 | #ifdef HAVE_MALLINFO |
23 | #include <malloc.h> |
24 | #endif |
25 | |
26 | #include <gtk/gtk.h> |
27 | |
28 | static int repeats = 2; |
29 | static int max_size = 8; |
30 | |
31 | static GOptionEntry entries[] = { |
32 | { "repeats" , 'r', 0, G_OPTION_ARG_INT, &repeats, "Average over N repetitions" , "N" }, |
33 | { "max-size" , 'm', 0, G_OPTION_ARG_INT, &max_size, "Test up to 2^M items" , "M" }, |
34 | { NULL } |
35 | }; |
36 | |
37 | |
38 | typedef void (ClearFunc)(GtkTreeModel *model); |
39 | typedef void (InsertFunc)(GtkTreeModel *model, |
40 | int items, |
41 | int i); |
42 | |
43 | static void |
44 | list_store_append (GtkTreeModel *model, |
45 | int items, |
46 | int i) |
47 | { |
48 | GtkListStore *store = GTK_LIST_STORE (model); |
49 | GtkTreeIter iter; |
50 | char *text; |
51 | |
52 | text = g_strdup_printf (format: "row %d" , i); |
53 | gtk_list_store_append (list_store: store, iter: &iter); |
54 | gtk_list_store_set (list_store: store, iter: &iter, 0, i, 1, text, -1); |
55 | g_free (mem: text); |
56 | } |
57 | |
58 | static void |
59 | list_store_prepend (GtkTreeModel *model, |
60 | int items, |
61 | int i) |
62 | { |
63 | GtkListStore *store = GTK_LIST_STORE (model); |
64 | GtkTreeIter iter; |
65 | char *text; |
66 | |
67 | text = g_strdup_printf (format: "row %d" , i); |
68 | gtk_list_store_prepend (list_store: store, iter: &iter); |
69 | gtk_list_store_set (list_store: store, iter: &iter, 0, i, 1, text, -1); |
70 | g_free (mem: text); |
71 | } |
72 | |
73 | static void |
74 | list_store_insert (GtkTreeModel *model, |
75 | int items, |
76 | int i) |
77 | { |
78 | GtkListStore *store = GTK_LIST_STORE (model); |
79 | GtkTreeIter iter; |
80 | char *text; |
81 | int n; |
82 | |
83 | text = g_strdup_printf (format: "row %d" , i); |
84 | n = g_random_int_range (begin: 0, end: i + 1); |
85 | gtk_list_store_insert (list_store: store, iter: &iter, position: n); |
86 | gtk_list_store_set (list_store: store, iter: &iter, 0, i, 1, text, -1); |
87 | g_free (mem: text); |
88 | } |
89 | |
90 | static int |
91 | compare (GtkTreeModel *model, |
92 | GtkTreeIter *a, |
93 | GtkTreeIter *b, |
94 | gpointer data) |
95 | { |
96 | char *str_a, *str_b; |
97 | int result; |
98 | |
99 | gtk_tree_model_get (tree_model: model, iter: a, 1, &str_a, -1); |
100 | gtk_tree_model_get (tree_model: model, iter: b, 1, &str_b, -1); |
101 | |
102 | result = strcmp (s1: str_a, s2: str_b); |
103 | |
104 | g_free (mem: str_a); |
105 | g_free (mem: str_b); |
106 | |
107 | return result; |
108 | } |
109 | |
110 | static void |
111 | tree_store_append (GtkTreeModel *model, |
112 | int items, |
113 | int i) |
114 | { |
115 | GtkTreeStore *store = GTK_TREE_STORE (model); |
116 | GtkTreeIter iter; |
117 | char *text; |
118 | |
119 | text = g_strdup_printf (format: "row %d" , i); |
120 | gtk_tree_store_append (tree_store: store, iter: &iter, NULL); |
121 | gtk_tree_store_set (tree_store: store, iter: &iter, 0, i, 1, text, -1); |
122 | g_free (mem: text); |
123 | } |
124 | |
125 | static void |
126 | tree_store_prepend (GtkTreeModel *model, |
127 | int items, |
128 | int i) |
129 | { |
130 | GtkTreeStore *store = GTK_TREE_STORE (model); |
131 | GtkTreeIter iter; |
132 | char *text; |
133 | |
134 | text = g_strdup_printf (format: "row %d" , i); |
135 | gtk_tree_store_prepend (tree_store: store, iter: &iter, NULL); |
136 | gtk_tree_store_set (tree_store: store, iter: &iter, 0, i, 1, text, -1); |
137 | g_free (mem: text); |
138 | } |
139 | |
140 | static void |
141 | tree_store_insert_flat (GtkTreeModel *model, |
142 | int items, |
143 | int i) |
144 | { |
145 | GtkTreeStore *store = GTK_TREE_STORE (model); |
146 | GtkTreeIter iter; |
147 | char *text; |
148 | int n; |
149 | |
150 | text = g_strdup_printf (format: "row %d" , i); |
151 | n = g_random_int_range (begin: 0, end: i + 1); |
152 | gtk_tree_store_insert (tree_store: store, iter: &iter, NULL, position: n); |
153 | gtk_tree_store_set (tree_store: store, iter: &iter, 0, i, 1, text, -1); |
154 | g_free (mem: text); |
155 | } |
156 | |
157 | typedef struct { |
158 | int i; |
159 | int n; |
160 | gboolean found; |
161 | GtkTreeIter iter; |
162 | } FindData; |
163 | |
164 | static gboolean |
165 | find_nth (GtkTreeModel *model, |
166 | GtkTreePath *path, |
167 | GtkTreeIter *iter, |
168 | gpointer data) |
169 | { |
170 | FindData *fdata = (FindData *)data; |
171 | |
172 | if (fdata->i >= fdata->n) |
173 | { |
174 | fdata->iter = *iter; |
175 | fdata->found = TRUE; |
176 | return TRUE; |
177 | } |
178 | |
179 | fdata->i++; |
180 | |
181 | return FALSE; |
182 | } |
183 | |
184 | static void |
185 | tree_store_insert_deep (GtkTreeModel *model, |
186 | int items, |
187 | int i) |
188 | { |
189 | GtkTreeStore *store = GTK_TREE_STORE (model); |
190 | GtkTreeIter iter; |
191 | char *text; |
192 | FindData data; |
193 | |
194 | text = g_strdup_printf (format: "row %d" , i); |
195 | data.n = g_random_int_range (begin: 0, end: items); |
196 | data.i = 0; |
197 | data.found = FALSE; |
198 | if (data.n < i) |
199 | gtk_tree_model_foreach (model, func: find_nth, user_data: &data); |
200 | gtk_tree_store_insert (tree_store: store, iter: &iter, parent: data.found ? &(data.iter) : NULL, position: data.n); |
201 | gtk_tree_store_set (tree_store: store, iter: &iter, 0, i, 1, text, -1); |
202 | g_free (mem: text); |
203 | } |
204 | |
205 | |
206 | static void |
207 | test_run (const char *title, |
208 | GtkTreeModel *store, |
209 | ClearFunc *clear, |
210 | InsertFunc *insert) |
211 | { |
212 | int i, k, d, items; |
213 | GTimer *timer; |
214 | double elapsed; |
215 | int memused; |
216 | #ifdef HAVE_MALLINFO |
217 | int uordblks_before = 0; |
218 | #endif |
219 | |
220 | g_print (format: "%s (average over %d runs, time in milliseconds)\n" |
221 | "items \ttime \ttime/item \tused memory\n" , title, repeats); |
222 | |
223 | timer = g_timer_new (); |
224 | |
225 | for (k = 0; k < max_size; k++) |
226 | { |
227 | items = 1 << k; |
228 | elapsed = 0.0; |
229 | for (d = 0; d < repeats; d++) |
230 | { |
231 | (*clear)(store); |
232 | #ifdef HAVE_MALLINFO |
233 | /* Peculiar location of this, btw. -- MW. */ |
234 | uordblks_before = mallinfo().uordblks; |
235 | #endif |
236 | g_timer_reset (timer); |
237 | g_timer_start (timer); |
238 | for (i = 0; i < items; i++) |
239 | (*insert) (store, items, i); |
240 | g_timer_stop (timer); |
241 | elapsed += g_timer_elapsed (timer, NULL); |
242 | } |
243 | |
244 | elapsed = elapsed * 1000 / repeats; |
245 | #ifdef HAVE_MALLINFO |
246 | memused = (mallinfo().uordblks - uordblks_before) / 1024; |
247 | #else |
248 | memused = 0; |
249 | #endif |
250 | g_print (format: "%d \t%f \t%f \t%dk\n" , |
251 | items, elapsed, elapsed/items, memused); |
252 | } |
253 | } |
254 | |
255 | int |
256 | main (int argc, char *argv[]) |
257 | { |
258 | GtkTreeModel *model; |
259 | GOptionContext *context; |
260 | |
261 | context = g_option_context_new (parameter_string: "" ); |
262 | g_option_context_add_main_entries (context, entries, NULL); |
263 | g_option_context_parse (context, argc: &argc, argv: &argv, NULL); |
264 | gtk_init (); |
265 | |
266 | model = GTK_TREE_MODEL (gtk_list_store_new (2, G_TYPE_INT, G_TYPE_STRING)); |
267 | |
268 | test_run (title: "list store append" , |
269 | store: model, |
270 | clear: (ClearFunc*)gtk_list_store_clear, |
271 | insert: (InsertFunc*)list_store_append); |
272 | |
273 | test_run (title: "list store prepend" , |
274 | store: model, |
275 | clear: (ClearFunc*)gtk_list_store_clear, |
276 | insert: (InsertFunc*)list_store_prepend); |
277 | |
278 | test_run (title: "list store insert" , |
279 | store: model, |
280 | clear: (ClearFunc*)gtk_list_store_clear, |
281 | insert: (InsertFunc*)list_store_insert); |
282 | |
283 | gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (model), |
284 | sort_func: compare, NULL, NULL); |
285 | gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), |
286 | GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, |
287 | order: GTK_SORT_ASCENDING); |
288 | |
289 | test_run (title: "list store insert (sorted)" , |
290 | store: model, |
291 | clear: (ClearFunc*)gtk_list_store_clear, |
292 | insert: (InsertFunc*)list_store_insert); |
293 | |
294 | g_object_unref (object: model); |
295 | |
296 | model = GTK_TREE_MODEL (gtk_tree_store_new (2, G_TYPE_INT, G_TYPE_STRING)); |
297 | |
298 | test_run (title: "tree store append" , |
299 | store: model, |
300 | clear: (ClearFunc*)gtk_tree_store_clear, |
301 | insert: (InsertFunc*)tree_store_append); |
302 | |
303 | test_run (title: "tree store prepend" , |
304 | store: model, |
305 | clear: (ClearFunc*)gtk_tree_store_clear, |
306 | insert: (InsertFunc*)tree_store_prepend); |
307 | |
308 | test_run (title: "tree store insert (flat)" , |
309 | store: model, |
310 | clear: (ClearFunc*)gtk_tree_store_clear, |
311 | insert: (InsertFunc*)tree_store_insert_flat); |
312 | |
313 | test_run (title: "tree store insert (deep)" , |
314 | store: model, |
315 | clear: (ClearFunc*)gtk_tree_store_clear, |
316 | insert: (InsertFunc*)tree_store_insert_deep); |
317 | |
318 | gtk_tree_sortable_set_default_sort_func (GTK_TREE_SORTABLE (model), |
319 | sort_func: compare, NULL, NULL); |
320 | gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (model), |
321 | GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, |
322 | order: GTK_SORT_ASCENDING); |
323 | |
324 | test_run (title: "tree store insert (flat, sorted)" , |
325 | store: model, |
326 | clear: (ClearFunc*)gtk_tree_store_clear, |
327 | insert: (InsertFunc*)tree_store_insert_flat); |
328 | |
329 | test_run (title: "tree store insert (deep, sorted)" , |
330 | store: model, |
331 | clear: (ClearFunc*)gtk_tree_store_clear, |
332 | insert: (InsertFunc*)tree_store_insert_deep); |
333 | |
334 | return 0; |
335 | } |
336 | |