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
;
475 #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
),
511 "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
);
522 process
= ts
->running_process
[cpu
];
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");
527 timestamp
= lttv_event_get_timestamp(event
);
528 /* For the pid_out */
529 /* First, check if the current process is in the state computation
530 * process list. If it is there, that means we must add it right now and
531 * draw items from the beginning of the read for it. If it is not
532 * present, it's a new process and it was not present : it will
533 * be added after the state update. */
535 /* unknown state, bad current pid */
537 if(process
!= NULL
) {
538 /* Well, the process_out existed : we must get it in the process hash
539 * or add it, and draw its items.
541 /* Add process to process list (if not present) */
543 HashedProcessData
*hashed_process_data
= NULL
;
544 ProcessList
*process_list
= control_flow_data
->process_list
;
545 LttTime birth
= process
->creation_time
;
547 hashed_process_data
= processlist_get_process_data(process_list
,
551 18);//TODO "use the right value or delete"
552 if(hashed_process_data
== NULL
)
554 g_assert(pid_out
== 0 || pid_out
!= process
->ppid
);
555 /* Process not present */
556 ProcessInfo
*process_info
;
557 Drawing_t
*drawing
= control_flow_data
->drawing
;
558 processlist_add(process_list
,
565 18,//TODO "use the right value or delete"
570 &hashed_process_data
);
571 gtk_widget_set_size_request(drawing
->drawing_area
,
574 gtk_widget_queue_draw(drawing
->drawing_area
);
577 /* Now, the process is in the state hash and our own process hash.
578 * We definitely can draw the items related to the ending state.
581 if(ltt_time_compare(hashed_process_data
->next_good_time
,
584 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
586 TimeWindow time_window
=
587 lttvwindow_get_time_window(control_flow_data
->tab
);
589 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
590 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
593 Drawing_t
*drawing
= control_flow_data
->drawing
;
594 guint width
= drawing
->width
;
596 convert_time_to_pixels(
602 /* Draw collision indicator */
603 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
604 gdk_draw_point(hashed_process_data
->pixmap
,
607 COLLISION_POSITION(hashed_process_data
->height
));
608 hashed_process_data
->x
.middle_marked
= TRUE
;
611 TimeWindow time_window
=
612 lttvwindow_get_time_window(control_flow_data
->tab
);
614 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
615 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
618 Drawing_t
*drawing
= control_flow_data
->drawing
;
619 guint width
= drawing
->width
;
621 convert_time_to_pixels(
628 /* Jump over draw if we are at the same x position */
629 if(x
== hashed_process_data
->x
.middle
&&
630 hashed_process_data
->x
.middle_used
)
632 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
633 /* Draw collision indicator */
634 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
635 gdk_draw_point(hashed_process_data
->pixmap
,
638 COLLISION_POSITION(hashed_process_data
->height
));
639 hashed_process_data
->x
.middle_marked
= TRUE
;
643 DrawContext draw_context
;
645 /* Now create the drawing context that will be used to draw
646 * items related to the last state. */
647 draw_context
.drawable
= hashed_process_data
->pixmap
;
648 draw_context
.gc
= drawing
->gc
;
649 draw_context
.pango_layout
= drawing
->pango_layout
;
650 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
651 draw_context
.drawinfo
.end
.x
= x
;
653 draw_context
.drawinfo
.y
.over
= 1;
654 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
655 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
657 draw_context
.drawinfo
.start
.offset
.over
= 0;
658 draw_context
.drawinfo
.start
.offset
.middle
= 0;
659 draw_context
.drawinfo
.start
.offset
.under
= 0;
660 draw_context
.drawinfo
.end
.offset
.over
= 0;
661 draw_context
.drawinfo
.end
.offset
.middle
= 0;
662 draw_context
.drawinfo
.end
.offset
.under
= 0;
666 PropertiesLine prop_line
= prepare_s_e_line(process
);
667 draw_line((void*)&prop_line
, (void*)&draw_context
);
670 /* become the last x position */
671 hashed_process_data
->x
.middle
= x
;
672 hashed_process_data
->x
.middle_used
= TRUE
;
673 hashed_process_data
->x
.middle_marked
= FALSE
;
675 /* Calculate the next good time */
676 convert_pixels_to_time(width
, x
+1, time_window
,
677 &hashed_process_data
->next_good_time
);
683 /* First, check if the current process is in the state computation
684 * process list. If it is there, that means we must add it right now and
685 * draw items from the beginning of the read for it. If it is not
686 * present, it's a new process and it was not present : it will
687 * be added after the state update. */
688 process
= ts
->running_process
[cpu
];
690 if(process
!= NULL
) {
691 /* Well, the process existed : we must get it in the process hash
692 * or add it, and draw its items.
694 /* Add process to process list (if not present) */
696 HashedProcessData
*hashed_process_data
= NULL
;
697 ProcessList
*process_list
= control_flow_data
->process_list
;
698 LttTime birth
= process
->creation_time
;
700 hashed_process_data
= processlist_get_process_data(process_list
,
704 18);//TODO "use the right value or delete"
705 if(hashed_process_data
== NULL
)
707 g_assert(pid_in
== 0 || pid_in
!= process
->ppid
);
708 /* Process not present */
709 ProcessInfo
*process_info
;
710 Drawing_t
*drawing
= control_flow_data
->drawing
;
711 processlist_add(process_list
,
723 &hashed_process_data
);
724 gtk_widget_set_size_request(drawing
->drawing_area
,
727 gtk_widget_queue_draw(drawing
->drawing_area
);
730 //We could set the current process and hash here, but will be done
731 //by after schedchange hook
733 /* Now, the process is in the state hash and our own process hash.
734 * We definitely can draw the items related to the ending state.
737 if(ltt_time_compare(hashed_process_data
->next_good_time
,
740 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
742 TimeWindow time_window
=
743 lttvwindow_get_time_window(control_flow_data
->tab
);
745 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
746 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
749 Drawing_t
*drawing
= control_flow_data
->drawing
;
750 guint width
= drawing
->width
;
752 convert_time_to_pixels(
758 /* Draw collision indicator */
759 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
760 gdk_draw_point(hashed_process_data
->pixmap
,
763 COLLISION_POSITION(hashed_process_data
->height
));
764 hashed_process_data
->x
.middle_marked
= TRUE
;
767 TimeWindow time_window
=
768 lttvwindow_get_time_window(control_flow_data
->tab
);
770 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
771 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
774 Drawing_t
*drawing
= control_flow_data
->drawing
;
775 guint width
= drawing
->width
;
778 convert_time_to_pixels(
785 /* Jump over draw if we are at the same x position */
786 if(x
== hashed_process_data
->x
.middle
&&
787 hashed_process_data
->x
.middle_used
)
789 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
790 /* Draw collision indicator */
791 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
792 gdk_draw_point(hashed_process_data
->pixmap
,
795 COLLISION_POSITION(hashed_process_data
->height
));
796 hashed_process_data
->x
.middle_marked
= TRUE
;
800 DrawContext draw_context
;
802 /* Now create the drawing context that will be used to draw
803 * items related to the last state. */
804 draw_context
.drawable
= hashed_process_data
->pixmap
;
805 draw_context
.gc
= drawing
->gc
;
806 draw_context
.pango_layout
= drawing
->pango_layout
;
807 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
808 draw_context
.drawinfo
.end
.x
= x
;
810 draw_context
.drawinfo
.y
.over
= 1;
811 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
812 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
814 draw_context
.drawinfo
.start
.offset
.over
= 0;
815 draw_context
.drawinfo
.start
.offset
.middle
= 0;
816 draw_context
.drawinfo
.start
.offset
.under
= 0;
817 draw_context
.drawinfo
.end
.offset
.over
= 0;
818 draw_context
.drawinfo
.end
.offset
.middle
= 0;
819 draw_context
.drawinfo
.end
.offset
.under
= 0;
823 PropertiesLine prop_line
= prepare_s_e_line(process
);
824 draw_line((void*)&prop_line
, (void*)&draw_context
);
828 /* become the last x position */
829 hashed_process_data
->x
.middle
= x
;
830 hashed_process_data
->x
.middle_used
= TRUE
;
831 hashed_process_data
->x
.middle_marked
= FALSE
;
833 /* Calculate the next good time */
834 convert_pixels_to_time(width
, x
+1, time_window
,
835 &hashed_process_data
->next_good_time
);
839 g_warning("Cannot find pin_in in schedchange %u", pid_in
);
841 tfc
->target_pid
= target_pid_saved
;
842 #endif //babel_cleanup
850 GString
*string
= g_string_new("");;
851 gboolean field_names
= TRUE
, state
= TRUE
;
853 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
854 g_string_append_printf(string
,"\n");
857 g_string_append_printf(string
, " %s",
858 g_quark_to_string(tfs
->process
->state
->s
));
861 g_info("%s",string
->str
);
863 g_string_free(string
, TRUE
);
865 /* End of text dump */
870 /* after_schedchange_hook
872 * The draw after hook is called by the reading API to have a
873 * particular event drawn on the screen.
874 * @param hook_data ControlFlowData structure of the viewer.
875 * @param call_data Event context.
877 * This function adds items to be drawn in a queue for each process.
880 int after_schedchange_hook(void *hook_data
, void *call_data
)
883 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
884 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
885 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
887 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
889 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
891 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
894 e
= ltt_tracefile_get_event(tfc
->tf
);
896 LttvFilter
*filter
= control_flow_data
->filter
;
897 LttTime evtime
= ltt_event_time(e
);
899 /* Add process to process list (if not present) */
900 LttvProcessState
*process_in
;
903 HashedProcessData
*hashed_process_data_in
= NULL
;
905 ProcessList
*process_list
= control_flow_data
->process_list
;
909 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
912 tfc
->target_pid
= pid_in
;
913 if(!filter
|| !filter
->head
||
914 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
915 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
916 /* Find process pid_in in the list... */
917 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
918 //process_in = tfs->process;
919 guint cpu
= tfs
->cpu
;
920 guint trace_num
= ts
->parent
.index
;
921 process_in
= ts
->running_process
[cpu
];
922 /* It should exist, because we are after the state update. */
924 g_assert(process_in
!= NULL
);
926 birth
= process_in
->creation_time
;
928 hashed_process_data_in
= processlist_get_process_data(process_list
,
933 if(hashed_process_data_in
== NULL
)
935 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
936 ProcessInfo
*process_info
;
937 Drawing_t
*drawing
= control_flow_data
->drawing
;
938 /* Process not present */
939 processlist_add(process_list
,
951 &hashed_process_data_in
);
952 gtk_widget_set_size_request(drawing
->drawing_area
,
955 gtk_widget_queue_draw(drawing
->drawing_area
);
957 /* Set the current process */
958 process_list
->current_hash_data
[trace_num
][process_in
->cpu
] =
959 hashed_process_data_in
;
961 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
964 TimeWindow time_window
=
965 lttvwindow_get_time_window(control_flow_data
->tab
);
968 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
969 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
972 Drawing_t
*drawing
= control_flow_data
->drawing
;
973 guint width
= drawing
->width
;
976 convert_time_to_pixels(
982 if(hashed_process_data_in
->x
.middle
!= new_x
) {
983 hashed_process_data_in
->x
.middle
= new_x
;
984 hashed_process_data_in
->x
.middle_used
= FALSE
;
985 hashed_process_data_in
->x
.middle_marked
= FALSE
;
991 #endif //babel_cleanup
997 /* before_execmode_hook
999 * This function basically draw lines and icons. Two types of lines are drawn :
1000 * one small (3 pixels?) representing the state of the process and the second
1001 * type is thicker (10 pixels?) representing on which CPU a process is running
1002 * (and this only in running state).
1004 * Extremums of the lines :
1005 * x_min : time of the last event context for this process kept in memory.
1006 * x_max : time of the current event.
1007 * y : middle of the process in the process list. The process is found in the
1008 * list, therefore is it's position in pixels.
1010 * The choice of lines'color is defined by the context of the last event for this
1015 int before_execmode_hook(void *hook_data
, void *call_data
)
1020 LttvProcessState
*process
;
1022 /* we are in a execmode, before the state update. We must draw the
1023 * items corresponding to the state before it changes : now is the right
1027 event
= (LttvEvent
*) call_data
;
1028 if (strcmp(lttv_traceset_get_name_from_event(event
),
1029 "irq_handler_entry") != 0)
1031 LttTime evtime
= lttv_event_get_timestamp(event
);
1032 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
1034 LttvTraceset
*traceSet
= lttvwindow_get_traceset(control_flow_data
->tab
);
1036 cpu
= lttv_traceset_get_cpuid_from_event(event
);
1039 guint trace_number
= 0;//TODO fdeslauriers 2012-07-17: // Use trace handle to know trace number
1040 process
= ts
->running_process
[cpu
];
1041 g_assert(process
!= NULL
);
1043 guint pid
= process
->pid
;
1045 /* Well, the process_out existed : we must get it in the process hash
1046 * or add it, and draw its items.
1048 /* Add process to process list (if not present) */
1049 guint pl_height
= 0;
1050 HashedProcessData
*hashed_process_data
= NULL
;
1051 ProcessList
*process_list
= control_flow_data
->process_list
;
1052 if(process_list
->current_hash_data
== NULL
){//TODO fdeslauriers 2012-07-17 : should not be necessary
1056 LttTime birth
= process
->creation_time
;
1058 if(likely(process_list
->current_hash_data
[trace_number
][cpu
] != NULL
)) {
1059 hashed_process_data
= process_list
->current_hash_data
[trace_number
][cpu
];
1061 hashed_process_data
= processlist_get_process_data(process_list
,
1066 if(unlikely(hashed_process_data
== NULL
))
1068 g_assert(pid
== 0 || pid
!= process
->ppid
);
1069 ProcessInfo
*process_info
;
1070 /* Process not present */
1071 Drawing_t
*drawing
= control_flow_data
->drawing
;
1072 processlist_add(process_list
,
1084 &hashed_process_data
);
1085 gtk_widget_set_size_request(drawing
->drawing_area
,
1088 gtk_widget_queue_draw(drawing
->drawing_area
);
1090 /* Set the current process */
1091 process_list
->current_hash_data
[trace_number
][process
->cpu
] =
1092 hashed_process_data
;
1095 /* Now, the process is in the state hash and our own process hash.
1096 * We definitely can draw the items related to the ending state.
1099 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1102 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1103 TimeWindow time_window
=
1104 lttvwindow_get_time_window(control_flow_data
->tab
);
1107 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1108 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1110 #endif //EXTRA_CHECK
1111 Drawing_t
*drawing
= control_flow_data
->drawing
;
1112 guint width
= drawing
->width
;
1114 convert_time_to_pixels(
1120 /* Draw collision indicator */
1121 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1122 gdk_draw_point(hashed_process_data
->pixmap
,
1125 COLLISION_POSITION(hashed_process_data
->height
));
1126 hashed_process_data
->x
.middle_marked
= TRUE
;
1129 TimeWindow time_window
=
1130 lttvwindow_get_time_window(control_flow_data
->tab
);
1133 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1134 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1136 #endif //EXTRA_CHECK
1137 Drawing_t
*drawing
= control_flow_data
->drawing
;
1138 guint width
= drawing
->width
;
1141 convert_time_to_pixels(
1148 /* Jump over draw if we are at the same x position */
1149 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1150 hashed_process_data
->x
.middle_used
))
1152 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1153 /* Draw collision indicator */
1154 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1155 gdk_draw_point(hashed_process_data
->pixmap
,
1158 COLLISION_POSITION(hashed_process_data
->height
));
1159 hashed_process_data
->x
.middle_marked
= TRUE
;
1164 DrawContext draw_context
;
1165 /* Now create the drawing context that will be used to draw
1166 * items related to the last state. */
1167 draw_context
.drawable
= hashed_process_data
->pixmap
;
1168 draw_context
.gc
= drawing
->gc
;
1169 draw_context
.pango_layout
= drawing
->pango_layout
;
1170 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1171 draw_context
.drawinfo
.end
.x
= x
;
1173 draw_context
.drawinfo
.y
.over
= 1;
1174 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1175 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1177 draw_context
.drawinfo
.start
.offset
.over
= 0;
1178 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1179 draw_context
.drawinfo
.start
.offset
.under
= 0;
1180 draw_context
.drawinfo
.end
.offset
.over
= 0;
1181 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1182 draw_context
.drawinfo
.end
.offset
.under
= 0;
1186 PropertiesLine prop_line
= prepare_s_e_line(process
);
1187 draw_line((void*)&prop_line
, (void*)&draw_context
);
1190 /* become the last x position */
1191 hashed_process_data
->x
.middle
= x
;
1192 hashed_process_data
->x
.middle_used
= TRUE
;
1193 hashed_process_data
->x
.middle_marked
= FALSE
;
1195 /* Calculate the next good time */
1196 convert_pixels_to_time(width
, x
+1, time_window
,
1197 &hashed_process_data
->next_good_time
);
1204 /* before_process_exit_hook
1206 * Draw lines for process event.
1208 * @param hook_data ControlFlowData structure of the viewer.
1209 * @param call_data Event context.
1211 * This function adds items to be drawn in a queue for each process.
1216 int before_process_exit_hook(void *hook_data
, void *call_data
)
1218 #ifdef BABEL_CLEANUP
1219 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1220 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1222 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1224 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1226 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1228 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1231 e
= ltt_tracefile_get_event(tfc
->tf
);
1233 LttvFilter
*filter
= control_flow_data
->filter
;
1234 if(filter
!= NULL
&& filter
->head
!= NULL
)
1235 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1236 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1239 LttTime evtime
= ltt_event_time(e
);
1241 /* Add process to process list (if not present) */
1242 //LttvProcessState *process = tfs->process;
1243 guint cpu
= tfs
->cpu
;
1244 guint trace_num
= ts
->parent
.index
;
1245 LttvProcessState
*process
= ts
->running_process
[cpu
];
1246 guint pid
= process
->pid
;
1248 guint pl_height
= 0;
1249 HashedProcessData
*hashed_process_data
= NULL
;
1251 ProcessList
*process_list
= control_flow_data
->process_list
;
1253 g_assert(process
!= NULL
);
1255 birth
= process
->creation_time
;
1257 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1258 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1260 hashed_process_data
= processlist_get_process_data(process_list
,
1265 if(unlikely(hashed_process_data
== NULL
))
1267 g_assert(pid
== 0 || pid
!= process
->ppid
);
1268 /* Process not present */
1269 Drawing_t
*drawing
= control_flow_data
->drawing
;
1270 ProcessInfo
*process_info
;
1271 processlist_add(process_list
,
1283 &hashed_process_data
);
1284 gtk_widget_set_size_request(drawing
->drawing_area
,
1287 gtk_widget_queue_draw(drawing
->drawing_area
);
1291 /* Now, the process is in the state hash and our own process hash.
1292 * We definitely can draw the items related to the ending state.
1295 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1298 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1299 TimeWindow time_window
=
1300 lttvwindow_get_time_window(control_flow_data
->tab
);
1303 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1304 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1306 #endif //EXTRA_CHECK
1307 Drawing_t
*drawing
= control_flow_data
->drawing
;
1308 guint width
= drawing
->width
;
1310 convert_time_to_pixels(
1316 /* Draw collision indicator */
1317 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1318 gdk_draw_point(hashed_process_data
->pixmap
,
1321 COLLISION_POSITION(hashed_process_data
->height
));
1322 hashed_process_data
->x
.middle_marked
= TRUE
;
1325 TimeWindow time_window
=
1326 lttvwindow_get_time_window(control_flow_data
->tab
);
1329 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1330 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1332 #endif //EXTRA_CHECK
1333 Drawing_t
*drawing
= control_flow_data
->drawing
;
1334 guint width
= drawing
->width
;
1337 convert_time_to_pixels(
1344 /* Jump over draw if we are at the same x position */
1345 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1346 hashed_process_data
->x
.middle_used
))
1348 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1349 /* Draw collision indicator */
1350 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1351 gdk_draw_point(hashed_process_data
->pixmap
,
1354 COLLISION_POSITION(hashed_process_data
->height
));
1355 hashed_process_data
->x
.middle_marked
= TRUE
;
1359 DrawContext draw_context
;
1361 /* Now create the drawing context that will be used to draw
1362 * items related to the last state. */
1363 draw_context
.drawable
= hashed_process_data
->pixmap
;
1364 draw_context
.gc
= drawing
->gc
;
1365 draw_context
.pango_layout
= drawing
->pango_layout
;
1366 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1367 draw_context
.drawinfo
.end
.x
= x
;
1369 draw_context
.drawinfo
.y
.over
= 1;
1370 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1371 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1373 draw_context
.drawinfo
.start
.offset
.over
= 0;
1374 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1375 draw_context
.drawinfo
.start
.offset
.under
= 0;
1376 draw_context
.drawinfo
.end
.offset
.over
= 0;
1377 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1378 draw_context
.drawinfo
.end
.offset
.under
= 0;
1382 PropertiesLine prop_line
= prepare_s_e_line(process
);
1383 draw_line((void*)&prop_line
, (void*)&draw_context
);
1386 /* become the last x position */
1387 hashed_process_data
->x
.middle
= x
;
1388 hashed_process_data
->x
.middle_used
= TRUE
;
1389 hashed_process_data
->x
.middle_marked
= FALSE
;
1391 /* Calculate the next good time */
1392 convert_pixels_to_time(width
, x
+1, time_window
,
1393 &hashed_process_data
->next_good_time
);
1398 #endif //babel_cleanup
1404 /* before_process_release_hook
1406 * Draw lines for process event.
1408 * @param hook_data ControlFlowData structure of the viewer.
1409 * @param call_data Event context.
1411 * This function adds items to be drawn in a queue for each process.
1416 int before_process_release_hook(void *hook_data
, void *call_data
)
1418 #ifdef BABEL_CLEANUP
1419 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1420 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1422 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1424 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1426 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1429 e
= ltt_tracefile_get_event(tfc
->tf
);
1431 LttvFilter
*filter
= control_flow_data
->filter
;
1432 if(filter
!= NULL
&& filter
->head
!= NULL
)
1433 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1434 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1437 LttTime evtime
= ltt_event_time(e
);
1439 guint trace_num
= ts
->parent
.index
;
1443 pid
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
1446 /* Add process to process list (if not present) */
1447 /* Don't care about the process if it's not in the state hash already :
1448 * that means a process that has never done anything in the trace and
1449 * unknown suddently gets destroyed : no state meaningful to show. */
1450 LttvProcessState
*process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1452 if(process
!= NULL
) {
1454 HashedProcessData
*hashed_process_data
= NULL
;
1456 ProcessList
*process_list
= control_flow_data
->process_list
;
1458 birth
= process
->creation_time
;
1460 /* Cannot use current process : this event happens on another process,
1461 * action done by the parent. */
1462 hashed_process_data
= processlist_get_process_data(process_list
,
1467 if(unlikely(hashed_process_data
== NULL
))
1469 * Process already been scheduled out EXIT_DEAD, not in the process list
1470 * anymore. Just return.
1474 /* Now, the process is in the state hash and our own process hash.
1475 * We definitely can draw the items related to the ending state.
1478 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1481 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1482 TimeWindow time_window
=
1483 lttvwindow_get_time_window(control_flow_data
->tab
);
1486 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1487 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1489 #endif //EXTRA_CHECK
1490 Drawing_t
*drawing
= control_flow_data
->drawing
;
1491 guint width
= drawing
->width
;
1493 convert_time_to_pixels(
1499 /* Draw collision indicator */
1500 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1501 gdk_draw_point(hashed_process_data
->pixmap
,
1504 COLLISION_POSITION(hashed_process_data
->height
));
1505 hashed_process_data
->x
.middle_marked
= TRUE
;
1508 TimeWindow time_window
=
1509 lttvwindow_get_time_window(control_flow_data
->tab
);
1512 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1513 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1515 #endif //EXTRA_CHECK
1516 Drawing_t
*drawing
= control_flow_data
->drawing
;
1517 guint width
= drawing
->width
;
1520 convert_time_to_pixels(
1527 /* Jump over draw if we are at the same x position */
1528 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1529 hashed_process_data
->x
.middle_used
))
1531 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1532 /* Draw collision indicator */
1533 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1534 gdk_draw_point(hashed_process_data
->pixmap
,
1537 COLLISION_POSITION(hashed_process_data
->height
));
1538 hashed_process_data
->x
.middle_marked
= TRUE
;
1542 DrawContext draw_context
;
1544 /* Now create the drawing context that will be used to draw
1545 * items related to the last state. */
1546 draw_context
.drawable
= hashed_process_data
->pixmap
;
1547 draw_context
.gc
= drawing
->gc
;
1548 draw_context
.pango_layout
= drawing
->pango_layout
;
1549 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1550 draw_context
.drawinfo
.end
.x
= x
;
1552 draw_context
.drawinfo
.y
.over
= 1;
1553 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1554 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1556 draw_context
.drawinfo
.start
.offset
.over
= 0;
1557 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1558 draw_context
.drawinfo
.start
.offset
.under
= 0;
1559 draw_context
.drawinfo
.end
.offset
.over
= 0;
1560 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1561 draw_context
.drawinfo
.end
.offset
.under
= 0;
1565 PropertiesLine prop_line
= prepare_s_e_line(process
);
1566 draw_line((void*)&prop_line
, (void*)&draw_context
);
1569 /* become the last x position */
1570 hashed_process_data
->x
.middle
= x
;
1571 hashed_process_data
->x
.middle_used
= TRUE
;
1572 hashed_process_data
->x
.middle_marked
= FALSE
;
1574 /* Calculate the next good time */
1575 convert_pixels_to_time(width
, x
+1, time_window
,
1576 &hashed_process_data
->next_good_time
);
1582 #endif //babel_cleanup
1589 /* after_process_fork_hook
1591 * Create the processlist entry for the child process. Put the last
1592 * position in x at the current time value.
1594 * @param hook_data ControlFlowData structure of the viewer.
1595 * @param call_data Event context.
1597 * This function adds items to be drawn in a queue for each process.
1600 int after_process_fork_hook(void *hook_data
, void *call_data
)
1602 #ifdef BABEL_CLEANUP
1603 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1604 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1605 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1607 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1609 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1612 e
= ltt_tracefile_get_event(tfc
->tf
);
1614 LttvFilter
*filter
= control_flow_data
->filter
;
1615 if(filter
!= NULL
&& filter
->head
!= NULL
)
1616 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1617 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1620 LttTime evtime
= ltt_event_time(e
);
1624 child_pid
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
1627 /* Add process to process list (if not present) */
1628 LttvProcessState
*process_child
;
1630 guint pl_height
= 0;
1631 HashedProcessData
*hashed_process_data_child
= NULL
;
1633 ProcessList
*process_list
= control_flow_data
->process_list
;
1635 /* Find child in the list... */
1636 process_child
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1637 /* It should exist, because we are after the state update. */
1638 g_assert(process_child
!= NULL
);
1640 birth
= process_child
->creation_time
;
1641 guint trace_num
= ts
->parent
.index
;
1643 /* Cannot use current process, because this action is done by the parent
1645 hashed_process_data_child
= processlist_get_process_data(process_list
,
1650 if(likely(hashed_process_data_child
== NULL
))
1652 g_assert(child_pid
== 0 || child_pid
!= process_child
->ppid
);
1653 /* Process not present */
1654 Drawing_t
*drawing
= control_flow_data
->drawing
;
1655 ProcessInfo
*process_info
;
1656 processlist_add(process_list
,
1659 process_child
->tgid
,
1661 process_child
->ppid
,
1664 process_child
->name
,
1665 process_child
->brand
,
1668 &hashed_process_data_child
);
1669 gtk_widget_set_size_request(drawing
->drawing_area
,
1672 gtk_widget_queue_draw(drawing
->drawing_area
);
1674 processlist_set_ppid(process_list
, process_child
->ppid
,
1675 hashed_process_data_child
);
1676 processlist_set_tgid(process_list
, process_child
->tgid
,
1677 hashed_process_data_child
);
1681 if(likely(ltt_time_compare(hashed_process_data_child
->next_good_time
,
1684 TimeWindow time_window
=
1685 lttvwindow_get_time_window(control_flow_data
->tab
);
1688 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1689 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1691 #endif //EXTRA_CHECK
1692 Drawing_t
*drawing
= control_flow_data
->drawing
;
1693 guint width
= drawing
->width
;
1695 convert_time_to_pixels(
1701 if(likely(hashed_process_data_child
->x
.over
!= new_x
)) {
1702 hashed_process_data_child
->x
.over
= new_x
;
1703 hashed_process_data_child
->x
.over_used
= FALSE
;
1704 hashed_process_data_child
->x
.over_marked
= FALSE
;
1706 if(likely(hashed_process_data_child
->x
.middle
!= new_x
)) {
1707 hashed_process_data_child
->x
.middle
= new_x
;
1708 hashed_process_data_child
->x
.middle_used
= FALSE
;
1709 hashed_process_data_child
->x
.middle_marked
= FALSE
;
1711 if(likely(hashed_process_data_child
->x
.under
!= new_x
)) {
1712 hashed_process_data_child
->x
.under
= new_x
;
1713 hashed_process_data_child
->x
.under_used
= FALSE
;
1714 hashed_process_data_child
->x
.under_marked
= FALSE
;
1718 #endif //babel_cleanup
1723 /* after_process_exit_hook
1725 * Create the processlist entry for the child process. Put the last
1726 * position in x at the current time value.
1728 * @param hook_data ControlFlowData structure of the viewer.
1729 * @param call_data Event context.
1731 * This function adds items to be drawn in a queue for each process.
1734 int after_process_exit_hook(void *hook_data
, void *call_data
)
1736 #ifdef BABEL_CLEANUP
1737 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1738 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1739 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1741 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1743 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1745 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1748 e
= ltt_tracefile_get_event(tfc
->tf
);
1750 LttvFilter
*filter
= control_flow_data
->filter
;
1751 if(filter
!= NULL
&& filter
->head
!= NULL
)
1752 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1753 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1756 LttTime evtime
= ltt_event_time(e
);
1758 /* Add process to process list (if not present) */
1759 //LttvProcessState *process = tfs->process;
1760 guint cpu
= tfs
->cpu
;
1761 guint trace_num
= ts
->parent
.index
;
1762 LttvProcessState
*process
= ts
->running_process
[cpu
];
1764 /* It should exist, because we are after the state update. */
1765 g_assert(process
!= NULL
);
1767 guint pid
= process
->pid
;
1769 guint pl_height
= 0;
1770 HashedProcessData
*hashed_process_data
= NULL
;
1772 ProcessList
*process_list
= control_flow_data
->process_list
;
1774 birth
= process
->creation_time
;
1776 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
) ){
1777 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1779 hashed_process_data
= processlist_get_process_data(process_list
,
1784 if(unlikely(hashed_process_data
== NULL
))
1786 g_assert(pid
== 0 || pid
!= process
->ppid
);
1787 /* Process not present */
1788 Drawing_t
*drawing
= control_flow_data
->drawing
;
1789 ProcessInfo
*process_info
;
1790 processlist_add(process_list
,
1802 &hashed_process_data
);
1803 gtk_widget_set_size_request(drawing
->drawing_area
,
1806 gtk_widget_queue_draw(drawing
->drawing_area
);
1809 /* Set the current process */
1810 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1811 hashed_process_data
;
1814 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
1817 TimeWindow time_window
=
1818 lttvwindow_get_time_window(control_flow_data
->tab
);
1821 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1822 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1824 #endif //EXTRA_CHECK
1825 Drawing_t
*drawing
= control_flow_data
->drawing
;
1826 guint width
= drawing
->width
;
1828 convert_time_to_pixels(
1833 if(unlikely(hashed_process_data
->x
.middle
!= new_x
)) {
1834 hashed_process_data
->x
.middle
= new_x
;
1835 hashed_process_data
->x
.middle_used
= FALSE
;
1836 hashed_process_data
->x
.middle_marked
= FALSE
;
1841 #endif //babel_cleanup
1845 /* Get the filename of the process to print */
1846 int after_fs_exec_hook(void *hook_data
, void *call_data
)
1848 #ifdef BABEL_CLEANUP
1849 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1850 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1851 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1853 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1855 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1857 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1860 e
= ltt_tracefile_get_event(tfc
->tf
);
1862 LttvFilter
*filter
= control_flow_data
->filter
;
1863 if(filter
!= NULL
&& filter
->head
!= NULL
)
1864 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1865 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1868 guint cpu
= tfs
->cpu
;
1869 guint trace_num
= ts
->parent
.index
;
1870 LttvProcessState
*process
= ts
->running_process
[cpu
];
1871 g_assert(process
!= NULL
);
1873 guint pid
= process
->pid
;
1875 /* Well, the process_out existed : we must get it in the process hash
1876 * or add it, and draw its items.
1878 /* Add process to process list (if not present) */
1879 guint pl_height
= 0;
1880 HashedProcessData
*hashed_process_data
= NULL
;
1881 ProcessList
*process_list
= control_flow_data
->process_list
;
1882 LttTime birth
= process
->creation_time
;
1884 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1885 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1887 hashed_process_data
= processlist_get_process_data(process_list
,
1892 if(unlikely(hashed_process_data
== NULL
))
1894 g_assert(pid
== 0 || pid
!= process
->ppid
);
1895 ProcessInfo
*process_info
;
1896 /* Process not present */
1897 Drawing_t
*drawing
= control_flow_data
->drawing
;
1898 processlist_add(process_list
,
1910 &hashed_process_data
);
1911 gtk_widget_set_size_request(drawing
->drawing_area
,
1914 gtk_widget_queue_draw(drawing
->drawing_area
);
1916 /* Set the current process */
1917 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1918 hashed_process_data
;
1921 processlist_set_name(process_list
, process
->name
, hashed_process_data
);
1924 #endif //babel_cleanup
1928 /* Get the filename of the process to print */
1929 int after_user_generic_thread_brand_hook(void *hook_data
, void *call_data
)
1931 #ifdef BABEL_CLEANUP
1932 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1933 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1934 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1936 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1938 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1940 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1943 e
= ltt_tracefile_get_event(tfc
->tf
);
1945 LttvFilter
*filter
= control_flow_data
->filter
;
1946 if(filter
!= NULL
&& filter
->head
!= NULL
)
1947 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1948 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1951 guint cpu
= tfs
->cpu
;
1952 guint trace_num
= ts
->parent
.index
;
1953 LttvProcessState
*process
= ts
->running_process
[cpu
];
1954 g_assert(process
!= NULL
);
1956 guint pid
= process
->pid
;
1958 /* Well, the process_out existed : we must get it in the process hash
1959 * or add it, and draw its items.
1961 /* Add process to process list (if not present) */
1962 guint pl_height
= 0;
1963 HashedProcessData
*hashed_process_data
= NULL
;
1964 ProcessList
*process_list
= control_flow_data
->process_list
;
1965 LttTime birth
= process
->creation_time
;
1967 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1968 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1970 hashed_process_data
= processlist_get_process_data(process_list
,
1975 if(unlikely(hashed_process_data
== NULL
))
1977 g_assert(pid
== 0 || pid
!= process
->ppid
);
1978 ProcessInfo
*process_info
;
1979 /* Process not present */
1980 Drawing_t
*drawing
= control_flow_data
->drawing
;
1981 processlist_add(process_list
,
1993 &hashed_process_data
);
1994 gtk_widget_set_size_request(drawing
->drawing_area
,
1997 gtk_widget_queue_draw(drawing
->drawing_area
);
1999 /* Set the current process */
2000 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
2001 hashed_process_data
;
2004 processlist_set_brand(process_list
, process
->brand
, hashed_process_data
);
2007 #endif //babel_cleanup
2011 /* after_event_enum_process_hook
2013 * Create the processlist entry for the child process. Put the last
2014 * position in x at the current time value.
2016 * @param hook_data ControlFlowData structure of the viewer.
2017 * @param call_data Event context.
2019 * This function adds items to be drawn in a queue for each process.
2022 int after_event_enum_process_hook(void *hook_data
, void *call_data
)
2024 #ifdef BABEL_CLEANUP
2025 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2026 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
2027 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2029 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2031 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
2033 guint first_cpu
, nb_cpus
, cpu
;
2036 e
= ltt_tracefile_get_event(tfc
->tf
);
2038 LttvFilter
*filter
= control_flow_data
->filter
;
2039 if(filter
!= NULL
&& filter
->head
!= NULL
)
2040 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2041 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2044 /* Add process to process list (if not present) */
2045 LttvProcessState
*process_in
;
2047 guint pl_height
= 0;
2048 HashedProcessData
*hashed_process_data_in
= NULL
;
2050 ProcessList
*process_list
= control_flow_data
->process_list
;
2051 guint trace_num
= ts
->parent
.index
;
2055 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2060 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2062 first_cpu
= ANY_CPU
;
2063 nb_cpus
= ANY_CPU
+1;
2066 for(cpu
= first_cpu
; cpu
< nb_cpus
; cpu
++) {
2067 /* Find process pid_in in the list... */
2068 process_in
= lttv_state_find_process(ts
, cpu
, pid_in
);
2069 //process_in = tfs->process;
2070 //guint cpu = tfs->cpu;
2071 //guint trace_num = ts->parent.index;
2072 //process_in = ts->running_process[cpu];
2073 /* It should exist, because we are after the state update. */
2075 //g_assert(process_in != NULL);
2076 #endif //EXTRA_CHECK
2077 birth
= process_in
->creation_time
;
2079 hashed_process_data_in
= processlist_get_process_data(process_list
,
2084 if(hashed_process_data_in
== NULL
)
2086 if(pid_in
!= 0 && pid_in
== process_in
->ppid
)
2087 g_critical("TEST %u , %u", pid_in
, process_in
->ppid
);
2088 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
2089 ProcessInfo
*process_info
;
2090 Drawing_t
*drawing
= control_flow_data
->drawing
;
2091 /* Process not present */
2092 processlist_add(process_list
,
2104 &hashed_process_data_in
);
2105 gtk_widget_set_size_request(drawing
->drawing_area
,
2108 gtk_widget_queue_draw(drawing
->drawing_area
);
2110 processlist_set_name(process_list
, process_in
->name
,
2111 hashed_process_data_in
);
2112 processlist_set_ppid(process_list
, process_in
->ppid
,
2113 hashed_process_data_in
);
2114 processlist_set_tgid(process_list
, process_in
->tgid
,
2115 hashed_process_data_in
);
2119 #endif //babel_cleanup
2123 gint
update_time_window_hook(void *hook_data
, void *call_data
)
2125 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2126 Drawing_t
*drawing
= control_flow_data
->drawing
;
2127 ProcessList
*process_list
= control_flow_data
->process_list
;
2129 const TimeWindowNotifyData
*time_window_nofify_data
=
2130 ((const TimeWindowNotifyData
*)call_data
);
2132 TimeWindow
*old_time_window
=
2133 time_window_nofify_data
->old_time_window
;
2134 TimeWindow
*new_time_window
=
2135 time_window_nofify_data
->new_time_window
;
2137 /* Update the ruler */
2138 drawing_update_ruler(control_flow_data
->drawing
,
2142 /* Two cases : zoom in/out or scrolling */
2144 /* In order to make sure we can reuse the old drawing, the scale must
2145 * be the same and the new time interval being partly located in the
2146 * currently shown time interval. (reuse is only for scrolling)
2149 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
2150 old_time_window
->start_time
.tv_sec
,
2151 old_time_window
->start_time
.tv_nsec
,
2152 old_time_window
->time_width
.tv_sec
,
2153 old_time_window
->time_width
.tv_nsec
);
2155 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
2156 new_time_window
->start_time
.tv_sec
,
2157 new_time_window
->start_time
.tv_nsec
,
2158 new_time_window
->time_width
.tv_sec
,
2159 new_time_window
->time_width
.tv_nsec
);
2161 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
2162 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
2164 /* Same scale (scrolling) */
2165 g_info("scrolling");
2166 LttTime
*ns
= &new_time_window
->start_time
;
2167 LttTime
*os
= &old_time_window
->start_time
;
2168 LttTime old_end
= old_time_window
->end_time
;
2169 LttTime new_end
= new_time_window
->end_time
;
2171 //if(ns<os+w && os+w<ns+w)
2172 //if(ns<old_end && os<ns)
2173 if(ltt_time_compare(*ns
, old_end
) == -1
2174 && ltt_time_compare(*os
, *ns
) == -1)
2176 g_info("scrolling near right");
2177 /* Scroll right, keep right part of the screen */
2179 guint width
= control_flow_data
->drawing
->width
;
2180 convert_time_to_pixels(
2186 /* Copy old data to new location */
2187 copy_pixmap_region(process_list
,
2189 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2193 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
2195 if(drawing
->damage_begin
== drawing
->damage_end
)
2196 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
2198 drawing
->damage_begin
= 0;
2200 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2202 /* Clear the data request background, but not SAFETY */
2203 rectangle_pixmap(process_list
,
2204 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2206 drawing
->damage_begin
+SAFETY
, 0,
2207 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2209 gtk_widget_queue_draw(drawing
->drawing_area
);
2210 //gtk_widget_queue_draw_area (drawing->drawing_area,
2212 // control_flow_data->drawing->width,
2213 // control_flow_data->drawing->height);
2215 /* Get new data for the rest. */
2216 drawing_data_request(control_flow_data
->drawing
,
2217 drawing
->damage_begin
, 0,
2218 drawing
->damage_end
- drawing
->damage_begin
,
2219 control_flow_data
->drawing
->height
);
2222 //if(ns<os && os<ns+w)
2223 //if(ns<os && os<new_end)
2224 if(ltt_time_compare(*ns
,*os
) == -1
2225 && ltt_time_compare(*os
,new_end
) == -1)
2227 g_info("scrolling near left");
2228 /* Scroll left, keep left part of the screen */
2230 guint width
= control_flow_data
->drawing
->width
;
2231 convert_time_to_pixels(
2237 /* Copy old data to new location */
2238 copy_pixmap_region (process_list
,
2240 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2246 if(drawing
->damage_begin
== drawing
->damage_end
)
2247 drawing
->damage_end
= x
;
2249 drawing
->damage_end
=
2250 control_flow_data
->drawing
->width
;
2252 drawing
->damage_begin
= 0;
2254 rectangle_pixmap (process_list
,
2255 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2257 drawing
->damage_begin
, 0,
2258 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2261 gtk_widget_queue_draw(drawing
->drawing_area
);
2262 //gtk_widget_queue_draw_area (drawing->drawing_area,
2264 // control_flow_data->drawing->width,
2265 // control_flow_data->drawing->height);
2268 /* Get new data for the rest. */
2269 drawing_data_request(control_flow_data
->drawing
,
2270 drawing
->damage_begin
, 0,
2271 drawing
->damage_end
- drawing
->damage_begin
,
2272 control_flow_data
->drawing
->height
);
2275 if(ltt_time_compare(*ns
,*os
) == 0)
2277 g_info("not scrolling");
2279 g_info("scrolling far");
2280 /* Cannot reuse any part of the screen : far jump */
2283 rectangle_pixmap (process_list
,
2284 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2287 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2290 //gtk_widget_queue_draw_area (drawing->drawing_area,
2292 // control_flow_data->drawing->width,
2293 // control_flow_data->drawing->height);
2294 gtk_widget_queue_draw(drawing
->drawing_area
);
2296 drawing
->damage_begin
= 0;
2297 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2299 drawing_data_request(control_flow_data
->drawing
,
2301 control_flow_data
->drawing
->width
,
2302 control_flow_data
->drawing
->height
);
2308 /* Different scale (zoom) */
2311 rectangle_pixmap (process_list
,
2312 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2315 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2318 //gtk_widget_queue_draw_area (drawing->drawing_area,
2320 // control_flow_data->drawing->width,
2321 // control_flow_data->drawing->height);
2322 gtk_widget_queue_draw(drawing
->drawing_area
);
2324 drawing
->damage_begin
= 0;
2325 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2327 drawing_data_request(control_flow_data
->drawing
,
2329 control_flow_data
->drawing
->width
,
2330 control_flow_data
->drawing
->height
);
2333 /* Update directly when scrolling */
2334 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2340 gint
traceset_notify(void *hook_data
, void *call_data
)
2342 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2343 Drawing_t
*drawing
= control_flow_data
->drawing
;
2345 if(unlikely(drawing
->gc
== NULL
)) {
2348 if(drawing
->dotted_gc
== NULL
) {
2352 drawing_clear(control_flow_data
->drawing
);
2353 processlist_clear(control_flow_data
->process_list
);
2354 gtk_widget_set_size_request(
2355 control_flow_data
->drawing
->drawing_area
,
2356 -1, processlist_get_height(control_flow_data
->process_list
));
2357 redraw_notify(control_flow_data
, NULL
);
2359 request_background_data(control_flow_data
);
2364 gint
redraw_notify(void *hook_data
, void *call_data
)
2366 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2367 Drawing_t
*drawing
= control_flow_data
->drawing
;
2368 GtkWidget
*widget
= drawing
->drawing_area
;
2370 drawing
->damage_begin
= 0;
2371 drawing
->damage_end
= drawing
->width
;
2373 /* fun feature, to be separated someday... */
2374 drawing_clear(control_flow_data
->drawing
);
2375 processlist_clear(control_flow_data
->process_list
);
2376 gtk_widget_set_size_request(
2377 control_flow_data
->drawing
->drawing_area
,
2378 -1, processlist_get_height(control_flow_data
->process_list
));
2380 rectangle_pixmap (control_flow_data
->process_list
,
2381 widget
->style
->black_gc
,
2384 drawing
->alloc_width
,
2387 gtk_widget_queue_draw(drawing
->drawing_area
);
2389 if(drawing
->damage_begin
< drawing
->damage_end
)
2391 drawing_data_request(drawing
,
2392 drawing
->damage_begin
,
2394 drawing
->damage_end
-drawing
->damage_begin
,
2398 //gtk_widget_queue_draw_area(drawing->drawing_area,
2401 // drawing->height);
2407 gint
continue_notify(void *hook_data
, void *call_data
)
2409 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2410 Drawing_t
*drawing
= control_flow_data
->drawing
;
2412 //g_assert(widget->allocation.width == drawing->damage_end);
2414 if(drawing
->damage_begin
< drawing
->damage_end
)
2416 drawing_data_request(drawing
,
2417 drawing
->damage_begin
,
2419 drawing
->damage_end
-drawing
->damage_begin
,
2427 gint
update_current_time_hook(void *hook_data
, void *call_data
)
2430 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
2432 LttTime current_time
= *((LttTime
*)call_data
);
2434 TimeWindow time_window
=
2435 lttvwindow_get_time_window(control_flow_data
->tab
);
2437 LttTime time_begin
= time_window
.start_time
;
2438 LttTime width
= time_window
.time_width
;
2441 guint64 time_ll
= ltt_time_to_uint64(width
);
2442 time_ll
= time_ll
>> 1; /* divide by two */
2443 half_width
= ltt_time_from_uint64(time_ll
);
2445 LttTime time_end
= ltt_time_add(time_begin
, width
);
2447 LttvTraceset
* ts
= lttvwindow_get_traceset(control_flow_data
->tab
);
2449 TimeInterval time_span
= lttv_traceset_get_time_span_real(ts
);
2450 LttTime trace_start
= time_span
.start_time
;
2451 LttTime trace_end
= time_span
.end_time
;
2453 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
2454 current_time
.tv_nsec
);
2458 /* If current time is inside time interval, just move the highlight
2461 /* Else, we have to change the time interval. We have to tell it
2462 * to the main window. */
2463 /* The time interval change will take care of placing the current
2464 * time at the center of the visible area, or nearest possible if we are
2465 * at one end of the trace. */
2468 if(ltt_time_compare(current_time
, time_begin
) < 0)
2470 TimeWindow new_time_window
;
2472 if(ltt_time_compare(current_time
,
2473 ltt_time_add(trace_start
,half_width
)) < 0)
2474 time_begin
= trace_start
;
2476 time_begin
= ltt_time_sub(current_time
,half_width
);
2478 new_time_window
.start_time
= time_begin
;
2479 new_time_window
.time_width
= width
;
2480 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2481 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2483 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2485 else if(ltt_time_compare(current_time
, time_end
) > 0)
2487 TimeWindow new_time_window
;
2489 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
2490 time_begin
= ltt_time_sub(trace_end
,width
);
2492 time_begin
= ltt_time_sub(current_time
,half_width
);
2494 new_time_window
.start_time
= time_begin
;
2495 new_time_window
.time_width
= width
;
2496 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2497 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2499 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2502 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2504 /* Update directly when scrolling */
2505 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2512 typedef struct _ClosureData
{
2513 EventsRequest
*events_request
;
2519 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
2522 ProcessInfo
*process_info
= (ProcessInfo
*)key
;
2523 HashedProcessData
*hashed_process_data
= (HashedProcessData
*)value
;
2524 ClosureData
*closure_data
= (ClosureData
*)user_data
;
2526 EventsRequest
*events_request
= closure_data
->events_request
;
2527 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2528 LttvTraceset
*ts
= lttvwindow_get_traceset(control_flow_data
->tab
);
2531 LttTime evtime
= closure_data
->end_time
;
2533 gboolean dodraw
= TRUE
;
2536 /* For the process */
2537 /* First, check if the current process is in the state computation
2538 * process list. If it is there, that means we must add it right now and
2539 * draw items from the beginning of the read for it. If it is not
2540 * present, it's a new process and it was not present : it will
2541 * be added after the state update. */
2543 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
2544 #endif //EXTRA_CHECK
2545 //TODO Fdeslauriers 2012-07-17: adapt for multiple traces
2546 LttvTrace
*trace
= lttv_traceset_get(ts
,0);
2547 LttvTraceState
*trace_state
= trace
->state
;
2550 //FIXME : optimize data structures.
2551 LttvTracefileState
*tfs
;
2552 LttvTracefileContext
*tfc
;
2554 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
2555 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
2556 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
2557 && tfs
->cpu
== process_info
->cpu
)
2561 g_assert(i
<tc
->tracefiles
->len
);
2562 tfs
= LTTV_TRACEFILE_STATE(tfc
);
2564 // LttvTracefileState *tfs =ts
2565 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2566 // tracefiles[process_info->cpu];
2568 LttvProcessState
*process
;
2569 process
= lttv_state_find_process(trace_state
, process_info
->cpu
,
2572 if(unlikely(process
!= NULL
)) {
2573 #ifdef BABEL_CLEANUP
2574 LttvFilter
*filter
= control_flow_data
->filter
;
2575 if(filter
!= NULL
&& filter
->head
!= NULL
)
2576 if(!lttv_filter_tree_parse(filter
->head
,NULL
,NULL
,
2577 tc
->t
,NULL
,process
,tc
))
2579 #endif //babel_cleanup
2580 /* Only draw for processes that are currently in the trace states */
2583 /* Should be alike when background info is ready */
2584 if(control_flow_data
->background_info_waiting
==0)
2585 g_assert(ltt_time_compare(process
->creation_time
,
2586 process_info
->birth
) == 0);
2587 #endif //EXTRA_CHECK
2589 /* Now, the process is in the state hash and our own process hash.
2590 * We definitely can draw the items related to the ending state.
2593 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2596 TimeWindow time_window
=
2597 lttvwindow_get_time_window(control_flow_data
->tab
);
2600 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2601 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2603 #endif //EXTRA_CHECK
2604 Drawing_t
*drawing
= control_flow_data
->drawing
;
2605 guint width
= drawing
->width
;
2607 guint x
= closure_data
->x_end
;
2609 DrawContext draw_context
;
2611 /* Now create the drawing context that will be used to draw
2612 * items related to the last state. */
2613 draw_context
.drawable
= hashed_process_data
->pixmap
;
2614 draw_context
.gc
= drawing
->gc
;
2615 draw_context
.pango_layout
= drawing
->pango_layout
;
2616 draw_context
.drawinfo
.end
.x
= x
;
2618 draw_context
.drawinfo
.y
.over
= 1;
2619 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2620 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2622 draw_context
.drawinfo
.start
.offset
.over
= 0;
2623 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2624 draw_context
.drawinfo
.start
.offset
.under
= 0;
2625 draw_context
.drawinfo
.end
.offset
.over
= 0;
2626 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2627 draw_context
.drawinfo
.end
.offset
.under
= 0;
2629 /* Jump over draw if we are at the same x position */
2630 if(x
== hashed_process_data
->x
.over
)
2634 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2636 PropertiesLine prop_line
= prepare_execmode_line(process
);
2637 draw_line((void*)&prop_line
, (void*)&draw_context
);
2639 hashed_process_data
->x
.over
= x
;
2643 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2644 hashed_process_data
->x
.middle_used
)) {
2645 #if 0 /* do not mark closure : not missing information */
2646 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2647 /* Draw collision indicator */
2648 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2649 gdk_draw_point(drawing
->pixmap
,
2653 hashed_process_data
->x
.middle_marked
= TRUE
;
2658 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2661 PropertiesLine prop_line
= prepare_s_e_line(process
);
2662 draw_line((void*)&prop_line
, (void*)&draw_context
);
2665 /* become the last x position */
2666 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2667 hashed_process_data
->x
.middle
= x
;
2668 /* but don't use the pixel */
2669 hashed_process_data
->x
.middle_used
= FALSE
;
2671 /* Calculate the next good time */
2672 convert_pixels_to_time(width
, x
+1, time_window
,
2673 &hashed_process_data
->next_good_time
);
2682 int before_chunk(void *hook_data
, void *call_data
)
2685 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2686 LttvTraceset
*ts
= (LttvTraceset
*)call_data
;
2688 /* Desactivate sort */
2689 gtk_tree_sortable_set_sort_column_id(
2690 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2692 GTK_SORT_ASCENDING
);
2694 drawing_chunk_begin(events_request
, ts
);
2699 int before_request(void *hook_data
, void *call_data
)
2702 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2704 drawing_data_request_begin(events_request
);
2712 * after request is necessary in addition of after chunk in order to draw
2713 * lines until the end of the screen. after chunk just draws lines until
2720 int after_request(void *hook_data
, void *call_data
)
2723 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2724 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2726 ProcessList
*process_list
= control_flow_data
->process_list
;
2727 LttTime end_time
= events_request
->end_time
;
2729 ClosureData closure_data
;
2730 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2731 closure_data
.end_time
= end_time
;
2733 TimeWindow time_window
=
2734 lttvwindow_get_time_window(control_flow_data
->tab
);
2735 guint width
= control_flow_data
->drawing
->width
;
2736 convert_time_to_pixels(
2740 &closure_data
.x_end
);
2743 /* Draw last items */
2744 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2745 (void*)&closure_data
);
2748 /* Request expose */
2749 drawing_request_expose(events_request
, end_time
);
2758 int after_chunk(void *hook_data
, void *call_data
)
2761 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2762 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2763 LttvTraceset
*ts
= (LttvTraceset
*)call_data
;
2767 ProcessList
*process_list
= control_flow_data
->process_list
;
2769 guint nb_trace
= lttv_traceset_number(ts
);
2771 /* Only execute when called for the first trace's events request */
2772 if(!process_list
->current_hash_data
)
2775 for(i
= 0 ; i
< nb_trace
; i
++) {
2776 g_free(process_list
->current_hash_data
[i
]);
2778 g_free(process_list
->current_hash_data
);
2779 process_list
->current_hash_data
= NULL
;
2781 end_time
= events_request
->end_time
;
2783 ClosureData closure_data
;
2784 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2785 closure_data
.end_time
= end_time
;
2787 TimeWindow time_window
=
2788 lttvwindow_get_time_window(control_flow_data
->tab
);
2789 guint width
= control_flow_data
->drawing
->width
;
2790 convert_time_to_pixels(
2794 &closure_data
.x_end
);
2796 /* Draw last items */
2797 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2798 (void*)&closure_data
);
2800 /* Reactivate sort */
2801 gtk_tree_sortable_set_sort_column_id(
2802 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2803 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2804 GTK_SORT_ASCENDING
);
2806 update_index_to_pixmap(control_flow_data
->process_list
);
2807 /* Request a full expose : drawing scrambled */
2808 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2810 /* Request expose (updates damages zone also) */
2812 drawing_request_expose(events_request
, end_time
);
2816 /* after_statedump_end
2818 * @param hook_data ControlFlowData structure of the viewer.
2819 * @param call_data Event context.
2821 * This function adds items to be drawn in a queue for each process.
2824 int before_statedump_end(void *hook_data
, void *call_data
)
2826 #ifdef BABEL_CLEANUP
2827 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2828 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
2829 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2831 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2833 LttvTracesetState
*tss
= (LttvTracesetState
*)tfc
->t_context
->ts_context
;
2834 ProcessList
*process_list
= control_flow_data
->process_list
;
2837 e
= ltt_tracefile_get_event(tfc
->tf
);
2839 LttvFilter
*filter
= control_flow_data
->filter
;
2840 if(filter
!= NULL
&& filter
->head
!= NULL
)
2841 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2842 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2845 LttTime evtime
= ltt_event_time(e
);
2847 ClosureData closure_data
;
2848 closure_data
.events_request
= events_request
;
2849 closure_data
.tss
= tss
;
2850 closure_data
.end_time
= evtime
;
2852 TimeWindow time_window
=
2853 lttvwindow_get_time_window(control_flow_data
->tab
);
2854 guint width
= control_flow_data
->drawing
->width
;
2855 convert_time_to_pixels(
2859 &closure_data
.x_end
);
2861 /* Draw last items */
2862 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2863 (void*)&closure_data
);
2865 /* Reactivate sort */
2866 gtk_tree_sortable_set_sort_column_id(
2867 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2868 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2869 GTK_SORT_ASCENDING
);
2871 update_index_to_pixmap(control_flow_data
->process_list
);
2872 /* Request a full expose : drawing scrambled */
2873 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2875 /* Request expose (updates damages zone also) */
2876 drawing_request_expose(events_request
, tss
, evtime
);
2879 #endif //babel_cleanup