1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Mathieu Desnoyers
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20 /*****************************************************************************
21 * Hooks to be called by the main window *
22 *****************************************************************************/
25 /* Event hooks are the drawing hooks called during traceset read. They draw the
26 * icons, text, lines and background color corresponding to the events read.
28 * Two hooks are used for drawing : before_schedchange and after_schedchange hooks. The
29 * before_schedchange is called before the state update that occurs with an event and
30 * the after_schedchange hook is called after this state update.
32 * The before_schedchange hooks fulfill the task of drawing the visible objects that
33 * corresponds to the data accumulated by the after_schedchange hook.
35 * The after_schedchange hook accumulates the data that need to be shown on the screen
36 * (items) into a queue. Then, the next before_schedchange hook will draw what that
37 * queue contains. That's the Right Way (TM) of drawing items on the screen,
38 * because we need to draw the background first (and then add icons, text, ...
39 * over it), but we only know the length of a background region once the state
40 * corresponding to it is over, which happens to be at the next before_schedchange
43 * We also have a hook called at the end of a chunk to draw the information left
44 * undrawn in each process queue. We use the current time as end of
52 //#define PANGO_ENABLE_BACKEND
60 //#include <pango/pango.h>
62 #include <ltt/event.h>
64 #include <ltt/trace.h>
66 #include <lttv/lttv.h>
67 #include <lttv/hook.h>
68 #include <lttv/state.h>
69 #include <lttvwindow/lttvwindow.h>
70 #include <lttvwindow/lttvwindowtraces.h>
71 #include <lttvwindow/support.h>
74 #include "eventhooks.h"
76 #include "processlist.h"
80 #define MAX_PATH_LEN 256
81 #define STATE_LINE_WIDTH 6
82 #define COLLISION_POSITION(height) (((height - STATE_LINE_WIDTH)/2) -3)
84 extern GSList
*g_legend_list
;
87 /* Action to do when background computation completed.
89 * Wait for all the awaited computations to be over.
92 static gint
background_ready(void *hook_data
, void *call_data
)
94 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
95 LttvTrace
*trace
= (LttvTrace
*)call_data
;
97 control_flow_data
->background_info_waiting
--;
99 if(control_flow_data
->background_info_waiting
== 0) {
100 g_message("control flow viewer : background computation data ready.");
102 drawing_clear(control_flow_data
->drawing
);
103 processlist_clear(control_flow_data
->process_list
);
104 gtk_widget_set_size_request(
105 control_flow_data
->drawing
->drawing_area
,
106 -1, processlist_get_height(control_flow_data
->process_list
));
107 redraw_notify(control_flow_data
, NULL
);
114 /* Request background computation. Verify if it is in progress or ready first.
115 * Only for each trace in the tab's traceset.
117 static void request_background_data(ControlFlowData
*control_flow_data
)
119 LttvTracesetContext
* tsc
=
120 lttvwindow_get_traceset_context(control_flow_data
->tab
);
121 gint num_traces
= lttv_traceset_number(tsc
->ts
);
124 LttvTraceState
*tstate
;
126 LttvHooks
*background_ready_hook
=
128 lttv_hooks_add(background_ready_hook
, background_ready
, control_flow_data
,
130 control_flow_data
->background_info_waiting
= 0;
132 for(i
=0;i
<num_traces
;i
++) {
133 trace
= lttv_traceset_get(tsc
->ts
, i
);
134 tstate
= LTTV_TRACE_STATE(tsc
->traces
[i
]);
136 if(lttvwindowtraces_get_ready(g_quark_from_string("state"),trace
)==FALSE
137 && !tstate
->has_precomputed_states
) {
139 if(lttvwindowtraces_get_in_progress(g_quark_from_string("state"),
141 /* We first remove requests that could have been done for the same
142 * information. Happens when two viewers ask for it before servicing
145 if(!lttvwindowtraces_background_request_find(trace
, "state"))
146 lttvwindowtraces_background_request_queue(
147 main_window_get_widget(control_flow_data
->tab
), trace
, "state");
148 lttvwindowtraces_background_notify_queue(control_flow_data
,
152 background_ready_hook
);
153 control_flow_data
->background_info_waiting
++;
154 } else { /* in progress */
156 lttvwindowtraces_background_notify_current(control_flow_data
,
160 background_ready_hook
);
161 control_flow_data
->background_info_waiting
++;
164 /* Data ready. By its nature, this viewer doesn't need to have
165 * its data ready hook called there, because a background
166 * request is always linked with a redraw.
172 lttv_hooks_destroy(background_ready_hook
);
179 * Event Viewer's constructor hook
181 * This constructor is given as a parameter to the menuitem and toolbar button
182 * registration. It creates the list.
183 * @param tab A pointer to the parent tab.
184 * @return The widget created.
187 h_guicontrolflow(LttvPlugin
*plugin
)
189 LttvPluginTab
*ptab
= LTTV_PLUGIN_TAB(plugin
);
190 Tab
*tab
= ptab
->tab
;
191 g_info("h_guicontrolflow, %p", tab
);
192 ControlFlowData
*control_flow_data
= guicontrolflow(ptab
);
194 control_flow_data
->tab
= tab
;
196 // Unreg done in the GuiControlFlow_Destructor
197 lttvwindow_register_traceset_notify(tab
,
201 lttvwindow_register_time_window_notify(tab
,
202 update_time_window_hook
,
204 lttvwindow_register_current_time_notify(tab
,
205 update_current_time_hook
,
207 lttvwindow_register_redraw_notify(tab
,
210 lttvwindow_register_continue_notify(tab
,
213 request_background_data(control_flow_data
);
216 return guicontrolflow_get_widget(control_flow_data
) ;
220 int event_selected_hook(void *hook_data
, void *call_data
)
222 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
223 guint
*event_number
= (guint
*) call_data
;
225 g_debug("DEBUG : event selected by main window : %u", *event_number
);
230 /* Function that selects the color of status&exemode line */
231 static inline PropertiesLine
prepare_s_e_line(LttvProcessState
*process
)
233 PropertiesLine prop_line
;
234 prop_line
.line_width
= STATE_LINE_WIDTH
;
235 prop_line
.style
= GDK_LINE_SOLID
;
236 prop_line
.y
= MIDDLE
;
237 //GdkColormap *colormap = gdk_colormap_get_system();
239 if(process
->state
->s
== LTTV_STATE_RUN
) {
240 if(process
->state
->t
== LTTV_STATE_USER_MODE
)
241 prop_line
.color
= drawing_colors
[COL_RUN_USER_MODE
];
242 else if(process
->state
->t
== LTTV_STATE_SYSCALL
)
243 prop_line
.color
= drawing_colors
[COL_RUN_SYSCALL
];
244 else if(process
->state
->t
== LTTV_STATE_TRAP
)
245 prop_line
.color
= drawing_colors
[COL_RUN_TRAP
];
246 else if(process
->state
->t
== LTTV_STATE_IRQ
)
247 prop_line
.color
= drawing_colors
[COL_RUN_IRQ
];
248 else if(process
->state
->t
== LTTV_STATE_SOFT_IRQ
)
249 prop_line
.color
= drawing_colors
[COL_RUN_SOFT_IRQ
];
250 else if(process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
)
251 prop_line
.color
= drawing_colors
[COL_MODE_UNKNOWN
];
253 g_assert(FALSE
); /* RUNNING MODE UNKNOWN */
254 } else if(process
->state
->s
== LTTV_STATE_WAIT
) {
255 /* We don't show if we wait while in user mode, trap, irq or syscall */
256 prop_line
.color
= drawing_colors
[COL_WAIT
];
257 } else if(process
->state
->s
== LTTV_STATE_WAIT_CPU
) {
258 /* We don't show if we wait for CPU while in user mode, trap, irq
260 prop_line
.color
= drawing_colors
[COL_WAIT_CPU
];
261 } else if(process
->state
->s
== LTTV_STATE_ZOMBIE
) {
262 prop_line
.color
= drawing_colors
[COL_ZOMBIE
];
263 } else if(process
->state
->s
== LTTV_STATE_WAIT_FORK
) {
264 prop_line
.color
= drawing_colors
[COL_WAIT_FORK
];
265 } else if(process
->state
->s
== LTTV_STATE_EXIT
) {
266 prop_line
.color
= drawing_colors
[COL_EXIT
];
267 } else if(process
->state
->s
== LTTV_STATE_UNNAMED
) {
268 prop_line
.color
= drawing_colors
[COL_UNNAMED
];
269 } else if(process
->state
->s
== LTTV_STATE_DEAD
) {
270 prop_line
.color
= drawing_colors
[COL_DEAD
];
272 g_critical("unknown state : %s", g_quark_to_string(process
->state
->s
));
273 g_assert(FALSE
); /* UNKNOWN STATE */
281 /* before_schedchange_hook
283 * This function basically draw lines and icons. Two types of lines are drawn :
284 * one small (3 pixels?) representing the state of the process and the second
285 * type is thicker (10 pixels?) representing on which CPU a process is running
286 * (and this only in running state).
288 * Extremums of the lines :
289 * x_min : time of the last event context for this process kept in memory.
290 * x_max : time of the current event.
291 * y : middle of the process in the process list. The process is found in the
292 * list, therefore is it's position in pixels.
294 * The choice of lines'color is defined by the context of the last event for this
299 int before_schedchange_hook(void *hook_data
, void *call_data
)
301 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
302 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
303 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
305 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
307 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
308 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
311 e
= ltt_tracefile_get_event(tfc
->tf
);
312 gint target_pid_saved
= tfc
->target_pid
;
314 LttTime evtime
= ltt_event_time(e
);
315 LttvFilter
*filter
= control_flow_data
->filter
;
317 /* we are in a schedchange, before the state update. We must draw the
318 * items corresponding to the state before it changes : now is the right
326 pid_out
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
327 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
328 state_out
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 2));
331 tfc
->target_pid
= pid_out
;
332 if(!filter
|| !filter
->head
||
333 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
334 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
335 /* For the pid_out */
336 /* First, check if the current process is in the state computation
337 * process list. If it is there, that means we must add it right now and
338 * draw items from the beginning of the read for it. If it is not
339 * present, it's a new process and it was not present : it will
340 * be added after the state update. */
341 guint cpu
= tfs
->cpu
;
342 guint trace_num
= ts
->parent
.index
;
343 LttvProcessState
*process
= ts
->running_process
[cpu
];
344 /* unknown state, bad current pid */
345 if(process
->pid
!= pid_out
)
346 process
= lttv_state_find_process(ts
,
349 if(process
!= NULL
) {
350 /* Well, the process_out existed : we must get it in the process hash
351 * or add it, and draw its items.
353 /* Add process to process list (if not present) */
355 HashedProcessData
*hashed_process_data
= NULL
;
356 ProcessList
*process_list
= control_flow_data
->process_list
;
357 LttTime birth
= process
->creation_time
;
359 hashed_process_data
= processlist_get_process_data(process_list
,
364 if(hashed_process_data
== NULL
)
366 g_assert(pid_out
== 0 || pid_out
!= process
->ppid
);
367 /* Process not present */
368 ProcessInfo
*process_info
;
369 Drawing_t
*drawing
= control_flow_data
->drawing
;
370 processlist_add(process_list
,
382 &hashed_process_data
);
383 gtk_widget_set_size_request(drawing
->drawing_area
,
386 gtk_widget_queue_draw(drawing
->drawing_area
);
390 /* Now, the process is in the state hash and our own process hash.
391 * We definitely can draw the items related to the ending state.
394 if(ltt_time_compare(hashed_process_data
->next_good_time
,
397 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
399 TimeWindow time_window
=
400 lttvwindow_get_time_window(control_flow_data
->tab
);
402 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
403 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
406 Drawing_t
*drawing
= control_flow_data
->drawing
;
407 guint width
= drawing
->width
;
409 convert_time_to_pixels(
415 /* Draw collision indicator */
416 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
417 gdk_draw_point(hashed_process_data
->pixmap
,
420 COLLISION_POSITION(hashed_process_data
->height
));
421 hashed_process_data
->x
.middle_marked
= TRUE
;
424 TimeWindow time_window
=
425 lttvwindow_get_time_window(control_flow_data
->tab
);
427 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
428 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
431 Drawing_t
*drawing
= control_flow_data
->drawing
;
432 guint width
= drawing
->width
;
434 convert_time_to_pixels(
441 /* Jump over draw if we are at the same x position */
442 if(x
== hashed_process_data
->x
.middle
&&
443 hashed_process_data
->x
.middle_used
)
445 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
446 /* Draw collision indicator */
447 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
448 gdk_draw_point(hashed_process_data
->pixmap
,
451 COLLISION_POSITION(hashed_process_data
->height
));
452 hashed_process_data
->x
.middle_marked
= TRUE
;
456 DrawContext draw_context
;
458 /* Now create the drawing context that will be used to draw
459 * items related to the last state. */
460 draw_context
.drawable
= hashed_process_data
->pixmap
;
461 draw_context
.gc
= drawing
->gc
;
462 draw_context
.pango_layout
= drawing
->pango_layout
;
463 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
464 draw_context
.drawinfo
.end
.x
= x
;
466 draw_context
.drawinfo
.y
.over
= 1;
467 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
468 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
470 draw_context
.drawinfo
.start
.offset
.over
= 0;
471 draw_context
.drawinfo
.start
.offset
.middle
= 0;
472 draw_context
.drawinfo
.start
.offset
.under
= 0;
473 draw_context
.drawinfo
.end
.offset
.over
= 0;
474 draw_context
.drawinfo
.end
.offset
.middle
= 0;
475 draw_context
.drawinfo
.end
.offset
.under
= 0;
479 PropertiesLine prop_line
= prepare_s_e_line(process
);
480 draw_line((void*)&prop_line
, (void*)&draw_context
);
483 /* become the last x position */
484 hashed_process_data
->x
.middle
= x
;
485 hashed_process_data
->x
.middle_used
= TRUE
;
486 hashed_process_data
->x
.middle_marked
= FALSE
;
488 /* Calculate the next good time */
489 convert_pixels_to_time(width
, x
+1, time_window
,
490 &hashed_process_data
->next_good_time
);
496 tfc
->target_pid
= pid_in
;
497 if(!filter
|| !filter
->head
||
498 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
499 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
501 /* First, check if the current process is in the state computation
502 * process list. If it is there, that means we must add it right now and
503 * draw items from the beginning of the read for it. If it is not
504 * present, it's a new process and it was not present : it will
505 * be added after the state update. */
506 LttvProcessState
*process
;
507 process
= lttv_state_find_process(ts
,
509 guint trace_num
= ts
->parent
.index
;
511 if(process
!= NULL
) {
512 /* Well, the process existed : we must get it in the process hash
513 * or add it, and draw its items.
515 /* Add process to process list (if not present) */
517 HashedProcessData
*hashed_process_data
= NULL
;
518 ProcessList
*process_list
= control_flow_data
->process_list
;
519 LttTime birth
= process
->creation_time
;
521 hashed_process_data
= processlist_get_process_data(process_list
,
526 if(hashed_process_data
== NULL
)
528 g_assert(pid_in
== 0 || pid_in
!= process
->ppid
);
529 /* Process not present */
530 ProcessInfo
*process_info
;
531 Drawing_t
*drawing
= control_flow_data
->drawing
;
532 processlist_add(process_list
,
544 &hashed_process_data
);
545 gtk_widget_set_size_request(drawing
->drawing_area
,
548 gtk_widget_queue_draw(drawing
->drawing_area
);
551 //We could set the current process and hash here, but will be done
552 //by after schedchange hook
554 /* Now, the process is in the state hash and our own process hash.
555 * We definitely can draw the items related to the ending state.
558 if(ltt_time_compare(hashed_process_data
->next_good_time
,
561 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
563 TimeWindow time_window
=
564 lttvwindow_get_time_window(control_flow_data
->tab
);
566 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
567 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
570 Drawing_t
*drawing
= control_flow_data
->drawing
;
571 guint width
= drawing
->width
;
573 convert_time_to_pixels(
579 /* Draw collision indicator */
580 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
581 gdk_draw_point(hashed_process_data
->pixmap
,
584 COLLISION_POSITION(hashed_process_data
->height
));
585 hashed_process_data
->x
.middle_marked
= TRUE
;
588 TimeWindow time_window
=
589 lttvwindow_get_time_window(control_flow_data
->tab
);
591 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
592 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
595 Drawing_t
*drawing
= control_flow_data
->drawing
;
596 guint width
= drawing
->width
;
599 convert_time_to_pixels(
606 /* Jump over draw if we are at the same x position */
607 if(x
== hashed_process_data
->x
.middle
&&
608 hashed_process_data
->x
.middle_used
)
610 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
611 /* Draw collision indicator */
612 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
613 gdk_draw_point(hashed_process_data
->pixmap
,
616 COLLISION_POSITION(hashed_process_data
->height
));
617 hashed_process_data
->x
.middle_marked
= TRUE
;
621 DrawContext draw_context
;
623 /* Now create the drawing context that will be used to draw
624 * items related to the last state. */
625 draw_context
.drawable
= hashed_process_data
->pixmap
;
626 draw_context
.gc
= drawing
->gc
;
627 draw_context
.pango_layout
= drawing
->pango_layout
;
628 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
629 draw_context
.drawinfo
.end
.x
= x
;
631 draw_context
.drawinfo
.y
.over
= 1;
632 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
633 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
635 draw_context
.drawinfo
.start
.offset
.over
= 0;
636 draw_context
.drawinfo
.start
.offset
.middle
= 0;
637 draw_context
.drawinfo
.start
.offset
.under
= 0;
638 draw_context
.drawinfo
.end
.offset
.over
= 0;
639 draw_context
.drawinfo
.end
.offset
.middle
= 0;
640 draw_context
.drawinfo
.end
.offset
.under
= 0;
644 PropertiesLine prop_line
= prepare_s_e_line(process
);
645 draw_line((void*)&prop_line
, (void*)&draw_context
);
649 /* become the last x position */
650 hashed_process_data
->x
.middle
= x
;
651 hashed_process_data
->x
.middle_used
= TRUE
;
652 hashed_process_data
->x
.middle_marked
= FALSE
;
654 /* Calculate the next good time */
655 convert_pixels_to_time(width
, x
+1, time_window
,
656 &hashed_process_data
->next_good_time
);
660 g_warning("Cannot find pin_in in schedchange %u", pid_in
);
662 tfc
->target_pid
= target_pid_saved
;
670 GString
*string
= g_string_new("");;
671 gboolean field_names
= TRUE
, state
= TRUE
;
673 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
674 g_string_append_printf(string
,"\n");
677 g_string_append_printf(string
, " %s",
678 g_quark_to_string(tfs
->process
->state
->s
));
681 g_info("%s",string
->str
);
683 g_string_free(string
, TRUE
);
685 /* End of text dump */
690 /* after_schedchange_hook
692 * The draw after hook is called by the reading API to have a
693 * particular event drawn on the screen.
694 * @param hook_data ControlFlowData structure of the viewer.
695 * @param call_data Event context.
697 * This function adds items to be drawn in a queue for each process.
700 int after_schedchange_hook(void *hook_data
, void *call_data
)
702 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
703 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
704 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
706 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
708 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
710 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
713 e
= ltt_tracefile_get_event(tfc
->tf
);
715 LttvFilter
*filter
= control_flow_data
->filter
;
716 LttTime evtime
= ltt_event_time(e
);
718 /* Add process to process list (if not present) */
719 LttvProcessState
*process_in
;
722 HashedProcessData
*hashed_process_data_in
= NULL
;
724 ProcessList
*process_list
= control_flow_data
->process_list
;
729 pid_out
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
730 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
733 tfc
->target_pid
= pid_in
;
734 if(!filter
|| !filter
->head
||
735 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
736 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
737 /* Find process pid_in in the list... */
738 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
739 //process_in = tfs->process;
740 guint cpu
= tfs
->cpu
;
741 guint trace_num
= ts
->parent
.index
;
742 process_in
= ts
->running_process
[cpu
];
743 /* It should exist, because we are after the state update. */
745 g_assert(process_in
!= NULL
);
747 birth
= process_in
->creation_time
;
749 hashed_process_data_in
= processlist_get_process_data(process_list
,
754 if(hashed_process_data_in
== NULL
)
756 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
757 ProcessInfo
*process_info
;
758 Drawing_t
*drawing
= control_flow_data
->drawing
;
759 /* Process not present */
760 processlist_add(process_list
,
772 &hashed_process_data_in
);
773 gtk_widget_set_size_request(drawing
->drawing_area
,
776 gtk_widget_queue_draw(drawing
->drawing_area
);
778 /* Set the current process */
779 process_list
->current_hash_data
[trace_num
][process_in
->cpu
] =
780 hashed_process_data_in
;
782 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
785 TimeWindow time_window
=
786 lttvwindow_get_time_window(control_flow_data
->tab
);
789 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
790 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
793 Drawing_t
*drawing
= control_flow_data
->drawing
;
794 guint width
= drawing
->width
;
797 convert_time_to_pixels(
803 if(hashed_process_data_in
->x
.middle
!= new_x
) {
804 hashed_process_data_in
->x
.middle
= new_x
;
805 hashed_process_data_in
->x
.middle_used
= FALSE
;
806 hashed_process_data_in
->x
.middle_marked
= FALSE
;
817 /* before_execmode_hook
819 * This function basically draw lines and icons. Two types of lines are drawn :
820 * one small (3 pixels?) representing the state of the process and the second
821 * type is thicker (10 pixels?) representing on which CPU a process is running
822 * (and this only in running state).
824 * Extremums of the lines :
825 * x_min : time of the last event context for this process kept in memory.
826 * x_max : time of the current event.
827 * y : middle of the process in the process list. The process is found in the
828 * list, therefore is it's position in pixels.
830 * The choice of lines'color is defined by the context of the last event for this
835 int before_execmode_hook(void *hook_data
, void *call_data
)
837 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
838 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
839 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
841 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
843 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
845 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
848 e
= ltt_tracefile_get_event(tfc
->tf
);
850 LttvFilter
*filter
= control_flow_data
->filter
;
851 if(filter
!= NULL
&& filter
->head
!= NULL
)
852 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
853 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
856 LttTime evtime
= ltt_event_time(e
);
858 /* we are in a execmode, before the state update. We must draw the
859 * items corresponding to the state before it changes : now is the right
863 //LttvProcessState *process = tfs->process;
864 guint cpu
= tfs
->cpu
;
865 guint trace_num
= ts
->parent
.index
;
866 LttvProcessState
*process
= ts
->running_process
[cpu
];
867 g_assert(process
!= NULL
);
869 guint pid
= process
->pid
;
871 /* Well, the process_out existed : we must get it in the process hash
872 * or add it, and draw its items.
874 /* Add process to process list (if not present) */
876 HashedProcessData
*hashed_process_data
= NULL
;
877 ProcessList
*process_list
= control_flow_data
->process_list
;
878 LttTime birth
= process
->creation_time
;
880 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
881 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
883 hashed_process_data
= processlist_get_process_data(process_list
,
888 if(unlikely(hashed_process_data
== NULL
))
890 g_assert(pid
== 0 || pid
!= process
->ppid
);
891 ProcessInfo
*process_info
;
892 /* Process not present */
893 Drawing_t
*drawing
= control_flow_data
->drawing
;
894 processlist_add(process_list
,
906 &hashed_process_data
);
907 gtk_widget_set_size_request(drawing
->drawing_area
,
910 gtk_widget_queue_draw(drawing
->drawing_area
);
912 /* Set the current process */
913 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
917 /* Now, the process is in the state hash and our own process hash.
918 * We definitely can draw the items related to the ending state.
921 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
924 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
925 TimeWindow time_window
=
926 lttvwindow_get_time_window(control_flow_data
->tab
);
929 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
930 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
933 Drawing_t
*drawing
= control_flow_data
->drawing
;
934 guint width
= drawing
->width
;
936 convert_time_to_pixels(
942 /* Draw collision indicator */
943 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
944 gdk_draw_point(hashed_process_data
->pixmap
,
947 COLLISION_POSITION(hashed_process_data
->height
));
948 hashed_process_data
->x
.middle_marked
= TRUE
;
951 TimeWindow time_window
=
952 lttvwindow_get_time_window(control_flow_data
->tab
);
955 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
956 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
959 Drawing_t
*drawing
= control_flow_data
->drawing
;
960 guint width
= drawing
->width
;
963 convert_time_to_pixels(
970 /* Jump over draw if we are at the same x position */
971 if(unlikely(x
== hashed_process_data
->x
.middle
&&
972 hashed_process_data
->x
.middle_used
))
974 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
975 /* Draw collision indicator */
976 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
977 gdk_draw_point(hashed_process_data
->pixmap
,
980 COLLISION_POSITION(hashed_process_data
->height
));
981 hashed_process_data
->x
.middle_marked
= TRUE
;
986 DrawContext draw_context
;
987 /* Now create the drawing context that will be used to draw
988 * items related to the last state. */
989 draw_context
.drawable
= hashed_process_data
->pixmap
;
990 draw_context
.gc
= drawing
->gc
;
991 draw_context
.pango_layout
= drawing
->pango_layout
;
992 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
993 draw_context
.drawinfo
.end
.x
= x
;
995 draw_context
.drawinfo
.y
.over
= 1;
996 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
997 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
999 draw_context
.drawinfo
.start
.offset
.over
= 0;
1000 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1001 draw_context
.drawinfo
.start
.offset
.under
= 0;
1002 draw_context
.drawinfo
.end
.offset
.over
= 0;
1003 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1004 draw_context
.drawinfo
.end
.offset
.under
= 0;
1008 PropertiesLine prop_line
= prepare_s_e_line(process
);
1009 draw_line((void*)&prop_line
, (void*)&draw_context
);
1012 /* become the last x position */
1013 hashed_process_data
->x
.middle
= x
;
1014 hashed_process_data
->x
.middle_used
= TRUE
;
1015 hashed_process_data
->x
.middle_marked
= FALSE
;
1017 /* Calculate the next good time */
1018 convert_pixels_to_time(width
, x
+1, time_window
,
1019 &hashed_process_data
->next_good_time
);
1026 /* before_process_exit_hook
1028 * Draw lines for process event.
1030 * @param hook_data ControlFlowData structure of the viewer.
1031 * @param call_data Event context.
1033 * This function adds items to be drawn in a queue for each process.
1038 int before_process_exit_hook(void *hook_data
, void *call_data
)
1040 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1041 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1043 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1045 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1047 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1049 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1052 e
= ltt_tracefile_get_event(tfc
->tf
);
1054 LttvFilter
*filter
= control_flow_data
->filter
;
1055 if(filter
!= NULL
&& filter
->head
!= NULL
)
1056 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1057 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1060 LttTime evtime
= ltt_event_time(e
);
1062 /* Add process to process list (if not present) */
1063 //LttvProcessState *process = tfs->process;
1064 guint cpu
= tfs
->cpu
;
1065 guint trace_num
= ts
->parent
.index
;
1066 LttvProcessState
*process
= ts
->running_process
[cpu
];
1067 guint pid
= process
->pid
;
1069 guint pl_height
= 0;
1070 HashedProcessData
*hashed_process_data
= NULL
;
1072 ProcessList
*process_list
= control_flow_data
->process_list
;
1074 g_assert(process
!= NULL
);
1076 birth
= process
->creation_time
;
1078 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1079 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1081 hashed_process_data
= processlist_get_process_data(process_list
,
1086 if(unlikely(hashed_process_data
== NULL
))
1088 g_assert(pid
== 0 || pid
!= process
->ppid
);
1089 /* Process not present */
1090 Drawing_t
*drawing
= control_flow_data
->drawing
;
1091 ProcessInfo
*process_info
;
1092 processlist_add(process_list
,
1104 &hashed_process_data
);
1105 gtk_widget_set_size_request(drawing
->drawing_area
,
1108 gtk_widget_queue_draw(drawing
->drawing_area
);
1112 /* Now, the process is in the state hash and our own process hash.
1113 * We definitely can draw the items related to the ending state.
1116 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1119 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1120 TimeWindow time_window
=
1121 lttvwindow_get_time_window(control_flow_data
->tab
);
1124 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1125 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1127 #endif //EXTRA_CHECK
1128 Drawing_t
*drawing
= control_flow_data
->drawing
;
1129 guint width
= drawing
->width
;
1131 convert_time_to_pixels(
1137 /* Draw collision indicator */
1138 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1139 gdk_draw_point(hashed_process_data
->pixmap
,
1142 COLLISION_POSITION(hashed_process_data
->height
));
1143 hashed_process_data
->x
.middle_marked
= TRUE
;
1146 TimeWindow time_window
=
1147 lttvwindow_get_time_window(control_flow_data
->tab
);
1150 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1151 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1153 #endif //EXTRA_CHECK
1154 Drawing_t
*drawing
= control_flow_data
->drawing
;
1155 guint width
= drawing
->width
;
1158 convert_time_to_pixels(
1165 /* Jump over draw if we are at the same x position */
1166 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1167 hashed_process_data
->x
.middle_used
))
1169 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1170 /* Draw collision indicator */
1171 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1172 gdk_draw_point(hashed_process_data
->pixmap
,
1175 COLLISION_POSITION(hashed_process_data
->height
));
1176 hashed_process_data
->x
.middle_marked
= TRUE
;
1180 DrawContext draw_context
;
1182 /* Now create the drawing context that will be used to draw
1183 * items related to the last state. */
1184 draw_context
.drawable
= hashed_process_data
->pixmap
;
1185 draw_context
.gc
= drawing
->gc
;
1186 draw_context
.pango_layout
= drawing
->pango_layout
;
1187 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1188 draw_context
.drawinfo
.end
.x
= x
;
1190 draw_context
.drawinfo
.y
.over
= 1;
1191 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1192 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1194 draw_context
.drawinfo
.start
.offset
.over
= 0;
1195 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1196 draw_context
.drawinfo
.start
.offset
.under
= 0;
1197 draw_context
.drawinfo
.end
.offset
.over
= 0;
1198 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1199 draw_context
.drawinfo
.end
.offset
.under
= 0;
1203 PropertiesLine prop_line
= prepare_s_e_line(process
);
1204 draw_line((void*)&prop_line
, (void*)&draw_context
);
1207 /* become the last x position */
1208 hashed_process_data
->x
.middle
= x
;
1209 hashed_process_data
->x
.middle_used
= TRUE
;
1210 hashed_process_data
->x
.middle_marked
= FALSE
;
1212 /* Calculate the next good time */
1213 convert_pixels_to_time(width
, x
+1, time_window
,
1214 &hashed_process_data
->next_good_time
);
1224 /* before_process_release_hook
1226 * Draw lines for process event.
1228 * @param hook_data ControlFlowData structure of the viewer.
1229 * @param call_data Event context.
1231 * This function adds items to be drawn in a queue for each process.
1236 int before_process_release_hook(void *hook_data
, void *call_data
)
1238 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1239 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1241 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1243 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1245 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1247 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1250 e
= ltt_tracefile_get_event(tfc
->tf
);
1252 LttvFilter
*filter
= control_flow_data
->filter
;
1253 if(filter
!= NULL
&& filter
->head
!= NULL
)
1254 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1255 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1258 LttTime evtime
= ltt_event_time(e
);
1260 guint trace_num
= ts
->parent
.index
;
1264 pid
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
1267 /* Add process to process list (if not present) */
1268 /* Don't care about the process if it's not in the state hash already :
1269 * that means a process that has never done anything in the trace and
1270 * unknown suddently gets destroyed : no state meaningful to show. */
1271 LttvProcessState
*process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1273 if(process
!= NULL
) {
1275 guint pl_height
= 0;
1276 HashedProcessData
*hashed_process_data
= NULL
;
1278 ProcessList
*process_list
= control_flow_data
->process_list
;
1280 birth
= process
->creation_time
;
1282 /* Cannot use current process : this event happens on another process,
1283 * action done by the parent. */
1284 hashed_process_data
= processlist_get_process_data(process_list
,
1289 if(unlikely(hashed_process_data
== NULL
))
1291 * Process already been scheduled out EXIT_DEAD, not in the process list
1292 * anymore. Just return.
1296 /* Now, the process is in the state hash and our own process hash.
1297 * We definitely can draw the items related to the ending state.
1300 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1303 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1304 TimeWindow time_window
=
1305 lttvwindow_get_time_window(control_flow_data
->tab
);
1308 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1309 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1311 #endif //EXTRA_CHECK
1312 Drawing_t
*drawing
= control_flow_data
->drawing
;
1313 guint width
= drawing
->width
;
1315 convert_time_to_pixels(
1321 /* Draw collision indicator */
1322 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1323 gdk_draw_point(hashed_process_data
->pixmap
,
1326 COLLISION_POSITION(hashed_process_data
->height
));
1327 hashed_process_data
->x
.middle_marked
= TRUE
;
1330 TimeWindow time_window
=
1331 lttvwindow_get_time_window(control_flow_data
->tab
);
1334 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1335 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1337 #endif //EXTRA_CHECK
1338 Drawing_t
*drawing
= control_flow_data
->drawing
;
1339 guint width
= drawing
->width
;
1342 convert_time_to_pixels(
1349 /* Jump over draw if we are at the same x position */
1350 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1351 hashed_process_data
->x
.middle_used
))
1353 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1354 /* Draw collision indicator */
1355 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1356 gdk_draw_point(hashed_process_data
->pixmap
,
1359 COLLISION_POSITION(hashed_process_data
->height
));
1360 hashed_process_data
->x
.middle_marked
= TRUE
;
1364 DrawContext draw_context
;
1366 /* Now create the drawing context that will be used to draw
1367 * items related to the last state. */
1368 draw_context
.drawable
= hashed_process_data
->pixmap
;
1369 draw_context
.gc
= drawing
->gc
;
1370 draw_context
.pango_layout
= drawing
->pango_layout
;
1371 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1372 draw_context
.drawinfo
.end
.x
= x
;
1374 draw_context
.drawinfo
.y
.over
= 1;
1375 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1376 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1378 draw_context
.drawinfo
.start
.offset
.over
= 0;
1379 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1380 draw_context
.drawinfo
.start
.offset
.under
= 0;
1381 draw_context
.drawinfo
.end
.offset
.over
= 0;
1382 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1383 draw_context
.drawinfo
.end
.offset
.under
= 0;
1387 PropertiesLine prop_line
= prepare_s_e_line(process
);
1388 draw_line((void*)&prop_line
, (void*)&draw_context
);
1391 /* become the last x position */
1392 hashed_process_data
->x
.middle
= x
;
1393 hashed_process_data
->x
.middle_used
= TRUE
;
1394 hashed_process_data
->x
.middle_marked
= FALSE
;
1396 /* Calculate the next good time */
1397 convert_pixels_to_time(width
, x
+1, time_window
,
1398 &hashed_process_data
->next_good_time
);
1410 /* after_process_fork_hook
1412 * Create the processlist entry for the child process. Put the last
1413 * position in x at the current time value.
1415 * @param hook_data ControlFlowData structure of the viewer.
1416 * @param call_data Event context.
1418 * This function adds items to be drawn in a queue for each process.
1421 int after_process_fork_hook(void *hook_data
, void *call_data
)
1423 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1424 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1425 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1427 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1429 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1431 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1434 e
= ltt_tracefile_get_event(tfc
->tf
);
1436 LttvFilter
*filter
= control_flow_data
->filter
;
1437 if(filter
!= NULL
&& filter
->head
!= NULL
)
1438 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1439 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1442 LttTime evtime
= ltt_event_time(e
);
1446 child_pid
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
1449 /* Add process to process list (if not present) */
1450 LttvProcessState
*process_child
;
1452 guint pl_height
= 0;
1453 HashedProcessData
*hashed_process_data_child
= NULL
;
1455 ProcessList
*process_list
= control_flow_data
->process_list
;
1457 /* Find child in the list... */
1458 process_child
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1459 /* It should exist, because we are after the state update. */
1460 g_assert(process_child
!= NULL
);
1462 birth
= process_child
->creation_time
;
1463 guint trace_num
= ts
->parent
.index
;
1465 /* Cannot use current process, because this action is done by the parent
1467 hashed_process_data_child
= processlist_get_process_data(process_list
,
1472 if(likely(hashed_process_data_child
== NULL
))
1474 g_assert(child_pid
== 0 || child_pid
!= process_child
->ppid
);
1475 /* Process not present */
1476 Drawing_t
*drawing
= control_flow_data
->drawing
;
1477 ProcessInfo
*process_info
;
1478 processlist_add(process_list
,
1481 process_child
->tgid
,
1483 process_child
->ppid
,
1486 process_child
->name
,
1487 process_child
->brand
,
1490 &hashed_process_data_child
);
1491 gtk_widget_set_size_request(drawing
->drawing_area
,
1494 gtk_widget_queue_draw(drawing
->drawing_area
);
1496 processlist_set_ppid(process_list
, process_child
->ppid
,
1497 hashed_process_data_child
);
1498 processlist_set_tgid(process_list
, process_child
->tgid
,
1499 hashed_process_data_child
);
1503 if(likely(ltt_time_compare(hashed_process_data_child
->next_good_time
,
1506 TimeWindow time_window
=
1507 lttvwindow_get_time_window(control_flow_data
->tab
);
1510 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1511 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1513 #endif //EXTRA_CHECK
1514 Drawing_t
*drawing
= control_flow_data
->drawing
;
1515 guint width
= drawing
->width
;
1517 convert_time_to_pixels(
1523 if(likely(hashed_process_data_child
->x
.over
!= new_x
)) {
1524 hashed_process_data_child
->x
.over
= new_x
;
1525 hashed_process_data_child
->x
.over_used
= FALSE
;
1526 hashed_process_data_child
->x
.over_marked
= FALSE
;
1528 if(likely(hashed_process_data_child
->x
.middle
!= new_x
)) {
1529 hashed_process_data_child
->x
.middle
= new_x
;
1530 hashed_process_data_child
->x
.middle_used
= FALSE
;
1531 hashed_process_data_child
->x
.middle_marked
= FALSE
;
1533 if(likely(hashed_process_data_child
->x
.under
!= new_x
)) {
1534 hashed_process_data_child
->x
.under
= new_x
;
1535 hashed_process_data_child
->x
.under_used
= FALSE
;
1536 hashed_process_data_child
->x
.under_marked
= FALSE
;
1544 /* after_process_exit_hook
1546 * Create the processlist entry for the child process. Put the last
1547 * position in x at the current time value.
1549 * @param hook_data ControlFlowData structure of the viewer.
1550 * @param call_data Event context.
1552 * This function adds items to be drawn in a queue for each process.
1555 int after_process_exit_hook(void *hook_data
, void *call_data
)
1557 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1558 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1559 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1561 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1563 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1565 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1568 e
= ltt_tracefile_get_event(tfc
->tf
);
1570 LttvFilter
*filter
= control_flow_data
->filter
;
1571 if(filter
!= NULL
&& filter
->head
!= NULL
)
1572 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1573 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1576 LttTime evtime
= ltt_event_time(e
);
1578 /* Add process to process list (if not present) */
1579 //LttvProcessState *process = tfs->process;
1580 guint cpu
= tfs
->cpu
;
1581 guint trace_num
= ts
->parent
.index
;
1582 LttvProcessState
*process
= ts
->running_process
[cpu
];
1584 /* It should exist, because we are after the state update. */
1585 g_assert(process
!= NULL
);
1587 guint pid
= process
->pid
;
1589 guint pl_height
= 0;
1590 HashedProcessData
*hashed_process_data
= NULL
;
1592 ProcessList
*process_list
= control_flow_data
->process_list
;
1594 birth
= process
->creation_time
;
1596 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
) ){
1597 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1599 hashed_process_data
= processlist_get_process_data(process_list
,
1604 if(unlikely(hashed_process_data
== NULL
))
1606 g_assert(pid
== 0 || pid
!= process
->ppid
);
1607 /* Process not present */
1608 Drawing_t
*drawing
= control_flow_data
->drawing
;
1609 ProcessInfo
*process_info
;
1610 processlist_add(process_list
,
1622 &hashed_process_data
);
1623 gtk_widget_set_size_request(drawing
->drawing_area
,
1626 gtk_widget_queue_draw(drawing
->drawing_area
);
1629 /* Set the current process */
1630 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1631 hashed_process_data
;
1634 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
1637 TimeWindow time_window
=
1638 lttvwindow_get_time_window(control_flow_data
->tab
);
1641 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1642 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1644 #endif //EXTRA_CHECK
1645 Drawing_t
*drawing
= control_flow_data
->drawing
;
1646 guint width
= drawing
->width
;
1648 convert_time_to_pixels(
1653 if(unlikely(hashed_process_data
->x
.middle
!= new_x
)) {
1654 hashed_process_data
->x
.middle
= new_x
;
1655 hashed_process_data
->x
.middle_used
= FALSE
;
1656 hashed_process_data
->x
.middle_marked
= FALSE
;
1664 /* Get the filename of the process to print */
1665 int after_fs_exec_hook(void *hook_data
, void *call_data
)
1667 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1668 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1669 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1671 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1673 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1675 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1678 e
= ltt_tracefile_get_event(tfc
->tf
);
1680 LttvFilter
*filter
= control_flow_data
->filter
;
1681 if(filter
!= NULL
&& filter
->head
!= NULL
)
1682 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1683 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1686 guint cpu
= tfs
->cpu
;
1687 guint trace_num
= ts
->parent
.index
;
1688 LttvProcessState
*process
= ts
->running_process
[cpu
];
1689 g_assert(process
!= NULL
);
1691 guint pid
= process
->pid
;
1693 /* Well, the process_out existed : we must get it in the process hash
1694 * or add it, and draw its items.
1696 /* Add process to process list (if not present) */
1697 guint pl_height
= 0;
1698 HashedProcessData
*hashed_process_data
= NULL
;
1699 ProcessList
*process_list
= control_flow_data
->process_list
;
1700 LttTime birth
= process
->creation_time
;
1702 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1703 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1705 hashed_process_data
= processlist_get_process_data(process_list
,
1710 if(unlikely(hashed_process_data
== NULL
))
1712 g_assert(pid
== 0 || pid
!= process
->ppid
);
1713 ProcessInfo
*process_info
;
1714 /* Process not present */
1715 Drawing_t
*drawing
= control_flow_data
->drawing
;
1716 processlist_add(process_list
,
1728 &hashed_process_data
);
1729 gtk_widget_set_size_request(drawing
->drawing_area
,
1732 gtk_widget_queue_draw(drawing
->drawing_area
);
1734 /* Set the current process */
1735 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1736 hashed_process_data
;
1739 processlist_set_name(process_list
, process
->name
, hashed_process_data
);
1745 /* Get the filename of the process to print */
1746 int after_user_generic_thread_brand_hook(void *hook_data
, void *call_data
)
1748 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1749 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1750 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1752 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1754 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1756 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1759 e
= ltt_tracefile_get_event(tfc
->tf
);
1761 LttvFilter
*filter
= control_flow_data
->filter
;
1762 if(filter
!= NULL
&& filter
->head
!= NULL
)
1763 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1764 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1767 guint cpu
= tfs
->cpu
;
1768 guint trace_num
= ts
->parent
.index
;
1769 LttvProcessState
*process
= ts
->running_process
[cpu
];
1770 g_assert(process
!= NULL
);
1772 guint pid
= process
->pid
;
1774 /* Well, the process_out existed : we must get it in the process hash
1775 * or add it, and draw its items.
1777 /* Add process to process list (if not present) */
1778 guint pl_height
= 0;
1779 HashedProcessData
*hashed_process_data
= NULL
;
1780 ProcessList
*process_list
= control_flow_data
->process_list
;
1781 LttTime birth
= process
->creation_time
;
1783 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1784 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1786 hashed_process_data
= processlist_get_process_data(process_list
,
1791 if(unlikely(hashed_process_data
== NULL
))
1793 g_assert(pid
== 0 || pid
!= process
->ppid
);
1794 ProcessInfo
*process_info
;
1795 /* Process not present */
1796 Drawing_t
*drawing
= control_flow_data
->drawing
;
1797 processlist_add(process_list
,
1809 &hashed_process_data
);
1810 gtk_widget_set_size_request(drawing
->drawing_area
,
1813 gtk_widget_queue_draw(drawing
->drawing_area
);
1815 /* Set the current process */
1816 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1817 hashed_process_data
;
1820 processlist_set_brand(process_list
, process
->brand
, hashed_process_data
);
1827 /* after_event_enum_process_hook
1829 * Create the processlist entry for the child process. Put the last
1830 * position in x at the current time value.
1832 * @param hook_data ControlFlowData structure of the viewer.
1833 * @param call_data Event context.
1835 * This function adds items to be drawn in a queue for each process.
1838 int after_event_enum_process_hook(void *hook_data
, void *call_data
)
1840 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1841 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1842 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1844 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1846 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1848 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1850 guint first_cpu
, nb_cpus
, cpu
;
1853 e
= ltt_tracefile_get_event(tfc
->tf
);
1855 LttvFilter
*filter
= control_flow_data
->filter
;
1856 if(filter
!= NULL
&& filter
->head
!= NULL
)
1857 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1858 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1861 LttTime evtime
= ltt_event_time(e
);
1863 /* Add process to process list (if not present) */
1864 LttvProcessState
*process_in
;
1866 guint pl_height
= 0;
1867 HashedProcessData
*hashed_process_data_in
= NULL
;
1869 ProcessList
*process_list
= control_flow_data
->process_list
;
1870 guint trace_num
= ts
->parent
.index
;
1874 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
1879 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1881 first_cpu
= ANY_CPU
;
1882 nb_cpus
= ANY_CPU
+1;
1885 for(cpu
= first_cpu
; cpu
< nb_cpus
; cpu
++) {
1886 /* Find process pid_in in the list... */
1887 process_in
= lttv_state_find_process(ts
, cpu
, pid_in
);
1888 //process_in = tfs->process;
1889 //guint cpu = tfs->cpu;
1890 //guint trace_num = ts->parent.index;
1891 //process_in = ts->running_process[cpu];
1892 /* It should exist, because we are after the state update. */
1894 //g_assert(process_in != NULL);
1895 #endif //EXTRA_CHECK
1896 birth
= process_in
->creation_time
;
1898 hashed_process_data_in
= processlist_get_process_data(process_list
,
1903 if(hashed_process_data_in
== NULL
)
1905 if(pid_in
!= 0 && pid_in
== process_in
->ppid
)
1906 g_critical("TEST %u , %u", pid_in
, process_in
->ppid
);
1907 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
1908 ProcessInfo
*process_info
;
1909 Drawing_t
*drawing
= control_flow_data
->drawing
;
1910 /* Process not present */
1911 processlist_add(process_list
,
1923 &hashed_process_data_in
);
1924 gtk_widget_set_size_request(drawing
->drawing_area
,
1927 gtk_widget_queue_draw(drawing
->drawing_area
);
1929 processlist_set_name(process_list
, process_in
->name
,
1930 hashed_process_data_in
);
1931 processlist_set_ppid(process_list
, process_in
->ppid
,
1932 hashed_process_data_in
);
1933 processlist_set_tgid(process_list
, process_in
->tgid
,
1934 hashed_process_data_in
);
1941 gint
update_time_window_hook(void *hook_data
, void *call_data
)
1943 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1944 Drawing_t
*drawing
= control_flow_data
->drawing
;
1945 ProcessList
*process_list
= control_flow_data
->process_list
;
1947 const TimeWindowNotifyData
*time_window_nofify_data
=
1948 ((const TimeWindowNotifyData
*)call_data
);
1950 TimeWindow
*old_time_window
=
1951 time_window_nofify_data
->old_time_window
;
1952 TimeWindow
*new_time_window
=
1953 time_window_nofify_data
->new_time_window
;
1955 /* Update the ruler */
1956 drawing_update_ruler(control_flow_data
->drawing
,
1960 /* Two cases : zoom in/out or scrolling */
1962 /* In order to make sure we can reuse the old drawing, the scale must
1963 * be the same and the new time interval being partly located in the
1964 * currently shown time interval. (reuse is only for scrolling)
1967 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
1968 old_time_window
->start_time
.tv_sec
,
1969 old_time_window
->start_time
.tv_nsec
,
1970 old_time_window
->time_width
.tv_sec
,
1971 old_time_window
->time_width
.tv_nsec
);
1973 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
1974 new_time_window
->start_time
.tv_sec
,
1975 new_time_window
->start_time
.tv_nsec
,
1976 new_time_window
->time_width
.tv_sec
,
1977 new_time_window
->time_width
.tv_nsec
);
1979 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
1980 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
1982 /* Same scale (scrolling) */
1983 g_info("scrolling");
1984 LttTime
*ns
= &new_time_window
->start_time
;
1985 LttTime
*nw
= &new_time_window
->time_width
;
1986 LttTime
*os
= &old_time_window
->start_time
;
1987 LttTime
*ow
= &old_time_window
->time_width
;
1988 LttTime old_end
= old_time_window
->end_time
;
1989 LttTime new_end
= new_time_window
->end_time
;
1991 //if(ns<os+w && os+w<ns+w)
1992 //if(ns<old_end && os<ns)
1993 if(ltt_time_compare(*ns
, old_end
) == -1
1994 && ltt_time_compare(*os
, *ns
) == -1)
1996 g_info("scrolling near right");
1997 /* Scroll right, keep right part of the screen */
1999 guint width
= control_flow_data
->drawing
->width
;
2000 convert_time_to_pixels(
2006 /* Copy old data to new location */
2007 copy_pixmap_region(process_list
,
2009 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2013 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
2015 if(drawing
->damage_begin
== drawing
->damage_end
)
2016 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
2018 drawing
->damage_begin
= 0;
2020 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2022 /* Clear the data request background, but not SAFETY */
2023 rectangle_pixmap(process_list
,
2024 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2026 drawing
->damage_begin
+SAFETY
, 0,
2027 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2029 gtk_widget_queue_draw(drawing
->drawing_area
);
2030 //gtk_widget_queue_draw_area (drawing->drawing_area,
2032 // control_flow_data->drawing->width,
2033 // control_flow_data->drawing->height);
2035 /* Get new data for the rest. */
2036 drawing_data_request(control_flow_data
->drawing
,
2037 drawing
->damage_begin
, 0,
2038 drawing
->damage_end
- drawing
->damage_begin
,
2039 control_flow_data
->drawing
->height
);
2042 //if(ns<os && os<ns+w)
2043 //if(ns<os && os<new_end)
2044 if(ltt_time_compare(*ns
,*os
) == -1
2045 && ltt_time_compare(*os
,new_end
) == -1)
2047 g_info("scrolling near left");
2048 /* Scroll left, keep left part of the screen */
2050 guint width
= control_flow_data
->drawing
->width
;
2051 convert_time_to_pixels(
2057 /* Copy old data to new location */
2058 copy_pixmap_region (process_list
,
2060 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2066 if(drawing
->damage_begin
== drawing
->damage_end
)
2067 drawing
->damage_end
= x
;
2069 drawing
->damage_end
=
2070 control_flow_data
->drawing
->width
;
2072 drawing
->damage_begin
= 0;
2074 rectangle_pixmap (process_list
,
2075 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2077 drawing
->damage_begin
, 0,
2078 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2081 gtk_widget_queue_draw(drawing
->drawing_area
);
2082 //gtk_widget_queue_draw_area (drawing->drawing_area,
2084 // control_flow_data->drawing->width,
2085 // control_flow_data->drawing->height);
2088 /* Get new data for the rest. */
2089 drawing_data_request(control_flow_data
->drawing
,
2090 drawing
->damage_begin
, 0,
2091 drawing
->damage_end
- drawing
->damage_begin
,
2092 control_flow_data
->drawing
->height
);
2095 if(ltt_time_compare(*ns
,*os
) == 0)
2097 g_info("not scrolling");
2099 g_info("scrolling far");
2100 /* Cannot reuse any part of the screen : far jump */
2103 rectangle_pixmap (process_list
,
2104 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2107 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2110 //gtk_widget_queue_draw_area (drawing->drawing_area,
2112 // control_flow_data->drawing->width,
2113 // control_flow_data->drawing->height);
2114 gtk_widget_queue_draw(drawing
->drawing_area
);
2116 drawing
->damage_begin
= 0;
2117 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2119 drawing_data_request(control_flow_data
->drawing
,
2121 control_flow_data
->drawing
->width
,
2122 control_flow_data
->drawing
->height
);
2128 /* Different scale (zoom) */
2131 rectangle_pixmap (process_list
,
2132 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2135 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2138 //gtk_widget_queue_draw_area (drawing->drawing_area,
2140 // control_flow_data->drawing->width,
2141 // control_flow_data->drawing->height);
2142 gtk_widget_queue_draw(drawing
->drawing_area
);
2144 drawing
->damage_begin
= 0;
2145 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2147 drawing_data_request(control_flow_data
->drawing
,
2149 control_flow_data
->drawing
->width
,
2150 control_flow_data
->drawing
->height
);
2153 /* Update directly when scrolling */
2154 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2160 gint
traceset_notify(void *hook_data
, void *call_data
)
2162 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2163 Drawing_t
*drawing
= control_flow_data
->drawing
;
2165 if(unlikely(drawing
->gc
== NULL
)) {
2168 if(drawing
->dotted_gc
== NULL
) {
2172 drawing_clear(control_flow_data
->drawing
);
2173 processlist_clear(control_flow_data
->process_list
);
2174 gtk_widget_set_size_request(
2175 control_flow_data
->drawing
->drawing_area
,
2176 -1, processlist_get_height(control_flow_data
->process_list
));
2177 redraw_notify(control_flow_data
, NULL
);
2179 request_background_data(control_flow_data
);
2184 gint
redraw_notify(void *hook_data
, void *call_data
)
2186 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2187 Drawing_t
*drawing
= control_flow_data
->drawing
;
2188 GtkWidget
*widget
= drawing
->drawing_area
;
2190 drawing
->damage_begin
= 0;
2191 drawing
->damage_end
= drawing
->width
;
2193 /* fun feature, to be separated someday... */
2194 drawing_clear(control_flow_data
->drawing
);
2195 processlist_clear(control_flow_data
->process_list
);
2196 gtk_widget_set_size_request(
2197 control_flow_data
->drawing
->drawing_area
,
2198 -1, processlist_get_height(control_flow_data
->process_list
));
2200 rectangle_pixmap (control_flow_data
->process_list
,
2201 widget
->style
->black_gc
,
2204 drawing
->alloc_width
,
2207 gtk_widget_queue_draw(drawing
->drawing_area
);
2209 if(drawing
->damage_begin
< drawing
->damage_end
)
2211 drawing_data_request(drawing
,
2212 drawing
->damage_begin
,
2214 drawing
->damage_end
-drawing
->damage_begin
,
2218 //gtk_widget_queue_draw_area(drawing->drawing_area,
2221 // drawing->height);
2227 gint
continue_notify(void *hook_data
, void *call_data
)
2229 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2230 Drawing_t
*drawing
= control_flow_data
->drawing
;
2232 //g_assert(widget->allocation.width == drawing->damage_end);
2234 if(drawing
->damage_begin
< drawing
->damage_end
)
2236 drawing_data_request(drawing
,
2237 drawing
->damage_begin
,
2239 drawing
->damage_end
-drawing
->damage_begin
,
2247 gint
update_current_time_hook(void *hook_data
, void *call_data
)
2249 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
2250 Drawing_t
*drawing
= control_flow_data
->drawing
;
2252 LttTime current_time
= *((LttTime
*)call_data
);
2254 TimeWindow time_window
=
2255 lttvwindow_get_time_window(control_flow_data
->tab
);
2257 LttTime time_begin
= time_window
.start_time
;
2258 LttTime width
= time_window
.time_width
;
2261 guint64 time_ll
= ltt_time_to_uint64(width
);
2262 time_ll
= time_ll
>> 1; /* divide by two */
2263 half_width
= ltt_time_from_uint64(time_ll
);
2265 LttTime time_end
= ltt_time_add(time_begin
, width
);
2267 LttvTracesetContext
* tsc
=
2268 lttvwindow_get_traceset_context(control_flow_data
->tab
);
2270 LttTime trace_start
= tsc
->time_span
.start_time
;
2271 LttTime trace_end
= tsc
->time_span
.end_time
;
2273 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
2274 current_time
.tv_nsec
);
2278 /* If current time is inside time interval, just move the highlight
2281 /* Else, we have to change the time interval. We have to tell it
2282 * to the main window. */
2283 /* The time interval change will take care of placing the current
2284 * time at the center of the visible area, or nearest possible if we are
2285 * at one end of the trace. */
2288 if(ltt_time_compare(current_time
, time_begin
) < 0)
2290 TimeWindow new_time_window
;
2292 if(ltt_time_compare(current_time
,
2293 ltt_time_add(trace_start
,half_width
)) < 0)
2294 time_begin
= trace_start
;
2296 time_begin
= ltt_time_sub(current_time
,half_width
);
2298 new_time_window
.start_time
= time_begin
;
2299 new_time_window
.time_width
= width
;
2300 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2301 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2303 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2305 else if(ltt_time_compare(current_time
, time_end
) > 0)
2307 TimeWindow new_time_window
;
2309 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
2310 time_begin
= ltt_time_sub(trace_end
,width
);
2312 time_begin
= ltt_time_sub(current_time
,half_width
);
2314 new_time_window
.start_time
= time_begin
;
2315 new_time_window
.time_width
= width
;
2316 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2317 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2319 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2322 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2324 /* Update directly when scrolling */
2325 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2331 typedef struct _ClosureData
{
2332 EventsRequest
*events_request
;
2333 LttvTracesetState
*tss
;
2339 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
2341 ProcessInfo
*process_info
= (ProcessInfo
*)key
;
2342 HashedProcessData
*hashed_process_data
= (HashedProcessData
*)value
;
2343 ClosureData
*closure_data
= (ClosureData
*)user_data
;
2345 EventsRequest
*events_request
= closure_data
->events_request
;
2346 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2348 LttvTracesetState
*tss
= closure_data
->tss
;
2349 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)tss
;
2351 LttTime evtime
= closure_data
->end_time
;
2353 gboolean dodraw
= TRUE
;
2356 /* For the process */
2357 /* First, check if the current process is in the state computation
2358 * process list. If it is there, that means we must add it right now and
2359 * draw items from the beginning of the read for it. If it is not
2360 * present, it's a new process and it was not present : it will
2361 * be added after the state update. */
2363 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
2364 #endif //EXTRA_CHECK
2365 LttvTraceContext
*tc
= tsc
->traces
[process_info
->trace_num
];
2366 LttvTraceState
*ts
= (LttvTraceState
*)tc
;
2369 //FIXME : optimize data structures.
2370 LttvTracefileState
*tfs
;
2371 LttvTracefileContext
*tfc
;
2373 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
2374 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
2375 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
2376 && tfs
->cpu
== process_info
->cpu
)
2380 g_assert(i
<tc
->tracefiles
->len
);
2381 tfs
= LTTV_TRACEFILE_STATE(tfc
);
2383 // LttvTracefileState *tfs =
2384 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2385 // tracefiles[process_info->cpu];
2387 LttvProcessState
*process
;
2388 process
= lttv_state_find_process(ts
, process_info
->cpu
,
2391 if(unlikely(process
!= NULL
)) {
2393 LttvFilter
*filter
= control_flow_data
->filter
;
2394 if(filter
!= NULL
&& filter
->head
!= NULL
)
2395 if(!lttv_filter_tree_parse(filter
->head
,NULL
,NULL
,
2396 tc
->t
,NULL
,process
,tc
))
2399 /* Only draw for processes that are currently in the trace states */
2401 ProcessList
*process_list
= control_flow_data
->process_list
;
2403 /* Should be alike when background info is ready */
2404 if(control_flow_data
->background_info_waiting
==0)
2405 g_assert(ltt_time_compare(process
->creation_time
,
2406 process_info
->birth
) == 0);
2407 #endif //EXTRA_CHECK
2409 /* Now, the process is in the state hash and our own process hash.
2410 * We definitely can draw the items related to the ending state.
2413 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2416 TimeWindow time_window
=
2417 lttvwindow_get_time_window(control_flow_data
->tab
);
2420 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2421 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2423 #endif //EXTRA_CHECK
2424 Drawing_t
*drawing
= control_flow_data
->drawing
;
2425 guint width
= drawing
->width
;
2427 guint x
= closure_data
->x_end
;
2429 DrawContext draw_context
;
2431 /* Now create the drawing context that will be used to draw
2432 * items related to the last state. */
2433 draw_context
.drawable
= hashed_process_data
->pixmap
;
2434 draw_context
.gc
= drawing
->gc
;
2435 draw_context
.pango_layout
= drawing
->pango_layout
;
2436 draw_context
.drawinfo
.end
.x
= x
;
2438 draw_context
.drawinfo
.y
.over
= 1;
2439 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2440 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2442 draw_context
.drawinfo
.start
.offset
.over
= 0;
2443 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2444 draw_context
.drawinfo
.start
.offset
.under
= 0;
2445 draw_context
.drawinfo
.end
.offset
.over
= 0;
2446 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2447 draw_context
.drawinfo
.end
.offset
.under
= 0;
2449 /* Jump over draw if we are at the same x position */
2450 if(x
== hashed_process_data
->x
.over
)
2454 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2456 PropertiesLine prop_line
= prepare_execmode_line(process
);
2457 draw_line((void*)&prop_line
, (void*)&draw_context
);
2459 hashed_process_data
->x
.over
= x
;
2463 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2464 hashed_process_data
->x
.middle_used
)) {
2465 #if 0 /* do not mark closure : not missing information */
2466 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2467 /* Draw collision indicator */
2468 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2469 gdk_draw_point(drawing
->pixmap
,
2473 hashed_process_data
->x
.middle_marked
= TRUE
;
2478 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2481 PropertiesLine prop_line
= prepare_s_e_line(process
);
2482 draw_line((void*)&prop_line
, (void*)&draw_context
);
2485 /* become the last x position */
2486 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2487 hashed_process_data
->x
.middle
= x
;
2488 /* but don't use the pixel */
2489 hashed_process_data
->x
.middle_used
= FALSE
;
2491 /* Calculate the next good time */
2492 convert_pixels_to_time(width
, x
+1, time_window
,
2493 &hashed_process_data
->next_good_time
);
2502 int before_chunk(void *hook_data
, void *call_data
)
2504 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2505 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2506 ControlFlowData
*cfd
= (ControlFlowData
*)events_request
->viewer_data
;
2508 /* Desactivate sort */
2509 gtk_tree_sortable_set_sort_column_id(
2510 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2512 GTK_SORT_ASCENDING
);
2514 drawing_chunk_begin(events_request
, tss
);
2519 int before_request(void *hook_data
, void *call_data
)
2521 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2522 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2524 drawing_data_request_begin(events_request
, tss
);
2531 * after request is necessary in addition of after chunk in order to draw
2532 * lines until the end of the screen. after chunk just draws lines until
2539 int after_request(void *hook_data
, void *call_data
)
2541 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2542 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2543 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2545 ProcessList
*process_list
= control_flow_data
->process_list
;
2546 LttTime end_time
= events_request
->end_time
;
2548 ClosureData closure_data
;
2549 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2550 closure_data
.tss
= tss
;
2551 closure_data
.end_time
= end_time
;
2553 TimeWindow time_window
=
2554 lttvwindow_get_time_window(control_flow_data
->tab
);
2555 guint width
= control_flow_data
->drawing
->width
;
2556 convert_time_to_pixels(
2560 &closure_data
.x_end
);
2563 /* Draw last items */
2564 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2565 (void*)&closure_data
);
2568 /* Request expose */
2569 drawing_request_expose(events_request
, tss
, end_time
);
2578 int after_chunk(void *hook_data
, void *call_data
)
2580 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2581 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2582 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2583 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)call_data
;
2584 LttvTracefileContext
*tfc
= lttv_traceset_context_get_current_tfc(tsc
);
2587 ProcessList
*process_list
= control_flow_data
->process_list
;
2589 LttvTraceset
*traceset
= tsc
->ts
;
2590 guint nb_trace
= lttv_traceset_number(traceset
);
2592 /* Only execute when called for the first trace's events request */
2593 if(!process_list
->current_hash_data
)
2596 for(i
= 0 ; i
< nb_trace
; i
++) {
2597 g_free(process_list
->current_hash_data
[i
]);
2599 g_free(process_list
->current_hash_data
);
2600 process_list
->current_hash_data
= NULL
;
2603 end_time
= LTT_TIME_MIN(tfc
->timestamp
, events_request
->end_time
);
2604 else /* end of traceset, or position now out of request : end */
2605 end_time
= events_request
->end_time
;
2607 ClosureData closure_data
;
2608 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2609 closure_data
.tss
= tss
;
2610 closure_data
.end_time
= end_time
;
2612 TimeWindow time_window
=
2613 lttvwindow_get_time_window(control_flow_data
->tab
);
2614 guint width
= control_flow_data
->drawing
->width
;
2615 convert_time_to_pixels(
2619 &closure_data
.x_end
);
2621 /* Draw last items */
2622 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2623 (void*)&closure_data
);
2625 /* Reactivate sort */
2626 gtk_tree_sortable_set_sort_column_id(
2627 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2628 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2629 GTK_SORT_ASCENDING
);
2631 update_index_to_pixmap(control_flow_data
->process_list
);
2632 /* Request a full expose : drawing scrambled */
2633 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2635 /* Request expose (updates damages zone also) */
2636 drawing_request_expose(events_request
, tss
, end_time
);
2641 /* after_statedump_end
2643 * @param hook_data ControlFlowData structure of the viewer.
2644 * @param call_data Event context.
2646 * This function adds items to be drawn in a queue for each process.
2649 int before_statedump_end(void *hook_data
, void *call_data
)
2651 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2652 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
2653 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2655 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2657 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
2659 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
2661 LttvTracesetState
*tss
= (LttvTracesetState
*)tfc
->t_context
->ts_context
;
2662 ProcessList
*process_list
= control_flow_data
->process_list
;
2665 e
= ltt_tracefile_get_event(tfc
->tf
);
2667 LttvFilter
*filter
= control_flow_data
->filter
;
2668 if(filter
!= NULL
&& filter
->head
!= NULL
)
2669 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2670 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2673 LttTime evtime
= ltt_event_time(e
);
2675 ClosureData closure_data
;
2676 closure_data
.events_request
= events_request
;
2677 closure_data
.tss
= tss
;
2678 closure_data
.end_time
= evtime
;
2680 TimeWindow time_window
=
2681 lttvwindow_get_time_window(control_flow_data
->tab
);
2682 guint width
= control_flow_data
->drawing
->width
;
2683 convert_time_to_pixels(
2687 &closure_data
.x_end
);
2689 /* Draw last items */
2690 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2691 (void*)&closure_data
);
2693 /* Reactivate sort */
2694 gtk_tree_sortable_set_sort_column_id(
2695 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2696 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2697 GTK_SORT_ASCENDING
);
2699 update_index_to_pixmap(control_flow_data
->process_list
);
2700 /* Request a full expose : drawing scrambled */
2701 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2703 /* Request expose (updates damages zone also) */
2704 drawing_request_expose(events_request
, tss
, evtime
);