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
)
291 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
292 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
294 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
296 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
298 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
300 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
301 gint target_pid_saved
= tfc
->target_pid
;
303 LttTime evtime
= ltt_event_time(e
);
304 LttvFilter
*filter
= control_flow_data
->filter
;
309 woken_pid
= ltt_event_get_int(e
, lttv_trace_get_hook_field(th
, 0));
310 woken_cpu
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
312 tfc
->target_pid
= woken_pid
;
313 if(!filter
|| !filter
->head
||
314 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
315 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
317 /* First, check if the woken process is in the state computation
318 * process list. If it is there, that means we must add it right now and
319 * draw items from the beginning of the read for it. If it is not
320 * present, it's a new process and it was not present : it will
321 * be added after the state update. TOCHECK: What does that last para mean? */
322 guint trace_num
= ts
->parent
.index
;
323 LttvProcessState
*process
= lttv_state_find_process(ts
, woken_cpu
, woken_pid
);
325 if(process
!= NULL
) {
326 /* Well, the woken process existed : we must get it in the process hash
327 * or add it, and draw its items.
329 /* Add process to process list (if not present) */
331 HashedProcessData
*hashed_process_data
= NULL
;
332 ProcessList
*process_list
= control_flow_data
->process_list
;
333 LttTime birth
= process
->creation_time
;
335 hashed_process_data
= processlist_get_process_data(process_list
,
340 if(hashed_process_data
== NULL
)
342 g_assert(woken_pid
!= process
->ppid
);
343 /* Process not present */
344 ProcessInfo
*process_info
;
345 Drawing_t
*drawing
= control_flow_data
->drawing
;
346 processlist_add(process_list
,
358 &hashed_process_data
);
359 gtk_widget_set_size_request(drawing
->drawing_area
,
362 gtk_widget_queue_draw(drawing
->drawing_area
);
366 /* Now, the process is in the state hash and our own process hash.
367 * We definitely can draw the items related to the ending state.
370 if(ltt_time_compare(hashed_process_data
->next_good_time
,
373 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
375 TimeWindow time_window
=
376 lttvwindow_get_time_window(control_flow_data
->tab
);
378 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
379 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
382 Drawing_t
*drawing
= control_flow_data
->drawing
;
383 guint width
= drawing
->width
;
385 convert_time_to_pixels(
391 /* Draw collision indicator */
392 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
393 gdk_draw_point(hashed_process_data
->pixmap
,
396 COLLISION_POSITION(hashed_process_data
->height
));
397 hashed_process_data
->x
.middle_marked
= TRUE
;
400 TimeWindow time_window
=
401 lttvwindow_get_time_window(control_flow_data
->tab
);
403 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
404 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
407 Drawing_t
*drawing
= control_flow_data
->drawing
;
408 guint width
= drawing
->width
;
410 convert_time_to_pixels(
417 /* Jump over draw if we are at the same x position */
418 if(x
== hashed_process_data
->x
.middle
&&
419 hashed_process_data
->x
.middle_used
)
421 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
422 /* Draw collision indicator */
423 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
424 gdk_draw_point(hashed_process_data
->pixmap
,
427 COLLISION_POSITION(hashed_process_data
->height
));
428 hashed_process_data
->x
.middle_marked
= TRUE
;
432 DrawContext draw_context
;
434 /* Now create the drawing context that will be used to draw
435 * items related to the last state. */
436 draw_context
.drawable
= hashed_process_data
->pixmap
;
437 draw_context
.gc
= drawing
->gc
;
438 draw_context
.pango_layout
= drawing
->pango_layout
;
439 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
440 draw_context
.drawinfo
.end
.x
= x
;
442 draw_context
.drawinfo
.y
.over
= 1;
443 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
444 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
446 draw_context
.drawinfo
.start
.offset
.over
= 0;
447 draw_context
.drawinfo
.start
.offset
.middle
= 0;
448 draw_context
.drawinfo
.start
.offset
.under
= 0;
449 draw_context
.drawinfo
.end
.offset
.over
= 0;
450 draw_context
.drawinfo
.end
.offset
.middle
= 0;
451 draw_context
.drawinfo
.end
.offset
.under
= 0;
455 PropertiesLine prop_line
= prepare_s_e_line(process
);
456 draw_line((void*)&prop_line
, (void*)&draw_context
);
459 /* become the last x position */
460 hashed_process_data
->x
.middle
= x
;
461 hashed_process_data
->x
.middle_used
= TRUE
;
462 hashed_process_data
->x
.middle_marked
= FALSE
;
464 /* Calculate the next good time */
465 convert_pixels_to_time(width
, x
+1, time_window
,
466 &hashed_process_data
->next_good_time
);
472 tfc
->target_pid
= target_pid_saved
;
474 #endif //babel_cleanup
479 /* before_schedchange_hook
481 * This function basically draw lines and icons. Two types of lines are drawn :
482 * one small (3 pixels?) representing the state of the process and the second
483 * type is thicker (10 pixels?) representing on which CPU a process is running
484 * (and this only in running state).
486 * Extremums of the lines :
487 * x_min : time of the last event context for this process kept in memory.
488 * x_max : time of the current event.
489 * y : middle of the process in the process list. The process is found in the
490 * list, therefore is it's position in pixels.
492 * The choice of lines'color is defined by the context of the last event for this
497 int before_schedchange_hook(void *hook_data
, void *call_data
)
502 LttvProcessState
*process
;
504 //LttvProcessState *old_process = ts->running_process[cpu];
506 guint pid_in
, pid_out
;
509 event
= (LttvEvent
*) call_data
;
510 if (strcmp(lttv_traceset_get_name_from_event(event
),"sched_switch") != 0)
513 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
516 /* we are in a schedchange, before the state update. We must draw the
517 * items corresponding to the state before it changes : now is the right
520 cpu
= lttv_traceset_get_cpuid_from_event(event
);
523 pid_out
= lttv_event_get_long(event
, "prev_tid");
524 pid_in
= lttv_event_get_long(event
, "next_tid");
525 state_out
= lttv_event_get_long(event
, "prev_state");
526 guint trace_number
= 0;//TODO fdeslauriers 2012-07-17: // Use trace handle to know trace number
528 process
= lttv_state_find_process(ts
,cpu
,pid_out
);
529 timestamp
= lttv_event_get_timestamp(event
);
530 /* For the pid_out */
531 /* First, check if the current process is in the state computation
532 * process list. If it is there, that means we must add it right now and
533 * draw items from the beginning of the read for it. If it is not
534 * present, it's a new process and it was not present : it will
535 * be added after the state update. */
537 /* unknown state, bad current pid */
539 if(process
!= NULL
) {
540 /* Well, the process_out existed : we must get it in the process hash
541 * or add it, and draw its items.
543 /* Add process to process list (if not present) */
545 HashedProcessData
*hashed_process_data
= NULL
;
546 ProcessList
*process_list
= control_flow_data
->process_list
;
547 LttTime birth
= process
->creation_time
;
549 hashed_process_data
= processlist_get_process_data(process_list
,
554 if(hashed_process_data
== NULL
)
556 g_assert(pid_out
== 0 || pid_out
!= process
->ppid
);
557 /* Process not present */
558 ProcessInfo
*process_info
;
559 Drawing_t
*drawing
= control_flow_data
->drawing
;
560 processlist_add(process_list
,
572 &hashed_process_data
);
573 gtk_widget_set_size_request(drawing
->drawing_area
,
576 gtk_widget_queue_draw(drawing
->drawing_area
);
579 /* Now, the process is in the state hash and our own process hash.
580 * We definitely can draw the items related to the ending state.
583 if(ltt_time_compare(hashed_process_data
->next_good_time
,
586 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
588 TimeWindow time_window
=
589 lttvwindow_get_time_window(control_flow_data
->tab
);
591 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
592 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
595 Drawing_t
*drawing
= control_flow_data
->drawing
;
596 guint width
= drawing
->width
;
598 convert_time_to_pixels(
604 /* Draw collision indicator */
605 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
606 gdk_draw_point(hashed_process_data
->pixmap
,
609 COLLISION_POSITION(hashed_process_data
->height
));
610 hashed_process_data
->x
.middle_marked
= TRUE
;
613 TimeWindow time_window
=
614 lttvwindow_get_time_window(control_flow_data
->tab
);
616 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
617 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
620 Drawing_t
*drawing
= control_flow_data
->drawing
;
621 guint width
= drawing
->width
;
623 convert_time_to_pixels(
630 /* Jump over draw if we are at the same x position */
631 if(x
== hashed_process_data
->x
.middle
&&
632 hashed_process_data
->x
.middle_used
)
634 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
635 /* Draw collision indicator */
636 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
637 gdk_draw_point(hashed_process_data
->pixmap
,
640 COLLISION_POSITION(hashed_process_data
->height
));
641 hashed_process_data
->x
.middle_marked
= TRUE
;
645 DrawContext draw_context
;
647 /* Now create the drawing context that will be used to draw
648 * items related to the last state. */
649 draw_context
.drawable
= hashed_process_data
->pixmap
;
650 draw_context
.gc
= drawing
->gc
;
651 draw_context
.pango_layout
= drawing
->pango_layout
;
652 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
653 draw_context
.drawinfo
.end
.x
= x
;
655 draw_context
.drawinfo
.y
.over
= 1;
656 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
657 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
659 draw_context
.drawinfo
.start
.offset
.over
= 0;
660 draw_context
.drawinfo
.start
.offset
.middle
= 0;
661 draw_context
.drawinfo
.start
.offset
.under
= 0;
662 draw_context
.drawinfo
.end
.offset
.over
= 0;
663 draw_context
.drawinfo
.end
.offset
.middle
= 0;
664 draw_context
.drawinfo
.end
.offset
.under
= 0;
668 PropertiesLine prop_line
= prepare_s_e_line(process
);
669 draw_line((void*)&prop_line
, (void*)&draw_context
);
672 /* become the last x position */
673 hashed_process_data
->x
.middle
= x
;
674 hashed_process_data
->x
.middle_used
= TRUE
;
675 hashed_process_data
->x
.middle_marked
= FALSE
;
677 /* Calculate the next good time */
678 convert_pixels_to_time(width
, x
+1, time_window
,
679 &hashed_process_data
->next_good_time
);
685 /* First, check if the current process is in the state computation
686 * process list. If it is there, that means we must add it right now and
687 * draw items from the beginning of the read for it. If it is not
688 * present, it's a new process and it was not present : it will
689 * be added after the state update. */
690 process
= lttv_state_find_process(ts
,cpu
,pid_in
);
692 if(process
!= NULL
) {
693 /* Well, the process existed : we must get it in the process hash
694 * or add it, and draw its items.
696 /* Add process to process list (if not present) */
698 HashedProcessData
*hashed_process_data
= NULL
;
699 ProcessList
*process_list
= control_flow_data
->process_list
;
700 LttTime birth
= process
->creation_time
;
702 hashed_process_data
= processlist_get_process_data(process_list
,
706 trace_number
);//TODO "use the right value or delete"
707 if(hashed_process_data
== NULL
)
709 g_assert(pid_in
== 0 || pid_in
!= process
->ppid
);
710 /* Process not present */
711 ProcessInfo
*process_info
;
712 Drawing_t
*drawing
= control_flow_data
->drawing
;
713 processlist_add(process_list
,
725 &hashed_process_data
);
726 gtk_widget_set_size_request(drawing
->drawing_area
,
729 gtk_widget_queue_draw(drawing
->drawing_area
);
732 //We could set the current process and hash here, but will be done
733 //by after schedchange hook
735 /* Now, the process is in the state hash and our own process hash.
736 * We definitely can draw the items related to the ending state.
739 if(ltt_time_compare(hashed_process_data
->next_good_time
,
742 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
744 TimeWindow time_window
=
745 lttvwindow_get_time_window(control_flow_data
->tab
);
747 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
748 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
751 Drawing_t
*drawing
= control_flow_data
->drawing
;
752 guint width
= drawing
->width
;
754 convert_time_to_pixels(
760 /* Draw collision indicator */
761 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
762 gdk_draw_point(hashed_process_data
->pixmap
,
765 COLLISION_POSITION(hashed_process_data
->height
));
766 hashed_process_data
->x
.middle_marked
= TRUE
;
769 TimeWindow time_window
=
770 lttvwindow_get_time_window(control_flow_data
->tab
);
772 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
773 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
776 Drawing_t
*drawing
= control_flow_data
->drawing
;
777 guint width
= drawing
->width
;
780 convert_time_to_pixels(
787 /* Jump over draw if we are at the same x position */
788 if(x
== hashed_process_data
->x
.middle
&&
789 hashed_process_data
->x
.middle_used
)
791 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
792 /* Draw collision indicator */
793 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
794 gdk_draw_point(hashed_process_data
->pixmap
,
797 COLLISION_POSITION(hashed_process_data
->height
));
798 hashed_process_data
->x
.middle_marked
= TRUE
;
802 DrawContext draw_context
;
804 /* Now create the drawing context that will be used to draw
805 * items related to the last state. */
806 draw_context
.drawable
= hashed_process_data
->pixmap
;
807 draw_context
.gc
= drawing
->gc
;
808 draw_context
.pango_layout
= drawing
->pango_layout
;
809 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
810 draw_context
.drawinfo
.end
.x
= x
;
812 draw_context
.drawinfo
.y
.over
= 1;
813 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
814 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
816 draw_context
.drawinfo
.start
.offset
.over
= 0;
817 draw_context
.drawinfo
.start
.offset
.middle
= 0;
818 draw_context
.drawinfo
.start
.offset
.under
= 0;
819 draw_context
.drawinfo
.end
.offset
.over
= 0;
820 draw_context
.drawinfo
.end
.offset
.middle
= 0;
821 draw_context
.drawinfo
.end
.offset
.under
= 0;
825 PropertiesLine prop_line
= prepare_s_e_line(process
);
826 draw_line((void*)&prop_line
, (void*)&draw_context
);
830 /* become the last x position */
831 hashed_process_data
->x
.middle
= x
;
832 hashed_process_data
->x
.middle_used
= TRUE
;
833 hashed_process_data
->x
.middle_marked
= FALSE
;
835 /* Calculate the next good time */
836 convert_pixels_to_time(width
, x
+1, time_window
,
837 &hashed_process_data
->next_good_time
);
841 g_warning("Cannot find pin_in in schedchange %u", pid_in
);
843 tfc
->target_pid
= target_pid_saved
;
844 #endif //babel_cleanup
852 GString
*string
= g_string_new("");;
853 gboolean field_names
= TRUE
, state
= TRUE
;
855 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
856 g_string_append_printf(string
,"\n");
859 g_string_append_printf(string
, " %s",
860 g_quark_to_string(tfs
->process
->state
->s
));
863 g_info("%s",string
->str
);
865 g_string_free(string
, TRUE
);
867 /* End of text dump */
872 /* after_schedchange_hook
874 * The draw after hook is called by the reading API to have a
875 * particular event drawn on the screen.
876 * @param hook_data ControlFlowData structure of the viewer.
877 * @param call_data Event context.
879 * This function adds items to be drawn in a queue for each process.
882 int after_schedchange_hook(void *hook_data
, void *call_data
)
885 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
886 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
887 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
889 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
891 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
893 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
896 e
= ltt_tracefile_get_event(tfc
->tf
);
898 LttvFilter
*filter
= control_flow_data
->filter
;
899 LttTime evtime
= ltt_event_time(e
);
901 /* Add process to process list (if not present) */
902 LttvProcessState
*process_in
;
905 HashedProcessData
*hashed_process_data_in
= NULL
;
907 ProcessList
*process_list
= control_flow_data
->process_list
;
911 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
914 tfc
->target_pid
= pid_in
;
915 if(!filter
|| !filter
->head
||
916 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
917 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
918 /* Find process pid_in in the list... */
919 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
920 //process_in = tfs->process;
921 guint cpu
= tfs
->cpu
;
922 guint trace_num
= ts
->parent
.index
;
923 process_in
= ts
->running_process
[cpu
];
924 /* It should exist, because we are after the state update. */
926 g_assert(process_in
!= NULL
);
928 birth
= process_in
->creation_time
;
930 hashed_process_data_in
= processlist_get_process_data(process_list
,
935 if(hashed_process_data_in
== NULL
)
937 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
938 ProcessInfo
*process_info
;
939 Drawing_t
*drawing
= control_flow_data
->drawing
;
940 /* Process not present */
941 processlist_add(process_list
,
953 &hashed_process_data_in
);
954 gtk_widget_set_size_request(drawing
->drawing_area
,
957 gtk_widget_queue_draw(drawing
->drawing_area
);
959 /* Set the current process */
960 process_list
->current_hash_data
[trace_num
][process_in
->cpu
] =
961 hashed_process_data_in
;
963 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
966 TimeWindow time_window
=
967 lttvwindow_get_time_window(control_flow_data
->tab
);
970 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
971 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
974 Drawing_t
*drawing
= control_flow_data
->drawing
;
975 guint width
= drawing
->width
;
978 convert_time_to_pixels(
984 if(hashed_process_data_in
->x
.middle
!= new_x
) {
985 hashed_process_data_in
->x
.middle
= new_x
;
986 hashed_process_data_in
->x
.middle_used
= FALSE
;
987 hashed_process_data_in
->x
.middle_marked
= FALSE
;
992 #endif //babel_cleanup
999 /* before_execmode_hook
1001 * This function basically draw lines and icons. Two types of lines are drawn :
1002 * one small (3 pixels?) representing the state of the process and the second
1003 * type is thicker (10 pixels?) representing on which CPU a process is running
1004 * (and this only in running state).
1006 * Extremums of the lines :
1007 * x_min : time of the last event context for this process kept in memory.
1008 * x_max : time of the current event.
1009 * y : middle of the process in the process list. The process is found in the
1010 * list, therefore is it's position in pixels.
1012 * The choice of lines'color is defined by the context of the last event for this
1017 int before_execmode_hook(void *hook_data
, void *call_data
)
1023 LttvProcessState
*process
;
1025 /* we are in a execmode, before the state update. We must draw the
1026 * items corresponding to the state before it changes : now is the right
1030 event
= (LttvEvent
*) call_data
;
1031 if ((strncmp(lttv_traceset_get_name_from_event(event
),"sys_", sizeof("sys_") - 1) == 0)
1032 ||(strcmp(lttv_traceset_get_name_from_event(event
),"exit_syscall") == 0)
1033 ||(strncmp(lttv_traceset_get_name_from_event(event
),"irq_handler_",sizeof("irq_handler_")) == 0)
1034 ||(strncmp(lttv_traceset_get_name_from_event(event
),"softirq_", sizeof("softirq_")) == 0)){
1036 LttTime evtime
= lttv_event_get_timestamp(event
);
1037 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
1039 LttvTraceset
*traceSet
= lttvwindow_get_traceset(control_flow_data
->tab
);
1041 cpu
= lttv_traceset_get_cpuid_from_event(event
);
1044 guint trace_number
= 0;//TODO fdeslauriers 2012-07-17: // Use trace handle to know trace number
1045 process
= lttv_state_find_process(ts
,cpu
,pid
);
1046 g_assert(process
!= NULL
);
1048 guint pid
= process
->pid
;
1050 /* Well, the process_out existed : we must get it in the process hash
1051 * or add it, and draw its items.
1053 /* Add process to process list (if not present) */
1054 guint pl_height
= 0;
1055 HashedProcessData
*hashed_process_data
= NULL
;
1056 ProcessList
*process_list
= control_flow_data
->process_list
;
1057 if(process_list
->current_hash_data
== NULL
){//TODO fdeslauriers 2012-07-17 : should not be necessary
1061 LttTime birth
= process
->creation_time
;
1063 if(likely(process_list
->current_hash_data
[trace_number
][cpu
] != NULL
)) {
1064 hashed_process_data
= process_list
->current_hash_data
[trace_number
][cpu
];
1066 hashed_process_data
= processlist_get_process_data(process_list
,
1071 if(unlikely(hashed_process_data
== NULL
))
1073 g_assert(pid
== 0 || pid
!= process
->ppid
);
1074 ProcessInfo
*process_info
;
1075 /* Process not present */
1076 Drawing_t
*drawing
= control_flow_data
->drawing
;
1077 processlist_add(process_list
,
1089 &hashed_process_data
);
1090 gtk_widget_set_size_request(drawing
->drawing_area
,
1093 gtk_widget_queue_draw(drawing
->drawing_area
);
1095 /* Set the current process */
1096 process_list
->current_hash_data
[trace_number
][process
->cpu
] =
1097 hashed_process_data
;
1100 /* Now, the process is in the state hash and our own process hash.
1101 * We definitely can draw the items related to the ending state.
1104 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1107 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1108 TimeWindow time_window
=
1109 lttvwindow_get_time_window(control_flow_data
->tab
);
1112 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1113 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1115 #endif //EXTRA_CHECK
1116 Drawing_t
*drawing
= control_flow_data
->drawing
;
1117 guint width
= drawing
->width
;
1119 convert_time_to_pixels(
1125 /* Draw collision indicator */
1126 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1127 gdk_draw_point(hashed_process_data
->pixmap
,
1130 COLLISION_POSITION(hashed_process_data
->height
));
1131 hashed_process_data
->x
.middle_marked
= TRUE
;
1134 TimeWindow time_window
=
1135 lttvwindow_get_time_window(control_flow_data
->tab
);
1138 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1139 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1141 #endif //EXTRA_CHECK
1142 Drawing_t
*drawing
= control_flow_data
->drawing
;
1143 guint width
= drawing
->width
;
1146 convert_time_to_pixels(
1153 /* Jump over draw if we are at the same x position */
1154 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1155 hashed_process_data
->x
.middle_used
))
1157 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1158 /* Draw collision indicator */
1159 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1160 gdk_draw_point(hashed_process_data
->pixmap
,
1163 COLLISION_POSITION(hashed_process_data
->height
));
1164 hashed_process_data
->x
.middle_marked
= TRUE
;
1169 DrawContext draw_context
;
1170 /* Now create the drawing context that will be used to draw
1171 * items related to the last state. */
1172 draw_context
.drawable
= hashed_process_data
->pixmap
;
1173 draw_context
.gc
= drawing
->gc
;
1174 draw_context
.pango_layout
= drawing
->pango_layout
;
1175 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1176 draw_context
.drawinfo
.end
.x
= x
;
1178 draw_context
.drawinfo
.y
.over
= 1;
1179 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1180 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1182 draw_context
.drawinfo
.start
.offset
.over
= 0;
1183 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1184 draw_context
.drawinfo
.start
.offset
.under
= 0;
1185 draw_context
.drawinfo
.end
.offset
.over
= 0;
1186 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1187 draw_context
.drawinfo
.end
.offset
.under
= 0;
1191 PropertiesLine prop_line
= prepare_s_e_line(process
);
1192 draw_line((void*)&prop_line
, (void*)&draw_context
);
1195 /* become the last x position */
1196 hashed_process_data
->x
.middle
= x
;
1197 hashed_process_data
->x
.middle_used
= TRUE
;
1198 hashed_process_data
->x
.middle_marked
= FALSE
;
1200 /* Calculate the next good time */
1201 convert_pixels_to_time(width
, x
+1, time_window
,
1202 &hashed_process_data
->next_good_time
);
1209 /* before_process_exit_hook
1211 * Draw lines for process event.
1213 * @param hook_data ControlFlowData structure of the viewer.
1214 * @param call_data Event context.
1216 * This function adds items to be drawn in a queue for each process.
1221 int before_process_exit_hook(void *hook_data
, void *call_data
)
1223 #ifdef BABEL_CLEANUP
1224 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1225 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1227 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1229 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1231 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1233 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1236 e
= ltt_tracefile_get_event(tfc
->tf
);
1238 LttvFilter
*filter
= control_flow_data
->filter
;
1239 if(filter
!= NULL
&& filter
->head
!= NULL
)
1240 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1241 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1244 LttTime evtime
= ltt_event_time(e
);
1246 /* Add process to process list (if not present) */
1247 //LttvProcessState *process = tfs->process;
1248 guint cpu
= tfs
->cpu
;
1249 guint trace_num
= ts
->parent
.index
;
1250 LttvProcessState
*process
= ts
->running_process
[cpu
];
1251 guint pid
= process
->pid
;
1253 guint pl_height
= 0;
1254 HashedProcessData
*hashed_process_data
= NULL
;
1256 ProcessList
*process_list
= control_flow_data
->process_list
;
1258 g_assert(process
!= NULL
);
1260 birth
= process
->creation_time
;
1262 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1263 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1265 hashed_process_data
= processlist_get_process_data(process_list
,
1270 if(unlikely(hashed_process_data
== NULL
))
1272 g_assert(pid
== 0 || pid
!= process
->ppid
);
1273 /* Process not present */
1274 Drawing_t
*drawing
= control_flow_data
->drawing
;
1275 ProcessInfo
*process_info
;
1276 processlist_add(process_list
,
1288 &hashed_process_data
);
1289 gtk_widget_set_size_request(drawing
->drawing_area
,
1292 gtk_widget_queue_draw(drawing
->drawing_area
);
1296 /* Now, the process is in the state hash and our own process hash.
1297 * We definitely can draw the items related to the ending state.
1300 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1303 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1304 TimeWindow time_window
=
1305 lttvwindow_get_time_window(control_flow_data
->tab
);
1308 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1309 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1311 #endif //EXTRA_CHECK
1312 Drawing_t
*drawing
= control_flow_data
->drawing
;
1313 guint width
= drawing
->width
;
1315 convert_time_to_pixels(
1321 /* Draw collision indicator */
1322 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1323 gdk_draw_point(hashed_process_data
->pixmap
,
1326 COLLISION_POSITION(hashed_process_data
->height
));
1327 hashed_process_data
->x
.middle_marked
= TRUE
;
1330 TimeWindow time_window
=
1331 lttvwindow_get_time_window(control_flow_data
->tab
);
1334 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1335 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1337 #endif //EXTRA_CHECK
1338 Drawing_t
*drawing
= control_flow_data
->drawing
;
1339 guint width
= drawing
->width
;
1342 convert_time_to_pixels(
1349 /* Jump over draw if we are at the same x position */
1350 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1351 hashed_process_data
->x
.middle_used
))
1353 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1354 /* Draw collision indicator */
1355 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1356 gdk_draw_point(hashed_process_data
->pixmap
,
1359 COLLISION_POSITION(hashed_process_data
->height
));
1360 hashed_process_data
->x
.middle_marked
= TRUE
;
1364 DrawContext draw_context
;
1366 /* Now create the drawing context that will be used to draw
1367 * items related to the last state. */
1368 draw_context
.drawable
= hashed_process_data
->pixmap
;
1369 draw_context
.gc
= drawing
->gc
;
1370 draw_context
.pango_layout
= drawing
->pango_layout
;
1371 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1372 draw_context
.drawinfo
.end
.x
= x
;
1374 draw_context
.drawinfo
.y
.over
= 1;
1375 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1376 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1378 draw_context
.drawinfo
.start
.offset
.over
= 0;
1379 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1380 draw_context
.drawinfo
.start
.offset
.under
= 0;
1381 draw_context
.drawinfo
.end
.offset
.over
= 0;
1382 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1383 draw_context
.drawinfo
.end
.offset
.under
= 0;
1387 PropertiesLine prop_line
= prepare_s_e_line(process
);
1388 draw_line((void*)&prop_line
, (void*)&draw_context
);
1391 /* become the last x position */
1392 hashed_process_data
->x
.middle
= x
;
1393 hashed_process_data
->x
.middle_used
= TRUE
;
1394 hashed_process_data
->x
.middle_marked
= FALSE
;
1396 /* Calculate the next good time */
1397 convert_pixels_to_time(width
, x
+1, time_window
,
1398 &hashed_process_data
->next_good_time
);
1402 #endif //babel_cleanup
1409 /* before_process_release_hook
1411 * Draw lines for process event.
1413 * @param hook_data ControlFlowData structure of the viewer.
1414 * @param call_data Event context.
1416 * This function adds items to be drawn in a queue for each process.
1421 int before_process_release_hook(void *hook_data
, void *call_data
)
1423 #ifdef BABEL_CLEANUP
1424 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1425 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1427 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1429 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1431 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1434 e
= ltt_tracefile_get_event(tfc
->tf
);
1436 LttvFilter
*filter
= control_flow_data
->filter
;
1437 if(filter
!= NULL
&& filter
->head
!= NULL
)
1438 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1439 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1442 LttTime evtime
= ltt_event_time(e
);
1444 guint trace_num
= ts
->parent
.index
;
1448 pid
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
1451 /* Add process to process list (if not present) */
1452 /* Don't care about the process if it's not in the state hash already :
1453 * that means a process that has never done anything in the trace and
1454 * unknown suddently gets destroyed : no state meaningful to show. */
1455 LttvProcessState
*process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1457 if(process
!= NULL
) {
1459 HashedProcessData
*hashed_process_data
= NULL
;
1461 ProcessList
*process_list
= control_flow_data
->process_list
;
1463 birth
= process
->creation_time
;
1465 /* Cannot use current process : this event happens on another process,
1466 * action done by the parent. */
1467 hashed_process_data
= processlist_get_process_data(process_list
,
1472 if(unlikely(hashed_process_data
== NULL
))
1474 * Process already been scheduled out EXIT_DEAD, not in the process list
1475 * anymore. Just return.
1479 /* Now, the process is in the state hash and our own process hash.
1480 * We definitely can draw the items related to the ending state.
1483 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1486 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1487 TimeWindow time_window
=
1488 lttvwindow_get_time_window(control_flow_data
->tab
);
1491 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1492 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1494 #endif //EXTRA_CHECK
1495 Drawing_t
*drawing
= control_flow_data
->drawing
;
1496 guint width
= drawing
->width
;
1498 convert_time_to_pixels(
1504 /* Draw collision indicator */
1505 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1506 gdk_draw_point(hashed_process_data
->pixmap
,
1509 COLLISION_POSITION(hashed_process_data
->height
));
1510 hashed_process_data
->x
.middle_marked
= TRUE
;
1513 TimeWindow time_window
=
1514 lttvwindow_get_time_window(control_flow_data
->tab
);
1517 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1518 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1520 #endif //EXTRA_CHECK
1521 Drawing_t
*drawing
= control_flow_data
->drawing
;
1522 guint width
= drawing
->width
;
1525 convert_time_to_pixels(
1532 /* Jump over draw if we are at the same x position */
1533 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1534 hashed_process_data
->x
.middle_used
))
1536 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1537 /* Draw collision indicator */
1538 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1539 gdk_draw_point(hashed_process_data
->pixmap
,
1542 COLLISION_POSITION(hashed_process_data
->height
));
1543 hashed_process_data
->x
.middle_marked
= TRUE
;
1547 DrawContext draw_context
;
1549 /* Now create the drawing context that will be used to draw
1550 * items related to the last state. */
1551 draw_context
.drawable
= hashed_process_data
->pixmap
;
1552 draw_context
.gc
= drawing
->gc
;
1553 draw_context
.pango_layout
= drawing
->pango_layout
;
1554 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1555 draw_context
.drawinfo
.end
.x
= x
;
1557 draw_context
.drawinfo
.y
.over
= 1;
1558 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1559 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1561 draw_context
.drawinfo
.start
.offset
.over
= 0;
1562 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1563 draw_context
.drawinfo
.start
.offset
.under
= 0;
1564 draw_context
.drawinfo
.end
.offset
.over
= 0;
1565 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1566 draw_context
.drawinfo
.end
.offset
.under
= 0;
1570 PropertiesLine prop_line
= prepare_s_e_line(process
);
1571 draw_line((void*)&prop_line
, (void*)&draw_context
);
1574 /* become the last x position */
1575 hashed_process_data
->x
.middle
= x
;
1576 hashed_process_data
->x
.middle_used
= TRUE
;
1577 hashed_process_data
->x
.middle_marked
= FALSE
;
1579 /* Calculate the next good time */
1580 convert_pixels_to_time(width
, x
+1, time_window
,
1581 &hashed_process_data
->next_good_time
);
1586 #endif //babel_cleanup
1594 /* after_process_fork_hook
1596 * Create the processlist entry for the child process. Put the last
1597 * position in x at the current time value.
1599 * @param hook_data ControlFlowData structure of the viewer.
1600 * @param call_data Event context.
1602 * This function adds items to be drawn in a queue for each process.
1605 int after_process_fork_hook(void *hook_data
, void *call_data
)
1607 #ifdef BABEL_CLEANUP
1608 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1609 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1610 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1612 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1614 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1617 e
= ltt_tracefile_get_event(tfc
->tf
);
1619 LttvFilter
*filter
= control_flow_data
->filter
;
1620 if(filter
!= NULL
&& filter
->head
!= NULL
)
1621 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1622 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1625 LttTime evtime
= ltt_event_time(e
);
1629 child_pid
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
1632 /* Add process to process list (if not present) */
1633 LttvProcessState
*process_child
;
1635 guint pl_height
= 0;
1636 HashedProcessData
*hashed_process_data_child
= NULL
;
1638 ProcessList
*process_list
= control_flow_data
->process_list
;
1640 /* Find child in the list... */
1641 process_child
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1642 /* It should exist, because we are after the state update. */
1643 g_assert(process_child
!= NULL
);
1645 birth
= process_child
->creation_time
;
1646 guint trace_num
= ts
->parent
.index
;
1648 /* Cannot use current process, because this action is done by the parent
1650 hashed_process_data_child
= processlist_get_process_data(process_list
,
1655 if(likely(hashed_process_data_child
== NULL
))
1657 g_assert(child_pid
== 0 || child_pid
!= process_child
->ppid
);
1658 /* Process not present */
1659 Drawing_t
*drawing
= control_flow_data
->drawing
;
1660 ProcessInfo
*process_info
;
1661 processlist_add(process_list
,
1664 process_child
->tgid
,
1666 process_child
->ppid
,
1669 process_child
->name
,
1670 process_child
->brand
,
1673 &hashed_process_data_child
);
1674 gtk_widget_set_size_request(drawing
->drawing_area
,
1677 gtk_widget_queue_draw(drawing
->drawing_area
);
1679 processlist_set_ppid(process_list
, process_child
->ppid
,
1680 hashed_process_data_child
);
1681 processlist_set_tgid(process_list
, process_child
->tgid
,
1682 hashed_process_data_child
);
1686 if(likely(ltt_time_compare(hashed_process_data_child
->next_good_time
,
1689 TimeWindow time_window
=
1690 lttvwindow_get_time_window(control_flow_data
->tab
);
1693 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1694 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1696 #endif //EXTRA_CHECK
1697 Drawing_t
*drawing
= control_flow_data
->drawing
;
1698 guint width
= drawing
->width
;
1700 convert_time_to_pixels(
1706 if(likely(hashed_process_data_child
->x
.over
!= new_x
)) {
1707 hashed_process_data_child
->x
.over
= new_x
;
1708 hashed_process_data_child
->x
.over_used
= FALSE
;
1709 hashed_process_data_child
->x
.over_marked
= FALSE
;
1711 if(likely(hashed_process_data_child
->x
.middle
!= new_x
)) {
1712 hashed_process_data_child
->x
.middle
= new_x
;
1713 hashed_process_data_child
->x
.middle_used
= FALSE
;
1714 hashed_process_data_child
->x
.middle_marked
= FALSE
;
1716 if(likely(hashed_process_data_child
->x
.under
!= new_x
)) {
1717 hashed_process_data_child
->x
.under
= new_x
;
1718 hashed_process_data_child
->x
.under_used
= FALSE
;
1719 hashed_process_data_child
->x
.under_marked
= FALSE
;
1722 #endif //babel_cleanup
1728 /* after_process_exit_hook
1730 * Create the processlist entry for the child process. Put the last
1731 * position in x at the current time value.
1733 * @param hook_data ControlFlowData structure of the viewer.
1734 * @param call_data Event context.
1736 * This function adds items to be drawn in a queue for each process.
1739 int after_process_exit_hook(void *hook_data
, void *call_data
)
1741 #ifdef BABEL_CLEANUP
1742 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1743 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1744 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1746 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1748 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1750 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1753 e
= ltt_tracefile_get_event(tfc
->tf
);
1755 LttvFilter
*filter
= control_flow_data
->filter
;
1756 if(filter
!= NULL
&& filter
->head
!= NULL
)
1757 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1758 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1761 LttTime evtime
= ltt_event_time(e
);
1763 /* Add process to process list (if not present) */
1764 //LttvProcessState *process = tfs->process;
1765 guint cpu
= tfs
->cpu
;
1766 guint trace_num
= ts
->parent
.index
;
1767 LttvProcessState
*process
= ts
->running_process
[cpu
];
1769 /* It should exist, because we are after the state update. */
1770 g_assert(process
!= NULL
);
1772 guint pid
= process
->pid
;
1774 guint pl_height
= 0;
1775 HashedProcessData
*hashed_process_data
= NULL
;
1777 ProcessList
*process_list
= control_flow_data
->process_list
;
1779 birth
= process
->creation_time
;
1781 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
) ){
1782 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1784 hashed_process_data
= processlist_get_process_data(process_list
,
1789 if(unlikely(hashed_process_data
== NULL
))
1791 g_assert(pid
== 0 || pid
!= process
->ppid
);
1792 /* Process not present */
1793 Drawing_t
*drawing
= control_flow_data
->drawing
;
1794 ProcessInfo
*process_info
;
1795 processlist_add(process_list
,
1807 &hashed_process_data
);
1808 gtk_widget_set_size_request(drawing
->drawing_area
,
1811 gtk_widget_queue_draw(drawing
->drawing_area
);
1814 /* Set the current process */
1815 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1816 hashed_process_data
;
1819 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
1822 TimeWindow time_window
=
1823 lttvwindow_get_time_window(control_flow_data
->tab
);
1826 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1827 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1829 #endif //EXTRA_CHECK
1830 Drawing_t
*drawing
= control_flow_data
->drawing
;
1831 guint width
= drawing
->width
;
1833 convert_time_to_pixels(
1838 if(unlikely(hashed_process_data
->x
.middle
!= new_x
)) {
1839 hashed_process_data
->x
.middle
= new_x
;
1840 hashed_process_data
->x
.middle_used
= FALSE
;
1841 hashed_process_data
->x
.middle_marked
= FALSE
;
1845 #endif //babel_cleanup
1850 /* Get the filename of the process to print */
1851 int after_fs_exec_hook(void *hook_data
, void *call_data
)
1853 #ifdef BABEL_CLEANUP
1854 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1855 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1856 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1858 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1860 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1862 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1865 e
= ltt_tracefile_get_event(tfc
->tf
);
1867 LttvFilter
*filter
= control_flow_data
->filter
;
1868 if(filter
!= NULL
&& filter
->head
!= NULL
)
1869 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1870 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1873 guint cpu
= tfs
->cpu
;
1874 guint trace_num
= ts
->parent
.index
;
1875 LttvProcessState
*process
= ts
->running_process
[cpu
];
1876 g_assert(process
!= NULL
);
1878 guint pid
= process
->pid
;
1880 /* Well, the process_out existed : we must get it in the process hash
1881 * or add it, and draw its items.
1883 /* Add process to process list (if not present) */
1884 guint pl_height
= 0;
1885 HashedProcessData
*hashed_process_data
= NULL
;
1886 ProcessList
*process_list
= control_flow_data
->process_list
;
1887 LttTime birth
= process
->creation_time
;
1889 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1890 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1892 hashed_process_data
= processlist_get_process_data(process_list
,
1897 if(unlikely(hashed_process_data
== NULL
))
1899 g_assert(pid
== 0 || pid
!= process
->ppid
);
1900 ProcessInfo
*process_info
;
1901 /* Process not present */
1902 Drawing_t
*drawing
= control_flow_data
->drawing
;
1903 processlist_add(process_list
,
1915 &hashed_process_data
);
1916 gtk_widget_set_size_request(drawing
->drawing_area
,
1919 gtk_widget_queue_draw(drawing
->drawing_area
);
1921 /* Set the current process */
1922 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1923 hashed_process_data
;
1926 processlist_set_name(process_list
, process
->name
, hashed_process_data
);
1928 #endif //babel_cleanup
1933 /* Get the filename of the process to print */
1934 int after_user_generic_thread_brand_hook(void *hook_data
, void *call_data
)
1936 #ifdef BABEL_CLEANUP
1937 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1938 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1939 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1941 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1943 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1945 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1948 e
= ltt_tracefile_get_event(tfc
->tf
);
1950 LttvFilter
*filter
= control_flow_data
->filter
;
1951 if(filter
!= NULL
&& filter
->head
!= NULL
)
1952 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1953 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1956 guint cpu
= tfs
->cpu
;
1957 guint trace_num
= ts
->parent
.index
;
1958 LttvProcessState
*process
= ts
->running_process
[cpu
];
1959 g_assert(process
!= NULL
);
1961 guint pid
= process
->pid
;
1963 /* Well, the process_out existed : we must get it in the process hash
1964 * or add it, and draw its items.
1966 /* Add process to process list (if not present) */
1967 guint pl_height
= 0;
1968 HashedProcessData
*hashed_process_data
= NULL
;
1969 ProcessList
*process_list
= control_flow_data
->process_list
;
1970 LttTime birth
= process
->creation_time
;
1972 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1973 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1975 hashed_process_data
= processlist_get_process_data(process_list
,
1980 if(unlikely(hashed_process_data
== NULL
))
1982 g_assert(pid
== 0 || pid
!= process
->ppid
);
1983 ProcessInfo
*process_info
;
1984 /* Process not present */
1985 Drawing_t
*drawing
= control_flow_data
->drawing
;
1986 processlist_add(process_list
,
1998 &hashed_process_data
);
1999 gtk_widget_set_size_request(drawing
->drawing_area
,
2002 gtk_widget_queue_draw(drawing
->drawing_area
);
2004 /* Set the current process */
2005 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
2006 hashed_process_data
;
2009 processlist_set_brand(process_list
, process
->brand
, hashed_process_data
);
2011 #endif //babel_cleanup
2016 /* after_event_enum_process_hook
2018 * Create the processlist entry for the child process. Put the last
2019 * position in x at the current time value.
2021 * @param hook_data ControlFlowData structure of the viewer.
2022 * @param call_data Event context.
2024 * This function adds items to be drawn in a queue for each process.
2027 int after_event_enum_process_hook(void *hook_data
, void *call_data
)
2029 #ifdef BABEL_CLEANUP
2030 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2031 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
2032 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2034 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2036 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
2038 guint first_cpu
, nb_cpus
, cpu
;
2041 e
= ltt_tracefile_get_event(tfc
->tf
);
2043 LttvFilter
*filter
= control_flow_data
->filter
;
2044 if(filter
!= NULL
&& filter
->head
!= NULL
)
2045 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2046 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2049 /* Add process to process list (if not present) */
2050 LttvProcessState
*process_in
;
2052 guint pl_height
= 0;
2053 HashedProcessData
*hashed_process_data_in
= NULL
;
2055 ProcessList
*process_list
= control_flow_data
->process_list
;
2056 guint trace_num
= ts
->parent
.index
;
2060 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2065 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2067 first_cpu
= ANY_CPU
;
2068 nb_cpus
= ANY_CPU
+1;
2071 for(cpu
= first_cpu
; cpu
< nb_cpus
; cpu
++) {
2072 /* Find process pid_in in the list... */
2073 process_in
= lttv_state_find_process(ts
, cpu
, pid_in
);
2074 //process_in = tfs->process;
2075 //guint cpu = tfs->cpu;
2076 //guint trace_num = ts->parent.index;
2077 //process_in = ts->running_process[cpu];
2078 /* It should exist, because we are after the state update. */
2080 //g_assert(process_in != NULL);
2081 #endif //EXTRA_CHECK
2082 birth
= process_in
->creation_time
;
2084 hashed_process_data_in
= processlist_get_process_data(process_list
,
2089 if(hashed_process_data_in
== NULL
)
2091 if(pid_in
!= 0 && pid_in
== process_in
->ppid
)
2092 g_critical("TEST %u , %u", pid_in
, process_in
->ppid
);
2093 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
2094 ProcessInfo
*process_info
;
2095 Drawing_t
*drawing
= control_flow_data
->drawing
;
2096 /* Process not present */
2097 processlist_add(process_list
,
2109 &hashed_process_data_in
);
2110 gtk_widget_set_size_request(drawing
->drawing_area
,
2113 gtk_widget_queue_draw(drawing
->drawing_area
);
2115 processlist_set_name(process_list
, process_in
->name
,
2116 hashed_process_data_in
);
2117 processlist_set_ppid(process_list
, process_in
->ppid
,
2118 hashed_process_data_in
);
2119 processlist_set_tgid(process_list
, process_in
->tgid
,
2120 hashed_process_data_in
);
2123 #endif //babel_cleanup
2128 gint
update_time_window_hook(void *hook_data
, void *call_data
)
2130 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2131 Drawing_t
*drawing
= control_flow_data
->drawing
;
2132 ProcessList
*process_list
= control_flow_data
->process_list
;
2134 const TimeWindowNotifyData
*time_window_nofify_data
=
2135 ((const TimeWindowNotifyData
*)call_data
);
2137 TimeWindow
*old_time_window
=
2138 time_window_nofify_data
->old_time_window
;
2139 TimeWindow
*new_time_window
=
2140 time_window_nofify_data
->new_time_window
;
2142 /* Update the ruler */
2143 drawing_update_ruler(control_flow_data
->drawing
,
2147 /* Two cases : zoom in/out or scrolling */
2149 /* In order to make sure we can reuse the old drawing, the scale must
2150 * be the same and the new time interval being partly located in the
2151 * currently shown time interval. (reuse is only for scrolling)
2154 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
2155 old_time_window
->start_time
.tv_sec
,
2156 old_time_window
->start_time
.tv_nsec
,
2157 old_time_window
->time_width
.tv_sec
,
2158 old_time_window
->time_width
.tv_nsec
);
2160 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
2161 new_time_window
->start_time
.tv_sec
,
2162 new_time_window
->start_time
.tv_nsec
,
2163 new_time_window
->time_width
.tv_sec
,
2164 new_time_window
->time_width
.tv_nsec
);
2166 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
2167 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
2169 /* Same scale (scrolling) */
2170 g_info("scrolling");
2171 LttTime
*ns
= &new_time_window
->start_time
;
2172 LttTime
*os
= &old_time_window
->start_time
;
2173 LttTime old_end
= old_time_window
->end_time
;
2174 LttTime new_end
= new_time_window
->end_time
;
2176 //if(ns<os+w && os+w<ns+w)
2177 //if(ns<old_end && os<ns)
2178 if(ltt_time_compare(*ns
, old_end
) == -1
2179 && ltt_time_compare(*os
, *ns
) == -1)
2181 g_info("scrolling near right");
2182 /* Scroll right, keep right part of the screen */
2184 guint width
= control_flow_data
->drawing
->width
;
2185 convert_time_to_pixels(
2191 /* Copy old data to new location */
2192 copy_pixmap_region(process_list
,
2194 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2198 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
2200 if(drawing
->damage_begin
== drawing
->damage_end
)
2201 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
2203 drawing
->damage_begin
= 0;
2205 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2207 /* Clear the data request background, but not SAFETY */
2208 rectangle_pixmap(process_list
,
2209 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2211 drawing
->damage_begin
+SAFETY
, 0,
2212 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2214 gtk_widget_queue_draw(drawing
->drawing_area
);
2215 //gtk_widget_queue_draw_area (drawing->drawing_area,
2217 // control_flow_data->drawing->width,
2218 // control_flow_data->drawing->height);
2220 /* Get new data for the rest. */
2221 drawing_data_request(control_flow_data
->drawing
,
2222 drawing
->damage_begin
, 0,
2223 drawing
->damage_end
- drawing
->damage_begin
,
2224 control_flow_data
->drawing
->height
);
2227 //if(ns<os && os<ns+w)
2228 //if(ns<os && os<new_end)
2229 if(ltt_time_compare(*ns
,*os
) == -1
2230 && ltt_time_compare(*os
,new_end
) == -1)
2232 g_info("scrolling near left");
2233 /* Scroll left, keep left part of the screen */
2235 guint width
= control_flow_data
->drawing
->width
;
2236 convert_time_to_pixels(
2242 /* Copy old data to new location */
2243 copy_pixmap_region (process_list
,
2245 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2251 if(drawing
->damage_begin
== drawing
->damage_end
)
2252 drawing
->damage_end
= x
;
2254 drawing
->damage_end
=
2255 control_flow_data
->drawing
->width
;
2257 drawing
->damage_begin
= 0;
2259 rectangle_pixmap (process_list
,
2260 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2262 drawing
->damage_begin
, 0,
2263 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2266 gtk_widget_queue_draw(drawing
->drawing_area
);
2267 //gtk_widget_queue_draw_area (drawing->drawing_area,
2269 // control_flow_data->drawing->width,
2270 // control_flow_data->drawing->height);
2273 /* Get new data for the rest. */
2274 drawing_data_request(control_flow_data
->drawing
,
2275 drawing
->damage_begin
, 0,
2276 drawing
->damage_end
- drawing
->damage_begin
,
2277 control_flow_data
->drawing
->height
);
2280 if(ltt_time_compare(*ns
,*os
) == 0)
2282 g_info("not scrolling");
2284 g_info("scrolling far");
2285 /* Cannot reuse any part of the screen : far jump */
2288 rectangle_pixmap (process_list
,
2289 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2292 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2295 //gtk_widget_queue_draw_area (drawing->drawing_area,
2297 // control_flow_data->drawing->width,
2298 // control_flow_data->drawing->height);
2299 gtk_widget_queue_draw(drawing
->drawing_area
);
2301 drawing
->damage_begin
= 0;
2302 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2304 drawing_data_request(control_flow_data
->drawing
,
2306 control_flow_data
->drawing
->width
,
2307 control_flow_data
->drawing
->height
);
2313 /* Different scale (zoom) */
2316 rectangle_pixmap (process_list
,
2317 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2320 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2323 //gtk_widget_queue_draw_area (drawing->drawing_area,
2325 // control_flow_data->drawing->width,
2326 // control_flow_data->drawing->height);
2327 gtk_widget_queue_draw(drawing
->drawing_area
);
2329 drawing
->damage_begin
= 0;
2330 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2332 drawing_data_request(control_flow_data
->drawing
,
2334 control_flow_data
->drawing
->width
,
2335 control_flow_data
->drawing
->height
);
2338 /* Update directly when scrolling */
2339 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2345 gint
traceset_notify(void *hook_data
, void *call_data
)
2347 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2348 Drawing_t
*drawing
= control_flow_data
->drawing
;
2350 if(unlikely(drawing
->gc
== NULL
)) {
2353 if(drawing
->dotted_gc
== NULL
) {
2357 drawing_clear(control_flow_data
->drawing
);
2358 processlist_clear(control_flow_data
->process_list
);
2359 gtk_widget_set_size_request(
2360 control_flow_data
->drawing
->drawing_area
,
2361 -1, processlist_get_height(control_flow_data
->process_list
));
2362 redraw_notify(control_flow_data
, NULL
);
2364 request_background_data(control_flow_data
);
2369 gint
redraw_notify(void *hook_data
, void *call_data
)
2371 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2372 Drawing_t
*drawing
= control_flow_data
->drawing
;
2373 GtkWidget
*widget
= drawing
->drawing_area
;
2375 drawing
->damage_begin
= 0;
2376 drawing
->damage_end
= drawing
->width
;
2378 /* fun feature, to be separated someday... */
2379 drawing_clear(control_flow_data
->drawing
);
2380 processlist_clear(control_flow_data
->process_list
);
2381 gtk_widget_set_size_request(
2382 control_flow_data
->drawing
->drawing_area
,
2383 -1, processlist_get_height(control_flow_data
->process_list
));
2385 rectangle_pixmap (control_flow_data
->process_list
,
2386 widget
->style
->black_gc
,
2389 drawing
->alloc_width
,
2392 gtk_widget_queue_draw(drawing
->drawing_area
);
2394 if(drawing
->damage_begin
< drawing
->damage_end
)
2396 drawing_data_request(drawing
,
2397 drawing
->damage_begin
,
2399 drawing
->damage_end
-drawing
->damage_begin
,
2403 //gtk_widget_queue_draw_area(drawing->drawing_area,
2406 // drawing->height);
2412 gint
continue_notify(void *hook_data
, void *call_data
)
2414 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2415 Drawing_t
*drawing
= control_flow_data
->drawing
;
2417 //g_assert(widget->allocation.width == drawing->damage_end);
2419 if(drawing
->damage_begin
< drawing
->damage_end
)
2421 drawing_data_request(drawing
,
2422 drawing
->damage_begin
,
2424 drawing
->damage_end
-drawing
->damage_begin
,
2432 gint
update_current_time_hook(void *hook_data
, void *call_data
)
2435 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
2437 LttTime current_time
= *((LttTime
*)call_data
);
2439 TimeWindow time_window
=
2440 lttvwindow_get_time_window(control_flow_data
->tab
);
2442 LttTime time_begin
= time_window
.start_time
;
2443 LttTime width
= time_window
.time_width
;
2446 guint64 time_ll
= ltt_time_to_uint64(width
);
2447 time_ll
= time_ll
>> 1; /* divide by two */
2448 half_width
= ltt_time_from_uint64(time_ll
);
2450 LttTime time_end
= ltt_time_add(time_begin
, width
);
2452 LttvTraceset
* ts
= lttvwindow_get_traceset(control_flow_data
->tab
);
2454 TimeInterval time_span
= lttv_traceset_get_time_span_real(ts
);
2455 LttTime trace_start
= time_span
.start_time
;
2456 LttTime trace_end
= time_span
.end_time
;
2458 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
2459 current_time
.tv_nsec
);
2463 /* If current time is inside time interval, just move the highlight
2466 /* Else, we have to change the time interval. We have to tell it
2467 * to the main window. */
2468 /* The time interval change will take care of placing the current
2469 * time at the center of the visible area, or nearest possible if we are
2470 * at one end of the trace. */
2473 if(ltt_time_compare(current_time
, time_begin
) < 0)
2475 TimeWindow new_time_window
;
2477 if(ltt_time_compare(current_time
,
2478 ltt_time_add(trace_start
,half_width
)) < 0)
2479 time_begin
= trace_start
;
2481 time_begin
= ltt_time_sub(current_time
,half_width
);
2483 new_time_window
.start_time
= time_begin
;
2484 new_time_window
.time_width
= width
;
2485 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2486 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2488 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2490 else if(ltt_time_compare(current_time
, time_end
) > 0)
2492 TimeWindow new_time_window
;
2494 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
2495 time_begin
= ltt_time_sub(trace_end
,width
);
2497 time_begin
= ltt_time_sub(current_time
,half_width
);
2499 new_time_window
.start_time
= time_begin
;
2500 new_time_window
.time_width
= width
;
2501 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2502 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2504 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2507 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2509 /* Update directly when scrolling */
2510 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2517 typedef struct _ClosureData
{
2518 EventsRequest
*events_request
;
2524 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
2527 ProcessInfo
*process_info
= (ProcessInfo
*)key
;
2528 HashedProcessData
*hashed_process_data
= (HashedProcessData
*)value
;
2529 ClosureData
*closure_data
= (ClosureData
*)user_data
;
2531 EventsRequest
*events_request
= closure_data
->events_request
;
2532 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2533 LttvTraceset
*ts
= lttvwindow_get_traceset(control_flow_data
->tab
);
2536 LttTime evtime
= closure_data
->end_time
;
2538 gboolean dodraw
= TRUE
;
2541 /* For the process */
2542 /* First, check if the current process is in the state computation
2543 * process list. If it is there, that means we must add it right now and
2544 * draw items from the beginning of the read for it. If it is not
2545 * present, it's a new process and it was not present : it will
2546 * be added after the state update. */
2548 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
2549 #endif //EXTRA_CHECK
2550 //TODO Fdeslauriers 2012-07-17: adapt for multiple traces
2551 LttvTrace
*trace
= lttv_traceset_get(ts
,0);
2552 LttvTraceState
*trace_state
= trace
->state
;
2555 //FIXME : optimize data structures.
2556 LttvTracefileState
*tfs
;
2557 LttvTracefileContext
*tfc
;
2559 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
2560 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
2561 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
2562 && tfs
->cpu
== process_info
->cpu
)
2566 g_assert(i
<tc
->tracefiles
->len
);
2567 tfs
= LTTV_TRACEFILE_STATE(tfc
);
2569 // LttvTracefileState *tfs =ts
2570 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2571 // tracefiles[process_info->cpu];
2573 LttvProcessState
*process
;
2574 process
= lttv_state_find_process(trace_state
, process_info
->cpu
,
2577 if(unlikely(process
!= NULL
)) {
2578 #ifdef BABEL_CLEANUP
2579 LttvFilter
*filter
= control_flow_data
->filter
;
2580 if(filter
!= NULL
&& filter
->head
!= NULL
)
2581 if(!lttv_filter_tree_parse(filter
->head
,NULL
,NULL
,
2582 tc
->t
,NULL
,process
,tc
))
2584 #endif //babel_cleanup
2585 /* Only draw for processes that are currently in the trace states */
2588 /* Should be alike when background info is ready */
2589 if(control_flow_data
->background_info_waiting
==0)
2590 g_assert(ltt_time_compare(process
->creation_time
,
2591 process_info
->birth
) == 0);
2592 #endif //EXTRA_CHECK
2594 /* Now, the process is in the state hash and our own process hash.
2595 * We definitely can draw the items related to the ending state.
2598 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2601 TimeWindow time_window
=
2602 lttvwindow_get_time_window(control_flow_data
->tab
);
2605 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2606 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2608 #endif //EXTRA_CHECK
2609 Drawing_t
*drawing
= control_flow_data
->drawing
;
2610 guint width
= drawing
->width
;
2612 guint x
= closure_data
->x_end
;
2614 DrawContext draw_context
;
2616 /* Now create the drawing context that will be used to draw
2617 * items related to the last state. */
2618 draw_context
.drawable
= hashed_process_data
->pixmap
;
2619 draw_context
.gc
= drawing
->gc
;
2620 draw_context
.pango_layout
= drawing
->pango_layout
;
2621 draw_context
.drawinfo
.end
.x
= x
;
2623 draw_context
.drawinfo
.y
.over
= 1;
2624 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2625 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2627 draw_context
.drawinfo
.start
.offset
.over
= 0;
2628 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2629 draw_context
.drawinfo
.start
.offset
.under
= 0;
2630 draw_context
.drawinfo
.end
.offset
.over
= 0;
2631 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2632 draw_context
.drawinfo
.end
.offset
.under
= 0;
2634 /* Jump over draw if we are at the same x position */
2635 if(x
== hashed_process_data
->x
.over
)
2639 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2641 PropertiesLine prop_line
= prepare_execmode_line(process
);
2642 draw_line((void*)&prop_line
, (void*)&draw_context
);
2644 hashed_process_data
->x
.over
= x
;
2648 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2649 hashed_process_data
->x
.middle_used
)) {
2650 #if 0 /* do not mark closure : not missing information */
2651 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2652 /* Draw collision indicator */
2653 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2654 gdk_draw_point(drawing
->pixmap
,
2658 hashed_process_data
->x
.middle_marked
= TRUE
;
2663 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2666 PropertiesLine prop_line
= prepare_s_e_line(process
);
2667 draw_line((void*)&prop_line
, (void*)&draw_context
);
2670 /* become the last x position */
2671 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2672 hashed_process_data
->x
.middle
= x
;
2673 /* but don't use the pixel */
2674 hashed_process_data
->x
.middle_used
= FALSE
;
2676 /* Calculate the next good time */
2677 convert_pixels_to_time(width
, x
+1, time_window
,
2678 &hashed_process_data
->next_good_time
);
2687 int before_chunk(void *hook_data
, void *call_data
)
2690 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2691 LttvTraceset
*ts
= (LttvTraceset
*)call_data
;
2693 /* Desactivate sort */
2694 gtk_tree_sortable_set_sort_column_id(
2695 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2697 GTK_SORT_ASCENDING
);
2699 drawing_chunk_begin(events_request
, ts
);
2704 int before_request(void *hook_data
, void *call_data
)
2707 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2709 drawing_data_request_begin(events_request
);
2717 * after request is necessary in addition of after chunk in order to draw
2718 * lines until the end of the screen. after chunk just draws lines until
2725 int after_request(void *hook_data
, void *call_data
)
2728 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2729 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2731 ProcessList
*process_list
= control_flow_data
->process_list
;
2732 LttTime end_time
= events_request
->end_time
;
2734 ClosureData closure_data
;
2735 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2736 closure_data
.end_time
= end_time
;
2738 TimeWindow time_window
=
2739 lttvwindow_get_time_window(control_flow_data
->tab
);
2740 guint width
= control_flow_data
->drawing
->width
;
2741 convert_time_to_pixels(
2745 &closure_data
.x_end
);
2748 /* Draw last items */
2749 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2750 (void*)&closure_data
);
2753 /* Request expose */
2754 drawing_request_expose(events_request
, end_time
);
2763 int after_chunk(void *hook_data
, void *call_data
)
2766 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2767 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2768 LttvTraceset
*ts
= (LttvTraceset
*)call_data
;
2772 ProcessList
*process_list
= control_flow_data
->process_list
;
2774 guint nb_trace
= lttv_traceset_number(ts
);
2776 /* Only execute when called for the first trace's events request */
2777 if(!process_list
->current_hash_data
)
2780 for(i
= 0 ; i
< nb_trace
; i
++) {
2781 g_free(process_list
->current_hash_data
[i
]);
2783 g_free(process_list
->current_hash_data
);
2784 process_list
->current_hash_data
= NULL
;
2786 end_time
= events_request
->end_time
;
2788 ClosureData closure_data
;
2789 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2790 closure_data
.end_time
= end_time
;
2792 TimeWindow time_window
=
2793 lttvwindow_get_time_window(control_flow_data
->tab
);
2794 guint width
= control_flow_data
->drawing
->width
;
2795 convert_time_to_pixels(
2799 &closure_data
.x_end
);
2801 /* Draw last items */
2802 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2803 (void*)&closure_data
);
2805 /* Reactivate sort */
2806 gtk_tree_sortable_set_sort_column_id(
2807 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2808 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2809 GTK_SORT_ASCENDING
);
2811 update_index_to_pixmap(control_flow_data
->process_list
);
2812 /* Request a full expose : drawing scrambled */
2813 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2815 /* Request expose (updates damages zone also) */
2817 drawing_request_expose(events_request
, end_time
);
2821 /* after_statedump_end
2823 * @param hook_data ControlFlowData structure of the viewer.
2824 * @param call_data Event context.
2826 * This function adds items to be drawn in a queue for each process.
2829 int before_statedump_end(void *hook_data
, void *call_data
)
2831 #ifdef BABEL_CLEANUP
2832 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2833 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
2834 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2836 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2838 LttvTracesetState
*tss
= (LttvTracesetState
*)tfc
->t_context
->ts_context
;
2839 ProcessList
*process_list
= control_flow_data
->process_list
;
2842 e
= ltt_tracefile_get_event(tfc
->tf
);
2844 LttvFilter
*filter
= control_flow_data
->filter
;
2845 if(filter
!= NULL
&& filter
->head
!= NULL
)
2846 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2847 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2850 LttTime evtime
= ltt_event_time(e
);
2852 ClosureData closure_data
;
2853 closure_data
.events_request
= events_request
;
2854 closure_data
.tss
= tss
;
2855 closure_data
.end_time
= evtime
;
2857 TimeWindow time_window
=
2858 lttvwindow_get_time_window(control_flow_data
->tab
);
2859 guint width
= control_flow_data
->drawing
->width
;
2860 convert_time_to_pixels(
2864 &closure_data
.x_end
);
2866 /* Draw last items */
2867 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2868 (void*)&closure_data
);
2870 /* Reactivate sort */
2871 gtk_tree_sortable_set_sort_column_id(
2872 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2873 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2874 GTK_SORT_ASCENDING
);
2876 update_index_to_pixmap(control_flow_data
->process_list
);
2877 /* Request a full expose : drawing scrambled */
2878 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2880 /* Request expose (updates damages zone also) */
2881 drawing_request_expose(events_request
, tss
, evtime
);
2883 #endif //babel_cleanup