aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2009-12-01 11:23:28 -0500
committerSteven Rostedt <rostedt@goodmis.org>2009-12-17 21:43:46 -0500
commit43e0833d8468c9d9b496abde1845dddff106d11e (patch)
tree96086c05b35ff7dbdd3bb296bb8d749a6c0e293f
parentab91bd24b899d73d7552c5d1947656a3b446660e (diff)
Add new trace view store model to improve performance
With the amount of data needed for loading a trace file, we must implement our own tree view model. Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--Makefile2
-rw-r--r--trace-view-store.c848
-rw-r--r--trace-view-store.h104
3 files changed, 953 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 848a6aa..0287721 100644
--- a/Makefile
+++ b/Makefile
@@ -30,7 +30,7 @@ trace-util.o:: $(HEADERS)
30trace-ftrace.o:: $(HEADERS) 30trace-ftrace.o:: $(HEADERS)
31trace-input.o:: $(HEADERS) 31trace-input.o:: $(HEADERS)
32 32
33trace-cmd:: trace-cmd.o trace-read.o trace-view.o 33trace-cmd:: trace-cmd.o trace-read.o trace-view.o trace-view-store.o
34 $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS) 34 $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS)
35 35
36.PHONY: view_depends 36.PHONY: view_depends
diff --git a/trace-view-store.c b/trace-view-store.c
new file mode 100644
index 0000000..55bf2e7
--- /dev/null
+++ b/trace-view-store.c
@@ -0,0 +1,848 @@
1#include "trace-view-store.h"
2#include <stdlib.h>
3
4/* boring declarations of local functions */
5
6static void trace_view_store_init (TraceViewStore *pkg_tree);
7
8static void trace_view_store_class_init (TraceViewStoreClass *klass);
9
10static void trace_view_store_tree_model_init (GtkTreeModelIface *iface);
11
12static void trace_view_store_finalize (GObject *object);
13
14static GtkTreeModelFlags trace_view_store_get_flags (GtkTreeModel *tree_model);
15
16static gint trace_view_store_get_n_columns (GtkTreeModel *tree_model);
17
18static GType trace_view_store_get_column_type (GtkTreeModel *tree_model,
19 gint index);
20
21static gboolean trace_view_store_get_iter (GtkTreeModel *tree_model,
22 GtkTreeIter *iter,
23 GtkTreePath *path);
24
25static GtkTreePath *trace_view_store_get_path (GtkTreeModel *tree_model,
26 GtkTreeIter *iter);
27
28static void trace_view_store_get_value (GtkTreeModel *tree_model,
29 GtkTreeIter *iter,
30 gint column,
31 GValue *value);
32
33static gboolean trace_view_store_iter_next (GtkTreeModel *tree_model,
34 GtkTreeIter *iter);
35
36static gboolean trace_view_store_iter_children (GtkTreeModel *tree_model,
37 GtkTreeIter *iter,
38 GtkTreeIter *parent);
39
40static gboolean trace_view_store_iter_has_child (GtkTreeModel *tree_model,
41 GtkTreeIter *iter);
42
43static gint trace_view_store_iter_n_children (GtkTreeModel *tree_model,
44 GtkTreeIter *iter);
45
46static gboolean trace_view_store_iter_nth_child (GtkTreeModel *tree_model,
47 GtkTreeIter *iter,
48 GtkTreeIter *parent,
49 gint n);
50
51static gboolean trace_view_store_iter_parent (GtkTreeModel *tree_model,
52 GtkTreeIter *iter,
53 GtkTreeIter *child);
54
55
56
57static GObjectClass *parent_class = NULL; /* GObject stuff - nothing to worry about */
58
59
60/*****************************************************************************
61 *
62 * trace_view_store_get_type: here we register our new type and its interfaces
63 * with the type system. If you want to implement
64 * additional interfaces like GtkTreeSortable, you
65 * will need to do it here.
66 *
67 *****************************************************************************/
68
69GType
70trace_view_store_get_type (void)
71{
72 static GType trace_view_store_type = 0;
73
74 /* Some boilerplate type registration stuff */
75 if (trace_view_store_type == 0)
76 {
77 static const GTypeInfo trace_view_store_info =
78 {
79 sizeof (TraceViewStoreClass),
80 NULL, /* base_init */
81 NULL, /* base_finalize */
82 (GClassInitFunc) trace_view_store_class_init,
83 NULL, /* class finalize */
84 NULL, /* class_data */
85 sizeof (TraceViewStore),
86 0, /* n_preallocs */
87 (GInstanceInitFunc) trace_view_store_init
88 };
89 static const GInterfaceInfo tree_model_info =
90 {
91 (GInterfaceInitFunc) trace_view_store_tree_model_init,
92 NULL,
93 NULL
94 };
95
96 /* First register the new derived type with the GObject type system */
97 trace_view_store_type = g_type_register_static (G_TYPE_OBJECT, "TraceViewStore",
98 &trace_view_store_info, (GTypeFlags)0);
99
100 /* Now register our GtkTreeModel interface with the type system */
101 g_type_add_interface_static (trace_view_store_type, GTK_TYPE_TREE_MODEL, &tree_model_info);
102 }
103
104 return trace_view_store_type;
105}
106
107
108/*****************************************************************************
109 *
110 * trace_view_store_class_init: more boilerplate GObject/GType stuff.
111 * Init callback for the type system,
112 * called once when our new class is created.
113 *
114 *****************************************************************************/
115
116static void
117trace_view_store_class_init (TraceViewStoreClass *klass)
118{
119 GObjectClass *object_class;
120
121 parent_class = (GObjectClass*) g_type_class_peek_parent (klass);
122 object_class = (GObjectClass*) klass;
123
124 object_class->finalize = trace_view_store_finalize;
125}
126
127/*****************************************************************************
128 *
129 * trace_view_store_tree_model_init: init callback for the interface registration
130 * in trace_view_store_get_type. Here we override
131 * the GtkTreeModel interface functions that
132 * we implement.
133 *
134 *****************************************************************************/
135
136static void
137trace_view_store_tree_model_init (GtkTreeModelIface *iface)
138{
139 iface->get_flags = trace_view_store_get_flags;
140 iface->get_n_columns = trace_view_store_get_n_columns;
141 iface->get_column_type = trace_view_store_get_column_type;
142 iface->get_iter = trace_view_store_get_iter;
143 iface->get_path = trace_view_store_get_path;
144 iface->get_value = trace_view_store_get_value;
145 iface->iter_next = trace_view_store_iter_next;
146 iface->iter_children = trace_view_store_iter_children;
147 iface->iter_has_child = trace_view_store_iter_has_child;
148 iface->iter_n_children = trace_view_store_iter_n_children;
149 iface->iter_nth_child = trace_view_store_iter_nth_child;
150 iface->iter_parent = trace_view_store_iter_parent;
151}
152
153
154/*****************************************************************************
155 *
156 * trace_view_store_init: this is called everytime a new trace view store object
157 * instance is created (we do that in trace_view_store_new).
158 * Initialise the list structure's fields here.
159 *
160 *****************************************************************************/
161
162static void
163trace_view_store_init (TraceViewStore *trace_view_store)
164{
165 trace_view_store->n_columns = TRACE_VIEW_STORE_N_COLUMNS;
166
167 trace_view_store->column_types[0] = G_TYPE_UINT; /* CPU */
168 trace_view_store->column_types[1] = G_TYPE_STRING; /* TS */
169 trace_view_store->column_types[2] = G_TYPE_STRING; /* COMM */
170 trace_view_store->column_types[3] = G_TYPE_UINT; /* PID */
171 trace_view_store->column_types[4] = G_TYPE_STRING; /* LAT */
172 trace_view_store->column_types[5] = G_TYPE_STRING; /* EVENT */
173 trace_view_store->column_types[6] = G_TYPE_STRING; /* INFO */
174
175 g_assert (TRACE_VIEW_STORE_N_COLUMNS == 7);
176
177 trace_view_store->num_rows = 0;
178 trace_view_store->rows = NULL;
179
180 /* Set all columns visible */
181 trace_view_store->visible_column_mask = (1 << TRACE_VIEW_STORE_N_COLUMNS) - 1;
182
183 trace_view_store->stamp = g_random_int(); /* Random int to check whether an iter belongs to our model */
184
185}
186
187
188/*****************************************************************************
189 *
190 * trace_view_store_finalize: this is called just before a trace view store is
191 * destroyed. Free dynamically allocated memory here.
192 *
193 *****************************************************************************/
194
195static void
196trace_view_store_finalize (GObject *object)
197{
198/* TraceViewStore *trace_view_store = TRACE_VIEW_STORE(object); */
199
200 /* free all records and free all memory used by the list */
201#warning IMPLEMENT
202
203 /* must chain up - finalize parent */
204 (* parent_class->finalize) (object);
205}
206
207
208/*****************************************************************************
209 *
210 * trace_view_store_get_flags: tells the rest of the world whether our tree model
211 * has any special characteristics. In our case,
212 * we have a list model (instead of a tree), and each
213 * tree iter is valid as long as the row in question
214 * exists, as it only contains a pointer to our struct.
215 *
216 *****************************************************************************/
217
218static GtkTreeModelFlags
219trace_view_store_get_flags (GtkTreeModel *tree_model)
220{
221 g_return_val_if_fail (TRACE_VIEW_IS_LIST(tree_model), (GtkTreeModelFlags)0);
222
223 return (GTK_TREE_MODEL_LIST_ONLY | GTK_TREE_MODEL_ITERS_PERSIST);
224}
225
226
227/*****************************************************************************
228 *
229 * trace_view_store_get_n_columns: tells the rest of the world how many data
230 * columns we export via the tree model interface
231 *
232 *****************************************************************************/
233
234static gint
235trace_view_store_get_n_columns (GtkTreeModel *tree_model)
236{
237 g_return_val_if_fail (TRACE_VIEW_IS_LIST(tree_model), 0);
238
239 return TRACE_VIEW_STORE(tree_model)->n_columns;
240}
241
242
243/*****************************************************************************
244 *
245 * trace_view_store_get_column_type: tells the rest of the world which type of
246 * data an exported model column contains
247 *
248 *****************************************************************************/
249
250static GType
251trace_view_store_get_column_type (GtkTreeModel *tree_model,
252 gint index)
253{
254 g_return_val_if_fail (TRACE_VIEW_IS_LIST(tree_model), G_TYPE_INVALID);
255 g_return_val_if_fail (index < TRACE_VIEW_STORE(tree_model)->n_columns && index >= 0, G_TYPE_INVALID);
256
257 return TRACE_VIEW_STORE(tree_model)->column_types[index];
258}
259
260
261/*****************************************************************************
262 *
263 * trace_view_store_get_iter: converts a tree path (physical position) into a
264 * tree iter structure (the content of the iter
265 * fields will only be used internally by our model).
266 * We simply store a pointer to our TraceViewRecord
267 * structure that represents that row in the tree iter.
268 *
269 *****************************************************************************/
270
271static gboolean
272trace_view_store_get_iter (GtkTreeModel *tree_model,
273 GtkTreeIter *iter,
274 GtkTreePath *path)
275{
276 TraceViewStore *trace_view_store;
277 TraceViewRecord *record;
278 gint *indices, n, depth;
279
280 g_assert(TRACE_VIEW_IS_LIST(tree_model));
281 g_assert(path!=NULL);
282
283 trace_view_store = TRACE_VIEW_STORE(tree_model);
284
285 indices = gtk_tree_path_get_indices(path);
286 depth = gtk_tree_path_get_depth(path);
287
288 /* we do not allow children */
289 g_assert(depth == 1); /* depth 1 = top level; a list only has top level nodes and no children */
290
291 n = indices[0]; /* the n-th top level row */
292
293 if ( n >= trace_view_store->num_rows || n < 0 )
294 return FALSE;
295
296 record = trace_view_store->rows[n];
297
298 g_assert(record != NULL);
299 g_assert(record->pos == n);
300
301 /* We simply store a pointer to our custom record in the iter */
302 iter->stamp = trace_view_store->stamp;
303 iter->user_data = record;
304 iter->user_data2 = NULL; /* unused */
305 iter->user_data3 = NULL; /* unused */
306
307 return TRUE;
308}
309
310
311/*****************************************************************************
312 *
313 * trace_view_store_get_path: converts a tree iter into a tree path (ie. the
314 * physical position of that row in the list).
315 *
316 *****************************************************************************/
317
318static GtkTreePath *
319trace_view_store_get_path (GtkTreeModel *tree_model,
320 GtkTreeIter *iter)
321{
322 GtkTreePath *path;
323 TraceViewRecord *record;
324 TraceViewStore *trace_view_store;
325
326 g_return_val_if_fail (TRACE_VIEW_IS_LIST(tree_model), NULL);
327 g_return_val_if_fail (iter != NULL, NULL);
328 g_return_val_if_fail (iter->user_data != NULL, NULL);
329
330 trace_view_store = TRACE_VIEW_STORE(tree_model);
331
332 record = (TraceViewRecord*) iter->user_data;
333
334 path = gtk_tree_path_new();
335 gtk_tree_path_append_index(path, record->pos);
336
337 return path;
338}
339
340
341/*****************************************************************************
342 *
343 * trace_view_store_get_value: Returns a row's exported data columns
344 * (_get_value is what gtk_tree_model_get uses)
345 *
346 *****************************************************************************/
347
348static void
349trace_view_store_get_value (GtkTreeModel *tree_model,
350 GtkTreeIter *iter,
351 gint column,
352 GValue *value)
353{
354 TraceViewRecord *record;
355 TraceViewStore *trace_view_store;
356 struct trace_seq s;
357 struct pevent *pevent;
358 struct event *event;
359 struct record *data;
360 const gchar *comm;
361 gchar *str;
362 guint64 secs, usecs;
363 gint val;
364 int cpu;
365
366 g_return_if_fail (TRACE_VIEW_IS_LIST (tree_model));
367 g_return_if_fail (iter != NULL);
368 g_return_if_fail (column < TRACE_VIEW_STORE(tree_model)->n_columns);
369
370 g_value_init (value, TRACE_VIEW_STORE(tree_model)->column_types[column]);
371
372 trace_view_store = TRACE_VIEW_STORE(tree_model);
373
374 pevent = tracecmd_get_pevent(trace_view_store->handle);
375
376 record = *(TraceViewRecord**)iter->user_data;
377
378 g_return_if_fail ( record != NULL );
379
380 if(record->pos >= trace_view_store->num_rows)
381 g_return_if_reached();
382
383 /* If all columns are visible just use what was passed in */
384 if (trace_view_store->visible_column_mask !=
385 ((1 << TRACE_VIEW_STORE_N_COLUMNS) - 1)) {
386 guint i;
387
388 column++; /* make 0 drop out */
389
390 for (i = 0; column && i < TRACE_VIEW_STORE_N_COLUMNS; i++) {
391 if (!trace_view_store->visible_column_mask & (1 << i))
392 continue;
393
394 column--;
395 }
396
397 g_return_if_fail(column);
398
399 column = i;
400 }
401
402 switch(column)
403 {
404 case TRACE_VIEW_STORE_COL_CPU:
405 g_value_set_uint(value, record->cpu);
406 break;
407
408 case TRACE_VIEW_STORE_COL_TS:
409 usecs = record->timestamp;
410 usecs /= 1000;
411 secs = usecs / 1000000ULL;
412 usecs -= secs * 1000000ULL;
413 str = g_strdup_printf("%lu.%06lu", secs, usecs);
414 g_value_set_string(value, str);
415 g_free(str);
416 break;
417
418 case TRACE_VIEW_STORE_COL_COMM:
419 case TRACE_VIEW_STORE_COL_PID:
420 case TRACE_VIEW_STORE_COL_LAT:
421 case TRACE_VIEW_STORE_COL_EVENT:
422 case TRACE_VIEW_STORE_COL_INFO:
423
424 data = tracecmd_read_at(trace_view_store->handle, record->offset, &cpu);
425 if (cpu != record->cpu) {
426 free(data);
427 return;
428 }
429
430 switch (column) {
431 case TRACE_VIEW_STORE_COL_COMM:
432 case TRACE_VIEW_STORE_COL_PID:
433 val = pevent_data_pid(pevent, data);
434 if (column == TRACE_VIEW_STORE_COL_PID)
435 g_value_set_uint(value, val);
436 else {
437 comm = pevent_data_comm_from_pid(pevent, val);
438 g_value_set_string(value, comm);
439 }
440 break;
441
442 case TRACE_VIEW_STORE_COL_LAT:
443 trace_seq_init(&s);
444 pevent_data_lat_fmt(pevent, &s, data, data->size);
445 g_value_set_string(value, s.buffer);
446 break;
447
448 case TRACE_VIEW_STORE_COL_EVENT:
449 case TRACE_VIEW_STORE_COL_INFO:
450 val = pevent_data_type(pevent, data);
451 event = pevent_data_event_from_type(pevent, val);
452 if (column == TRACE_VIEW_STORE_COL_EVENT) {
453 g_value_set_string(value, event->name);
454 break;
455 }
456
457
458 trace_seq_init(&s);
459 pevent_event_info(&s, event, cpu, data, data->size,
460 record->timestamp);
461 g_value_set_string(value, s.buffer);
462 break;
463 }
464 free(data);
465 }
466}
467
468
469/*****************************************************************************
470 *
471 * trace_view_store_iter_next: Takes an iter structure and sets it to point
472 * to the next row.
473 *
474 *****************************************************************************/
475
476static gboolean
477trace_view_store_iter_next (GtkTreeModel *tree_model,
478 GtkTreeIter *iter)
479{
480 TraceViewRecord *record, *nextrecord;
481 TraceViewStore *trace_view_store;
482
483 g_return_val_if_fail (TRACE_VIEW_IS_LIST (tree_model), FALSE);
484
485 if (iter == NULL || iter->user_data == NULL)
486 return FALSE;
487
488 trace_view_store = TRACE_VIEW_STORE(tree_model);
489
490 record = (TraceViewRecord *) iter->user_data;
491
492 /* Is this the last record in the list? */
493 if ((record->pos + 1) >= trace_view_store->num_rows)
494 return FALSE;
495
496 nextrecord = trace_view_store->rows[(record->pos + 1)];
497
498 g_assert ( nextrecord != NULL );
499 g_assert ( nextrecord->pos == (record->pos + 1) );
500
501 iter->stamp = trace_view_store->stamp;
502 iter->user_data = nextrecord;
503
504 return TRUE;
505}
506
507
508/*****************************************************************************
509 *
510 * trace_view_store_iter_children: Returns TRUE or FALSE depending on whether
511 * the row specified by 'parent' has any children.
512 * If it has children, then 'iter' is set to
513 * point to the first child. Special case: if
514 * 'parent' is NULL, then the first top-level
515 * row should be returned if it exists.
516 *
517 *****************************************************************************/
518
519static gboolean
520trace_view_store_iter_children (GtkTreeModel *tree_model,
521 GtkTreeIter *iter,
522 GtkTreeIter *parent)
523{
524 TraceViewStore *trace_view_store;
525
526 g_return_val_if_fail (parent == NULL || parent->user_data != NULL, FALSE);
527
528 /* this is a list, nodes have no children */
529 if (parent)
530 return FALSE;
531
532 /* parent == NULL is a special case; we need to return the first top-level row */
533
534 g_return_val_if_fail (TRACE_VIEW_IS_LIST (tree_model), FALSE);
535
536 trace_view_store = TRACE_VIEW_STORE(tree_model);
537
538 /* No rows => no first row */
539 if (trace_view_store->num_rows == 0)
540 return FALSE;
541
542 /* Set iter to first item in list */
543 iter->stamp = trace_view_store->stamp;
544 iter->user_data = trace_view_store->rows[0];
545
546 return TRUE;
547}
548
549
550/*****************************************************************************
551 *
552 * trace_view_store_iter_has_child: Returns TRUE or FALSE depending on whether
553 * the row specified by 'iter' has any children.
554 * We only have a list and thus no children.
555 *
556 *****************************************************************************/
557
558static gboolean
559trace_view_store_iter_has_child (GtkTreeModel *tree_model,
560 GtkTreeIter *iter)
561{
562 return FALSE;
563}
564
565
566/*****************************************************************************
567 *
568 * trace_view_store_iter_n_children: Returns the number of children the row
569 * specified by 'iter' has. This is usually 0,
570 * as we only have a list and thus do not have
571 * any children to any rows. A special case is
572 * when 'iter' is NULL, in which case we need
573 * to return the number of top-level nodes,
574 * ie. the number of rows in our list.
575 *
576 *****************************************************************************/
577
578static gint
579trace_view_store_iter_n_children (GtkTreeModel *tree_model,
580 GtkTreeIter *iter)
581{
582 TraceViewStore *trace_view_store;
583
584 g_return_val_if_fail (TRACE_VIEW_IS_LIST (tree_model), -1);
585 g_return_val_if_fail (iter == NULL || iter->user_data != NULL, FALSE);
586
587 trace_view_store = TRACE_VIEW_STORE(tree_model);
588
589 /* special case: if iter == NULL, return number of top-level rows */
590 if (!iter)
591 return trace_view_store->num_rows;
592
593 return 0; /* otherwise, this is easy again for a list */
594}
595
596
597/*****************************************************************************
598 *
599 * trace_view_store_iter_nth_child: If the row specified by 'parent' has any
600 * children, set 'iter' to the n-th child and
601 * return TRUE if it exists, otherwise FALSE.
602 * A special case is when 'parent' is NULL, in
603 * which case we need to set 'iter' to the n-th
604 * row if it exists.
605 *
606 *****************************************************************************/
607
608static gboolean
609trace_view_store_iter_nth_child (GtkTreeModel *tree_model,
610 GtkTreeIter *iter,
611 GtkTreeIter *parent,
612 gint n)
613{
614 TraceViewRecord *record;
615 TraceViewStore *trace_view_store;
616
617 g_return_val_if_fail (TRACE_VIEW_IS_LIST (tree_model), FALSE);
618
619 trace_view_store = TRACE_VIEW_STORE(tree_model);
620
621 /* a list has only top-level rows */
622 if(parent)
623 return FALSE;
624
625 /* special case: if parent == NULL, set iter to n-th top-level row */
626
627 if( n >= trace_view_store->num_rows )
628 return FALSE;
629
630 record = trace_view_store->rows[n];
631
632 g_assert( record != NULL );
633 g_assert( record->pos == n );
634
635 iter->stamp = trace_view_store->stamp;
636 iter->user_data = record;
637
638 return TRUE;
639}
640
641
642/*****************************************************************************
643 *
644 * trace_view_store_iter_parent: Point 'iter' to the parent node of 'child'. As
645 * we have a list and thus no children and no
646 * parents of children, we can just return FALSE.
647 *
648 *****************************************************************************/
649
650static gboolean
651trace_view_store_iter_parent (GtkTreeModel *tree_model,
652 GtkTreeIter *iter,
653 GtkTreeIter *child)
654{
655 return FALSE;
656}
657
658
659/*****************************************************************************
660 *
661 * merge_sort_rows_ts: Merge sort the data by time stamp.
662 *
663 *
664 *****************************************************************************/
665
666static void merge_sort_rows_ts(TraceViewStore *store)
667{
668 guint64 ts;
669 gint next;
670 guint *indexes;
671 guint count = 0;
672 gint cpu;
673 guint i;
674
675
676 indexes = g_new0(guint, store->cpus);
677
678 /* Now sort these by timestamp */
679 do {
680 next = -1;
681 ts = 0;
682 for (cpu = 0; cpu < store->cpus; cpu++) {
683 if (indexes[cpu] == store->cpu_items[cpu])
684 continue;
685 i = indexes[cpu];
686 if (!ts || store->cpu_list[cpu][i].timestamp < ts) {
687 ts = store->cpu_list[cpu][i].timestamp;
688 next = cpu;
689 }
690 }
691 if (next >= 0) {
692 i = indexes[next]++;
693 store->rows[count] = &store->cpu_list[next][i];
694 store->cpu_list[next][i].pos = count++;
695 }
696 } while (next >= 0);
697
698 g_free(indexes);
699}
700
701/*****************************************************************************
702 *
703 * trace_view_store_new: This is what you use in your own code to create a
704 * new trace view store tree model for you to use.
705 *
706 *****************************************************************************/
707
708TraceViewStore *
709trace_view_store_new (struct tracecmd_input *handle)
710{
711 TraceViewStore *newstore;
712 struct record *data;
713 gint cpu, count, total=0;
714 struct temp {
715 guint64 offset;
716 guint64 ts;
717 struct temp *next;
718 } *list, **next, *rec;
719
720 newstore = (TraceViewStore*) g_object_new (TRACE_VIEW_STORE_TYPE, NULL);
721
722 g_assert( newstore != NULL );
723
724 newstore->handle = handle;
725 newstore->cpus = tracecmd_cpus(handle);
726
727 newstore->cpu_list = g_new(TraceViewRecord *, newstore->cpus);
728 g_assert(newstore->cpu_list != NULL);
729
730 newstore->cpu_items = g_new(gint, newstore->cpus);
731 g_assert(newstore->cpu_items != NULL);
732
733 for (cpu = 0; cpu < newstore->cpus; cpu++) {
734
735 count = 0;
736 list = NULL;
737 next = &list;
738
739 do {
740 data = tracecmd_read_data(handle, cpu);
741 if (data) {
742 *next = rec = g_malloc(sizeof(*rec));
743 g_assert(rec != NULL);
744 rec->offset = data->offset;
745 rec->ts = data->ts;
746 rec->next = NULL;
747 next = &rec->next;
748 free(data);
749 }
750 count++;
751 } while (data);
752
753 if (count) {
754 TraceViewRecord *trec;
755 struct temp *t;
756 gint i;
757
758 rec = list;
759
760 trec = g_new(TraceViewRecord, count);
761 for (i = 0; i < count; i++) {
762 g_assert(rec != NULL);
763 trec[i].cpu = cpu;
764 trec[i].timestamp = rec->ts;
765 trec[i].offset = rec->offset;
766 trec[i].visible = 1;
767 trec[i].pos = i;
768 t = rec;
769 rec = rec->next;
770 g_free(t);
771 }
772 g_assert(rec == NULL);
773
774 newstore->cpu_list[cpu] = trec;
775 } else
776 newstore->cpu_list[cpu] = NULL;
777
778 newstore->cpu_items[cpu] = count;
779
780 total += count;
781 }
782
783 newstore->num_rows = total;
784 newstore->rows = g_malloc(sizeof(*newstore->rows) * total);
785
786 merge_sort_rows_ts(newstore);
787
788 return newstore;
789}
790
791
792/*****************************************************************************
793 *
794 * trace_view_store_append_record: Empty lists are boring. This function can
795 * be used in your own code to add rows to the
796 * list. Note how we emit the "row-inserted"
797 * signal after we have appended the row
798 * internally, so the tree view and other
799 * interested objects know about the new row.
800 *
801 *****************************************************************************/
802
803#if 0
804void
805trace_view_store_append_record (TraceViewStore *trace_view_store,
806 const gchar *name,
807 guint year_born)
808{
809 GtkTreeIter iter;
810 GtkTreePath *path;
811 TraceViewRecord *newrecord;
812 gulong newsize;
813 guint pos;
814
815 g_return_if_fail (TRACE_VIEW_IS_LIST(trace_view_store));
816 g_return_if_fail (name != NULL);
817
818 pos = trace_view_store->num_rows;
819
820 trace_view_store->num_rows++;
821
822 newsize = trace_view_store->num_rows * sizeof(TraceViewRecord*);
823
824 trace_view_store->rows = g_realloc(trace_view_store->rows, newsize);
825
826 newrecord = g_new0(TraceViewRecord, 1);
827
828 newrecord->name = g_strdup(name);
829 newrecord->name_collate_key = g_utf8_collate_key(name,-1); /* for fast sorting, used later */
830 newrecord->year_born = year_born;
831
832 trace_view_store->rows[pos] = newrecord;
833 newrecord->pos = pos;
834
835 /* inform the tree view and other interested objects
836 * (e.g. tree row references) that we have inserted
837 * a new row, and where it was inserted */
838
839 path = gtk_tree_path_new();
840 gtk_tree_path_append_index(path, newrecord->pos);
841
842 trace_view_store_get_iter(GTK_TREE_MODEL(trace_view_store), &iter, path);
843
844 gtk_tree_model_row_inserted(GTK_TREE_MODEL(trace_view_store), path, &iter);
845
846 gtk_tree_path_free(path);
847}
848#endif
diff --git a/trace-view-store.h b/trace-view-store.h
new file mode 100644
index 0000000..73a38e7
--- /dev/null
+++ b/trace-view-store.h
@@ -0,0 +1,104 @@
1#ifndef _trace_view_store_h_included_
2#define _trace_view_store_h_included_
3
4#include <gtk/gtk.h>
5#include "trace-cmd.h"
6
7/* Some boilerplate GObject defines. 'klass' is used
8 * instead of 'class', because 'class' is a C++ keyword */
9
10#define TRACE_VIEW_STORE_TYPE (trace_view_store_get_type ())
11#define TRACE_VIEW_STORE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TRACE_VIEW_STORE_TYPE, TraceViewStore))
12#define TRACE_VIEW_STORE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TRACE_VIEW_STORE_TYPE, TraceViewStoreClass))
13#define TRACE_VIEW_IS_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TRACE_VIEW_STORE_TYPE))
14#define TRACE_VIEW_IS_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TRACE_VIEW_STORE_TYPE))
15#define TRACE_VIEW_STORE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TRACE_VIEW_STORE_TYPE, TraceViewStoreClass))
16
17/* The data columns that we export via the tree model interface */
18
19enum
20{
21 TRACE_VIEW_STORE_COL_CPU,
22 TRACE_VIEW_STORE_COL_TS,
23 TRACE_VIEW_STORE_COL_COMM,
24 TRACE_VIEW_STORE_COL_PID,
25 TRACE_VIEW_STORE_COL_LAT,
26 TRACE_VIEW_STORE_COL_EVENT,
27 TRACE_VIEW_STORE_COL_INFO,
28 TRACE_VIEW_STORE_N_COLUMNS,
29} ;
30
31
32typedef struct _TraceViewRecord TraceViewRecord;
33typedef struct _TraceViewStore TraceViewStore;
34typedef struct _TraceViewStoreClass TraceViewStoreClass;
35
36
37
38/* TraceViewRecord: this structure represents a row */
39
40struct _TraceViewRecord
41{
42 /* What we need from the record */
43 guint64 timestamp;
44 guint64 offset;
45 gint cpu;
46
47 /* admin stuff used by the trace view store model */
48 gint visible;
49 guint pos; /* pos within the array */
50};
51
52
53
54/* TraceViewStore: this structure contains everything we need for our
55 * model implementation. You can add extra fields to
56 * this structure, e.g. hashtables to quickly lookup
57 * rows or whatever else you might need, but it is
58 * crucial that 'parent' is the first member of the
59 * structure. */
60
61struct _TraceViewStore
62{
63 GObject parent; /* this MUST be the first member */
64
65 guint num_rows; /* number of rows that we have */
66 TraceViewRecord **rows; /* a dynamically allocated array of pointers to
67 * the TraceViewRecord structure for each row */
68
69 guint visible_column_mask;
70 gint n_columns; /* number of columns visible */
71
72 GType column_types[TRACE_VIEW_STORE_N_COLUMNS];
73
74 /* Tracecmd specific info */
75 struct tracecmd_input *handle;
76 int cpus;
77
78 TraceViewRecord **cpu_list;
79 gint *cpu_items;
80
81 gint stamp; /* Random integer to check whether an iter belongs to our model */
82};
83
84
85
86/* TraceViewStoreClass: more boilerplate GObject stuff */
87
88struct _TraceViewStoreClass
89{
90 GObjectClass parent_class;
91};
92
93
94GType trace_view_store_get_type (void);
95
96TraceViewStore *trace_view_store_new (struct tracecmd_input *handle);
97
98#if 0
99void trace_view_store_append_record (TraceViewStore *trace_view_store,
100 const gchar *name,
101 guint year_born);
102#endif
103
104#endif /* _trace_view_store_h_included_ */