1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Mathieu Desnoyers
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
30 #include "processlist.h"
34 #define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
35 //#define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format)
37 /* Preallocated Size of the index_to_pixmap array */
38 #define ALLOCATE_PROCESSES 1000
40 /*****************************************************************************
41 * Methods to synchronize process list *
42 *****************************************************************************/
45 gint
resource_sort_func ( GtkTreeModel
*model
,
53 gtk_tree_model_get(model
, it_a
, NAME_COLUMN
, &a_name
, -1);
55 gtk_tree_model_get(model
, it_b
, NAME_COLUMN
, &b_name
, -1);
57 return strcmp(a_name
, b_name
);
60 static guint
ru_numeric_hash_fct(gconstpointer key
)
62 ResourceUniqueNumeric
*ru
= (ResourceUniqueNumeric
*)key
;
63 int tmp
= (ru
->trace_num
<< 8) ^ ru
->id
;
65 return g_int_hash(&tmp
);
68 static gboolean
ru_numeric_equ_fct(gconstpointer a
, gconstpointer b
)
70 const ResourceUniqueNumeric
*pa
= (const ResourceUniqueNumeric
*)a
;
71 const ResourceUniqueNumeric
*pb
= (const ResourceUniqueNumeric
*)b
;
73 if(pa
->id
== pb
->id
&& pa
->trace_num
== pb
->trace_num
)
79 void destroy_hash_key(gpointer key
);
81 void destroy_hash_data(gpointer data
);
84 gboolean
scroll_event(GtkWidget
*widget
, GdkEventScroll
*event
, gpointer data
)
86 ControlFlowData
*control_flow_data
=
87 (ControlFlowData
*)g_object_get_data(
90 Drawing_t
*drawing
= control_flow_data
->drawing
;
91 unsigned int cell_height
=
92 get_cell_height(GTK_TREE_VIEW(control_flow_data
->process_list
->process_list_widget
));
94 switch(event
->direction
) {
96 gtk_adjustment_set_value(control_flow_data
->v_adjust
,
97 gtk_adjustment_get_value(control_flow_data
->v_adjust
) - cell_height
);
100 gtk_adjustment_set_value(control_flow_data
->v_adjust
,
101 gtk_adjustment_get_value(control_flow_data
->v_adjust
) + cell_height
);
104 g_error("should only scroll up and down.");
109 static gboolean
update_index_to_pixmap_each (GtkTreeModel
*model
, GtkTreePath
*path
, GtkTreeIter
*iter
, UpdateIndexPixmapArg
*arg
)
111 guint array_index
= arg
->count
;
112 HashedResourceData
*hdata
;
115 gtk_tree_model_get(model
, iter
, NAME_COLUMN
, &name
, DATA_COLUMN
, &hdata
, -1);
117 g_assert(array_index
< arg
->process_list
->index_to_pixmap
->len
);
120 (GdkPixmap
**)&g_ptr_array_index(arg
->process_list
->index_to_pixmap
, array_index
);
121 *pixmap
= hdata
->pixmap
;
128 void update_index_to_pixmap(ProcessList
*process_list
)
131 UpdateIndexPixmapArg arg
;
133 for(i
=0; i
<RV_RESOURCE_COUNT
; i
++) {
134 items
+= g_hash_table_size(process_list
->restypes
[i
].hash_table
);
137 g_ptr_array_set_size(process_list
->index_to_pixmap
, items
);
140 arg
.process_list
= process_list
;
142 gtk_tree_model_foreach(GTK_TREE_MODEL(process_list
->list_store
),
143 (GtkTreeModelForeachFunc
)update_index_to_pixmap_each
, &arg
);
147 static void update_pixmap_size_each(void *key
,
148 HashedResourceData
*value
,
151 GdkPixmap
*old_pixmap
= value
->pixmap
;
154 gdk_pixmap_new(old_pixmap
,
159 gdk_pixmap_unref(old_pixmap
);
163 void update_pixmap_size(ProcessList
*process_list
, guint width
)
166 for(i
=0; i
<RV_RESOURCE_COUNT
; i
++) {
167 g_hash_table_foreach(process_list
->restypes
[i
].hash_table
,
168 (GHFunc
)update_pixmap_size_each
,
174 typedef struct _CopyPixmap
{
178 gint xsrc
, ysrc
, xdest
, ydest
, width
, height
;
181 static void copy_pixmap_region_each(void *key
,
182 HashedResourceData
*value
,
185 GdkPixmap
*src
= cp
->src
;
186 GdkPixmap
*dest
= cp
->dest
;
189 dest
= value
->pixmap
;
193 gdk_draw_drawable (dest
,
197 cp
->xdest
, cp
->ydest
,
198 cp
->width
, cp
->height
);
201 void copy_pixmap_region(ProcessList
*process_list
, GdkDrawable
*dest
,
202 GdkGC
*gc
, GdkDrawable
*src
,
203 gint xsrc
, gint ysrc
,
204 gint xdest
, gint ydest
, gint width
, gint height
)
207 CopyPixmap cp
= { dest
, gc
, src
, xsrc
, ysrc
, xdest
, ydest
, width
, height
};
209 for(i
=0; i
<RV_RESOURCE_COUNT
; i
++) {
210 g_hash_table_foreach(process_list
->restypes
[i
].hash_table
,
211 (GHFunc
)copy_pixmap_region_each
,
218 typedef struct _RectanglePixmap
{
220 gint x
, y
, width
, height
;
224 static void rectangle_pixmap_each(void *key
,
225 HashedResourceData
*value
,
229 rp
->height
= value
->height
;
231 gdk_draw_rectangle (value
->pixmap
,
235 rp
->width
, rp
->height
);
238 void rectangle_pixmap(ProcessList
*process_list
, GdkGC
*gc
,
239 gboolean filled
, gint x
, gint y
, gint width
, gint height
)
242 RectanglePixmap rp
= { filled
, x
, y
, width
, height
, gc
};
244 for(i
=0; i
<RV_RESOURCE_COUNT
; i
++) {
245 g_hash_table_foreach(process_list
->restypes
[i
].hash_table
,
246 (GHFunc
)rectangle_pixmap_each
,
251 /* Renders each pixmaps into on big drawable */
252 void copy_pixmap_to_screen(ProcessList
*process_list
,
256 gint width
, gint height
)
258 if(process_list
->index_to_pixmap
->len
== 0) return;
259 guint cell_height
= process_list
->cell_height
;
262 gint begin
= floor(y
/(double)cell_height
);
263 gint end
= MIN(ceil((y
+height
)/(double)cell_height
),
264 process_list
->index_to_pixmap
->len
);
267 for(i
=begin
; i
<end
; i
++) {
268 g_assert(i
<process_list
->index_to_pixmap
->len
);
269 /* Render the pixmap to the screen */
271 //(GdkPixmap*)g_ptr_array_index(process_list->index_to_pixmap, i);
272 GDK_PIXMAP(g_ptr_array_index(process_list
->index_to_pixmap
, i
));
274 gdk_draw_drawable (dest
,
284 ProcessList
*processlist_construct(void)
286 GtkTreeViewColumn
*column
;
287 GtkCellRenderer
*renderer
;
289 ProcessList
* process_list
= g_new(ProcessList
,1);
291 process_list
->number_of_process
= 0;
293 process_list
->current_hash_data
= NULL
;
295 /* Create the Process list */
296 process_list
->list_store
= gtk_tree_store_new ( N_COLUMNS
, G_TYPE_STRING
, G_TYPE_POINTER
);
298 process_list
->process_list_widget
=
299 gtk_tree_view_new_with_model
300 (GTK_TREE_MODEL (process_list
->list_store
));
302 gtk_tree_view_set_show_expanders(
303 GTK_TREE_VIEW(process_list
->process_list_widget
), FALSE
);
304 gtk_tree_view_set_level_indentation(
305 process_list
->process_list_widget
, 20);
307 gtk_tree_view_set_enable_tree_lines(process_list
->process_list_widget
, TRUE
);
309 g_object_unref (G_OBJECT (process_list
->list_store
));
311 gtk_tree_sortable_set_default_sort_func(
312 GTK_TREE_SORTABLE(process_list
->list_store
),
317 gtk_tree_sortable_set_sort_column_id(
318 GTK_TREE_SORTABLE(process_list
->list_store
),
319 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
322 gtk_tree_view_set_headers_visible(
323 GTK_TREE_VIEW(process_list
->process_list_widget
), TRUE
);
325 /* Create a column, associating the "text" attribute of the
326 * cell_renderer to the first column of the model */
327 /* Columns alignment : 0.0 : Left 0.5 : Center 1.0 : Right */
328 renderer
= gtk_cell_renderer_text_new ();
329 process_list
->renderer
= renderer
;
331 gint vertical_separator
;
332 gtk_widget_style_get (GTK_WIDGET (process_list
->process_list_widget
),
333 "vertical-separator", &vertical_separator
,
335 gtk_cell_renderer_get_size(renderer
,
336 GTK_WIDGET(process_list
->process_list_widget
),
341 &process_list
->cell_height
);
343 #if GTK_CHECK_VERSION(2,4,15)
345 g_object_get(G_OBJECT(renderer
), "ypad", &ypad
, NULL
);
347 process_list
->cell_height
+= ypad
;
349 process_list
->cell_height
+= vertical_separator
;
352 column
= gtk_tree_view_column_new_with_attributes ( "Resource",
357 gtk_tree_view_column_set_alignment (column
, 0.0);
358 gtk_tree_view_column_set_fixed_width (column
, 45);
359 gtk_tree_view_append_column (
360 GTK_TREE_VIEW (process_list
->process_list_widget
), column
);
362 process_list
->button
= column
->button
;
364 g_object_set_data_full(
365 G_OBJECT(process_list
->process_list_widget
),
368 (GDestroyNotify
)processlist_destroy
);
370 process_list
->index_to_pixmap
= g_ptr_array_sized_new(ALLOCATE_PROCESSES
);
372 process_list
->restypes
[RV_RESOURCE_MACHINE
].hash_table
= g_hash_table_new(ru_numeric_hash_fct
, ru_numeric_equ_fct
);
373 process_list
->restypes
[RV_RESOURCE_CPU
].hash_table
= g_hash_table_new(ru_numeric_hash_fct
, ru_numeric_equ_fct
);
374 process_list
->restypes
[RV_RESOURCE_IRQ
].hash_table
= g_hash_table_new(ru_numeric_hash_fct
, ru_numeric_equ_fct
);
375 process_list
->restypes
[RV_RESOURCE_SOFT_IRQ
].hash_table
= g_hash_table_new(ru_numeric_hash_fct
, ru_numeric_equ_fct
);
376 process_list
->restypes
[RV_RESOURCE_TRAP
].hash_table
= g_hash_table_new(ru_numeric_hash_fct
, ru_numeric_equ_fct
);
377 process_list
->restypes
[RV_RESOURCE_BDEV
].hash_table
= g_hash_table_new(ru_numeric_hash_fct
, ru_numeric_equ_fct
);
382 void processlist_destroy(ProcessList
*process_list
)
386 g_debug("processlist_destroy %p", process_list
);
388 for(i
=0; i
<RV_RESOURCE_COUNT
; i
++) {
389 g_hash_table_destroy(process_list
->restypes
[i
].hash_table
);
390 process_list
->restypes
[i
].hash_table
= NULL
;
392 g_ptr_array_free(process_list
->index_to_pixmap
, TRUE
);
394 g_free(process_list
);
395 g_debug("processlist_destroy end");
398 static gboolean
remove_hash_item(void *key
,
399 HashedResourceData
*hashed_process_data
,
400 ProcessList
*process_list
)
404 iter
= hashed_process_data
->y_iter
;
406 gtk_tree_store_remove (process_list
->list_store
, &iter
);
407 gdk_pixmap_unref(hashed_process_data
->pixmap
);
409 // TODO pmf: check this; might be needed
410 // if(likely(process_list->current_hash_data != NULL)) {
411 // if(likely(hashed_process_data ==
412 // process_list->current_hash_data[process_info->trace_num][process_info->cpu]))
413 // process_list->current_hash_data[process_info->trace_num][process_info->cpu] = NULL;
415 return TRUE
; /* remove the element from the hash table */
418 void processlist_clear(ProcessList
*process_list
)
422 g_info("processlist_clear %p", process_list
);
424 for(i
=RV_RESOURCE_COUNT
-1; i
>=0; i
--) {
425 g_hash_table_foreach_remove(process_list
->restypes
[i
].hash_table
,
426 (GHRFunc
)remove_hash_item
,
427 (gpointer
)process_list
);
429 process_list
->number_of_process
= 0;
430 update_index_to_pixmap(process_list
);
434 GtkWidget
*processlist_get_widget(ProcessList
*process_list
)
436 return process_list
->process_list_widget
;
440 void destroy_hash_key(gpointer key
)
445 void destroy_hash_data(gpointer data
)
450 GQuark
make_cpu_name(ControlFlowData
*resourceview_data
, guint trace_num
, guint id
)
455 str
= g_strdup_printf("CPU%u", id
);
456 name
= g_quark_from_string(str
);
462 GQuark
make_irq_name(ControlFlowData
*resourceview_data
, guint trace_num
, guint id
)
467 str
= g_strdup_printf("IRQ %u", id
);
468 name
= g_quark_from_string(str
);
474 GQuark
make_soft_irq_name(ControlFlowData
*resourceview_data
, guint trace_num
, guint id
)
479 str
= g_strdup_printf("SOFTIRQ %u", id
);
480 name
= g_quark_from_string(str
);
486 GQuark
make_trap_name(ControlFlowData
*resourceview_data
, guint trace_num
, guint id
)
491 str
= g_strdup_printf("Trap %u", id
);
492 name
= g_quark_from_string(str
);
498 GQuark
make_bdev_name(ControlFlowData
*resourceview_data
, guint trace_num
, guint id
)
503 str
= g_strdup_printf("Block (%u,%u)", MAJOR(id
), MINOR(id
));
504 name
= g_quark_from_string(str
);
510 HashedResourceData
*resourcelist_obtain_machine(ControlFlowData
*resourceview_data
, guint trace_num
, guint id
)
512 ResourceUniqueNumeric
*ru
= g_new(ResourceUniqueNumeric
, 1);
513 HashedResourceData
*data
= g_new(HashedResourceData
, 1);
515 /* Prepare hash key */
516 ru
->trace_num
= trace_num
;
519 /* Search within hash table */
520 GHashTable
*ht
= resourceview_data
->process_list
->restypes
[RV_RESOURCE_MACHINE
].hash_table
;
521 data
= g_hash_table_lookup(ht
, ru
);
523 /* If not found in hash table, add it */
527 data
= g_malloc(sizeof(HashedResourceData
));
528 /* Prepare hashed data */
529 data
->type
= RV_RESOURCE_MACHINE
;
531 data
->x
.over_used
= FALSE
;
532 data
->x
.over_marked
= FALSE
;
533 data
->x
.middle
= 0; // last
534 data
->x
.middle_used
= FALSE
;
535 data
->x
.middle_marked
= FALSE
;
537 data
->x
.under_used
= FALSE
;
538 data
->x
.under_marked
= FALSE
;
539 data
->next_good_time
= ltt_time_zero
;
541 data
->height
= resourceview_data
->process_list
->cell_height
;
543 gdk_pixmap_new(resourceview_data
->drawing
->drawing_area
->window
,
544 resourceview_data
->drawing
->alloc_width
,
547 g_assert(data
->pixmap
);
549 gdk_draw_rectangle (data
->pixmap
,
550 resourceview_data
->drawing
->drawing_area
->style
->black_gc
,
553 resourceview_data
->drawing
->alloc_width
,
556 /* add to hash table */
557 g_hash_table_insert(ht
, ru
, data
);
558 resourceview_data
->process_list
->number_of_process
++; // TODO: check
560 /* add to process list */
563 str
= g_strdup_printf("Trace %u", id
);
564 name
= g_quark_from_string(str
);
568 gtk_tree_store_append(resourceview_data
->process_list
->list_store
, &data
->y_iter
, NULL
);
569 gtk_tree_store_set(resourceview_data
->process_list
->list_store
, &data
->y_iter
,
570 NAME_COLUMN
, g_quark_to_string(name
), DATA_COLUMN
, data
,
573 update_index_to_pixmap(resourceview_data
->process_list
);
575 int heightall
= data
->height
* resourceview_data
->process_list
->number_of_process
;
577 gtk_widget_set_size_request(resourceview_data
->drawing
->drawing_area
,
581 gtk_widget_queue_draw(resourceview_data
->drawing
->drawing_area
);
584 gtk_tree_view_expand_all(GTK_TREE_VIEW(resourceview_data
->process_list
->process_list_widget
));
589 HashedResourceData
*resourcelist_obtain_generic(ControlFlowData
*resourceview_data
, gint res_type
, guint trace_num
, guint id
, GQuark (*make_name_func
)(ControlFlowData
*resourceview_data
, guint trace_num
, guint id
))
591 ResourceUniqueNumeric
*ru
= g_new(ResourceUniqueNumeric
, 1);
592 HashedResourceData
*data
= g_new(HashedResourceData
, 1);
594 /* Prepare hash key */
595 ru
->trace_num
= trace_num
;
598 /* Search within hash table */
599 GHashTable
*ht
= resourceview_data
->process_list
->restypes
[res_type
].hash_table
;
600 data
= g_hash_table_lookup(ht
, ru
);
602 /* If not found in hash table, add it */
605 HashedResourceData
*parent
;
607 /* Find the parent machine */
608 parent
= resourcelist_obtain_machine(resourceview_data
, trace_num
, trace_num
);
610 /* Prepare hashed data */
611 data
= g_malloc(sizeof(HashedResourceData
));
613 data
->type
= res_type
;
615 data
->x
.over_used
= FALSE
;
616 data
->x
.over_marked
= FALSE
;
617 data
->x
.middle
= 0; // last
618 data
->x
.middle_used
= FALSE
;
619 data
->x
.middle_marked
= FALSE
;
621 data
->x
.under_used
= FALSE
;
622 data
->x
.under_marked
= FALSE
;
623 data
->next_good_time
= ltt_time_zero
;
625 data
->height
= resourceview_data
->process_list
->cell_height
;
627 gdk_pixmap_new(resourceview_data
->drawing
->drawing_area
->window
,
628 resourceview_data
->drawing
->alloc_width
,
632 gdk_draw_rectangle (data
->pixmap
,
633 resourceview_data
->drawing
->drawing_area
->style
->black_gc
,
636 resourceview_data
->drawing
->alloc_width
,
639 /* add to hash table */
640 g_hash_table_insert(ht
, ru
, data
);
641 resourceview_data
->process_list
->number_of_process
++; // TODO: check
643 /* add to process list */
644 name
= make_name_func(resourceview_data
, trace_num
, id
);
646 gtk_tree_store_append(resourceview_data
->process_list
->list_store
, &data
->y_iter
, &parent
->y_iter
);
647 gtk_tree_store_set(resourceview_data
->process_list
->list_store
, &data
->y_iter
,
648 NAME_COLUMN
, g_quark_to_string(name
), DATA_COLUMN
, data
,
651 update_index_to_pixmap(resourceview_data
->process_list
);
653 int heightall
= data
->height
* resourceview_data
->process_list
->number_of_process
;
655 gtk_widget_set_size_request(resourceview_data
->drawing
->drawing_area
,
659 gtk_widget_queue_draw(resourceview_data
->drawing
->drawing_area
);
665 HashedResourceData
*resourcelist_obtain_cpu(ControlFlowData
*resourceview_data
, guint trace_num
, guint id
)
667 return resourcelist_obtain_generic(resourceview_data
, RV_RESOURCE_CPU
, trace_num
, id
, make_cpu_name
);
670 HashedResourceData
*resourcelist_obtain_irq(ControlFlowData
*resourceview_data
, guint trace_num
, guint id
)
672 return resourcelist_obtain_generic(resourceview_data
, RV_RESOURCE_IRQ
, trace_num
, id
, make_irq_name
);
675 HashedResourceData
*resourcelist_obtain_soft_irq(ControlFlowData
*resourceview_data
, guint trace_num
, guint id
)
677 return resourcelist_obtain_generic(resourceview_data
, RV_RESOURCE_SOFT_IRQ
, trace_num
, id
, make_soft_irq_name
);
680 HashedResourceData
*resourcelist_obtain_trap(ControlFlowData
*resourceview_data
, guint trace_num
, guint id
)
682 return resourcelist_obtain_generic(resourceview_data
, RV_RESOURCE_TRAP
, trace_num
, id
, make_trap_name
);
685 HashedResourceData
*resourcelist_obtain_bdev(ControlFlowData
*resourceview_data
, guint trace_num
, guint id
)
687 return resourcelist_obtain_generic(resourceview_data
, RV_RESOURCE_BDEV
, trace_num
, id
, make_bdev_name
);