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
;
95 LttvTrace
*trace
= (LttvTrace
*)call_data
;
97 control_flow_data
->background_info_waiting
--;
99 if(control_flow_data
->background_info_waiting
== 0) {
100 g_message("control flow viewer : background computation data ready.");
102 drawing_clear(control_flow_data
->drawing
);
103 processlist_clear(control_flow_data
->process_list
);
104 gtk_widget_set_size_request(
105 control_flow_data
->drawing
->drawing_area
,
106 -1, processlist_get_height(control_flow_data
->process_list
));
107 redraw_notify(control_flow_data
, NULL
);
114 /* Request background computation. Verify if it is in progress or ready first.
115 * Only for each trace in the tab's traceset.
117 static void request_background_data(ControlFlowData
*control_flow_data
)
119 LttvTracesetContext
* tsc
=
120 lttvwindow_get_traceset_context(control_flow_data
->tab
);
121 gint num_traces
= lttv_traceset_number(tsc
->ts
);
124 LttvTraceState
*tstate
;
126 LttvHooks
*background_ready_hook
=
128 lttv_hooks_add(background_ready_hook
, background_ready
, control_flow_data
,
130 control_flow_data
->background_info_waiting
= 0;
132 for(i
=0;i
<num_traces
;i
++) {
133 trace
= lttv_traceset_get(tsc
->ts
, i
);
134 tstate
= LTTV_TRACE_STATE(tsc
->traces
[i
]);
136 if(lttvwindowtraces_get_ready(g_quark_from_string("state"),trace
)==FALSE
137 && !tstate
->has_precomputed_states
) {
139 if(lttvwindowtraces_get_in_progress(g_quark_from_string("state"),
141 /* We first remove requests that could have been done for the same
142 * information. Happens when two viewers ask for it before servicing
145 if(!lttvwindowtraces_background_request_find(trace
, "state"))
146 lttvwindowtraces_background_request_queue(
147 main_window_get_widget(control_flow_data
->tab
), trace
, "state");
148 lttvwindowtraces_background_notify_queue(control_flow_data
,
152 background_ready_hook
);
153 control_flow_data
->background_info_waiting
++;
154 } else { /* in progress */
156 lttvwindowtraces_background_notify_current(control_flow_data
,
160 background_ready_hook
);
161 control_flow_data
->background_info_waiting
++;
164 /* Data ready. By its nature, this viewer doesn't need to have
165 * its data ready hook called there, because a background
166 * request is always linked with a redraw.
172 lttv_hooks_destroy(background_ready_hook
);
179 * Event Viewer's constructor hook
181 * This constructor is given as a parameter to the menuitem and toolbar button
182 * registration. It creates the list.
183 * @param tab A pointer to the parent tab.
184 * @return The widget created.
187 h_guicontrolflow(LttvPlugin
*plugin
)
189 LttvPluginTab
*ptab
= LTTV_PLUGIN_TAB(plugin
);
190 Tab
*tab
= ptab
->tab
;
191 g_info("h_guicontrolflow, %p", tab
);
192 ControlFlowData
*control_flow_data
= guicontrolflow(ptab
);
194 control_flow_data
->tab
= tab
;
196 // Unreg done in the GuiControlFlow_Destructor
197 lttvwindow_register_traceset_notify(tab
,
201 lttvwindow_register_time_window_notify(tab
,
202 update_time_window_hook
,
204 lttvwindow_register_current_time_notify(tab
,
205 update_current_time_hook
,
207 lttvwindow_register_redraw_notify(tab
,
210 lttvwindow_register_continue_notify(tab
,
213 request_background_data(control_flow_data
);
216 return guicontrolflow_get_widget(control_flow_data
) ;
220 int event_selected_hook(void *hook_data
, void *call_data
)
222 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
223 guint
*event_number
= (guint
*) call_data
;
225 g_debug("DEBUG : event selected by main window : %u", *event_number
);
230 /* Function that selects the color of status&exemode line */
231 static inline PropertiesLine
prepare_s_e_line(LttvProcessState
*process
)
233 PropertiesLine prop_line
;
234 prop_line
.line_width
= STATE_LINE_WIDTH
;
235 prop_line
.style
= GDK_LINE_SOLID
;
236 prop_line
.y
= MIDDLE
;
237 //GdkColormap *colormap = gdk_colormap_get_system();
239 if(process
->state
->s
== LTTV_STATE_RUN
) {
240 if(process
->state
->t
== LTTV_STATE_USER_MODE
)
241 prop_line
.color
= drawing_colors
[COL_RUN_USER_MODE
];
242 else if(process
->state
->t
== LTTV_STATE_SYSCALL
)
243 prop_line
.color
= drawing_colors
[COL_RUN_SYSCALL
];
244 else if(process
->state
->t
== LTTV_STATE_TRAP
)
245 prop_line
.color
= drawing_colors
[COL_RUN_TRAP
];
246 else if(process
->state
->t
== LTTV_STATE_IRQ
)
247 prop_line
.color
= drawing_colors
[COL_RUN_IRQ
];
248 else if(process
->state
->t
== LTTV_STATE_SOFT_IRQ
)
249 prop_line
.color
= drawing_colors
[COL_RUN_SOFT_IRQ
];
250 else if(process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
)
251 prop_line
.color
= drawing_colors
[COL_MODE_UNKNOWN
];
253 g_assert(FALSE
); /* RUNNING MODE UNKNOWN */
254 } else if(process
->state
->s
== LTTV_STATE_WAIT
) {
255 /* We don't show if we wait while in user mode, trap, irq or syscall */
256 prop_line
.color
= drawing_colors
[COL_WAIT
];
257 } else if(process
->state
->s
== LTTV_STATE_WAIT_CPU
) {
258 /* We don't show if we wait for CPU while in user mode, trap, irq
260 prop_line
.color
= drawing_colors
[COL_WAIT_CPU
];
261 } else if(process
->state
->s
== LTTV_STATE_ZOMBIE
) {
262 prop_line
.color
= drawing_colors
[COL_ZOMBIE
];
263 } else if(process
->state
->s
== LTTV_STATE_WAIT_FORK
) {
264 prop_line
.color
= drawing_colors
[COL_WAIT_FORK
];
265 } else if(process
->state
->s
== LTTV_STATE_EXIT
) {
266 prop_line
.color
= drawing_colors
[COL_EXIT
];
267 } else if(process
->state
->s
== LTTV_STATE_UNNAMED
) {
268 prop_line
.color
= drawing_colors
[COL_UNNAMED
];
269 } else if(process
->state
->s
== LTTV_STATE_DEAD
) {
270 prop_line
.color
= drawing_colors
[COL_DEAD
];
272 g_critical("unknown state : %s", g_quark_to_string(process
->state
->s
));
273 g_assert(FALSE
); /* UNKNOWN STATE */
280 /* Before try-wake-up hook. A process is being woken; we need to draw its line up to this point in time
281 in that colour. This is basically like exec-state, but the change applies to a process other than that
282 which is currently running. */
284 int before_trywakeup_hook(void *hook_data
, void *call_data
)
286 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
287 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
288 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
290 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
292 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
293 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
295 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
296 gint target_pid_saved
= tfc
->target_pid
;
298 LttTime evtime
= ltt_event_time(e
);
299 LttvFilter
*filter
= control_flow_data
->filter
;
304 woken_pid
= ltt_event_get_int(e
, lttv_trace_get_hook_field(th
, 0));
305 woken_cpu
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
307 tfc
->target_pid
= woken_pid
;
308 if(!filter
|| !filter
->head
||
309 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
310 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
312 /* First, check if the woken process is in the state computation
313 * process list. If it is there, that means we must add it right now and
314 * draw items from the beginning of the read for it. If it is not
315 * present, it's a new process and it was not present : it will
316 * be added after the state update. TOCHECK: What does that last para mean? */
317 guint cpu
= tfs
->cpu
;
318 guint trace_num
= ts
->parent
.index
;
319 LttvProcessState
*process
= lttv_state_find_process(ts
, woken_cpu
, woken_pid
);
321 if(process
!= NULL
) {
322 /* Well, the woken process existed : we must get it in the process hash
323 * or add it, and draw its items.
325 /* Add process to process list (if not present) */
327 HashedProcessData
*hashed_process_data
= NULL
;
328 ProcessList
*process_list
= control_flow_data
->process_list
;
329 LttTime birth
= process
->creation_time
;
331 hashed_process_data
= processlist_get_process_data(process_list
,
336 if(hashed_process_data
== NULL
)
338 g_assert(woken_pid
!= process
->ppid
);
339 /* Process not present */
340 ProcessInfo
*process_info
;
341 Drawing_t
*drawing
= control_flow_data
->drawing
;
342 processlist_add(process_list
,
354 &hashed_process_data
);
355 gtk_widget_set_size_request(drawing
->drawing_area
,
358 gtk_widget_queue_draw(drawing
->drawing_area
);
362 /* Now, the process is in the state hash and our own process hash.
363 * We definitely can draw the items related to the ending state.
366 if(ltt_time_compare(hashed_process_data
->next_good_time
,
369 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
371 TimeWindow time_window
=
372 lttvwindow_get_time_window(control_flow_data
->tab
);
374 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
375 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
378 Drawing_t
*drawing
= control_flow_data
->drawing
;
379 guint width
= drawing
->width
;
381 convert_time_to_pixels(
387 /* Draw collision indicator */
388 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
389 gdk_draw_point(hashed_process_data
->pixmap
,
392 COLLISION_POSITION(hashed_process_data
->height
));
393 hashed_process_data
->x
.middle_marked
= TRUE
;
396 TimeWindow time_window
=
397 lttvwindow_get_time_window(control_flow_data
->tab
);
399 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
400 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
403 Drawing_t
*drawing
= control_flow_data
->drawing
;
404 guint width
= drawing
->width
;
406 convert_time_to_pixels(
413 /* Jump over draw if we are at the same x position */
414 if(x
== hashed_process_data
->x
.middle
&&
415 hashed_process_data
->x
.middle_used
)
417 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
418 /* Draw collision indicator */
419 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
420 gdk_draw_point(hashed_process_data
->pixmap
,
423 COLLISION_POSITION(hashed_process_data
->height
));
424 hashed_process_data
->x
.middle_marked
= TRUE
;
428 DrawContext draw_context
;
430 /* Now create the drawing context that will be used to draw
431 * items related to the last state. */
432 draw_context
.drawable
= hashed_process_data
->pixmap
;
433 draw_context
.gc
= drawing
->gc
;
434 draw_context
.pango_layout
= drawing
->pango_layout
;
435 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
436 draw_context
.drawinfo
.end
.x
= x
;
438 draw_context
.drawinfo
.y
.over
= 1;
439 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
440 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
442 draw_context
.drawinfo
.start
.offset
.over
= 0;
443 draw_context
.drawinfo
.start
.offset
.middle
= 0;
444 draw_context
.drawinfo
.start
.offset
.under
= 0;
445 draw_context
.drawinfo
.end
.offset
.over
= 0;
446 draw_context
.drawinfo
.end
.offset
.middle
= 0;
447 draw_context
.drawinfo
.end
.offset
.under
= 0;
451 PropertiesLine prop_line
= prepare_s_e_line(process
);
452 draw_line((void*)&prop_line
, (void*)&draw_context
);
455 /* become the last x position */
456 hashed_process_data
->x
.middle
= x
;
457 hashed_process_data
->x
.middle_used
= TRUE
;
458 hashed_process_data
->x
.middle_marked
= FALSE
;
460 /* Calculate the next good time */
461 convert_pixels_to_time(width
, x
+1, time_window
,
462 &hashed_process_data
->next_good_time
);
468 tfc
->target_pid
= target_pid_saved
;
474 /* before_schedchange_hook
476 * This function basically draw lines and icons. Two types of lines are drawn :
477 * one small (3 pixels?) representing the state of the process and the second
478 * type is thicker (10 pixels?) representing on which CPU a process is running
479 * (and this only in running state).
481 * Extremums of the lines :
482 * x_min : time of the last event context for this process kept in memory.
483 * x_max : time of the current event.
484 * y : middle of the process in the process list. The process is found in the
485 * list, therefore is it's position in pixels.
487 * The choice of lines'color is defined by the context of the last event for this
492 int before_schedchange_hook(void *hook_data
, void *call_data
)
494 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
495 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
496 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
498 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
500 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
501 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
504 e
= ltt_tracefile_get_event(tfc
->tf
);
505 gint target_pid_saved
= tfc
->target_pid
;
507 LttTime evtime
= ltt_event_time(e
);
508 LttvFilter
*filter
= control_flow_data
->filter
;
510 /* we are in a schedchange, before the state update. We must draw the
511 * items corresponding to the state before it changes : now is the right
519 pid_out
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
520 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
521 state_out
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 2));
524 tfc
->target_pid
= pid_out
;
525 if(!filter
|| !filter
->head
||
526 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
527 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
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. */
534 guint cpu
= tfs
->cpu
;
535 guint trace_num
= ts
->parent
.index
;
536 LttvProcessState
*process
= ts
->running_process
[cpu
];
537 /* unknown state, bad current pid */
538 if(process
->pid
!= pid_out
)
539 process
= lttv_state_find_process(ts
,
542 if(process
!= NULL
) {
543 /* Well, the process_out existed : we must get it in the process hash
544 * or add it, and draw its items.
546 /* Add process to process list (if not present) */
548 HashedProcessData
*hashed_process_data
= NULL
;
549 ProcessList
*process_list
= control_flow_data
->process_list
;
550 LttTime birth
= process
->creation_time
;
552 hashed_process_data
= processlist_get_process_data(process_list
,
557 if(hashed_process_data
== NULL
)
559 g_assert(pid_out
== 0 || pid_out
!= process
->ppid
);
560 /* Process not present */
561 ProcessInfo
*process_info
;
562 Drawing_t
*drawing
= control_flow_data
->drawing
;
563 processlist_add(process_list
,
575 &hashed_process_data
);
576 gtk_widget_set_size_request(drawing
->drawing_area
,
579 gtk_widget_queue_draw(drawing
->drawing_area
);
583 /* Now, the process is in the state hash and our own process hash.
584 * We definitely can draw the items related to the ending state.
587 if(ltt_time_compare(hashed_process_data
->next_good_time
,
590 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
592 TimeWindow time_window
=
593 lttvwindow_get_time_window(control_flow_data
->tab
);
595 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
596 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
599 Drawing_t
*drawing
= control_flow_data
->drawing
;
600 guint width
= drawing
->width
;
602 convert_time_to_pixels(
608 /* Draw collision indicator */
609 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
610 gdk_draw_point(hashed_process_data
->pixmap
,
613 COLLISION_POSITION(hashed_process_data
->height
));
614 hashed_process_data
->x
.middle_marked
= TRUE
;
617 TimeWindow time_window
=
618 lttvwindow_get_time_window(control_flow_data
->tab
);
620 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
621 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
624 Drawing_t
*drawing
= control_flow_data
->drawing
;
625 guint width
= drawing
->width
;
627 convert_time_to_pixels(
634 /* Jump over draw if we are at the same x position */
635 if(x
== hashed_process_data
->x
.middle
&&
636 hashed_process_data
->x
.middle_used
)
638 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
639 /* Draw collision indicator */
640 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
641 gdk_draw_point(hashed_process_data
->pixmap
,
644 COLLISION_POSITION(hashed_process_data
->height
));
645 hashed_process_data
->x
.middle_marked
= TRUE
;
649 DrawContext draw_context
;
651 /* Now create the drawing context that will be used to draw
652 * items related to the last state. */
653 draw_context
.drawable
= hashed_process_data
->pixmap
;
654 draw_context
.gc
= drawing
->gc
;
655 draw_context
.pango_layout
= drawing
->pango_layout
;
656 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
657 draw_context
.drawinfo
.end
.x
= x
;
659 draw_context
.drawinfo
.y
.over
= 1;
660 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
661 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
663 draw_context
.drawinfo
.start
.offset
.over
= 0;
664 draw_context
.drawinfo
.start
.offset
.middle
= 0;
665 draw_context
.drawinfo
.start
.offset
.under
= 0;
666 draw_context
.drawinfo
.end
.offset
.over
= 0;
667 draw_context
.drawinfo
.end
.offset
.middle
= 0;
668 draw_context
.drawinfo
.end
.offset
.under
= 0;
672 PropertiesLine prop_line
= prepare_s_e_line(process
);
673 draw_line((void*)&prop_line
, (void*)&draw_context
);
676 /* become the last x position */
677 hashed_process_data
->x
.middle
= x
;
678 hashed_process_data
->x
.middle_used
= TRUE
;
679 hashed_process_data
->x
.middle_marked
= FALSE
;
681 /* Calculate the next good time */
682 convert_pixels_to_time(width
, x
+1, time_window
,
683 &hashed_process_data
->next_good_time
);
689 tfc
->target_pid
= pid_in
;
690 if(!filter
|| !filter
->head
||
691 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
692 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
694 /* First, check if the current process is in the state computation
695 * process list. If it is there, that means we must add it right now and
696 * draw items from the beginning of the read for it. If it is not
697 * present, it's a new process and it was not present : it will
698 * be added after the state update. */
699 LttvProcessState
*process
;
700 process
= lttv_state_find_process(ts
,
702 guint trace_num
= ts
->parent
.index
;
704 if(process
!= NULL
) {
705 /* Well, the process existed : we must get it in the process hash
706 * or add it, and draw its items.
708 /* Add process to process list (if not present) */
710 HashedProcessData
*hashed_process_data
= NULL
;
711 ProcessList
*process_list
= control_flow_data
->process_list
;
712 LttTime birth
= process
->creation_time
;
714 hashed_process_data
= processlist_get_process_data(process_list
,
719 if(hashed_process_data
== NULL
)
721 g_assert(pid_in
== 0 || pid_in
!= process
->ppid
);
722 /* Process not present */
723 ProcessInfo
*process_info
;
724 Drawing_t
*drawing
= control_flow_data
->drawing
;
725 processlist_add(process_list
,
737 &hashed_process_data
);
738 gtk_widget_set_size_request(drawing
->drawing_area
,
741 gtk_widget_queue_draw(drawing
->drawing_area
);
744 //We could set the current process and hash here, but will be done
745 //by after schedchange hook
747 /* Now, the process is in the state hash and our own process hash.
748 * We definitely can draw the items related to the ending state.
751 if(ltt_time_compare(hashed_process_data
->next_good_time
,
754 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
756 TimeWindow time_window
=
757 lttvwindow_get_time_window(control_flow_data
->tab
);
759 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
760 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
763 Drawing_t
*drawing
= control_flow_data
->drawing
;
764 guint width
= drawing
->width
;
766 convert_time_to_pixels(
772 /* Draw collision indicator */
773 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
774 gdk_draw_point(hashed_process_data
->pixmap
,
777 COLLISION_POSITION(hashed_process_data
->height
));
778 hashed_process_data
->x
.middle_marked
= TRUE
;
781 TimeWindow time_window
=
782 lttvwindow_get_time_window(control_flow_data
->tab
);
784 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
785 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
788 Drawing_t
*drawing
= control_flow_data
->drawing
;
789 guint width
= drawing
->width
;
792 convert_time_to_pixels(
799 /* Jump over draw if we are at the same x position */
800 if(x
== hashed_process_data
->x
.middle
&&
801 hashed_process_data
->x
.middle_used
)
803 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
804 /* Draw collision indicator */
805 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
806 gdk_draw_point(hashed_process_data
->pixmap
,
809 COLLISION_POSITION(hashed_process_data
->height
));
810 hashed_process_data
->x
.middle_marked
= TRUE
;
814 DrawContext draw_context
;
816 /* Now create the drawing context that will be used to draw
817 * items related to the last state. */
818 draw_context
.drawable
= hashed_process_data
->pixmap
;
819 draw_context
.gc
= drawing
->gc
;
820 draw_context
.pango_layout
= drawing
->pango_layout
;
821 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
822 draw_context
.drawinfo
.end
.x
= x
;
824 draw_context
.drawinfo
.y
.over
= 1;
825 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
826 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
828 draw_context
.drawinfo
.start
.offset
.over
= 0;
829 draw_context
.drawinfo
.start
.offset
.middle
= 0;
830 draw_context
.drawinfo
.start
.offset
.under
= 0;
831 draw_context
.drawinfo
.end
.offset
.over
= 0;
832 draw_context
.drawinfo
.end
.offset
.middle
= 0;
833 draw_context
.drawinfo
.end
.offset
.under
= 0;
837 PropertiesLine prop_line
= prepare_s_e_line(process
);
838 draw_line((void*)&prop_line
, (void*)&draw_context
);
842 /* become the last x position */
843 hashed_process_data
->x
.middle
= x
;
844 hashed_process_data
->x
.middle_used
= TRUE
;
845 hashed_process_data
->x
.middle_marked
= FALSE
;
847 /* Calculate the next good time */
848 convert_pixels_to_time(width
, x
+1, time_window
,
849 &hashed_process_data
->next_good_time
);
853 g_warning("Cannot find pin_in in schedchange %u", pid_in
);
855 tfc
->target_pid
= target_pid_saved
;
863 GString
*string
= g_string_new("");;
864 gboolean field_names
= TRUE
, state
= TRUE
;
866 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
867 g_string_append_printf(string
,"\n");
870 g_string_append_printf(string
, " %s",
871 g_quark_to_string(tfs
->process
->state
->s
));
874 g_info("%s",string
->str
);
876 g_string_free(string
, TRUE
);
878 /* End of text dump */
883 /* after_schedchange_hook
885 * The draw after hook is called by the reading API to have a
886 * particular event drawn on the screen.
887 * @param hook_data ControlFlowData structure of the viewer.
888 * @param call_data Event context.
890 * This function adds items to be drawn in a queue for each process.
893 int after_schedchange_hook(void *hook_data
, void *call_data
)
895 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
896 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
897 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
899 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
901 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
903 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
906 e
= ltt_tracefile_get_event(tfc
->tf
);
908 LttvFilter
*filter
= control_flow_data
->filter
;
909 LttTime evtime
= ltt_event_time(e
);
911 /* Add process to process list (if not present) */
912 LttvProcessState
*process_in
;
915 HashedProcessData
*hashed_process_data_in
= NULL
;
917 ProcessList
*process_list
= control_flow_data
->process_list
;
922 pid_out
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
923 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
926 tfc
->target_pid
= pid_in
;
927 if(!filter
|| !filter
->head
||
928 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
929 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
930 /* Find process pid_in in the list... */
931 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
932 //process_in = tfs->process;
933 guint cpu
= tfs
->cpu
;
934 guint trace_num
= ts
->parent
.index
;
935 process_in
= ts
->running_process
[cpu
];
936 /* It should exist, because we are after the state update. */
938 g_assert(process_in
!= NULL
);
940 birth
= process_in
->creation_time
;
942 hashed_process_data_in
= processlist_get_process_data(process_list
,
947 if(hashed_process_data_in
== NULL
)
949 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
950 ProcessInfo
*process_info
;
951 Drawing_t
*drawing
= control_flow_data
->drawing
;
952 /* Process not present */
953 processlist_add(process_list
,
965 &hashed_process_data_in
);
966 gtk_widget_set_size_request(drawing
->drawing_area
,
969 gtk_widget_queue_draw(drawing
->drawing_area
);
971 /* Set the current process */
972 process_list
->current_hash_data
[trace_num
][process_in
->cpu
] =
973 hashed_process_data_in
;
975 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
978 TimeWindow time_window
=
979 lttvwindow_get_time_window(control_flow_data
->tab
);
982 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
983 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
986 Drawing_t
*drawing
= control_flow_data
->drawing
;
987 guint width
= drawing
->width
;
990 convert_time_to_pixels(
996 if(hashed_process_data_in
->x
.middle
!= new_x
) {
997 hashed_process_data_in
->x
.middle
= new_x
;
998 hashed_process_data_in
->x
.middle_used
= FALSE
;
999 hashed_process_data_in
->x
.middle_marked
= FALSE
;
1010 /* before_execmode_hook
1012 * This function basically draw lines and icons. Two types of lines are drawn :
1013 * one small (3 pixels?) representing the state of the process and the second
1014 * type is thicker (10 pixels?) representing on which CPU a process is running
1015 * (and this only in running state).
1017 * Extremums of the lines :
1018 * x_min : time of the last event context for this process kept in memory.
1019 * x_max : time of the current event.
1020 * y : middle of the process in the process list. The process is found in the
1021 * list, therefore is it's position in pixels.
1023 * The choice of lines'color is defined by the context of the last event for this
1028 int before_execmode_hook(void *hook_data
, void *call_data
)
1030 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1031 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1032 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1034 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1036 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1038 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1041 e
= ltt_tracefile_get_event(tfc
->tf
);
1043 LttvFilter
*filter
= control_flow_data
->filter
;
1044 if(filter
!= NULL
&& filter
->head
!= NULL
)
1045 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1046 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1049 LttTime evtime
= ltt_event_time(e
);
1051 /* we are in a execmode, before the state update. We must draw the
1052 * items corresponding to the state before it changes : now is the right
1056 //LttvProcessState *process = tfs->process;
1057 guint cpu
= tfs
->cpu
;
1058 guint trace_num
= ts
->parent
.index
;
1059 LttvProcessState
*process
= ts
->running_process
[cpu
];
1060 g_assert(process
!= NULL
);
1062 guint pid
= process
->pid
;
1064 /* Well, the process_out existed : we must get it in the process hash
1065 * or add it, and draw its items.
1067 /* Add process to process list (if not present) */
1068 guint pl_height
= 0;
1069 HashedProcessData
*hashed_process_data
= NULL
;
1070 ProcessList
*process_list
= control_flow_data
->process_list
;
1071 LttTime birth
= process
->creation_time
;
1073 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1074 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1076 hashed_process_data
= processlist_get_process_data(process_list
,
1081 if(unlikely(hashed_process_data
== NULL
))
1083 g_assert(pid
== 0 || pid
!= process
->ppid
);
1084 ProcessInfo
*process_info
;
1085 /* Process not present */
1086 Drawing_t
*drawing
= control_flow_data
->drawing
;
1087 processlist_add(process_list
,
1099 &hashed_process_data
);
1100 gtk_widget_set_size_request(drawing
->drawing_area
,
1103 gtk_widget_queue_draw(drawing
->drawing_area
);
1105 /* Set the current process */
1106 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1107 hashed_process_data
;
1110 /* Now, the process is in the state hash and our own process hash.
1111 * We definitely can draw the items related to the ending state.
1114 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1117 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1118 TimeWindow time_window
=
1119 lttvwindow_get_time_window(control_flow_data
->tab
);
1122 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1123 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1125 #endif //EXTRA_CHECK
1126 Drawing_t
*drawing
= control_flow_data
->drawing
;
1127 guint width
= drawing
->width
;
1129 convert_time_to_pixels(
1135 /* Draw collision indicator */
1136 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1137 gdk_draw_point(hashed_process_data
->pixmap
,
1140 COLLISION_POSITION(hashed_process_data
->height
));
1141 hashed_process_data
->x
.middle_marked
= TRUE
;
1144 TimeWindow time_window
=
1145 lttvwindow_get_time_window(control_flow_data
->tab
);
1148 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1149 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1151 #endif //EXTRA_CHECK
1152 Drawing_t
*drawing
= control_flow_data
->drawing
;
1153 guint width
= drawing
->width
;
1156 convert_time_to_pixels(
1163 /* Jump over draw if we are at the same x position */
1164 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1165 hashed_process_data
->x
.middle_used
))
1167 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1168 /* Draw collision indicator */
1169 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1170 gdk_draw_point(hashed_process_data
->pixmap
,
1173 COLLISION_POSITION(hashed_process_data
->height
));
1174 hashed_process_data
->x
.middle_marked
= TRUE
;
1179 DrawContext draw_context
;
1180 /* Now create the drawing context that will be used to draw
1181 * items related to the last state. */
1182 draw_context
.drawable
= hashed_process_data
->pixmap
;
1183 draw_context
.gc
= drawing
->gc
;
1184 draw_context
.pango_layout
= drawing
->pango_layout
;
1185 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1186 draw_context
.drawinfo
.end
.x
= x
;
1188 draw_context
.drawinfo
.y
.over
= 1;
1189 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1190 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1192 draw_context
.drawinfo
.start
.offset
.over
= 0;
1193 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1194 draw_context
.drawinfo
.start
.offset
.under
= 0;
1195 draw_context
.drawinfo
.end
.offset
.over
= 0;
1196 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1197 draw_context
.drawinfo
.end
.offset
.under
= 0;
1201 PropertiesLine prop_line
= prepare_s_e_line(process
);
1202 draw_line((void*)&prop_line
, (void*)&draw_context
);
1205 /* become the last x position */
1206 hashed_process_data
->x
.middle
= x
;
1207 hashed_process_data
->x
.middle_used
= TRUE
;
1208 hashed_process_data
->x
.middle_marked
= FALSE
;
1210 /* Calculate the next good time */
1211 convert_pixels_to_time(width
, x
+1, time_window
,
1212 &hashed_process_data
->next_good_time
);
1219 /* before_process_exit_hook
1221 * Draw lines for process event.
1223 * @param hook_data ControlFlowData structure of the viewer.
1224 * @param call_data Event context.
1226 * This function adds items to be drawn in a queue for each process.
1231 int before_process_exit_hook(void *hook_data
, void *call_data
)
1233 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1234 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1236 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1238 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1240 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1242 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1245 e
= ltt_tracefile_get_event(tfc
->tf
);
1247 LttvFilter
*filter
= control_flow_data
->filter
;
1248 if(filter
!= NULL
&& filter
->head
!= NULL
)
1249 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1250 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1253 LttTime evtime
= ltt_event_time(e
);
1255 /* Add process to process list (if not present) */
1256 //LttvProcessState *process = tfs->process;
1257 guint cpu
= tfs
->cpu
;
1258 guint trace_num
= ts
->parent
.index
;
1259 LttvProcessState
*process
= ts
->running_process
[cpu
];
1260 guint pid
= process
->pid
;
1262 guint pl_height
= 0;
1263 HashedProcessData
*hashed_process_data
= NULL
;
1265 ProcessList
*process_list
= control_flow_data
->process_list
;
1267 g_assert(process
!= NULL
);
1269 birth
= process
->creation_time
;
1271 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1272 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1274 hashed_process_data
= processlist_get_process_data(process_list
,
1279 if(unlikely(hashed_process_data
== NULL
))
1281 g_assert(pid
== 0 || pid
!= process
->ppid
);
1282 /* Process not present */
1283 Drawing_t
*drawing
= control_flow_data
->drawing
;
1284 ProcessInfo
*process_info
;
1285 processlist_add(process_list
,
1297 &hashed_process_data
);
1298 gtk_widget_set_size_request(drawing
->drawing_area
,
1301 gtk_widget_queue_draw(drawing
->drawing_area
);
1305 /* Now, the process is in the state hash and our own process hash.
1306 * We definitely can draw the items related to the ending state.
1309 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1312 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1313 TimeWindow time_window
=
1314 lttvwindow_get_time_window(control_flow_data
->tab
);
1317 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1318 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1320 #endif //EXTRA_CHECK
1321 Drawing_t
*drawing
= control_flow_data
->drawing
;
1322 guint width
= drawing
->width
;
1324 convert_time_to_pixels(
1330 /* Draw collision indicator */
1331 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1332 gdk_draw_point(hashed_process_data
->pixmap
,
1335 COLLISION_POSITION(hashed_process_data
->height
));
1336 hashed_process_data
->x
.middle_marked
= TRUE
;
1339 TimeWindow time_window
=
1340 lttvwindow_get_time_window(control_flow_data
->tab
);
1343 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1344 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1346 #endif //EXTRA_CHECK
1347 Drawing_t
*drawing
= control_flow_data
->drawing
;
1348 guint width
= drawing
->width
;
1351 convert_time_to_pixels(
1358 /* Jump over draw if we are at the same x position */
1359 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1360 hashed_process_data
->x
.middle_used
))
1362 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1363 /* Draw collision indicator */
1364 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1365 gdk_draw_point(hashed_process_data
->pixmap
,
1368 COLLISION_POSITION(hashed_process_data
->height
));
1369 hashed_process_data
->x
.middle_marked
= TRUE
;
1373 DrawContext draw_context
;
1375 /* Now create the drawing context that will be used to draw
1376 * items related to the last state. */
1377 draw_context
.drawable
= hashed_process_data
->pixmap
;
1378 draw_context
.gc
= drawing
->gc
;
1379 draw_context
.pango_layout
= drawing
->pango_layout
;
1380 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1381 draw_context
.drawinfo
.end
.x
= x
;
1383 draw_context
.drawinfo
.y
.over
= 1;
1384 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1385 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1387 draw_context
.drawinfo
.start
.offset
.over
= 0;
1388 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1389 draw_context
.drawinfo
.start
.offset
.under
= 0;
1390 draw_context
.drawinfo
.end
.offset
.over
= 0;
1391 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1392 draw_context
.drawinfo
.end
.offset
.under
= 0;
1396 PropertiesLine prop_line
= prepare_s_e_line(process
);
1397 draw_line((void*)&prop_line
, (void*)&draw_context
);
1400 /* become the last x position */
1401 hashed_process_data
->x
.middle
= x
;
1402 hashed_process_data
->x
.middle_used
= TRUE
;
1403 hashed_process_data
->x
.middle_marked
= FALSE
;
1405 /* Calculate the next good time */
1406 convert_pixels_to_time(width
, x
+1, time_window
,
1407 &hashed_process_data
->next_good_time
);
1417 /* before_process_release_hook
1419 * Draw lines for process event.
1421 * @param hook_data ControlFlowData structure of the viewer.
1422 * @param call_data Event context.
1424 * This function adds items to be drawn in a queue for each process.
1429 int before_process_release_hook(void *hook_data
, void *call_data
)
1431 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1432 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1434 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1436 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1438 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1440 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1443 e
= ltt_tracefile_get_event(tfc
->tf
);
1445 LttvFilter
*filter
= control_flow_data
->filter
;
1446 if(filter
!= NULL
&& filter
->head
!= NULL
)
1447 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1448 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1451 LttTime evtime
= ltt_event_time(e
);
1453 guint trace_num
= ts
->parent
.index
;
1457 pid
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
1460 /* Add process to process list (if not present) */
1461 /* Don't care about the process if it's not in the state hash already :
1462 * that means a process that has never done anything in the trace and
1463 * unknown suddently gets destroyed : no state meaningful to show. */
1464 LttvProcessState
*process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1466 if(process
!= NULL
) {
1468 guint pl_height
= 0;
1469 HashedProcessData
*hashed_process_data
= NULL
;
1471 ProcessList
*process_list
= control_flow_data
->process_list
;
1473 birth
= process
->creation_time
;
1475 /* Cannot use current process : this event happens on another process,
1476 * action done by the parent. */
1477 hashed_process_data
= processlist_get_process_data(process_list
,
1482 if(unlikely(hashed_process_data
== NULL
))
1484 * Process already been scheduled out EXIT_DEAD, not in the process list
1485 * anymore. Just return.
1489 /* Now, the process is in the state hash and our own process hash.
1490 * We definitely can draw the items related to the ending state.
1493 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1496 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1497 TimeWindow time_window
=
1498 lttvwindow_get_time_window(control_flow_data
->tab
);
1501 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1502 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1504 #endif //EXTRA_CHECK
1505 Drawing_t
*drawing
= control_flow_data
->drawing
;
1506 guint width
= drawing
->width
;
1508 convert_time_to_pixels(
1514 /* Draw collision indicator */
1515 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1516 gdk_draw_point(hashed_process_data
->pixmap
,
1519 COLLISION_POSITION(hashed_process_data
->height
));
1520 hashed_process_data
->x
.middle_marked
= TRUE
;
1523 TimeWindow time_window
=
1524 lttvwindow_get_time_window(control_flow_data
->tab
);
1527 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1528 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1530 #endif //EXTRA_CHECK
1531 Drawing_t
*drawing
= control_flow_data
->drawing
;
1532 guint width
= drawing
->width
;
1535 convert_time_to_pixels(
1542 /* Jump over draw if we are at the same x position */
1543 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1544 hashed_process_data
->x
.middle_used
))
1546 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1547 /* Draw collision indicator */
1548 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1549 gdk_draw_point(hashed_process_data
->pixmap
,
1552 COLLISION_POSITION(hashed_process_data
->height
));
1553 hashed_process_data
->x
.middle_marked
= TRUE
;
1557 DrawContext draw_context
;
1559 /* Now create the drawing context that will be used to draw
1560 * items related to the last state. */
1561 draw_context
.drawable
= hashed_process_data
->pixmap
;
1562 draw_context
.gc
= drawing
->gc
;
1563 draw_context
.pango_layout
= drawing
->pango_layout
;
1564 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1565 draw_context
.drawinfo
.end
.x
= x
;
1567 draw_context
.drawinfo
.y
.over
= 1;
1568 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1569 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1571 draw_context
.drawinfo
.start
.offset
.over
= 0;
1572 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1573 draw_context
.drawinfo
.start
.offset
.under
= 0;
1574 draw_context
.drawinfo
.end
.offset
.over
= 0;
1575 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1576 draw_context
.drawinfo
.end
.offset
.under
= 0;
1580 PropertiesLine prop_line
= prepare_s_e_line(process
);
1581 draw_line((void*)&prop_line
, (void*)&draw_context
);
1584 /* become the last x position */
1585 hashed_process_data
->x
.middle
= x
;
1586 hashed_process_data
->x
.middle_used
= TRUE
;
1587 hashed_process_data
->x
.middle_marked
= FALSE
;
1589 /* Calculate the next good time */
1590 convert_pixels_to_time(width
, x
+1, time_window
,
1591 &hashed_process_data
->next_good_time
);
1603 /* after_process_fork_hook
1605 * Create the processlist entry for the child process. Put the last
1606 * position in x at the current time value.
1608 * @param hook_data ControlFlowData structure of the viewer.
1609 * @param call_data Event context.
1611 * This function adds items to be drawn in a queue for each process.
1614 int after_process_fork_hook(void *hook_data
, void *call_data
)
1616 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1617 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1618 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1620 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1622 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1624 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1627 e
= ltt_tracefile_get_event(tfc
->tf
);
1629 LttvFilter
*filter
= control_flow_data
->filter
;
1630 if(filter
!= NULL
&& filter
->head
!= NULL
)
1631 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1632 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1635 LttTime evtime
= ltt_event_time(e
);
1639 child_pid
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
1642 /* Add process to process list (if not present) */
1643 LttvProcessState
*process_child
;
1645 guint pl_height
= 0;
1646 HashedProcessData
*hashed_process_data_child
= NULL
;
1648 ProcessList
*process_list
= control_flow_data
->process_list
;
1650 /* Find child in the list... */
1651 process_child
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1652 /* It should exist, because we are after the state update. */
1653 g_assert(process_child
!= NULL
);
1655 birth
= process_child
->creation_time
;
1656 guint trace_num
= ts
->parent
.index
;
1658 /* Cannot use current process, because this action is done by the parent
1660 hashed_process_data_child
= processlist_get_process_data(process_list
,
1665 if(likely(hashed_process_data_child
== NULL
))
1667 g_assert(child_pid
== 0 || child_pid
!= process_child
->ppid
);
1668 /* Process not present */
1669 Drawing_t
*drawing
= control_flow_data
->drawing
;
1670 ProcessInfo
*process_info
;
1671 processlist_add(process_list
,
1674 process_child
->tgid
,
1676 process_child
->ppid
,
1679 process_child
->name
,
1680 process_child
->brand
,
1683 &hashed_process_data_child
);
1684 gtk_widget_set_size_request(drawing
->drawing_area
,
1687 gtk_widget_queue_draw(drawing
->drawing_area
);
1689 processlist_set_ppid(process_list
, process_child
->ppid
,
1690 hashed_process_data_child
);
1691 processlist_set_tgid(process_list
, process_child
->tgid
,
1692 hashed_process_data_child
);
1696 if(likely(ltt_time_compare(hashed_process_data_child
->next_good_time
,
1699 TimeWindow time_window
=
1700 lttvwindow_get_time_window(control_flow_data
->tab
);
1703 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1704 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1706 #endif //EXTRA_CHECK
1707 Drawing_t
*drawing
= control_flow_data
->drawing
;
1708 guint width
= drawing
->width
;
1710 convert_time_to_pixels(
1716 if(likely(hashed_process_data_child
->x
.over
!= new_x
)) {
1717 hashed_process_data_child
->x
.over
= new_x
;
1718 hashed_process_data_child
->x
.over_used
= FALSE
;
1719 hashed_process_data_child
->x
.over_marked
= FALSE
;
1721 if(likely(hashed_process_data_child
->x
.middle
!= new_x
)) {
1722 hashed_process_data_child
->x
.middle
= new_x
;
1723 hashed_process_data_child
->x
.middle_used
= FALSE
;
1724 hashed_process_data_child
->x
.middle_marked
= FALSE
;
1726 if(likely(hashed_process_data_child
->x
.under
!= new_x
)) {
1727 hashed_process_data_child
->x
.under
= new_x
;
1728 hashed_process_data_child
->x
.under_used
= FALSE
;
1729 hashed_process_data_child
->x
.under_marked
= FALSE
;
1737 /* after_process_exit_hook
1739 * Create the processlist entry for the child process. Put the last
1740 * position in x at the current time value.
1742 * @param hook_data ControlFlowData structure of the viewer.
1743 * @param call_data Event context.
1745 * This function adds items to be drawn in a queue for each process.
1748 int after_process_exit_hook(void *hook_data
, void *call_data
)
1750 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1751 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1752 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1754 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1756 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1758 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1761 e
= ltt_tracefile_get_event(tfc
->tf
);
1763 LttvFilter
*filter
= control_flow_data
->filter
;
1764 if(filter
!= NULL
&& filter
->head
!= NULL
)
1765 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1766 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1769 LttTime evtime
= ltt_event_time(e
);
1771 /* Add process to process list (if not present) */
1772 //LttvProcessState *process = tfs->process;
1773 guint cpu
= tfs
->cpu
;
1774 guint trace_num
= ts
->parent
.index
;
1775 LttvProcessState
*process
= ts
->running_process
[cpu
];
1777 /* It should exist, because we are after the state update. */
1778 g_assert(process
!= NULL
);
1780 guint pid
= process
->pid
;
1782 guint pl_height
= 0;
1783 HashedProcessData
*hashed_process_data
= NULL
;
1785 ProcessList
*process_list
= control_flow_data
->process_list
;
1787 birth
= process
->creation_time
;
1789 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
) ){
1790 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1792 hashed_process_data
= processlist_get_process_data(process_list
,
1797 if(unlikely(hashed_process_data
== NULL
))
1799 g_assert(pid
== 0 || pid
!= process
->ppid
);
1800 /* Process not present */
1801 Drawing_t
*drawing
= control_flow_data
->drawing
;
1802 ProcessInfo
*process_info
;
1803 processlist_add(process_list
,
1815 &hashed_process_data
);
1816 gtk_widget_set_size_request(drawing
->drawing_area
,
1819 gtk_widget_queue_draw(drawing
->drawing_area
);
1822 /* Set the current process */
1823 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1824 hashed_process_data
;
1827 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
1830 TimeWindow time_window
=
1831 lttvwindow_get_time_window(control_flow_data
->tab
);
1834 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1835 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1837 #endif //EXTRA_CHECK
1838 Drawing_t
*drawing
= control_flow_data
->drawing
;
1839 guint width
= drawing
->width
;
1841 convert_time_to_pixels(
1846 if(unlikely(hashed_process_data
->x
.middle
!= new_x
)) {
1847 hashed_process_data
->x
.middle
= new_x
;
1848 hashed_process_data
->x
.middle_used
= FALSE
;
1849 hashed_process_data
->x
.middle_marked
= FALSE
;
1857 /* Get the filename of the process to print */
1858 int after_fs_exec_hook(void *hook_data
, void *call_data
)
1860 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1861 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1862 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1864 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1866 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1868 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1871 e
= ltt_tracefile_get_event(tfc
->tf
);
1873 LttvFilter
*filter
= control_flow_data
->filter
;
1874 if(filter
!= NULL
&& filter
->head
!= NULL
)
1875 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1876 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1879 guint cpu
= tfs
->cpu
;
1880 guint trace_num
= ts
->parent
.index
;
1881 LttvProcessState
*process
= ts
->running_process
[cpu
];
1882 g_assert(process
!= NULL
);
1884 guint pid
= process
->pid
;
1886 /* Well, the process_out existed : we must get it in the process hash
1887 * or add it, and draw its items.
1889 /* Add process to process list (if not present) */
1890 guint pl_height
= 0;
1891 HashedProcessData
*hashed_process_data
= NULL
;
1892 ProcessList
*process_list
= control_flow_data
->process_list
;
1893 LttTime birth
= process
->creation_time
;
1895 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1896 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1898 hashed_process_data
= processlist_get_process_data(process_list
,
1903 if(unlikely(hashed_process_data
== NULL
))
1905 g_assert(pid
== 0 || pid
!= process
->ppid
);
1906 ProcessInfo
*process_info
;
1907 /* Process not present */
1908 Drawing_t
*drawing
= control_flow_data
->drawing
;
1909 processlist_add(process_list
,
1921 &hashed_process_data
);
1922 gtk_widget_set_size_request(drawing
->drawing_area
,
1925 gtk_widget_queue_draw(drawing
->drawing_area
);
1927 /* Set the current process */
1928 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1929 hashed_process_data
;
1932 processlist_set_name(process_list
, process
->name
, hashed_process_data
);
1938 /* Get the filename of the process to print */
1939 int after_user_generic_thread_brand_hook(void *hook_data
, void *call_data
)
1941 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1942 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1943 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1945 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1947 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1949 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1952 e
= ltt_tracefile_get_event(tfc
->tf
);
1954 LttvFilter
*filter
= control_flow_data
->filter
;
1955 if(filter
!= NULL
&& filter
->head
!= NULL
)
1956 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1957 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1960 guint cpu
= tfs
->cpu
;
1961 guint trace_num
= ts
->parent
.index
;
1962 LttvProcessState
*process
= ts
->running_process
[cpu
];
1963 g_assert(process
!= NULL
);
1965 guint pid
= process
->pid
;
1967 /* Well, the process_out existed : we must get it in the process hash
1968 * or add it, and draw its items.
1970 /* Add process to process list (if not present) */
1971 guint pl_height
= 0;
1972 HashedProcessData
*hashed_process_data
= NULL
;
1973 ProcessList
*process_list
= control_flow_data
->process_list
;
1974 LttTime birth
= process
->creation_time
;
1976 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1977 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1979 hashed_process_data
= processlist_get_process_data(process_list
,
1984 if(unlikely(hashed_process_data
== NULL
))
1986 g_assert(pid
== 0 || pid
!= process
->ppid
);
1987 ProcessInfo
*process_info
;
1988 /* Process not present */
1989 Drawing_t
*drawing
= control_flow_data
->drawing
;
1990 processlist_add(process_list
,
2002 &hashed_process_data
);
2003 gtk_widget_set_size_request(drawing
->drawing_area
,
2006 gtk_widget_queue_draw(drawing
->drawing_area
);
2008 /* Set the current process */
2009 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
2010 hashed_process_data
;
2013 processlist_set_brand(process_list
, process
->brand
, hashed_process_data
);
2020 /* after_event_enum_process_hook
2022 * Create the processlist entry for the child process. Put the last
2023 * position in x at the current time value.
2025 * @param hook_data ControlFlowData structure of the viewer.
2026 * @param call_data Event context.
2028 * This function adds items to be drawn in a queue for each process.
2031 int after_event_enum_process_hook(void *hook_data
, void *call_data
)
2033 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2034 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
2035 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2037 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2039 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
2041 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
2043 guint first_cpu
, nb_cpus
, cpu
;
2046 e
= ltt_tracefile_get_event(tfc
->tf
);
2048 LttvFilter
*filter
= control_flow_data
->filter
;
2049 if(filter
!= NULL
&& filter
->head
!= NULL
)
2050 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2051 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2054 LttTime evtime
= ltt_event_time(e
);
2056 /* Add process to process list (if not present) */
2057 LttvProcessState
*process_in
;
2059 guint pl_height
= 0;
2060 HashedProcessData
*hashed_process_data_in
= NULL
;
2062 ProcessList
*process_list
= control_flow_data
->process_list
;
2063 guint trace_num
= ts
->parent
.index
;
2067 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2072 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2074 first_cpu
= ANY_CPU
;
2075 nb_cpus
= ANY_CPU
+1;
2078 for(cpu
= first_cpu
; cpu
< nb_cpus
; cpu
++) {
2079 /* Find process pid_in in the list... */
2080 process_in
= lttv_state_find_process(ts
, cpu
, pid_in
);
2081 //process_in = tfs->process;
2082 //guint cpu = tfs->cpu;
2083 //guint trace_num = ts->parent.index;
2084 //process_in = ts->running_process[cpu];
2085 /* It should exist, because we are after the state update. */
2087 //g_assert(process_in != NULL);
2088 #endif //EXTRA_CHECK
2089 birth
= process_in
->creation_time
;
2091 hashed_process_data_in
= processlist_get_process_data(process_list
,
2096 if(hashed_process_data_in
== NULL
)
2098 if(pid_in
!= 0 && pid_in
== process_in
->ppid
)
2099 g_critical("TEST %u , %u", pid_in
, process_in
->ppid
);
2100 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
2101 ProcessInfo
*process_info
;
2102 Drawing_t
*drawing
= control_flow_data
->drawing
;
2103 /* Process not present */
2104 processlist_add(process_list
,
2116 &hashed_process_data_in
);
2117 gtk_widget_set_size_request(drawing
->drawing_area
,
2120 gtk_widget_queue_draw(drawing
->drawing_area
);
2122 processlist_set_name(process_list
, process_in
->name
,
2123 hashed_process_data_in
);
2124 processlist_set_ppid(process_list
, process_in
->ppid
,
2125 hashed_process_data_in
);
2126 processlist_set_tgid(process_list
, process_in
->tgid
,
2127 hashed_process_data_in
);
2134 gint
update_time_window_hook(void *hook_data
, void *call_data
)
2136 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2137 Drawing_t
*drawing
= control_flow_data
->drawing
;
2138 ProcessList
*process_list
= control_flow_data
->process_list
;
2140 const TimeWindowNotifyData
*time_window_nofify_data
=
2141 ((const TimeWindowNotifyData
*)call_data
);
2143 TimeWindow
*old_time_window
=
2144 time_window_nofify_data
->old_time_window
;
2145 TimeWindow
*new_time_window
=
2146 time_window_nofify_data
->new_time_window
;
2148 /* Update the ruler */
2149 drawing_update_ruler(control_flow_data
->drawing
,
2153 /* Two cases : zoom in/out or scrolling */
2155 /* In order to make sure we can reuse the old drawing, the scale must
2156 * be the same and the new time interval being partly located in the
2157 * currently shown time interval. (reuse is only for scrolling)
2160 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
2161 old_time_window
->start_time
.tv_sec
,
2162 old_time_window
->start_time
.tv_nsec
,
2163 old_time_window
->time_width
.tv_sec
,
2164 old_time_window
->time_width
.tv_nsec
);
2166 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
2167 new_time_window
->start_time
.tv_sec
,
2168 new_time_window
->start_time
.tv_nsec
,
2169 new_time_window
->time_width
.tv_sec
,
2170 new_time_window
->time_width
.tv_nsec
);
2172 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
2173 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
2175 /* Same scale (scrolling) */
2176 g_info("scrolling");
2177 LttTime
*ns
= &new_time_window
->start_time
;
2178 LttTime
*nw
= &new_time_window
->time_width
;
2179 LttTime
*os
= &old_time_window
->start_time
;
2180 LttTime
*ow
= &old_time_window
->time_width
;
2181 LttTime old_end
= old_time_window
->end_time
;
2182 LttTime new_end
= new_time_window
->end_time
;
2184 //if(ns<os+w && os+w<ns+w)
2185 //if(ns<old_end && os<ns)
2186 if(ltt_time_compare(*ns
, old_end
) == -1
2187 && ltt_time_compare(*os
, *ns
) == -1)
2189 g_info("scrolling near right");
2190 /* Scroll right, keep right part of the screen */
2192 guint width
= control_flow_data
->drawing
->width
;
2193 convert_time_to_pixels(
2199 /* Copy old data to new location */
2200 copy_pixmap_region(process_list
,
2202 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2206 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
2208 if(drawing
->damage_begin
== drawing
->damage_end
)
2209 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
2211 drawing
->damage_begin
= 0;
2213 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2215 /* Clear the data request background, but not SAFETY */
2216 rectangle_pixmap(process_list
,
2217 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2219 drawing
->damage_begin
+SAFETY
, 0,
2220 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2222 gtk_widget_queue_draw(drawing
->drawing_area
);
2223 //gtk_widget_queue_draw_area (drawing->drawing_area,
2225 // control_flow_data->drawing->width,
2226 // control_flow_data->drawing->height);
2228 /* Get new data for the rest. */
2229 drawing_data_request(control_flow_data
->drawing
,
2230 drawing
->damage_begin
, 0,
2231 drawing
->damage_end
- drawing
->damage_begin
,
2232 control_flow_data
->drawing
->height
);
2235 //if(ns<os && os<ns+w)
2236 //if(ns<os && os<new_end)
2237 if(ltt_time_compare(*ns
,*os
) == -1
2238 && ltt_time_compare(*os
,new_end
) == -1)
2240 g_info("scrolling near left");
2241 /* Scroll left, keep left part of the screen */
2243 guint width
= control_flow_data
->drawing
->width
;
2244 convert_time_to_pixels(
2250 /* Copy old data to new location */
2251 copy_pixmap_region (process_list
,
2253 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2259 if(drawing
->damage_begin
== drawing
->damage_end
)
2260 drawing
->damage_end
= x
;
2262 drawing
->damage_end
=
2263 control_flow_data
->drawing
->width
;
2265 drawing
->damage_begin
= 0;
2267 rectangle_pixmap (process_list
,
2268 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2270 drawing
->damage_begin
, 0,
2271 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2274 gtk_widget_queue_draw(drawing
->drawing_area
);
2275 //gtk_widget_queue_draw_area (drawing->drawing_area,
2277 // control_flow_data->drawing->width,
2278 // control_flow_data->drawing->height);
2281 /* Get new data for the rest. */
2282 drawing_data_request(control_flow_data
->drawing
,
2283 drawing
->damage_begin
, 0,
2284 drawing
->damage_end
- drawing
->damage_begin
,
2285 control_flow_data
->drawing
->height
);
2288 if(ltt_time_compare(*ns
,*os
) == 0)
2290 g_info("not scrolling");
2292 g_info("scrolling far");
2293 /* Cannot reuse any part of the screen : far jump */
2296 rectangle_pixmap (process_list
,
2297 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2300 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2303 //gtk_widget_queue_draw_area (drawing->drawing_area,
2305 // control_flow_data->drawing->width,
2306 // control_flow_data->drawing->height);
2307 gtk_widget_queue_draw(drawing
->drawing_area
);
2309 drawing
->damage_begin
= 0;
2310 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2312 drawing_data_request(control_flow_data
->drawing
,
2314 control_flow_data
->drawing
->width
,
2315 control_flow_data
->drawing
->height
);
2321 /* Different scale (zoom) */
2324 rectangle_pixmap (process_list
,
2325 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2328 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2331 //gtk_widget_queue_draw_area (drawing->drawing_area,
2333 // control_flow_data->drawing->width,
2334 // control_flow_data->drawing->height);
2335 gtk_widget_queue_draw(drawing
->drawing_area
);
2337 drawing
->damage_begin
= 0;
2338 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2340 drawing_data_request(control_flow_data
->drawing
,
2342 control_flow_data
->drawing
->width
,
2343 control_flow_data
->drawing
->height
);
2346 /* Update directly when scrolling */
2347 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2353 gint
traceset_notify(void *hook_data
, void *call_data
)
2355 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2356 Drawing_t
*drawing
= control_flow_data
->drawing
;
2358 if(unlikely(drawing
->gc
== NULL
)) {
2361 if(drawing
->dotted_gc
== NULL
) {
2365 drawing_clear(control_flow_data
->drawing
);
2366 processlist_clear(control_flow_data
->process_list
);
2367 gtk_widget_set_size_request(
2368 control_flow_data
->drawing
->drawing_area
,
2369 -1, processlist_get_height(control_flow_data
->process_list
));
2370 redraw_notify(control_flow_data
, NULL
);
2372 request_background_data(control_flow_data
);
2377 gint
redraw_notify(void *hook_data
, void *call_data
)
2379 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2380 Drawing_t
*drawing
= control_flow_data
->drawing
;
2381 GtkWidget
*widget
= drawing
->drawing_area
;
2383 drawing
->damage_begin
= 0;
2384 drawing
->damage_end
= drawing
->width
;
2386 /* fun feature, to be separated someday... */
2387 drawing_clear(control_flow_data
->drawing
);
2388 processlist_clear(control_flow_data
->process_list
);
2389 gtk_widget_set_size_request(
2390 control_flow_data
->drawing
->drawing_area
,
2391 -1, processlist_get_height(control_flow_data
->process_list
));
2393 rectangle_pixmap (control_flow_data
->process_list
,
2394 widget
->style
->black_gc
,
2397 drawing
->alloc_width
,
2400 gtk_widget_queue_draw(drawing
->drawing_area
);
2402 if(drawing
->damage_begin
< drawing
->damage_end
)
2404 drawing_data_request(drawing
,
2405 drawing
->damage_begin
,
2407 drawing
->damage_end
-drawing
->damage_begin
,
2411 //gtk_widget_queue_draw_area(drawing->drawing_area,
2414 // drawing->height);
2420 gint
continue_notify(void *hook_data
, void *call_data
)
2422 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2423 Drawing_t
*drawing
= control_flow_data
->drawing
;
2425 //g_assert(widget->allocation.width == drawing->damage_end);
2427 if(drawing
->damage_begin
< drawing
->damage_end
)
2429 drawing_data_request(drawing
,
2430 drawing
->damage_begin
,
2432 drawing
->damage_end
-drawing
->damage_begin
,
2440 gint
update_current_time_hook(void *hook_data
, void *call_data
)
2442 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
2443 Drawing_t
*drawing
= control_flow_data
->drawing
;
2445 LttTime current_time
= *((LttTime
*)call_data
);
2447 TimeWindow time_window
=
2448 lttvwindow_get_time_window(control_flow_data
->tab
);
2450 LttTime time_begin
= time_window
.start_time
;
2451 LttTime width
= time_window
.time_width
;
2454 guint64 time_ll
= ltt_time_to_uint64(width
);
2455 time_ll
= time_ll
>> 1; /* divide by two */
2456 half_width
= ltt_time_from_uint64(time_ll
);
2458 LttTime time_end
= ltt_time_add(time_begin
, width
);
2460 LttvTracesetContext
* tsc
=
2461 lttvwindow_get_traceset_context(control_flow_data
->tab
);
2463 LttTime trace_start
= tsc
->time_span
.start_time
;
2464 LttTime trace_end
= tsc
->time_span
.end_time
;
2466 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
2467 current_time
.tv_nsec
);
2471 /* If current time is inside time interval, just move the highlight
2474 /* Else, we have to change the time interval. We have to tell it
2475 * to the main window. */
2476 /* The time interval change will take care of placing the current
2477 * time at the center of the visible area, or nearest possible if we are
2478 * at one end of the trace. */
2481 if(ltt_time_compare(current_time
, time_begin
) < 0)
2483 TimeWindow new_time_window
;
2485 if(ltt_time_compare(current_time
,
2486 ltt_time_add(trace_start
,half_width
)) < 0)
2487 time_begin
= trace_start
;
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
);
2498 else if(ltt_time_compare(current_time
, time_end
) > 0)
2500 TimeWindow new_time_window
;
2502 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
2503 time_begin
= ltt_time_sub(trace_end
,width
);
2505 time_begin
= ltt_time_sub(current_time
,half_width
);
2507 new_time_window
.start_time
= time_begin
;
2508 new_time_window
.time_width
= width
;
2509 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2510 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2512 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2515 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2517 /* Update directly when scrolling */
2518 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2524 typedef struct _ClosureData
{
2525 EventsRequest
*events_request
;
2526 LttvTracesetState
*tss
;
2532 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
2534 ProcessInfo
*process_info
= (ProcessInfo
*)key
;
2535 HashedProcessData
*hashed_process_data
= (HashedProcessData
*)value
;
2536 ClosureData
*closure_data
= (ClosureData
*)user_data
;
2538 EventsRequest
*events_request
= closure_data
->events_request
;
2539 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2541 LttvTracesetState
*tss
= closure_data
->tss
;
2542 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)tss
;
2544 LttTime evtime
= closure_data
->end_time
;
2546 gboolean dodraw
= TRUE
;
2549 /* For the process */
2550 /* First, check if the current process is in the state computation
2551 * process list. If it is there, that means we must add it right now and
2552 * draw items from the beginning of the read for it. If it is not
2553 * present, it's a new process and it was not present : it will
2554 * be added after the state update. */
2556 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
2557 #endif //EXTRA_CHECK
2558 LttvTraceContext
*tc
= tsc
->traces
[process_info
->trace_num
];
2559 LttvTraceState
*ts
= (LttvTraceState
*)tc
;
2562 //FIXME : optimize data structures.
2563 LttvTracefileState
*tfs
;
2564 LttvTracefileContext
*tfc
;
2566 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
2567 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
2568 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
2569 && tfs
->cpu
== process_info
->cpu
)
2573 g_assert(i
<tc
->tracefiles
->len
);
2574 tfs
= LTTV_TRACEFILE_STATE(tfc
);
2576 // LttvTracefileState *tfs =
2577 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2578 // tracefiles[process_info->cpu];
2580 LttvProcessState
*process
;
2581 process
= lttv_state_find_process(ts
, process_info
->cpu
,
2584 if(unlikely(process
!= NULL
)) {
2586 LttvFilter
*filter
= control_flow_data
->filter
;
2587 if(filter
!= NULL
&& filter
->head
!= NULL
)
2588 if(!lttv_filter_tree_parse(filter
->head
,NULL
,NULL
,
2589 tc
->t
,NULL
,process
,tc
))
2592 /* Only draw for processes that are currently in the trace states */
2594 ProcessList
*process_list
= control_flow_data
->process_list
;
2596 /* Should be alike when background info is ready */
2597 if(control_flow_data
->background_info_waiting
==0)
2598 g_assert(ltt_time_compare(process
->creation_time
,
2599 process_info
->birth
) == 0);
2600 #endif //EXTRA_CHECK
2602 /* Now, the process is in the state hash and our own process hash.
2603 * We definitely can draw the items related to the ending state.
2606 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2609 TimeWindow time_window
=
2610 lttvwindow_get_time_window(control_flow_data
->tab
);
2613 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2614 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2616 #endif //EXTRA_CHECK
2617 Drawing_t
*drawing
= control_flow_data
->drawing
;
2618 guint width
= drawing
->width
;
2620 guint x
= closure_data
->x_end
;
2622 DrawContext draw_context
;
2624 /* Now create the drawing context that will be used to draw
2625 * items related to the last state. */
2626 draw_context
.drawable
= hashed_process_data
->pixmap
;
2627 draw_context
.gc
= drawing
->gc
;
2628 draw_context
.pango_layout
= drawing
->pango_layout
;
2629 draw_context
.drawinfo
.end
.x
= x
;
2631 draw_context
.drawinfo
.y
.over
= 1;
2632 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2633 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2635 draw_context
.drawinfo
.start
.offset
.over
= 0;
2636 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2637 draw_context
.drawinfo
.start
.offset
.under
= 0;
2638 draw_context
.drawinfo
.end
.offset
.over
= 0;
2639 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2640 draw_context
.drawinfo
.end
.offset
.under
= 0;
2642 /* Jump over draw if we are at the same x position */
2643 if(x
== hashed_process_data
->x
.over
)
2647 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2649 PropertiesLine prop_line
= prepare_execmode_line(process
);
2650 draw_line((void*)&prop_line
, (void*)&draw_context
);
2652 hashed_process_data
->x
.over
= x
;
2656 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2657 hashed_process_data
->x
.middle_used
)) {
2658 #if 0 /* do not mark closure : not missing information */
2659 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2660 /* Draw collision indicator */
2661 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2662 gdk_draw_point(drawing
->pixmap
,
2666 hashed_process_data
->x
.middle_marked
= TRUE
;
2671 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2674 PropertiesLine prop_line
= prepare_s_e_line(process
);
2675 draw_line((void*)&prop_line
, (void*)&draw_context
);
2678 /* become the last x position */
2679 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2680 hashed_process_data
->x
.middle
= x
;
2681 /* but don't use the pixel */
2682 hashed_process_data
->x
.middle_used
= FALSE
;
2684 /* Calculate the next good time */
2685 convert_pixels_to_time(width
, x
+1, time_window
,
2686 &hashed_process_data
->next_good_time
);
2695 int before_chunk(void *hook_data
, void *call_data
)
2697 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2698 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2699 ControlFlowData
*cfd
= (ControlFlowData
*)events_request
->viewer_data
;
2701 /* Desactivate sort */
2702 gtk_tree_sortable_set_sort_column_id(
2703 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2705 GTK_SORT_ASCENDING
);
2707 drawing_chunk_begin(events_request
, tss
);
2712 int before_request(void *hook_data
, void *call_data
)
2714 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2715 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2717 drawing_data_request_begin(events_request
, tss
);
2724 * after request is necessary in addition of after chunk in order to draw
2725 * lines until the end of the screen. after chunk just draws lines until
2732 int after_request(void *hook_data
, void *call_data
)
2734 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2735 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2736 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2738 ProcessList
*process_list
= control_flow_data
->process_list
;
2739 LttTime end_time
= events_request
->end_time
;
2741 ClosureData closure_data
;
2742 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2743 closure_data
.tss
= tss
;
2744 closure_data
.end_time
= end_time
;
2746 TimeWindow time_window
=
2747 lttvwindow_get_time_window(control_flow_data
->tab
);
2748 guint width
= control_flow_data
->drawing
->width
;
2749 convert_time_to_pixels(
2753 &closure_data
.x_end
);
2756 /* Draw last items */
2757 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2758 (void*)&closure_data
);
2761 /* Request expose */
2762 drawing_request_expose(events_request
, tss
, end_time
);
2771 int after_chunk(void *hook_data
, void *call_data
)
2773 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2774 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2775 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2776 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)call_data
;
2777 LttvTracefileContext
*tfc
= lttv_traceset_context_get_current_tfc(tsc
);
2780 ProcessList
*process_list
= control_flow_data
->process_list
;
2782 LttvTraceset
*traceset
= tsc
->ts
;
2783 guint nb_trace
= lttv_traceset_number(traceset
);
2785 /* Only execute when called for the first trace's events request */
2786 if(!process_list
->current_hash_data
)
2789 for(i
= 0 ; i
< nb_trace
; i
++) {
2790 g_free(process_list
->current_hash_data
[i
]);
2792 g_free(process_list
->current_hash_data
);
2793 process_list
->current_hash_data
= NULL
;
2796 end_time
= LTT_TIME_MIN(tfc
->timestamp
, events_request
->end_time
);
2797 else /* end of traceset, or position now out of request : end */
2798 end_time
= events_request
->end_time
;
2800 ClosureData closure_data
;
2801 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2802 closure_data
.tss
= tss
;
2803 closure_data
.end_time
= end_time
;
2805 TimeWindow time_window
=
2806 lttvwindow_get_time_window(control_flow_data
->tab
);
2807 guint width
= control_flow_data
->drawing
->width
;
2808 convert_time_to_pixels(
2812 &closure_data
.x_end
);
2814 /* Draw last items */
2815 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2816 (void*)&closure_data
);
2818 /* Reactivate sort */
2819 gtk_tree_sortable_set_sort_column_id(
2820 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2821 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2822 GTK_SORT_ASCENDING
);
2824 update_index_to_pixmap(control_flow_data
->process_list
);
2825 /* Request a full expose : drawing scrambled */
2826 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2828 /* Request expose (updates damages zone also) */
2829 drawing_request_expose(events_request
, tss
, end_time
);
2834 /* after_statedump_end
2836 * @param hook_data ControlFlowData structure of the viewer.
2837 * @param call_data Event context.
2839 * This function adds items to be drawn in a queue for each process.
2842 int before_statedump_end(void *hook_data
, void *call_data
)
2844 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2845 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
2846 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2848 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2850 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
2852 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
2854 LttvTracesetState
*tss
= (LttvTracesetState
*)tfc
->t_context
->ts_context
;
2855 ProcessList
*process_list
= control_flow_data
->process_list
;
2858 e
= ltt_tracefile_get_event(tfc
->tf
);
2860 LttvFilter
*filter
= control_flow_data
->filter
;
2861 if(filter
!= NULL
&& filter
->head
!= NULL
)
2862 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2863 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2866 LttTime evtime
= ltt_event_time(e
);
2868 ClosureData closure_data
;
2869 closure_data
.events_request
= events_request
;
2870 closure_data
.tss
= tss
;
2871 closure_data
.end_time
= evtime
;
2873 TimeWindow time_window
=
2874 lttvwindow_get_time_window(control_flow_data
->tab
);
2875 guint width
= control_flow_data
->drawing
->width
;
2876 convert_time_to_pixels(
2880 &closure_data
.x_end
);
2882 /* Draw last items */
2883 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2884 (void*)&closure_data
);
2886 /* Reactivate sort */
2887 gtk_tree_sortable_set_sort_column_id(
2888 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2889 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2890 GTK_SORT_ASCENDING
);
2892 update_index_to_pixmap(control_flow_data
->process_list
);
2893 /* Request a full expose : drawing scrambled */
2894 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2896 /* Request expose (updates damages zone also) */
2897 drawing_request_expose(events_request
, tss
, evtime
);