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
60 //#include <pango/pango.h>
62 #include <ltt/event.h>
64 #include <ltt/trace.h>
66 #include <lttv/lttv.h>
67 #include <lttv/hook.h>
68 #include <lttv/state.h>
69 #include <lttvwindow/lttvwindow.h>
70 #include <lttvwindow/lttvwindowtraces.h>
71 #include <lttvwindow/support.h>
74 #include "eventhooks.h"
76 #include "processlist.h"
80 #define MAX_PATH_LEN 256
81 #define STATE_LINE_WIDTH 6
82 #define COLLISION_POSITION(height) (((height - STATE_LINE_WIDTH)/2) -3)
84 extern GSList
*g_legend_list
;
87 /* Action to do when background computation completed.
89 * Wait for all the awaited computations to be over.
92 static gint
background_ready(void *hook_data
, void *call_data
)
94 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
96 control_flow_data
->background_info_waiting
--;
98 if(control_flow_data
->background_info_waiting
== 0) {
99 g_message("control flow viewer : background computation data ready.");
101 drawing_clear(control_flow_data
->drawing
);
102 processlist_clear(control_flow_data
->process_list
);
103 gtk_widget_set_size_request(
104 control_flow_data
->drawing
->drawing_area
,
105 -1, processlist_get_height(control_flow_data
->process_list
));
106 redraw_notify(control_flow_data
, NULL
);
113 /* Request background computation. Verify if it is in progress or ready first.
114 * Only for each trace in the tab's traceset.
117 static void request_background_data(ControlFlowData
*control_flow_data
)
120 LttvTraceset
*ts
= lttvwindow_get_traceset(control_flow_data
->tab
);
121 gint num_traces
= lttv_traceset_number(ts
);
124 LttvTraceState
*tstate
;
126 LttvHooks
*background_ready_hook
= lttv_hooks_new();
127 lttv_hooks_add(background_ready_hook
, background_ready
, control_flow_data
,
129 control_flow_data
->background_info_waiting
= 0;
131 for(i
=0;i
<num_traces
;i
++) {
132 trace
= lttv_traceset_get(ts
, i
);
133 tstate
= trace
->state
;
135 if(lttvwindowtraces_get_ready(g_quark_from_string("state"),trace
)==FALSE
136 && !ts
->has_precomputed_states
) {
138 if(lttvwindowtraces_get_in_progress(g_quark_from_string("state"),
140 /* We first remove requests that could have been done for the same
141 * information. Happens when two viewers ask for it before servicing
144 if(!lttvwindowtraces_background_request_find(trace
, "state"))
145 lttvwindowtraces_background_request_queue(
146 main_window_get_widget(control_flow_data
->tab
), trace
, "state");
147 lttvwindowtraces_background_notify_queue(control_flow_data
,
151 background_ready_hook
);
152 control_flow_data
->background_info_waiting
++;
153 } else { /* in progress */
155 lttvwindowtraces_background_notify_current(control_flow_data
,
159 background_ready_hook
);
160 control_flow_data
->background_info_waiting
++;
163 /* Data ready. By its nature, this viewer doesn't need to have
164 * its data ready hook called there, because a background
165 * request is always linked with a redraw.
171 lttv_hooks_destroy(background_ready_hook
);
178 * Event Viewer's constructor hook
180 * This constructor is given as a parameter to the menuitem and toolbar button
181 * registration. It creates the list.
182 * @param tab A pointer to the parent tab.
183 * @return The widget created.
186 h_guicontrolflow(LttvPlugin
*plugin
)
188 LttvPluginTab
*ptab
= LTTV_PLUGIN_TAB(plugin
);
189 Tab
*tab
= ptab
->tab
;
190 g_info("h_guicontrolflow, %p", tab
);
191 ControlFlowData
*control_flow_data
= guicontrolflow(ptab
);
193 control_flow_data
->tab
= tab
;
195 // Unreg done in the GuiControlFlow_Destructor
196 lttvwindow_register_traceset_notify(tab
,
200 lttvwindow_register_time_window_notify(tab
,
201 update_time_window_hook
,
203 lttvwindow_register_current_time_notify(tab
,
204 update_current_time_hook
,
206 lttvwindow_register_redraw_notify(tab
,
209 lttvwindow_register_continue_notify(tab
,
212 request_background_data(control_flow_data
);
215 return guicontrolflow_get_widget(control_flow_data
) ;
219 int event_selected_hook(void *hook_data
, void *call_data
)
221 guint
*event_number
= (guint
*) call_data
;
223 g_debug("DEBUG : event selected by main window : %u", *event_number
);
228 /* Function that selects the color of status&exemode line */
229 static inline PropertiesLine
prepare_s_e_line(LttvProcessState
*process
)
231 PropertiesLine prop_line
;
232 prop_line
.line_width
= STATE_LINE_WIDTH
;
233 prop_line
.style
= GDK_LINE_SOLID
;
234 prop_line
.y
= MIDDLE
;
235 //GdkColormap *colormap = gdk_colormap_get_system();
237 if(process
->state
->s
== LTTV_STATE_RUN
) {
238 if(process
->state
->t
== LTTV_STATE_USER_MODE
)
239 prop_line
.color
= drawing_colors
[COL_RUN_USER_MODE
];
240 else if(process
->state
->t
== LTTV_STATE_SYSCALL
)
241 prop_line
.color
= drawing_colors
[COL_RUN_SYSCALL
];
242 else if(process
->state
->t
== LTTV_STATE_TRAP
)
243 prop_line
.color
= drawing_colors
[COL_RUN_TRAP
];
244 else if(process
->state
->t
== LTTV_STATE_IRQ
)
245 prop_line
.color
= drawing_colors
[COL_RUN_IRQ
];
246 else if(process
->state
->t
== LTTV_STATE_SOFT_IRQ
)
247 prop_line
.color
= drawing_colors
[COL_RUN_SOFT_IRQ
];
248 else if(process
->state
->t
== LTTV_STATE_MAYBE_SYSCALL
)
249 prop_line
.color
= drawing_colors
[COL_MODE_UNKNOWN
];
250 else if(process
->state
->t
== LTTV_STATE_MAYBE_USER_MODE
)
251 prop_line
.color
= drawing_colors
[COL_MODE_UNKNOWN
];
252 else if(process
->state
->t
== LTTV_STATE_MAYBE_TRAP
)
253 prop_line
.color
= drawing_colors
[COL_MODE_UNKNOWN
];
254 else if(process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
)
255 prop_line
.color
= drawing_colors
[COL_MODE_UNKNOWN
];
257 g_assert(FALSE
); /* RUNNING MODE UNKNOWN */
258 } else if(process
->state
->s
== LTTV_STATE_WAIT
) {
259 /* We don't show if we wait while in user mode, trap, irq or syscall */
260 prop_line
.color
= drawing_colors
[COL_WAIT
];
261 } else if(process
->state
->s
== LTTV_STATE_WAIT_CPU
) {
262 /* We don't show if we wait for CPU while in user mode, trap, irq
264 prop_line
.color
= drawing_colors
[COL_WAIT_CPU
];
265 } else if(process
->state
->s
== LTTV_STATE_ZOMBIE
) {
266 prop_line
.color
= drawing_colors
[COL_ZOMBIE
];
267 } else if(process
->state
->s
== LTTV_STATE_WAIT_FORK
) {
268 prop_line
.color
= drawing_colors
[COL_WAIT_FORK
];
269 } else if(process
->state
->s
== LTTV_STATE_EXIT
) {
270 prop_line
.color
= drawing_colors
[COL_EXIT
];
271 } else if(process
->state
->s
== LTTV_STATE_UNNAMED
) {
272 prop_line
.color
= drawing_colors
[COL_UNNAMED
];
273 } else if(process
->state
->s
== LTTV_STATE_DEAD
) {
274 prop_line
.color
= drawing_colors
[COL_DEAD
];
276 g_critical("unknown state : %s", g_quark_to_string(process
->state
->s
));
277 g_assert(FALSE
); /* UNKNOWN STATE */
284 /* Before try-wake-up hook. A process is being woken; we need to draw its line up to this point in time
285 in that colour. This is basically like exec-state, but the change applies to a process other than that
286 which is currently running. */
288 int before_trywakeup_hook(void *hook_data
, void *call_data
)
293 event
= (LttvEvent
*) call_data
;
294 if (strcmp(lttv_traceset_get_name_from_event(event
),"sched_wakeup") != 0)
297 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
299 LttvTraceState
*ts
= event
->state
;;
302 LttTime evtime
= lttv_event_get_timestamp(event
);
304 LttvFilter
*filter
= control_flow_data
->filter
;
310 woken_pid
= lttv_event_get_long(event
, "tid");
311 woken_cpu
= lttv_event_get_long(event
, "target_cpu");
314 if(!filter
|| !filter
->head
||
315 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
316 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
320 /* First, check if the woken process is in the state computation
321 * process list. If it is there, that means we must add it right now and
322 * draw items from the beginning of the read for it. If it is not
323 * present, it's a new process and it was not present : it will
324 * be added after the state update. TOCHECK: What does that last para mean? */
325 guint trace_num
= 0; /*TODO ybrosseau 2012-08-23: use right number */
326 LttvProcessState
*process
= lttv_state_find_process(ts
, woken_cpu
, woken_pid
);
328 if(process
!= NULL
) {
329 /* Well, the woken process existed : we must get it in the process hash
330 * or add it, and draw its items.
332 /* Add process to process list (if not present) */
334 HashedProcessData
*hashed_process_data
= NULL
;
335 ProcessList
*process_list
= control_flow_data
->process_list
;
336 LttTime birth
= process
->creation_time
;
338 hashed_process_data
= processlist_get_process_data(process_list
,
343 if(hashed_process_data
== NULL
)
345 g_assert(woken_pid
!= process
->ppid
);
346 /* Process not present */
347 ProcessInfo
*process_info
;
348 Drawing_t
*drawing
= control_flow_data
->drawing
;
349 processlist_add(process_list
,
361 &hashed_process_data
);
362 gtk_widget_set_size_request(drawing
->drawing_area
,
365 gtk_widget_queue_draw(drawing
->drawing_area
);
369 /* Now, the process is in the state hash and our own process hash.
370 * We definitely can draw the items related to the ending state.
373 if(ltt_time_compare(hashed_process_data
->next_good_time
,
376 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
378 TimeWindow time_window
=
379 lttvwindow_get_time_window(control_flow_data
->tab
);
381 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
382 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
385 Drawing_t
*drawing
= control_flow_data
->drawing
;
386 guint width
= drawing
->width
;
388 convert_time_to_pixels(
394 /* Draw collision indicator */
395 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
396 gdk_draw_point(hashed_process_data
->pixmap
,
399 COLLISION_POSITION(hashed_process_data
->height
));
400 hashed_process_data
->x
.middle_marked
= TRUE
;
403 TimeWindow time_window
=
404 lttvwindow_get_time_window(control_flow_data
->tab
);
406 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
407 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
410 Drawing_t
*drawing
= control_flow_data
->drawing
;
411 guint width
= drawing
->width
;
413 convert_time_to_pixels(
420 /* Jump over draw if we are at the same x position */
421 if(x
== hashed_process_data
->x
.middle
&&
422 hashed_process_data
->x
.middle_used
)
424 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
425 /* Draw collision indicator */
426 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
427 gdk_draw_point(hashed_process_data
->pixmap
,
430 COLLISION_POSITION(hashed_process_data
->height
));
431 hashed_process_data
->x
.middle_marked
= TRUE
;
435 DrawContext draw_context
;
437 /* Now create the drawing context that will be used to draw
438 * items related to the last state. */
439 draw_context
.drawable
= hashed_process_data
->pixmap
;
440 draw_context
.gc
= drawing
->gc
;
441 draw_context
.pango_layout
= drawing
->pango_layout
;
442 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
443 draw_context
.drawinfo
.end
.x
= x
;
445 draw_context
.drawinfo
.y
.over
= 1;
446 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
447 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
449 draw_context
.drawinfo
.start
.offset
.over
= 0;
450 draw_context
.drawinfo
.start
.offset
.middle
= 0;
451 draw_context
.drawinfo
.start
.offset
.under
= 0;
452 draw_context
.drawinfo
.end
.offset
.over
= 0;
453 draw_context
.drawinfo
.end
.offset
.middle
= 0;
454 draw_context
.drawinfo
.end
.offset
.under
= 0;
458 PropertiesLine prop_line
= prepare_s_e_line(process
);
459 draw_line((void*)&prop_line
, (void*)&draw_context
);
462 /* become the last x position */
463 hashed_process_data
->x
.middle
= x
;
464 hashed_process_data
->x
.middle_used
= TRUE
;
465 hashed_process_data
->x
.middle_marked
= FALSE
;
467 /* Calculate the next good time */
468 convert_pixels_to_time(width
, x
+1, time_window
,
469 &hashed_process_data
->next_good_time
);
482 /* before_schedchange_hook
484 * This function basically draw lines and icons. Two types of lines are drawn :
485 * one small (3 pixels?) representing the state of the process and the second
486 * type is thicker (10 pixels?) representing on which CPU a process is running
487 * (and this only in running state).
489 * Extremums of the lines :
490 * x_min : time of the last event context for this process kept in memory.
491 * x_max : time of the current event.
492 * y : middle of the process in the process list. The process is found in the
493 * list, therefore is it's position in pixels.
495 * The choice of lines'color is defined by the context of the last event for this
500 int before_schedchange_hook(void *hook_data
, void *call_data
)
505 LttvProcessState
*process
;
507 //LttvProcessState *old_process = ts->running_process[cpu];
509 guint pid_in
, pid_out
;
512 event
= (LttvEvent
*) call_data
;
513 if (strcmp(lttv_traceset_get_name_from_event(event
),"sched_switch") != 0)
516 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
519 /* we are in a schedchange, before the state update. We must draw the
520 * items corresponding to the state before it changes : now is the right
523 cpu
= lttv_traceset_get_cpuid_from_event(event
);
526 pid_out
= lttv_event_get_long(event
, "prev_tid");
527 pid_in
= lttv_event_get_long(event
, "next_tid");
528 state_out
= lttv_event_get_long(event
, "prev_state");
529 guint trace_number
= 0;//TODO fdeslauriers 2012-07-17: // Use trace handle to know trace number
531 process
= lttv_state_find_process(ts
,cpu
,pid_out
);
532 timestamp
= lttv_event_get_timestamp(event
);
533 /* For the pid_out */
534 /* First, check if the current process is in the state computation
535 * process list. If it is there, that means we must add it right now and
536 * draw items from the beginning of the read for it. If it is not
537 * present, it's a new process and it was not present : it will
538 * be added after the state update. */
540 /* unknown state, bad current pid */
542 if(process
!= NULL
) {
543 /* Well, the process_out existed : we must get it in the process hash
544 * or add it, and draw its items.
546 /* Add process to process list (if not present) */
548 HashedProcessData
*hashed_process_data
= NULL
;
549 ProcessList
*process_list
= control_flow_data
->process_list
;
550 LttTime birth
= process
->creation_time
;
552 hashed_process_data
= processlist_get_process_data(process_list
,
557 if(hashed_process_data
== NULL
)
559 g_assert(pid_out
== 0 || pid_out
!= process
->ppid
);
560 /* Process not present */
561 ProcessInfo
*process_info
;
562 Drawing_t
*drawing
= control_flow_data
->drawing
;
563 processlist_add(process_list
,
575 &hashed_process_data
);
576 gtk_widget_set_size_request(drawing
->drawing_area
,
579 gtk_widget_queue_draw(drawing
->drawing_area
);
582 /* Now, the process is in the state hash and our own process hash.
583 * We definitely can draw the items related to the ending state.
586 if(ltt_time_compare(hashed_process_data
->next_good_time
,
589 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
591 TimeWindow time_window
=
592 lttvwindow_get_time_window(control_flow_data
->tab
);
594 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
595 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
598 Drawing_t
*drawing
= control_flow_data
->drawing
;
599 guint width
= drawing
->width
;
601 convert_time_to_pixels(
607 /* Draw collision indicator */
608 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
609 gdk_draw_point(hashed_process_data
->pixmap
,
612 COLLISION_POSITION(hashed_process_data
->height
));
613 hashed_process_data
->x
.middle_marked
= TRUE
;
616 TimeWindow time_window
=
617 lttvwindow_get_time_window(control_flow_data
->tab
);
619 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
620 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
623 Drawing_t
*drawing
= control_flow_data
->drawing
;
624 guint width
= drawing
->width
;
626 convert_time_to_pixels(
633 /* Jump over draw if we are at the same x position */
634 if(x
== hashed_process_data
->x
.middle
&&
635 hashed_process_data
->x
.middle_used
)
637 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
638 /* Draw collision indicator */
639 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
640 gdk_draw_point(hashed_process_data
->pixmap
,
643 COLLISION_POSITION(hashed_process_data
->height
));
644 hashed_process_data
->x
.middle_marked
= TRUE
;
648 DrawContext draw_context
;
650 /* Now create the drawing context that will be used to draw
651 * items related to the last state. */
652 draw_context
.drawable
= hashed_process_data
->pixmap
;
653 draw_context
.gc
= drawing
->gc
;
654 draw_context
.pango_layout
= drawing
->pango_layout
;
655 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
656 draw_context
.drawinfo
.end
.x
= x
;
658 draw_context
.drawinfo
.y
.over
= 1;
659 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
660 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
662 draw_context
.drawinfo
.start
.offset
.over
= 0;
663 draw_context
.drawinfo
.start
.offset
.middle
= 0;
664 draw_context
.drawinfo
.start
.offset
.under
= 0;
665 draw_context
.drawinfo
.end
.offset
.over
= 0;
666 draw_context
.drawinfo
.end
.offset
.middle
= 0;
667 draw_context
.drawinfo
.end
.offset
.under
= 0;
671 PropertiesLine prop_line
= prepare_s_e_line(process
);
672 draw_line((void*)&prop_line
, (void*)&draw_context
);
675 /* become the last x position */
676 hashed_process_data
->x
.middle
= x
;
677 hashed_process_data
->x
.middle_used
= TRUE
;
678 hashed_process_data
->x
.middle_marked
= FALSE
;
680 /* Calculate the next good time */
681 convert_pixels_to_time(width
, x
+1, time_window
,
682 &hashed_process_data
->next_good_time
);
688 /* First, check if the current process is in the state computation
689 * process list. If it is there, that means we must add it right now and
690 * draw items from the beginning of the read for it. If it is not
691 * present, it's a new process and it was not present : it will
692 * be added after the state update. */
693 process
= lttv_state_find_process(ts
,cpu
,pid_in
);
695 if(process
!= NULL
) {
696 /* Well, the process existed : we must get it in the process hash
697 * or add it, and draw its items.
699 /* Add process to process list (if not present) */
701 HashedProcessData
*hashed_process_data
= NULL
;
702 ProcessList
*process_list
= control_flow_data
->process_list
;
703 LttTime birth
= process
->creation_time
;
705 hashed_process_data
= processlist_get_process_data(process_list
,
709 trace_number
);//TODO "use the right value or delete"
710 if(hashed_process_data
== NULL
)
712 g_assert(pid_in
== 0 || pid_in
!= process
->ppid
);
713 /* Process not present */
714 ProcessInfo
*process_info
;
715 Drawing_t
*drawing
= control_flow_data
->drawing
;
716 processlist_add(process_list
,
728 &hashed_process_data
);
729 gtk_widget_set_size_request(drawing
->drawing_area
,
732 gtk_widget_queue_draw(drawing
->drawing_area
);
735 //We could set the current process and hash here, but will be done
736 //by after schedchange hook
738 /* Now, the process is in the state hash and our own process hash.
739 * We definitely can draw the items related to the ending state.
742 if(ltt_time_compare(hashed_process_data
->next_good_time
,
745 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
747 TimeWindow time_window
=
748 lttvwindow_get_time_window(control_flow_data
->tab
);
750 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
751 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
754 Drawing_t
*drawing
= control_flow_data
->drawing
;
755 guint width
= drawing
->width
;
757 convert_time_to_pixels(
763 /* Draw collision indicator */
764 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
765 gdk_draw_point(hashed_process_data
->pixmap
,
768 COLLISION_POSITION(hashed_process_data
->height
));
769 hashed_process_data
->x
.middle_marked
= TRUE
;
772 TimeWindow time_window
=
773 lttvwindow_get_time_window(control_flow_data
->tab
);
775 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
776 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
779 Drawing_t
*drawing
= control_flow_data
->drawing
;
780 guint width
= drawing
->width
;
783 convert_time_to_pixels(
790 /* Jump over draw if we are at the same x position */
791 if(x
== hashed_process_data
->x
.middle
&&
792 hashed_process_data
->x
.middle_used
)
794 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
795 /* Draw collision indicator */
796 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
797 gdk_draw_point(hashed_process_data
->pixmap
,
800 COLLISION_POSITION(hashed_process_data
->height
));
801 hashed_process_data
->x
.middle_marked
= TRUE
;
805 DrawContext draw_context
;
807 /* Now create the drawing context that will be used to draw
808 * items related to the last state. */
809 draw_context
.drawable
= hashed_process_data
->pixmap
;
810 draw_context
.gc
= drawing
->gc
;
811 draw_context
.pango_layout
= drawing
->pango_layout
;
812 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
813 draw_context
.drawinfo
.end
.x
= x
;
815 draw_context
.drawinfo
.y
.over
= 1;
816 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
817 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
819 draw_context
.drawinfo
.start
.offset
.over
= 0;
820 draw_context
.drawinfo
.start
.offset
.middle
= 0;
821 draw_context
.drawinfo
.start
.offset
.under
= 0;
822 draw_context
.drawinfo
.end
.offset
.over
= 0;
823 draw_context
.drawinfo
.end
.offset
.middle
= 0;
824 draw_context
.drawinfo
.end
.offset
.under
= 0;
828 PropertiesLine prop_line
= prepare_s_e_line(process
);
829 draw_line((void*)&prop_line
, (void*)&draw_context
);
833 /* become the last x position */
834 hashed_process_data
->x
.middle
= x
;
835 hashed_process_data
->x
.middle_used
= TRUE
;
836 hashed_process_data
->x
.middle_marked
= FALSE
;
838 /* Calculate the next good time */
839 convert_pixels_to_time(width
, x
+1, time_window
,
840 &hashed_process_data
->next_good_time
);
844 g_warning("Cannot find pin_in in schedchange %u", pid_in
);
846 tfc
->target_pid
= target_pid_saved
;
847 #endif //babel_cleanup
855 GString
*string
= g_string_new("");;
856 gboolean field_names
= TRUE
, state
= TRUE
;
858 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
859 g_string_append_printf(string
,"\n");
862 g_string_append_printf(string
, " %s",
863 g_quark_to_string(tfs
->process
->state
->s
));
866 g_info("%s",string
->str
);
868 g_string_free(string
, TRUE
);
870 /* End of text dump */
875 /* after_schedchange_hook
877 * The draw after hook is called by the reading API to have a
878 * particular event drawn on the screen.
879 * @param hook_data ControlFlowData structure of the viewer.
880 * @param call_data Event context.
882 * This function adds items to be drawn in a queue for each process.
885 int after_schedchange_hook(void *hook_data
, void *call_data
)
889 event
= (LttvEvent
*) call_data
;
891 if (strcmp(lttv_traceset_get_name_from_event(event
),"sched_switch") != 0)
894 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
897 LttvTraceState
*ts
= event
->state
;
900 LttvFilter
*filter
= control_flow_data
->filter
;
902 LttTime evtime
= lttv_event_get_timestamp(event
);
904 /* Add process to process list (if not present) */
905 LttvProcessState
*process_in
;
908 HashedProcessData
*hashed_process_data_in
= NULL
;
910 ProcessList
*process_list
= control_flow_data
->process_list
;
914 pid_in
= lttv_event_get_long(event
, "next_tid");
918 if(!filter
|| !filter
->head
||
919 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
920 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
924 /* Find process pid_in in the list... */
925 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
926 //process_in = tfs->process;
927 guint cpu
= lttv_traceset_get_cpuid_from_event(event
);
928 guint trace_num
= 0; /* TODO set right trace number */
929 process_in
= ts
->running_process
[cpu
];
930 /* It should exist, because we are after the state update. */
932 g_assert(process_in
!= NULL
);
934 birth
= process_in
->creation_time
;
936 hashed_process_data_in
= processlist_get_process_data(process_list
,
941 if(hashed_process_data_in
== NULL
)
943 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
944 ProcessInfo
*process_info
;
945 Drawing_t
*drawing
= control_flow_data
->drawing
;
946 /* Process not present */
947 processlist_add(process_list
,
959 &hashed_process_data_in
);
960 gtk_widget_set_size_request(drawing
->drawing_area
,
963 gtk_widget_queue_draw(drawing
->drawing_area
);
965 /* Set the current process */
966 process_list
->current_hash_data
[trace_num
][process_in
->cpu
] =
967 hashed_process_data_in
;
969 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
972 TimeWindow time_window
=
973 lttvwindow_get_time_window(control_flow_data
->tab
);
976 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
977 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
980 Drawing_t
*drawing
= control_flow_data
->drawing
;
981 guint width
= drawing
->width
;
984 convert_time_to_pixels(
990 if(hashed_process_data_in
->x
.middle
!= new_x
) {
991 hashed_process_data_in
->x
.middle
= new_x
;
992 hashed_process_data_in
->x
.middle_used
= FALSE
;
993 hashed_process_data_in
->x
.middle_marked
= FALSE
;
1004 /* before_execmode_hook
1006 * This function basically draw lines and icons. Two types of lines are drawn :
1007 * one small (3 pixels?) representing the state of the process and the second
1008 * type is thicker (10 pixels?) representing on which CPU a process is running
1009 * (and this only in running state).
1011 * Extremums of the lines :
1012 * x_min : time of the last event context for this process kept in memory.
1013 * x_max : time of the current event.
1014 * y : middle of the process in the process list. The process is found in the
1015 * list, therefore is it's position in pixels.
1017 * The choice of lines'color is defined by the context of the last event for this
1022 int before_execmode_hook(void *hook_data
, void *call_data
)
1028 LttvProcessState
*process
;
1030 /* we are in a execmode, before the state update. We must draw the
1031 * items corresponding to the state before it changes : now is the right
1035 event
= (LttvEvent
*) call_data
;
1036 if ((strncmp(lttv_traceset_get_name_from_event(event
),"sys_", sizeof("sys_") - 1) == 0)
1037 ||(strcmp(lttv_traceset_get_name_from_event(event
),"exit_syscall") == 0)
1038 ||(strncmp(lttv_traceset_get_name_from_event(event
),"irq_handler_",sizeof("irq_handler_")) == 0)
1039 ||(strncmp(lttv_traceset_get_name_from_event(event
),"softirq_", sizeof("softirq_")) == 0)){
1041 LttTime evtime
= lttv_event_get_timestamp(event
);
1042 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
1044 LttvTraceset
*traceSet
= lttvwindow_get_traceset(control_flow_data
->tab
);
1046 cpu
= lttv_traceset_get_cpuid_from_event(event
);
1049 guint trace_number
= 0;//TODO fdeslauriers 2012-07-17: // Use trace handle to know trace number
1050 process
= lttv_state_find_process(ts
,cpu
,pid
);
1051 g_assert(process
!= NULL
);
1053 guint pid
= process
->pid
;
1055 /* Well, the process_out existed : we must get it in the process hash
1056 * or add it, and draw its items.
1058 /* Add process to process list (if not present) */
1059 guint pl_height
= 0;
1060 HashedProcessData
*hashed_process_data
= NULL
;
1061 ProcessList
*process_list
= control_flow_data
->process_list
;
1062 if(process_list
->current_hash_data
== NULL
){//TODO fdeslauriers 2012-07-17 : should not be necessary
1066 LttTime birth
= process
->creation_time
;
1068 if(likely(process_list
->current_hash_data
[trace_number
][cpu
] != NULL
)) {
1069 hashed_process_data
= process_list
->current_hash_data
[trace_number
][cpu
];
1071 hashed_process_data
= processlist_get_process_data(process_list
,
1076 if(unlikely(hashed_process_data
== NULL
))
1078 g_assert(pid
== 0 || pid
!= process
->ppid
);
1079 ProcessInfo
*process_info
;
1080 /* Process not present */
1081 Drawing_t
*drawing
= control_flow_data
->drawing
;
1082 processlist_add(process_list
,
1094 &hashed_process_data
);
1095 gtk_widget_set_size_request(drawing
->drawing_area
,
1098 gtk_widget_queue_draw(drawing
->drawing_area
);
1100 /* Set the current process */
1101 process_list
->current_hash_data
[trace_number
][process
->cpu
] =
1102 hashed_process_data
;
1105 /* Now, the process is in the state hash and our own process hash.
1106 * We definitely can draw the items related to the ending state.
1109 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1112 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1113 TimeWindow time_window
=
1114 lttvwindow_get_time_window(control_flow_data
->tab
);
1117 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1118 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1120 #endif //EXTRA_CHECK
1121 Drawing_t
*drawing
= control_flow_data
->drawing
;
1122 guint width
= drawing
->width
;
1124 convert_time_to_pixels(
1130 /* Draw collision indicator */
1131 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1132 gdk_draw_point(hashed_process_data
->pixmap
,
1135 COLLISION_POSITION(hashed_process_data
->height
));
1136 hashed_process_data
->x
.middle_marked
= TRUE
;
1139 TimeWindow time_window
=
1140 lttvwindow_get_time_window(control_flow_data
->tab
);
1143 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1144 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1146 #endif //EXTRA_CHECK
1147 Drawing_t
*drawing
= control_flow_data
->drawing
;
1148 guint width
= drawing
->width
;
1151 convert_time_to_pixels(
1158 /* Jump over draw if we are at the same x position */
1159 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1160 hashed_process_data
->x
.middle_used
))
1162 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1163 /* Draw collision indicator */
1164 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1165 gdk_draw_point(hashed_process_data
->pixmap
,
1168 COLLISION_POSITION(hashed_process_data
->height
));
1169 hashed_process_data
->x
.middle_marked
= TRUE
;
1174 DrawContext draw_context
;
1175 /* Now create the drawing context that will be used to draw
1176 * items related to the last state. */
1177 draw_context
.drawable
= hashed_process_data
->pixmap
;
1178 draw_context
.gc
= drawing
->gc
;
1179 draw_context
.pango_layout
= drawing
->pango_layout
;
1180 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1181 draw_context
.drawinfo
.end
.x
= x
;
1183 draw_context
.drawinfo
.y
.over
= 1;
1184 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1185 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1187 draw_context
.drawinfo
.start
.offset
.over
= 0;
1188 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1189 draw_context
.drawinfo
.start
.offset
.under
= 0;
1190 draw_context
.drawinfo
.end
.offset
.over
= 0;
1191 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1192 draw_context
.drawinfo
.end
.offset
.under
= 0;
1196 PropertiesLine prop_line
= prepare_s_e_line(process
);
1197 draw_line((void*)&prop_line
, (void*)&draw_context
);
1200 /* become the last x position */
1201 hashed_process_data
->x
.middle
= x
;
1202 hashed_process_data
->x
.middle_used
= TRUE
;
1203 hashed_process_data
->x
.middle_marked
= FALSE
;
1205 /* Calculate the next good time */
1206 convert_pixels_to_time(width
, x
+1, time_window
,
1207 &hashed_process_data
->next_good_time
);
1214 /* before_process_exit_hook
1216 * Draw lines for process event.
1218 * @param hook_data ControlFlowData structure of the viewer.
1219 * @param call_data Event context.
1221 * This function adds items to be drawn in a queue for each process.
1226 int before_process_exit_hook(void *hook_data
, void *call_data
)
1231 event
= (LttvEvent
*) call_data
;
1232 if (strcmp(lttv_traceset_get_name_from_event(event
),
1233 "sched_process_exit") != 0)
1237 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1238 LttvTraceState
*ts
= event
->state
;
1240 #ifdef BABEL_CLEANUP
1241 LttvFilter
*filter
= control_flow_data
->filter
;
1242 if(filter
!= NULL
&& filter
->head
!= NULL
)
1243 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1244 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1248 LttTime evtime
= lttv_event_get_timestamp(event
);
1250 /* Add process to process list (if not present) */
1251 //LttvProcessState *process = tfs->process;
1252 guint cpu
= lttv_traceset_get_cpuid_from_event(event
);
1253 guint trace_num
= 0; /* TODO set right trace number */
1255 LttvProcessState
*process
= ts
->running_process
[cpu
];
1256 guint pid
= process
->pid
;
1258 guint pl_height
= 0;
1259 HashedProcessData
*hashed_process_data
= NULL
;
1261 ProcessList
*process_list
= control_flow_data
->process_list
;
1263 g_assert(process
!= NULL
);
1265 birth
= process
->creation_time
;
1267 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1268 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1270 hashed_process_data
= processlist_get_process_data(process_list
,
1275 if(unlikely(hashed_process_data
== NULL
))
1277 g_assert(pid
== 0 || pid
!= process
->ppid
);
1278 /* Process not present */
1279 Drawing_t
*drawing
= control_flow_data
->drawing
;
1280 ProcessInfo
*process_info
;
1281 processlist_add(process_list
,
1293 &hashed_process_data
);
1294 gtk_widget_set_size_request(drawing
->drawing_area
,
1297 gtk_widget_queue_draw(drawing
->drawing_area
);
1301 /* Now, the process is in the state hash and our own process hash.
1302 * We definitely can draw the items related to the ending state.
1305 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1308 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1309 TimeWindow time_window
=
1310 lttvwindow_get_time_window(control_flow_data
->tab
);
1313 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1314 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1316 #endif //EXTRA_CHECK
1317 Drawing_t
*drawing
= control_flow_data
->drawing
;
1318 guint width
= drawing
->width
;
1320 convert_time_to_pixels(
1326 /* Draw collision indicator */
1327 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1328 gdk_draw_point(hashed_process_data
->pixmap
,
1331 COLLISION_POSITION(hashed_process_data
->height
));
1332 hashed_process_data
->x
.middle_marked
= TRUE
;
1335 TimeWindow time_window
=
1336 lttvwindow_get_time_window(control_flow_data
->tab
);
1339 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1340 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1342 #endif //EXTRA_CHECK
1343 Drawing_t
*drawing
= control_flow_data
->drawing
;
1344 guint width
= drawing
->width
;
1347 convert_time_to_pixels(
1354 /* Jump over draw if we are at the same x position */
1355 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1356 hashed_process_data
->x
.middle_used
))
1358 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1359 /* Draw collision indicator */
1360 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1361 gdk_draw_point(hashed_process_data
->pixmap
,
1364 COLLISION_POSITION(hashed_process_data
->height
));
1365 hashed_process_data
->x
.middle_marked
= TRUE
;
1369 DrawContext draw_context
;
1371 /* Now create the drawing context that will be used to draw
1372 * items related to the last state. */
1373 draw_context
.drawable
= hashed_process_data
->pixmap
;
1374 draw_context
.gc
= drawing
->gc
;
1375 draw_context
.pango_layout
= drawing
->pango_layout
;
1376 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1377 draw_context
.drawinfo
.end
.x
= x
;
1379 draw_context
.drawinfo
.y
.over
= 1;
1380 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1381 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1383 draw_context
.drawinfo
.start
.offset
.over
= 0;
1384 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1385 draw_context
.drawinfo
.start
.offset
.under
= 0;
1386 draw_context
.drawinfo
.end
.offset
.over
= 0;
1387 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1388 draw_context
.drawinfo
.end
.offset
.under
= 0;
1392 PropertiesLine prop_line
= prepare_s_e_line(process
);
1393 draw_line((void*)&prop_line
, (void*)&draw_context
);
1396 /* become the last x position */
1397 hashed_process_data
->x
.middle
= x
;
1398 hashed_process_data
->x
.middle_used
= TRUE
;
1399 hashed_process_data
->x
.middle_marked
= FALSE
;
1401 /* Calculate the next good time */
1402 convert_pixels_to_time(width
, x
+1, time_window
,
1403 &hashed_process_data
->next_good_time
);
1413 /* before_process_release_hook
1415 * Draw lines for process event.
1417 * @param hook_data ControlFlowData structure of the viewer.
1418 * @param call_data Event context.
1420 * This function adds items to be drawn in a queue for each process.
1425 int before_process_release_hook(void *hook_data
, void *call_data
)
1430 event
= (LttvEvent
*) call_data
;
1432 if (strcmp(lttv_traceset_get_name_from_event(event
),"sched_process_free") != 0)
1435 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1438 LttvTraceState
*ts
= event
->state
;
1440 #ifdef BABEL_CLEANUP
1441 LttvFilter
*filter
= control_flow_data
->filter
;
1442 if(filter
!= NULL
&& filter
->head
!= NULL
)
1443 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1444 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1447 LttTime evtime
= lttv_event_get_timestamp(event
);
1450 guint trace_num
= 0; /* TODO set right trace number */
1454 pid
= lttv_event_get_long(event
, "tid");
1457 /* Add process to process list (if not present) */
1458 /* Don't care about the process if it's not in the state hash already :
1459 * that means a process that has never done anything in the trace and
1460 * unknown suddently gets destroyed : no state meaningful to show. */
1461 LttvProcessState
*process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1463 if(process
!= NULL
) {
1465 HashedProcessData
*hashed_process_data
= NULL
;
1467 ProcessList
*process_list
= control_flow_data
->process_list
;
1469 birth
= process
->creation_time
;
1471 /* Cannot use current process : this event happens on another process,
1472 * action done by the parent. */
1473 hashed_process_data
= processlist_get_process_data(process_list
,
1478 if(unlikely(hashed_process_data
== NULL
))
1480 * Process already been scheduled out EXIT_DEAD, not in the process list
1481 * anymore. Just return.
1485 /* Now, the process is in the state hash and our own process hash.
1486 * We definitely can draw the items related to the ending state.
1489 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1492 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1493 TimeWindow time_window
=
1494 lttvwindow_get_time_window(control_flow_data
->tab
);
1497 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1498 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1500 #endif //EXTRA_CHECK
1501 Drawing_t
*drawing
= control_flow_data
->drawing
;
1502 guint width
= drawing
->width
;
1504 convert_time_to_pixels(
1510 /* Draw collision indicator */
1511 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1512 gdk_draw_point(hashed_process_data
->pixmap
,
1515 COLLISION_POSITION(hashed_process_data
->height
));
1516 hashed_process_data
->x
.middle_marked
= TRUE
;
1519 TimeWindow time_window
=
1520 lttvwindow_get_time_window(control_flow_data
->tab
);
1523 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1524 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1526 #endif //EXTRA_CHECK
1527 Drawing_t
*drawing
= control_flow_data
->drawing
;
1528 guint width
= drawing
->width
;
1531 convert_time_to_pixels(
1538 /* Jump over draw if we are at the same x position */
1539 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1540 hashed_process_data
->x
.middle_used
))
1542 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1543 /* Draw collision indicator */
1544 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1545 gdk_draw_point(hashed_process_data
->pixmap
,
1548 COLLISION_POSITION(hashed_process_data
->height
));
1549 hashed_process_data
->x
.middle_marked
= TRUE
;
1553 DrawContext draw_context
;
1555 /* Now create the drawing context that will be used to draw
1556 * items related to the last state. */
1557 draw_context
.drawable
= hashed_process_data
->pixmap
;
1558 draw_context
.gc
= drawing
->gc
;
1559 draw_context
.pango_layout
= drawing
->pango_layout
;
1560 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1561 draw_context
.drawinfo
.end
.x
= x
;
1563 draw_context
.drawinfo
.y
.over
= 1;
1564 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1565 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1567 draw_context
.drawinfo
.start
.offset
.over
= 0;
1568 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1569 draw_context
.drawinfo
.start
.offset
.under
= 0;
1570 draw_context
.drawinfo
.end
.offset
.over
= 0;
1571 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1572 draw_context
.drawinfo
.end
.offset
.under
= 0;
1576 PropertiesLine prop_line
= prepare_s_e_line(process
);
1577 draw_line((void*)&prop_line
, (void*)&draw_context
);
1580 /* become the last x position */
1581 hashed_process_data
->x
.middle
= x
;
1582 hashed_process_data
->x
.middle_used
= TRUE
;
1583 hashed_process_data
->x
.middle_marked
= FALSE
;
1585 /* Calculate the next good time */
1586 convert_pixels_to_time(width
, x
+1, time_window
,
1587 &hashed_process_data
->next_good_time
);
1599 /* after_process_fork_hook
1601 * Create the processlist entry for the child process. Put the last
1602 * position in x at the current time value.
1604 * @param hook_data ControlFlowData structure of the viewer.
1605 * @param call_data Event context.
1607 * This function adds items to be drawn in a queue for each process.
1610 int after_process_fork_hook(void *hook_data
, void *call_data
)
1614 event
= (LttvEvent
*) call_data
;
1616 if (strcmp(lttv_traceset_get_name_from_event(event
),"sched_process_fork") != 0)
1619 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1622 LttvTraceState
*ts
= event
->state
;
1624 #ifdef BABEL_CLEANUP
1625 LttvFilter
*filter
= control_flow_data
->filter
;
1626 if(filter
!= NULL
&& filter
->head
!= NULL
)
1627 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1628 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1632 LttTime evtime
= lttv_event_get_timestamp(event
);
1636 child_pid
= lttv_event_get_long(event
, "child_tid");
1639 /* Add process to process list (if not present) */
1640 LttvProcessState
*process_child
;
1642 guint pl_height
= 0;
1643 HashedProcessData
*hashed_process_data_child
= NULL
;
1645 ProcessList
*process_list
= control_flow_data
->process_list
;
1647 /* Find child in the list... */
1648 process_child
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1649 /* It should exist, because we are after the state update. */
1650 g_assert(process_child
!= NULL
);
1652 birth
= process_child
->creation_time
;
1653 guint trace_num
= 0; /* TODO put right */
1655 /* Cannot use current process, because this action is done by the parent
1657 hashed_process_data_child
= processlist_get_process_data(process_list
,
1662 if(likely(hashed_process_data_child
== NULL
))
1664 g_assert(child_pid
== 0 || child_pid
!= process_child
->ppid
);
1665 /* Process not present */
1666 Drawing_t
*drawing
= control_flow_data
->drawing
;
1667 ProcessInfo
*process_info
;
1668 processlist_add(process_list
,
1671 process_child
->tgid
,
1673 process_child
->ppid
,
1676 process_child
->name
,
1677 process_child
->brand
,
1680 &hashed_process_data_child
);
1681 gtk_widget_set_size_request(drawing
->drawing_area
,
1684 gtk_widget_queue_draw(drawing
->drawing_area
);
1686 processlist_set_ppid(process_list
, process_child
->ppid
,
1687 hashed_process_data_child
);
1688 processlist_set_tgid(process_list
, process_child
->tgid
,
1689 hashed_process_data_child
);
1693 if(likely(ltt_time_compare(hashed_process_data_child
->next_good_time
,
1696 TimeWindow time_window
=
1697 lttvwindow_get_time_window(control_flow_data
->tab
);
1700 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1701 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1703 #endif //EXTRA_CHECK
1704 Drawing_t
*drawing
= control_flow_data
->drawing
;
1705 guint width
= drawing
->width
;
1707 convert_time_to_pixels(
1713 if(likely(hashed_process_data_child
->x
.over
!= new_x
)) {
1714 hashed_process_data_child
->x
.over
= new_x
;
1715 hashed_process_data_child
->x
.over_used
= FALSE
;
1716 hashed_process_data_child
->x
.over_marked
= FALSE
;
1718 if(likely(hashed_process_data_child
->x
.middle
!= new_x
)) {
1719 hashed_process_data_child
->x
.middle
= new_x
;
1720 hashed_process_data_child
->x
.middle_used
= FALSE
;
1721 hashed_process_data_child
->x
.middle_marked
= FALSE
;
1723 if(likely(hashed_process_data_child
->x
.under
!= new_x
)) {
1724 hashed_process_data_child
->x
.under
= new_x
;
1725 hashed_process_data_child
->x
.under_used
= FALSE
;
1726 hashed_process_data_child
->x
.under_marked
= FALSE
;
1734 /* after_process_exit_hook
1736 * Create the processlist entry for the child process. Put the last
1737 * position in x at the current time value.
1739 * @param hook_data ControlFlowData structure of the viewer.
1740 * @param call_data Event context.
1742 * This function adds items to be drawn in a queue for each process.
1745 int after_process_exit_hook(void *hook_data
, void *call_data
)
1750 event
= (LttvEvent
*) call_data
;
1752 if (strcmp(lttv_traceset_get_name_from_event(event
),"sched_process_exit") != 0)
1755 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1757 LttvTraceState
*ts
= event
->state
;
1759 #ifdef BABEL_CLEANUP
1760 LttvFilter
*filter
= control_flow_data
->filter
;
1761 if(filter
!= NULL
&& filter
->head
!= NULL
)
1762 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1763 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1767 LttTime evtime
= lttv_event_get_timestamp(event
);
1769 /* Add process to process list (if not present) */
1770 //LttvProcessState *process = tfs->process;
1771 guint cpu
= lttv_traceset_get_cpuid_from_event(event
);
1772 guint trace_num
= 0; /* TODO set right trace number */
1773 LttvProcessState
*process
= ts
->running_process
[cpu
];
1775 /* It should exist, because we are after the state update. */
1776 g_assert(process
!= NULL
);
1778 guint pid
= process
->pid
;
1780 guint pl_height
= 0;
1781 HashedProcessData
*hashed_process_data
= NULL
;
1783 ProcessList
*process_list
= control_flow_data
->process_list
;
1785 birth
= process
->creation_time
;
1787 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
) ){
1788 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1790 hashed_process_data
= processlist_get_process_data(process_list
,
1795 if(unlikely(hashed_process_data
== NULL
))
1797 g_assert(pid
== 0 || pid
!= process
->ppid
);
1798 /* Process not present */
1799 Drawing_t
*drawing
= control_flow_data
->drawing
;
1800 ProcessInfo
*process_info
;
1801 processlist_add(process_list
,
1813 &hashed_process_data
);
1814 gtk_widget_set_size_request(drawing
->drawing_area
,
1817 gtk_widget_queue_draw(drawing
->drawing_area
);
1820 /* Set the current process */
1821 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1822 hashed_process_data
;
1825 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
1828 TimeWindow time_window
=
1829 lttvwindow_get_time_window(control_flow_data
->tab
);
1832 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1833 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1835 #endif //EXTRA_CHECK
1836 Drawing_t
*drawing
= control_flow_data
->drawing
;
1837 guint width
= drawing
->width
;
1839 convert_time_to_pixels(
1844 if(unlikely(hashed_process_data
->x
.middle
!= new_x
)) {
1845 hashed_process_data
->x
.middle
= new_x
;
1846 hashed_process_data
->x
.middle_used
= FALSE
;
1847 hashed_process_data
->x
.middle_marked
= FALSE
;
1855 /* Get the filename of the process to print */
1856 int after_fs_exec_hook(void *hook_data
, void *call_data
)
1858 #ifdef BABEL_CLEANUP
1859 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1860 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1861 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1863 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1865 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1867 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1870 e
= ltt_tracefile_get_event(tfc
->tf
);
1872 LttvFilter
*filter
= control_flow_data
->filter
;
1873 if(filter
!= NULL
&& filter
->head
!= NULL
)
1874 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1875 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1878 guint cpu
= tfs
->cpu
;
1879 guint trace_num
= ts
->parent
.index
;
1880 LttvProcessState
*process
= ts
->running_process
[cpu
];
1881 g_assert(process
!= NULL
);
1883 guint pid
= process
->pid
;
1885 /* Well, the process_out existed : we must get it in the process hash
1886 * or add it, and draw its items.
1888 /* Add process to process list (if not present) */
1889 guint pl_height
= 0;
1890 HashedProcessData
*hashed_process_data
= NULL
;
1891 ProcessList
*process_list
= control_flow_data
->process_list
;
1892 LttTime birth
= process
->creation_time
;
1894 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1895 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1897 hashed_process_data
= processlist_get_process_data(process_list
,
1902 if(unlikely(hashed_process_data
== NULL
))
1904 g_assert(pid
== 0 || pid
!= process
->ppid
);
1905 ProcessInfo
*process_info
;
1906 /* Process not present */
1907 Drawing_t
*drawing
= control_flow_data
->drawing
;
1908 processlist_add(process_list
,
1920 &hashed_process_data
);
1921 gtk_widget_set_size_request(drawing
->drawing_area
,
1924 gtk_widget_queue_draw(drawing
->drawing_area
);
1926 /* Set the current process */
1927 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1928 hashed_process_data
;
1931 processlist_set_name(process_list
, process
->name
, hashed_process_data
);
1933 #endif //babel_cleanup
1938 /* Get the filename of the process to print */
1939 int after_user_generic_thread_brand_hook(void *hook_data
, void *call_data
)
1941 #ifdef BABEL_CLEANUP
1942 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1943 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1944 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1946 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1948 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1950 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1953 e
= ltt_tracefile_get_event(tfc
->tf
);
1955 LttvFilter
*filter
= control_flow_data
->filter
;
1956 if(filter
!= NULL
&& filter
->head
!= NULL
)
1957 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1958 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1961 guint cpu
= tfs
->cpu
;
1962 guint trace_num
= ts
->parent
.index
;
1963 LttvProcessState
*process
= ts
->running_process
[cpu
];
1964 g_assert(process
!= NULL
);
1966 guint pid
= process
->pid
;
1968 /* Well, the process_out existed : we must get it in the process hash
1969 * or add it, and draw its items.
1971 /* Add process to process list (if not present) */
1972 guint pl_height
= 0;
1973 HashedProcessData
*hashed_process_data
= NULL
;
1974 ProcessList
*process_list
= control_flow_data
->process_list
;
1975 LttTime birth
= process
->creation_time
;
1977 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1978 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1980 hashed_process_data
= processlist_get_process_data(process_list
,
1985 if(unlikely(hashed_process_data
== NULL
))
1987 g_assert(pid
== 0 || pid
!= process
->ppid
);
1988 ProcessInfo
*process_info
;
1989 /* Process not present */
1990 Drawing_t
*drawing
= control_flow_data
->drawing
;
1991 processlist_add(process_list
,
2003 &hashed_process_data
);
2004 gtk_widget_set_size_request(drawing
->drawing_area
,
2007 gtk_widget_queue_draw(drawing
->drawing_area
);
2009 /* Set the current process */
2010 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
2011 hashed_process_data
;
2014 processlist_set_brand(process_list
, process
->brand
, hashed_process_data
);
2016 #endif //babel_cleanup
2021 /* after_event_enum_process_hook
2023 * Create the processlist entry for the child process. Put the last
2024 * position in x at the current time value.
2026 * @param hook_data ControlFlowData structure of the viewer.
2027 * @param call_data Event context.
2029 * This function adds items to be drawn in a queue for each process.
2032 int after_event_enum_process_hook(void *hook_data
, void *call_data
)
2036 event
= (LttvEvent
*) call_data
;
2038 if (strcmp(lttv_traceset_get_name_from_event(event
),"lttng_statedump_process_state") != 0)
2041 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2044 LttvTraceState
*ts
= event
->state
;
2046 guint first_cpu
, nb_cpus
, cpu
;
2048 #ifdef BABEL_CLEANUP
2049 LttvFilter
*filter
= control_flow_data
->filter
;
2050 if(filter
!= NULL
&& filter
->head
!= NULL
)
2051 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2052 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2055 /* Add process to process list (if not present) */
2056 LttvProcessState
*process_in
;
2058 guint pl_height
= 0;
2059 HashedProcessData
*hashed_process_data_in
= NULL
;
2061 ProcessList
*process_list
= control_flow_data
->process_list
;
2062 guint trace_num
= 0; /* TODO put right trace number */
2066 pid_in
= lttv_event_get_long(event
, "tid");
2071 nb_cpus
= lttv_trace_get_num_cpu(ts
->trace
);
2073 first_cpu
= ANY_CPU
;
2074 nb_cpus
= ANY_CPU
+1;
2077 for(cpu
= first_cpu
; cpu
< nb_cpus
; cpu
++) {
2078 /* Find process pid_in in the list... */
2079 process_in
= lttv_state_find_process(ts
, cpu
, pid_in
);
2080 //process_in = tfs->process;
2081 //guint cpu = tfs->cpu;
2082 //guint trace_num = ts->parent.index;
2083 //process_in = ts->running_process[cpu];
2084 /* It should exist, because we are after the state update. */
2086 //g_assert(process_in != NULL);
2087 #endif //EXTRA_CHECK
2088 birth
= process_in
->creation_time
;
2090 hashed_process_data_in
= processlist_get_process_data(process_list
,
2095 if(hashed_process_data_in
== NULL
)
2097 if(pid_in
!= 0 && pid_in
== process_in
->ppid
)
2098 g_critical("TEST %u , %u", pid_in
, process_in
->ppid
);
2099 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
2100 ProcessInfo
*process_info
;
2101 Drawing_t
*drawing
= control_flow_data
->drawing
;
2102 /* Process not present */
2103 processlist_add(process_list
,
2115 &hashed_process_data_in
);
2116 gtk_widget_set_size_request(drawing
->drawing_area
,
2119 gtk_widget_queue_draw(drawing
->drawing_area
);
2121 processlist_set_name(process_list
, process_in
->name
,
2122 hashed_process_data_in
);
2123 processlist_set_ppid(process_list
, process_in
->ppid
,
2124 hashed_process_data_in
);
2125 processlist_set_tgid(process_list
, process_in
->tgid
,
2126 hashed_process_data_in
);
2133 gint
update_time_window_hook(void *hook_data
, void *call_data
)
2135 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2136 Drawing_t
*drawing
= control_flow_data
->drawing
;
2137 ProcessList
*process_list
= control_flow_data
->process_list
;
2139 const TimeWindowNotifyData
*time_window_nofify_data
=
2140 ((const TimeWindowNotifyData
*)call_data
);
2142 TimeWindow
*old_time_window
=
2143 time_window_nofify_data
->old_time_window
;
2144 TimeWindow
*new_time_window
=
2145 time_window_nofify_data
->new_time_window
;
2147 /* Update the ruler */
2148 drawing_update_ruler(control_flow_data
->drawing
,
2152 /* Two cases : zoom in/out or scrolling */
2154 /* In order to make sure we can reuse the old drawing, the scale must
2155 * be the same and the new time interval being partly located in the
2156 * currently shown time interval. (reuse is only for scrolling)
2159 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
2160 old_time_window
->start_time
.tv_sec
,
2161 old_time_window
->start_time
.tv_nsec
,
2162 old_time_window
->time_width
.tv_sec
,
2163 old_time_window
->time_width
.tv_nsec
);
2165 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
2166 new_time_window
->start_time
.tv_sec
,
2167 new_time_window
->start_time
.tv_nsec
,
2168 new_time_window
->time_width
.tv_sec
,
2169 new_time_window
->time_width
.tv_nsec
);
2171 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
2172 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
2174 /* Same scale (scrolling) */
2175 g_info("scrolling");
2176 LttTime
*ns
= &new_time_window
->start_time
;
2177 LttTime
*os
= &old_time_window
->start_time
;
2178 LttTime old_end
= old_time_window
->end_time
;
2179 LttTime new_end
= new_time_window
->end_time
;
2181 //if(ns<os+w && os+w<ns+w)
2182 //if(ns<old_end && os<ns)
2183 if(ltt_time_compare(*ns
, old_end
) == -1
2184 && ltt_time_compare(*os
, *ns
) == -1)
2186 g_info("scrolling near right");
2187 /* Scroll right, keep right part of the screen */
2189 guint width
= control_flow_data
->drawing
->width
;
2190 convert_time_to_pixels(
2196 /* Copy old data to new location */
2197 copy_pixmap_region(process_list
,
2199 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2203 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
2205 if(drawing
->damage_begin
== drawing
->damage_end
)
2206 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
2208 drawing
->damage_begin
= 0;
2210 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2212 /* Clear the data request background, but not SAFETY */
2213 rectangle_pixmap(process_list
,
2214 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2216 drawing
->damage_begin
+SAFETY
, 0,
2217 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2219 gtk_widget_queue_draw(drawing
->drawing_area
);
2220 //gtk_widget_queue_draw_area (drawing->drawing_area,
2222 // control_flow_data->drawing->width,
2223 // control_flow_data->drawing->height);
2225 /* Get new data for the rest. */
2226 drawing_data_request(control_flow_data
->drawing
,
2227 drawing
->damage_begin
, 0,
2228 drawing
->damage_end
- drawing
->damage_begin
,
2229 control_flow_data
->drawing
->height
);
2232 //if(ns<os && os<ns+w)
2233 //if(ns<os && os<new_end)
2234 if(ltt_time_compare(*ns
,*os
) == -1
2235 && ltt_time_compare(*os
,new_end
) == -1)
2237 g_info("scrolling near left");
2238 /* Scroll left, keep left part of the screen */
2240 guint width
= control_flow_data
->drawing
->width
;
2241 convert_time_to_pixels(
2247 /* Copy old data to new location */
2248 copy_pixmap_region (process_list
,
2250 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2256 if(drawing
->damage_begin
== drawing
->damage_end
)
2257 drawing
->damage_end
= x
;
2259 drawing
->damage_end
=
2260 control_flow_data
->drawing
->width
;
2262 drawing
->damage_begin
= 0;
2264 rectangle_pixmap (process_list
,
2265 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2267 drawing
->damage_begin
, 0,
2268 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2271 gtk_widget_queue_draw(drawing
->drawing_area
);
2272 //gtk_widget_queue_draw_area (drawing->drawing_area,
2274 // control_flow_data->drawing->width,
2275 // control_flow_data->drawing->height);
2278 /* Get new data for the rest. */
2279 drawing_data_request(control_flow_data
->drawing
,
2280 drawing
->damage_begin
, 0,
2281 drawing
->damage_end
- drawing
->damage_begin
,
2282 control_flow_data
->drawing
->height
);
2285 if(ltt_time_compare(*ns
,*os
) == 0)
2287 g_info("not scrolling");
2289 g_info("scrolling far");
2290 /* Cannot reuse any part of the screen : far jump */
2293 rectangle_pixmap (process_list
,
2294 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2297 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2300 //gtk_widget_queue_draw_area (drawing->drawing_area,
2302 // control_flow_data->drawing->width,
2303 // control_flow_data->drawing->height);
2304 gtk_widget_queue_draw(drawing
->drawing_area
);
2306 drawing
->damage_begin
= 0;
2307 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2309 drawing_data_request(control_flow_data
->drawing
,
2311 control_flow_data
->drawing
->width
,
2312 control_flow_data
->drawing
->height
);
2318 /* Different scale (zoom) */
2321 rectangle_pixmap (process_list
,
2322 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2325 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2328 //gtk_widget_queue_draw_area (drawing->drawing_area,
2330 // control_flow_data->drawing->width,
2331 // control_flow_data->drawing->height);
2332 gtk_widget_queue_draw(drawing
->drawing_area
);
2334 drawing
->damage_begin
= 0;
2335 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2337 drawing_data_request(control_flow_data
->drawing
,
2339 control_flow_data
->drawing
->width
,
2340 control_flow_data
->drawing
->height
);
2343 /* Update directly when scrolling */
2344 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2350 gint
traceset_notify(void *hook_data
, void *call_data
)
2352 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2353 Drawing_t
*drawing
= control_flow_data
->drawing
;
2355 if(unlikely(drawing
->gc
== NULL
)) {
2358 if(drawing
->dotted_gc
== NULL
) {
2362 drawing_clear(control_flow_data
->drawing
);
2363 processlist_clear(control_flow_data
->process_list
);
2364 gtk_widget_set_size_request(
2365 control_flow_data
->drawing
->drawing_area
,
2366 -1, processlist_get_height(control_flow_data
->process_list
));
2367 redraw_notify(control_flow_data
, NULL
);
2369 request_background_data(control_flow_data
);
2374 gint
redraw_notify(void *hook_data
, void *call_data
)
2376 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2377 Drawing_t
*drawing
= control_flow_data
->drawing
;
2378 GtkWidget
*widget
= drawing
->drawing_area
;
2380 drawing
->damage_begin
= 0;
2381 drawing
->damage_end
= drawing
->width
;
2383 /* fun feature, to be separated someday... */
2384 drawing_clear(control_flow_data
->drawing
);
2385 processlist_clear(control_flow_data
->process_list
);
2386 gtk_widget_set_size_request(
2387 control_flow_data
->drawing
->drawing_area
,
2388 -1, processlist_get_height(control_flow_data
->process_list
));
2390 rectangle_pixmap (control_flow_data
->process_list
,
2391 widget
->style
->black_gc
,
2394 drawing
->alloc_width
,
2397 gtk_widget_queue_draw(drawing
->drawing_area
);
2399 if(drawing
->damage_begin
< drawing
->damage_end
)
2401 drawing_data_request(drawing
,
2402 drawing
->damage_begin
,
2404 drawing
->damage_end
-drawing
->damage_begin
,
2408 //gtk_widget_queue_draw_area(drawing->drawing_area,
2411 // drawing->height);
2417 gint
continue_notify(void *hook_data
, void *call_data
)
2419 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2420 Drawing_t
*drawing
= control_flow_data
->drawing
;
2422 //g_assert(widget->allocation.width == drawing->damage_end);
2424 if(drawing
->damage_begin
< drawing
->damage_end
)
2426 drawing_data_request(drawing
,
2427 drawing
->damage_begin
,
2429 drawing
->damage_end
-drawing
->damage_begin
,
2437 gint
update_current_time_hook(void *hook_data
, void *call_data
)
2440 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
2442 LttTime current_time
= *((LttTime
*)call_data
);
2444 TimeWindow time_window
=
2445 lttvwindow_get_time_window(control_flow_data
->tab
);
2447 LttTime time_begin
= time_window
.start_time
;
2448 LttTime width
= time_window
.time_width
;
2451 guint64 time_ll
= ltt_time_to_uint64(width
);
2452 time_ll
= time_ll
>> 1; /* divide by two */
2453 half_width
= ltt_time_from_uint64(time_ll
);
2455 LttTime time_end
= ltt_time_add(time_begin
, width
);
2457 LttvTraceset
* ts
= lttvwindow_get_traceset(control_flow_data
->tab
);
2459 TimeInterval time_span
= lttv_traceset_get_time_span_real(ts
);
2460 LttTime trace_start
= time_span
.start_time
;
2461 LttTime trace_end
= time_span
.end_time
;
2463 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
2464 current_time
.tv_nsec
);
2468 /* If current time is inside time interval, just move the highlight
2471 /* Else, we have to change the time interval. We have to tell it
2472 * to the main window. */
2473 /* The time interval change will take care of placing the current
2474 * time at the center of the visible area, or nearest possible if we are
2475 * at one end of the trace. */
2478 if(ltt_time_compare(current_time
, time_begin
) < 0)
2480 TimeWindow new_time_window
;
2482 if(ltt_time_compare(current_time
,
2483 ltt_time_add(trace_start
,half_width
)) < 0)
2484 time_begin
= trace_start
;
2486 time_begin
= ltt_time_sub(current_time
,half_width
);
2488 new_time_window
.start_time
= time_begin
;
2489 new_time_window
.time_width
= width
;
2490 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2491 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2493 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2495 else if(ltt_time_compare(current_time
, time_end
) > 0)
2497 TimeWindow new_time_window
;
2499 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
2500 time_begin
= ltt_time_sub(trace_end
,width
);
2502 time_begin
= ltt_time_sub(current_time
,half_width
);
2504 new_time_window
.start_time
= time_begin
;
2505 new_time_window
.time_width
= width
;
2506 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2507 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2509 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2512 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2514 /* Update directly when scrolling */
2515 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2522 typedef struct _ClosureData
{
2523 EventsRequest
*events_request
;
2529 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
2532 ProcessInfo
*process_info
= (ProcessInfo
*)key
;
2533 HashedProcessData
*hashed_process_data
= (HashedProcessData
*)value
;
2534 ClosureData
*closure_data
= (ClosureData
*)user_data
;
2536 EventsRequest
*events_request
= closure_data
->events_request
;
2537 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2538 LttvTraceset
*ts
= lttvwindow_get_traceset(control_flow_data
->tab
);
2541 LttTime evtime
= closure_data
->end_time
;
2543 gboolean dodraw
= TRUE
;
2546 /* For the process */
2547 /* First, check if the current process is in the state computation
2548 * process list. If it is there, that means we must add it right now and
2549 * draw items from the beginning of the read for it. If it is not
2550 * present, it's a new process and it was not present : it will
2551 * be added after the state update. */
2553 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
2554 #endif //EXTRA_CHECK
2555 //TODO Fdeslauriers 2012-07-17: adapt for multiple traces
2556 LttvTrace
*trace
= lttv_traceset_get(ts
,0);
2557 LttvTraceState
*trace_state
= trace
->state
;
2560 //FIXME : optimize data structures.
2561 LttvTracefileState
*tfs
;
2562 LttvTracefileContext
*tfc
;
2564 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
2565 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
2566 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
2567 && tfs
->cpu
== process_info
->cpu
)
2571 g_assert(i
<tc
->tracefiles
->len
);
2572 tfs
= LTTV_TRACEFILE_STATE(tfc
);
2574 // LttvTracefileState *tfs =ts
2575 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2576 // tracefiles[process_info->cpu];
2578 LttvProcessState
*process
;
2579 process
= lttv_state_find_process(trace_state
, process_info
->cpu
,
2582 if(unlikely(process
!= NULL
)) {
2583 #ifdef BABEL_CLEANUP
2584 LttvFilter
*filter
= control_flow_data
->filter
;
2585 if(filter
!= NULL
&& filter
->head
!= NULL
)
2586 if(!lttv_filter_tree_parse(filter
->head
,NULL
,NULL
,
2587 tc
->t
,NULL
,process
,tc
))
2589 #endif //babel_cleanup
2590 /* Only draw for processes that are currently in the trace states */
2593 /* Should be alike when background info is ready */
2594 if(control_flow_data
->background_info_waiting
==0)
2595 g_assert(ltt_time_compare(process
->creation_time
,
2596 process_info
->birth
) == 0);
2597 #endif //EXTRA_CHECK
2599 /* Now, the process is in the state hash and our own process hash.
2600 * We definitely can draw the items related to the ending state.
2603 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2606 TimeWindow time_window
=
2607 lttvwindow_get_time_window(control_flow_data
->tab
);
2610 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2611 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2613 #endif //EXTRA_CHECK
2614 Drawing_t
*drawing
= control_flow_data
->drawing
;
2615 guint width
= drawing
->width
;
2617 guint x
= closure_data
->x_end
;
2619 DrawContext draw_context
;
2621 /* Now create the drawing context that will be used to draw
2622 * items related to the last state. */
2623 draw_context
.drawable
= hashed_process_data
->pixmap
;
2624 draw_context
.gc
= drawing
->gc
;
2625 draw_context
.pango_layout
= drawing
->pango_layout
;
2626 draw_context
.drawinfo
.end
.x
= x
;
2628 draw_context
.drawinfo
.y
.over
= 1;
2629 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2630 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2632 draw_context
.drawinfo
.start
.offset
.over
= 0;
2633 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2634 draw_context
.drawinfo
.start
.offset
.under
= 0;
2635 draw_context
.drawinfo
.end
.offset
.over
= 0;
2636 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2637 draw_context
.drawinfo
.end
.offset
.under
= 0;
2639 /* Jump over draw if we are at the same x position */
2640 if(x
== hashed_process_data
->x
.over
)
2644 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2646 PropertiesLine prop_line
= prepare_execmode_line(process
);
2647 draw_line((void*)&prop_line
, (void*)&draw_context
);
2649 hashed_process_data
->x
.over
= x
;
2653 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2654 hashed_process_data
->x
.middle_used
)) {
2655 #if 0 /* do not mark closure : not missing information */
2656 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2657 /* Draw collision indicator */
2658 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2659 gdk_draw_point(drawing
->pixmap
,
2663 hashed_process_data
->x
.middle_marked
= TRUE
;
2668 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2671 PropertiesLine prop_line
= prepare_s_e_line(process
);
2672 draw_line((void*)&prop_line
, (void*)&draw_context
);
2675 /* become the last x position */
2676 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2677 hashed_process_data
->x
.middle
= x
;
2678 /* but don't use the pixel */
2679 hashed_process_data
->x
.middle_used
= FALSE
;
2681 /* Calculate the next good time */
2682 convert_pixels_to_time(width
, x
+1, time_window
,
2683 &hashed_process_data
->next_good_time
);
2692 int before_chunk(void *hook_data
, void *call_data
)
2695 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2696 LttvTraceset
*ts
= (LttvTraceset
*)call_data
;
2698 /* Desactivate sort */
2699 gtk_tree_sortable_set_sort_column_id(
2700 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2702 GTK_SORT_ASCENDING
);
2704 drawing_chunk_begin(events_request
, ts
);
2709 int before_request(void *hook_data
, void *call_data
)
2712 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2714 drawing_data_request_begin(events_request
);
2722 * after request is necessary in addition of after chunk in order to draw
2723 * lines until the end of the screen. after chunk just draws lines until
2730 int after_request(void *hook_data
, void *call_data
)
2733 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2734 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2736 ProcessList
*process_list
= control_flow_data
->process_list
;
2737 LttTime end_time
= events_request
->end_time
;
2739 ClosureData closure_data
;
2740 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2741 closure_data
.end_time
= end_time
;
2743 TimeWindow time_window
=
2744 lttvwindow_get_time_window(control_flow_data
->tab
);
2745 guint width
= control_flow_data
->drawing
->width
;
2746 convert_time_to_pixels(
2750 &closure_data
.x_end
);
2753 /* Draw last items */
2754 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2755 (void*)&closure_data
);
2758 /* Request expose */
2759 drawing_request_expose(events_request
, end_time
);
2768 int after_chunk(void *hook_data
, void *call_data
)
2771 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2772 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2773 LttvTraceset
*ts
= (LttvTraceset
*)call_data
;
2777 ProcessList
*process_list
= control_flow_data
->process_list
;
2779 guint nb_trace
= lttv_traceset_number(ts
);
2781 /* Only execute when called for the first trace's events request */
2782 if(!process_list
->current_hash_data
)
2785 for(i
= 0 ; i
< nb_trace
; i
++) {
2786 g_free(process_list
->current_hash_data
[i
]);
2788 g_free(process_list
->current_hash_data
);
2789 process_list
->current_hash_data
= NULL
;
2791 end_time
= events_request
->end_time
;
2793 ClosureData closure_data
;
2794 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2795 closure_data
.end_time
= end_time
;
2797 TimeWindow time_window
=
2798 lttvwindow_get_time_window(control_flow_data
->tab
);
2799 guint width
= control_flow_data
->drawing
->width
;
2800 convert_time_to_pixels(
2804 &closure_data
.x_end
);
2806 /* Draw last items */
2807 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2808 (void*)&closure_data
);
2810 /* Reactivate sort */
2811 gtk_tree_sortable_set_sort_column_id(
2812 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2813 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2814 GTK_SORT_ASCENDING
);
2816 update_index_to_pixmap(control_flow_data
->process_list
);
2817 /* Request a full expose : drawing scrambled */
2818 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2820 /* Request expose (updates damages zone also) */
2822 drawing_request_expose(events_request
, end_time
);
2826 /* after_statedump_end
2828 * @param hook_data ControlFlowData structure of the viewer.
2829 * @param call_data Event context.
2831 * This function adds items to be drawn in a queue for each process.
2834 int before_statedump_end(void *hook_data
, void *call_data
)
2838 event
= (LttvEvent
*) call_data
;
2840 if (strcmp(lttv_traceset_get_name_from_event(event
),"lttng_statedump_end") != 0)
2843 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2846 LttvTraceState
*ts
= event
->state
;
2849 ProcessList
*process_list
= control_flow_data
->process_list
;
2851 #ifdef BABEL_CLEANUP
2852 LttvFilter
*filter
= control_flow_data
->filter
;
2853 if(filter
!= NULL
&& filter
->head
!= NULL
)
2854 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2855 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2859 LttTime evtime
= lttv_event_get_timestamp(event
);
2860 #ifdef BABEL_CLEANUP
2861 ClosureData closure_data
;
2862 closure_data
.events_request
= events_request
;
2863 closure_data
.tss
= tss
;
2864 closure_data
.end_time
= evtime
;
2866 TimeWindow time_window
=
2867 lttvwindow_get_time_window(control_flow_data
->tab
);
2868 guint width
= control_flow_data
->drawing
->width
;
2869 convert_time_to_pixels(
2873 &closure_data
.x_end
);
2875 /* Draw last items */
2876 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2877 (void*)&closure_data
);
2880 /* Reactivate sort */
2881 gtk_tree_sortable_set_sort_column_id(
2882 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2883 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2884 GTK_SORT_ASCENDING
);
2886 update_index_to_pixmap(control_flow_data
->process_list
);
2887 /* Request a full expose : drawing scrambled */
2888 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2890 /* Request expose (updates damages zone also) */
2891 drawing_request_expose(events_request
, tss
, evtime
);