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
process_sort_func ( GtkTreeModel
*model
,
52 guint a_pid
, a_tgid
, a_ppid
, a_cpu
;
53 gulong a_birth_s
, a_birth_ns
;
58 guint b_pid
, b_tgid
, b_ppid
, b_cpu
;
59 gulong b_birth_s
, b_birth_ns
;
62 gtk_tree_model_get(model
,
64 PROCESS_COLUMN
, &a_name
,
65 BRAND_COLUMN
, &a_brand
,
70 BIRTH_S_COLUMN
, &a_birth_s
,
71 BIRTH_NS_COLUMN
, &a_birth_ns
,
72 TRACE_COLUMN
, &a_trace
,
75 gtk_tree_model_get(model
,
77 PROCESS_COLUMN
, &b_name
,
78 BRAND_COLUMN
, &b_brand
,
83 BIRTH_S_COLUMN
, &b_birth_s
,
84 BIRTH_NS_COLUMN
, &b_birth_ns
,
85 TRACE_COLUMN
, &b_trace
,
90 if(a_pid
== 0 && b_pid
== 0) {
91 /* If 0, order by CPU */
92 if(a_cpu
> b_cpu
) return 1;
93 if(a_cpu
< b_cpu
) return -1;
95 } else { /* if not 0, order by pid */
97 if(a_pid
> b_pid
) return 1;
98 if(a_pid
< b_pid
) return -1;
101 /* Order by birth second */
103 if(a_birth_s
> b_birth_s
) return 1;
104 if(a_birth_s
< b_birth_s
) return -1;
107 /* Order by birth nanosecond */
108 if(a_birth_ns
> b_birth_ns
) return 1;
109 if(a_birth_ns
< b_birth_ns
) return -1;
111 /* Order by trace_num */
112 if(a_trace
> b_trace
) return 1;
113 if(a_trace
< b_trace
) return -1;
119 static guint
process_list_hash_fct(gconstpointer key
)
121 guint pid
= ((const ProcessInfo
*)key
)->pid
;
122 return ((pid
>>8 ^ pid
>>4 ^ pid
>>2 ^ pid
) ^ ((const ProcessInfo
*)key
)->cpu
);
125 /* If hash is good, should be different */
126 static gboolean
process_list_equ_fct(gconstpointer a
, gconstpointer b
)
128 const ProcessInfo
*pa
= (const ProcessInfo
*)a
;
129 const ProcessInfo
*pb
= (const ProcessInfo
*)b
;
133 if(likely(pa
->pid
!= pb
->pid
))
135 if(likely((pa
->pid
== 0 && (pa
->cpu
!= pb
->cpu
))))
137 if(unlikely(ltt_time_compare(pa
->birth
, pb
->birth
) != 0))
139 if(unlikely(pa
->trace_num
!= pb
->trace_num
))
145 void destroy_hash_key(gpointer key
);
147 void destroy_hash_data(gpointer data
);
150 gboolean
scroll_event(GtkWidget
*widget
, GdkEventScroll
*event
, gpointer data
)
152 ControlFlowData
*control_flow_data
=
153 (ControlFlowData
*)g_object_get_data(
155 "control_flow_data");
156 Drawing_t
*drawing
= control_flow_data
->drawing
;
157 unsigned int cell_height
=
158 get_cell_height(GTK_TREE_VIEW(control_flow_data
->process_list
->process_list_widget
));
160 switch(event
->direction
) {
162 gtk_adjustment_set_value(control_flow_data
->v_adjust
,
163 gtk_adjustment_get_value(control_flow_data
->v_adjust
) - cell_height
);
165 case GDK_SCROLL_DOWN
:
166 gtk_adjustment_set_value(control_flow_data
->v_adjust
,
167 gtk_adjustment_get_value(control_flow_data
->v_adjust
) + cell_height
);
170 g_error("should only scroll up and down.");
176 static void update_index_to_pixmap_each(ProcessInfo
*key
,
177 HashedProcessData
*value
,
178 ProcessList
*process_list
)
180 guint array_index
= processlist_get_index_from_data(process_list
, value
);
182 g_assert(array_index
< process_list
->index_to_pixmap
->len
);
185 (GdkPixmap
**)&g_ptr_array_index(process_list
->index_to_pixmap
, array_index
);
187 *pixmap
= value
->pixmap
;
191 void update_index_to_pixmap(ProcessList
*process_list
)
193 g_ptr_array_set_size(process_list
->index_to_pixmap
,
194 g_hash_table_size(process_list
->process_hash
));
195 g_hash_table_foreach(process_list
->process_hash
,
196 (GHFunc
)update_index_to_pixmap_each
,
201 static void update_pixmap_size_each(ProcessInfo
*key
,
202 HashedProcessData
*value
,
205 GdkPixmap
*old_pixmap
= value
->pixmap
;
208 gdk_pixmap_new(old_pixmap
,
213 gdk_pixmap_unref(old_pixmap
);
217 void update_pixmap_size(ProcessList
*process_list
, guint width
)
219 g_hash_table_foreach(process_list
->process_hash
,
220 (GHFunc
)update_pixmap_size_each
,
225 typedef struct _CopyPixmap
{
229 gint xsrc
, ysrc
, xdest
, ydest
, width
, height
;
232 static void copy_pixmap_region_each(ProcessInfo
*key
,
233 HashedProcessData
*value
,
236 GdkPixmap
*src
= cp
->src
;
237 GdkPixmap
*dest
= cp
->dest
;
240 dest
= value
->pixmap
;
244 gdk_draw_drawable (dest
,
248 cp
->xdest
, cp
->ydest
,
249 cp
->width
, cp
->height
);
252 void copy_pixmap_region(ProcessList
*process_list
, GdkDrawable
*dest
,
253 GdkGC
*gc
, GdkDrawable
*src
,
254 gint xsrc
, gint ysrc
,
255 gint xdest
, gint ydest
, gint width
, gint height
)
257 CopyPixmap cp
= { dest
, gc
, src
, xsrc
, ysrc
, xdest
, ydest
, width
, height
};
259 g_hash_table_foreach(process_list
->process_hash
,
260 (GHFunc
)copy_pixmap_region_each
,
266 typedef struct _RectanglePixmap
{
268 gint x
, y
, width
, height
;
272 static void rectangle_pixmap_each(ProcessInfo
*key
,
273 HashedProcessData
*value
,
277 rp
->height
= value
->height
;
279 gdk_draw_rectangle (value
->pixmap
,
283 rp
->width
, rp
->height
);
289 void rectangle_pixmap(ProcessList
*process_list
, GdkGC
*gc
,
290 gboolean filled
, gint x
, gint y
, gint width
, gint height
)
292 RectanglePixmap rp
= { filled
, x
, y
, width
, height
, gc
};
294 g_hash_table_foreach(process_list
->process_hash
,
295 (GHFunc
)rectangle_pixmap_each
,
300 /* Renders each pixmaps into on big drawable */
301 void copy_pixmap_to_screen(ProcessList
*process_list
,
305 gint width
, gint height
)
307 if(process_list
->index_to_pixmap
->len
== 0) return;
308 guint cell_height
= process_list
->cell_height
;
311 gint begin
= floor(y
/(double)cell_height
);
312 gint end
= MIN(ceil((y
+height
)/(double)cell_height
),
313 process_list
->index_to_pixmap
->len
);
316 for(i
=begin
; i
<end
; i
++) {
317 g_assert(i
<process_list
->index_to_pixmap
->len
);
318 /* Render the pixmap to the screen */
320 //(GdkPixmap*)g_ptr_array_index(process_list->index_to_pixmap, i);
321 GDK_PIXMAP(g_ptr_array_index(process_list
->index_to_pixmap
, i
));
323 gdk_draw_drawable (dest
,
333 ProcessList
*processlist_construct(void)
335 GtkTreeViewColumn
*column
;
336 GtkCellRenderer
*renderer
;
338 ProcessList
* process_list
= g_new(ProcessList
,1);
340 process_list
->number_of_process
= 0;
342 process_list
->current_hash_data
= NULL
;
344 /* Create the Process list */
345 process_list
->list_store
= gtk_list_store_new ( N_COLUMNS
,
357 process_list
->process_list_widget
=
358 gtk_tree_view_new_with_model
359 (GTK_TREE_MODEL (process_list
->list_store
));
361 g_object_unref (G_OBJECT (process_list
->list_store
));
363 gtk_tree_sortable_set_default_sort_func(
364 GTK_TREE_SORTABLE(process_list
->list_store
),
370 gtk_tree_sortable_set_sort_column_id(
371 GTK_TREE_SORTABLE(process_list
->list_store
),
372 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
376 process_list
->process_hash
= g_hash_table_new_full(
377 process_list_hash_fct
, process_list_equ_fct
,
378 destroy_hash_key
, destroy_hash_data
382 gtk_tree_view_set_headers_visible(
383 GTK_TREE_VIEW(process_list
->process_list_widget
), TRUE
);
385 /* Create a column, associating the "text" attribute of the
386 * cell_renderer to the first column of the model */
387 /* Columns alignment : 0.0 : Left 0.5 : Center 1.0 : Right */
388 renderer
= gtk_cell_renderer_text_new ();
389 process_list
->renderer
= renderer
;
391 gint vertical_separator
;
392 gtk_widget_style_get (GTK_WIDGET (process_list
->process_list_widget
),
393 "vertical-separator", &vertical_separator
,
395 gtk_cell_renderer_get_size(renderer
,
396 GTK_WIDGET(process_list
->process_list_widget
),
401 &process_list
->cell_height
);
403 #if GTK_CHECK_VERSION(2,4,15)
405 g_object_get(G_OBJECT(renderer
), "ypad", &ypad
, NULL
);
407 process_list
->cell_height
+= ypad
;
409 process_list
->cell_height
+= vertical_separator
;
412 column
= gtk_tree_view_column_new_with_attributes ( "Resource",
417 gtk_tree_view_column_set_alignment (column
, 0.0);
418 gtk_tree_view_column_set_fixed_width (column
, 45);
419 gtk_tree_view_append_column (
420 GTK_TREE_VIEW (process_list
->process_list_widget
), column
);
422 process_list
->button
= column
->button
;
424 // column = gtk_tree_view_column_new_with_attributes ( "Brand",
429 // gtk_tree_view_column_set_alignment (column, 0.0);
430 // gtk_tree_view_column_set_fixed_width (column, 45);
431 // gtk_tree_view_append_column (
432 // GTK_TREE_VIEW (process_list->process_list_widget), column);
434 // column = gtk_tree_view_column_new_with_attributes ( "PID",
439 // gtk_tree_view_append_column (
440 // GTK_TREE_VIEW (process_list->process_list_widget), column);
442 // column = gtk_tree_view_column_new_with_attributes ( "TGID",
447 // gtk_tree_view_append_column (
448 // GTK_TREE_VIEW (process_list->process_list_widget), column);
450 // column = gtk_tree_view_column_new_with_attributes ( "PPID",
455 // gtk_tree_view_append_column (
456 // GTK_TREE_VIEW (process_list->process_list_widget), column);
458 // column = gtk_tree_view_column_new_with_attributes ( "CPU",
463 // gtk_tree_view_append_column (
464 // GTK_TREE_VIEW (process_list->process_list_widget), column);
466 // column = gtk_tree_view_column_new_with_attributes ( "Birth sec",
471 // gtk_tree_view_append_column (
472 // GTK_TREE_VIEW (process_list->process_list_widget), column);
474 // //gtk_tree_view_column_set_visible(column, 0);
476 // column = gtk_tree_view_column_new_with_attributes ( "Birth nsec",
481 // gtk_tree_view_append_column (
482 // GTK_TREE_VIEW (process_list->process_list_widget), column);
484 // column = gtk_tree_view_column_new_with_attributes ( "TRACE",
489 // gtk_tree_view_append_column (
490 // GTK_TREE_VIEW (process_list->process_list_widget), column);
493 //gtk_tree_view_column_set_visible(column, 0);
495 g_object_set_data_full(
496 G_OBJECT(process_list
->process_list_widget
),
499 (GDestroyNotify
)processlist_destroy
);
501 process_list
->index_to_pixmap
= g_ptr_array_sized_new(ALLOCATE_PROCESSES
);
506 void processlist_destroy(ProcessList
*process_list
)
508 g_debug("processlist_destroy %p", process_list
);
509 g_hash_table_destroy(process_list
->process_hash
);
510 process_list
->process_hash
= NULL
;
511 g_ptr_array_free(process_list
->index_to_pixmap
, TRUE
);
513 g_free(process_list
);
514 g_debug("processlist_destroy end");
517 static gboolean
remove_hash_item(ProcessInfo
*process_info
,
518 HashedProcessData
*hashed_process_data
,
519 ProcessList
*process_list
)
523 iter
= hashed_process_data
->y_iter
;
525 gtk_list_store_remove (process_list
->list_store
, &iter
);
526 gdk_pixmap_unref(hashed_process_data
->pixmap
);
528 if(likely(process_list
->current_hash_data
!= NULL
)) {
529 if(likely(hashed_process_data
==
530 process_list
->current_hash_data
[process_info
->trace_num
][process_info
->cpu
]))
531 process_list
->current_hash_data
[process_info
->trace_num
][process_info
->cpu
] = NULL
;
533 return TRUE
; /* remove the element from the hash table */
536 void processlist_clear(ProcessList
*process_list
)
538 g_info("processlist_clear %p", process_list
);
540 g_hash_table_foreach_remove(process_list
->process_hash
,
541 (GHRFunc
)remove_hash_item
,
542 (gpointer
)process_list
);
543 process_list
->number_of_process
= 0;
544 update_index_to_pixmap(process_list
);
548 GtkWidget
*processlist_get_widget(ProcessList
*process_list
)
550 return process_list
->process_list_widget
;
554 void destroy_hash_key(gpointer key
)
559 void destroy_hash_data(gpointer data
)
565 void processlist_set_name(ProcessList
*process_list
,
567 HashedProcessData
*hashed_process_data
)
569 gtk_list_store_set ( process_list
->list_store
, &hashed_process_data
->y_iter
,
570 PROCESS_COLUMN
, g_quark_to_string(name
),
574 void processlist_set_brand(ProcessList
*process_list
,
576 HashedProcessData
*hashed_process_data
)
578 gtk_list_store_set ( process_list
->list_store
, &hashed_process_data
->y_iter
,
579 BRAND_COLUMN
, g_quark_to_string(brand
),
583 void processlist_set_tgid(ProcessList
*process_list
,
585 HashedProcessData
*hashed_process_data
)
587 gtk_list_store_set ( process_list
->list_store
, &hashed_process_data
->y_iter
,
592 void processlist_set_ppid(ProcessList
*process_list
,
594 HashedProcessData
*hashed_process_data
)
596 gtk_list_store_set ( process_list
->list_store
, &hashed_process_data
->y_iter
,
601 int resourcelist_add( ProcessList
*process_list
,
612 ResourceInfo
**pm_process_info
,
614 ResourceProcessData
**pm_hashed_process_data
)
616 ResourceInfo
*Process_Info
= g_new(ProcessInfo
, 1);
617 HashedResourceData
*hashed_resource_data
= g_new(HashedProcessData
, 1);
618 *pm_hashed_resource_data
= hashed_resource_data
;
619 *pm_resource_info
= Resource_Info
;
621 // Process_Info->pid = pid;
622 // Process_Info->tgid = tgid;
624 // Process_Info->cpu = cpu;
626 // Process_Info->cpu = 0;
627 // Process_Info->ppid = ppid;
628 // Process_Info->birth = *birth;
629 // Process_Info->trace_num = trace_num;
631 /* When we create it from before state update, we are sure that the
632 * last event occured before the beginning of the global area.
634 * If it is created after state update, this value (0) will be
635 * overriden by the new state before anything is drawn.
637 * There are 3 potential lines for the each process: one in the middle,
638 * one under it and one over it. The {over,middle,under} fields tell us
639 * the x pixel on the pixmap where we are. The _used fields tell us
640 * whether that pixel was used. The _marked field tells us if we marked a
643 hashed_resource_data
->x
.over
= 0;
644 hashed_resource_data
->x
.over_used
= FALSE
;
645 hashed_resource_data
->x
.over_marked
= FALSE
;
646 hashed_resource_data
->x
.middle
= 0; // last
647 hashed_resource_data
->x
.middle_used
= FALSE
;
648 hashed_resource_data
->x
.middle_marked
= FALSE
;
649 hashed_resource_data
->x
.under
= 0;
650 hashed_resource_data
->x
.under_used
= FALSE
;
651 hashed_resource_data
->x
.under_marked
= FALSE
;
652 hashed_resource_data
->next_good_time
= ltt_time_zero
;
654 /* Add a new row to the model */
655 gtk_list_store_append ( process_list
->list_store
,
656 &hashed_process_data
->y_iter
);
658 gtk_list_store_set ( process_list
->list_store
, &hashed_process_data
->y_iter
,
659 PROCESS_COLUMN
, g_quark_to_string(name
),
662 g_hash_table_insert(process_list
->process_hash
,
663 (gpointer
)Process_Info
,
664 (gpointer
)hashed_process_data
);
666 process_list
->number_of_process
++; // of resources
668 hashed_process_data
->height
= process_list
->cell_height
;
670 g_assert(hashed_process_data
->height
!= 0);
672 *height
= hashed_process_data
->height
* process_list
->number_of_process
;
674 hashed_process_data
->pixmap
=
675 gdk_pixmap_new(drawing
->drawing_area
->window
,
676 drawing
->alloc_width
,
677 hashed_process_data
->height
,
680 // Clear the image with black background
681 gdk_draw_rectangle (hashed_process_data
->pixmap
,
682 drawing
->drawing_area
->style
->black_gc
,
685 drawing
->alloc_width
,
686 hashed_process_data
->height
);
688 update_index_to_pixmap(process_list
);
692 //int processlist_add( ProcessList *process_list,
693 // Drawing_t *drawing,
703 // ProcessInfo **pm_process_info,
704 // HashedProcessData **pm_hashed_process_data)
706 // ProcessInfo *Process_Info = g_new(ProcessInfo, 1);
707 // HashedProcessData *hashed_process_data = g_new(HashedProcessData, 1);
708 // *pm_hashed_process_data = hashed_process_data;
709 // *pm_process_info = Process_Info;
711 // Process_Info->pid = pid;
712 // Process_Info->tgid = tgid;
714 // Process_Info->cpu = cpu;
716 // Process_Info->cpu = 0;
717 // Process_Info->ppid = ppid;
718 // Process_Info->birth = *birth;
719 // Process_Info->trace_num = trace_num;
721 // /* When we create it from before state update, we are sure that the
722 // * last event occured before the beginning of the global area.
724 // * If it is created after state update, this value (0) will be
725 // * overriden by the new state before anything is drawn.
727 // hashed_process_data->x.over = 0;
728 // hashed_process_data->x.over_used = FALSE;
729 // hashed_process_data->x.over_marked = FALSE;
730 // hashed_process_data->x.middle = 0;
731 // hashed_process_data->x.middle_used = FALSE;
732 // hashed_process_data->x.middle_marked = FALSE;
733 // hashed_process_data->x.under = 0;
734 // hashed_process_data->x.under_used = FALSE;
735 // hashed_process_data->x.under_marked = FALSE;
736 // hashed_process_data->next_good_time = ltt_time_zero;
738 // /* Add a new row to the model */
739 // gtk_list_store_append ( process_list->list_store,
740 // &hashed_process_data->y_iter);
742 // gtk_list_store_set ( process_list->list_store, &hashed_process_data->y_iter,
743 // PROCESS_COLUMN, g_quark_to_string(name),
744 // BRAND_COLUMN, g_quark_to_string(brand),
746 // TGID_COLUMN, tgid,
747 // PPID_COLUMN, ppid,
749 // BIRTH_S_COLUMN, birth->tv_sec,
750 // BIRTH_NS_COLUMN, birth->tv_nsec,
751 // TRACE_COLUMN, trace_num,
753 // //gtk_tree_view_set_model(GTK_TREE_VIEW(process_list->process_list_widget),
754 // // GTK_TREE_MODEL(process_list->list_store));
755 // //gtk_container_resize_children(GTK_CONTAINER(process_list->process_list_widget));
757 // g_hash_table_insert(process_list->process_hash,
758 // (gpointer)Process_Info,
759 // (gpointer)hashed_process_data);
761 // process_list->number_of_process++;
763 // hashed_process_data->height = process_list->cell_height;
765 // g_assert(hashed_process_data->height != 0);
767 // *height = hashed_process_data->height * process_list->number_of_process;
769 // hashed_process_data->pixmap =
770 // gdk_pixmap_new(drawing->drawing_area->window,
771 // drawing->alloc_width,
772 // hashed_process_data->height,
775 // // Clear the image
776 // gdk_draw_rectangle (hashed_process_data->pixmap,
777 // drawing->drawing_area->style->black_gc,
780 // drawing->alloc_width,
781 // hashed_process_data->height);
783 // update_index_to_pixmap(process_list);
789 int processlist_remove( ProcessList
*process_list
,
795 ProcessInfo process_info
;
796 HashedProcessData
*hashed_process_data
;
799 process_info
.pid
= pid
;
801 process_info
.cpu
= cpu
;
803 process_info
.cpu
= 0;
804 process_info
.birth
= *birth
;
805 process_info
.trace_num
= trace_num
;
808 hashed_process_data
=
809 (HashedProcessData
*)g_hash_table_lookup(
810 process_list
->process_hash
,
812 if(likely(hashed_process_data
!= NULL
))
814 iter
= hashed_process_data
->y_iter
;
816 gtk_list_store_remove (process_list
->list_store
, &iter
);
818 g_hash_table_remove(process_list
->process_hash
,
821 if(likely(process_list
->current_hash_data
!= NULL
)) {
822 if(likely(hashed_process_data
== process_list
->current_hash_data
[trace_num
][cpu
])) {
823 process_list
->current_hash_data
[trace_num
][cpu
] = NULL
;
827 gdk_pixmap_unref(hashed_process_data
->pixmap
);
829 update_index_to_pixmap(process_list
);
831 process_list
->number_of_process
--;
841 static inline guint
get_cpu_number_from_name(GQuark name
)
847 string
= g_quark_to_string(name
);
849 begin
= strrchr(string
, '/');
852 g_assert(begin
!= '\0');
854 cpu
= strtoul(begin
, NULL
, 10);