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,
20 /*****************************************************************************
21 * Hooks to be called by the main window *
22 *****************************************************************************/
25 /* Event hooks are the drawing hooks called during traceset read. They draw the
26 * icons, text, lines and background color corresponding to the events read.
28 * Two hooks are used for drawing : before_schedchange and after_schedchange hooks. The
29 * before_schedchange is called before the state update that occurs with an event and
30 * the after_schedchange hook is called after this state update.
32 * The before_schedchange hooks fulfill the task of drawing the visible objects that
33 * corresponds to the data accumulated by the after_schedchange hook.
35 * The after_schedchange hook accumulates the data that need to be shown on the screen
36 * (items) into a queue. Then, the next before_schedchange hook will draw what that
37 * queue contains. That's the Right Way (TM) of drawing items on the screen,
38 * because we need to draw the background first (and then add icons, text, ...
39 * over it), but we only know the length of a background region once the state
40 * corresponding to it is over, which happens to be at the next before_schedchange
43 * We also have a hook called at the end of a chunk to draw the information left
44 * undrawn in each process queue. We use the current time as end of
52 //#define PANGO_ENABLE_BACKEND
61 //#include <pango/pango.h>
63 #include <lttv/lttv.h>
64 #include <lttv/hook.h>
65 #include <lttv/state.h>
66 #include <lttvwindow/lttvwindow.h>
67 #include <lttvwindow/lttvwindowtraces.h>
68 #include <lttvwindow/support.h>
71 #include "eventhooks.h"
73 #include "processlist.h"
77 #define MAX_PATH_LEN 256
78 #define STATE_LINE_WIDTH 6
79 #define COLLISION_POSITION(height) (((height - STATE_LINE_WIDTH)/2) -3)
81 extern GSList
*g_legend_list
;
84 /* Action to do when background computation completed.
86 * Wait for all the awaited computations to be over.
89 static gint
background_ready(void *hook_data
, void *call_data
)
91 ControlFlowData
*resourceview_data
= (ControlFlowData
*)hook_data
;
93 resourceview_data
->background_info_waiting
--;
95 if(resourceview_data
->background_info_waiting
== 0) {
96 g_message("control flow viewer : background computation data ready.");
98 drawing_clear(resourceview_data
->drawing
);
99 processlist_clear(resourceview_data
->process_list
);
100 gtk_widget_set_size_request(
101 resourceview_data
->drawing
->drawing_area
,
102 -1, processlist_get_height(resourceview_data
->process_list
));
103 redraw_notify(resourceview_data
, NULL
);
110 /* Request background computation. Verify if it is in progress or ready first.
111 * Only for each trace in the tab's traceset.
113 static void request_background_data(ControlFlowData
*resourceview_data
)
116 lttvwindow_get_traceset(resourceview_data
->tab
);
117 gint num_traces
= lttv_traceset_number(ts
);
121 LttvHooks
*background_ready_hook
=
123 lttv_hooks_add(background_ready_hook
, background_ready
, resourceview_data
,
125 resourceview_data
->background_info_waiting
= 0;
127 for(i
=0;i
<num_traces
;i
++) {
128 trace
= lttv_traceset_get(ts
, i
);
130 if(lttvwindowtraces_get_ready(g_quark_from_string("state"),trace
)==FALSE
131 && !ts
->has_precomputed_states
) {
133 if(lttvwindowtraces_get_in_progress(g_quark_from_string("state"),
135 /* We first remove requests that could have been done for the same
136 * information. Happens when two viewers ask for it before servicing
139 if(!lttvwindowtraces_background_request_find(trace
, "state"))
140 lttvwindowtraces_background_request_queue(
141 main_window_get_widget(resourceview_data
->tab
), trace
, "state");
142 lttvwindowtraces_background_notify_queue(resourceview_data
,
146 background_ready_hook
);
147 resourceview_data
->background_info_waiting
++;
148 } else { /* in progress */
150 lttvwindowtraces_background_notify_current(resourceview_data
,
154 background_ready_hook
);
155 resourceview_data
->background_info_waiting
++;
158 /* Data ready. By its nature, this viewer doesn't need to have
159 * its data ready hook called there, because a background
160 * request is always linked with a redraw.
165 lttv_hooks_destroy(background_ready_hook
);
170 * Event Viewer's constructor hook
172 * This constructor is given as a parameter to the menuitem and toolbar button
173 * registration. It creates the list.
174 * @param tab A pointer to the parent tab.
175 * @return The widget created.
178 h_resourceview(LttvPlugin
*plugin
)
180 LttvPluginTab
*ptab
= LTTV_PLUGIN_TAB(plugin
);
181 Tab
*tab
= ptab
->tab
;
182 g_info("h_guicontrolflow, %p", tab
);
183 ControlFlowData
*resourceview_data
= resourceview(ptab
);
185 resourceview_data
->tab
= tab
;
187 // Unreg done in the GuiControlFlow_Destructor
188 lttvwindow_register_traceset_notify(tab
,
192 lttvwindow_register_time_window_notify(tab
,
193 update_time_window_hook
,
195 lttvwindow_register_current_time_notify(tab
,
196 update_current_time_hook
,
198 lttvwindow_register_redraw_notify(tab
,
201 lttvwindow_register_continue_notify(tab
,
204 request_background_data(resourceview_data
);
207 return guicontrolflow_get_widget(resourceview_data
) ;
211 void legend_destructor(GtkWindow
*legend
)
213 g_legend_list
= g_slist_remove(g_legend_list
, legend
);
216 /* Create a popup legend */
218 h_legend(LttvPlugin
*plugin
)
220 LttvPluginTab
*ptab
= LTTV_PLUGIN_TAB(plugin
);
221 Tab
*tab
= ptab
->tab
;
222 g_info("h_legend, %p", tab
);
224 GtkWindow
*legend
= GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL
));
226 g_legend_list
= g_slist_append(
230 g_object_set_data_full(
234 (GDestroyNotify
)legend_destructor
);
236 gtk_window_set_title(legend
, "Control Flow View Legend");
238 GtkWidget
*pixmap
= create_pixmap(GTK_WIDGET(legend
), "lttv-color-list.png");
240 gtk_container_add(GTK_CONTAINER(legend
), GTK_WIDGET(pixmap
));
242 gtk_widget_show(GTK_WIDGET(pixmap
));
243 gtk_widget_show(GTK_WIDGET(legend
));
246 return NULL
; /* This is a popup window */
250 int event_selected_hook(void *hook_data
, void *call_data
)
252 guint
*event_number
= (guint
*) call_data
;
254 g_debug("DEBUG : event selected by main window : %u", *event_number
);
259 static void cpu_set_line_color(PropertiesLine
*prop_line
, LttvCPUState
*s
)
261 GQuark present_state
;
263 if(s
->mode_stack
->len
== 0)
264 present_state
= LTTV_CPU_UNKNOWN
;
266 present_state
= ((GQuark
*)s
->mode_stack
->data
)[s
->mode_stack
->len
-1];
268 if(present_state
== LTTV_CPU_IDLE
) {
269 prop_line
->color
= drawing_colors_cpu
[COL_CPU_IDLE
];
271 else if(present_state
== LTTV_CPU_BUSY
) {
272 prop_line
->color
= drawing_colors_cpu
[COL_CPU_BUSY
];
274 else if(present_state
== LTTV_CPU_IRQ
) {
275 prop_line
->color
= drawing_colors_cpu
[COL_CPU_IRQ
];
277 else if(present_state
== LTTV_CPU_SOFT_IRQ
) {
278 prop_line
->color
= drawing_colors_cpu
[COL_CPU_SOFT_IRQ
];
280 else if(present_state
== LTTV_CPU_TRAP
) {
281 prop_line
->color
= drawing_colors_cpu
[COL_CPU_TRAP
];
283 prop_line
->color
= drawing_colors_cpu
[COL_CPU_UNKNOWN
];
287 static void irq_set_line_color(PropertiesLine
*prop_line
, LttvIRQState
*s
)
289 GQuark present_state
;
290 if(s
->mode_stack
->len
== 0)
291 present_state
= LTTV_IRQ_UNKNOWN
;
293 present_state
= ((GQuark
*)s
->mode_stack
->data
)[s
->mode_stack
->len
-1];
295 if(present_state
== LTTV_IRQ_IDLE
) {
296 prop_line
->color
= drawing_colors_irq
[COL_IRQ_IDLE
];
298 else if(present_state
== LTTV_IRQ_BUSY
) {
299 prop_line
->color
= drawing_colors_irq
[COL_IRQ_BUSY
];
302 prop_line
->color
= drawing_colors_irq
[COL_IRQ_UNKNOWN
];
306 static void soft_irq_set_line_color(PropertiesLine
*prop_line
, LttvSoftIRQState
*s
)
309 prop_line
->color
= drawing_colors_soft_irq
[COL_SOFT_IRQ_BUSY
];
311 prop_line
->color
= drawing_colors_soft_irq
[COL_SOFT_IRQ_PENDING
];
313 prop_line
->color
= drawing_colors_soft_irq
[COL_SOFT_IRQ_IDLE
];
316 static void trap_set_line_color(PropertiesLine
*prop_line
, LttvTrapState
*s
)
319 prop_line
->color
= drawing_colors_trap
[COL_TRAP_IDLE
];
321 prop_line
->color
= drawing_colors_trap
[COL_TRAP_BUSY
];
324 static void bdev_set_line_color(PropertiesLine
*prop_line
, LttvBdevState
*s
)
326 GQuark present_state
;
327 if(s
== 0 || s
->mode_stack
->len
== 0)
328 present_state
= LTTV_BDEV_UNKNOWN
;
330 present_state
= ((GQuark
*)s
->mode_stack
->data
)[s
->mode_stack
->len
-1];
332 if(present_state
== LTTV_BDEV_IDLE
) {
333 prop_line
->color
= drawing_colors_bdev
[COL_BDEV_IDLE
];
335 else if(present_state
== LTTV_BDEV_BUSY_READING
) {
336 prop_line
->color
= drawing_colors_bdev
[COL_BDEV_BUSY_READING
];
338 else if(present_state
== LTTV_BDEV_BUSY_WRITING
) {
339 prop_line
->color
= drawing_colors_bdev
[COL_BDEV_BUSY_WRITING
];
342 prop_line
->color
= drawing_colors_bdev
[COL_BDEV_UNKNOWN
];
346 /* before_schedchange_hook
348 * This function basically draw lines and icons. Two types of lines are drawn :
349 * one small (3 pixels?) representing the state of the process and the second
350 * type is thicker (10 pixels?) representing on which CPU a process is running
351 * (and this only in running state).
353 * Extremums of the lines :
354 * x_min : time of the last event context for this process kept in memory.
355 * x_max : time of the current event.
356 * y : middle of the process in the process list. The process is found in the
357 * list, therefore is it's position in pixels.
359 * The choice of lines'color is defined by the context of the last event for this
364 int before_schedchange_hook(void *hook_data
, void *call_data
)
370 event
= (LttvEvent
*) call_data
;
371 if (strcmp(lttv_traceset_get_name_from_event(event
),"sched_switch") != 0)
374 ControlFlowData
*resourceview_data
= (ControlFlowData
*)hook_data
;
376 LttTime evtime
= lttv_event_get_timestamp(event
);
378 /* we are in a schedchange, before the state update. We must draw the
379 * items corresponding to the state before it changes : now is the right
385 pid_out
= lttv_event_get_long(event
, "prev_tid");
386 // TODO: can't we reenable this? pmf
387 // if(pid_in != 0 && pid_out != 0) {
388 // /* not a transition to/from idle */
393 guint cpu
= lttv_traceset_get_cpuid_from_event(event
);
396 guint trace_num
= lttv_traceset_get_trace_index_from_event(event
);
398 /* Add process to process list (if not present) */
399 HashedResourceData
*hashed_process_data
= NULL
;
401 hashed_process_data
= resourcelist_obtain_cpu(resourceview_data
, trace_num
, cpu
);
403 /* Now, the process is in the state hash and our own process hash.
404 * We definitely can draw the items related to the ending state.
407 if(ltt_time_compare(hashed_process_data
->next_good_time
,
410 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
412 TimeWindow time_window
=
413 lttvwindow_get_time_window(resourceview_data
->tab
);
415 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
416 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
419 Drawing_t
*drawing
= resourceview_data
->drawing
;
420 guint width
= drawing
->width
;
422 convert_time_to_pixels(
428 /* Draw collision indicator */
429 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
430 gdk_draw_point(hashed_process_data
->pixmap
,
433 COLLISION_POSITION(hashed_process_data
->height
));
434 hashed_process_data
->x
.middle_marked
= TRUE
;
437 TimeWindow time_window
=
438 lttvwindow_get_time_window(resourceview_data
->tab
);
440 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
441 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
444 Drawing_t
*drawing
= resourceview_data
->drawing
;
445 guint width
= drawing
->width
;
447 convert_time_to_pixels(
453 /* Jump over draw if we are at the same x position */
454 if(x
== hashed_process_data
->x
.middle
&&
455 hashed_process_data
->x
.middle_used
)
457 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
458 /* Draw collision indicator */
459 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
460 gdk_draw_point(hashed_process_data
->pixmap
,
463 COLLISION_POSITION(hashed_process_data
->height
));
464 hashed_process_data
->x
.middle_marked
= TRUE
;
468 DrawContext draw_context
;
470 /* Now create the drawing context that will be used to draw
471 * items related to the last state. */
472 draw_context
.drawable
= hashed_process_data
->pixmap
;
473 draw_context
.gc
= drawing
->gc
;
474 draw_context
.pango_layout
= drawing
->pango_layout
;
475 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
476 draw_context
.drawinfo
.end
.x
= x
;
478 draw_context
.drawinfo
.y
.over
= 1;
479 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
480 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
482 draw_context
.drawinfo
.start
.offset
.over
= 0;
483 draw_context
.drawinfo
.start
.offset
.middle
= 0;
484 draw_context
.drawinfo
.start
.offset
.under
= 0;
485 draw_context
.drawinfo
.end
.offset
.over
= 0;
486 draw_context
.drawinfo
.end
.offset
.middle
= 0;
487 draw_context
.drawinfo
.end
.offset
.under
= 0;
491 //PropertiesLine prop_line = prepare_s_e_line(process);
492 PropertiesLine prop_line
;
493 prop_line
.line_width
= STATE_LINE_WIDTH
;
494 prop_line
.style
= GDK_LINE_SOLID
;
495 prop_line
.y
= MIDDLE
;
496 cpu_set_line_color(&prop_line
, &(ts
->cpu_states
[cpu
]));
497 draw_line((void*)&prop_line
, (void*)&draw_context
);
500 /* become the last x position */
501 hashed_process_data
->x
.middle
= x
;
502 hashed_process_data
->x
.middle_used
= TRUE
;
503 hashed_process_data
->x
.middle_marked
= FALSE
;
505 /* Calculate the next good time */
506 convert_pixels_to_time(width
, x
+1, time_window
,
507 &hashed_process_data
->next_good_time
);
514 /* after_schedchange_hook
516 * The draw after hook is called by the reading API to have a
517 * particular event drawn on the screen.
518 * @param hook_data ControlFlowData structure of the viewer.
519 * @param call_data Event context.
521 * This function adds items to be drawn in a queue for each process.
524 int after_schedchange_hook(void *hook_data
, void *call_data
)
528 event
= (LttvEvent
*) call_data
;
530 if (strcmp(lttv_traceset_get_name_from_event(event
),"sched_switch") != 0)
533 ControlFlowData
*resourceview_data
= (ControlFlowData
*) hook_data
;
535 LttvTraceState
*ts
= event
->state
;
537 LttvFilter
*filter
= resourceview_data
->filter
;
538 if(filter
!= NULL
&& filter
->head
!= NULL
)
539 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
540 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
544 LttTime evtime
= lttv_event_get_timestamp(event
);
546 /* Add process to process list (if not present) */
547 LttvProcessState
*process_in
;
548 HashedResourceData
*hashed_process_data_in
= NULL
;
550 ProcessList
*process_list
= resourceview_data
->process_list
;
552 /* Find process pid_in in the list... */
553 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
554 //process_in = tfs->process;
555 guint cpu
= lttv_traceset_get_cpuid_from_event(event
);
556 guint trace_num
= lttv_traceset_get_trace_index_from_event(event
);
557 process_in
= ts
->running_process
[cpu
];
558 /* It should exist, because we are after the state update. */
560 g_assert(process_in
!= NULL
);
563 //hashed_process_data_in = processlist_get_process_data(process_list, cpuq, trace_num);
564 hashed_process_data_in
= resourcelist_obtain_cpu(resourceview_data
, trace_num
, cpu
);
566 /* Set the current process */
567 process_list
->current_hash_data
[trace_num
][process_in
->cpu
] =
568 hashed_process_data_in
;
570 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
573 TimeWindow time_window
=
574 lttvwindow_get_time_window(resourceview_data
->tab
);
577 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
578 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
581 Drawing_t
*drawing
= resourceview_data
->drawing
;
582 guint width
= drawing
->width
;
585 convert_time_to_pixels(
591 if(hashed_process_data_in
->x
.middle
!= new_x
) {
592 hashed_process_data_in
->x
.middle
= new_x
;
593 hashed_process_data_in
->x
.middle_used
= FALSE
;
594 hashed_process_data_in
->x
.middle_marked
= FALSE
;
600 int before_execmode_hook_irq(void *hook_data
, void *call_data
);
601 int before_execmode_hook_soft_irq(void *hook_data
, void *call_data
);
602 int before_execmode_hook_trap(void *hook_data
, void *call_data
);
604 /* before_execmode_hook
606 * This function basically draw lines and icons. Two types of lines are drawn :
607 * one small (3 pixels?) representing the state of the process and the second
608 * type is thicker (10 pixels?) representing on which CPU a process is running
609 * (and this only in running state).
611 * Extremums of the lines :
612 * x_min : time of the last event context for this process kept in memory.
613 * x_max : time of the current event.
614 * y : middle of the process in the process list. The process is found in the
615 * list, therefore is it's position in pixels.
617 * The choice of lines'color is defined by the context of the last event for this
621 int before_execmode_hook(void *hook_data
, void *call_data
)
626 LttvProcessState
*process
;
628 before_execmode_hook_irq(hook_data
, call_data
);
629 before_execmode_hook_soft_irq(hook_data
, call_data
);
631 before_execmode_hook_trap(hook_data
, call_data
);
633 /* we are in a execmode, before the state update. We must draw the
634 * items corresponding to the state before it changes : now is the right
637 event
= (LttvEvent
*) call_data
;
638 if ((strncmp(lttv_traceset_get_name_from_event(event
),"sys_", sizeof("sys_") - 1) == 0)
639 ||(strcmp(lttv_traceset_get_name_from_event(event
),"exit_syscall") == 0)
640 ||(strncmp(lttv_traceset_get_name_from_event(event
),"irq_handler_",sizeof("irq_handler_") -1) == 0)
641 ||(strncmp(lttv_traceset_get_name_from_event(event
),"softirq_", sizeof("softirq_") - 1) == 0)) {
643 LttTime evtime
= lttv_event_get_timestamp(event
);
644 ControlFlowData
*resourceview_data
= (ControlFlowData
*)hook_data
;
646 cpu
= lttv_traceset_get_cpuid_from_event(event
);
649 guint trace_num
= lttv_traceset_get_trace_index_from_event(event
);
651 process
= ts
->running_process
[cpu
];
652 g_assert(process
!= NULL
);
654 /* Well, the process_out existed : we must get it in the process hash
655 * or add it, and draw its items.
657 /* Add process to process list (if not present) */
658 HashedResourceData
*hashed_process_data
= NULL
;
659 ProcessList
*process_list
= resourceview_data
->process_list
;
661 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
662 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
664 hashed_process_data
= resourcelist_obtain_cpu(resourceview_data
, trace_num
, cpu
);
666 /* Set the current process */
667 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
671 /* Now, the process is in the state hash and our own process hash.
672 * We definitely can draw the items related to the ending state.
675 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
678 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
679 TimeWindow time_window
=
680 lttvwindow_get_time_window(resourceview_data
->tab
);
683 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
684 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
687 Drawing_t
*drawing
= resourceview_data
->drawing
;
688 guint width
= drawing
->width
;
690 convert_time_to_pixels(
696 /* Draw collision indicator */
697 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
698 gdk_draw_point(hashed_process_data
->pixmap
,
701 COLLISION_POSITION(hashed_process_data
->height
));
702 hashed_process_data
->x
.middle_marked
= TRUE
;
706 TimeWindow time_window
=
707 lttvwindow_get_time_window(resourceview_data
->tab
);
710 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
711 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
714 Drawing_t
*drawing
= resourceview_data
->drawing
;
715 guint width
= drawing
->width
;
718 convert_time_to_pixels(
725 /* Jump over draw if we are at the same x position */
726 if(unlikely(x
== hashed_process_data
->x
.middle
&&
727 hashed_process_data
->x
.middle_used
))
729 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
730 /* Draw collision indicator */
731 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
732 gdk_draw_point(hashed_process_data
->pixmap
,
735 COLLISION_POSITION(hashed_process_data
->height
));
736 hashed_process_data
->x
.middle_marked
= TRUE
;
742 DrawContext draw_context
;
743 /* Now create the drawing context that will be used to draw
744 * items related to the last state. */
745 draw_context
.drawable
= hashed_process_data
->pixmap
;
746 draw_context
.gc
= drawing
->gc
;
747 draw_context
.pango_layout
= drawing
->pango_layout
;
748 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
749 draw_context
.drawinfo
.end
.x
= x
;
751 draw_context
.drawinfo
.y
.over
= 1;
752 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
753 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
755 draw_context
.drawinfo
.start
.offset
.over
= 0;
756 draw_context
.drawinfo
.start
.offset
.middle
= 0;
757 draw_context
.drawinfo
.start
.offset
.under
= 0;
758 draw_context
.drawinfo
.end
.offset
.over
= 0;
759 draw_context
.drawinfo
.end
.offset
.middle
= 0;
760 draw_context
.drawinfo
.end
.offset
.under
= 0;
764 PropertiesLine prop_line
;
765 prop_line
.line_width
= STATE_LINE_WIDTH
;
766 prop_line
.style
= GDK_LINE_SOLID
;
767 prop_line
.y
= MIDDLE
;
768 cpu_set_line_color(&prop_line
, &ts
->cpu_states
[cpu
]);
769 draw_line((void*)&prop_line
, (void*)&draw_context
);
771 /* become the last x position */
772 hashed_process_data
->x
.middle
= x
;
773 hashed_process_data
->x
.middle_used
= TRUE
;
774 hashed_process_data
->x
.middle_marked
= FALSE
;
776 /* Calculate the next good time */
777 convert_pixels_to_time(width
, x
+1, time_window
,
778 &hashed_process_data
->next_good_time
);
785 int before_execmode_hook_irq(void *hook_data
, void *call_data
)
789 event
= (LttvEvent
*) call_data
;
791 LttTime evtime
= lttv_event_get_timestamp(event
);
792 ControlFlowData
*resourceview_data
= (ControlFlowData
*)hook_data
;
794 /* we are in a execmode, before the state update. We must draw the
795 * items corresponding to the state before it changes : now is the right
801 guint cpu
= lttv_traceset_get_cpuid_from_event(event
);
802 LttvTraceState
*ts
= event
->state
;;
805 * Check for LTT_CHANNEL_KERNEL channel name and event ID
806 * corresponding to LTT_EVENT_IRQ_ENTRY or LTT_EVENT_IRQ_EXIT.
808 if (strncmp(lttv_traceset_get_name_from_event(event
),"irq_handler_entry",sizeof("irq_handler_entry")) == 0) {
809 irq
= lttv_event_get_long(event
, "irq");
810 } else if (strncmp(lttv_traceset_get_name_from_event(event
),"irq_handler_exit",sizeof("irq_handler_exit")) == 0) {
811 gint len
= ts
->cpu_states
[cpu
].irq_stack
->len
;
813 irq
= g_array_index(ts
->cpu_states
[cpu
].irq_stack
, gint
, len
-1);
821 guint trace_num
= lttv_traceset_get_trace_index_from_event(event
);
823 /* Well, the process_out existed : we must get it in the process hash
824 * or add it, and draw its items.
826 /* Add process to process list (if not present) */
827 HashedResourceData
*hashed_process_data
= NULL
;
829 hashed_process_data
= resourcelist_obtain_irq(resourceview_data
, trace_num
, irq
);
830 // TODO: fix this, it's ugly and slow:
834 str
= g_strdup_printf("IRQ %" PRIu64
" [%s]", irq
,
835 (char*)g_quark_to_string(ts
->name_tables
->irq_names
[irq
]));
836 name
= g_quark_from_string(str
);
839 gtk_tree_store_set(resourceview_data
->process_list
->list_store
, &hashed_process_data
->y_iter
, NAME_COLUMN
, g_quark_to_string(name
), -1);
841 /* Now, the process is in the state hash and our own process hash.
842 * We definitely can draw the items related to the ending state.
845 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
848 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
849 TimeWindow time_window
=
850 lttvwindow_get_time_window(resourceview_data
->tab
);
853 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
854 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
857 Drawing_t
*drawing
= resourceview_data
->drawing
;
858 guint width
= drawing
->width
;
860 convert_time_to_pixels(
866 /* Draw collision indicator */
867 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
868 gdk_draw_point(hashed_process_data
->pixmap
,
871 COLLISION_POSITION(hashed_process_data
->height
));
872 hashed_process_data
->x
.middle_marked
= TRUE
;
876 TimeWindow time_window
=
877 lttvwindow_get_time_window(resourceview_data
->tab
);
880 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
881 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
884 Drawing_t
*drawing
= resourceview_data
->drawing
;
885 guint width
= drawing
->width
;
888 convert_time_to_pixels(
895 /* Jump over draw if we are at the same x position */
896 if(unlikely(x
== hashed_process_data
->x
.middle
&&
897 hashed_process_data
->x
.middle_used
))
899 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
900 /* Draw collision indicator */
901 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
902 gdk_draw_point(hashed_process_data
->pixmap
,
905 COLLISION_POSITION(hashed_process_data
->height
));
906 hashed_process_data
->x
.middle_marked
= TRUE
;
912 DrawContext draw_context
;
913 /* Now create the drawing context that will be used to draw
914 * items related to the last state. */
915 draw_context
.drawable
= hashed_process_data
->pixmap
;
916 draw_context
.gc
= drawing
->gc
;
917 draw_context
.pango_layout
= drawing
->pango_layout
;
918 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
919 draw_context
.drawinfo
.end
.x
= x
;
921 draw_context
.drawinfo
.y
.over
= 1;
922 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
923 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
925 draw_context
.drawinfo
.start
.offset
.over
= 0;
926 draw_context
.drawinfo
.start
.offset
.middle
= 0;
927 draw_context
.drawinfo
.start
.offset
.under
= 0;
928 draw_context
.drawinfo
.end
.offset
.over
= 0;
929 draw_context
.drawinfo
.end
.offset
.middle
= 0;
930 draw_context
.drawinfo
.end
.offset
.under
= 0;
934 PropertiesLine prop_line
;
935 prop_line
.line_width
= STATE_LINE_WIDTH
;
936 prop_line
.style
= GDK_LINE_SOLID
;
937 prop_line
.y
= MIDDLE
;
938 irq_set_line_color(&prop_line
, &ts
->irq_states
[irq
]);
939 draw_line((void*)&prop_line
, (void*)&draw_context
);
941 /* become the last x position */
942 hashed_process_data
->x
.middle
= x
;
943 hashed_process_data
->x
.middle_used
= TRUE
;
944 hashed_process_data
->x
.middle_marked
= FALSE
;
946 /* Calculate the next good time */
947 convert_pixels_to_time(width
, x
+1, time_window
,
948 &hashed_process_data
->next_good_time
);
955 int before_execmode_hook_soft_irq(void *hook_data
, void *call_data
)
961 event
= (LttvEvent
*) call_data
;
966 /* we are in a execmode, before the state update. We must draw the
967 * items corresponding to the state before it changes : now is the right
976 * Check for LTT_CHANNEL_KERNEL channel name and event ID
977 * corresponding to LTT_EVENT_SOFT_IRQ_RAISE, LTT_EVENT_SOFT_IRQ_ENTRY
978 * or LTT_EVENT_SOFT_IRQ_EXIT.
981 if (strncmp(lttv_traceset_get_name_from_event(event
),"softirq_entry",sizeof("softirq_entry")) == 0
982 || strncmp(lttv_traceset_get_name_from_event(event
),"softirq_raise",sizeof("softirq_raise")) == 0
983 || strncmp(lttv_traceset_get_name_from_event(event
),"softirq_exit",sizeof("softirq_exit")) == 0 ) {
985 softirq
= lttv_event_get_long_unsigned(event
, "vec");
991 LttTime evtime
= lttv_event_get_timestamp(event
);
992 ControlFlowData
*resourceview_data
= (ControlFlowData
*)hook_data
;
994 guint trace_num
= lttv_traceset_get_trace_index_from_event(event
);
996 /* Well, the process_out existed : we must get it in the process hash
997 * or add it, and draw its items.
999 /* Add process to process list (if not present) */
1000 HashedResourceData
*hashed_process_data
= NULL
;
1002 hashed_process_data
= resourcelist_obtain_soft_irq(resourceview_data
, trace_num
, softirq
);
1004 /* Now, the process is in the state hash and our own process hash.
1005 * We definitely can draw the items related to the ending state.
1008 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1011 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1012 TimeWindow time_window
=
1013 lttvwindow_get_time_window(resourceview_data
->tab
);
1016 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1017 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1019 #endif //EXTRA_CHECK
1020 Drawing_t
*drawing
= resourceview_data
->drawing
;
1021 guint width
= drawing
->width
;
1023 convert_time_to_pixels(
1029 /* Draw collision indicator */
1030 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1031 gdk_draw_point(hashed_process_data
->pixmap
,
1034 COLLISION_POSITION(hashed_process_data
->height
));
1035 hashed_process_data
->x
.middle_marked
= TRUE
;
1039 TimeWindow time_window
=
1040 lttvwindow_get_time_window(resourceview_data
->tab
);
1043 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1044 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1046 #endif //EXTRA_CHECK
1047 Drawing_t
*drawing
= resourceview_data
->drawing
;
1048 guint width
= drawing
->width
;
1051 convert_time_to_pixels(
1058 /* Jump over draw if we are at the same x position */
1059 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1060 hashed_process_data
->x
.middle_used
))
1062 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1063 /* Draw collision indicator */
1064 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1065 gdk_draw_point(hashed_process_data
->pixmap
,
1068 COLLISION_POSITION(hashed_process_data
->height
));
1069 hashed_process_data
->x
.middle_marked
= TRUE
;
1075 DrawContext draw_context
;
1076 /* Now create the drawing context that will be used to draw
1077 * items related to the last state. */
1078 draw_context
.drawable
= hashed_process_data
->pixmap
;
1079 draw_context
.gc
= drawing
->gc
;
1080 draw_context
.pango_layout
= drawing
->pango_layout
;
1081 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1082 draw_context
.drawinfo
.end
.x
= x
;
1084 draw_context
.drawinfo
.y
.over
= 1;
1085 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1086 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1088 draw_context
.drawinfo
.start
.offset
.over
= 0;
1089 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1090 draw_context
.drawinfo
.start
.offset
.under
= 0;
1091 draw_context
.drawinfo
.end
.offset
.over
= 0;
1092 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1093 draw_context
.drawinfo
.end
.offset
.under
= 0;
1097 PropertiesLine prop_line
;
1098 prop_line
.line_width
= STATE_LINE_WIDTH
;
1099 prop_line
.style
= GDK_LINE_SOLID
;
1100 prop_line
.y
= MIDDLE
;
1101 soft_irq_set_line_color(&prop_line
, &ts
->soft_irq_states
[softirq
]);
1102 draw_line((void*)&prop_line
, (void*)&draw_context
);
1104 /* become the last x position */
1105 hashed_process_data
->x
.middle
= x
;
1106 hashed_process_data
->x
.middle_used
= TRUE
;
1107 hashed_process_data
->x
.middle_marked
= FALSE
;
1109 /* Calculate the next good time */
1110 convert_pixels_to_time(width
, x
+1, time_window
,
1111 &hashed_process_data
->next_good_time
);
1117 #ifdef TRAP_NO_EXIST
1118 int before_execmode_hook_trap(void *hook_data
, void *call_data
)
1120 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1121 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1122 ControlFlowData
*resourceview_data
= events_request
->viewer_data
;
1124 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1126 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1127 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1128 struct marker_info
*minfo
;
1131 e
= ltt_tracefile_get_event(tfc
->tf
);
1133 LttTime evtime
= ltt_event_time(e
);
1135 /* we are in a execmode, before the state update. We must draw the
1136 * items corresponding to the state before it changes : now is the right
1142 guint cpu
= tfs
->cpu
;
1145 * Check for LTT_CHANNEL_KERNEL channel name and event ID
1146 * corresponding to LTT_EVENT_TRAP/PAGE_FAULT_ENTRY or
1147 * LTT_EVENT_TRAP/PAGE_FAULT_EXIT.
1149 if (tfc
->tf
->name
!= LTT_CHANNEL_KERNEL
)
1151 minfo
= marker_get_info_from_id(tfc
->tf
->mdata
, e
->event_id
);
1152 g_assert(minfo
!= NULL
);
1153 if (minfo
->name
== LTT_EVENT_TRAP_ENTRY
1154 || minfo
->name
== LTT_EVENT_PAGE_FAULT_ENTRY
1155 || minfo
->name
== LTT_EVENT_PAGE_FAULT_NOSEM_ENTRY
) {
1156 trap
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
1157 } else if (minfo
->name
== LTT_EVENT_TRAP_EXIT
1158 || minfo
->name
== LTT_EVENT_PAGE_FAULT_EXIT
1159 || minfo
->name
== LTT_EVENT_PAGE_FAULT_NOSEM_EXIT
) {
1160 gint len
= ts
->cpu_states
[cpu
].trap_stack
->len
;
1162 trap
= g_array_index(ts
->cpu_states
[cpu
].trap_stack
, gint
, len
-1);
1170 guint trace_num
= ts
->parent
.index
;
1172 /* Well, the process_out existed : we must get it in the process hash
1173 * or add it, and draw its items.
1175 /* Add process to process list (if not present) */
1176 HashedResourceData
*hashed_process_data
= NULL
;
1178 hashed_process_data
= resourcelist_obtain_trap(resourceview_data
, trace_num
, trap
);
1180 /* Now, the process is in the state hash and our own process hash.
1181 * We definitely can draw the items related to the ending state.
1184 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1187 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1188 TimeWindow time_window
=
1189 lttvwindow_get_time_window(resourceview_data
->tab
);
1192 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1193 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1195 #endif //EXTRA_CHECK
1196 Drawing_t
*drawing
= resourceview_data
->drawing
;
1197 guint width
= drawing
->width
;
1199 convert_time_to_pixels(
1205 /* Draw collision indicator */
1206 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1207 gdk_draw_point(hashed_process_data
->pixmap
,
1210 COLLISION_POSITION(hashed_process_data
->height
));
1211 hashed_process_data
->x
.middle_marked
= TRUE
;
1215 TimeWindow time_window
=
1216 lttvwindow_get_time_window(resourceview_data
->tab
);
1219 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1220 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1222 #endif //EXTRA_CHECK
1223 Drawing_t
*drawing
= resourceview_data
->drawing
;
1224 guint width
= drawing
->width
;
1227 convert_time_to_pixels(
1234 /* Jump over draw if we are at the same x position */
1235 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1236 hashed_process_data
->x
.middle_used
))
1238 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1239 /* Draw collision indicator */
1240 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1241 gdk_draw_point(hashed_process_data
->pixmap
,
1244 COLLISION_POSITION(hashed_process_data
->height
));
1245 hashed_process_data
->x
.middle_marked
= TRUE
;
1251 DrawContext draw_context
;
1252 /* Now create the drawing context that will be used to draw
1253 * items related to the last state. */
1254 draw_context
.drawable
= hashed_process_data
->pixmap
;
1255 draw_context
.gc
= drawing
->gc
;
1256 draw_context
.pango_layout
= drawing
->pango_layout
;
1257 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1258 draw_context
.drawinfo
.end
.x
= x
;
1260 draw_context
.drawinfo
.y
.over
= 1;
1261 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1262 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1264 draw_context
.drawinfo
.start
.offset
.over
= 0;
1265 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1266 draw_context
.drawinfo
.start
.offset
.under
= 0;
1267 draw_context
.drawinfo
.end
.offset
.over
= 0;
1268 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1269 draw_context
.drawinfo
.end
.offset
.under
= 0;
1273 PropertiesLine prop_line
;
1274 prop_line
.line_width
= STATE_LINE_WIDTH
;
1275 prop_line
.style
= GDK_LINE_SOLID
;
1276 prop_line
.y
= MIDDLE
;
1277 trap_set_line_color(&prop_line
, &ts
->trap_states
[trap
]);
1278 draw_line((void*)&prop_line
, (void*)&draw_context
);
1280 /* become the last x position */
1281 hashed_process_data
->x
.middle
= x
;
1282 hashed_process_data
->x
.middle_used
= TRUE
;
1283 hashed_process_data
->x
.middle_marked
= FALSE
;
1285 /* Calculate the next good time */
1286 convert_pixels_to_time(width
, x
+1, time_window
,
1287 &hashed_process_data
->next_good_time
);
1294 #ifdef BABEL_CLEANUP
1295 //TODO investigate the use of block dev resource
1296 int before_bdev_event_hook(void *hook_data
, void *call_data
)
1301 LttvProcessState
*process
;
1304 /* we are in a execmode, before the state update. We must draw the
1305 * items corresponding to the state before it changes : now is the right
1309 event
= (LttvEvent
*) call_data
;
1310 if (strcmp(lttv_traceset_get_name_from_event(event
),"block_rq_issue") != 0 && strcmp(lttv_traceset_get_name_from_event(event
),"block_rq_complete") != 0)
1314 ControlFlowData
*resourceview_data
= (ControlFlowData
*) hook_data
;
1316 LttvTraceState
*ts
= event
->state
;
1319 guint8 major
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
1320 guint8 minor
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
1321 gint devcode_gint
= MKDEV(major
,minor
);
1323 guint trace_num
= lttv_traceset_get_trace_index_from_event(event
);
1325 LttvBdevState
*bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1326 /* the result of the lookup might be NULL. that's ok, the rest of the function
1327 should understand it was not found and that its state is unknown */
1329 /* Well, the process_out existed : we must get it in the process hash
1330 * or add it, and draw its items.
1332 /* Add process to process list (if not present) */
1333 HashedResourceData
*hashed_process_data
= NULL
;
1334 // LttTime birth = process->creation_time;
1336 // if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1337 // hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1339 hashed_process_data
= resourcelist_obtain_bdev(resourceview_data
, trace_num
, devcode_gint
);
1340 ////hashed_process_data = processlist_get_process_data(process_list, resourceq, trace_num);
1341 // hashed_process_data = processlist_get_process_data(process_list,
1347 /* Set the current process */
1348 // process_list->current_hash_data[trace_num][process->cpu] =
1349 // hashed_process_data;
1352 /* Now, the process is in the state hash and our own process hash.
1353 * We definitely can draw the items related to the ending state.
1356 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1359 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1360 TimeWindow time_window
=
1361 lttvwindow_get_time_window(resourceview_data
->tab
);
1364 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1365 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1367 #endif //EXTRA_CHECK
1368 Drawing_t
*drawing
= resourceview_data
->drawing
;
1369 guint width
= drawing
->width
;
1371 convert_time_to_pixels(
1377 /* Draw collision indicator */
1378 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1379 gdk_draw_point(hashed_process_data
->pixmap
,
1382 COLLISION_POSITION(hashed_process_data
->height
));
1383 hashed_process_data
->x
.middle_marked
= TRUE
;
1387 TimeWindow time_window
=
1388 lttvwindow_get_time_window(resourceview_data
->tab
);
1391 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1392 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1394 #endif //EXTRA_CHECK
1395 Drawing_t
*drawing
= resourceview_data
->drawing
;
1396 guint width
= drawing
->width
;
1399 convert_time_to_pixels(
1406 /* Jump over draw if we are at the same x position */
1407 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1408 hashed_process_data
->x
.middle_used
))
1410 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1411 /* Draw collision indicator */
1412 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1413 gdk_draw_point(hashed_process_data
->pixmap
,
1416 COLLISION_POSITION(hashed_process_data
->height
));
1417 hashed_process_data
->x
.middle_marked
= TRUE
;
1423 DrawContext draw_context
;
1424 /* Now create the drawing context that will be used to draw
1425 * items related to the last state. */
1426 draw_context
.drawable
= hashed_process_data
->pixmap
;
1427 draw_context
.gc
= drawing
->gc
;
1428 draw_context
.pango_layout
= drawing
->pango_layout
;
1429 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1430 draw_context
.drawinfo
.end
.x
= x
;
1432 draw_context
.drawinfo
.y
.over
= 1;
1433 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1434 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1436 draw_context
.drawinfo
.start
.offset
.over
= 0;
1437 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1438 draw_context
.drawinfo
.start
.offset
.under
= 0;
1439 draw_context
.drawinfo
.end
.offset
.over
= 0;
1440 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1441 draw_context
.drawinfo
.end
.offset
.under
= 0;
1445 PropertiesLine prop_line
;
1446 prop_line
.line_width
= STATE_LINE_WIDTH
;
1447 prop_line
.style
= GDK_LINE_SOLID
;
1448 prop_line
.y
= MIDDLE
;
1449 bdev_set_line_color(&prop_line
, bdev
);
1450 draw_line((void*)&prop_line
, (void*)&draw_context
);
1452 /* become the last x position */
1453 hashed_process_data
->x
.middle
= x
;
1454 hashed_process_data
->x
.middle_used
= TRUE
;
1455 hashed_process_data
->x
.middle_marked
= FALSE
;
1457 /* Calculate the next good time */
1458 convert_pixels_to_time(width
, x
+1, time_window
,
1459 &hashed_process_data
->next_good_time
);
1466 gint
update_time_window_hook(void *hook_data
, void *call_data
)
1468 ControlFlowData
*resourceview_data
= (ControlFlowData
*) hook_data
;
1469 Drawing_t
*drawing
= resourceview_data
->drawing
;
1470 ProcessList
*process_list
= resourceview_data
->process_list
;
1472 const TimeWindowNotifyData
*time_window_nofify_data
=
1473 ((const TimeWindowNotifyData
*)call_data
);
1475 TimeWindow
*old_time_window
=
1476 time_window_nofify_data
->old_time_window
;
1477 TimeWindow
*new_time_window
=
1478 time_window_nofify_data
->new_time_window
;
1480 /* Update the ruler */
1481 drawing_update_ruler(resourceview_data
->drawing
,
1485 /* Two cases : zoom in/out or scrolling */
1487 /* In order to make sure we can reuse the old drawing, the scale must
1488 * be the same and the new time interval being partly located in the
1489 * currently shown time interval. (reuse is only for scrolling)
1492 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
1493 old_time_window
->start_time
.tv_sec
,
1494 old_time_window
->start_time
.tv_nsec
,
1495 old_time_window
->time_width
.tv_sec
,
1496 old_time_window
->time_width
.tv_nsec
);
1498 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
1499 new_time_window
->start_time
.tv_sec
,
1500 new_time_window
->start_time
.tv_nsec
,
1501 new_time_window
->time_width
.tv_sec
,
1502 new_time_window
->time_width
.tv_nsec
);
1504 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
1505 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
1507 /* Same scale (scrolling) */
1508 g_info("scrolling");
1509 LttTime
*ns
= &new_time_window
->start_time
;
1510 LttTime
*os
= &old_time_window
->start_time
;
1511 LttTime old_end
= old_time_window
->end_time
;
1512 LttTime new_end
= new_time_window
->end_time
;
1514 //if(ns<os+w && os+w<ns+w)
1515 //if(ns<old_end && os<ns)
1516 if(ltt_time_compare(*ns
, old_end
) == -1
1517 && ltt_time_compare(*os
, *ns
) == -1)
1519 g_info("scrolling near right");
1520 /* Scroll right, keep right part of the screen */
1522 guint width
= resourceview_data
->drawing
->width
;
1523 convert_time_to_pixels(
1529 /* Copy old data to new location */
1530 copy_pixmap_region(process_list
,
1532 resourceview_data
->drawing
->drawing_area
->style
->black_gc
,
1536 resourceview_data
->drawing
->width
-x
+SAFETY
, -1);
1538 if(drawing
->damage_begin
== drawing
->damage_end
)
1539 drawing
->damage_begin
= resourceview_data
->drawing
->width
-x
;
1541 drawing
->damage_begin
= 0;
1543 drawing
->damage_end
= resourceview_data
->drawing
->width
;
1545 /* Clear the data request background, but not SAFETY */
1546 rectangle_pixmap(process_list
,
1547 resourceview_data
->drawing
->drawing_area
->style
->black_gc
,
1549 drawing
->damage_begin
+SAFETY
, 0,
1550 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
1552 gtk_widget_queue_draw(drawing
->drawing_area
);
1554 /* Get new data for the rest. */
1555 drawing_data_request(resourceview_data
->drawing
,
1556 drawing
->damage_begin
, 0,
1557 drawing
->damage_end
- drawing
->damage_begin
,
1558 resourceview_data
->drawing
->height
);
1560 if(ltt_time_compare(*ns
,*os
) == -1
1561 && ltt_time_compare(*os
,new_end
) == -1)
1563 g_info("scrolling near left");
1564 /* Scroll left, keep left part of the screen */
1566 guint width
= resourceview_data
->drawing
->width
;
1567 convert_time_to_pixels(
1573 /* Copy old data to new location */
1574 copy_pixmap_region (process_list
,
1576 resourceview_data
->drawing
->drawing_area
->style
->black_gc
,
1582 if(drawing
->damage_begin
== drawing
->damage_end
)
1583 drawing
->damage_end
= x
;
1585 drawing
->damage_end
=
1586 resourceview_data
->drawing
->width
;
1588 drawing
->damage_begin
= 0;
1590 rectangle_pixmap (process_list
,
1591 resourceview_data
->drawing
->drawing_area
->style
->black_gc
,
1593 drawing
->damage_begin
, 0,
1594 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
1597 gtk_widget_queue_draw(drawing
->drawing_area
);
1599 /* Get new data for the rest. */
1600 drawing_data_request(resourceview_data
->drawing
,
1601 drawing
->damage_begin
, 0,
1602 drawing
->damage_end
- drawing
->damage_begin
,
1603 resourceview_data
->drawing
->height
);
1606 if(ltt_time_compare(*ns
,*os
) == 0)
1608 g_info("not scrolling");
1610 g_info("scrolling far");
1611 /* Cannot reuse any part of the screen : far jump */
1614 rectangle_pixmap (process_list
,
1615 resourceview_data
->drawing
->drawing_area
->style
->black_gc
,
1618 resourceview_data
->drawing
->width
+SAFETY
, // do not overlap
1621 gtk_widget_queue_draw(drawing
->drawing_area
);
1623 drawing
->damage_begin
= 0;
1624 drawing
->damage_end
= resourceview_data
->drawing
->width
;
1626 drawing_data_request(resourceview_data
->drawing
,
1628 resourceview_data
->drawing
->width
,
1629 resourceview_data
->drawing
->height
);
1635 /* Different scale (zoom) */
1638 rectangle_pixmap (process_list
,
1639 resourceview_data
->drawing
->drawing_area
->style
->black_gc
,
1642 resourceview_data
->drawing
->width
+SAFETY
, // do not overlap
1645 gtk_widget_queue_draw(drawing
->drawing_area
);
1647 drawing
->damage_begin
= 0;
1648 drawing
->damage_end
= resourceview_data
->drawing
->width
;
1650 drawing_data_request(resourceview_data
->drawing
,
1652 resourceview_data
->drawing
->width
,
1653 resourceview_data
->drawing
->height
);
1656 /* Update directly when scrolling */
1657 gdk_window_process_updates(resourceview_data
->drawing
->drawing_area
->window
,
1663 gint
traceset_notify(void *hook_data
, void *call_data
)
1665 ControlFlowData
*resourceview_data
= (ControlFlowData
*) hook_data
;
1666 Drawing_t
*drawing
= resourceview_data
->drawing
;
1668 if(unlikely(drawing
->gc
== NULL
)) {
1671 if(drawing
->dotted_gc
== NULL
) {
1675 drawing_clear(resourceview_data
->drawing
);
1676 processlist_clear(resourceview_data
->process_list
);
1677 gtk_widget_set_size_request(
1678 resourceview_data
->drawing
->drawing_area
,
1679 -1, processlist_get_height(resourceview_data
->process_list
));
1680 redraw_notify(resourceview_data
, NULL
);
1682 request_background_data(resourceview_data
);
1687 gint
redraw_notify(void *hook_data
, void *call_data
)
1689 ControlFlowData
*resourceview_data
= (ControlFlowData
*) hook_data
;
1690 Drawing_t
*drawing
= resourceview_data
->drawing
;
1691 GtkWidget
*widget
= drawing
->drawing_area
;
1693 drawing
->damage_begin
= 0;
1694 drawing
->damage_end
= drawing
->width
;
1696 /* fun feature, to be separated someday... */
1697 drawing_clear(resourceview_data
->drawing
);
1698 processlist_clear(resourceview_data
->process_list
);
1699 gtk_widget_set_size_request(
1700 resourceview_data
->drawing
->drawing_area
,
1701 -1, processlist_get_height(resourceview_data
->process_list
));
1703 rectangle_pixmap (resourceview_data
->process_list
,
1704 widget
->style
->black_gc
,
1707 drawing
->alloc_width
,
1710 gtk_widget_queue_draw(drawing
->drawing_area
);
1712 if(drawing
->damage_begin
< drawing
->damage_end
)
1714 drawing_data_request(drawing
,
1715 drawing
->damage_begin
,
1717 drawing
->damage_end
-drawing
->damage_begin
,
1726 gint
continue_notify(void *hook_data
, void *call_data
)
1728 ControlFlowData
*resourceview_data
= (ControlFlowData
*) hook_data
;
1729 Drawing_t
*drawing
= resourceview_data
->drawing
;
1731 if(drawing
->damage_begin
< drawing
->damage_end
)
1733 drawing_data_request(drawing
,
1734 drawing
->damage_begin
,
1736 drawing
->damage_end
-drawing
->damage_begin
,
1744 gint
update_current_time_hook(void *hook_data
, void *call_data
)
1746 ControlFlowData
*resourceview_data
= (ControlFlowData
*)hook_data
;
1748 LttTime current_time
= *((LttTime
*)call_data
);
1750 TimeWindow time_window
=
1751 lttvwindow_get_time_window(resourceview_data
->tab
);
1753 LttTime time_begin
= time_window
.start_time
;
1754 LttTime width
= time_window
.time_width
;
1757 guint64 time_ll
= ltt_time_to_uint64(width
);
1758 time_ll
= time_ll
>> 1; /* divide by two */
1759 half_width
= ltt_time_from_uint64(time_ll
);
1761 LttTime time_end
= ltt_time_add(time_begin
, width
);
1763 LttvTraceset
* ts
= lttvwindow_get_traceset(resourceview_data
->tab
);
1765 TimeInterval time_span
= lttv_traceset_get_time_span_real(ts
);
1766 LttTime trace_start
= time_span
.start_time
;
1767 LttTime trace_end
= time_span
.end_time
;
1769 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
1770 current_time
.tv_nsec
);
1772 /* If current time is inside time interval, just move the highlight
1775 /* Else, we have to change the time interval. We have to tell it
1776 * to the main window. */
1777 /* The time interval change will take care of placing the current
1778 * time at the center of the visible area, or nearest possible if we are
1779 * at one end of the trace. */
1782 if(ltt_time_compare(current_time
, time_begin
) < 0)
1784 TimeWindow new_time_window
;
1786 if(ltt_time_compare(current_time
,
1787 ltt_time_add(trace_start
,half_width
)) < 0)
1788 time_begin
= trace_start
;
1790 time_begin
= ltt_time_sub(current_time
,half_width
);
1792 new_time_window
.start_time
= time_begin
;
1793 new_time_window
.time_width
= width
;
1794 new_time_window
.time_width_double
= ltt_time_to_double(width
);
1795 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
1797 lttvwindow_report_time_window(resourceview_data
->tab
, new_time_window
);
1799 else if(ltt_time_compare(current_time
, time_end
) > 0)
1801 TimeWindow new_time_window
;
1803 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
1804 time_begin
= ltt_time_sub(trace_end
,width
);
1806 time_begin
= ltt_time_sub(current_time
,half_width
);
1808 new_time_window
.start_time
= time_begin
;
1809 new_time_window
.time_width
= width
;
1810 new_time_window
.time_width_double
= ltt_time_to_double(width
);
1811 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
1813 lttvwindow_report_time_window(resourceview_data
->tab
, new_time_window
);
1816 gtk_widget_queue_draw(resourceview_data
->drawing
->drawing_area
);
1818 /* Update directly when scrolling */
1819 gdk_window_process_updates(resourceview_data
->drawing
->drawing_area
->window
,
1825 typedef struct _ClosureData
{
1826 EventsRequest
*events_request
;
1831 /* Draw line until end of the screen */
1833 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
1835 ResourceUniqueNumeric
*process_info
= (ResourceUniqueNumeric
*)key
;
1836 HashedResourceData
*hashed_process_data
= (HashedResourceData
*)value
;
1837 ClosureData
*closure_data
= (ClosureData
*)user_data
;
1839 EventsRequest
*events_request
= closure_data
->events_request
;
1840 ControlFlowData
*resourceview_data
= events_request
->viewer_data
;
1841 LttvTraceset
*ts
= lttvwindow_get_traceset(resourceview_data
->tab
);
1843 LttTime evtime
= closure_data
->end_time
;
1845 gboolean dodraw
= TRUE
;
1847 if(hashed_process_data
->type
== RV_RESOURCE_MACHINE
)
1851 /* For the process */
1852 /* First, check if the current process is in the state computation
1853 * process list. If it is there, that means we must add it right now and
1854 * draw items from the beginning of the read for it. If it is not
1855 * present, it's a new process and it was not present : it will
1856 * be added after the state update. */
1858 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
1859 #endif //EXTRA_CHECK
1861 LttvTrace
*trace
= lttv_traceset_get(ts
,process_info
->trace_num
);
1862 LttvTraceState
*ts
= trace
->state
;
1864 /* Only draw for processes that are currently in the trace states */
1867 /* Should be alike when background info is ready */
1868 if(resourceview_data
->background_info_waiting
==0)
1869 g_assert(ltt_time_compare(process
->creation_time
,
1870 process_info
->birth
) == 0);
1871 #endif //EXTRA_CHECK
1873 /* Now, the process is in the state hash and our own process hash.
1874 * We definitely can draw the items related to the ending state.
1877 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
1880 TimeWindow time_window
=
1881 lttvwindow_get_time_window(resourceview_data
->tab
);
1884 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1885 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1887 #endif //EXTRA_CHECK
1888 Drawing_t
*drawing
= resourceview_data
->drawing
;
1889 guint width
= drawing
->width
;
1891 guint x
= closure_data
->x_end
;
1893 DrawContext draw_context
;
1895 /* Now create the drawing context that will be used to draw
1896 * items related to the last state. */
1897 draw_context
.drawable
= hashed_process_data
->pixmap
;
1898 draw_context
.gc
= drawing
->gc
;
1899 draw_context
.pango_layout
= drawing
->pango_layout
;
1900 draw_context
.drawinfo
.end
.x
= x
;
1902 draw_context
.drawinfo
.y
.over
= 1;
1903 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1904 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1906 draw_context
.drawinfo
.start
.offset
.over
= 0;
1907 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1908 draw_context
.drawinfo
.start
.offset
.under
= 0;
1909 draw_context
.drawinfo
.end
.offset
.over
= 0;
1910 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1911 draw_context
.drawinfo
.end
.offset
.under
= 0;
1913 /* Jump over draw if we are at the same x position */
1914 if(x
== hashed_process_data
->x
.over
)
1918 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
1920 PropertiesLine prop_line
= prepare_execmode_line(process
);
1921 draw_line((void*)&prop_line
, (void*)&draw_context
);
1923 hashed_process_data
->x
.over
= x
;
1927 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1928 hashed_process_data
->x
.middle_used
)) {
1929 #if 0 /* do not mark closure : not missing information */
1930 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
1931 /* Draw collision indicator */
1932 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1933 gdk_draw_point(drawing
->pixmap
,
1937 hashed_process_data
->x
.middle_marked
= TRUE
;
1942 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1945 PropertiesLine prop_line
;
1946 prop_line
.line_width
= STATE_LINE_WIDTH
;
1947 prop_line
.style
= GDK_LINE_SOLID
;
1948 prop_line
.y
= MIDDLE
;
1949 if(hashed_process_data
->type
== RV_RESOURCE_CPU
)
1950 cpu_set_line_color(&prop_line
, &ts
->cpu_states
[process_info
->id
]);
1951 else if(hashed_process_data
->type
== RV_RESOURCE_IRQ
)
1952 irq_set_line_color(&prop_line
, &ts
->irq_states
[process_info
->id
]);
1953 else if(hashed_process_data
->type
== RV_RESOURCE_SOFT_IRQ
)
1954 soft_irq_set_line_color(&prop_line
, &ts
->soft_irq_states
[process_info
->id
]);
1955 else if(hashed_process_data
->type
== RV_RESOURCE_TRAP
)
1956 trap_set_line_color(&prop_line
, &ts
->trap_states
[process_info
->id
]);
1957 else if(hashed_process_data
->type
== RV_RESOURCE_BDEV
) {
1958 gint devcode_gint
= process_info
->id
;
1959 LttvBdevState
*bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1960 // the lookup may return null; bdev_set_line_color must act appropriately
1961 bdev_set_line_color(&prop_line
, bdev
);
1964 draw_line((void*)&prop_line
, (void*)&draw_context
);
1967 /* become the last x position */
1968 if(likely(x
!= hashed_process_data
->x
.middle
)) {
1969 hashed_process_data
->x
.middle
= x
;
1970 /* but don't use the pixel */
1971 hashed_process_data
->x
.middle_used
= FALSE
;
1973 /* Calculate the next good time */
1974 convert_pixels_to_time(width
, x
+1, time_window
,
1975 &hashed_process_data
->next_good_time
);
1982 int before_chunk(void *hook_data
, void *call_data
)
1984 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
1985 LttvTraceset
*ts
= (LttvTraceset
*)call_data
;
1988 /* Deactivate sort */
1989 gtk_tree_sortable_set_sort_column_id(
1990 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
1992 GTK_SORT_ASCENDING
);
1994 drawing_chunk_begin(events_request
, ts
);
2001 * This gets executed just before an events request is executed
2004 int before_request(void *hook_data
, void *call_data
)
2006 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2008 drawing_data_request_begin(events_request
);
2013 void draw_closing_lines(ControlFlowData
*resourceview_data
,
2014 EventsRequest
* events_request
)
2016 LttTime end_time
= events_request
->end_time
;
2017 ClosureData closure_data
;
2018 closure_data
.events_request
= events_request
;
2019 closure_data
.end_time
= end_time
;
2022 TimeWindow time_window
=
2023 lttvwindow_get_time_window(resourceview_data
->tab
);
2024 guint width
= resourceview_data
->drawing
->width
;
2025 convert_time_to_pixels(
2029 &closure_data
.x_end
);
2032 /* Draw last items */
2033 for(i
=0; i
<RV_RESOURCE_COUNT
; i
++) {
2034 g_hash_table_foreach(resourcelist_get_resource_hash_table(resourceview_data
, i
), draw_closure
,
2035 (void*)&closure_data
);
2038 /* Request expose */
2039 drawing_request_expose(events_request
, end_time
);
2043 * after request is necessary in addition of after chunk in order to draw
2044 * lines until the end of the screen. after chunk just draws lines until
2051 int after_request(void *hook_data
, void *call_data
)
2054 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2055 ControlFlowData
*resourceview_data
= events_request
->viewer_data
;
2057 draw_closing_lines(resourceview_data
, events_request
);
2067 int after_chunk(void *hook_data
, void *call_data
)
2069 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2070 ControlFlowData
*resourceview_data
= events_request
->viewer_data
;
2071 LttvTraceset
*ts
= (LttvTraceset
*)call_data
;
2073 ProcessList
*process_list
= resourceview_data
->process_list
;
2075 guint nb_trace
= lttv_traceset_number(ts
);
2077 /* Only execute when called for the first trace's events request */
2078 if(!process_list
->current_hash_data
)
2081 for(i
= 0 ; i
< nb_trace
; i
++) {
2082 g_free(process_list
->current_hash_data
[i
]);
2084 g_free(process_list
->current_hash_data
);
2085 process_list
->current_hash_data
= NULL
;
2087 draw_closing_lines(resourceview_data
, events_request
);
2092 /* after_statedump_end
2094 * @param hook_data ControlFlowData structure of the viewer.
2095 * @param call_data Event context.
2097 * This function adds items to be drawn in a queue for each process.
2100 int before_statedump_end(void *hook_data
, void *call_data
)
2104 event
= (LttvEvent
*) call_data
;
2106 if (strcmp(lttv_traceset_get_name_from_event(event
),"lttng_statedump_end") != 0)
2109 ControlFlowData
*resourceview_data
= (ControlFlowData
*) hook_data
;
2113 #ifdef BABEL_CLEANUP
2115 LttvFilter
*filter
= resourceview_data
->filter
;
2116 if(filter
!= NULL
&& filter
->head
!= NULL
)
2117 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2118 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2122 LttTime evtime
= lttv_event_get_timestamp(event
);
2124 ClosureData closure_data
;
2125 //TODO ybrosseau 2013-03-27: Fake and event_request.
2126 // We need to change the API of drawing_request_expose to ask
2127 // For and control flow data only.
2128 EventsRequest events_request
;
2129 events_request
.viewer_data
= resourceview_data
;
2130 closure_data
.events_request
= &events_request
;
2131 closure_data
.end_time
= evtime
;
2133 TimeWindow time_window
=
2134 lttvwindow_get_time_window(resourceview_data
->tab
);
2135 guint width
= resourceview_data
->drawing
->width
;
2136 convert_time_to_pixels(
2140 &closure_data
.x_end
);
2142 /* Draw last items */
2144 for(i
=0; i
<RV_RESOURCE_COUNT
; i
++) {
2145 g_hash_table_foreach(resourcelist_get_resource_hash_table(resourceview_data
, i
), draw_closure
,
2146 (void*)&closure_data
);
2149 /* Reactivate sort */
2150 gtk_tree_sortable_set_sort_column_id(
2151 GTK_TREE_SORTABLE(resourceview_data
->process_list
->list_store
),
2152 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2153 GTK_SORT_ASCENDING
);
2155 update_index_to_pixmap(resourceview_data
->process_list
);
2156 /* Request a full expose : drawing scrambled */
2157 gtk_widget_queue_draw(resourceview_data
->drawing
->drawing_area
);
2159 /* Request expose (updates damages zone also) */
2160 drawing_request_expose(&events_request
, evtime
);