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 4
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
];
270 g_critical("unknown state : %s", g_quark_to_string(process
->state
->s
));
271 g_assert(FALSE
); /* UNKNOWN STATE */
279 /* before_schedchange_hook
281 * This function basically draw lines and icons. Two types of lines are drawn :
282 * one small (3 pixels?) representing the state of the process and the second
283 * type is thicker (10 pixels?) representing on which CPU a process is running
284 * (and this only in running state).
286 * Extremums of the lines :
287 * x_min : time of the last event context for this process kept in memory.
288 * x_max : time of the current event.
289 * y : middle of the process in the process list. The process is found in the
290 * list, therefore is it's position in pixels.
292 * The choice of lines'color is defined by the context of the last event for this
297 int before_schedchange_hook(void *hook_data
, void *call_data
)
299 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
300 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
301 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
303 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
305 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
306 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
309 e
= ltt_tracefile_get_event(tfc
->tf
);
310 gint target_pid_saved
= tfc
->target_pid
;
312 LttTime evtime
= ltt_event_time(e
);
313 LttvFilter
*filter
= control_flow_data
->filter
;
315 /* we are in a schedchange, before the state update. We must draw the
316 * items corresponding to the state before it changes : now is the right
323 pid_out
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
324 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
327 tfc
->target_pid
= pid_out
;
328 if(!filter
|| !filter
->head
||
329 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
330 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
331 /* For the pid_out */
332 /* First, check if the current process is in the state computation
333 * process list. If it is there, that means we must add it right now and
334 * draw items from the beginning of the read for it. If it is not
335 * present, it's a new process and it was not present : it will
336 * be added after the state update. */
337 guint cpu
= tfs
->cpu
;
338 guint trace_num
= ts
->parent
.index
;
339 LttvProcessState
*process
= ts
->running_process
[cpu
];
340 /* unknown state, bad current pid */
341 if(process
->pid
!= pid_out
)
342 process
= lttv_state_find_process(ts
,
345 if(process
!= NULL
) {
346 /* Well, the process_out existed : we must get it in the process hash
347 * or add it, and draw its items.
349 /* Add process to process list (if not present) */
351 HashedProcessData
*hashed_process_data
= NULL
;
352 ProcessList
*process_list
= control_flow_data
->process_list
;
353 LttTime birth
= process
->creation_time
;
355 hashed_process_data
= processlist_get_process_data(process_list
,
360 if(hashed_process_data
== NULL
)
362 g_assert(pid_out
== 0 || pid_out
!= process
->ppid
);
363 /* Process not present */
364 ProcessInfo
*process_info
;
365 Drawing_t
*drawing
= control_flow_data
->drawing
;
366 processlist_add(process_list
,
378 &hashed_process_data
);
379 gtk_widget_set_size_request(drawing
->drawing_area
,
382 gtk_widget_queue_draw(drawing
->drawing_area
);
386 /* Now, the process is in the state hash and our own process hash.
387 * We definitely can draw the items related to the ending state.
390 if(ltt_time_compare(hashed_process_data
->next_good_time
,
393 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
395 TimeWindow time_window
=
396 lttvwindow_get_time_window(control_flow_data
->tab
);
398 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
399 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
402 Drawing_t
*drawing
= control_flow_data
->drawing
;
403 guint width
= drawing
->width
;
405 convert_time_to_pixels(
411 /* Draw collision indicator */
412 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
413 gdk_draw_point(hashed_process_data
->pixmap
,
416 COLLISION_POSITION(hashed_process_data
->height
));
417 hashed_process_data
->x
.middle_marked
= TRUE
;
420 TimeWindow time_window
=
421 lttvwindow_get_time_window(control_flow_data
->tab
);
423 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
424 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
427 Drawing_t
*drawing
= control_flow_data
->drawing
;
428 guint width
= drawing
->width
;
430 convert_time_to_pixels(
437 /* Jump over draw if we are at the same x position */
438 if(x
== hashed_process_data
->x
.middle
&&
439 hashed_process_data
->x
.middle_used
)
441 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
442 /* Draw collision indicator */
443 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
444 gdk_draw_point(hashed_process_data
->pixmap
,
447 COLLISION_POSITION(hashed_process_data
->height
));
448 hashed_process_data
->x
.middle_marked
= TRUE
;
452 DrawContext draw_context
;
454 /* Now create the drawing context that will be used to draw
455 * items related to the last state. */
456 draw_context
.drawable
= hashed_process_data
->pixmap
;
457 draw_context
.gc
= drawing
->gc
;
458 draw_context
.pango_layout
= drawing
->pango_layout
;
459 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
460 draw_context
.drawinfo
.end
.x
= x
;
462 draw_context
.drawinfo
.y
.over
= 1;
463 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
464 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
466 draw_context
.drawinfo
.start
.offset
.over
= 0;
467 draw_context
.drawinfo
.start
.offset
.middle
= 0;
468 draw_context
.drawinfo
.start
.offset
.under
= 0;
469 draw_context
.drawinfo
.end
.offset
.over
= 0;
470 draw_context
.drawinfo
.end
.offset
.middle
= 0;
471 draw_context
.drawinfo
.end
.offset
.under
= 0;
475 PropertiesLine prop_line
= prepare_s_e_line(process
);
476 draw_line((void*)&prop_line
, (void*)&draw_context
);
479 /* become the last x position */
480 hashed_process_data
->x
.middle
= x
;
481 hashed_process_data
->x
.middle_used
= TRUE
;
482 hashed_process_data
->x
.middle_marked
= FALSE
;
484 /* Calculate the next good time */
485 convert_pixels_to_time(width
, x
+1, time_window
,
486 &hashed_process_data
->next_good_time
);
492 tfc
->target_pid
= pid_in
;
493 if(!filter
|| !filter
->head
||
494 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
495 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
497 /* First, check if the current process is in the state computation
498 * process list. If it is there, that means we must add it right now and
499 * draw items from the beginning of the read for it. If it is not
500 * present, it's a new process and it was not present : it will
501 * be added after the state update. */
502 LttvProcessState
*process
;
503 process
= lttv_state_find_process(ts
,
505 guint trace_num
= ts
->parent
.index
;
507 if(process
!= NULL
) {
508 /* Well, the process existed : we must get it in the process hash
509 * or add it, and draw its items.
511 /* Add process to process list (if not present) */
513 HashedProcessData
*hashed_process_data
= NULL
;
514 ProcessList
*process_list
= control_flow_data
->process_list
;
515 LttTime birth
= process
->creation_time
;
517 hashed_process_data
= processlist_get_process_data(process_list
,
522 if(hashed_process_data
== NULL
)
524 g_assert(pid_in
== 0 || pid_in
!= process
->ppid
);
525 /* Process not present */
526 ProcessInfo
*process_info
;
527 Drawing_t
*drawing
= control_flow_data
->drawing
;
528 processlist_add(process_list
,
540 &hashed_process_data
);
541 gtk_widget_set_size_request(drawing
->drawing_area
,
544 gtk_widget_queue_draw(drawing
->drawing_area
);
547 //We could set the current process and hash here, but will be done
548 //by after schedchange hook
550 /* Now, the process is in the state hash and our own process hash.
551 * We definitely can draw the items related to the ending state.
554 if(ltt_time_compare(hashed_process_data
->next_good_time
,
557 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
559 TimeWindow time_window
=
560 lttvwindow_get_time_window(control_flow_data
->tab
);
562 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
563 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
566 Drawing_t
*drawing
= control_flow_data
->drawing
;
567 guint width
= drawing
->width
;
569 convert_time_to_pixels(
575 /* Draw collision indicator */
576 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
577 gdk_draw_point(hashed_process_data
->pixmap
,
580 COLLISION_POSITION(hashed_process_data
->height
));
581 hashed_process_data
->x
.middle_marked
= TRUE
;
584 TimeWindow time_window
=
585 lttvwindow_get_time_window(control_flow_data
->tab
);
587 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
588 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
591 Drawing_t
*drawing
= control_flow_data
->drawing
;
592 guint width
= drawing
->width
;
595 convert_time_to_pixels(
602 /* Jump over draw if we are at the same x position */
603 if(x
== hashed_process_data
->x
.middle
&&
604 hashed_process_data
->x
.middle_used
)
606 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
607 /* Draw collision indicator */
608 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
609 gdk_draw_point(hashed_process_data
->pixmap
,
612 COLLISION_POSITION(hashed_process_data
->height
));
613 hashed_process_data
->x
.middle_marked
= TRUE
;
617 DrawContext draw_context
;
619 /* Now create the drawing context that will be used to draw
620 * items related to the last state. */
621 draw_context
.drawable
= hashed_process_data
->pixmap
;
622 draw_context
.gc
= drawing
->gc
;
623 draw_context
.pango_layout
= drawing
->pango_layout
;
624 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
625 draw_context
.drawinfo
.end
.x
= x
;
627 draw_context
.drawinfo
.y
.over
= 1;
628 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
629 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
631 draw_context
.drawinfo
.start
.offset
.over
= 0;
632 draw_context
.drawinfo
.start
.offset
.middle
= 0;
633 draw_context
.drawinfo
.start
.offset
.under
= 0;
634 draw_context
.drawinfo
.end
.offset
.over
= 0;
635 draw_context
.drawinfo
.end
.offset
.middle
= 0;
636 draw_context
.drawinfo
.end
.offset
.under
= 0;
640 PropertiesLine prop_line
= prepare_s_e_line(process
);
641 draw_line((void*)&prop_line
, (void*)&draw_context
);
645 /* become the last x position */
646 hashed_process_data
->x
.middle
= x
;
647 hashed_process_data
->x
.middle_used
= TRUE
;
648 hashed_process_data
->x
.middle_marked
= FALSE
;
650 /* Calculate the next good time */
651 convert_pixels_to_time(width
, x
+1, time_window
,
652 &hashed_process_data
->next_good_time
);
656 g_warning("Cannot find pin_in in schedchange %u", pid_in
);
658 tfc
->target_pid
= target_pid_saved
;
666 GString
*string
= g_string_new("");;
667 gboolean field_names
= TRUE
, state
= TRUE
;
669 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
670 g_string_append_printf(string
,"\n");
673 g_string_append_printf(string
, " %s",
674 g_quark_to_string(tfs
->process
->state
->s
));
677 g_info("%s",string
->str
);
679 g_string_free(string
, TRUE
);
681 /* End of text dump */
686 /* after_schedchange_hook
688 * The draw after hook is called by the reading API to have a
689 * particular event drawn on the screen.
690 * @param hook_data ControlFlowData structure of the viewer.
691 * @param call_data Event context.
693 * This function adds items to be drawn in a queue for each process.
696 int after_schedchange_hook(void *hook_data
, void *call_data
)
698 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
699 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
700 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
702 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
704 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
706 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
709 e
= ltt_tracefile_get_event(tfc
->tf
);
711 LttvFilter
*filter
= control_flow_data
->filter
;
712 if(filter
!= NULL
&& filter
->head
!= NULL
)
713 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
714 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
717 LttTime evtime
= ltt_event_time(e
);
719 /* Add process to process list (if not present) */
720 LttvProcessState
*process_in
;
723 HashedProcessData
*hashed_process_data_in
= NULL
;
725 ProcessList
*process_list
= control_flow_data
->process_list
;
730 pid_out
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
731 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
735 /* Find process pid_in in the list... */
736 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
737 //process_in = tfs->process;
738 guint cpu
= tfs
->cpu
;
739 guint trace_num
= ts
->parent
.index
;
740 process_in
= ts
->running_process
[cpu
];
741 /* It should exist, because we are after the state update. */
743 g_assert(process_in
!= NULL
);
745 birth
= process_in
->creation_time
;
747 hashed_process_data_in
= processlist_get_process_data(process_list
,
752 if(hashed_process_data_in
== NULL
)
754 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
755 ProcessInfo
*process_info
;
756 Drawing_t
*drawing
= control_flow_data
->drawing
;
757 /* Process not present */
758 processlist_add(process_list
,
770 &hashed_process_data_in
);
771 gtk_widget_set_size_request(drawing
->drawing_area
,
774 gtk_widget_queue_draw(drawing
->drawing_area
);
776 /* Set the current process */
777 process_list
->current_hash_data
[trace_num
][process_in
->cpu
] =
778 hashed_process_data_in
;
780 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
783 TimeWindow time_window
=
784 lttvwindow_get_time_window(control_flow_data
->tab
);
787 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
788 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
791 Drawing_t
*drawing
= control_flow_data
->drawing
;
792 guint width
= drawing
->width
;
795 convert_time_to_pixels(
801 if(hashed_process_data_in
->x
.middle
!= new_x
) {
802 hashed_process_data_in
->x
.middle
= new_x
;
803 hashed_process_data_in
->x
.middle_used
= FALSE
;
804 hashed_process_data_in
->x
.middle_marked
= FALSE
;
813 /* before_execmode_hook
815 * This function basically draw lines and icons. Two types of lines are drawn :
816 * one small (3 pixels?) representing the state of the process and the second
817 * type is thicker (10 pixels?) representing on which CPU a process is running
818 * (and this only in running state).
820 * Extremums of the lines :
821 * x_min : time of the last event context for this process kept in memory.
822 * x_max : time of the current event.
823 * y : middle of the process in the process list. The process is found in the
824 * list, therefore is it's position in pixels.
826 * The choice of lines'color is defined by the context of the last event for this
831 int before_execmode_hook(void *hook_data
, void *call_data
)
833 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
834 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
835 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
837 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
839 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
841 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
844 e
= ltt_tracefile_get_event(tfc
->tf
);
846 LttvFilter
*filter
= control_flow_data
->filter
;
847 if(filter
!= NULL
&& filter
->head
!= NULL
)
848 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
849 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
852 LttTime evtime
= ltt_event_time(e
);
854 /* we are in a execmode, before the state update. We must draw the
855 * items corresponding to the state before it changes : now is the right
859 //LttvProcessState *process = tfs->process;
860 guint cpu
= tfs
->cpu
;
861 guint trace_num
= ts
->parent
.index
;
862 LttvProcessState
*process
= ts
->running_process
[cpu
];
863 g_assert(process
!= NULL
);
865 guint pid
= process
->pid
;
867 /* Well, the process_out existed : we must get it in the process hash
868 * or add it, and draw its items.
870 /* Add process to process list (if not present) */
872 HashedProcessData
*hashed_process_data
= NULL
;
873 ProcessList
*process_list
= control_flow_data
->process_list
;
874 LttTime birth
= process
->creation_time
;
876 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
877 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
879 hashed_process_data
= processlist_get_process_data(process_list
,
884 if(unlikely(hashed_process_data
== NULL
))
886 g_assert(pid
== 0 || pid
!= process
->ppid
);
887 ProcessInfo
*process_info
;
888 /* Process not present */
889 Drawing_t
*drawing
= control_flow_data
->drawing
;
890 processlist_add(process_list
,
902 &hashed_process_data
);
903 gtk_widget_set_size_request(drawing
->drawing_area
,
906 gtk_widget_queue_draw(drawing
->drawing_area
);
908 /* Set the current process */
909 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
913 /* Now, the process is in the state hash and our own process hash.
914 * We definitely can draw the items related to the ending state.
917 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
920 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
921 TimeWindow time_window
=
922 lttvwindow_get_time_window(control_flow_data
->tab
);
925 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
926 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
929 Drawing_t
*drawing
= control_flow_data
->drawing
;
930 guint width
= drawing
->width
;
932 convert_time_to_pixels(
938 /* Draw collision indicator */
939 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
940 gdk_draw_point(hashed_process_data
->pixmap
,
943 COLLISION_POSITION(hashed_process_data
->height
));
944 hashed_process_data
->x
.middle_marked
= TRUE
;
947 TimeWindow time_window
=
948 lttvwindow_get_time_window(control_flow_data
->tab
);
951 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
952 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
955 Drawing_t
*drawing
= control_flow_data
->drawing
;
956 guint width
= drawing
->width
;
959 convert_time_to_pixels(
966 /* Jump over draw if we are at the same x position */
967 if(unlikely(x
== hashed_process_data
->x
.middle
&&
968 hashed_process_data
->x
.middle_used
))
970 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
971 /* Draw collision indicator */
972 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
973 gdk_draw_point(hashed_process_data
->pixmap
,
976 COLLISION_POSITION(hashed_process_data
->height
));
977 hashed_process_data
->x
.middle_marked
= TRUE
;
982 DrawContext draw_context
;
983 /* Now create the drawing context that will be used to draw
984 * items related to the last state. */
985 draw_context
.drawable
= hashed_process_data
->pixmap
;
986 draw_context
.gc
= drawing
->gc
;
987 draw_context
.pango_layout
= drawing
->pango_layout
;
988 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
989 draw_context
.drawinfo
.end
.x
= x
;
991 draw_context
.drawinfo
.y
.over
= 1;
992 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
993 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
995 draw_context
.drawinfo
.start
.offset
.over
= 0;
996 draw_context
.drawinfo
.start
.offset
.middle
= 0;
997 draw_context
.drawinfo
.start
.offset
.under
= 0;
998 draw_context
.drawinfo
.end
.offset
.over
= 0;
999 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1000 draw_context
.drawinfo
.end
.offset
.under
= 0;
1004 PropertiesLine prop_line
= prepare_s_e_line(process
);
1005 draw_line((void*)&prop_line
, (void*)&draw_context
);
1008 /* become the last x position */
1009 hashed_process_data
->x
.middle
= x
;
1010 hashed_process_data
->x
.middle_used
= TRUE
;
1011 hashed_process_data
->x
.middle_marked
= FALSE
;
1013 /* Calculate the next good time */
1014 convert_pixels_to_time(width
, x
+1, time_window
,
1015 &hashed_process_data
->next_good_time
);
1022 /* before_process_exit_hook
1024 * Draw lines for process event.
1026 * @param hook_data ControlFlowData structure of the viewer.
1027 * @param call_data Event context.
1029 * This function adds items to be drawn in a queue for each process.
1034 int before_process_exit_hook(void *hook_data
, void *call_data
)
1036 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1037 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1039 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1041 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1043 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1045 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1048 e
= ltt_tracefile_get_event(tfc
->tf
);
1050 LttvFilter
*filter
= control_flow_data
->filter
;
1051 if(filter
!= NULL
&& filter
->head
!= NULL
)
1052 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1053 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1056 LttTime evtime
= ltt_event_time(e
);
1058 /* Add process to process list (if not present) */
1059 //LttvProcessState *process = tfs->process;
1060 guint cpu
= tfs
->cpu
;
1061 guint trace_num
= ts
->parent
.index
;
1062 LttvProcessState
*process
= ts
->running_process
[cpu
];
1063 guint pid
= process
->pid
;
1065 guint pl_height
= 0;
1066 HashedProcessData
*hashed_process_data
= NULL
;
1068 ProcessList
*process_list
= control_flow_data
->process_list
;
1070 g_assert(process
!= NULL
);
1072 birth
= process
->creation_time
;
1074 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1075 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1077 hashed_process_data
= processlist_get_process_data(process_list
,
1082 if(unlikely(hashed_process_data
== NULL
))
1084 g_assert(pid
== 0 || pid
!= process
->ppid
);
1085 /* Process not present */
1086 Drawing_t
*drawing
= control_flow_data
->drawing
;
1087 ProcessInfo
*process_info
;
1088 processlist_add(process_list
,
1100 &hashed_process_data
);
1101 gtk_widget_set_size_request(drawing
->drawing_area
,
1104 gtk_widget_queue_draw(drawing
->drawing_area
);
1108 /* Now, the process is in the state hash and our own process hash.
1109 * We definitely can draw the items related to the ending state.
1112 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1115 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1116 TimeWindow time_window
=
1117 lttvwindow_get_time_window(control_flow_data
->tab
);
1120 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1121 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1123 #endif //EXTRA_CHECK
1124 Drawing_t
*drawing
= control_flow_data
->drawing
;
1125 guint width
= drawing
->width
;
1127 convert_time_to_pixels(
1133 /* Draw collision indicator */
1134 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1135 gdk_draw_point(hashed_process_data
->pixmap
,
1138 COLLISION_POSITION(hashed_process_data
->height
));
1139 hashed_process_data
->x
.middle_marked
= TRUE
;
1142 TimeWindow time_window
=
1143 lttvwindow_get_time_window(control_flow_data
->tab
);
1146 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1147 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1149 #endif //EXTRA_CHECK
1150 Drawing_t
*drawing
= control_flow_data
->drawing
;
1151 guint width
= drawing
->width
;
1154 convert_time_to_pixels(
1161 /* Jump over draw if we are at the same x position */
1162 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1163 hashed_process_data
->x
.middle_used
))
1165 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1166 /* Draw collision indicator */
1167 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1168 gdk_draw_point(hashed_process_data
->pixmap
,
1171 COLLISION_POSITION(hashed_process_data
->height
));
1172 hashed_process_data
->x
.middle_marked
= TRUE
;
1176 DrawContext draw_context
;
1178 /* Now create the drawing context that will be used to draw
1179 * items related to the last state. */
1180 draw_context
.drawable
= hashed_process_data
->pixmap
;
1181 draw_context
.gc
= drawing
->gc
;
1182 draw_context
.pango_layout
= drawing
->pango_layout
;
1183 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1184 draw_context
.drawinfo
.end
.x
= x
;
1186 draw_context
.drawinfo
.y
.over
= 1;
1187 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1188 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1190 draw_context
.drawinfo
.start
.offset
.over
= 0;
1191 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1192 draw_context
.drawinfo
.start
.offset
.under
= 0;
1193 draw_context
.drawinfo
.end
.offset
.over
= 0;
1194 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1195 draw_context
.drawinfo
.end
.offset
.under
= 0;
1199 PropertiesLine prop_line
= prepare_s_e_line(process
);
1200 draw_line((void*)&prop_line
, (void*)&draw_context
);
1203 /* become the last x position */
1204 hashed_process_data
->x
.middle
= x
;
1205 hashed_process_data
->x
.middle_used
= TRUE
;
1206 hashed_process_data
->x
.middle_marked
= FALSE
;
1208 /* Calculate the next good time */
1209 convert_pixels_to_time(width
, x
+1, time_window
,
1210 &hashed_process_data
->next_good_time
);
1220 /* before_process_release_hook
1222 * Draw lines for process event.
1224 * @param hook_data ControlFlowData structure of the viewer.
1225 * @param call_data Event context.
1227 * This function adds items to be drawn in a queue for each process.
1232 int before_process_release_hook(void *hook_data
, void *call_data
)
1234 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1235 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1237 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1239 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1241 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1243 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1246 e
= ltt_tracefile_get_event(tfc
->tf
);
1248 LttvFilter
*filter
= control_flow_data
->filter
;
1249 if(filter
!= NULL
&& filter
->head
!= NULL
)
1250 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1251 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1254 LttTime evtime
= ltt_event_time(e
);
1256 guint trace_num
= ts
->parent
.index
;
1260 pid
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
1263 /* Add process to process list (if not present) */
1264 /* Don't care about the process if it's not in the state hash already :
1265 * that means a process that has never done anything in the trace and
1266 * unknown suddently gets destroyed : no state meaningful to show. */
1267 LttvProcessState
*process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1269 if(process
!= NULL
) {
1271 guint pl_height
= 0;
1272 HashedProcessData
*hashed_process_data
= NULL
;
1274 ProcessList
*process_list
= control_flow_data
->process_list
;
1276 birth
= process
->creation_time
;
1278 /* Cannot use current process : this event happens on another process,
1279 * action done by the parent. */
1280 hashed_process_data
= processlist_get_process_data(process_list
,
1285 if(unlikely(hashed_process_data
== NULL
))
1287 * Process already been scheduled out EXIT_DEAD, not in the process list
1288 * anymore. Just return.
1292 /* Now, the process is in the state hash and our own process hash.
1293 * We definitely can draw the items related to the ending state.
1296 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1299 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1300 TimeWindow time_window
=
1301 lttvwindow_get_time_window(control_flow_data
->tab
);
1304 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1305 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1307 #endif //EXTRA_CHECK
1308 Drawing_t
*drawing
= control_flow_data
->drawing
;
1309 guint width
= drawing
->width
;
1311 convert_time_to_pixels(
1317 /* Draw collision indicator */
1318 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1319 gdk_draw_point(hashed_process_data
->pixmap
,
1322 COLLISION_POSITION(hashed_process_data
->height
));
1323 hashed_process_data
->x
.middle_marked
= TRUE
;
1326 TimeWindow time_window
=
1327 lttvwindow_get_time_window(control_flow_data
->tab
);
1330 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1331 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1333 #endif //EXTRA_CHECK
1334 Drawing_t
*drawing
= control_flow_data
->drawing
;
1335 guint width
= drawing
->width
;
1338 convert_time_to_pixels(
1345 /* Jump over draw if we are at the same x position */
1346 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1347 hashed_process_data
->x
.middle_used
))
1349 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1350 /* Draw collision indicator */
1351 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1352 gdk_draw_point(hashed_process_data
->pixmap
,
1355 COLLISION_POSITION(hashed_process_data
->height
));
1356 hashed_process_data
->x
.middle_marked
= TRUE
;
1360 DrawContext draw_context
;
1362 /* Now create the drawing context that will be used to draw
1363 * items related to the last state. */
1364 draw_context
.drawable
= hashed_process_data
->pixmap
;
1365 draw_context
.gc
= drawing
->gc
;
1366 draw_context
.pango_layout
= drawing
->pango_layout
;
1367 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1368 draw_context
.drawinfo
.end
.x
= x
;
1370 draw_context
.drawinfo
.y
.over
= 1;
1371 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1372 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1374 draw_context
.drawinfo
.start
.offset
.over
= 0;
1375 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1376 draw_context
.drawinfo
.start
.offset
.under
= 0;
1377 draw_context
.drawinfo
.end
.offset
.over
= 0;
1378 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1379 draw_context
.drawinfo
.end
.offset
.under
= 0;
1383 PropertiesLine prop_line
= prepare_s_e_line(process
);
1384 draw_line((void*)&prop_line
, (void*)&draw_context
);
1387 /* become the last x position */
1388 hashed_process_data
->x
.middle
= x
;
1389 hashed_process_data
->x
.middle_used
= TRUE
;
1390 hashed_process_data
->x
.middle_marked
= FALSE
;
1392 /* Calculate the next good time */
1393 convert_pixels_to_time(width
, x
+1, time_window
,
1394 &hashed_process_data
->next_good_time
);
1406 /* after_process_fork_hook
1408 * Create the processlist entry for the child process. Put the last
1409 * position in x at the current time value.
1411 * @param hook_data ControlFlowData structure of the viewer.
1412 * @param call_data Event context.
1414 * This function adds items to be drawn in a queue for each process.
1417 int after_process_fork_hook(void *hook_data
, void *call_data
)
1419 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1420 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1421 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1423 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1425 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1427 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1430 e
= ltt_tracefile_get_event(tfc
->tf
);
1432 LttvFilter
*filter
= control_flow_data
->filter
;
1433 if(filter
!= NULL
&& filter
->head
!= NULL
)
1434 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1435 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1438 LttTime evtime
= ltt_event_time(e
);
1442 child_pid
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
1445 /* Add process to process list (if not present) */
1446 LttvProcessState
*process_child
;
1448 guint pl_height
= 0;
1449 HashedProcessData
*hashed_process_data_child
= NULL
;
1451 ProcessList
*process_list
= control_flow_data
->process_list
;
1453 /* Find child in the list... */
1454 process_child
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1455 /* It should exist, because we are after the state update. */
1456 g_assert(process_child
!= NULL
);
1458 birth
= process_child
->creation_time
;
1459 guint trace_num
= ts
->parent
.index
;
1461 /* Cannot use current process, because this action is done by the parent
1463 hashed_process_data_child
= processlist_get_process_data(process_list
,
1468 if(likely(hashed_process_data_child
== NULL
))
1470 g_assert(child_pid
== 0 || child_pid
!= process_child
->ppid
);
1471 /* Process not present */
1472 Drawing_t
*drawing
= control_flow_data
->drawing
;
1473 ProcessInfo
*process_info
;
1474 processlist_add(process_list
,
1477 process_child
->tgid
,
1479 process_child
->ppid
,
1482 process_child
->name
,
1483 process_child
->brand
,
1486 &hashed_process_data_child
);
1487 gtk_widget_set_size_request(drawing
->drawing_area
,
1490 gtk_widget_queue_draw(drawing
->drawing_area
);
1492 processlist_set_ppid(process_list
, process_child
->ppid
,
1493 hashed_process_data_child
);
1494 processlist_set_tgid(process_list
, process_child
->tgid
,
1495 hashed_process_data_child
);
1499 if(likely(ltt_time_compare(hashed_process_data_child
->next_good_time
,
1502 TimeWindow time_window
=
1503 lttvwindow_get_time_window(control_flow_data
->tab
);
1506 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1507 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1509 #endif //EXTRA_CHECK
1510 Drawing_t
*drawing
= control_flow_data
->drawing
;
1511 guint width
= drawing
->width
;
1513 convert_time_to_pixels(
1519 if(likely(hashed_process_data_child
->x
.over
!= new_x
)) {
1520 hashed_process_data_child
->x
.over
= new_x
;
1521 hashed_process_data_child
->x
.over_used
= FALSE
;
1522 hashed_process_data_child
->x
.over_marked
= FALSE
;
1524 if(likely(hashed_process_data_child
->x
.middle
!= new_x
)) {
1525 hashed_process_data_child
->x
.middle
= new_x
;
1526 hashed_process_data_child
->x
.middle_used
= FALSE
;
1527 hashed_process_data_child
->x
.middle_marked
= FALSE
;
1529 if(likely(hashed_process_data_child
->x
.under
!= new_x
)) {
1530 hashed_process_data_child
->x
.under
= new_x
;
1531 hashed_process_data_child
->x
.under_used
= FALSE
;
1532 hashed_process_data_child
->x
.under_marked
= FALSE
;
1540 /* after_process_exit_hook
1542 * Create the processlist entry for the child process. Put the last
1543 * position in x at the current time value.
1545 * @param hook_data ControlFlowData structure of the viewer.
1546 * @param call_data Event context.
1548 * This function adds items to be drawn in a queue for each process.
1551 int after_process_exit_hook(void *hook_data
, void *call_data
)
1553 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1554 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1555 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1557 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1559 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1561 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1564 e
= ltt_tracefile_get_event(tfc
->tf
);
1566 LttvFilter
*filter
= control_flow_data
->filter
;
1567 if(filter
!= NULL
&& filter
->head
!= NULL
)
1568 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1569 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1572 LttTime evtime
= ltt_event_time(e
);
1574 /* Add process to process list (if not present) */
1575 //LttvProcessState *process = tfs->process;
1576 guint cpu
= tfs
->cpu
;
1577 guint trace_num
= ts
->parent
.index
;
1578 LttvProcessState
*process
= ts
->running_process
[cpu
];
1580 /* It should exist, because we are after the state update. */
1581 g_assert(process
!= NULL
);
1583 guint pid
= process
->pid
;
1585 guint pl_height
= 0;
1586 HashedProcessData
*hashed_process_data
= NULL
;
1588 ProcessList
*process_list
= control_flow_data
->process_list
;
1590 birth
= process
->creation_time
;
1592 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
) ){
1593 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1595 hashed_process_data
= processlist_get_process_data(process_list
,
1600 if(unlikely(hashed_process_data
== NULL
))
1602 g_assert(pid
== 0 || pid
!= process
->ppid
);
1603 /* Process not present */
1604 Drawing_t
*drawing
= control_flow_data
->drawing
;
1605 ProcessInfo
*process_info
;
1606 processlist_add(process_list
,
1618 &hashed_process_data
);
1619 gtk_widget_set_size_request(drawing
->drawing_area
,
1622 gtk_widget_queue_draw(drawing
->drawing_area
);
1625 /* Set the current process */
1626 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1627 hashed_process_data
;
1630 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
1633 TimeWindow time_window
=
1634 lttvwindow_get_time_window(control_flow_data
->tab
);
1637 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1638 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1640 #endif //EXTRA_CHECK
1641 Drawing_t
*drawing
= control_flow_data
->drawing
;
1642 guint width
= drawing
->width
;
1644 convert_time_to_pixels(
1649 if(unlikely(hashed_process_data
->x
.middle
!= new_x
)) {
1650 hashed_process_data
->x
.middle
= new_x
;
1651 hashed_process_data
->x
.middle_used
= FALSE
;
1652 hashed_process_data
->x
.middle_marked
= FALSE
;
1660 /* Get the filename of the process to print */
1661 int after_fs_exec_hook(void *hook_data
, void *call_data
)
1663 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1664 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1665 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1667 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1669 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1671 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1674 e
= ltt_tracefile_get_event(tfc
->tf
);
1676 LttvFilter
*filter
= control_flow_data
->filter
;
1677 if(filter
!= NULL
&& filter
->head
!= NULL
)
1678 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1679 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1682 guint cpu
= tfs
->cpu
;
1683 guint trace_num
= ts
->parent
.index
;
1684 LttvProcessState
*process
= ts
->running_process
[cpu
];
1685 g_assert(process
!= NULL
);
1687 guint pid
= process
->pid
;
1689 /* Well, the process_out existed : we must get it in the process hash
1690 * or add it, and draw its items.
1692 /* Add process to process list (if not present) */
1693 guint pl_height
= 0;
1694 HashedProcessData
*hashed_process_data
= NULL
;
1695 ProcessList
*process_list
= control_flow_data
->process_list
;
1696 LttTime birth
= process
->creation_time
;
1698 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1699 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1701 hashed_process_data
= processlist_get_process_data(process_list
,
1706 if(unlikely(hashed_process_data
== NULL
))
1708 g_assert(pid
== 0 || pid
!= process
->ppid
);
1709 ProcessInfo
*process_info
;
1710 /* Process not present */
1711 Drawing_t
*drawing
= control_flow_data
->drawing
;
1712 processlist_add(process_list
,
1724 &hashed_process_data
);
1725 gtk_widget_set_size_request(drawing
->drawing_area
,
1728 gtk_widget_queue_draw(drawing
->drawing_area
);
1730 /* Set the current process */
1731 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1732 hashed_process_data
;
1735 processlist_set_name(process_list
, process
->name
, hashed_process_data
);
1741 /* Get the filename of the process to print */
1742 int after_user_generic_thread_brand_hook(void *hook_data
, void *call_data
)
1744 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1745 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1746 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1748 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1750 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1752 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1755 e
= ltt_tracefile_get_event(tfc
->tf
);
1757 LttvFilter
*filter
= control_flow_data
->filter
;
1758 if(filter
!= NULL
&& filter
->head
!= NULL
)
1759 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1760 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1763 guint cpu
= tfs
->cpu
;
1764 guint trace_num
= ts
->parent
.index
;
1765 LttvProcessState
*process
= ts
->running_process
[cpu
];
1766 g_assert(process
!= NULL
);
1768 guint pid
= process
->pid
;
1770 /* Well, the process_out existed : we must get it in the process hash
1771 * or add it, and draw its items.
1773 /* Add process to process list (if not present) */
1774 guint pl_height
= 0;
1775 HashedProcessData
*hashed_process_data
= NULL
;
1776 ProcessList
*process_list
= control_flow_data
->process_list
;
1777 LttTime birth
= process
->creation_time
;
1779 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1780 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1782 hashed_process_data
= processlist_get_process_data(process_list
,
1787 if(unlikely(hashed_process_data
== NULL
))
1789 g_assert(pid
== 0 || pid
!= process
->ppid
);
1790 ProcessInfo
*process_info
;
1791 /* Process not present */
1792 Drawing_t
*drawing
= control_flow_data
->drawing
;
1793 processlist_add(process_list
,
1805 &hashed_process_data
);
1806 gtk_widget_set_size_request(drawing
->drawing_area
,
1809 gtk_widget_queue_draw(drawing
->drawing_area
);
1811 /* Set the current process */
1812 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1813 hashed_process_data
;
1816 processlist_set_brand(process_list
, process
->brand
, hashed_process_data
);
1823 /* after_event_enum_process_hook
1825 * Create the processlist entry for the child process. Put the last
1826 * position in x at the current time value.
1828 * @param hook_data ControlFlowData structure of the viewer.
1829 * @param call_data Event context.
1831 * This function adds items to be drawn in a queue for each process.
1834 int after_event_enum_process_hook(void *hook_data
, void *call_data
)
1836 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1837 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1838 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1840 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1842 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1844 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1846 guint first_cpu
, nb_cpus
, cpu
;
1849 e
= ltt_tracefile_get_event(tfc
->tf
);
1851 LttvFilter
*filter
= control_flow_data
->filter
;
1852 if(filter
!= NULL
&& filter
->head
!= NULL
)
1853 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1854 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1857 LttTime evtime
= ltt_event_time(e
);
1859 /* Add process to process list (if not present) */
1860 LttvProcessState
*process_in
;
1862 guint pl_height
= 0;
1863 HashedProcessData
*hashed_process_data_in
= NULL
;
1865 ProcessList
*process_list
= control_flow_data
->process_list
;
1866 guint trace_num
= ts
->parent
.index
;
1870 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
1875 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1877 first_cpu
= ANY_CPU
;
1878 nb_cpus
= ANY_CPU
+1;
1881 for(cpu
= first_cpu
; cpu
< nb_cpus
; cpu
++) {
1882 /* Find process pid_in in the list... */
1883 process_in
= lttv_state_find_process(ts
, cpu
, pid_in
);
1884 //process_in = tfs->process;
1885 //guint cpu = tfs->cpu;
1886 //guint trace_num = ts->parent.index;
1887 //process_in = ts->running_process[cpu];
1888 /* It should exist, because we are after the state update. */
1890 //g_assert(process_in != NULL);
1891 #endif //EXTRA_CHECK
1892 birth
= process_in
->creation_time
;
1894 hashed_process_data_in
= processlist_get_process_data(process_list
,
1899 if(hashed_process_data_in
== NULL
)
1901 if(pid_in
!= 0 && pid_in
== process_in
->ppid
)
1902 g_critical("TEST %u , %u", pid_in
, process_in
->ppid
);
1903 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
1904 ProcessInfo
*process_info
;
1905 Drawing_t
*drawing
= control_flow_data
->drawing
;
1906 /* Process not present */
1907 processlist_add(process_list
,
1919 &hashed_process_data_in
);
1920 gtk_widget_set_size_request(drawing
->drawing_area
,
1923 gtk_widget_queue_draw(drawing
->drawing_area
);
1925 processlist_set_name(process_list
, process_in
->name
,
1926 hashed_process_data_in
);
1927 processlist_set_ppid(process_list
, process_in
->ppid
,
1928 hashed_process_data_in
);
1929 processlist_set_tgid(process_list
, process_in
->tgid
,
1930 hashed_process_data_in
);
1937 gint
update_time_window_hook(void *hook_data
, void *call_data
)
1939 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1940 Drawing_t
*drawing
= control_flow_data
->drawing
;
1941 ProcessList
*process_list
= control_flow_data
->process_list
;
1943 const TimeWindowNotifyData
*time_window_nofify_data
=
1944 ((const TimeWindowNotifyData
*)call_data
);
1946 TimeWindow
*old_time_window
=
1947 time_window_nofify_data
->old_time_window
;
1948 TimeWindow
*new_time_window
=
1949 time_window_nofify_data
->new_time_window
;
1951 /* Update the ruler */
1952 drawing_update_ruler(control_flow_data
->drawing
,
1956 /* Two cases : zoom in/out or scrolling */
1958 /* In order to make sure we can reuse the old drawing, the scale must
1959 * be the same and the new time interval being partly located in the
1960 * currently shown time interval. (reuse is only for scrolling)
1963 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
1964 old_time_window
->start_time
.tv_sec
,
1965 old_time_window
->start_time
.tv_nsec
,
1966 old_time_window
->time_width
.tv_sec
,
1967 old_time_window
->time_width
.tv_nsec
);
1969 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
1970 new_time_window
->start_time
.tv_sec
,
1971 new_time_window
->start_time
.tv_nsec
,
1972 new_time_window
->time_width
.tv_sec
,
1973 new_time_window
->time_width
.tv_nsec
);
1975 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
1976 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
1978 /* Same scale (scrolling) */
1979 g_info("scrolling");
1980 LttTime
*ns
= &new_time_window
->start_time
;
1981 LttTime
*nw
= &new_time_window
->time_width
;
1982 LttTime
*os
= &old_time_window
->start_time
;
1983 LttTime
*ow
= &old_time_window
->time_width
;
1984 LttTime old_end
= old_time_window
->end_time
;
1985 LttTime new_end
= new_time_window
->end_time
;
1987 //if(ns<os+w && os+w<ns+w)
1988 //if(ns<old_end && os<ns)
1989 if(ltt_time_compare(*ns
, old_end
) == -1
1990 && ltt_time_compare(*os
, *ns
) == -1)
1992 g_info("scrolling near right");
1993 /* Scroll right, keep right part of the screen */
1995 guint width
= control_flow_data
->drawing
->width
;
1996 convert_time_to_pixels(
2002 /* Copy old data to new location */
2003 copy_pixmap_region(process_list
,
2005 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2009 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
2011 if(drawing
->damage_begin
== drawing
->damage_end
)
2012 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
2014 drawing
->damage_begin
= 0;
2016 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2018 /* Clear the data request background, but not SAFETY */
2019 rectangle_pixmap(process_list
,
2020 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2022 drawing
->damage_begin
+SAFETY
, 0,
2023 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2025 gtk_widget_queue_draw(drawing
->drawing_area
);
2026 //gtk_widget_queue_draw_area (drawing->drawing_area,
2028 // control_flow_data->drawing->width,
2029 // control_flow_data->drawing->height);
2031 /* Get new data for the rest. */
2032 drawing_data_request(control_flow_data
->drawing
,
2033 drawing
->damage_begin
, 0,
2034 drawing
->damage_end
- drawing
->damage_begin
,
2035 control_flow_data
->drawing
->height
);
2038 //if(ns<os && os<ns+w)
2039 //if(ns<os && os<new_end)
2040 if(ltt_time_compare(*ns
,*os
) == -1
2041 && ltt_time_compare(*os
,new_end
) == -1)
2043 g_info("scrolling near left");
2044 /* Scroll left, keep left part of the screen */
2046 guint width
= control_flow_data
->drawing
->width
;
2047 convert_time_to_pixels(
2053 /* Copy old data to new location */
2054 copy_pixmap_region (process_list
,
2056 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2062 if(drawing
->damage_begin
== drawing
->damage_end
)
2063 drawing
->damage_end
= x
;
2065 drawing
->damage_end
=
2066 control_flow_data
->drawing
->width
;
2068 drawing
->damage_begin
= 0;
2070 rectangle_pixmap (process_list
,
2071 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2073 drawing
->damage_begin
, 0,
2074 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2077 gtk_widget_queue_draw(drawing
->drawing_area
);
2078 //gtk_widget_queue_draw_area (drawing->drawing_area,
2080 // control_flow_data->drawing->width,
2081 // control_flow_data->drawing->height);
2084 /* Get new data for the rest. */
2085 drawing_data_request(control_flow_data
->drawing
,
2086 drawing
->damage_begin
, 0,
2087 drawing
->damage_end
- drawing
->damage_begin
,
2088 control_flow_data
->drawing
->height
);
2091 if(ltt_time_compare(*ns
,*os
) == 0)
2093 g_info("not scrolling");
2095 g_info("scrolling far");
2096 /* Cannot reuse any part of the screen : far jump */
2099 rectangle_pixmap (process_list
,
2100 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2103 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2106 //gtk_widget_queue_draw_area (drawing->drawing_area,
2108 // control_flow_data->drawing->width,
2109 // control_flow_data->drawing->height);
2110 gtk_widget_queue_draw(drawing
->drawing_area
);
2112 drawing
->damage_begin
= 0;
2113 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2115 drawing_data_request(control_flow_data
->drawing
,
2117 control_flow_data
->drawing
->width
,
2118 control_flow_data
->drawing
->height
);
2124 /* Different scale (zoom) */
2127 rectangle_pixmap (process_list
,
2128 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2131 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2134 //gtk_widget_queue_draw_area (drawing->drawing_area,
2136 // control_flow_data->drawing->width,
2137 // control_flow_data->drawing->height);
2138 gtk_widget_queue_draw(drawing
->drawing_area
);
2140 drawing
->damage_begin
= 0;
2141 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2143 drawing_data_request(control_flow_data
->drawing
,
2145 control_flow_data
->drawing
->width
,
2146 control_flow_data
->drawing
->height
);
2149 /* Update directly when scrolling */
2150 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2156 gint
traceset_notify(void *hook_data
, void *call_data
)
2158 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2159 Drawing_t
*drawing
= control_flow_data
->drawing
;
2161 if(unlikely(drawing
->gc
== NULL
)) {
2164 if(drawing
->dotted_gc
== NULL
) {
2168 drawing_clear(control_flow_data
->drawing
);
2169 processlist_clear(control_flow_data
->process_list
);
2170 gtk_widget_set_size_request(
2171 control_flow_data
->drawing
->drawing_area
,
2172 -1, processlist_get_height(control_flow_data
->process_list
));
2173 redraw_notify(control_flow_data
, NULL
);
2175 request_background_data(control_flow_data
);
2180 gint
redraw_notify(void *hook_data
, void *call_data
)
2182 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2183 Drawing_t
*drawing
= control_flow_data
->drawing
;
2184 GtkWidget
*widget
= drawing
->drawing_area
;
2186 drawing
->damage_begin
= 0;
2187 drawing
->damage_end
= drawing
->width
;
2189 /* fun feature, to be separated someday... */
2190 drawing_clear(control_flow_data
->drawing
);
2191 processlist_clear(control_flow_data
->process_list
);
2192 gtk_widget_set_size_request(
2193 control_flow_data
->drawing
->drawing_area
,
2194 -1, processlist_get_height(control_flow_data
->process_list
));
2196 rectangle_pixmap (control_flow_data
->process_list
,
2197 widget
->style
->black_gc
,
2200 drawing
->alloc_width
,
2203 gtk_widget_queue_draw(drawing
->drawing_area
);
2205 if(drawing
->damage_begin
< drawing
->damage_end
)
2207 drawing_data_request(drawing
,
2208 drawing
->damage_begin
,
2210 drawing
->damage_end
-drawing
->damage_begin
,
2214 //gtk_widget_queue_draw_area(drawing->drawing_area,
2217 // drawing->height);
2223 gint
continue_notify(void *hook_data
, void *call_data
)
2225 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2226 Drawing_t
*drawing
= control_flow_data
->drawing
;
2228 //g_assert(widget->allocation.width == drawing->damage_end);
2230 if(drawing
->damage_begin
< drawing
->damage_end
)
2232 drawing_data_request(drawing
,
2233 drawing
->damage_begin
,
2235 drawing
->damage_end
-drawing
->damage_begin
,
2243 gint
update_current_time_hook(void *hook_data
, void *call_data
)
2245 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
2246 Drawing_t
*drawing
= control_flow_data
->drawing
;
2248 LttTime current_time
= *((LttTime
*)call_data
);
2250 TimeWindow time_window
=
2251 lttvwindow_get_time_window(control_flow_data
->tab
);
2253 LttTime time_begin
= time_window
.start_time
;
2254 LttTime width
= time_window
.time_width
;
2257 guint64 time_ll
= ltt_time_to_uint64(width
);
2258 time_ll
= time_ll
>> 1; /* divide by two */
2259 half_width
= ltt_time_from_uint64(time_ll
);
2261 LttTime time_end
= ltt_time_add(time_begin
, width
);
2263 LttvTracesetContext
* tsc
=
2264 lttvwindow_get_traceset_context(control_flow_data
->tab
);
2266 LttTime trace_start
= tsc
->time_span
.start_time
;
2267 LttTime trace_end
= tsc
->time_span
.end_time
;
2269 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
2270 current_time
.tv_nsec
);
2274 /* If current time is inside time interval, just move the highlight
2277 /* Else, we have to change the time interval. We have to tell it
2278 * to the main window. */
2279 /* The time interval change will take care of placing the current
2280 * time at the center of the visible area, or nearest possible if we are
2281 * at one end of the trace. */
2284 if(ltt_time_compare(current_time
, time_begin
) < 0)
2286 TimeWindow new_time_window
;
2288 if(ltt_time_compare(current_time
,
2289 ltt_time_add(trace_start
,half_width
)) < 0)
2290 time_begin
= trace_start
;
2292 time_begin
= ltt_time_sub(current_time
,half_width
);
2294 new_time_window
.start_time
= time_begin
;
2295 new_time_window
.time_width
= width
;
2296 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2297 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2299 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2301 else if(ltt_time_compare(current_time
, time_end
) > 0)
2303 TimeWindow new_time_window
;
2305 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
2306 time_begin
= ltt_time_sub(trace_end
,width
);
2308 time_begin
= ltt_time_sub(current_time
,half_width
);
2310 new_time_window
.start_time
= time_begin
;
2311 new_time_window
.time_width
= width
;
2312 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2313 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2315 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2318 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2320 /* Update directly when scrolling */
2321 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2327 typedef struct _ClosureData
{
2328 EventsRequest
*events_request
;
2329 LttvTracesetState
*tss
;
2335 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
2337 ProcessInfo
*process_info
= (ProcessInfo
*)key
;
2338 HashedProcessData
*hashed_process_data
= (HashedProcessData
*)value
;
2339 ClosureData
*closure_data
= (ClosureData
*)user_data
;
2341 EventsRequest
*events_request
= closure_data
->events_request
;
2342 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2344 LttvTracesetState
*tss
= closure_data
->tss
;
2345 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)tss
;
2347 LttTime evtime
= closure_data
->end_time
;
2349 gboolean dodraw
= TRUE
;
2352 /* For the process */
2353 /* First, check if the current process is in the state computation
2354 * process list. If it is there, that means we must add it right now and
2355 * draw items from the beginning of the read for it. If it is not
2356 * present, it's a new process and it was not present : it will
2357 * be added after the state update. */
2359 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
2360 #endif //EXTRA_CHECK
2361 LttvTraceContext
*tc
= tsc
->traces
[process_info
->trace_num
];
2362 LttvTraceState
*ts
= (LttvTraceState
*)tc
;
2365 //FIXME : optimize data structures.
2366 LttvTracefileState
*tfs
;
2367 LttvTracefileContext
*tfc
;
2369 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
2370 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
2371 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
2372 && tfs
->cpu
== process_info
->cpu
)
2376 g_assert(i
<tc
->tracefiles
->len
);
2377 tfs
= LTTV_TRACEFILE_STATE(tfc
);
2379 // LttvTracefileState *tfs =
2380 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2381 // tracefiles[process_info->cpu];
2383 LttvProcessState
*process
;
2384 process
= lttv_state_find_process(ts
, process_info
->cpu
,
2387 if(unlikely(process
!= NULL
)) {
2389 LttvFilter
*filter
= control_flow_data
->filter
;
2390 if(filter
!= NULL
&& filter
->head
!= NULL
)
2391 if(!lttv_filter_tree_parse(filter
->head
,NULL
,NULL
,
2392 tc
->t
,NULL
,process
,tc
))
2395 /* Only draw for processes that are currently in the trace states */
2397 ProcessList
*process_list
= control_flow_data
->process_list
;
2399 /* Should be alike when background info is ready */
2400 if(control_flow_data
->background_info_waiting
==0)
2401 g_assert(ltt_time_compare(process
->creation_time
,
2402 process_info
->birth
) == 0);
2403 #endif //EXTRA_CHECK
2405 /* Now, the process is in the state hash and our own process hash.
2406 * We definitely can draw the items related to the ending state.
2409 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2412 TimeWindow time_window
=
2413 lttvwindow_get_time_window(control_flow_data
->tab
);
2416 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2417 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2419 #endif //EXTRA_CHECK
2420 Drawing_t
*drawing
= control_flow_data
->drawing
;
2421 guint width
= drawing
->width
;
2423 guint x
= closure_data
->x_end
;
2425 DrawContext draw_context
;
2427 /* Now create the drawing context that will be used to draw
2428 * items related to the last state. */
2429 draw_context
.drawable
= hashed_process_data
->pixmap
;
2430 draw_context
.gc
= drawing
->gc
;
2431 draw_context
.pango_layout
= drawing
->pango_layout
;
2432 draw_context
.drawinfo
.end
.x
= x
;
2434 draw_context
.drawinfo
.y
.over
= 1;
2435 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2436 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2438 draw_context
.drawinfo
.start
.offset
.over
= 0;
2439 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2440 draw_context
.drawinfo
.start
.offset
.under
= 0;
2441 draw_context
.drawinfo
.end
.offset
.over
= 0;
2442 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2443 draw_context
.drawinfo
.end
.offset
.under
= 0;
2445 /* Jump over draw if we are at the same x position */
2446 if(x
== hashed_process_data
->x
.over
)
2450 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2452 PropertiesLine prop_line
= prepare_execmode_line(process
);
2453 draw_line((void*)&prop_line
, (void*)&draw_context
);
2455 hashed_process_data
->x
.over
= x
;
2459 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2460 hashed_process_data
->x
.middle_used
)) {
2461 #if 0 /* do not mark closure : not missing information */
2462 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2463 /* Draw collision indicator */
2464 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2465 gdk_draw_point(drawing
->pixmap
,
2469 hashed_process_data
->x
.middle_marked
= TRUE
;
2474 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2477 PropertiesLine prop_line
= prepare_s_e_line(process
);
2478 draw_line((void*)&prop_line
, (void*)&draw_context
);
2481 /* become the last x position */
2482 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2483 hashed_process_data
->x
.middle
= x
;
2484 /* but don't use the pixel */
2485 hashed_process_data
->x
.middle_used
= FALSE
;
2487 /* Calculate the next good time */
2488 convert_pixels_to_time(width
, x
+1, time_window
,
2489 &hashed_process_data
->next_good_time
);
2498 int before_chunk(void *hook_data
, void *call_data
)
2500 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2501 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2502 ControlFlowData
*cfd
= (ControlFlowData
*)events_request
->viewer_data
;
2504 /* Desactivate sort */
2505 gtk_tree_sortable_set_sort_column_id(
2506 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2508 GTK_SORT_ASCENDING
);
2510 drawing_chunk_begin(events_request
, tss
);
2515 int before_request(void *hook_data
, void *call_data
)
2517 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2518 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2520 drawing_data_request_begin(events_request
, tss
);
2527 * after request is necessary in addition of after chunk in order to draw
2528 * lines until the end of the screen. after chunk just draws lines until
2535 int after_request(void *hook_data
, void *call_data
)
2537 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2538 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2539 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2541 ProcessList
*process_list
= control_flow_data
->process_list
;
2542 LttTime end_time
= events_request
->end_time
;
2544 ClosureData closure_data
;
2545 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2546 closure_data
.tss
= tss
;
2547 closure_data
.end_time
= end_time
;
2549 TimeWindow time_window
=
2550 lttvwindow_get_time_window(control_flow_data
->tab
);
2551 guint width
= control_flow_data
->drawing
->width
;
2552 convert_time_to_pixels(
2556 &closure_data
.x_end
);
2559 /* Draw last items */
2560 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2561 (void*)&closure_data
);
2564 /* Request expose */
2565 drawing_request_expose(events_request
, tss
, end_time
);
2574 int after_chunk(void *hook_data
, void *call_data
)
2576 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2577 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2578 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2579 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)call_data
;
2580 LttvTracefileContext
*tfc
= lttv_traceset_context_get_current_tfc(tsc
);
2583 ProcessList
*process_list
= control_flow_data
->process_list
;
2585 LttvTraceset
*traceset
= tsc
->ts
;
2586 guint nb_trace
= lttv_traceset_number(traceset
);
2588 /* Only execute when called for the first trace's events request */
2589 if(!process_list
->current_hash_data
) return;
2591 for(i
= 0 ; i
< nb_trace
; i
++) {
2592 g_free(process_list
->current_hash_data
[i
]);
2594 g_free(process_list
->current_hash_data
);
2595 process_list
->current_hash_data
= NULL
;
2598 end_time
= LTT_TIME_MIN(tfc
->timestamp
, events_request
->end_time
);
2599 else /* end of traceset, or position now out of request : end */
2600 end_time
= events_request
->end_time
;
2602 ClosureData closure_data
;
2603 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2604 closure_data
.tss
= tss
;
2605 closure_data
.end_time
= end_time
;
2607 TimeWindow time_window
=
2608 lttvwindow_get_time_window(control_flow_data
->tab
);
2609 guint width
= control_flow_data
->drawing
->width
;
2610 convert_time_to_pixels(
2614 &closure_data
.x_end
);
2616 /* Draw last items */
2617 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2618 (void*)&closure_data
);
2620 /* Reactivate sort */
2621 gtk_tree_sortable_set_sort_column_id(
2622 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2623 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2624 GTK_SORT_ASCENDING
);
2626 update_index_to_pixmap(control_flow_data
->process_list
);
2627 /* Request a full expose : drawing scrambled */
2628 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2630 /* Request expose (updates damages zone also) */
2631 drawing_request_expose(events_request
, tss
, end_time
);
2636 /* after_statedump_end
2638 * @param hook_data ControlFlowData structure of the viewer.
2639 * @param call_data Event context.
2641 * This function adds items to be drawn in a queue for each process.
2644 int before_statedump_end(void *hook_data
, void *call_data
)
2646 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2647 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
2648 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2650 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2652 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
2654 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
2656 LttvTracesetState
*tss
= (LttvTracesetState
*)tfc
->t_context
->ts_context
;
2657 ProcessList
*process_list
= control_flow_data
->process_list
;
2660 e
= ltt_tracefile_get_event(tfc
->tf
);
2662 LttvFilter
*filter
= control_flow_data
->filter
;
2663 if(filter
!= NULL
&& filter
->head
!= NULL
)
2664 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2665 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2668 LttTime evtime
= ltt_event_time(e
);
2670 ClosureData closure_data
;
2671 closure_data
.events_request
= events_request
;
2672 closure_data
.tss
= tss
;
2673 closure_data
.end_time
= evtime
;
2675 TimeWindow time_window
=
2676 lttvwindow_get_time_window(control_flow_data
->tab
);
2677 guint width
= control_flow_data
->drawing
->width
;
2678 convert_time_to_pixels(
2682 &closure_data
.x_end
);
2684 /* Draw last items */
2685 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2686 (void*)&closure_data
);
2688 /* Reactivate sort */
2689 gtk_tree_sortable_set_sort_column_id(
2690 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2691 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2692 GTK_SORT_ASCENDING
);
2694 update_index_to_pixmap(control_flow_data
->process_list
);
2695 /* Request a full expose : drawing scrambled */
2696 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2698 /* Request expose (updates damages zone also) */
2699 drawing_request_expose(events_request
, tss
, evtime
);