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 g_assert(pid
== 0 || pid
!= process
->ppid
);
1288 /* Process not present */
1289 Drawing_t
*drawing
= control_flow_data
->drawing
;
1290 ProcessInfo
*process_info
;
1291 processlist_add(process_list
,
1303 &hashed_process_data
);
1304 gtk_widget_set_size_request(drawing
->drawing_area
,
1307 gtk_widget_queue_draw(drawing
->drawing_area
);
1310 /* Now, the process is in the state hash and our own process hash.
1311 * We definitely can draw the items related to the ending state.
1314 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1317 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1318 TimeWindow time_window
=
1319 lttvwindow_get_time_window(control_flow_data
->tab
);
1322 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1323 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1325 #endif //EXTRA_CHECK
1326 Drawing_t
*drawing
= control_flow_data
->drawing
;
1327 guint width
= drawing
->width
;
1329 convert_time_to_pixels(
1335 /* Draw collision indicator */
1336 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1337 gdk_draw_point(hashed_process_data
->pixmap
,
1340 COLLISION_POSITION(hashed_process_data
->height
));
1341 hashed_process_data
->x
.middle_marked
= TRUE
;
1344 TimeWindow time_window
=
1345 lttvwindow_get_time_window(control_flow_data
->tab
);
1348 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1349 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1351 #endif //EXTRA_CHECK
1352 Drawing_t
*drawing
= control_flow_data
->drawing
;
1353 guint width
= drawing
->width
;
1356 convert_time_to_pixels(
1363 /* Jump over draw if we are at the same x position */
1364 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1365 hashed_process_data
->x
.middle_used
))
1367 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1368 /* Draw collision indicator */
1369 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1370 gdk_draw_point(hashed_process_data
->pixmap
,
1373 COLLISION_POSITION(hashed_process_data
->height
));
1374 hashed_process_data
->x
.middle_marked
= TRUE
;
1378 DrawContext draw_context
;
1380 /* Now create the drawing context that will be used to draw
1381 * items related to the last state. */
1382 draw_context
.drawable
= hashed_process_data
->pixmap
;
1383 draw_context
.gc
= drawing
->gc
;
1384 draw_context
.pango_layout
= drawing
->pango_layout
;
1385 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1386 draw_context
.drawinfo
.end
.x
= x
;
1388 draw_context
.drawinfo
.y
.over
= 1;
1389 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1390 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1392 draw_context
.drawinfo
.start
.offset
.over
= 0;
1393 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1394 draw_context
.drawinfo
.start
.offset
.under
= 0;
1395 draw_context
.drawinfo
.end
.offset
.over
= 0;
1396 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1397 draw_context
.drawinfo
.end
.offset
.under
= 0;
1401 PropertiesLine prop_line
= prepare_s_e_line(process
);
1402 draw_line((void*)&prop_line
, (void*)&draw_context
);
1405 /* become the last x position */
1406 hashed_process_data
->x
.middle
= x
;
1407 hashed_process_data
->x
.middle_used
= TRUE
;
1408 hashed_process_data
->x
.middle_marked
= FALSE
;
1410 /* Calculate the next good time */
1411 convert_pixels_to_time(width
, x
+1, time_window
,
1412 &hashed_process_data
->next_good_time
);
1424 /* after_process_fork_hook
1426 * Create the processlist entry for the child process. Put the last
1427 * position in x at the current time value.
1429 * @param hook_data ControlFlowData structure of the viewer.
1430 * @param call_data Event context.
1432 * This function adds items to be drawn in a queue for each process.
1435 int after_process_fork_hook(void *hook_data
, void *call_data
)
1437 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1438 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1439 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1441 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1443 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1445 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1448 e
= ltt_tracefile_get_event(tfc
->tf
);
1450 LttvFilter
*filter
= control_flow_data
->filter
;
1451 if(filter
!= NULL
&& filter
->head
!= NULL
)
1452 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1453 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1456 LttTime evtime
= ltt_event_time(e
);
1460 child_pid
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
1463 /* Add process to process list (if not present) */
1464 LttvProcessState
*process_child
;
1466 guint pl_height
= 0;
1467 HashedProcessData
*hashed_process_data_child
= NULL
;
1469 ProcessList
*process_list
= control_flow_data
->process_list
;
1471 /* Find child in the list... */
1472 process_child
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1473 /* It should exist, because we are after the state update. */
1474 g_assert(process_child
!= NULL
);
1476 birth
= process_child
->creation_time
;
1477 guint trace_num
= ts
->parent
.index
;
1479 /* Cannot use current process, because this action is done by the parent
1481 hashed_process_data_child
= processlist_get_process_data(process_list
,
1486 if(likely(hashed_process_data_child
== NULL
))
1488 g_assert(child_pid
== 0 || child_pid
!= process_child
->ppid
);
1489 /* Process not present */
1490 Drawing_t
*drawing
= control_flow_data
->drawing
;
1491 ProcessInfo
*process_info
;
1492 processlist_add(process_list
,
1495 process_child
->tgid
,
1497 process_child
->ppid
,
1500 process_child
->name
,
1501 process_child
->brand
,
1504 &hashed_process_data_child
);
1505 gtk_widget_set_size_request(drawing
->drawing_area
,
1508 gtk_widget_queue_draw(drawing
->drawing_area
);
1510 processlist_set_ppid(process_list
, process_child
->ppid
,
1511 hashed_process_data_child
);
1512 processlist_set_tgid(process_list
, process_child
->tgid
,
1513 hashed_process_data_child
);
1517 if(likely(ltt_time_compare(hashed_process_data_child
->next_good_time
,
1520 TimeWindow time_window
=
1521 lttvwindow_get_time_window(control_flow_data
->tab
);
1524 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1525 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1527 #endif //EXTRA_CHECK
1528 Drawing_t
*drawing
= control_flow_data
->drawing
;
1529 guint width
= drawing
->width
;
1531 convert_time_to_pixels(
1537 if(likely(hashed_process_data_child
->x
.over
!= new_x
)) {
1538 hashed_process_data_child
->x
.over
= new_x
;
1539 hashed_process_data_child
->x
.over_used
= FALSE
;
1540 hashed_process_data_child
->x
.over_marked
= FALSE
;
1542 if(likely(hashed_process_data_child
->x
.middle
!= new_x
)) {
1543 hashed_process_data_child
->x
.middle
= new_x
;
1544 hashed_process_data_child
->x
.middle_used
= FALSE
;
1545 hashed_process_data_child
->x
.middle_marked
= FALSE
;
1547 if(likely(hashed_process_data_child
->x
.under
!= new_x
)) {
1548 hashed_process_data_child
->x
.under
= new_x
;
1549 hashed_process_data_child
->x
.under_used
= FALSE
;
1550 hashed_process_data_child
->x
.under_marked
= FALSE
;
1558 /* after_process_exit_hook
1560 * Create the processlist entry for the child process. Put the last
1561 * position in x at the current time value.
1563 * @param hook_data ControlFlowData structure of the viewer.
1564 * @param call_data Event context.
1566 * This function adds items to be drawn in a queue for each process.
1569 int after_process_exit_hook(void *hook_data
, void *call_data
)
1571 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1572 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1573 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1575 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1577 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1579 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1582 e
= ltt_tracefile_get_event(tfc
->tf
);
1584 LttvFilter
*filter
= control_flow_data
->filter
;
1585 if(filter
!= NULL
&& filter
->head
!= NULL
)
1586 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1587 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1590 LttTime evtime
= ltt_event_time(e
);
1592 /* Add process to process list (if not present) */
1593 //LttvProcessState *process = tfs->process;
1594 guint cpu
= tfs
->cpu
;
1595 guint trace_num
= ts
->parent
.index
;
1596 LttvProcessState
*process
= ts
->running_process
[cpu
];
1598 /* It should exist, because we are after the state update. */
1599 g_assert(process
!= NULL
);
1601 guint pid
= process
->pid
;
1603 guint pl_height
= 0;
1604 HashedProcessData
*hashed_process_data
= NULL
;
1606 ProcessList
*process_list
= control_flow_data
->process_list
;
1608 birth
= process
->creation_time
;
1610 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
) ){
1611 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1613 hashed_process_data
= processlist_get_process_data(process_list
,
1618 if(unlikely(hashed_process_data
== NULL
))
1620 g_assert(pid
== 0 || pid
!= process
->ppid
);
1621 /* Process not present */
1622 Drawing_t
*drawing
= control_flow_data
->drawing
;
1623 ProcessInfo
*process_info
;
1624 processlist_add(process_list
,
1636 &hashed_process_data
);
1637 gtk_widget_set_size_request(drawing
->drawing_area
,
1640 gtk_widget_queue_draw(drawing
->drawing_area
);
1643 /* Set the current process */
1644 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1645 hashed_process_data
;
1648 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
1651 TimeWindow time_window
=
1652 lttvwindow_get_time_window(control_flow_data
->tab
);
1655 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1656 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1658 #endif //EXTRA_CHECK
1659 Drawing_t
*drawing
= control_flow_data
->drawing
;
1660 guint width
= drawing
->width
;
1662 convert_time_to_pixels(
1667 if(unlikely(hashed_process_data
->x
.middle
!= new_x
)) {
1668 hashed_process_data
->x
.middle
= new_x
;
1669 hashed_process_data
->x
.middle_used
= FALSE
;
1670 hashed_process_data
->x
.middle_marked
= FALSE
;
1678 /* Get the filename of the process to print */
1679 int after_fs_exec_hook(void *hook_data
, void *call_data
)
1681 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1682 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1683 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1685 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1687 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1689 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1692 e
= ltt_tracefile_get_event(tfc
->tf
);
1694 LttvFilter
*filter
= control_flow_data
->filter
;
1695 if(filter
!= NULL
&& filter
->head
!= NULL
)
1696 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1697 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1700 guint cpu
= tfs
->cpu
;
1701 guint trace_num
= ts
->parent
.index
;
1702 LttvProcessState
*process
= ts
->running_process
[cpu
];
1703 g_assert(process
!= NULL
);
1705 guint pid
= process
->pid
;
1707 /* Well, the process_out existed : we must get it in the process hash
1708 * or add it, and draw its items.
1710 /* Add process to process list (if not present) */
1711 guint pl_height
= 0;
1712 HashedProcessData
*hashed_process_data
= NULL
;
1713 ProcessList
*process_list
= control_flow_data
->process_list
;
1714 LttTime birth
= process
->creation_time
;
1716 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1717 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1719 hashed_process_data
= processlist_get_process_data(process_list
,
1724 if(unlikely(hashed_process_data
== NULL
))
1726 g_assert(pid
== 0 || pid
!= process
->ppid
);
1727 ProcessInfo
*process_info
;
1728 /* Process not present */
1729 Drawing_t
*drawing
= control_flow_data
->drawing
;
1730 processlist_add(process_list
,
1742 &hashed_process_data
);
1743 gtk_widget_set_size_request(drawing
->drawing_area
,
1746 gtk_widget_queue_draw(drawing
->drawing_area
);
1748 /* Set the current process */
1749 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1750 hashed_process_data
;
1753 processlist_set_name(process_list
, process
->name
, hashed_process_data
);
1759 /* Get the filename of the process to print */
1760 int after_user_generic_thread_brand_hook(void *hook_data
, void *call_data
)
1762 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1763 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1764 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1766 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1768 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1770 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1773 e
= ltt_tracefile_get_event(tfc
->tf
);
1775 LttvFilter
*filter
= control_flow_data
->filter
;
1776 if(filter
!= NULL
&& filter
->head
!= NULL
)
1777 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1778 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1781 guint cpu
= tfs
->cpu
;
1782 guint trace_num
= ts
->parent
.index
;
1783 LttvProcessState
*process
= ts
->running_process
[cpu
];
1784 g_assert(process
!= NULL
);
1786 guint pid
= process
->pid
;
1788 /* Well, the process_out existed : we must get it in the process hash
1789 * or add it, and draw its items.
1791 /* Add process to process list (if not present) */
1792 guint pl_height
= 0;
1793 HashedProcessData
*hashed_process_data
= NULL
;
1794 ProcessList
*process_list
= control_flow_data
->process_list
;
1795 LttTime birth
= process
->creation_time
;
1797 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1798 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1800 hashed_process_data
= processlist_get_process_data(process_list
,
1805 if(unlikely(hashed_process_data
== NULL
))
1807 g_assert(pid
== 0 || pid
!= process
->ppid
);
1808 ProcessInfo
*process_info
;
1809 /* Process not present */
1810 Drawing_t
*drawing
= control_flow_data
->drawing
;
1811 processlist_add(process_list
,
1823 &hashed_process_data
);
1824 gtk_widget_set_size_request(drawing
->drawing_area
,
1827 gtk_widget_queue_draw(drawing
->drawing_area
);
1829 /* Set the current process */
1830 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1831 hashed_process_data
;
1834 processlist_set_brand(process_list
, process
->brand
, hashed_process_data
);
1841 /* after_event_enum_process_hook
1843 * Create the processlist entry for the child process. Put the last
1844 * position in x at the current time value.
1846 * @param hook_data ControlFlowData structure of the viewer.
1847 * @param call_data Event context.
1849 * This function adds items to be drawn in a queue for each process.
1852 int after_event_enum_process_hook(void *hook_data
, void *call_data
)
1854 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1855 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1856 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1858 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1860 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1862 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1864 guint first_cpu
, nb_cpus
, cpu
;
1867 e
= ltt_tracefile_get_event(tfc
->tf
);
1869 LttvFilter
*filter
= control_flow_data
->filter
;
1870 if(filter
!= NULL
&& filter
->head
!= NULL
)
1871 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1872 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1875 LttTime evtime
= ltt_event_time(e
);
1877 /* Add process to process list (if not present) */
1878 LttvProcessState
*process_in
;
1880 guint pl_height
= 0;
1881 HashedProcessData
*hashed_process_data_in
= NULL
;
1883 ProcessList
*process_list
= control_flow_data
->process_list
;
1884 guint trace_num
= ts
->parent
.index
;
1888 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
1893 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1895 first_cpu
= ANY_CPU
;
1896 nb_cpus
= ANY_CPU
+1;
1899 for(cpu
= first_cpu
; cpu
< nb_cpus
; cpu
++) {
1900 /* Find process pid_in in the list... */
1901 process_in
= lttv_state_find_process(ts
, cpu
, pid_in
);
1902 //process_in = tfs->process;
1903 //guint cpu = tfs->cpu;
1904 //guint trace_num = ts->parent.index;
1905 //process_in = ts->running_process[cpu];
1906 /* It should exist, because we are after the state update. */
1908 //g_assert(process_in != NULL);
1909 #endif //EXTRA_CHECK
1910 birth
= process_in
->creation_time
;
1912 hashed_process_data_in
= processlist_get_process_data(process_list
,
1917 if(hashed_process_data_in
== NULL
)
1919 if(pid_in
!= 0 && pid_in
== process_in
->ppid
)
1920 g_critical("TEST %u , %u", pid_in
, process_in
->ppid
);
1921 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
1922 ProcessInfo
*process_info
;
1923 Drawing_t
*drawing
= control_flow_data
->drawing
;
1924 /* Process not present */
1925 processlist_add(process_list
,
1937 &hashed_process_data_in
);
1938 gtk_widget_set_size_request(drawing
->drawing_area
,
1941 gtk_widget_queue_draw(drawing
->drawing_area
);
1943 processlist_set_name(process_list
, process_in
->name
,
1944 hashed_process_data_in
);
1945 processlist_set_ppid(process_list
, process_in
->ppid
,
1946 hashed_process_data_in
);
1947 processlist_set_tgid(process_list
, process_in
->tgid
,
1948 hashed_process_data_in
);
1955 gint
update_time_window_hook(void *hook_data
, void *call_data
)
1957 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1958 Drawing_t
*drawing
= control_flow_data
->drawing
;
1959 ProcessList
*process_list
= control_flow_data
->process_list
;
1961 const TimeWindowNotifyData
*time_window_nofify_data
=
1962 ((const TimeWindowNotifyData
*)call_data
);
1964 TimeWindow
*old_time_window
=
1965 time_window_nofify_data
->old_time_window
;
1966 TimeWindow
*new_time_window
=
1967 time_window_nofify_data
->new_time_window
;
1969 /* Update the ruler */
1970 drawing_update_ruler(control_flow_data
->drawing
,
1974 /* Two cases : zoom in/out or scrolling */
1976 /* In order to make sure we can reuse the old drawing, the scale must
1977 * be the same and the new time interval being partly located in the
1978 * currently shown time interval. (reuse is only for scrolling)
1981 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
1982 old_time_window
->start_time
.tv_sec
,
1983 old_time_window
->start_time
.tv_nsec
,
1984 old_time_window
->time_width
.tv_sec
,
1985 old_time_window
->time_width
.tv_nsec
);
1987 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
1988 new_time_window
->start_time
.tv_sec
,
1989 new_time_window
->start_time
.tv_nsec
,
1990 new_time_window
->time_width
.tv_sec
,
1991 new_time_window
->time_width
.tv_nsec
);
1993 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
1994 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
1996 /* Same scale (scrolling) */
1997 g_info("scrolling");
1998 LttTime
*ns
= &new_time_window
->start_time
;
1999 LttTime
*nw
= &new_time_window
->time_width
;
2000 LttTime
*os
= &old_time_window
->start_time
;
2001 LttTime
*ow
= &old_time_window
->time_width
;
2002 LttTime old_end
= old_time_window
->end_time
;
2003 LttTime new_end
= new_time_window
->end_time
;
2005 //if(ns<os+w && os+w<ns+w)
2006 //if(ns<old_end && os<ns)
2007 if(ltt_time_compare(*ns
, old_end
) == -1
2008 && ltt_time_compare(*os
, *ns
) == -1)
2010 g_info("scrolling near right");
2011 /* Scroll right, keep right part of the screen */
2013 guint width
= control_flow_data
->drawing
->width
;
2014 convert_time_to_pixels(
2020 /* Copy old data to new location */
2021 copy_pixmap_region(process_list
,
2023 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2027 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
2029 if(drawing
->damage_begin
== drawing
->damage_end
)
2030 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
2032 drawing
->damage_begin
= 0;
2034 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2036 /* Clear the data request background, but not SAFETY */
2037 rectangle_pixmap(process_list
,
2038 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2040 drawing
->damage_begin
+SAFETY
, 0,
2041 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2043 gtk_widget_queue_draw(drawing
->drawing_area
);
2044 //gtk_widget_queue_draw_area (drawing->drawing_area,
2046 // control_flow_data->drawing->width,
2047 // control_flow_data->drawing->height);
2049 /* Get new data for the rest. */
2050 drawing_data_request(control_flow_data
->drawing
,
2051 drawing
->damage_begin
, 0,
2052 drawing
->damage_end
- drawing
->damage_begin
,
2053 control_flow_data
->drawing
->height
);
2056 //if(ns<os && os<ns+w)
2057 //if(ns<os && os<new_end)
2058 if(ltt_time_compare(*ns
,*os
) == -1
2059 && ltt_time_compare(*os
,new_end
) == -1)
2061 g_info("scrolling near left");
2062 /* Scroll left, keep left part of the screen */
2064 guint width
= control_flow_data
->drawing
->width
;
2065 convert_time_to_pixels(
2071 /* Copy old data to new location */
2072 copy_pixmap_region (process_list
,
2074 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2080 if(drawing
->damage_begin
== drawing
->damage_end
)
2081 drawing
->damage_end
= x
;
2083 drawing
->damage_end
=
2084 control_flow_data
->drawing
->width
;
2086 drawing
->damage_begin
= 0;
2088 rectangle_pixmap (process_list
,
2089 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2091 drawing
->damage_begin
, 0,
2092 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2095 gtk_widget_queue_draw(drawing
->drawing_area
);
2096 //gtk_widget_queue_draw_area (drawing->drawing_area,
2098 // control_flow_data->drawing->width,
2099 // control_flow_data->drawing->height);
2102 /* Get new data for the rest. */
2103 drawing_data_request(control_flow_data
->drawing
,
2104 drawing
->damage_begin
, 0,
2105 drawing
->damage_end
- drawing
->damage_begin
,
2106 control_flow_data
->drawing
->height
);
2109 if(ltt_time_compare(*ns
,*os
) == 0)
2111 g_info("not scrolling");
2113 g_info("scrolling far");
2114 /* Cannot reuse any part of the screen : far jump */
2117 rectangle_pixmap (process_list
,
2118 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2121 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2124 //gtk_widget_queue_draw_area (drawing->drawing_area,
2126 // control_flow_data->drawing->width,
2127 // control_flow_data->drawing->height);
2128 gtk_widget_queue_draw(drawing
->drawing_area
);
2130 drawing
->damage_begin
= 0;
2131 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2133 drawing_data_request(control_flow_data
->drawing
,
2135 control_flow_data
->drawing
->width
,
2136 control_flow_data
->drawing
->height
);
2142 /* Different scale (zoom) */
2145 rectangle_pixmap (process_list
,
2146 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2149 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2152 //gtk_widget_queue_draw_area (drawing->drawing_area,
2154 // control_flow_data->drawing->width,
2155 // control_flow_data->drawing->height);
2156 gtk_widget_queue_draw(drawing
->drawing_area
);
2158 drawing
->damage_begin
= 0;
2159 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2161 drawing_data_request(control_flow_data
->drawing
,
2163 control_flow_data
->drawing
->width
,
2164 control_flow_data
->drawing
->height
);
2167 /* Update directly when scrolling */
2168 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2174 gint
traceset_notify(void *hook_data
, void *call_data
)
2176 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2177 Drawing_t
*drawing
= control_flow_data
->drawing
;
2179 if(unlikely(drawing
->gc
== NULL
)) {
2182 if(drawing
->dotted_gc
== NULL
) {
2186 drawing_clear(control_flow_data
->drawing
);
2187 processlist_clear(control_flow_data
->process_list
);
2188 gtk_widget_set_size_request(
2189 control_flow_data
->drawing
->drawing_area
,
2190 -1, processlist_get_height(control_flow_data
->process_list
));
2191 redraw_notify(control_flow_data
, NULL
);
2193 request_background_data(control_flow_data
);
2198 gint
redraw_notify(void *hook_data
, void *call_data
)
2200 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2201 Drawing_t
*drawing
= control_flow_data
->drawing
;
2202 GtkWidget
*widget
= drawing
->drawing_area
;
2204 drawing
->damage_begin
= 0;
2205 drawing
->damage_end
= drawing
->width
;
2207 /* fun feature, to be separated someday... */
2208 drawing_clear(control_flow_data
->drawing
);
2209 processlist_clear(control_flow_data
->process_list
);
2210 gtk_widget_set_size_request(
2211 control_flow_data
->drawing
->drawing_area
,
2212 -1, processlist_get_height(control_flow_data
->process_list
));
2214 rectangle_pixmap (control_flow_data
->process_list
,
2215 widget
->style
->black_gc
,
2218 drawing
->alloc_width
,
2221 gtk_widget_queue_draw(drawing
->drawing_area
);
2223 if(drawing
->damage_begin
< drawing
->damage_end
)
2225 drawing_data_request(drawing
,
2226 drawing
->damage_begin
,
2228 drawing
->damage_end
-drawing
->damage_begin
,
2232 //gtk_widget_queue_draw_area(drawing->drawing_area,
2235 // drawing->height);
2241 gint
continue_notify(void *hook_data
, void *call_data
)
2243 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2244 Drawing_t
*drawing
= control_flow_data
->drawing
;
2246 //g_assert(widget->allocation.width == drawing->damage_end);
2248 if(drawing
->damage_begin
< drawing
->damage_end
)
2250 drawing_data_request(drawing
,
2251 drawing
->damage_begin
,
2253 drawing
->damage_end
-drawing
->damage_begin
,
2261 gint
update_current_time_hook(void *hook_data
, void *call_data
)
2263 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
2264 Drawing_t
*drawing
= control_flow_data
->drawing
;
2266 LttTime current_time
= *((LttTime
*)call_data
);
2268 TimeWindow time_window
=
2269 lttvwindow_get_time_window(control_flow_data
->tab
);
2271 LttTime time_begin
= time_window
.start_time
;
2272 LttTime width
= time_window
.time_width
;
2275 guint64 time_ll
= ltt_time_to_uint64(width
);
2276 time_ll
= time_ll
>> 1; /* divide by two */
2277 half_width
= ltt_time_from_uint64(time_ll
);
2279 LttTime time_end
= ltt_time_add(time_begin
, width
);
2281 LttvTracesetContext
* tsc
=
2282 lttvwindow_get_traceset_context(control_flow_data
->tab
);
2284 LttTime trace_start
= tsc
->time_span
.start_time
;
2285 LttTime trace_end
= tsc
->time_span
.end_time
;
2287 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
2288 current_time
.tv_nsec
);
2292 /* If current time is inside time interval, just move the highlight
2295 /* Else, we have to change the time interval. We have to tell it
2296 * to the main window. */
2297 /* The time interval change will take care of placing the current
2298 * time at the center of the visible area, or nearest possible if we are
2299 * at one end of the trace. */
2302 if(ltt_time_compare(current_time
, time_begin
) < 0)
2304 TimeWindow new_time_window
;
2306 if(ltt_time_compare(current_time
,
2307 ltt_time_add(trace_start
,half_width
)) < 0)
2308 time_begin
= trace_start
;
2310 time_begin
= ltt_time_sub(current_time
,half_width
);
2312 new_time_window
.start_time
= time_begin
;
2313 new_time_window
.time_width
= width
;
2314 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2315 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2317 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2319 else if(ltt_time_compare(current_time
, time_end
) > 0)
2321 TimeWindow new_time_window
;
2323 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
2324 time_begin
= ltt_time_sub(trace_end
,width
);
2326 time_begin
= ltt_time_sub(current_time
,half_width
);
2328 new_time_window
.start_time
= time_begin
;
2329 new_time_window
.time_width
= width
;
2330 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2331 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2333 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2336 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2338 /* Update directly when scrolling */
2339 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2345 typedef struct _ClosureData
{
2346 EventsRequest
*events_request
;
2347 LttvTracesetState
*tss
;
2353 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
2355 ProcessInfo
*process_info
= (ProcessInfo
*)key
;
2356 HashedProcessData
*hashed_process_data
= (HashedProcessData
*)value
;
2357 ClosureData
*closure_data
= (ClosureData
*)user_data
;
2359 EventsRequest
*events_request
= closure_data
->events_request
;
2360 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2362 LttvTracesetState
*tss
= closure_data
->tss
;
2363 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)tss
;
2365 LttTime evtime
= closure_data
->end_time
;
2367 gboolean dodraw
= TRUE
;
2370 /* For the process */
2371 /* First, check if the current process is in the state computation
2372 * process list. If it is there, that means we must add it right now and
2373 * draw items from the beginning of the read for it. If it is not
2374 * present, it's a new process and it was not present : it will
2375 * be added after the state update. */
2377 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
2378 #endif //EXTRA_CHECK
2379 LttvTraceContext
*tc
= tsc
->traces
[process_info
->trace_num
];
2380 LttvTraceState
*ts
= (LttvTraceState
*)tc
;
2383 //FIXME : optimize data structures.
2384 LttvTracefileState
*tfs
;
2385 LttvTracefileContext
*tfc
;
2387 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
2388 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
2389 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
2390 && tfs
->cpu
== process_info
->cpu
)
2394 g_assert(i
<tc
->tracefiles
->len
);
2395 tfs
= LTTV_TRACEFILE_STATE(tfc
);
2397 // LttvTracefileState *tfs =
2398 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2399 // tracefiles[process_info->cpu];
2401 LttvProcessState
*process
;
2402 process
= lttv_state_find_process(ts
, process_info
->cpu
,
2405 if(unlikely(process
!= NULL
)) {
2407 LttvFilter
*filter
= control_flow_data
->filter
;
2408 if(filter
!= NULL
&& filter
->head
!= NULL
)
2409 if(!lttv_filter_tree_parse(filter
->head
,NULL
,NULL
,
2410 tc
->t
,NULL
,process
,tc
))
2413 /* Only draw for processes that are currently in the trace states */
2415 ProcessList
*process_list
= control_flow_data
->process_list
;
2417 /* Should be alike when background info is ready */
2418 if(control_flow_data
->background_info_waiting
==0)
2419 g_assert(ltt_time_compare(process
->creation_time
,
2420 process_info
->birth
) == 0);
2421 #endif //EXTRA_CHECK
2423 /* Now, the process is in the state hash and our own process hash.
2424 * We definitely can draw the items related to the ending state.
2427 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2430 TimeWindow time_window
=
2431 lttvwindow_get_time_window(control_flow_data
->tab
);
2434 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2435 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2437 #endif //EXTRA_CHECK
2438 Drawing_t
*drawing
= control_flow_data
->drawing
;
2439 guint width
= drawing
->width
;
2441 guint x
= closure_data
->x_end
;
2443 DrawContext draw_context
;
2445 /* Now create the drawing context that will be used to draw
2446 * items related to the last state. */
2447 draw_context
.drawable
= hashed_process_data
->pixmap
;
2448 draw_context
.gc
= drawing
->gc
;
2449 draw_context
.pango_layout
= drawing
->pango_layout
;
2450 draw_context
.drawinfo
.end
.x
= x
;
2452 draw_context
.drawinfo
.y
.over
= 1;
2453 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2454 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2456 draw_context
.drawinfo
.start
.offset
.over
= 0;
2457 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2458 draw_context
.drawinfo
.start
.offset
.under
= 0;
2459 draw_context
.drawinfo
.end
.offset
.over
= 0;
2460 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2461 draw_context
.drawinfo
.end
.offset
.under
= 0;
2463 /* Jump over draw if we are at the same x position */
2464 if(x
== hashed_process_data
->x
.over
)
2468 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2470 PropertiesLine prop_line
= prepare_execmode_line(process
);
2471 draw_line((void*)&prop_line
, (void*)&draw_context
);
2473 hashed_process_data
->x
.over
= x
;
2477 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2478 hashed_process_data
->x
.middle_used
)) {
2479 #if 0 /* do not mark closure : not missing information */
2480 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2481 /* Draw collision indicator */
2482 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2483 gdk_draw_point(drawing
->pixmap
,
2487 hashed_process_data
->x
.middle_marked
= TRUE
;
2492 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2495 PropertiesLine prop_line
= prepare_s_e_line(process
);
2496 draw_line((void*)&prop_line
, (void*)&draw_context
);
2499 /* become the last x position */
2500 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2501 hashed_process_data
->x
.middle
= x
;
2502 /* but don't use the pixel */
2503 hashed_process_data
->x
.middle_used
= FALSE
;
2505 /* Calculate the next good time */
2506 convert_pixels_to_time(width
, x
+1, time_window
,
2507 &hashed_process_data
->next_good_time
);
2516 int before_chunk(void *hook_data
, void *call_data
)
2518 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2519 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2520 ControlFlowData
*cfd
= (ControlFlowData
*)events_request
->viewer_data
;
2522 /* Desactivate sort */
2523 gtk_tree_sortable_set_sort_column_id(
2524 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2526 GTK_SORT_ASCENDING
);
2528 drawing_chunk_begin(events_request
, tss
);
2533 int before_request(void *hook_data
, void *call_data
)
2535 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2536 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2538 drawing_data_request_begin(events_request
, tss
);
2545 * after request is necessary in addition of after chunk in order to draw
2546 * lines until the end of the screen. after chunk just draws lines until
2553 int after_request(void *hook_data
, void *call_data
)
2555 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2556 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2557 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2559 ProcessList
*process_list
= control_flow_data
->process_list
;
2560 LttTime end_time
= events_request
->end_time
;
2562 ClosureData closure_data
;
2563 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2564 closure_data
.tss
= tss
;
2565 closure_data
.end_time
= end_time
;
2567 TimeWindow time_window
=
2568 lttvwindow_get_time_window(control_flow_data
->tab
);
2569 guint width
= control_flow_data
->drawing
->width
;
2570 convert_time_to_pixels(
2574 &closure_data
.x_end
);
2577 /* Draw last items */
2578 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2579 (void*)&closure_data
);
2582 /* Request expose */
2583 drawing_request_expose(events_request
, tss
, end_time
);
2592 int after_chunk(void *hook_data
, void *call_data
)
2594 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2595 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2596 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2597 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)call_data
;
2598 LttvTracefileContext
*tfc
= lttv_traceset_context_get_current_tfc(tsc
);
2601 ProcessList
*process_list
= control_flow_data
->process_list
;
2603 LttvTraceset
*traceset
= tsc
->ts
;
2604 guint nb_trace
= lttv_traceset_number(traceset
);
2606 /* Only execute when called for the first trace's events request */
2607 if(!process_list
->current_hash_data
) return;
2609 for(i
= 0 ; i
< nb_trace
; i
++) {
2610 g_free(process_list
->current_hash_data
[i
]);
2612 g_free(process_list
->current_hash_data
);
2613 process_list
->current_hash_data
= NULL
;
2616 end_time
= LTT_TIME_MIN(tfc
->timestamp
, events_request
->end_time
);
2617 else /* end of traceset, or position now out of request : end */
2618 end_time
= events_request
->end_time
;
2620 ClosureData closure_data
;
2621 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2622 closure_data
.tss
= tss
;
2623 closure_data
.end_time
= end_time
;
2625 TimeWindow time_window
=
2626 lttvwindow_get_time_window(control_flow_data
->tab
);
2627 guint width
= control_flow_data
->drawing
->width
;
2628 convert_time_to_pixels(
2632 &closure_data
.x_end
);
2634 /* Draw last items */
2635 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2636 (void*)&closure_data
);
2638 /* Reactivate sort */
2639 gtk_tree_sortable_set_sort_column_id(
2640 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2641 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2642 GTK_SORT_ASCENDING
);
2644 update_index_to_pixmap(control_flow_data
->process_list
);
2645 /* Request a full expose : drawing scrambled */
2646 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2648 /* Request expose (updates damages zone also) */
2649 drawing_request_expose(events_request
, tss
, end_time
);
2654 /* after_statedump_end
2656 * @param hook_data ControlFlowData structure of the viewer.
2657 * @param call_data Event context.
2659 * This function adds items to be drawn in a queue for each process.
2662 int before_statedump_end(void *hook_data
, void *call_data
)
2664 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2665 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
2666 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2668 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2670 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
2672 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
2674 LttvTracesetState
*tss
= (LttvTracesetState
*)tfc
->t_context
->ts_context
;
2675 ProcessList
*process_list
= control_flow_data
->process_list
;
2678 e
= ltt_tracefile_get_event(tfc
->tf
);
2680 LttvFilter
*filter
= control_flow_data
->filter
;
2681 if(filter
!= NULL
&& filter
->head
!= NULL
)
2682 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2683 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2686 LttTime evtime
= ltt_event_time(e
);
2688 ClosureData closure_data
;
2689 closure_data
.events_request
= events_request
;
2690 closure_data
.tss
= tss
;
2691 closure_data
.end_time
= evtime
;
2693 TimeWindow time_window
=
2694 lttvwindow_get_time_window(control_flow_data
->tab
);
2695 guint width
= control_flow_data
->drawing
->width
;
2696 convert_time_to_pixels(
2700 &closure_data
.x_end
);
2702 /* Draw last items */
2703 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2704 (void*)&closure_data
);
2706 /* Reactivate sort */
2707 gtk_tree_sortable_set_sort_column_id(
2708 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2709 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2710 GTK_SORT_ASCENDING
);
2712 update_index_to_pixmap(control_flow_data
->process_list
);
2713 /* Request a full expose : drawing scrambled */
2714 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2716 /* Request expose (updates damages zone also) */
2717 drawing_request_expose(events_request
, tss
, evtime
);