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 void legend_destructor(GtkWindow
*legend
)
222 g_legend_list
= g_slist_remove(g_legend_list
, legend
);
225 /* Create a popup legend */
227 h_legend(LttvPlugin
*plugin
)
229 LttvPluginTab
*ptab
= LTTV_PLUGIN_TAB(plugin
);
230 Tab
*tab
= ptab
->tab
;
231 g_info("h_legend, %p", tab
);
233 GtkWindow
*legend
= GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL
));
235 g_legend_list
= g_slist_append(
239 g_object_set_data_full(
243 (GDestroyNotify
)legend_destructor
);
245 gtk_window_set_title(legend
, "Control Flow View Legend");
247 GtkWidget
*pixmap
= create_pixmap(GTK_WIDGET(legend
), "lttv-color-list.png");
249 // GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixmap(
250 // GDK_PIXMAP(pixmap), NULL));
252 gtk_container_add(GTK_CONTAINER(legend
), GTK_WIDGET(pixmap
));
254 gtk_widget_show(GTK_WIDGET(pixmap
));
255 gtk_widget_show(GTK_WIDGET(legend
));
258 return NULL
; /* This is a popup window */
262 int event_selected_hook(void *hook_data
, void *call_data
)
264 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
265 guint
*event_number
= (guint
*) call_data
;
267 g_debug("DEBUG : event selected by main window : %u", *event_number
);
272 /* Function that selects the color of status&exemode line */
273 static inline PropertiesLine
prepare_s_e_line(LttvProcessState
*process
)
275 PropertiesLine prop_line
;
276 prop_line
.line_width
= STATE_LINE_WIDTH
;
277 prop_line
.style
= GDK_LINE_SOLID
;
278 prop_line
.y
= MIDDLE
;
279 //GdkColormap *colormap = gdk_colormap_get_system();
281 if(process
->state
->s
== LTTV_STATE_RUN
) {
282 if(process
->state
->t
== LTTV_STATE_USER_MODE
)
283 prop_line
.color
= drawing_colors
[COL_RUN_USER_MODE
];
284 else if(process
->state
->t
== LTTV_STATE_SYSCALL
)
285 prop_line
.color
= drawing_colors
[COL_RUN_SYSCALL
];
286 else if(process
->state
->t
== LTTV_STATE_TRAP
)
287 prop_line
.color
= drawing_colors
[COL_RUN_TRAP
];
288 else if(process
->state
->t
== LTTV_STATE_IRQ
)
289 prop_line
.color
= drawing_colors
[COL_RUN_IRQ
];
290 else if(process
->state
->t
== LTTV_STATE_SOFT_IRQ
)
291 prop_line
.color
= drawing_colors
[COL_RUN_SOFT_IRQ
];
292 else if(process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
)
293 prop_line
.color
= drawing_colors
[COL_MODE_UNKNOWN
];
295 g_assert(FALSE
); /* RUNNING MODE UNKNOWN */
296 } else if(process
->state
->s
== LTTV_STATE_WAIT
) {
297 /* We don't show if we wait while in user mode, trap, irq or syscall */
298 prop_line
.color
= drawing_colors
[COL_WAIT
];
299 } else if(process
->state
->s
== LTTV_STATE_WAIT_CPU
) {
300 /* We don't show if we wait for CPU while in user mode, trap, irq
302 prop_line
.color
= drawing_colors
[COL_WAIT_CPU
];
303 } else if(process
->state
->s
== LTTV_STATE_ZOMBIE
) {
304 prop_line
.color
= drawing_colors
[COL_ZOMBIE
];
305 } else if(process
->state
->s
== LTTV_STATE_WAIT_FORK
) {
306 prop_line
.color
= drawing_colors
[COL_WAIT_FORK
];
307 } else if(process
->state
->s
== LTTV_STATE_EXIT
) {
308 prop_line
.color
= drawing_colors
[COL_EXIT
];
309 } else if(process
->state
->s
== LTTV_STATE_UNNAMED
) {
310 prop_line
.color
= drawing_colors
[COL_UNNAMED
];
312 g_critical("unknown state : %s", g_quark_to_string(process
->state
->s
));
313 g_assert(FALSE
); /* UNKNOWN STATE */
321 /* before_schedchange_hook
323 * This function basically draw lines and icons. Two types of lines are drawn :
324 * one small (3 pixels?) representing the state of the process and the second
325 * type is thicker (10 pixels?) representing on which CPU a process is running
326 * (and this only in running state).
328 * Extremums of the lines :
329 * x_min : time of the last event context for this process kept in memory.
330 * x_max : time of the current event.
331 * y : middle of the process in the process list. The process is found in the
332 * list, therefore is it's position in pixels.
334 * The choice of lines'color is defined by the context of the last event for this
339 int before_schedchange_hook(void *hook_data
, void *call_data
)
341 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
342 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
343 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
345 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
347 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
348 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
351 e
= ltt_tracefile_get_event(tfc
->tf
);
352 gint target_pid_saved
= tfc
->target_pid
;
354 LttTime evtime
= ltt_event_time(e
);
355 LttvFilter
*filter
= control_flow_data
->filter
;
357 /* we are in a schedchange, before the state update. We must draw the
358 * items corresponding to the state before it changes : now is the right
365 pid_out
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
366 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
369 tfc
->target_pid
= pid_out
;
370 if(!filter
|| !filter
->head
||
371 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
372 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
373 /* For the pid_out */
374 /* First, check if the current process is in the state computation
375 * process list. If it is there, that means we must add it right now and
376 * draw items from the beginning of the read for it. If it is not
377 * present, it's a new process and it was not present : it will
378 * be added after the state update. */
379 guint cpu
= tfs
->cpu
;
380 guint trace_num
= ts
->parent
.index
;
381 LttvProcessState
*process
= ts
->running_process
[cpu
];
382 /* unknown state, bad current pid */
383 if(process
->pid
!= pid_out
)
384 process
= lttv_state_find_process(ts
,
387 if(process
!= NULL
) {
388 /* Well, the process_out existed : we must get it in the process hash
389 * or add it, and draw its items.
391 /* Add process to process list (if not present) */
393 HashedProcessData
*hashed_process_data
= NULL
;
394 ProcessList
*process_list
= control_flow_data
->process_list
;
395 LttTime birth
= process
->creation_time
;
397 hashed_process_data
= processlist_get_process_data(process_list
,
402 if(hashed_process_data
== NULL
)
404 g_assert(pid_out
== 0 || pid_out
!= process
->ppid
);
405 /* Process not present */
406 ProcessInfo
*process_info
;
407 Drawing_t
*drawing
= control_flow_data
->drawing
;
408 processlist_add(process_list
,
420 &hashed_process_data
);
421 gtk_widget_set_size_request(drawing
->drawing_area
,
424 gtk_widget_queue_draw(drawing
->drawing_area
);
428 /* Now, the process is in the state hash and our own process hash.
429 * We definitely can draw the items related to the ending state.
432 if(ltt_time_compare(hashed_process_data
->next_good_time
,
435 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
437 TimeWindow time_window
=
438 lttvwindow_get_time_window(control_flow_data
->tab
);
440 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
441 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
444 Drawing_t
*drawing
= control_flow_data
->drawing
;
445 guint width
= drawing
->width
;
447 convert_time_to_pixels(
453 /* Draw collision indicator */
454 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
455 gdk_draw_point(hashed_process_data
->pixmap
,
458 COLLISION_POSITION(hashed_process_data
->height
));
459 hashed_process_data
->x
.middle_marked
= TRUE
;
462 TimeWindow time_window
=
463 lttvwindow_get_time_window(control_flow_data
->tab
);
465 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
466 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
469 Drawing_t
*drawing
= control_flow_data
->drawing
;
470 guint width
= drawing
->width
;
472 convert_time_to_pixels(
479 /* Jump over draw if we are at the same x position */
480 if(x
== hashed_process_data
->x
.middle
&&
481 hashed_process_data
->x
.middle_used
)
483 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
484 /* Draw collision indicator */
485 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
486 gdk_draw_point(hashed_process_data
->pixmap
,
489 COLLISION_POSITION(hashed_process_data
->height
));
490 hashed_process_data
->x
.middle_marked
= TRUE
;
494 DrawContext draw_context
;
496 /* Now create the drawing context that will be used to draw
497 * items related to the last state. */
498 draw_context
.drawable
= hashed_process_data
->pixmap
;
499 draw_context
.gc
= drawing
->gc
;
500 draw_context
.pango_layout
= drawing
->pango_layout
;
501 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
502 draw_context
.drawinfo
.end
.x
= x
;
504 draw_context
.drawinfo
.y
.over
= 1;
505 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
506 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
508 draw_context
.drawinfo
.start
.offset
.over
= 0;
509 draw_context
.drawinfo
.start
.offset
.middle
= 0;
510 draw_context
.drawinfo
.start
.offset
.under
= 0;
511 draw_context
.drawinfo
.end
.offset
.over
= 0;
512 draw_context
.drawinfo
.end
.offset
.middle
= 0;
513 draw_context
.drawinfo
.end
.offset
.under
= 0;
517 PropertiesLine prop_line
= prepare_s_e_line(process
);
518 draw_line((void*)&prop_line
, (void*)&draw_context
);
521 /* become the last x position */
522 hashed_process_data
->x
.middle
= x
;
523 hashed_process_data
->x
.middle_used
= TRUE
;
524 hashed_process_data
->x
.middle_marked
= FALSE
;
526 /* Calculate the next good time */
527 convert_pixels_to_time(width
, x
+1, time_window
,
528 &hashed_process_data
->next_good_time
);
534 tfc
->target_pid
= pid_in
;
535 if(!filter
|| !filter
->head
||
536 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
537 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
539 /* First, check if the current process is in the state computation
540 * process list. If it is there, that means we must add it right now and
541 * draw items from the beginning of the read for it. If it is not
542 * present, it's a new process and it was not present : it will
543 * be added after the state update. */
544 LttvProcessState
*process
;
545 process
= lttv_state_find_process(ts
,
547 guint trace_num
= ts
->parent
.index
;
549 if(process
!= NULL
) {
550 /* Well, the process existed : we must get it in the process hash
551 * or add it, and draw its items.
553 /* Add process to process list (if not present) */
555 HashedProcessData
*hashed_process_data
= NULL
;
556 ProcessList
*process_list
= control_flow_data
->process_list
;
557 LttTime birth
= process
->creation_time
;
559 hashed_process_data
= processlist_get_process_data(process_list
,
564 if(hashed_process_data
== NULL
)
566 g_assert(pid_in
== 0 || pid_in
!= process
->ppid
);
567 /* Process not present */
568 ProcessInfo
*process_info
;
569 Drawing_t
*drawing
= control_flow_data
->drawing
;
570 processlist_add(process_list
,
582 &hashed_process_data
);
583 gtk_widget_set_size_request(drawing
->drawing_area
,
586 gtk_widget_queue_draw(drawing
->drawing_area
);
589 //We could set the current process and hash here, but will be done
590 //by after schedchange hook
592 /* Now, the process is in the state hash and our own process hash.
593 * We definitely can draw the items related to the ending state.
596 if(ltt_time_compare(hashed_process_data
->next_good_time
,
599 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
601 TimeWindow time_window
=
602 lttvwindow_get_time_window(control_flow_data
->tab
);
604 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
605 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
608 Drawing_t
*drawing
= control_flow_data
->drawing
;
609 guint width
= drawing
->width
;
611 convert_time_to_pixels(
617 /* Draw collision indicator */
618 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
619 gdk_draw_point(hashed_process_data
->pixmap
,
622 COLLISION_POSITION(hashed_process_data
->height
));
623 hashed_process_data
->x
.middle_marked
= TRUE
;
626 TimeWindow time_window
=
627 lttvwindow_get_time_window(control_flow_data
->tab
);
629 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
630 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
633 Drawing_t
*drawing
= control_flow_data
->drawing
;
634 guint width
= drawing
->width
;
637 convert_time_to_pixels(
644 /* Jump over draw if we are at the same x position */
645 if(x
== hashed_process_data
->x
.middle
&&
646 hashed_process_data
->x
.middle_used
)
648 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
649 /* Draw collision indicator */
650 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
651 gdk_draw_point(hashed_process_data
->pixmap
,
654 COLLISION_POSITION(hashed_process_data
->height
));
655 hashed_process_data
->x
.middle_marked
= TRUE
;
659 DrawContext draw_context
;
661 /* Now create the drawing context that will be used to draw
662 * items related to the last state. */
663 draw_context
.drawable
= hashed_process_data
->pixmap
;
664 draw_context
.gc
= drawing
->gc
;
665 draw_context
.pango_layout
= drawing
->pango_layout
;
666 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
667 draw_context
.drawinfo
.end
.x
= x
;
669 draw_context
.drawinfo
.y
.over
= 1;
670 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
671 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
673 draw_context
.drawinfo
.start
.offset
.over
= 0;
674 draw_context
.drawinfo
.start
.offset
.middle
= 0;
675 draw_context
.drawinfo
.start
.offset
.under
= 0;
676 draw_context
.drawinfo
.end
.offset
.over
= 0;
677 draw_context
.drawinfo
.end
.offset
.middle
= 0;
678 draw_context
.drawinfo
.end
.offset
.under
= 0;
682 PropertiesLine prop_line
= prepare_s_e_line(process
);
683 draw_line((void*)&prop_line
, (void*)&draw_context
);
687 /* become the last x position */
688 hashed_process_data
->x
.middle
= x
;
689 hashed_process_data
->x
.middle_used
= TRUE
;
690 hashed_process_data
->x
.middle_marked
= FALSE
;
692 /* Calculate the next good time */
693 convert_pixels_to_time(width
, x
+1, time_window
,
694 &hashed_process_data
->next_good_time
);
698 g_warning("Cannot find pin_in in schedchange %u", pid_in
);
700 tfc
->target_pid
= target_pid_saved
;
708 GString
*string
= g_string_new("");;
709 gboolean field_names
= TRUE
, state
= TRUE
;
711 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
712 g_string_append_printf(string
,"\n");
715 g_string_append_printf(string
, " %s",
716 g_quark_to_string(tfs
->process
->state
->s
));
719 g_info("%s",string
->str
);
721 g_string_free(string
, TRUE
);
723 /* End of text dump */
728 /* after_schedchange_hook
730 * The draw after hook is called by the reading API to have a
731 * particular event drawn on the screen.
732 * @param hook_data ControlFlowData structure of the viewer.
733 * @param call_data Event context.
735 * This function adds items to be drawn in a queue for each process.
738 int after_schedchange_hook(void *hook_data
, void *call_data
)
740 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
741 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
742 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
744 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
746 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
748 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
751 e
= ltt_tracefile_get_event(tfc
->tf
);
753 LttvFilter
*filter
= control_flow_data
->filter
;
754 if(filter
!= NULL
&& filter
->head
!= NULL
)
755 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
756 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
759 LttTime evtime
= ltt_event_time(e
);
761 /* Add process to process list (if not present) */
762 LttvProcessState
*process_in
;
765 HashedProcessData
*hashed_process_data_in
= NULL
;
767 ProcessList
*process_list
= control_flow_data
->process_list
;
772 pid_out
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
773 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
777 /* Find process pid_in in the list... */
778 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
779 //process_in = tfs->process;
780 guint cpu
= tfs
->cpu
;
781 guint trace_num
= ts
->parent
.index
;
782 process_in
= ts
->running_process
[cpu
];
783 /* It should exist, because we are after the state update. */
785 g_assert(process_in
!= NULL
);
787 birth
= process_in
->creation_time
;
789 hashed_process_data_in
= processlist_get_process_data(process_list
,
794 if(hashed_process_data_in
== NULL
)
796 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
797 ProcessInfo
*process_info
;
798 Drawing_t
*drawing
= control_flow_data
->drawing
;
799 /* Process not present */
800 processlist_add(process_list
,
812 &hashed_process_data_in
);
813 gtk_widget_set_size_request(drawing
->drawing_area
,
816 gtk_widget_queue_draw(drawing
->drawing_area
);
818 /* Set the current process */
819 process_list
->current_hash_data
[trace_num
][process_in
->cpu
] =
820 hashed_process_data_in
;
822 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
825 TimeWindow time_window
=
826 lttvwindow_get_time_window(control_flow_data
->tab
);
829 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
830 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
833 Drawing_t
*drawing
= control_flow_data
->drawing
;
834 guint width
= drawing
->width
;
837 convert_time_to_pixels(
843 if(hashed_process_data_in
->x
.middle
!= new_x
) {
844 hashed_process_data_in
->x
.middle
= new_x
;
845 hashed_process_data_in
->x
.middle_used
= FALSE
;
846 hashed_process_data_in
->x
.middle_marked
= FALSE
;
855 /* before_execmode_hook
857 * This function basically draw lines and icons. Two types of lines are drawn :
858 * one small (3 pixels?) representing the state of the process and the second
859 * type is thicker (10 pixels?) representing on which CPU a process is running
860 * (and this only in running state).
862 * Extremums of the lines :
863 * x_min : time of the last event context for this process kept in memory.
864 * x_max : time of the current event.
865 * y : middle of the process in the process list. The process is found in the
866 * list, therefore is it's position in pixels.
868 * The choice of lines'color is defined by the context of the last event for this
873 int before_execmode_hook(void *hook_data
, void *call_data
)
875 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
876 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
877 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
879 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
881 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
883 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
886 e
= ltt_tracefile_get_event(tfc
->tf
);
888 LttvFilter
*filter
= control_flow_data
->filter
;
889 if(filter
!= NULL
&& filter
->head
!= NULL
)
890 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
891 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
894 LttTime evtime
= ltt_event_time(e
);
896 /* we are in a execmode, before the state update. We must draw the
897 * items corresponding to the state before it changes : now is the right
901 //LttvProcessState *process = tfs->process;
902 guint cpu
= tfs
->cpu
;
903 guint trace_num
= ts
->parent
.index
;
904 LttvProcessState
*process
= ts
->running_process
[cpu
];
905 g_assert(process
!= NULL
);
907 guint pid
= process
->pid
;
909 /* Well, the process_out existed : we must get it in the process hash
910 * or add it, and draw its items.
912 /* Add process to process list (if not present) */
914 HashedProcessData
*hashed_process_data
= NULL
;
915 ProcessList
*process_list
= control_flow_data
->process_list
;
916 LttTime birth
= process
->creation_time
;
918 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
919 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
921 hashed_process_data
= processlist_get_process_data(process_list
,
926 if(unlikely(hashed_process_data
== NULL
))
928 g_assert(pid
== 0 || pid
!= process
->ppid
);
929 ProcessInfo
*process_info
;
930 /* Process not present */
931 Drawing_t
*drawing
= control_flow_data
->drawing
;
932 processlist_add(process_list
,
944 &hashed_process_data
);
945 gtk_widget_set_size_request(drawing
->drawing_area
,
948 gtk_widget_queue_draw(drawing
->drawing_area
);
950 /* Set the current process */
951 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
955 /* Now, the process is in the state hash and our own process hash.
956 * We definitely can draw the items related to the ending state.
959 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
962 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
963 TimeWindow time_window
=
964 lttvwindow_get_time_window(control_flow_data
->tab
);
967 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
968 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
971 Drawing_t
*drawing
= control_flow_data
->drawing
;
972 guint width
= drawing
->width
;
974 convert_time_to_pixels(
980 /* Draw collision indicator */
981 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
982 gdk_draw_point(hashed_process_data
->pixmap
,
985 COLLISION_POSITION(hashed_process_data
->height
));
986 hashed_process_data
->x
.middle_marked
= TRUE
;
989 TimeWindow time_window
=
990 lttvwindow_get_time_window(control_flow_data
->tab
);
993 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
994 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
997 Drawing_t
*drawing
= control_flow_data
->drawing
;
998 guint width
= drawing
->width
;
1001 convert_time_to_pixels(
1008 /* Jump over draw if we are at the same x position */
1009 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1010 hashed_process_data
->x
.middle_used
))
1012 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1013 /* Draw collision indicator */
1014 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1015 gdk_draw_point(hashed_process_data
->pixmap
,
1018 COLLISION_POSITION(hashed_process_data
->height
));
1019 hashed_process_data
->x
.middle_marked
= TRUE
;
1024 DrawContext draw_context
;
1025 /* Now create the drawing context that will be used to draw
1026 * items related to the last state. */
1027 draw_context
.drawable
= hashed_process_data
->pixmap
;
1028 draw_context
.gc
= drawing
->gc
;
1029 draw_context
.pango_layout
= drawing
->pango_layout
;
1030 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1031 draw_context
.drawinfo
.end
.x
= x
;
1033 draw_context
.drawinfo
.y
.over
= 1;
1034 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1035 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1037 draw_context
.drawinfo
.start
.offset
.over
= 0;
1038 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1039 draw_context
.drawinfo
.start
.offset
.under
= 0;
1040 draw_context
.drawinfo
.end
.offset
.over
= 0;
1041 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1042 draw_context
.drawinfo
.end
.offset
.under
= 0;
1046 PropertiesLine prop_line
= prepare_s_e_line(process
);
1047 draw_line((void*)&prop_line
, (void*)&draw_context
);
1050 /* become the last x position */
1051 hashed_process_data
->x
.middle
= x
;
1052 hashed_process_data
->x
.middle_used
= TRUE
;
1053 hashed_process_data
->x
.middle_marked
= FALSE
;
1055 /* Calculate the next good time */
1056 convert_pixels_to_time(width
, x
+1, time_window
,
1057 &hashed_process_data
->next_good_time
);
1064 /* before_process_exit_hook
1066 * Draw lines for process event.
1068 * @param hook_data ControlFlowData structure of the viewer.
1069 * @param call_data Event context.
1071 * This function adds items to be drawn in a queue for each process.
1076 int before_process_exit_hook(void *hook_data
, void *call_data
)
1078 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1079 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1081 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1083 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1085 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1087 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1090 e
= ltt_tracefile_get_event(tfc
->tf
);
1092 LttvFilter
*filter
= control_flow_data
->filter
;
1093 if(filter
!= NULL
&& filter
->head
!= NULL
)
1094 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1095 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1098 LttTime evtime
= ltt_event_time(e
);
1100 /* Add process to process list (if not present) */
1101 //LttvProcessState *process = tfs->process;
1102 guint cpu
= tfs
->cpu
;
1103 guint trace_num
= ts
->parent
.index
;
1104 LttvProcessState
*process
= ts
->running_process
[cpu
];
1105 guint pid
= process
->pid
;
1107 guint pl_height
= 0;
1108 HashedProcessData
*hashed_process_data
= NULL
;
1110 ProcessList
*process_list
= control_flow_data
->process_list
;
1112 g_assert(process
!= NULL
);
1114 birth
= process
->creation_time
;
1116 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1117 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1119 hashed_process_data
= processlist_get_process_data(process_list
,
1124 if(unlikely(hashed_process_data
== NULL
))
1126 g_assert(pid
== 0 || pid
!= process
->ppid
);
1127 /* Process not present */
1128 Drawing_t
*drawing
= control_flow_data
->drawing
;
1129 ProcessInfo
*process_info
;
1130 processlist_add(process_list
,
1142 &hashed_process_data
);
1143 gtk_widget_set_size_request(drawing
->drawing_area
,
1146 gtk_widget_queue_draw(drawing
->drawing_area
);
1150 /* Now, the process is in the state hash and our own process hash.
1151 * We definitely can draw the items related to the ending state.
1154 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1157 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1158 TimeWindow time_window
=
1159 lttvwindow_get_time_window(control_flow_data
->tab
);
1162 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1163 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1165 #endif //EXTRA_CHECK
1166 Drawing_t
*drawing
= control_flow_data
->drawing
;
1167 guint width
= drawing
->width
;
1169 convert_time_to_pixels(
1175 /* Draw collision indicator */
1176 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1177 gdk_draw_point(hashed_process_data
->pixmap
,
1180 COLLISION_POSITION(hashed_process_data
->height
));
1181 hashed_process_data
->x
.middle_marked
= TRUE
;
1184 TimeWindow time_window
=
1185 lttvwindow_get_time_window(control_flow_data
->tab
);
1188 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1189 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1191 #endif //EXTRA_CHECK
1192 Drawing_t
*drawing
= control_flow_data
->drawing
;
1193 guint width
= drawing
->width
;
1196 convert_time_to_pixels(
1203 /* Jump over draw if we are at the same x position */
1204 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1205 hashed_process_data
->x
.middle_used
))
1207 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1208 /* Draw collision indicator */
1209 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1210 gdk_draw_point(hashed_process_data
->pixmap
,
1213 COLLISION_POSITION(hashed_process_data
->height
));
1214 hashed_process_data
->x
.middle_marked
= TRUE
;
1218 DrawContext draw_context
;
1220 /* Now create the drawing context that will be used to draw
1221 * items related to the last state. */
1222 draw_context
.drawable
= hashed_process_data
->pixmap
;
1223 draw_context
.gc
= drawing
->gc
;
1224 draw_context
.pango_layout
= drawing
->pango_layout
;
1225 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1226 draw_context
.drawinfo
.end
.x
= x
;
1228 draw_context
.drawinfo
.y
.over
= 1;
1229 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1230 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1232 draw_context
.drawinfo
.start
.offset
.over
= 0;
1233 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1234 draw_context
.drawinfo
.start
.offset
.under
= 0;
1235 draw_context
.drawinfo
.end
.offset
.over
= 0;
1236 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1237 draw_context
.drawinfo
.end
.offset
.under
= 0;
1241 PropertiesLine prop_line
= prepare_s_e_line(process
);
1242 draw_line((void*)&prop_line
, (void*)&draw_context
);
1245 /* become the last x position */
1246 hashed_process_data
->x
.middle
= x
;
1247 hashed_process_data
->x
.middle_used
= TRUE
;
1248 hashed_process_data
->x
.middle_marked
= FALSE
;
1250 /* Calculate the next good time */
1251 convert_pixels_to_time(width
, x
+1, time_window
,
1252 &hashed_process_data
->next_good_time
);
1262 /* before_process_release_hook
1264 * Draw lines for process event.
1266 * @param hook_data ControlFlowData structure of the viewer.
1267 * @param call_data Event context.
1269 * This function adds items to be drawn in a queue for each process.
1274 int before_process_release_hook(void *hook_data
, void *call_data
)
1276 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1277 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1279 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1281 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1283 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1285 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1288 e
= ltt_tracefile_get_event(tfc
->tf
);
1290 LttvFilter
*filter
= control_flow_data
->filter
;
1291 if(filter
!= NULL
&& filter
->head
!= NULL
)
1292 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1293 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1296 LttTime evtime
= ltt_event_time(e
);
1298 guint trace_num
= ts
->parent
.index
;
1302 pid
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
1305 /* Add process to process list (if not present) */
1306 /* Don't care about the process if it's not in the state hash already :
1307 * that means a process that has never done anything in the trace and
1308 * unknown suddently gets destroyed : no state meaningful to show. */
1309 LttvProcessState
*process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1311 if(process
!= NULL
) {
1313 guint pl_height
= 0;
1314 HashedProcessData
*hashed_process_data
= NULL
;
1316 ProcessList
*process_list
= control_flow_data
->process_list
;
1318 birth
= process
->creation_time
;
1320 /* Cannot use current process : this event happens on another process,
1321 * action done by the parent. */
1322 hashed_process_data
= processlist_get_process_data(process_list
,
1327 if(unlikely(hashed_process_data
== NULL
))
1329 g_assert(pid
== 0 || pid
!= process
->ppid
);
1330 /* Process not present */
1331 Drawing_t
*drawing
= control_flow_data
->drawing
;
1332 ProcessInfo
*process_info
;
1333 processlist_add(process_list
,
1345 &hashed_process_data
);
1346 gtk_widget_set_size_request(drawing
->drawing_area
,
1349 gtk_widget_queue_draw(drawing
->drawing_area
);
1352 /* Now, the process is in the state hash and our own process hash.
1353 * We definitely can draw the items related to the ending state.
1356 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1359 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1360 TimeWindow time_window
=
1361 lttvwindow_get_time_window(control_flow_data
->tab
);
1364 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1365 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1367 #endif //EXTRA_CHECK
1368 Drawing_t
*drawing
= control_flow_data
->drawing
;
1369 guint width
= drawing
->width
;
1371 convert_time_to_pixels(
1377 /* Draw collision indicator */
1378 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1379 gdk_draw_point(hashed_process_data
->pixmap
,
1382 COLLISION_POSITION(hashed_process_data
->height
));
1383 hashed_process_data
->x
.middle_marked
= TRUE
;
1386 TimeWindow time_window
=
1387 lttvwindow_get_time_window(control_flow_data
->tab
);
1390 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1391 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1393 #endif //EXTRA_CHECK
1394 Drawing_t
*drawing
= control_flow_data
->drawing
;
1395 guint width
= drawing
->width
;
1398 convert_time_to_pixels(
1405 /* Jump over draw if we are at the same x position */
1406 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1407 hashed_process_data
->x
.middle_used
))
1409 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1410 /* Draw collision indicator */
1411 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1412 gdk_draw_point(hashed_process_data
->pixmap
,
1415 COLLISION_POSITION(hashed_process_data
->height
));
1416 hashed_process_data
->x
.middle_marked
= TRUE
;
1420 DrawContext draw_context
;
1422 /* Now create the drawing context that will be used to draw
1423 * items related to the last state. */
1424 draw_context
.drawable
= hashed_process_data
->pixmap
;
1425 draw_context
.gc
= drawing
->gc
;
1426 draw_context
.pango_layout
= drawing
->pango_layout
;
1427 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1428 draw_context
.drawinfo
.end
.x
= x
;
1430 draw_context
.drawinfo
.y
.over
= 1;
1431 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1432 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1434 draw_context
.drawinfo
.start
.offset
.over
= 0;
1435 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1436 draw_context
.drawinfo
.start
.offset
.under
= 0;
1437 draw_context
.drawinfo
.end
.offset
.over
= 0;
1438 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1439 draw_context
.drawinfo
.end
.offset
.under
= 0;
1443 PropertiesLine prop_line
= prepare_s_e_line(process
);
1444 draw_line((void*)&prop_line
, (void*)&draw_context
);
1447 /* become the last x position */
1448 hashed_process_data
->x
.middle
= x
;
1449 hashed_process_data
->x
.middle_used
= TRUE
;
1450 hashed_process_data
->x
.middle_marked
= FALSE
;
1452 /* Calculate the next good time */
1453 convert_pixels_to_time(width
, x
+1, time_window
,
1454 &hashed_process_data
->next_good_time
);
1466 /* after_process_fork_hook
1468 * Create the processlist entry for the child process. Put the last
1469 * position in x at the current time value.
1471 * @param hook_data ControlFlowData structure of the viewer.
1472 * @param call_data Event context.
1474 * This function adds items to be drawn in a queue for each process.
1477 int after_process_fork_hook(void *hook_data
, void *call_data
)
1479 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1480 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1481 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1483 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1485 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1487 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1490 e
= ltt_tracefile_get_event(tfc
->tf
);
1492 LttvFilter
*filter
= control_flow_data
->filter
;
1493 if(filter
!= NULL
&& filter
->head
!= NULL
)
1494 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1495 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1498 LttTime evtime
= ltt_event_time(e
);
1502 child_pid
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
1505 /* Add process to process list (if not present) */
1506 LttvProcessState
*process_child
;
1508 guint pl_height
= 0;
1509 HashedProcessData
*hashed_process_data_child
= NULL
;
1511 ProcessList
*process_list
= control_flow_data
->process_list
;
1513 /* Find child in the list... */
1514 process_child
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1515 /* It should exist, because we are after the state update. */
1516 g_assert(process_child
!= NULL
);
1518 birth
= process_child
->creation_time
;
1519 guint trace_num
= ts
->parent
.index
;
1521 /* Cannot use current process, because this action is done by the parent
1523 hashed_process_data_child
= processlist_get_process_data(process_list
,
1528 if(likely(hashed_process_data_child
== NULL
))
1530 g_assert(child_pid
== 0 || child_pid
!= process_child
->ppid
);
1531 /* Process not present */
1532 Drawing_t
*drawing
= control_flow_data
->drawing
;
1533 ProcessInfo
*process_info
;
1534 processlist_add(process_list
,
1537 process_child
->tgid
,
1539 process_child
->ppid
,
1542 process_child
->name
,
1543 process_child
->brand
,
1546 &hashed_process_data_child
);
1547 gtk_widget_set_size_request(drawing
->drawing_area
,
1550 gtk_widget_queue_draw(drawing
->drawing_area
);
1552 processlist_set_ppid(process_list
, process_child
->ppid
,
1553 hashed_process_data_child
);
1554 processlist_set_tgid(process_list
, process_child
->tgid
,
1555 hashed_process_data_child
);
1559 if(likely(ltt_time_compare(hashed_process_data_child
->next_good_time
,
1562 TimeWindow time_window
=
1563 lttvwindow_get_time_window(control_flow_data
->tab
);
1566 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1567 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1569 #endif //EXTRA_CHECK
1570 Drawing_t
*drawing
= control_flow_data
->drawing
;
1571 guint width
= drawing
->width
;
1573 convert_time_to_pixels(
1579 if(likely(hashed_process_data_child
->x
.over
!= new_x
)) {
1580 hashed_process_data_child
->x
.over
= new_x
;
1581 hashed_process_data_child
->x
.over_used
= FALSE
;
1582 hashed_process_data_child
->x
.over_marked
= FALSE
;
1584 if(likely(hashed_process_data_child
->x
.middle
!= new_x
)) {
1585 hashed_process_data_child
->x
.middle
= new_x
;
1586 hashed_process_data_child
->x
.middle_used
= FALSE
;
1587 hashed_process_data_child
->x
.middle_marked
= FALSE
;
1589 if(likely(hashed_process_data_child
->x
.under
!= new_x
)) {
1590 hashed_process_data_child
->x
.under
= new_x
;
1591 hashed_process_data_child
->x
.under_used
= FALSE
;
1592 hashed_process_data_child
->x
.under_marked
= FALSE
;
1600 /* after_process_exit_hook
1602 * Create the processlist entry for the child process. Put the last
1603 * position in x at the current time value.
1605 * @param hook_data ControlFlowData structure of the viewer.
1606 * @param call_data Event context.
1608 * This function adds items to be drawn in a queue for each process.
1611 int after_process_exit_hook(void *hook_data
, void *call_data
)
1613 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1614 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1615 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1617 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1619 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1621 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1624 e
= ltt_tracefile_get_event(tfc
->tf
);
1626 LttvFilter
*filter
= control_flow_data
->filter
;
1627 if(filter
!= NULL
&& filter
->head
!= NULL
)
1628 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1629 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1632 LttTime evtime
= ltt_event_time(e
);
1634 /* Add process to process list (if not present) */
1635 //LttvProcessState *process = tfs->process;
1636 guint cpu
= tfs
->cpu
;
1637 guint trace_num
= ts
->parent
.index
;
1638 LttvProcessState
*process
= ts
->running_process
[cpu
];
1640 /* It should exist, because we are after the state update. */
1641 g_assert(process
!= NULL
);
1643 guint pid
= process
->pid
;
1645 guint pl_height
= 0;
1646 HashedProcessData
*hashed_process_data
= NULL
;
1648 ProcessList
*process_list
= control_flow_data
->process_list
;
1650 birth
= process
->creation_time
;
1652 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
) ){
1653 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1655 hashed_process_data
= processlist_get_process_data(process_list
,
1660 if(unlikely(hashed_process_data
== NULL
))
1662 g_assert(pid
== 0 || pid
!= process
->ppid
);
1663 /* Process not present */
1664 Drawing_t
*drawing
= control_flow_data
->drawing
;
1665 ProcessInfo
*process_info
;
1666 processlist_add(process_list
,
1678 &hashed_process_data
);
1679 gtk_widget_set_size_request(drawing
->drawing_area
,
1682 gtk_widget_queue_draw(drawing
->drawing_area
);
1685 /* Set the current process */
1686 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1687 hashed_process_data
;
1690 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
1693 TimeWindow time_window
=
1694 lttvwindow_get_time_window(control_flow_data
->tab
);
1697 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1698 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1700 #endif //EXTRA_CHECK
1701 Drawing_t
*drawing
= control_flow_data
->drawing
;
1702 guint width
= drawing
->width
;
1704 convert_time_to_pixels(
1709 if(unlikely(hashed_process_data
->x
.middle
!= new_x
)) {
1710 hashed_process_data
->x
.middle
= new_x
;
1711 hashed_process_data
->x
.middle_used
= FALSE
;
1712 hashed_process_data
->x
.middle_marked
= FALSE
;
1720 /* Get the filename of the process to print */
1721 int after_fs_exec_hook(void *hook_data
, void *call_data
)
1723 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1724 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1725 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1727 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1729 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1731 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1734 e
= ltt_tracefile_get_event(tfc
->tf
);
1736 LttvFilter
*filter
= control_flow_data
->filter
;
1737 if(filter
!= NULL
&& filter
->head
!= NULL
)
1738 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1739 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1742 guint cpu
= tfs
->cpu
;
1743 guint trace_num
= ts
->parent
.index
;
1744 LttvProcessState
*process
= ts
->running_process
[cpu
];
1745 g_assert(process
!= NULL
);
1747 guint pid
= process
->pid
;
1749 /* Well, the process_out existed : we must get it in the process hash
1750 * or add it, and draw its items.
1752 /* Add process to process list (if not present) */
1753 guint pl_height
= 0;
1754 HashedProcessData
*hashed_process_data
= NULL
;
1755 ProcessList
*process_list
= control_flow_data
->process_list
;
1756 LttTime birth
= process
->creation_time
;
1758 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1759 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1761 hashed_process_data
= processlist_get_process_data(process_list
,
1766 if(unlikely(hashed_process_data
== NULL
))
1768 g_assert(pid
== 0 || pid
!= process
->ppid
);
1769 ProcessInfo
*process_info
;
1770 /* Process not present */
1771 Drawing_t
*drawing
= control_flow_data
->drawing
;
1772 processlist_add(process_list
,
1784 &hashed_process_data
);
1785 gtk_widget_set_size_request(drawing
->drawing_area
,
1788 gtk_widget_queue_draw(drawing
->drawing_area
);
1790 /* Set the current process */
1791 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1792 hashed_process_data
;
1795 processlist_set_name(process_list
, process
->name
, hashed_process_data
);
1801 /* Get the filename of the process to print */
1802 int after_user_generic_thread_brand_hook(void *hook_data
, void *call_data
)
1804 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1805 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1806 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1808 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1810 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1812 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1815 e
= ltt_tracefile_get_event(tfc
->tf
);
1817 LttvFilter
*filter
= control_flow_data
->filter
;
1818 if(filter
!= NULL
&& filter
->head
!= NULL
)
1819 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1820 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1823 guint cpu
= tfs
->cpu
;
1824 guint trace_num
= ts
->parent
.index
;
1825 LttvProcessState
*process
= ts
->running_process
[cpu
];
1826 g_assert(process
!= NULL
);
1828 guint pid
= process
->pid
;
1830 /* Well, the process_out existed : we must get it in the process hash
1831 * or add it, and draw its items.
1833 /* Add process to process list (if not present) */
1834 guint pl_height
= 0;
1835 HashedProcessData
*hashed_process_data
= NULL
;
1836 ProcessList
*process_list
= control_flow_data
->process_list
;
1837 LttTime birth
= process
->creation_time
;
1839 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1840 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1842 hashed_process_data
= processlist_get_process_data(process_list
,
1847 if(unlikely(hashed_process_data
== NULL
))
1849 g_assert(pid
== 0 || pid
!= process
->ppid
);
1850 ProcessInfo
*process_info
;
1851 /* Process not present */
1852 Drawing_t
*drawing
= control_flow_data
->drawing
;
1853 processlist_add(process_list
,
1865 &hashed_process_data
);
1866 gtk_widget_set_size_request(drawing
->drawing_area
,
1869 gtk_widget_queue_draw(drawing
->drawing_area
);
1871 /* Set the current process */
1872 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1873 hashed_process_data
;
1876 processlist_set_brand(process_list
, process
->brand
, hashed_process_data
);
1883 /* after_event_enum_process_hook
1885 * Create the processlist entry for the child process. Put the last
1886 * position in x at the current time value.
1888 * @param hook_data ControlFlowData structure of the viewer.
1889 * @param call_data Event context.
1891 * This function adds items to be drawn in a queue for each process.
1894 int after_event_enum_process_hook(void *hook_data
, void *call_data
)
1896 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1897 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1898 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1900 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1902 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1904 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1906 guint first_cpu
, nb_cpus
, cpu
;
1909 e
= ltt_tracefile_get_event(tfc
->tf
);
1911 LttvFilter
*filter
= control_flow_data
->filter
;
1912 if(filter
!= NULL
&& filter
->head
!= NULL
)
1913 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1914 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1917 LttTime evtime
= ltt_event_time(e
);
1919 /* Add process to process list (if not present) */
1920 LttvProcessState
*process_in
;
1922 guint pl_height
= 0;
1923 HashedProcessData
*hashed_process_data_in
= NULL
;
1925 ProcessList
*process_list
= control_flow_data
->process_list
;
1926 guint trace_num
= ts
->parent
.index
;
1930 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
1935 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1937 first_cpu
= ANY_CPU
;
1938 nb_cpus
= ANY_CPU
+1;
1941 for(cpu
= first_cpu
; cpu
< nb_cpus
; cpu
++) {
1942 /* Find process pid_in in the list... */
1943 process_in
= lttv_state_find_process(ts
, cpu
, pid_in
);
1944 //process_in = tfs->process;
1945 //guint cpu = tfs->cpu;
1946 //guint trace_num = ts->parent.index;
1947 //process_in = ts->running_process[cpu];
1948 /* It should exist, because we are after the state update. */
1950 //g_assert(process_in != NULL);
1951 #endif //EXTRA_CHECK
1952 birth
= process_in
->creation_time
;
1954 hashed_process_data_in
= processlist_get_process_data(process_list
,
1959 if(hashed_process_data_in
== NULL
)
1961 if(pid_in
!= 0 && pid_in
== process_in
->ppid
)
1962 g_critical("TEST %u , %u", pid_in
, process_in
->ppid
);
1963 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
1964 ProcessInfo
*process_info
;
1965 Drawing_t
*drawing
= control_flow_data
->drawing
;
1966 /* Process not present */
1967 processlist_add(process_list
,
1979 &hashed_process_data_in
);
1980 gtk_widget_set_size_request(drawing
->drawing_area
,
1983 gtk_widget_queue_draw(drawing
->drawing_area
);
1985 processlist_set_name(process_list
, process_in
->name
,
1986 hashed_process_data_in
);
1987 processlist_set_ppid(process_list
, process_in
->ppid
,
1988 hashed_process_data_in
);
1989 processlist_set_tgid(process_list
, process_in
->tgid
,
1990 hashed_process_data_in
);
1997 gint
update_time_window_hook(void *hook_data
, void *call_data
)
1999 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2000 Drawing_t
*drawing
= control_flow_data
->drawing
;
2001 ProcessList
*process_list
= control_flow_data
->process_list
;
2003 const TimeWindowNotifyData
*time_window_nofify_data
=
2004 ((const TimeWindowNotifyData
*)call_data
);
2006 TimeWindow
*old_time_window
=
2007 time_window_nofify_data
->old_time_window
;
2008 TimeWindow
*new_time_window
=
2009 time_window_nofify_data
->new_time_window
;
2011 /* Update the ruler */
2012 drawing_update_ruler(control_flow_data
->drawing
,
2016 /* Two cases : zoom in/out or scrolling */
2018 /* In order to make sure we can reuse the old drawing, the scale must
2019 * be the same and the new time interval being partly located in the
2020 * currently shown time interval. (reuse is only for scrolling)
2023 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
2024 old_time_window
->start_time
.tv_sec
,
2025 old_time_window
->start_time
.tv_nsec
,
2026 old_time_window
->time_width
.tv_sec
,
2027 old_time_window
->time_width
.tv_nsec
);
2029 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
2030 new_time_window
->start_time
.tv_sec
,
2031 new_time_window
->start_time
.tv_nsec
,
2032 new_time_window
->time_width
.tv_sec
,
2033 new_time_window
->time_width
.tv_nsec
);
2035 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
2036 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
2038 /* Same scale (scrolling) */
2039 g_info("scrolling");
2040 LttTime
*ns
= &new_time_window
->start_time
;
2041 LttTime
*nw
= &new_time_window
->time_width
;
2042 LttTime
*os
= &old_time_window
->start_time
;
2043 LttTime
*ow
= &old_time_window
->time_width
;
2044 LttTime old_end
= old_time_window
->end_time
;
2045 LttTime new_end
= new_time_window
->end_time
;
2047 //if(ns<os+w && os+w<ns+w)
2048 //if(ns<old_end && os<ns)
2049 if(ltt_time_compare(*ns
, old_end
) == -1
2050 && ltt_time_compare(*os
, *ns
) == -1)
2052 g_info("scrolling near right");
2053 /* Scroll right, keep right part of the screen */
2055 guint width
= control_flow_data
->drawing
->width
;
2056 convert_time_to_pixels(
2062 /* Copy old data to new location */
2063 copy_pixmap_region(process_list
,
2065 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2069 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
2071 if(drawing
->damage_begin
== drawing
->damage_end
)
2072 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
2074 drawing
->damage_begin
= 0;
2076 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2078 /* Clear the data request background, but not SAFETY */
2079 rectangle_pixmap(process_list
,
2080 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2082 drawing
->damage_begin
+SAFETY
, 0,
2083 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2085 gtk_widget_queue_draw(drawing
->drawing_area
);
2086 //gtk_widget_queue_draw_area (drawing->drawing_area,
2088 // control_flow_data->drawing->width,
2089 // control_flow_data->drawing->height);
2091 /* Get new data for the rest. */
2092 drawing_data_request(control_flow_data
->drawing
,
2093 drawing
->damage_begin
, 0,
2094 drawing
->damage_end
- drawing
->damage_begin
,
2095 control_flow_data
->drawing
->height
);
2098 //if(ns<os && os<ns+w)
2099 //if(ns<os && os<new_end)
2100 if(ltt_time_compare(*ns
,*os
) == -1
2101 && ltt_time_compare(*os
,new_end
) == -1)
2103 g_info("scrolling near left");
2104 /* Scroll left, keep left part of the screen */
2106 guint width
= control_flow_data
->drawing
->width
;
2107 convert_time_to_pixels(
2113 /* Copy old data to new location */
2114 copy_pixmap_region (process_list
,
2116 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2122 if(drawing
->damage_begin
== drawing
->damage_end
)
2123 drawing
->damage_end
= x
;
2125 drawing
->damage_end
=
2126 control_flow_data
->drawing
->width
;
2128 drawing
->damage_begin
= 0;
2130 rectangle_pixmap (process_list
,
2131 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2133 drawing
->damage_begin
, 0,
2134 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2137 gtk_widget_queue_draw(drawing
->drawing_area
);
2138 //gtk_widget_queue_draw_area (drawing->drawing_area,
2140 // control_flow_data->drawing->width,
2141 // control_flow_data->drawing->height);
2144 /* Get new data for the rest. */
2145 drawing_data_request(control_flow_data
->drawing
,
2146 drawing
->damage_begin
, 0,
2147 drawing
->damage_end
- drawing
->damage_begin
,
2148 control_flow_data
->drawing
->height
);
2151 if(ltt_time_compare(*ns
,*os
) == 0)
2153 g_info("not scrolling");
2155 g_info("scrolling far");
2156 /* Cannot reuse any part of the screen : far jump */
2159 rectangle_pixmap (process_list
,
2160 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2163 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2166 //gtk_widget_queue_draw_area (drawing->drawing_area,
2168 // control_flow_data->drawing->width,
2169 // control_flow_data->drawing->height);
2170 gtk_widget_queue_draw(drawing
->drawing_area
);
2172 drawing
->damage_begin
= 0;
2173 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2175 drawing_data_request(control_flow_data
->drawing
,
2177 control_flow_data
->drawing
->width
,
2178 control_flow_data
->drawing
->height
);
2184 /* Different scale (zoom) */
2187 rectangle_pixmap (process_list
,
2188 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2191 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2194 //gtk_widget_queue_draw_area (drawing->drawing_area,
2196 // control_flow_data->drawing->width,
2197 // control_flow_data->drawing->height);
2198 gtk_widget_queue_draw(drawing
->drawing_area
);
2200 drawing
->damage_begin
= 0;
2201 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2203 drawing_data_request(control_flow_data
->drawing
,
2205 control_flow_data
->drawing
->width
,
2206 control_flow_data
->drawing
->height
);
2209 /* Update directly when scrolling */
2210 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2216 gint
traceset_notify(void *hook_data
, void *call_data
)
2218 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2219 Drawing_t
*drawing
= control_flow_data
->drawing
;
2221 if(unlikely(drawing
->gc
== NULL
)) {
2224 if(drawing
->dotted_gc
== NULL
) {
2228 drawing_clear(control_flow_data
->drawing
);
2229 processlist_clear(control_flow_data
->process_list
);
2230 gtk_widget_set_size_request(
2231 control_flow_data
->drawing
->drawing_area
,
2232 -1, processlist_get_height(control_flow_data
->process_list
));
2233 redraw_notify(control_flow_data
, NULL
);
2235 request_background_data(control_flow_data
);
2240 gint
redraw_notify(void *hook_data
, void *call_data
)
2242 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2243 Drawing_t
*drawing
= control_flow_data
->drawing
;
2244 GtkWidget
*widget
= drawing
->drawing_area
;
2246 drawing
->damage_begin
= 0;
2247 drawing
->damage_end
= drawing
->width
;
2249 /* fun feature, to be separated someday... */
2250 drawing_clear(control_flow_data
->drawing
);
2251 processlist_clear(control_flow_data
->process_list
);
2252 gtk_widget_set_size_request(
2253 control_flow_data
->drawing
->drawing_area
,
2254 -1, processlist_get_height(control_flow_data
->process_list
));
2256 rectangle_pixmap (control_flow_data
->process_list
,
2257 widget
->style
->black_gc
,
2260 drawing
->alloc_width
,
2263 gtk_widget_queue_draw(drawing
->drawing_area
);
2265 if(drawing
->damage_begin
< drawing
->damage_end
)
2267 drawing_data_request(drawing
,
2268 drawing
->damage_begin
,
2270 drawing
->damage_end
-drawing
->damage_begin
,
2274 //gtk_widget_queue_draw_area(drawing->drawing_area,
2277 // drawing->height);
2283 gint
continue_notify(void *hook_data
, void *call_data
)
2285 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2286 Drawing_t
*drawing
= control_flow_data
->drawing
;
2288 //g_assert(widget->allocation.width == drawing->damage_end);
2290 if(drawing
->damage_begin
< drawing
->damage_end
)
2292 drawing_data_request(drawing
,
2293 drawing
->damage_begin
,
2295 drawing
->damage_end
-drawing
->damage_begin
,
2303 gint
update_current_time_hook(void *hook_data
, void *call_data
)
2305 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
2306 Drawing_t
*drawing
= control_flow_data
->drawing
;
2308 LttTime current_time
= *((LttTime
*)call_data
);
2310 TimeWindow time_window
=
2311 lttvwindow_get_time_window(control_flow_data
->tab
);
2313 LttTime time_begin
= time_window
.start_time
;
2314 LttTime width
= time_window
.time_width
;
2317 guint64 time_ll
= ltt_time_to_uint64(width
);
2318 time_ll
= time_ll
>> 1; /* divide by two */
2319 half_width
= ltt_time_from_uint64(time_ll
);
2321 LttTime time_end
= ltt_time_add(time_begin
, width
);
2323 LttvTracesetContext
* tsc
=
2324 lttvwindow_get_traceset_context(control_flow_data
->tab
);
2326 LttTime trace_start
= tsc
->time_span
.start_time
;
2327 LttTime trace_end
= tsc
->time_span
.end_time
;
2329 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
2330 current_time
.tv_nsec
);
2334 /* If current time is inside time interval, just move the highlight
2337 /* Else, we have to change the time interval. We have to tell it
2338 * to the main window. */
2339 /* The time interval change will take care of placing the current
2340 * time at the center of the visible area, or nearest possible if we are
2341 * at one end of the trace. */
2344 if(ltt_time_compare(current_time
, time_begin
) < 0)
2346 TimeWindow new_time_window
;
2348 if(ltt_time_compare(current_time
,
2349 ltt_time_add(trace_start
,half_width
)) < 0)
2350 time_begin
= trace_start
;
2352 time_begin
= ltt_time_sub(current_time
,half_width
);
2354 new_time_window
.start_time
= time_begin
;
2355 new_time_window
.time_width
= width
;
2356 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2357 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2359 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2361 else if(ltt_time_compare(current_time
, time_end
) > 0)
2363 TimeWindow new_time_window
;
2365 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
2366 time_begin
= ltt_time_sub(trace_end
,width
);
2368 time_begin
= ltt_time_sub(current_time
,half_width
);
2370 new_time_window
.start_time
= time_begin
;
2371 new_time_window
.time_width
= width
;
2372 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2373 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2375 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2378 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2380 /* Update directly when scrolling */
2381 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2387 typedef struct _ClosureData
{
2388 EventsRequest
*events_request
;
2389 LttvTracesetState
*tss
;
2395 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
2397 ProcessInfo
*process_info
= (ProcessInfo
*)key
;
2398 HashedProcessData
*hashed_process_data
= (HashedProcessData
*)value
;
2399 ClosureData
*closure_data
= (ClosureData
*)user_data
;
2401 EventsRequest
*events_request
= closure_data
->events_request
;
2402 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2404 LttvTracesetState
*tss
= closure_data
->tss
;
2405 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)tss
;
2407 LttTime evtime
= closure_data
->end_time
;
2409 gboolean dodraw
= TRUE
;
2412 /* For the process */
2413 /* First, check if the current process is in the state computation
2414 * process list. If it is there, that means we must add it right now and
2415 * draw items from the beginning of the read for it. If it is not
2416 * present, it's a new process and it was not present : it will
2417 * be added after the state update. */
2419 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
2420 #endif //EXTRA_CHECK
2421 LttvTraceContext
*tc
= tsc
->traces
[process_info
->trace_num
];
2422 LttvTraceState
*ts
= (LttvTraceState
*)tc
;
2425 //FIXME : optimize data structures.
2426 LttvTracefileState
*tfs
;
2427 LttvTracefileContext
*tfc
;
2429 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
2430 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
2431 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
2432 && tfs
->cpu
== process_info
->cpu
)
2436 g_assert(i
<tc
->tracefiles
->len
);
2437 tfs
= LTTV_TRACEFILE_STATE(tfc
);
2439 // LttvTracefileState *tfs =
2440 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2441 // tracefiles[process_info->cpu];
2443 LttvProcessState
*process
;
2444 process
= lttv_state_find_process(ts
, process_info
->cpu
,
2447 if(unlikely(process
!= NULL
)) {
2449 LttvFilter
*filter
= control_flow_data
->filter
;
2450 if(filter
!= NULL
&& filter
->head
!= NULL
)
2451 if(!lttv_filter_tree_parse(filter
->head
,NULL
,NULL
,
2452 tc
->t
,NULL
,process
,tc
))
2455 /* Only draw for processes that are currently in the trace states */
2457 ProcessList
*process_list
= control_flow_data
->process_list
;
2459 /* Should be alike when background info is ready */
2460 if(control_flow_data
->background_info_waiting
==0)
2461 g_assert(ltt_time_compare(process
->creation_time
,
2462 process_info
->birth
) == 0);
2463 #endif //EXTRA_CHECK
2465 /* Now, the process is in the state hash and our own process hash.
2466 * We definitely can draw the items related to the ending state.
2469 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2472 TimeWindow time_window
=
2473 lttvwindow_get_time_window(control_flow_data
->tab
);
2476 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2477 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2479 #endif //EXTRA_CHECK
2480 Drawing_t
*drawing
= control_flow_data
->drawing
;
2481 guint width
= drawing
->width
;
2483 guint x
= closure_data
->x_end
;
2485 DrawContext draw_context
;
2487 /* Now create the drawing context that will be used to draw
2488 * items related to the last state. */
2489 draw_context
.drawable
= hashed_process_data
->pixmap
;
2490 draw_context
.gc
= drawing
->gc
;
2491 draw_context
.pango_layout
= drawing
->pango_layout
;
2492 draw_context
.drawinfo
.end
.x
= x
;
2494 draw_context
.drawinfo
.y
.over
= 1;
2495 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2496 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2498 draw_context
.drawinfo
.start
.offset
.over
= 0;
2499 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2500 draw_context
.drawinfo
.start
.offset
.under
= 0;
2501 draw_context
.drawinfo
.end
.offset
.over
= 0;
2502 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2503 draw_context
.drawinfo
.end
.offset
.under
= 0;
2505 /* Jump over draw if we are at the same x position */
2506 if(x
== hashed_process_data
->x
.over
)
2510 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2512 PropertiesLine prop_line
= prepare_execmode_line(process
);
2513 draw_line((void*)&prop_line
, (void*)&draw_context
);
2515 hashed_process_data
->x
.over
= x
;
2519 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2520 hashed_process_data
->x
.middle_used
)) {
2521 #if 0 /* do not mark closure : not missing information */
2522 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2523 /* Draw collision indicator */
2524 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2525 gdk_draw_point(drawing
->pixmap
,
2529 hashed_process_data
->x
.middle_marked
= TRUE
;
2534 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2537 PropertiesLine prop_line
= prepare_s_e_line(process
);
2538 draw_line((void*)&prop_line
, (void*)&draw_context
);
2541 /* become the last x position */
2542 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2543 hashed_process_data
->x
.middle
= x
;
2544 /* but don't use the pixel */
2545 hashed_process_data
->x
.middle_used
= FALSE
;
2547 /* Calculate the next good time */
2548 convert_pixels_to_time(width
, x
+1, time_window
,
2549 &hashed_process_data
->next_good_time
);
2558 int before_chunk(void *hook_data
, void *call_data
)
2560 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2561 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2562 ControlFlowData
*cfd
= (ControlFlowData
*)events_request
->viewer_data
;
2564 /* Desactivate sort */
2565 gtk_tree_sortable_set_sort_column_id(
2566 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2568 GTK_SORT_ASCENDING
);
2570 drawing_chunk_begin(events_request
, tss
);
2575 int before_request(void *hook_data
, void *call_data
)
2577 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2578 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2580 drawing_data_request_begin(events_request
, tss
);
2587 * after request is necessary in addition of after chunk in order to draw
2588 * lines until the end of the screen. after chunk just draws lines until
2595 int after_request(void *hook_data
, void *call_data
)
2597 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2598 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2599 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2601 ProcessList
*process_list
= control_flow_data
->process_list
;
2602 LttTime end_time
= events_request
->end_time
;
2604 ClosureData closure_data
;
2605 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2606 closure_data
.tss
= tss
;
2607 closure_data
.end_time
= end_time
;
2609 TimeWindow time_window
=
2610 lttvwindow_get_time_window(control_flow_data
->tab
);
2611 guint width
= control_flow_data
->drawing
->width
;
2612 convert_time_to_pixels(
2616 &closure_data
.x_end
);
2619 /* Draw last items */
2620 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2621 (void*)&closure_data
);
2624 /* Request expose */
2625 drawing_request_expose(events_request
, tss
, end_time
);
2634 int after_chunk(void *hook_data
, void *call_data
)
2636 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2637 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2638 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2639 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)call_data
;
2640 LttvTracefileContext
*tfc
= lttv_traceset_context_get_current_tfc(tsc
);
2643 ProcessList
*process_list
= control_flow_data
->process_list
;
2645 LttvTraceset
*traceset
= tsc
->ts
;
2646 guint nb_trace
= lttv_traceset_number(traceset
);
2648 /* Only execute when called for the first trace's events request */
2649 if(!process_list
->current_hash_data
) return;
2651 for(i
= 0 ; i
< nb_trace
; i
++) {
2652 g_free(process_list
->current_hash_data
[i
]);
2654 g_free(process_list
->current_hash_data
);
2655 process_list
->current_hash_data
= NULL
;
2658 end_time
= LTT_TIME_MIN(tfc
->timestamp
, events_request
->end_time
);
2659 else /* end of traceset, or position now out of request : end */
2660 end_time
= events_request
->end_time
;
2662 ClosureData closure_data
;
2663 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2664 closure_data
.tss
= tss
;
2665 closure_data
.end_time
= end_time
;
2667 TimeWindow time_window
=
2668 lttvwindow_get_time_window(control_flow_data
->tab
);
2669 guint width
= control_flow_data
->drawing
->width
;
2670 convert_time_to_pixels(
2674 &closure_data
.x_end
);
2676 /* Draw last items */
2677 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2678 (void*)&closure_data
);
2680 /* Reactivate sort */
2681 gtk_tree_sortable_set_sort_column_id(
2682 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2683 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2684 GTK_SORT_ASCENDING
);
2686 update_index_to_pixmap(control_flow_data
->process_list
);
2687 /* Request a full expose : drawing scrambled */
2688 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2690 /* Request expose (updates damages zone also) */
2691 drawing_request_expose(events_request
, tss
, end_time
);
2696 /* after_statedump_end
2698 * @param hook_data ControlFlowData structure of the viewer.
2699 * @param call_data Event context.
2701 * This function adds items to be drawn in a queue for each process.
2704 int before_statedump_end(void *hook_data
, void *call_data
)
2706 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2707 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
2708 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2710 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2712 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
2714 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
2716 LttvTracesetState
*tss
= (LttvTracesetState
*)tfc
->t_context
->ts_context
;
2717 ProcessList
*process_list
= control_flow_data
->process_list
;
2720 e
= ltt_tracefile_get_event(tfc
->tf
);
2722 LttvFilter
*filter
= control_flow_data
->filter
;
2723 if(filter
!= NULL
&& filter
->head
!= NULL
)
2724 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2725 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2728 LttTime evtime
= ltt_event_time(e
);
2730 ClosureData closure_data
;
2731 closure_data
.events_request
= events_request
;
2732 closure_data
.tss
= tss
;
2733 closure_data
.end_time
= evtime
;
2735 TimeWindow time_window
=
2736 lttvwindow_get_time_window(control_flow_data
->tab
);
2737 guint width
= control_flow_data
->drawing
->width
;
2738 convert_time_to_pixels(
2742 &closure_data
.x_end
);
2744 /* Draw last items */
2745 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2746 (void*)&closure_data
);
2748 /* Reactivate sort */
2749 gtk_tree_sortable_set_sort_column_id(
2750 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2751 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2752 GTK_SORT_ASCENDING
);
2754 update_index_to_pixmap(control_flow_data
->process_list
);
2755 /* Request a full expose : drawing scrambled */
2756 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2758 /* Request expose (updates damages zone also) */
2759 drawing_request_expose(events_request
, tss
, evtime
);