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.
116 static void request_background_data(ControlFlowData
*control_flow_data
)
118 LttvTracesetContext
* tsc
=
119 lttvwindow_get_traceset_context(control_flow_data
->tab
);
120 gint num_traces
= lttv_traceset_number(tsc
->ts
);
123 LttvTraceState
*tstate
;
125 LttvHooks
*background_ready_hook
=
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(tsc
->ts
, i
);
133 tstate
= LTTV_TRACE_STATE(tsc
->traces
[i
]);
135 if(lttvwindowtraces_get_ready(g_quark_from_string("state"),trace
)==FALSE
136 && !tstate
->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_MODE_UNKNOWN
)
249 prop_line
.color
= drawing_colors
[COL_MODE_UNKNOWN
];
251 g_assert(FALSE
); /* RUNNING MODE UNKNOWN */
252 } else if(process
->state
->s
== LTTV_STATE_WAIT
) {
253 /* We don't show if we wait while in user mode, trap, irq or syscall */
254 prop_line
.color
= drawing_colors
[COL_WAIT
];
255 } else if(process
->state
->s
== LTTV_STATE_WAIT_CPU
) {
256 /* We don't show if we wait for CPU while in user mode, trap, irq
258 prop_line
.color
= drawing_colors
[COL_WAIT_CPU
];
259 } else if(process
->state
->s
== LTTV_STATE_ZOMBIE
) {
260 prop_line
.color
= drawing_colors
[COL_ZOMBIE
];
261 } else if(process
->state
->s
== LTTV_STATE_WAIT_FORK
) {
262 prop_line
.color
= drawing_colors
[COL_WAIT_FORK
];
263 } else if(process
->state
->s
== LTTV_STATE_EXIT
) {
264 prop_line
.color
= drawing_colors
[COL_EXIT
];
265 } else if(process
->state
->s
== LTTV_STATE_UNNAMED
) {
266 prop_line
.color
= drawing_colors
[COL_UNNAMED
];
267 } else if(process
->state
->s
== LTTV_STATE_DEAD
) {
268 prop_line
.color
= drawing_colors
[COL_DEAD
];
270 g_critical("unknown state : %s", g_quark_to_string(process
->state
->s
));
271 g_assert(FALSE
); /* UNKNOWN STATE */
278 /* Before try-wake-up hook. A process is being woken; we need to draw its line up to this point in time
279 in that colour. This is basically like exec-state, but the change applies to a process other than that
280 which is currently running. */
282 int before_trywakeup_hook(void *hook_data
, void *call_data
)
284 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
285 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
286 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
288 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
290 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
292 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
293 gint target_pid_saved
= tfc
->target_pid
;
295 LttTime evtime
= ltt_event_time(e
);
296 LttvFilter
*filter
= control_flow_data
->filter
;
301 woken_pid
= ltt_event_get_int(e
, lttv_trace_get_hook_field(th
, 0));
302 woken_cpu
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
304 tfc
->target_pid
= woken_pid
;
305 if(!filter
|| !filter
->head
||
306 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
307 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
309 /* First, check if the woken process is in the state computation
310 * process list. If it is there, that means we must add it right now and
311 * draw items from the beginning of the read for it. If it is not
312 * present, it's a new process and it was not present : it will
313 * be added after the state update. TOCHECK: What does that last para mean? */
314 guint trace_num
= ts
->parent
.index
;
315 LttvProcessState
*process
= lttv_state_find_process(ts
, woken_cpu
, woken_pid
);
317 if(process
!= NULL
) {
318 /* Well, the woken process existed : we must get it in the process hash
319 * or add it, and draw its items.
321 /* Add process to process list (if not present) */
323 HashedProcessData
*hashed_process_data
= NULL
;
324 ProcessList
*process_list
= control_flow_data
->process_list
;
325 LttTime birth
= process
->creation_time
;
327 hashed_process_data
= processlist_get_process_data(process_list
,
332 if(hashed_process_data
== NULL
)
334 g_assert(woken_pid
!= process
->ppid
);
335 /* Process not present */
336 ProcessInfo
*process_info
;
337 Drawing_t
*drawing
= control_flow_data
->drawing
;
338 processlist_add(process_list
,
350 &hashed_process_data
);
351 gtk_widget_set_size_request(drawing
->drawing_area
,
354 gtk_widget_queue_draw(drawing
->drawing_area
);
358 /* Now, the process is in the state hash and our own process hash.
359 * We definitely can draw the items related to the ending state.
362 if(ltt_time_compare(hashed_process_data
->next_good_time
,
365 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
367 TimeWindow time_window
=
368 lttvwindow_get_time_window(control_flow_data
->tab
);
370 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
371 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
374 Drawing_t
*drawing
= control_flow_data
->drawing
;
375 guint width
= drawing
->width
;
377 convert_time_to_pixels(
383 /* Draw collision indicator */
384 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
385 gdk_draw_point(hashed_process_data
->pixmap
,
388 COLLISION_POSITION(hashed_process_data
->height
));
389 hashed_process_data
->x
.middle_marked
= TRUE
;
392 TimeWindow time_window
=
393 lttvwindow_get_time_window(control_flow_data
->tab
);
395 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
396 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
399 Drawing_t
*drawing
= control_flow_data
->drawing
;
400 guint width
= drawing
->width
;
402 convert_time_to_pixels(
409 /* Jump over draw if we are at the same x position */
410 if(x
== hashed_process_data
->x
.middle
&&
411 hashed_process_data
->x
.middle_used
)
413 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
414 /* Draw collision indicator */
415 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
416 gdk_draw_point(hashed_process_data
->pixmap
,
419 COLLISION_POSITION(hashed_process_data
->height
));
420 hashed_process_data
->x
.middle_marked
= TRUE
;
424 DrawContext draw_context
;
426 /* Now create the drawing context that will be used to draw
427 * items related to the last state. */
428 draw_context
.drawable
= hashed_process_data
->pixmap
;
429 draw_context
.gc
= drawing
->gc
;
430 draw_context
.pango_layout
= drawing
->pango_layout
;
431 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
432 draw_context
.drawinfo
.end
.x
= x
;
434 draw_context
.drawinfo
.y
.over
= 1;
435 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
436 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
438 draw_context
.drawinfo
.start
.offset
.over
= 0;
439 draw_context
.drawinfo
.start
.offset
.middle
= 0;
440 draw_context
.drawinfo
.start
.offset
.under
= 0;
441 draw_context
.drawinfo
.end
.offset
.over
= 0;
442 draw_context
.drawinfo
.end
.offset
.middle
= 0;
443 draw_context
.drawinfo
.end
.offset
.under
= 0;
447 PropertiesLine prop_line
= prepare_s_e_line(process
);
448 draw_line((void*)&prop_line
, (void*)&draw_context
);
451 /* become the last x position */
452 hashed_process_data
->x
.middle
= x
;
453 hashed_process_data
->x
.middle_used
= TRUE
;
454 hashed_process_data
->x
.middle_marked
= FALSE
;
456 /* Calculate the next good time */
457 convert_pixels_to_time(width
, x
+1, time_window
,
458 &hashed_process_data
->next_good_time
);
464 tfc
->target_pid
= target_pid_saved
;
470 /* before_schedchange_hook
472 * This function basically draw lines and icons. Two types of lines are drawn :
473 * one small (3 pixels?) representing the state of the process and the second
474 * type is thicker (10 pixels?) representing on which CPU a process is running
475 * (and this only in running state).
477 * Extremums of the lines :
478 * x_min : time of the last event context for this process kept in memory.
479 * x_max : time of the current event.
480 * y : middle of the process in the process list. The process is found in the
481 * list, therefore is it's position in pixels.
483 * The choice of lines'color is defined by the context of the last event for this
488 int before_schedchange_hook(void *hook_data
, void *call_data
)
490 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
491 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
492 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
494 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
496 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
497 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
500 e
= ltt_tracefile_get_event(tfc
->tf
);
501 gint target_pid_saved
= tfc
->target_pid
;
503 LttTime evtime
= ltt_event_time(e
);
504 LttvFilter
*filter
= control_flow_data
->filter
;
506 /* we are in a schedchange, before the state update. We must draw the
507 * items corresponding to the state before it changes : now is the right
515 pid_out
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
516 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
517 state_out
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 2));
520 tfc
->target_pid
= pid_out
;
521 if(!filter
|| !filter
->head
||
522 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
523 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
524 /* For the pid_out */
525 /* First, check if the current process is in the state computation
526 * process list. If it is there, that means we must add it right now and
527 * draw items from the beginning of the read for it. If it is not
528 * present, it's a new process and it was not present : it will
529 * be added after the state update. */
530 guint cpu
= tfs
->cpu
;
531 guint trace_num
= ts
->parent
.index
;
532 LttvProcessState
*process
= ts
->running_process
[cpu
];
533 /* unknown state, bad current pid */
534 if(process
->pid
!= pid_out
)
535 process
= lttv_state_find_process(ts
,
538 if(process
!= NULL
) {
539 /* Well, the process_out existed : we must get it in the process hash
540 * or add it, and draw its items.
542 /* Add process to process list (if not present) */
544 HashedProcessData
*hashed_process_data
= NULL
;
545 ProcessList
*process_list
= control_flow_data
->process_list
;
546 LttTime birth
= process
->creation_time
;
548 hashed_process_data
= processlist_get_process_data(process_list
,
553 if(hashed_process_data
== NULL
)
555 g_assert(pid_out
== 0 || pid_out
!= process
->ppid
);
556 /* Process not present */
557 ProcessInfo
*process_info
;
558 Drawing_t
*drawing
= control_flow_data
->drawing
;
559 processlist_add(process_list
,
571 &hashed_process_data
);
572 gtk_widget_set_size_request(drawing
->drawing_area
,
575 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 tfc
->target_pid
= pid_in
;
686 if(!filter
|| !filter
->head
||
687 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
688 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
690 /* First, check if the current process is in the state computation
691 * process list. If it is there, that means we must add it right now and
692 * draw items from the beginning of the read for it. If it is not
693 * present, it's a new process and it was not present : it will
694 * be added after the state update. */
695 LttvProcessState
*process
;
696 process
= lttv_state_find_process(ts
,
698 guint trace_num
= ts
->parent
.index
;
700 if(process
!= NULL
) {
701 /* Well, the process existed : we must get it in the process hash
702 * or add it, and draw its items.
704 /* Add process to process list (if not present) */
706 HashedProcessData
*hashed_process_data
= NULL
;
707 ProcessList
*process_list
= control_flow_data
->process_list
;
708 LttTime birth
= process
->creation_time
;
710 hashed_process_data
= processlist_get_process_data(process_list
,
715 if(hashed_process_data
== NULL
)
717 g_assert(pid_in
== 0 || pid_in
!= process
->ppid
);
718 /* Process not present */
719 ProcessInfo
*process_info
;
720 Drawing_t
*drawing
= control_flow_data
->drawing
;
721 processlist_add(process_list
,
733 &hashed_process_data
);
734 gtk_widget_set_size_request(drawing
->drawing_area
,
737 gtk_widget_queue_draw(drawing
->drawing_area
);
740 //We could set the current process and hash here, but will be done
741 //by after schedchange hook
743 /* Now, the process is in the state hash and our own process hash.
744 * We definitely can draw the items related to the ending state.
747 if(ltt_time_compare(hashed_process_data
->next_good_time
,
750 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
752 TimeWindow time_window
=
753 lttvwindow_get_time_window(control_flow_data
->tab
);
755 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
756 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
759 Drawing_t
*drawing
= control_flow_data
->drawing
;
760 guint width
= drawing
->width
;
762 convert_time_to_pixels(
768 /* Draw collision indicator */
769 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
770 gdk_draw_point(hashed_process_data
->pixmap
,
773 COLLISION_POSITION(hashed_process_data
->height
));
774 hashed_process_data
->x
.middle_marked
= TRUE
;
777 TimeWindow time_window
=
778 lttvwindow_get_time_window(control_flow_data
->tab
);
780 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
781 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
784 Drawing_t
*drawing
= control_flow_data
->drawing
;
785 guint width
= drawing
->width
;
788 convert_time_to_pixels(
795 /* Jump over draw if we are at the same x position */
796 if(x
== hashed_process_data
->x
.middle
&&
797 hashed_process_data
->x
.middle_used
)
799 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
800 /* Draw collision indicator */
801 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
802 gdk_draw_point(hashed_process_data
->pixmap
,
805 COLLISION_POSITION(hashed_process_data
->height
));
806 hashed_process_data
->x
.middle_marked
= TRUE
;
810 DrawContext draw_context
;
812 /* Now create the drawing context that will be used to draw
813 * items related to the last state. */
814 draw_context
.drawable
= hashed_process_data
->pixmap
;
815 draw_context
.gc
= drawing
->gc
;
816 draw_context
.pango_layout
= drawing
->pango_layout
;
817 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
818 draw_context
.drawinfo
.end
.x
= x
;
820 draw_context
.drawinfo
.y
.over
= 1;
821 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
822 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
824 draw_context
.drawinfo
.start
.offset
.over
= 0;
825 draw_context
.drawinfo
.start
.offset
.middle
= 0;
826 draw_context
.drawinfo
.start
.offset
.under
= 0;
827 draw_context
.drawinfo
.end
.offset
.over
= 0;
828 draw_context
.drawinfo
.end
.offset
.middle
= 0;
829 draw_context
.drawinfo
.end
.offset
.under
= 0;
833 PropertiesLine prop_line
= prepare_s_e_line(process
);
834 draw_line((void*)&prop_line
, (void*)&draw_context
);
838 /* become the last x position */
839 hashed_process_data
->x
.middle
= x
;
840 hashed_process_data
->x
.middle_used
= TRUE
;
841 hashed_process_data
->x
.middle_marked
= FALSE
;
843 /* Calculate the next good time */
844 convert_pixels_to_time(width
, x
+1, time_window
,
845 &hashed_process_data
->next_good_time
);
849 g_warning("Cannot find pin_in in schedchange %u", pid_in
);
851 tfc
->target_pid
= target_pid_saved
;
859 GString
*string
= g_string_new("");;
860 gboolean field_names
= TRUE
, state
= TRUE
;
862 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
863 g_string_append_printf(string
,"\n");
866 g_string_append_printf(string
, " %s",
867 g_quark_to_string(tfs
->process
->state
->s
));
870 g_info("%s",string
->str
);
872 g_string_free(string
, TRUE
);
874 /* End of text dump */
879 /* after_schedchange_hook
881 * The draw after hook is called by the reading API to have a
882 * particular event drawn on the screen.
883 * @param hook_data ControlFlowData structure of the viewer.
884 * @param call_data Event context.
886 * This function adds items to be drawn in a queue for each process.
889 int after_schedchange_hook(void *hook_data
, void *call_data
)
891 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
892 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
893 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
895 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
897 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
899 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
902 e
= ltt_tracefile_get_event(tfc
->tf
);
904 LttvFilter
*filter
= control_flow_data
->filter
;
905 LttTime evtime
= ltt_event_time(e
);
907 /* Add process to process list (if not present) */
908 LttvProcessState
*process_in
;
911 HashedProcessData
*hashed_process_data_in
= NULL
;
913 ProcessList
*process_list
= control_flow_data
->process_list
;
918 pid_out
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
919 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
922 tfc
->target_pid
= pid_in
;
923 if(!filter
|| !filter
->head
||
924 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
925 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
926 /* Find process pid_in in the list... */
927 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
928 //process_in = tfs->process;
929 guint cpu
= tfs
->cpu
;
930 guint trace_num
= ts
->parent
.index
;
931 process_in
= ts
->running_process
[cpu
];
932 /* It should exist, because we are after the state update. */
934 g_assert(process_in
!= NULL
);
936 birth
= process_in
->creation_time
;
938 hashed_process_data_in
= processlist_get_process_data(process_list
,
943 if(hashed_process_data_in
== NULL
)
945 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
946 ProcessInfo
*process_info
;
947 Drawing_t
*drawing
= control_flow_data
->drawing
;
948 /* Process not present */
949 processlist_add(process_list
,
961 &hashed_process_data_in
);
962 gtk_widget_set_size_request(drawing
->drawing_area
,
965 gtk_widget_queue_draw(drawing
->drawing_area
);
967 /* Set the current process */
968 process_list
->current_hash_data
[trace_num
][process_in
->cpu
] =
969 hashed_process_data_in
;
971 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
974 TimeWindow time_window
=
975 lttvwindow_get_time_window(control_flow_data
->tab
);
978 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
979 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
982 Drawing_t
*drawing
= control_flow_data
->drawing
;
983 guint width
= drawing
->width
;
986 convert_time_to_pixels(
992 if(hashed_process_data_in
->x
.middle
!= new_x
) {
993 hashed_process_data_in
->x
.middle
= new_x
;
994 hashed_process_data_in
->x
.middle_used
= FALSE
;
995 hashed_process_data_in
->x
.middle_marked
= FALSE
;
1006 /* before_execmode_hook
1008 * This function basically draw lines and icons. Two types of lines are drawn :
1009 * one small (3 pixels?) representing the state of the process and the second
1010 * type is thicker (10 pixels?) representing on which CPU a process is running
1011 * (and this only in running state).
1013 * Extremums of the lines :
1014 * x_min : time of the last event context for this process kept in memory.
1015 * x_max : time of the current event.
1016 * y : middle of the process in the process list. The process is found in the
1017 * list, therefore is it's position in pixels.
1019 * The choice of lines'color is defined by the context of the last event for this
1024 int before_execmode_hook(void *hook_data
, void *call_data
)
1026 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1027 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1028 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1030 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1032 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1034 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1037 e
= ltt_tracefile_get_event(tfc
->tf
);
1039 LttvFilter
*filter
= control_flow_data
->filter
;
1040 if(filter
!= NULL
&& filter
->head
!= NULL
)
1041 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1042 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1045 LttTime evtime
= ltt_event_time(e
);
1047 /* we are in a execmode, before the state update. We must draw the
1048 * items corresponding to the state before it changes : now is the right
1052 //LttvProcessState *process = tfs->process;
1053 guint cpu
= tfs
->cpu
;
1054 guint trace_num
= ts
->parent
.index
;
1055 LttvProcessState
*process
= ts
->running_process
[cpu
];
1056 g_assert(process
!= NULL
);
1058 guint pid
= process
->pid
;
1060 /* Well, the process_out existed : we must get it in the process hash
1061 * or add it, and draw its items.
1063 /* Add process to process list (if not present) */
1064 guint pl_height
= 0;
1065 HashedProcessData
*hashed_process_data
= NULL
;
1066 ProcessList
*process_list
= control_flow_data
->process_list
;
1067 LttTime birth
= process
->creation_time
;
1069 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1070 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1072 hashed_process_data
= processlist_get_process_data(process_list
,
1077 if(unlikely(hashed_process_data
== NULL
))
1079 g_assert(pid
== 0 || pid
!= process
->ppid
);
1080 ProcessInfo
*process_info
;
1081 /* Process not present */
1082 Drawing_t
*drawing
= control_flow_data
->drawing
;
1083 processlist_add(process_list
,
1095 &hashed_process_data
);
1096 gtk_widget_set_size_request(drawing
->drawing_area
,
1099 gtk_widget_queue_draw(drawing
->drawing_area
);
1101 /* Set the current process */
1102 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1103 hashed_process_data
;
1106 /* Now, the process is in the state hash and our own process hash.
1107 * We definitely can draw the items related to the ending state.
1110 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1113 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1114 TimeWindow time_window
=
1115 lttvwindow_get_time_window(control_flow_data
->tab
);
1118 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1119 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1121 #endif //EXTRA_CHECK
1122 Drawing_t
*drawing
= control_flow_data
->drawing
;
1123 guint width
= drawing
->width
;
1125 convert_time_to_pixels(
1131 /* Draw collision indicator */
1132 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1133 gdk_draw_point(hashed_process_data
->pixmap
,
1136 COLLISION_POSITION(hashed_process_data
->height
));
1137 hashed_process_data
->x
.middle_marked
= TRUE
;
1140 TimeWindow time_window
=
1141 lttvwindow_get_time_window(control_flow_data
->tab
);
1144 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1145 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1147 #endif //EXTRA_CHECK
1148 Drawing_t
*drawing
= control_flow_data
->drawing
;
1149 guint width
= drawing
->width
;
1152 convert_time_to_pixels(
1159 /* Jump over draw if we are at the same x position */
1160 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1161 hashed_process_data
->x
.middle_used
))
1163 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1164 /* Draw collision indicator */
1165 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1166 gdk_draw_point(hashed_process_data
->pixmap
,
1169 COLLISION_POSITION(hashed_process_data
->height
));
1170 hashed_process_data
->x
.middle_marked
= TRUE
;
1175 DrawContext draw_context
;
1176 /* Now create the drawing context that will be used to draw
1177 * items related to the last state. */
1178 draw_context
.drawable
= hashed_process_data
->pixmap
;
1179 draw_context
.gc
= drawing
->gc
;
1180 draw_context
.pango_layout
= drawing
->pango_layout
;
1181 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1182 draw_context
.drawinfo
.end
.x
= x
;
1184 draw_context
.drawinfo
.y
.over
= 1;
1185 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1186 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1188 draw_context
.drawinfo
.start
.offset
.over
= 0;
1189 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1190 draw_context
.drawinfo
.start
.offset
.under
= 0;
1191 draw_context
.drawinfo
.end
.offset
.over
= 0;
1192 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1193 draw_context
.drawinfo
.end
.offset
.under
= 0;
1197 PropertiesLine prop_line
= prepare_s_e_line(process
);
1198 draw_line((void*)&prop_line
, (void*)&draw_context
);
1201 /* become the last x position */
1202 hashed_process_data
->x
.middle
= x
;
1203 hashed_process_data
->x
.middle_used
= TRUE
;
1204 hashed_process_data
->x
.middle_marked
= FALSE
;
1206 /* Calculate the next good time */
1207 convert_pixels_to_time(width
, x
+1, time_window
,
1208 &hashed_process_data
->next_good_time
);
1215 /* before_process_exit_hook
1217 * Draw lines for process event.
1219 * @param hook_data ControlFlowData structure of the viewer.
1220 * @param call_data Event context.
1222 * This function adds items to be drawn in a queue for each process.
1227 int before_process_exit_hook(void *hook_data
, void *call_data
)
1229 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1230 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1232 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1234 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1236 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1238 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1241 e
= ltt_tracefile_get_event(tfc
->tf
);
1243 LttvFilter
*filter
= control_flow_data
->filter
;
1244 if(filter
!= NULL
&& filter
->head
!= NULL
)
1245 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1246 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1249 LttTime evtime
= ltt_event_time(e
);
1251 /* Add process to process list (if not present) */
1252 //LttvProcessState *process = tfs->process;
1253 guint cpu
= tfs
->cpu
;
1254 guint trace_num
= ts
->parent
.index
;
1255 LttvProcessState
*process
= ts
->running_process
[cpu
];
1256 guint pid
= process
->pid
;
1258 guint pl_height
= 0;
1259 HashedProcessData
*hashed_process_data
= NULL
;
1261 ProcessList
*process_list
= control_flow_data
->process_list
;
1263 g_assert(process
!= NULL
);
1265 birth
= process
->creation_time
;
1267 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1268 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1270 hashed_process_data
= processlist_get_process_data(process_list
,
1275 if(unlikely(hashed_process_data
== NULL
))
1277 g_assert(pid
== 0 || pid
!= process
->ppid
);
1278 /* Process not present */
1279 Drawing_t
*drawing
= control_flow_data
->drawing
;
1280 ProcessInfo
*process_info
;
1281 processlist_add(process_list
,
1293 &hashed_process_data
);
1294 gtk_widget_set_size_request(drawing
->drawing_area
,
1297 gtk_widget_queue_draw(drawing
->drawing_area
);
1301 /* Now, the process is in the state hash and our own process hash.
1302 * We definitely can draw the items related to the ending state.
1305 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1308 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1309 TimeWindow time_window
=
1310 lttvwindow_get_time_window(control_flow_data
->tab
);
1313 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1314 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1316 #endif //EXTRA_CHECK
1317 Drawing_t
*drawing
= control_flow_data
->drawing
;
1318 guint width
= drawing
->width
;
1320 convert_time_to_pixels(
1326 /* Draw collision indicator */
1327 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1328 gdk_draw_point(hashed_process_data
->pixmap
,
1331 COLLISION_POSITION(hashed_process_data
->height
));
1332 hashed_process_data
->x
.middle_marked
= TRUE
;
1335 TimeWindow time_window
=
1336 lttvwindow_get_time_window(control_flow_data
->tab
);
1339 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1340 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1342 #endif //EXTRA_CHECK
1343 Drawing_t
*drawing
= control_flow_data
->drawing
;
1344 guint width
= drawing
->width
;
1347 convert_time_to_pixels(
1354 /* Jump over draw if we are at the same x position */
1355 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1356 hashed_process_data
->x
.middle_used
))
1358 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1359 /* Draw collision indicator */
1360 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1361 gdk_draw_point(hashed_process_data
->pixmap
,
1364 COLLISION_POSITION(hashed_process_data
->height
));
1365 hashed_process_data
->x
.middle_marked
= TRUE
;
1369 DrawContext draw_context
;
1371 /* Now create the drawing context that will be used to draw
1372 * items related to the last state. */
1373 draw_context
.drawable
= hashed_process_data
->pixmap
;
1374 draw_context
.gc
= drawing
->gc
;
1375 draw_context
.pango_layout
= drawing
->pango_layout
;
1376 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1377 draw_context
.drawinfo
.end
.x
= x
;
1379 draw_context
.drawinfo
.y
.over
= 1;
1380 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1381 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1383 draw_context
.drawinfo
.start
.offset
.over
= 0;
1384 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1385 draw_context
.drawinfo
.start
.offset
.under
= 0;
1386 draw_context
.drawinfo
.end
.offset
.over
= 0;
1387 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1388 draw_context
.drawinfo
.end
.offset
.under
= 0;
1392 PropertiesLine prop_line
= prepare_s_e_line(process
);
1393 draw_line((void*)&prop_line
, (void*)&draw_context
);
1396 /* become the last x position */
1397 hashed_process_data
->x
.middle
= x
;
1398 hashed_process_data
->x
.middle_used
= TRUE
;
1399 hashed_process_data
->x
.middle_marked
= FALSE
;
1401 /* Calculate the next good time */
1402 convert_pixels_to_time(width
, x
+1, time_window
,
1403 &hashed_process_data
->next_good_time
);
1413 /* before_process_release_hook
1415 * Draw lines for process event.
1417 * @param hook_data ControlFlowData structure of the viewer.
1418 * @param call_data Event context.
1420 * This function adds items to be drawn in a queue for each process.
1425 int before_process_release_hook(void *hook_data
, void *call_data
)
1427 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1428 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1430 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1432 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1434 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1437 e
= ltt_tracefile_get_event(tfc
->tf
);
1439 LttvFilter
*filter
= control_flow_data
->filter
;
1440 if(filter
!= NULL
&& filter
->head
!= NULL
)
1441 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1442 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1445 LttTime evtime
= ltt_event_time(e
);
1447 guint trace_num
= ts
->parent
.index
;
1451 pid
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
1454 /* Add process to process list (if not present) */
1455 /* Don't care about the process if it's not in the state hash already :
1456 * that means a process that has never done anything in the trace and
1457 * unknown suddently gets destroyed : no state meaningful to show. */
1458 LttvProcessState
*process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1460 if(process
!= NULL
) {
1462 HashedProcessData
*hashed_process_data
= NULL
;
1464 ProcessList
*process_list
= control_flow_data
->process_list
;
1466 birth
= process
->creation_time
;
1468 /* Cannot use current process : this event happens on another process,
1469 * action done by the parent. */
1470 hashed_process_data
= processlist_get_process_data(process_list
,
1475 if(unlikely(hashed_process_data
== NULL
))
1477 * Process already been scheduled out EXIT_DEAD, not in the process list
1478 * anymore. Just return.
1482 /* Now, the process is in the state hash and our own process hash.
1483 * We definitely can draw the items related to the ending state.
1486 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1489 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1490 TimeWindow time_window
=
1491 lttvwindow_get_time_window(control_flow_data
->tab
);
1494 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1495 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1497 #endif //EXTRA_CHECK
1498 Drawing_t
*drawing
= control_flow_data
->drawing
;
1499 guint width
= drawing
->width
;
1501 convert_time_to_pixels(
1507 /* Draw collision indicator */
1508 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1509 gdk_draw_point(hashed_process_data
->pixmap
,
1512 COLLISION_POSITION(hashed_process_data
->height
));
1513 hashed_process_data
->x
.middle_marked
= TRUE
;
1516 TimeWindow time_window
=
1517 lttvwindow_get_time_window(control_flow_data
->tab
);
1520 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1521 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1523 #endif //EXTRA_CHECK
1524 Drawing_t
*drawing
= control_flow_data
->drawing
;
1525 guint width
= drawing
->width
;
1528 convert_time_to_pixels(
1535 /* Jump over draw if we are at the same x position */
1536 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1537 hashed_process_data
->x
.middle_used
))
1539 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1540 /* Draw collision indicator */
1541 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1542 gdk_draw_point(hashed_process_data
->pixmap
,
1545 COLLISION_POSITION(hashed_process_data
->height
));
1546 hashed_process_data
->x
.middle_marked
= TRUE
;
1550 DrawContext draw_context
;
1552 /* Now create the drawing context that will be used to draw
1553 * items related to the last state. */
1554 draw_context
.drawable
= hashed_process_data
->pixmap
;
1555 draw_context
.gc
= drawing
->gc
;
1556 draw_context
.pango_layout
= drawing
->pango_layout
;
1557 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1558 draw_context
.drawinfo
.end
.x
= x
;
1560 draw_context
.drawinfo
.y
.over
= 1;
1561 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1562 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1564 draw_context
.drawinfo
.start
.offset
.over
= 0;
1565 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1566 draw_context
.drawinfo
.start
.offset
.under
= 0;
1567 draw_context
.drawinfo
.end
.offset
.over
= 0;
1568 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1569 draw_context
.drawinfo
.end
.offset
.under
= 0;
1573 PropertiesLine prop_line
= prepare_s_e_line(process
);
1574 draw_line((void*)&prop_line
, (void*)&draw_context
);
1577 /* become the last x position */
1578 hashed_process_data
->x
.middle
= x
;
1579 hashed_process_data
->x
.middle_used
= TRUE
;
1580 hashed_process_data
->x
.middle_marked
= FALSE
;
1582 /* Calculate the next good time */
1583 convert_pixels_to_time(width
, x
+1, time_window
,
1584 &hashed_process_data
->next_good_time
);
1596 /* after_process_fork_hook
1598 * Create the processlist entry for the child process. Put the last
1599 * position in x at the current time value.
1601 * @param hook_data ControlFlowData structure of the viewer.
1602 * @param call_data Event context.
1604 * This function adds items to be drawn in a queue for each process.
1607 int after_process_fork_hook(void *hook_data
, void *call_data
)
1609 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1610 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1611 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1613 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1615 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1618 e
= ltt_tracefile_get_event(tfc
->tf
);
1620 LttvFilter
*filter
= control_flow_data
->filter
;
1621 if(filter
!= NULL
&& filter
->head
!= NULL
)
1622 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1623 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1626 LttTime evtime
= ltt_event_time(e
);
1630 child_pid
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
1633 /* Add process to process list (if not present) */
1634 LttvProcessState
*process_child
;
1636 guint pl_height
= 0;
1637 HashedProcessData
*hashed_process_data_child
= NULL
;
1639 ProcessList
*process_list
= control_flow_data
->process_list
;
1641 /* Find child in the list... */
1642 process_child
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1643 /* It should exist, because we are after the state update. */
1644 g_assert(process_child
!= NULL
);
1646 birth
= process_child
->creation_time
;
1647 guint trace_num
= ts
->parent
.index
;
1649 /* Cannot use current process, because this action is done by the parent
1651 hashed_process_data_child
= processlist_get_process_data(process_list
,
1656 if(likely(hashed_process_data_child
== NULL
))
1658 g_assert(child_pid
== 0 || child_pid
!= process_child
->ppid
);
1659 /* Process not present */
1660 Drawing_t
*drawing
= control_flow_data
->drawing
;
1661 ProcessInfo
*process_info
;
1662 processlist_add(process_list
,
1665 process_child
->tgid
,
1667 process_child
->ppid
,
1670 process_child
->name
,
1671 process_child
->brand
,
1674 &hashed_process_data_child
);
1675 gtk_widget_set_size_request(drawing
->drawing_area
,
1678 gtk_widget_queue_draw(drawing
->drawing_area
);
1680 processlist_set_ppid(process_list
, process_child
->ppid
,
1681 hashed_process_data_child
);
1682 processlist_set_tgid(process_list
, process_child
->tgid
,
1683 hashed_process_data_child
);
1687 if(likely(ltt_time_compare(hashed_process_data_child
->next_good_time
,
1690 TimeWindow time_window
=
1691 lttvwindow_get_time_window(control_flow_data
->tab
);
1694 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1695 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1697 #endif //EXTRA_CHECK
1698 Drawing_t
*drawing
= control_flow_data
->drawing
;
1699 guint width
= drawing
->width
;
1701 convert_time_to_pixels(
1707 if(likely(hashed_process_data_child
->x
.over
!= new_x
)) {
1708 hashed_process_data_child
->x
.over
= new_x
;
1709 hashed_process_data_child
->x
.over_used
= FALSE
;
1710 hashed_process_data_child
->x
.over_marked
= FALSE
;
1712 if(likely(hashed_process_data_child
->x
.middle
!= new_x
)) {
1713 hashed_process_data_child
->x
.middle
= new_x
;
1714 hashed_process_data_child
->x
.middle_used
= FALSE
;
1715 hashed_process_data_child
->x
.middle_marked
= FALSE
;
1717 if(likely(hashed_process_data_child
->x
.under
!= new_x
)) {
1718 hashed_process_data_child
->x
.under
= new_x
;
1719 hashed_process_data_child
->x
.under_used
= FALSE
;
1720 hashed_process_data_child
->x
.under_marked
= FALSE
;
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 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1742 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1743 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1745 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1747 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1749 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1752 e
= ltt_tracefile_get_event(tfc
->tf
);
1754 LttvFilter
*filter
= control_flow_data
->filter
;
1755 if(filter
!= NULL
&& filter
->head
!= NULL
)
1756 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1757 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1760 LttTime evtime
= ltt_event_time(e
);
1762 /* Add process to process list (if not present) */
1763 //LttvProcessState *process = tfs->process;
1764 guint cpu
= tfs
->cpu
;
1765 guint trace_num
= ts
->parent
.index
;
1766 LttvProcessState
*process
= ts
->running_process
[cpu
];
1768 /* It should exist, because we are after the state update. */
1769 g_assert(process
!= NULL
);
1771 guint pid
= process
->pid
;
1773 guint pl_height
= 0;
1774 HashedProcessData
*hashed_process_data
= NULL
;
1776 ProcessList
*process_list
= control_flow_data
->process_list
;
1778 birth
= process
->creation_time
;
1780 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
) ){
1781 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1783 hashed_process_data
= processlist_get_process_data(process_list
,
1788 if(unlikely(hashed_process_data
== NULL
))
1790 g_assert(pid
== 0 || pid
!= process
->ppid
);
1791 /* Process not present */
1792 Drawing_t
*drawing
= control_flow_data
->drawing
;
1793 ProcessInfo
*process_info
;
1794 processlist_add(process_list
,
1806 &hashed_process_data
);
1807 gtk_widget_set_size_request(drawing
->drawing_area
,
1810 gtk_widget_queue_draw(drawing
->drawing_area
);
1813 /* Set the current process */
1814 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1815 hashed_process_data
;
1818 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
1821 TimeWindow time_window
=
1822 lttvwindow_get_time_window(control_flow_data
->tab
);
1825 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1826 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1828 #endif //EXTRA_CHECK
1829 Drawing_t
*drawing
= control_flow_data
->drawing
;
1830 guint width
= drawing
->width
;
1832 convert_time_to_pixels(
1837 if(unlikely(hashed_process_data
->x
.middle
!= new_x
)) {
1838 hashed_process_data
->x
.middle
= new_x
;
1839 hashed_process_data
->x
.middle_used
= FALSE
;
1840 hashed_process_data
->x
.middle_marked
= FALSE
;
1848 /* Get the filename of the process to print */
1849 int after_fs_exec_hook(void *hook_data
, void *call_data
)
1851 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1852 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1853 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1855 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1857 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1859 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1862 e
= ltt_tracefile_get_event(tfc
->tf
);
1864 LttvFilter
*filter
= control_flow_data
->filter
;
1865 if(filter
!= NULL
&& filter
->head
!= NULL
)
1866 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1867 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1870 guint cpu
= tfs
->cpu
;
1871 guint trace_num
= ts
->parent
.index
;
1872 LttvProcessState
*process
= ts
->running_process
[cpu
];
1873 g_assert(process
!= NULL
);
1875 guint pid
= process
->pid
;
1877 /* Well, the process_out existed : we must get it in the process hash
1878 * or add it, and draw its items.
1880 /* Add process to process list (if not present) */
1881 guint pl_height
= 0;
1882 HashedProcessData
*hashed_process_data
= NULL
;
1883 ProcessList
*process_list
= control_flow_data
->process_list
;
1884 LttTime birth
= process
->creation_time
;
1886 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1887 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1889 hashed_process_data
= processlist_get_process_data(process_list
,
1894 if(unlikely(hashed_process_data
== NULL
))
1896 g_assert(pid
== 0 || pid
!= process
->ppid
);
1897 ProcessInfo
*process_info
;
1898 /* Process not present */
1899 Drawing_t
*drawing
= control_flow_data
->drawing
;
1900 processlist_add(process_list
,
1912 &hashed_process_data
);
1913 gtk_widget_set_size_request(drawing
->drawing_area
,
1916 gtk_widget_queue_draw(drawing
->drawing_area
);
1918 /* Set the current process */
1919 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1920 hashed_process_data
;
1923 processlist_set_name(process_list
, process
->name
, hashed_process_data
);
1929 /* Get the filename of the process to print */
1930 int after_user_generic_thread_brand_hook(void *hook_data
, void *call_data
)
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
);
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 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2025 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
2026 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2028 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2030 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
2032 guint first_cpu
, nb_cpus
, cpu
;
2035 e
= ltt_tracefile_get_event(tfc
->tf
);
2037 LttvFilter
*filter
= control_flow_data
->filter
;
2038 if(filter
!= NULL
&& filter
->head
!= NULL
)
2039 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2040 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2043 /* Add process to process list (if not present) */
2044 LttvProcessState
*process_in
;
2046 guint pl_height
= 0;
2047 HashedProcessData
*hashed_process_data_in
= NULL
;
2049 ProcessList
*process_list
= control_flow_data
->process_list
;
2050 guint trace_num
= ts
->parent
.index
;
2054 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2059 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2061 first_cpu
= ANY_CPU
;
2062 nb_cpus
= ANY_CPU
+1;
2065 for(cpu
= first_cpu
; cpu
< nb_cpus
; cpu
++) {
2066 /* Find process pid_in in the list... */
2067 process_in
= lttv_state_find_process(ts
, cpu
, pid_in
);
2068 //process_in = tfs->process;
2069 //guint cpu = tfs->cpu;
2070 //guint trace_num = ts->parent.index;
2071 //process_in = ts->running_process[cpu];
2072 /* It should exist, because we are after the state update. */
2074 //g_assert(process_in != NULL);
2075 #endif //EXTRA_CHECK
2076 birth
= process_in
->creation_time
;
2078 hashed_process_data_in
= processlist_get_process_data(process_list
,
2083 if(hashed_process_data_in
== NULL
)
2085 if(pid_in
!= 0 && pid_in
== process_in
->ppid
)
2086 g_critical("TEST %u , %u", pid_in
, process_in
->ppid
);
2087 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
2088 ProcessInfo
*process_info
;
2089 Drawing_t
*drawing
= control_flow_data
->drawing
;
2090 /* Process not present */
2091 processlist_add(process_list
,
2103 &hashed_process_data_in
);
2104 gtk_widget_set_size_request(drawing
->drawing_area
,
2107 gtk_widget_queue_draw(drawing
->drawing_area
);
2109 processlist_set_name(process_list
, process_in
->name
,
2110 hashed_process_data_in
);
2111 processlist_set_ppid(process_list
, process_in
->ppid
,
2112 hashed_process_data_in
);
2113 processlist_set_tgid(process_list
, process_in
->tgid
,
2114 hashed_process_data_in
);
2121 gint
update_time_window_hook(void *hook_data
, void *call_data
)
2123 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2124 Drawing_t
*drawing
= control_flow_data
->drawing
;
2125 ProcessList
*process_list
= control_flow_data
->process_list
;
2127 const TimeWindowNotifyData
*time_window_nofify_data
=
2128 ((const TimeWindowNotifyData
*)call_data
);
2130 TimeWindow
*old_time_window
=
2131 time_window_nofify_data
->old_time_window
;
2132 TimeWindow
*new_time_window
=
2133 time_window_nofify_data
->new_time_window
;
2135 /* Update the ruler */
2136 drawing_update_ruler(control_flow_data
->drawing
,
2140 /* Two cases : zoom in/out or scrolling */
2142 /* In order to make sure we can reuse the old drawing, the scale must
2143 * be the same and the new time interval being partly located in the
2144 * currently shown time interval. (reuse is only for scrolling)
2147 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
2148 old_time_window
->start_time
.tv_sec
,
2149 old_time_window
->start_time
.tv_nsec
,
2150 old_time_window
->time_width
.tv_sec
,
2151 old_time_window
->time_width
.tv_nsec
);
2153 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
2154 new_time_window
->start_time
.tv_sec
,
2155 new_time_window
->start_time
.tv_nsec
,
2156 new_time_window
->time_width
.tv_sec
,
2157 new_time_window
->time_width
.tv_nsec
);
2159 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
2160 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
2162 /* Same scale (scrolling) */
2163 g_info("scrolling");
2164 LttTime
*ns
= &new_time_window
->start_time
;
2165 LttTime
*os
= &old_time_window
->start_time
;
2166 LttTime old_end
= old_time_window
->end_time
;
2167 LttTime new_end
= new_time_window
->end_time
;
2169 //if(ns<os+w && os+w<ns+w)
2170 //if(ns<old_end && os<ns)
2171 if(ltt_time_compare(*ns
, old_end
) == -1
2172 && ltt_time_compare(*os
, *ns
) == -1)
2174 g_info("scrolling near right");
2175 /* Scroll right, keep right part of the screen */
2177 guint width
= control_flow_data
->drawing
->width
;
2178 convert_time_to_pixels(
2184 /* Copy old data to new location */
2185 copy_pixmap_region(process_list
,
2187 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2191 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
2193 if(drawing
->damage_begin
== drawing
->damage_end
)
2194 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
2196 drawing
->damage_begin
= 0;
2198 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2200 /* Clear the data request background, but not SAFETY */
2201 rectangle_pixmap(process_list
,
2202 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2204 drawing
->damage_begin
+SAFETY
, 0,
2205 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2207 gtk_widget_queue_draw(drawing
->drawing_area
);
2208 //gtk_widget_queue_draw_area (drawing->drawing_area,
2210 // control_flow_data->drawing->width,
2211 // control_flow_data->drawing->height);
2213 /* Get new data for the rest. */
2214 drawing_data_request(control_flow_data
->drawing
,
2215 drawing
->damage_begin
, 0,
2216 drawing
->damage_end
- drawing
->damage_begin
,
2217 control_flow_data
->drawing
->height
);
2220 //if(ns<os && os<ns+w)
2221 //if(ns<os && os<new_end)
2222 if(ltt_time_compare(*ns
,*os
) == -1
2223 && ltt_time_compare(*os
,new_end
) == -1)
2225 g_info("scrolling near left");
2226 /* Scroll left, keep left part of the screen */
2228 guint width
= control_flow_data
->drawing
->width
;
2229 convert_time_to_pixels(
2235 /* Copy old data to new location */
2236 copy_pixmap_region (process_list
,
2238 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2244 if(drawing
->damage_begin
== drawing
->damage_end
)
2245 drawing
->damage_end
= x
;
2247 drawing
->damage_end
=
2248 control_flow_data
->drawing
->width
;
2250 drawing
->damage_begin
= 0;
2252 rectangle_pixmap (process_list
,
2253 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2255 drawing
->damage_begin
, 0,
2256 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2259 gtk_widget_queue_draw(drawing
->drawing_area
);
2260 //gtk_widget_queue_draw_area (drawing->drawing_area,
2262 // control_flow_data->drawing->width,
2263 // control_flow_data->drawing->height);
2266 /* Get new data for the rest. */
2267 drawing_data_request(control_flow_data
->drawing
,
2268 drawing
->damage_begin
, 0,
2269 drawing
->damage_end
- drawing
->damage_begin
,
2270 control_flow_data
->drawing
->height
);
2273 if(ltt_time_compare(*ns
,*os
) == 0)
2275 g_info("not scrolling");
2277 g_info("scrolling far");
2278 /* Cannot reuse any part of the screen : far jump */
2281 rectangle_pixmap (process_list
,
2282 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2285 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2288 //gtk_widget_queue_draw_area (drawing->drawing_area,
2290 // control_flow_data->drawing->width,
2291 // control_flow_data->drawing->height);
2292 gtk_widget_queue_draw(drawing
->drawing_area
);
2294 drawing
->damage_begin
= 0;
2295 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2297 drawing_data_request(control_flow_data
->drawing
,
2299 control_flow_data
->drawing
->width
,
2300 control_flow_data
->drawing
->height
);
2306 /* Different scale (zoom) */
2309 rectangle_pixmap (process_list
,
2310 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2313 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2316 //gtk_widget_queue_draw_area (drawing->drawing_area,
2318 // control_flow_data->drawing->width,
2319 // control_flow_data->drawing->height);
2320 gtk_widget_queue_draw(drawing
->drawing_area
);
2322 drawing
->damage_begin
= 0;
2323 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2325 drawing_data_request(control_flow_data
->drawing
,
2327 control_flow_data
->drawing
->width
,
2328 control_flow_data
->drawing
->height
);
2331 /* Update directly when scrolling */
2332 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2338 gint
traceset_notify(void *hook_data
, void *call_data
)
2340 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2341 Drawing_t
*drawing
= control_flow_data
->drawing
;
2343 if(unlikely(drawing
->gc
== NULL
)) {
2346 if(drawing
->dotted_gc
== NULL
) {
2350 drawing_clear(control_flow_data
->drawing
);
2351 processlist_clear(control_flow_data
->process_list
);
2352 gtk_widget_set_size_request(
2353 control_flow_data
->drawing
->drawing_area
,
2354 -1, processlist_get_height(control_flow_data
->process_list
));
2355 redraw_notify(control_flow_data
, NULL
);
2357 request_background_data(control_flow_data
);
2362 gint
redraw_notify(void *hook_data
, void *call_data
)
2364 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2365 Drawing_t
*drawing
= control_flow_data
->drawing
;
2366 GtkWidget
*widget
= drawing
->drawing_area
;
2368 drawing
->damage_begin
= 0;
2369 drawing
->damage_end
= drawing
->width
;
2371 /* fun feature, to be separated someday... */
2372 drawing_clear(control_flow_data
->drawing
);
2373 processlist_clear(control_flow_data
->process_list
);
2374 gtk_widget_set_size_request(
2375 control_flow_data
->drawing
->drawing_area
,
2376 -1, processlist_get_height(control_flow_data
->process_list
));
2378 rectangle_pixmap (control_flow_data
->process_list
,
2379 widget
->style
->black_gc
,
2382 drawing
->alloc_width
,
2385 gtk_widget_queue_draw(drawing
->drawing_area
);
2387 if(drawing
->damage_begin
< drawing
->damage_end
)
2389 drawing_data_request(drawing
,
2390 drawing
->damage_begin
,
2392 drawing
->damage_end
-drawing
->damage_begin
,
2396 //gtk_widget_queue_draw_area(drawing->drawing_area,
2399 // drawing->height);
2405 gint
continue_notify(void *hook_data
, void *call_data
)
2407 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2408 Drawing_t
*drawing
= control_flow_data
->drawing
;
2410 //g_assert(widget->allocation.width == drawing->damage_end);
2412 if(drawing
->damage_begin
< drawing
->damage_end
)
2414 drawing_data_request(drawing
,
2415 drawing
->damage_begin
,
2417 drawing
->damage_end
-drawing
->damage_begin
,
2425 gint
update_current_time_hook(void *hook_data
, void *call_data
)
2427 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
2429 LttTime current_time
= *((LttTime
*)call_data
);
2431 TimeWindow time_window
=
2432 lttvwindow_get_time_window(control_flow_data
->tab
);
2434 LttTime time_begin
= time_window
.start_time
;
2435 LttTime width
= time_window
.time_width
;
2438 guint64 time_ll
= ltt_time_to_uint64(width
);
2439 time_ll
= time_ll
>> 1; /* divide by two */
2440 half_width
= ltt_time_from_uint64(time_ll
);
2442 LttTime time_end
= ltt_time_add(time_begin
, width
);
2444 LttvTracesetContext
* tsc
=
2445 lttvwindow_get_traceset_context(control_flow_data
->tab
);
2447 LttTime trace_start
= tsc
->time_span
.start_time
;
2448 LttTime trace_end
= tsc
->time_span
.end_time
;
2450 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
2451 current_time
.tv_nsec
);
2455 /* If current time is inside time interval, just move the highlight
2458 /* Else, we have to change the time interval. We have to tell it
2459 * to the main window. */
2460 /* The time interval change will take care of placing the current
2461 * time at the center of the visible area, or nearest possible if we are
2462 * at one end of the trace. */
2465 if(ltt_time_compare(current_time
, time_begin
) < 0)
2467 TimeWindow new_time_window
;
2469 if(ltt_time_compare(current_time
,
2470 ltt_time_add(trace_start
,half_width
)) < 0)
2471 time_begin
= trace_start
;
2473 time_begin
= ltt_time_sub(current_time
,half_width
);
2475 new_time_window
.start_time
= time_begin
;
2476 new_time_window
.time_width
= width
;
2477 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2478 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2480 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2482 else if(ltt_time_compare(current_time
, time_end
) > 0)
2484 TimeWindow new_time_window
;
2486 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
2487 time_begin
= ltt_time_sub(trace_end
,width
);
2489 time_begin
= ltt_time_sub(current_time
,half_width
);
2491 new_time_window
.start_time
= time_begin
;
2492 new_time_window
.time_width
= width
;
2493 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2494 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2496 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2499 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2501 /* Update directly when scrolling */
2502 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2508 typedef struct _ClosureData
{
2509 EventsRequest
*events_request
;
2510 LttvTracesetState
*tss
;
2516 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
2518 ProcessInfo
*process_info
= (ProcessInfo
*)key
;
2519 HashedProcessData
*hashed_process_data
= (HashedProcessData
*)value
;
2520 ClosureData
*closure_data
= (ClosureData
*)user_data
;
2522 EventsRequest
*events_request
= closure_data
->events_request
;
2523 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2525 LttvTracesetState
*tss
= closure_data
->tss
;
2526 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)tss
;
2528 LttTime evtime
= closure_data
->end_time
;
2530 gboolean dodraw
= TRUE
;
2533 /* For the process */
2534 /* First, check if the current process is in the state computation
2535 * process list. If it is there, that means we must add it right now and
2536 * draw items from the beginning of the read for it. If it is not
2537 * present, it's a new process and it was not present : it will
2538 * be added after the state update. */
2540 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
2541 #endif //EXTRA_CHECK
2542 LttvTraceContext
*tc
= tsc
->traces
[process_info
->trace_num
];
2543 LttvTraceState
*ts
= (LttvTraceState
*)tc
;
2546 //FIXME : optimize data structures.
2547 LttvTracefileState
*tfs
;
2548 LttvTracefileContext
*tfc
;
2550 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
2551 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
2552 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
2553 && tfs
->cpu
== process_info
->cpu
)
2557 g_assert(i
<tc
->tracefiles
->len
);
2558 tfs
= LTTV_TRACEFILE_STATE(tfc
);
2560 // LttvTracefileState *tfs =
2561 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2562 // tracefiles[process_info->cpu];
2564 LttvProcessState
*process
;
2565 process
= lttv_state_find_process(ts
, process_info
->cpu
,
2568 if(unlikely(process
!= NULL
)) {
2570 LttvFilter
*filter
= control_flow_data
->filter
;
2571 if(filter
!= NULL
&& filter
->head
!= NULL
)
2572 if(!lttv_filter_tree_parse(filter
->head
,NULL
,NULL
,
2573 tc
->t
,NULL
,process
,tc
))
2576 /* Only draw for processes that are currently in the trace states */
2579 /* Should be alike when background info is ready */
2580 if(control_flow_data
->background_info_waiting
==0)
2581 g_assert(ltt_time_compare(process
->creation_time
,
2582 process_info
->birth
) == 0);
2583 #endif //EXTRA_CHECK
2585 /* Now, the process is in the state hash and our own process hash.
2586 * We definitely can draw the items related to the ending state.
2589 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2592 TimeWindow time_window
=
2593 lttvwindow_get_time_window(control_flow_data
->tab
);
2596 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2597 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2599 #endif //EXTRA_CHECK
2600 Drawing_t
*drawing
= control_flow_data
->drawing
;
2601 guint width
= drawing
->width
;
2603 guint x
= closure_data
->x_end
;
2605 DrawContext draw_context
;
2607 /* Now create the drawing context that will be used to draw
2608 * items related to the last state. */
2609 draw_context
.drawable
= hashed_process_data
->pixmap
;
2610 draw_context
.gc
= drawing
->gc
;
2611 draw_context
.pango_layout
= drawing
->pango_layout
;
2612 draw_context
.drawinfo
.end
.x
= x
;
2614 draw_context
.drawinfo
.y
.over
= 1;
2615 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2616 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2618 draw_context
.drawinfo
.start
.offset
.over
= 0;
2619 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2620 draw_context
.drawinfo
.start
.offset
.under
= 0;
2621 draw_context
.drawinfo
.end
.offset
.over
= 0;
2622 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2623 draw_context
.drawinfo
.end
.offset
.under
= 0;
2625 /* Jump over draw if we are at the same x position */
2626 if(x
== hashed_process_data
->x
.over
)
2630 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2632 PropertiesLine prop_line
= prepare_execmode_line(process
);
2633 draw_line((void*)&prop_line
, (void*)&draw_context
);
2635 hashed_process_data
->x
.over
= x
;
2639 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2640 hashed_process_data
->x
.middle_used
)) {
2641 #if 0 /* do not mark closure : not missing information */
2642 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2643 /* Draw collision indicator */
2644 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2645 gdk_draw_point(drawing
->pixmap
,
2649 hashed_process_data
->x
.middle_marked
= TRUE
;
2654 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2657 PropertiesLine prop_line
= prepare_s_e_line(process
);
2658 draw_line((void*)&prop_line
, (void*)&draw_context
);
2661 /* become the last x position */
2662 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2663 hashed_process_data
->x
.middle
= x
;
2664 /* but don't use the pixel */
2665 hashed_process_data
->x
.middle_used
= FALSE
;
2667 /* Calculate the next good time */
2668 convert_pixels_to_time(width
, x
+1, time_window
,
2669 &hashed_process_data
->next_good_time
);
2678 int before_chunk(void *hook_data
, void *call_data
)
2680 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2681 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2683 /* Desactivate sort */
2684 gtk_tree_sortable_set_sort_column_id(
2685 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2687 GTK_SORT_ASCENDING
);
2689 drawing_chunk_begin(events_request
, tss
);
2694 int before_request(void *hook_data
, void *call_data
)
2696 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2697 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2699 drawing_data_request_begin(events_request
, tss
);
2706 * after request is necessary in addition of after chunk in order to draw
2707 * lines until the end of the screen. after chunk just draws lines until
2714 int after_request(void *hook_data
, void *call_data
)
2716 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2717 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2718 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2720 ProcessList
*process_list
= control_flow_data
->process_list
;
2721 LttTime end_time
= events_request
->end_time
;
2723 ClosureData closure_data
;
2724 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2725 closure_data
.tss
= tss
;
2726 closure_data
.end_time
= end_time
;
2728 TimeWindow time_window
=
2729 lttvwindow_get_time_window(control_flow_data
->tab
);
2730 guint width
= control_flow_data
->drawing
->width
;
2731 convert_time_to_pixels(
2735 &closure_data
.x_end
);
2738 /* Draw last items */
2739 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2740 (void*)&closure_data
);
2743 /* Request expose */
2744 drawing_request_expose(events_request
, tss
, end_time
);
2753 int after_chunk(void *hook_data
, void *call_data
)
2755 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2756 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2757 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2758 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)call_data
;
2759 LttvTracefileContext
*tfc
= lttv_traceset_context_get_current_tfc(tsc
);
2762 ProcessList
*process_list
= control_flow_data
->process_list
;
2764 LttvTraceset
*traceset
= tsc
->ts
;
2765 guint nb_trace
= lttv_traceset_number(traceset
);
2767 /* Only execute when called for the first trace's events request */
2768 if(!process_list
->current_hash_data
)
2771 for(i
= 0 ; i
< nb_trace
; i
++) {
2772 g_free(process_list
->current_hash_data
[i
]);
2774 g_free(process_list
->current_hash_data
);
2775 process_list
->current_hash_data
= NULL
;
2778 end_time
= LTT_TIME_MIN(tfc
->timestamp
, events_request
->end_time
);
2779 else /* end of traceset, or position now out of request : end */
2780 end_time
= events_request
->end_time
;
2782 ClosureData closure_data
;
2783 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2784 closure_data
.tss
= tss
;
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) */
2811 drawing_request_expose(events_request
, tss
, 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 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2827 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
2828 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2830 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2832 LttvTracesetState
*tss
= (LttvTracesetState
*)tfc
->t_context
->ts_context
;
2833 ProcessList
*process_list
= control_flow_data
->process_list
;
2836 e
= ltt_tracefile_get_event(tfc
->tf
);
2838 LttvFilter
*filter
= control_flow_data
->filter
;
2839 if(filter
!= NULL
&& filter
->head
!= NULL
)
2840 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2841 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2844 LttTime evtime
= ltt_event_time(e
);
2846 ClosureData closure_data
;
2847 closure_data
.events_request
= events_request
;
2848 closure_data
.tss
= tss
;
2849 closure_data
.end_time
= evtime
;
2851 TimeWindow time_window
=
2852 lttvwindow_get_time_window(control_flow_data
->tab
);
2853 guint width
= control_flow_data
->drawing
->width
;
2854 convert_time_to_pixels(
2858 &closure_data
.x_end
);
2860 /* Draw last items */
2861 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2862 (void*)&closure_data
);
2864 /* Reactivate sort */
2865 gtk_tree_sortable_set_sort_column_id(
2866 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2867 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2868 GTK_SORT_ASCENDING
);
2870 update_index_to_pixmap(control_flow_data
->process_list
);
2871 /* Request a full expose : drawing scrambled */
2872 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2874 /* Request expose (updates damages zone also) */
2875 drawing_request_expose(events_request
, tss
, evtime
);