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_BDEV
].hash_table
= g_hash_table_new(ru_numeric_hash_fct
, ru_numeric_equ_fct
);
380 void processlist_destroy(ProcessList
*process_list
)
384 g_debug("processlist_destroy %p", process_list
);
386 for(i
=0; i
<RV_RESOURCE_COUNT
; i
++) {
387 g_hash_table_destroy(process_list
->restypes
[i
].hash_table
);
388 process_list
->restypes
[i
].hash_table
= NULL
;
390 g_ptr_array_free(process_list
->index_to_pixmap
, TRUE
);
392 g_free(process_list
);
393 g_debug("processlist_destroy end");
396 static gboolean
remove_hash_item(void *key
,
397 HashedResourceData
*hashed_process_data
,
398 ProcessList
*process_list
)
402 iter
= hashed_process_data
->y_iter
;
404 gtk_tree_store_remove (process_list
->list_store
, &iter
);
405 gdk_pixmap_unref(hashed_process_data
->pixmap
);
407 // TODO pmf: check this; might be needed
408 // if(likely(process_list->current_hash_data != NULL)) {
409 // if(likely(hashed_process_data ==
410 // process_list->current_hash_data[process_info->trace_num][process_info->cpu]))
411 // process_list->current_hash_data[process_info->trace_num][process_info->cpu] = NULL;
413 return TRUE
; /* remove the element from the hash table */
416 void processlist_clear(ProcessList
*process_list
)
420 g_info("processlist_clear %p", process_list
);
422 for(i
=RV_RESOURCE_COUNT
-1; i
>=0; i
--) {
423 g_hash_table_foreach_remove(process_list
->restypes
[i
].hash_table
,
424 (GHRFunc
)remove_hash_item
,
425 (gpointer
)process_list
);
427 process_list
->number_of_process
= 0;
428 update_index_to_pixmap(process_list
);
432 GtkWidget
*processlist_get_widget(ProcessList
*process_list
)
434 return process_list
->process_list_widget
;
438 void destroy_hash_key(gpointer key
)
443 void destroy_hash_data(gpointer data
)
448 GQuark
make_cpu_name(ControlFlowData
*resourceview_data
, guint trace_num
, guint id
)
453 str
= g_strdup_printf("CPU%u", id
);
454 name
= g_quark_from_string(str
);
460 GQuark
make_irq_name(ControlFlowData
*resourceview_data
, guint trace_num
, guint id
)
465 str
= g_strdup_printf("IRQ %u", id
);
466 name
= g_quark_from_string(str
);
472 GQuark
make_bdev_name(ControlFlowData
*resourceview_data
, guint trace_num
, guint id
)
477 str
= g_strdup_printf("Block (%u,%u)", MAJOR(id
), MINOR(id
));
478 name
= g_quark_from_string(str
);
484 HashedResourceData
*resourcelist_obtain_machine(ControlFlowData
*resourceview_data
, guint trace_num
, guint id
)
486 ResourceUniqueNumeric
*ru
= g_new(ResourceUniqueNumeric
, 1);
487 HashedResourceData
*data
= g_new(HashedResourceData
, 1);
489 /* Prepare hash key */
490 ru
->trace_num
= trace_num
;
493 /* Search within hash table */
494 GHashTable
*ht
= resourceview_data
->process_list
->restypes
[RV_RESOURCE_MACHINE
].hash_table
;
495 data
= g_hash_table_lookup(ht
, ru
);
497 /* If not found in hash table, add it */
501 data
= g_malloc(sizeof(HashedResourceData
));
502 /* Prepare hashed data */
503 data
->type
= RV_RESOURCE_MACHINE
;
505 data
->x
.over_used
= FALSE
;
506 data
->x
.over_marked
= FALSE
;
507 data
->x
.middle
= 0; // last
508 data
->x
.middle_used
= FALSE
;
509 data
->x
.middle_marked
= FALSE
;
511 data
->x
.under_used
= FALSE
;
512 data
->x
.under_marked
= FALSE
;
513 data
->next_good_time
= ltt_time_zero
;
515 data
->height
= resourceview_data
->process_list
->cell_height
;
517 gdk_pixmap_new(resourceview_data
->drawing
->drawing_area
->window
,
518 resourceview_data
->drawing
->alloc_width
,
521 g_assert(data
->pixmap
);
523 gdk_draw_rectangle (data
->pixmap
,
524 resourceview_data
->drawing
->drawing_area
->style
->black_gc
,
527 resourceview_data
->drawing
->alloc_width
,
530 /* add to hash table */
531 g_hash_table_insert(ht
, ru
, data
);
532 resourceview_data
->process_list
->number_of_process
++; // TODO: check
534 /* add to process list */
537 str
= g_strdup_printf("Trace %u", id
);
538 name
= g_quark_from_string(str
);
542 gtk_tree_store_append(resourceview_data
->process_list
->list_store
, &data
->y_iter
, NULL
);
543 gtk_tree_store_set(resourceview_data
->process_list
->list_store
, &data
->y_iter
,
544 NAME_COLUMN
, g_quark_to_string(name
), DATA_COLUMN
, data
,
547 update_index_to_pixmap(resourceview_data
->process_list
);
549 int heightall
= data
->height
* resourceview_data
->process_list
->number_of_process
;
551 gtk_widget_set_size_request(resourceview_data
->drawing
->drawing_area
,
555 gtk_widget_queue_draw(resourceview_data
->drawing
->drawing_area
);
558 gtk_tree_view_expand_all(GTK_TREE_VIEW(resourceview_data
->process_list
->process_list_widget
));
563 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
))
565 ResourceUniqueNumeric
*ru
= g_new(ResourceUniqueNumeric
, 1);
566 HashedResourceData
*data
= g_new(HashedResourceData
, 1);
568 /* Prepare hash key */
569 ru
->trace_num
= trace_num
;
572 /* Search within hash table */
573 GHashTable
*ht
= resourceview_data
->process_list
->restypes
[res_type
].hash_table
;
574 data
= g_hash_table_lookup(ht
, ru
);
576 /* If not found in hash table, add it */
579 HashedResourceData
*parent
;
581 /* Find the parent machine */
582 parent
= resourcelist_obtain_machine(resourceview_data
, trace_num
, trace_num
);
584 /* Prepare hashed data */
585 data
= g_malloc(sizeof(HashedResourceData
));
587 data
->type
= res_type
;
589 data
->x
.over_used
= FALSE
;
590 data
->x
.over_marked
= FALSE
;
591 data
->x
.middle
= 0; // last
592 data
->x
.middle_used
= FALSE
;
593 data
->x
.middle_marked
= FALSE
;
595 data
->x
.under_used
= FALSE
;
596 data
->x
.under_marked
= FALSE
;
597 data
->next_good_time
= ltt_time_zero
;
599 data
->height
= resourceview_data
->process_list
->cell_height
;
601 gdk_pixmap_new(resourceview_data
->drawing
->drawing_area
->window
,
602 resourceview_data
->drawing
->alloc_width
,
606 gdk_draw_rectangle (data
->pixmap
,
607 resourceview_data
->drawing
->drawing_area
->style
->black_gc
,
610 resourceview_data
->drawing
->alloc_width
,
613 /* add to hash table */
614 g_hash_table_insert(ht
, ru
, data
);
615 resourceview_data
->process_list
->number_of_process
++; // TODO: check
617 /* add to process list */
618 name
= make_name_func(resourceview_data
, trace_num
, id
);
620 gtk_tree_store_append(resourceview_data
->process_list
->list_store
, &data
->y_iter
, &parent
->y_iter
);
621 gtk_tree_store_set(resourceview_data
->process_list
->list_store
, &data
->y_iter
,
622 NAME_COLUMN
, g_quark_to_string(name
), DATA_COLUMN
, data
,
625 update_index_to_pixmap(resourceview_data
->process_list
);
627 int heightall
= data
->height
* resourceview_data
->process_list
->number_of_process
;
629 gtk_widget_set_size_request(resourceview_data
->drawing
->drawing_area
,
633 gtk_widget_queue_draw(resourceview_data
->drawing
->drawing_area
);
639 HashedResourceData
*resourcelist_obtain_cpu(ControlFlowData
*resourceview_data
, guint trace_num
, guint id
)
641 return resourcelist_obtain_generic(resourceview_data
, RV_RESOURCE_CPU
, trace_num
, id
, make_cpu_name
);
644 HashedResourceData
*resourcelist_obtain_irq(ControlFlowData
*resourceview_data
, guint trace_num
, guint id
)
646 return resourcelist_obtain_generic(resourceview_data
, RV_RESOURCE_IRQ
, trace_num
, id
, make_irq_name
);
649 HashedResourceData
*resourcelist_obtain_bdev(ControlFlowData
*resourceview_data
, guint trace_num
, guint id
)
651 return resourcelist_obtain_generic(resourceview_data
, RV_RESOURCE_BDEV
, trace_num
, id
, make_bdev_name
);