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>
65 #include <ltt/trace.h>
67 #include <lttv/lttv.h>
68 #include <lttv/hook.h>
69 #include <lttv/state.h>
70 #include <lttvwindow/lttvwindow.h>
71 #include <lttvwindow/lttvwindowtraces.h>
72 #include <lttvwindow/support.h>
75 #include "eventhooks.h"
77 #include "processlist.h"
81 #define MAX_PATH_LEN 256
82 #define STATE_LINE_WIDTH 4
83 #define COLLISION_POSITION(height) (((height - STATE_LINE_WIDTH)/2) -3)
85 extern GSList
*g_legend_list
;
88 /* Action to do when background computation completed.
90 * Wait for all the awaited computations to be over.
93 static gint
background_ready(void *hook_data
, void *call_data
)
95 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
96 LttvTrace
*trace
= (LttvTrace
*)call_data
;
98 control_flow_data
->background_info_waiting
--;
100 if(control_flow_data
->background_info_waiting
== 0) {
101 g_message("control flow viewer : background computation data ready.");
103 drawing_clear(control_flow_data
->drawing
);
104 processlist_clear(control_flow_data
->process_list
);
105 gtk_widget_set_size_request(
106 control_flow_data
->drawing
->drawing_area
,
107 -1, processlist_get_height(control_flow_data
->process_list
));
108 redraw_notify(control_flow_data
, NULL
);
115 /* Request background computation. Verify if it is in progress or ready first.
116 * Only for each trace in the tab's traceset.
118 static void request_background_data(ControlFlowData
*control_flow_data
)
120 LttvTracesetContext
* tsc
=
121 lttvwindow_get_traceset_context(control_flow_data
->tab
);
122 gint num_traces
= lttv_traceset_number(tsc
->ts
);
125 LttvTraceState
*tstate
;
127 LttvHooks
*background_ready_hook
=
129 lttv_hooks_add(background_ready_hook
, background_ready
, control_flow_data
,
131 control_flow_data
->background_info_waiting
= 0;
133 for(i
=0;i
<num_traces
;i
++) {
134 trace
= lttv_traceset_get(tsc
->ts
, i
);
135 tstate
= LTTV_TRACE_STATE(tsc
->traces
[i
]);
137 if(lttvwindowtraces_get_ready(g_quark_from_string("state"),trace
)==FALSE
138 && !tstate
->has_precomputed_states
) {
140 if(lttvwindowtraces_get_in_progress(g_quark_from_string("state"),
142 /* We first remove requests that could have been done for the same
143 * information. Happens when two viewers ask for it before servicing
146 if(!lttvwindowtraces_background_request_find(trace
, "state"))
147 lttvwindowtraces_background_request_queue(
148 main_window_get_widget(control_flow_data
->tab
), trace
, "state");
149 lttvwindowtraces_background_notify_queue(control_flow_data
,
153 background_ready_hook
);
154 control_flow_data
->background_info_waiting
++;
155 } else { /* in progress */
157 lttvwindowtraces_background_notify_current(control_flow_data
,
161 background_ready_hook
);
162 control_flow_data
->background_info_waiting
++;
165 /* Data ready. By its nature, this viewer doesn't need to have
166 * its data ready hook called there, because a background
167 * request is always linked with a redraw.
173 lttv_hooks_destroy(background_ready_hook
);
180 * Event Viewer's constructor hook
182 * This constructor is given as a parameter to the menuitem and toolbar button
183 * registration. It creates the list.
184 * @param tab A pointer to the parent tab.
185 * @return The widget created.
188 h_guicontrolflow(LttvPlugin
*plugin
)
190 LttvPluginTab
*ptab
= LTTV_PLUGIN_TAB(plugin
);
191 Tab
*tab
= ptab
->tab
;
192 g_info("h_guicontrolflow, %p", tab
);
193 ControlFlowData
*control_flow_data
= guicontrolflow(ptab
);
195 control_flow_data
->tab
= tab
;
197 // Unreg done in the GuiControlFlow_Destructor
198 lttvwindow_register_traceset_notify(tab
,
202 lttvwindow_register_time_window_notify(tab
,
203 update_time_window_hook
,
205 lttvwindow_register_current_time_notify(tab
,
206 update_current_time_hook
,
208 lttvwindow_register_redraw_notify(tab
,
211 lttvwindow_register_continue_notify(tab
,
214 request_background_data(control_flow_data
);
217 return guicontrolflow_get_widget(control_flow_data
) ;
221 void legend_destructor(GtkWindow
*legend
)
223 g_legend_list
= g_slist_remove(g_legend_list
, legend
);
226 /* Create a popup legend */
228 h_legend(LttvPlugin
*plugin
)
230 LttvPluginTab
*ptab
= LTTV_PLUGIN_TAB(plugin
);
231 Tab
*tab
= ptab
->tab
;
232 g_info("h_legend, %p", tab
);
234 GtkWindow
*legend
= GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL
));
236 g_legend_list
= g_slist_append(
240 g_object_set_data_full(
244 (GDestroyNotify
)legend_destructor
);
246 gtk_window_set_title(legend
, "Control Flow View Legend");
248 GtkWidget
*pixmap
= create_pixmap(GTK_WIDGET(legend
), "lttv-color-list.png");
250 // GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixmap(
251 // GDK_PIXMAP(pixmap), NULL));
253 gtk_container_add(GTK_CONTAINER(legend
), GTK_WIDGET(pixmap
));
255 gtk_widget_show(GTK_WIDGET(pixmap
));
256 gtk_widget_show(GTK_WIDGET(legend
));
259 return NULL
; /* This is a popup window */
263 int event_selected_hook(void *hook_data
, void *call_data
)
265 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
266 guint
*event_number
= (guint
*) call_data
;
268 g_debug("DEBUG : event selected by main window : %u", *event_number
);
273 /* Function that selects the color of status&exemode line */
274 static inline PropertiesLine
prepare_s_e_line(LttvProcessState
*process
)
276 PropertiesLine prop_line
;
277 prop_line
.line_width
= STATE_LINE_WIDTH
;
278 prop_line
.style
= GDK_LINE_SOLID
;
279 prop_line
.y
= MIDDLE
;
280 //GdkColormap *colormap = gdk_colormap_get_system();
282 if(process
->state
->s
== LTTV_STATE_RUN
) {
283 if(process
->state
->t
== LTTV_STATE_USER_MODE
)
284 prop_line
.color
= drawing_colors
[COL_RUN_USER_MODE
];
285 else if(process
->state
->t
== LTTV_STATE_SYSCALL
)
286 prop_line
.color
= drawing_colors
[COL_RUN_SYSCALL
];
287 else if(process
->state
->t
== LTTV_STATE_TRAP
)
288 prop_line
.color
= drawing_colors
[COL_RUN_TRAP
];
289 else if(process
->state
->t
== LTTV_STATE_IRQ
)
290 prop_line
.color
= drawing_colors
[COL_RUN_IRQ
];
291 else if(process
->state
->t
== LTTV_STATE_SOFT_IRQ
)
292 prop_line
.color
= drawing_colors
[COL_RUN_SOFT_IRQ
];
293 else if(process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
)
294 prop_line
.color
= drawing_colors
[COL_MODE_UNKNOWN
];
296 g_assert(FALSE
); /* RUNNING MODE UNKNOWN */
297 } else if(process
->state
->s
== LTTV_STATE_WAIT
) {
298 /* We don't show if we wait while in user mode, trap, irq or syscall */
299 prop_line
.color
= drawing_colors
[COL_WAIT
];
300 } else if(process
->state
->s
== LTTV_STATE_WAIT_CPU
) {
301 /* We don't show if we wait for CPU while in user mode, trap, irq
303 prop_line
.color
= drawing_colors
[COL_WAIT_CPU
];
304 } else if(process
->state
->s
== LTTV_STATE_ZOMBIE
) {
305 prop_line
.color
= drawing_colors
[COL_ZOMBIE
];
306 } else if(process
->state
->s
== LTTV_STATE_WAIT_FORK
) {
307 prop_line
.color
= drawing_colors
[COL_WAIT_FORK
];
308 } else if(process
->state
->s
== LTTV_STATE_EXIT
) {
309 prop_line
.color
= drawing_colors
[COL_EXIT
];
310 } else if(process
->state
->s
== LTTV_STATE_UNNAMED
) {
311 prop_line
.color
= drawing_colors
[COL_UNNAMED
];
313 g_critical("unknown state : %s", g_quark_to_string(process
->state
->s
));
314 g_assert(FALSE
); /* UNKNOWN STATE */
322 /* before_schedchange_hook
324 * This function basically draw lines and icons. Two types of lines are drawn :
325 * one small (3 pixels?) representing the state of the process and the second
326 * type is thicker (10 pixels?) representing on which CPU a process is running
327 * (and this only in running state).
329 * Extremums of the lines :
330 * x_min : time of the last event context for this process kept in memory.
331 * x_max : time of the current event.
332 * y : middle of the process in the process list. The process is found in the
333 * list, therefore is it's position in pixels.
335 * The choice of lines'color is defined by the context of the last event for this
340 int before_schedchange_hook(void *hook_data
, void *call_data
)
342 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
343 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
344 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
346 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
348 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
349 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
352 e
= ltt_tracefile_get_event(tfc
->tf
);
353 gint target_pid_saved
= tfc
->target_pid
;
355 LttTime evtime
= ltt_event_time(e
);
356 LttvFilter
*filter
= control_flow_data
->filter
;
358 /* we are in a schedchange, before the state update. We must draw the
359 * items corresponding to the state before it changes : now is the right
366 pid_out
= ltt_event_get_long_unsigned(e
, thf
->f1
);
367 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f2
);
372 tfc
->target_pid
= pid_out
;
373 if(!filter
|| !filter
->head
||
374 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
375 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
376 /* For the pid_out */
377 /* First, check if the current process is in the state computation
378 * process list. If it is there, that means we must add it right now and
379 * draw items from the beginning of the read for it. If it is not
380 * present, it's a new process and it was not present : it will
381 * be added after the state update. */
382 guint cpu
= tfs
->cpu
;
383 guint trace_num
= ts
->parent
.index
;
384 LttvProcessState
*process
= ts
->running_process
[cpu
];
385 /* unknown state, bad current pid */
386 if(process
->pid
!= pid_out
)
387 process
= lttv_state_find_process(ts
,
390 if(process
!= NULL
) {
391 /* Well, the process_out existed : we must get it in the process hash
392 * or add it, and draw its items.
394 /* Add process to process list (if not present) */
396 HashedProcessData
*hashed_process_data
= NULL
;
397 ProcessList
*process_list
= control_flow_data
->process_list
;
398 LttTime birth
= process
->creation_time
;
400 hashed_process_data
= processlist_get_process_data(process_list
,
405 if(hashed_process_data
== NULL
)
407 g_assert(pid_out
== 0 || pid_out
!= process
->ppid
);
408 /* Process not present */
409 ProcessInfo
*process_info
;
410 Drawing_t
*drawing
= control_flow_data
->drawing
;
411 resourcelist_add(process_list
,
423 &hashed_process_data
);
424 gtk_widget_set_size_request(drawing
->drawing_area
,
427 gtk_widget_queue_draw(drawing
->drawing_area
);
431 /* Now, the process is in the state hash and our own process hash.
432 * We definitely can draw the items related to the ending state.
435 if(ltt_time_compare(hashed_process_data
->next_good_time
,
438 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
440 TimeWindow time_window
=
441 lttvwindow_get_time_window(control_flow_data
->tab
);
443 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
444 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
447 Drawing_t
*drawing
= control_flow_data
->drawing
;
448 guint width
= drawing
->width
;
450 convert_time_to_pixels(
456 /* Draw collision indicator */
457 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
458 gdk_draw_point(hashed_process_data
->pixmap
,
461 COLLISION_POSITION(hashed_process_data
->height
));
462 hashed_process_data
->x
.middle_marked
= TRUE
;
465 TimeWindow time_window
=
466 lttvwindow_get_time_window(control_flow_data
->tab
);
468 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
469 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
472 Drawing_t
*drawing
= control_flow_data
->drawing
;
473 guint width
= drawing
->width
;
475 convert_time_to_pixels(
482 /* Jump over draw if we are at the same x position */
483 if(x
== hashed_process_data
->x
.middle
&&
484 hashed_process_data
->x
.middle_used
)
486 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
487 /* Draw collision indicator */
488 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
489 gdk_draw_point(hashed_process_data
->pixmap
,
492 COLLISION_POSITION(hashed_process_data
->height
));
493 hashed_process_data
->x
.middle_marked
= TRUE
;
497 DrawContext draw_context
;
499 /* Now create the drawing context that will be used to draw
500 * items related to the last state. */
501 draw_context
.drawable
= hashed_process_data
->pixmap
;
502 draw_context
.gc
= drawing
->gc
;
503 draw_context
.pango_layout
= drawing
->pango_layout
;
504 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
505 draw_context
.drawinfo
.end
.x
= x
;
507 draw_context
.drawinfo
.y
.over
= 1;
508 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
509 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
511 draw_context
.drawinfo
.start
.offset
.over
= 0;
512 draw_context
.drawinfo
.start
.offset
.middle
= 0;
513 draw_context
.drawinfo
.start
.offset
.under
= 0;
514 draw_context
.drawinfo
.end
.offset
.over
= 0;
515 draw_context
.drawinfo
.end
.offset
.middle
= 0;
516 draw_context
.drawinfo
.end
.offset
.under
= 0;
520 PropertiesLine prop_line
= prepare_s_e_line(process
);
521 draw_line((void*)&prop_line
, (void*)&draw_context
);
524 /* become the last x position */
525 hashed_process_data
->x
.middle
= x
;
526 hashed_process_data
->x
.middle_used
= TRUE
;
527 hashed_process_data
->x
.middle_marked
= FALSE
;
529 /* Calculate the next good time */
530 convert_pixels_to_time(width
, x
+1, time_window
,
531 &hashed_process_data
->next_good_time
);
537 tfc
->target_pid
= pid_in
;
538 if(!filter
|| !filter
->head
||
539 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
540 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
542 /* First, check if the current process is in the state computation
543 * process list. If it is there, that means we must add it right now and
544 * draw items from the beginning of the read for it. If it is not
545 * present, it's a new process and it was not present : it will
546 * be added after the state update. */
547 LttvProcessState
*process
;
548 process
= lttv_state_find_process(ts
,
550 guint trace_num
= ts
->parent
.index
;
552 if(process
!= NULL
) {
553 /* Well, the process existed : we must get it in the process hash
554 * or add it, and draw its items.
556 /* Add process to process list (if not present) */
558 HashedProcessData
*hashed_process_data
= NULL
;
559 ProcessList
*process_list
= control_flow_data
->process_list
;
560 LttTime birth
= process
->creation_time
;
562 hashed_process_data
= processlist_get_process_data(process_list
,
567 if(hashed_process_data
== NULL
)
569 g_assert(pid_in
== 0 || pid_in
!= process
->ppid
);
570 /* Process not present */
571 ProcessInfo
*process_info
;
572 Drawing_t
*drawing
= control_flow_data
->drawing
;
573 processlist_add(process_list
,
585 &hashed_process_data
);
586 gtk_widget_set_size_request(drawing
->drawing_area
,
589 gtk_widget_queue_draw(drawing
->drawing_area
);
592 //We could set the current process and hash here, but will be done
593 //by after schedchange hook
595 /* Now, the process is in the state hash and our own process hash.
596 * We definitely can draw the items related to the ending state.
599 if(ltt_time_compare(hashed_process_data
->next_good_time
,
602 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
604 TimeWindow time_window
=
605 lttvwindow_get_time_window(control_flow_data
->tab
);
607 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
608 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
611 Drawing_t
*drawing
= control_flow_data
->drawing
;
612 guint width
= drawing
->width
;
614 convert_time_to_pixels(
620 /* Draw collision indicator */
621 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
622 gdk_draw_point(hashed_process_data
->pixmap
,
625 COLLISION_POSITION(hashed_process_data
->height
));
626 hashed_process_data
->x
.middle_marked
= TRUE
;
629 TimeWindow time_window
=
630 lttvwindow_get_time_window(control_flow_data
->tab
);
632 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
633 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
636 Drawing_t
*drawing
= control_flow_data
->drawing
;
637 guint width
= drawing
->width
;
640 convert_time_to_pixels(
647 /* Jump over draw if we are at the same x position */
648 if(x
== hashed_process_data
->x
.middle
&&
649 hashed_process_data
->x
.middle_used
)
651 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
652 /* Draw collision indicator */
653 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
654 gdk_draw_point(hashed_process_data
->pixmap
,
657 COLLISION_POSITION(hashed_process_data
->height
));
658 hashed_process_data
->x
.middle_marked
= TRUE
;
662 DrawContext draw_context
;
664 /* Now create the drawing context that will be used to draw
665 * items related to the last state. */
666 draw_context
.drawable
= hashed_process_data
->pixmap
;
667 draw_context
.gc
= drawing
->gc
;
668 draw_context
.pango_layout
= drawing
->pango_layout
;
669 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
670 draw_context
.drawinfo
.end
.x
= x
;
672 draw_context
.drawinfo
.y
.over
= 1;
673 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
674 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
676 draw_context
.drawinfo
.start
.offset
.over
= 0;
677 draw_context
.drawinfo
.start
.offset
.middle
= 0;
678 draw_context
.drawinfo
.start
.offset
.under
= 0;
679 draw_context
.drawinfo
.end
.offset
.over
= 0;
680 draw_context
.drawinfo
.end
.offset
.middle
= 0;
681 draw_context
.drawinfo
.end
.offset
.under
= 0;
685 PropertiesLine prop_line
= prepare_s_e_line(process
);
686 draw_line((void*)&prop_line
, (void*)&draw_context
);
690 /* become the last x position */
691 hashed_process_data
->x
.middle
= x
;
692 hashed_process_data
->x
.middle_used
= TRUE
;
693 hashed_process_data
->x
.middle_marked
= FALSE
;
695 /* Calculate the next good time */
696 convert_pixels_to_time(width
, x
+1, time_window
,
697 &hashed_process_data
->next_good_time
);
701 g_warning("Cannot find pin_in in schedchange %u", pid_in
);
703 tfc
->target_pid
= target_pid_saved
;
711 GString
*string
= g_string_new("");;
712 gboolean field_names
= TRUE
, state
= TRUE
;
714 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
715 g_string_append_printf(string
,"\n");
718 g_string_append_printf(string
, " %s",
719 g_quark_to_string(tfs
->process
->state
->s
));
722 g_info("%s",string
->str
);
724 g_string_free(string
, TRUE
);
726 /* End of text dump */
731 /* after_schedchange_hook
733 * The draw after hook is called by the reading API to have a
734 * particular event drawn on the screen.
735 * @param hook_data ControlFlowData structure of the viewer.
736 * @param call_data Event context.
738 * This function adds items to be drawn in a queue for each process.
741 int after_schedchange_hook(void *hook_data
, void *call_data
)
743 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
744 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
745 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
747 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
749 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
751 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
754 e
= ltt_tracefile_get_event(tfc
->tf
);
756 LttvFilter
*filter
= control_flow_data
->filter
;
757 if(filter
!= NULL
&& filter
->head
!= NULL
)
758 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
759 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
762 LttTime evtime
= ltt_event_time(e
);
764 /* Add process to process list (if not present) */
765 LttvProcessState
*process_in
;
768 HashedProcessData
*hashed_process_data_in
= NULL
;
770 ProcessList
*process_list
= control_flow_data
->process_list
;
775 pid_out
= ltt_event_get_long_unsigned(e
, thf
->f1
);
776 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f2
);
780 /* Find process pid_in in the list... */
781 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
782 //process_in = tfs->process;
783 guint cpu
= tfs
->cpu
;
784 guint trace_num
= ts
->parent
.index
;
785 process_in
= ts
->running_process
[cpu
];
786 /* It should exist, because we are after the state update. */
788 g_assert(process_in
!= NULL
);
790 birth
= process_in
->creation_time
;
792 hashed_process_data_in
= processlist_get_process_data(process_list
,
797 if(hashed_process_data_in
== NULL
)
799 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
800 ProcessInfo
*process_info
;
801 Drawing_t
*drawing
= control_flow_data
->drawing
;
802 /* Process not present */
803 processlist_add(process_list
,
815 &hashed_process_data_in
);
816 gtk_widget_set_size_request(drawing
->drawing_area
,
819 gtk_widget_queue_draw(drawing
->drawing_area
);
821 /* Set the current process */
822 process_list
->current_hash_data
[trace_num
][process_in
->cpu
] =
823 hashed_process_data_in
;
825 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
828 TimeWindow time_window
=
829 lttvwindow_get_time_window(control_flow_data
->tab
);
832 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
833 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
836 Drawing_t
*drawing
= control_flow_data
->drawing
;
837 guint width
= drawing
->width
;
840 convert_time_to_pixels(
846 if(hashed_process_data_in
->x
.middle
!= new_x
) {
847 hashed_process_data_in
->x
.middle
= new_x
;
848 hashed_process_data_in
->x
.middle_used
= FALSE
;
849 hashed_process_data_in
->x
.middle_marked
= FALSE
;
858 /* before_execmode_hook
860 * This function basically draw lines and icons. Two types of lines are drawn :
861 * one small (3 pixels?) representing the state of the process and the second
862 * type is thicker (10 pixels?) representing on which CPU a process is running
863 * (and this only in running state).
865 * Extremums of the lines :
866 * x_min : time of the last event context for this process kept in memory.
867 * x_max : time of the current event.
868 * y : middle of the process in the process list. The process is found in the
869 * list, therefore is it's position in pixels.
871 * The choice of lines'color is defined by the context of the last event for this
876 int before_execmode_hook(void *hook_data
, void *call_data
)
878 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
879 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
880 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
882 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
884 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
886 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
889 e
= ltt_tracefile_get_event(tfc
->tf
);
891 LttvFilter
*filter
= control_flow_data
->filter
;
892 if(filter
!= NULL
&& filter
->head
!= NULL
)
893 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
894 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
897 LttTime evtime
= ltt_event_time(e
);
899 /* we are in a execmode, before the state update. We must draw the
900 * items corresponding to the state before it changes : now is the right
904 //LttvProcessState *process = tfs->process;
905 guint cpu
= tfs
->cpu
;
906 guint trace_num
= ts
->parent
.index
;
907 LttvProcessState
*process
= ts
->running_process
[cpu
];
908 g_assert(process
!= NULL
);
910 guint pid
= process
->pid
;
912 /* Well, the process_out existed : we must get it in the process hash
913 * or add it, and draw its items.
915 /* Add process to process list (if not present) */
917 HashedProcessData
*hashed_process_data
= NULL
;
918 ProcessList
*process_list
= control_flow_data
->process_list
;
919 LttTime birth
= process
->creation_time
;
921 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
922 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
924 hashed_process_data
= processlist_get_process_data(process_list
,
929 if(unlikely(hashed_process_data
== NULL
))
931 g_assert(pid
== 0 || pid
!= process
->ppid
);
932 ProcessInfo
*process_info
;
933 /* Process not present */
934 Drawing_t
*drawing
= control_flow_data
->drawing
;
935 processlist_add(process_list
,
947 &hashed_process_data
);
948 gtk_widget_set_size_request(drawing
->drawing_area
,
951 gtk_widget_queue_draw(drawing
->drawing_area
);
953 /* Set the current process */
954 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
958 /* Now, the process is in the state hash and our own process hash.
959 * We definitely can draw the items related to the ending state.
962 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
965 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
966 TimeWindow time_window
=
967 lttvwindow_get_time_window(control_flow_data
->tab
);
970 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
971 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
974 Drawing_t
*drawing
= control_flow_data
->drawing
;
975 guint width
= drawing
->width
;
977 convert_time_to_pixels(
983 /* Draw collision indicator */
984 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
985 gdk_draw_point(hashed_process_data
->pixmap
,
988 COLLISION_POSITION(hashed_process_data
->height
));
989 hashed_process_data
->x
.middle_marked
= TRUE
;
992 TimeWindow time_window
=
993 lttvwindow_get_time_window(control_flow_data
->tab
);
996 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
997 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1000 Drawing_t
*drawing
= control_flow_data
->drawing
;
1001 guint width
= drawing
->width
;
1004 convert_time_to_pixels(
1011 /* Jump over draw if we are at the same x position */
1012 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1013 hashed_process_data
->x
.middle_used
))
1015 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1016 /* Draw collision indicator */
1017 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1018 gdk_draw_point(hashed_process_data
->pixmap
,
1021 COLLISION_POSITION(hashed_process_data
->height
));
1022 hashed_process_data
->x
.middle_marked
= TRUE
;
1027 DrawContext draw_context
;
1028 /* Now create the drawing context that will be used to draw
1029 * items related to the last state. */
1030 draw_context
.drawable
= hashed_process_data
->pixmap
;
1031 draw_context
.gc
= drawing
->gc
;
1032 draw_context
.pango_layout
= drawing
->pango_layout
;
1033 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1034 draw_context
.drawinfo
.end
.x
= x
;
1036 draw_context
.drawinfo
.y
.over
= 1;
1037 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1038 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1040 draw_context
.drawinfo
.start
.offset
.over
= 0;
1041 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1042 draw_context
.drawinfo
.start
.offset
.under
= 0;
1043 draw_context
.drawinfo
.end
.offset
.over
= 0;
1044 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1045 draw_context
.drawinfo
.end
.offset
.under
= 0;
1049 PropertiesLine prop_line
= prepare_s_e_line(process
);
1050 draw_line((void*)&prop_line
, (void*)&draw_context
);
1053 /* become the last x position */
1054 hashed_process_data
->x
.middle
= x
;
1055 hashed_process_data
->x
.middle_used
= TRUE
;
1056 hashed_process_data
->x
.middle_marked
= FALSE
;
1058 /* Calculate the next good time */
1059 convert_pixels_to_time(width
, x
+1, time_window
,
1060 &hashed_process_data
->next_good_time
);
1067 /* before_process_exit_hook
1069 * Draw lines for process event.
1071 * @param hook_data ControlFlowData structure of the viewer.
1072 * @param call_data Event context.
1074 * This function adds items to be drawn in a queue for each process.
1079 int before_process_exit_hook(void *hook_data
, void *call_data
)
1081 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1082 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1084 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1086 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1088 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1090 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1093 e
= ltt_tracefile_get_event(tfc
->tf
);
1095 LttvFilter
*filter
= control_flow_data
->filter
;
1096 if(filter
!= NULL
&& filter
->head
!= NULL
)
1097 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1098 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1101 LttTime evtime
= ltt_event_time(e
);
1103 /* Add process to process list (if not present) */
1104 //LttvProcessState *process = tfs->process;
1105 guint cpu
= tfs
->cpu
;
1106 guint trace_num
= ts
->parent
.index
;
1107 LttvProcessState
*process
= ts
->running_process
[cpu
];
1108 guint pid
= process
->pid
;
1110 guint pl_height
= 0;
1111 HashedProcessData
*hashed_process_data
= NULL
;
1113 ProcessList
*process_list
= control_flow_data
->process_list
;
1115 g_assert(process
!= NULL
);
1117 birth
= process
->creation_time
;
1119 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1120 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1122 hashed_process_data
= processlist_get_process_data(process_list
,
1127 if(unlikely(hashed_process_data
== NULL
))
1129 g_assert(pid
== 0 || pid
!= process
->ppid
);
1130 /* Process not present */
1131 Drawing_t
*drawing
= control_flow_data
->drawing
;
1132 ProcessInfo
*process_info
;
1133 processlist_add(process_list
,
1145 &hashed_process_data
);
1146 gtk_widget_set_size_request(drawing
->drawing_area
,
1149 gtk_widget_queue_draw(drawing
->drawing_area
);
1153 /* Now, the process is in the state hash and our own process hash.
1154 * We definitely can draw the items related to the ending state.
1157 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1160 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1161 TimeWindow time_window
=
1162 lttvwindow_get_time_window(control_flow_data
->tab
);
1165 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1166 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1168 #endif //EXTRA_CHECK
1169 Drawing_t
*drawing
= control_flow_data
->drawing
;
1170 guint width
= drawing
->width
;
1172 convert_time_to_pixels(
1178 /* Draw collision indicator */
1179 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1180 gdk_draw_point(hashed_process_data
->pixmap
,
1183 COLLISION_POSITION(hashed_process_data
->height
));
1184 hashed_process_data
->x
.middle_marked
= TRUE
;
1187 TimeWindow time_window
=
1188 lttvwindow_get_time_window(control_flow_data
->tab
);
1191 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1192 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1194 #endif //EXTRA_CHECK
1195 Drawing_t
*drawing
= control_flow_data
->drawing
;
1196 guint width
= drawing
->width
;
1199 convert_time_to_pixels(
1206 /* Jump over draw if we are at the same x position */
1207 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1208 hashed_process_data
->x
.middle_used
))
1210 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1211 /* Draw collision indicator */
1212 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1213 gdk_draw_point(hashed_process_data
->pixmap
,
1216 COLLISION_POSITION(hashed_process_data
->height
));
1217 hashed_process_data
->x
.middle_marked
= TRUE
;
1221 DrawContext draw_context
;
1223 /* Now create the drawing context that will be used to draw
1224 * items related to the last state. */
1225 draw_context
.drawable
= hashed_process_data
->pixmap
;
1226 draw_context
.gc
= drawing
->gc
;
1227 draw_context
.pango_layout
= drawing
->pango_layout
;
1228 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1229 draw_context
.drawinfo
.end
.x
= x
;
1231 draw_context
.drawinfo
.y
.over
= 1;
1232 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1233 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1235 draw_context
.drawinfo
.start
.offset
.over
= 0;
1236 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1237 draw_context
.drawinfo
.start
.offset
.under
= 0;
1238 draw_context
.drawinfo
.end
.offset
.over
= 0;
1239 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1240 draw_context
.drawinfo
.end
.offset
.under
= 0;
1244 PropertiesLine prop_line
= prepare_s_e_line(process
);
1245 draw_line((void*)&prop_line
, (void*)&draw_context
);
1248 /* become the last x position */
1249 hashed_process_data
->x
.middle
= x
;
1250 hashed_process_data
->x
.middle_used
= TRUE
;
1251 hashed_process_data
->x
.middle_marked
= FALSE
;
1253 /* Calculate the next good time */
1254 convert_pixels_to_time(width
, x
+1, time_window
,
1255 &hashed_process_data
->next_good_time
);
1265 /* before_process_release_hook
1267 * Draw lines for process event.
1269 * @param hook_data ControlFlowData structure of the viewer.
1270 * @param call_data Event context.
1272 * This function adds items to be drawn in a queue for each process.
1277 int before_process_release_hook(void *hook_data
, void *call_data
)
1279 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1280 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1282 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1284 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1286 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1288 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1291 e
= ltt_tracefile_get_event(tfc
->tf
);
1293 LttvFilter
*filter
= control_flow_data
->filter
;
1294 if(filter
!= NULL
&& filter
->head
!= NULL
)
1295 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1296 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1299 LttTime evtime
= ltt_event_time(e
);
1301 guint trace_num
= ts
->parent
.index
;
1305 pid
= ltt_event_get_long_unsigned(e
, thf
->f1
);
1308 /* Add process to process list (if not present) */
1309 /* Don't care about the process if it's not in the state hash already :
1310 * that means a process that has never done anything in the trace and
1311 * unknown suddently gets destroyed : no state meaningful to show. */
1312 LttvProcessState
*process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1314 if(process
!= NULL
) {
1316 guint pl_height
= 0;
1317 HashedProcessData
*hashed_process_data
= NULL
;
1319 ProcessList
*process_list
= control_flow_data
->process_list
;
1321 birth
= process
->creation_time
;
1323 /* Cannot use current process : this event happens on another process,
1324 * action done by the parent. */
1325 hashed_process_data
= processlist_get_process_data(process_list
,
1330 if(unlikely(hashed_process_data
== NULL
))
1332 g_assert(pid
== 0 || pid
!= process
->ppid
);
1333 /* Process not present */
1334 Drawing_t
*drawing
= control_flow_data
->drawing
;
1335 ProcessInfo
*process_info
;
1336 processlist_add(process_list
,
1348 &hashed_process_data
);
1349 gtk_widget_set_size_request(drawing
->drawing_area
,
1352 gtk_widget_queue_draw(drawing
->drawing_area
);
1355 /* Now, the process is in the state hash and our own process hash.
1356 * We definitely can draw the items related to the ending state.
1359 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1362 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1363 TimeWindow time_window
=
1364 lttvwindow_get_time_window(control_flow_data
->tab
);
1367 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1368 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1370 #endif //EXTRA_CHECK
1371 Drawing_t
*drawing
= control_flow_data
->drawing
;
1372 guint width
= drawing
->width
;
1374 convert_time_to_pixels(
1380 /* Draw collision indicator */
1381 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1382 gdk_draw_point(hashed_process_data
->pixmap
,
1385 COLLISION_POSITION(hashed_process_data
->height
));
1386 hashed_process_data
->x
.middle_marked
= TRUE
;
1389 TimeWindow time_window
=
1390 lttvwindow_get_time_window(control_flow_data
->tab
);
1393 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1394 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1396 #endif //EXTRA_CHECK
1397 Drawing_t
*drawing
= control_flow_data
->drawing
;
1398 guint width
= drawing
->width
;
1401 convert_time_to_pixels(
1408 /* Jump over draw if we are at the same x position */
1409 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1410 hashed_process_data
->x
.middle_used
))
1412 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1413 /* Draw collision indicator */
1414 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1415 gdk_draw_point(hashed_process_data
->pixmap
,
1418 COLLISION_POSITION(hashed_process_data
->height
));
1419 hashed_process_data
->x
.middle_marked
= TRUE
;
1423 DrawContext draw_context
;
1425 /* Now create the drawing context that will be used to draw
1426 * items related to the last state. */
1427 draw_context
.drawable
= hashed_process_data
->pixmap
;
1428 draw_context
.gc
= drawing
->gc
;
1429 draw_context
.pango_layout
= drawing
->pango_layout
;
1430 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1431 draw_context
.drawinfo
.end
.x
= x
;
1433 draw_context
.drawinfo
.y
.over
= 1;
1434 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1435 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1437 draw_context
.drawinfo
.start
.offset
.over
= 0;
1438 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1439 draw_context
.drawinfo
.start
.offset
.under
= 0;
1440 draw_context
.drawinfo
.end
.offset
.over
= 0;
1441 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1442 draw_context
.drawinfo
.end
.offset
.under
= 0;
1446 PropertiesLine prop_line
= prepare_s_e_line(process
);
1447 draw_line((void*)&prop_line
, (void*)&draw_context
);
1450 /* become the last x position */
1451 hashed_process_data
->x
.middle
= x
;
1452 hashed_process_data
->x
.middle_used
= TRUE
;
1453 hashed_process_data
->x
.middle_marked
= FALSE
;
1455 /* Calculate the next good time */
1456 convert_pixels_to_time(width
, x
+1, time_window
,
1457 &hashed_process_data
->next_good_time
);
1469 /* after_process_fork_hook
1471 * Create the processlist entry for the child process. Put the last
1472 * position in x at the current time value.
1474 * @param hook_data ControlFlowData structure of the viewer.
1475 * @param call_data Event context.
1477 * This function adds items to be drawn in a queue for each process.
1480 int after_process_fork_hook(void *hook_data
, void *call_data
)
1482 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1483 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1484 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1486 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1488 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1490 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1493 e
= ltt_tracefile_get_event(tfc
->tf
);
1495 LttvFilter
*filter
= control_flow_data
->filter
;
1496 if(filter
!= NULL
&& filter
->head
!= NULL
)
1497 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1498 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1501 LttTime evtime
= ltt_event_time(e
);
1505 child_pid
= ltt_event_get_long_unsigned(e
, thf
->f2
);
1508 /* Add process to process list (if not present) */
1509 LttvProcessState
*process_child
;
1511 guint pl_height
= 0;
1512 HashedProcessData
*hashed_process_data_child
= NULL
;
1514 ProcessList
*process_list
= control_flow_data
->process_list
;
1516 /* Find child in the list... */
1517 process_child
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1518 /* It should exist, because we are after the state update. */
1519 g_assert(process_child
!= NULL
);
1521 birth
= process_child
->creation_time
;
1522 guint trace_num
= ts
->parent
.index
;
1524 /* Cannot use current process, because this action is done by the parent
1526 hashed_process_data_child
= processlist_get_process_data(process_list
,
1531 if(likely(hashed_process_data_child
== NULL
))
1533 g_assert(child_pid
== 0 || child_pid
!= process_child
->ppid
);
1534 /* Process not present */
1535 Drawing_t
*drawing
= control_flow_data
->drawing
;
1536 ProcessInfo
*process_info
;
1537 processlist_add(process_list
,
1540 process_child
->tgid
,
1542 process_child
->ppid
,
1545 process_child
->name
,
1546 process_child
->brand
,
1549 &hashed_process_data_child
);
1550 gtk_widget_set_size_request(drawing
->drawing_area
,
1553 gtk_widget_queue_draw(drawing
->drawing_area
);
1555 processlist_set_ppid(process_list
, process_child
->ppid
,
1556 hashed_process_data_child
);
1557 processlist_set_tgid(process_list
, process_child
->tgid
,
1558 hashed_process_data_child
);
1562 if(likely(ltt_time_compare(hashed_process_data_child
->next_good_time
,
1565 TimeWindow time_window
=
1566 lttvwindow_get_time_window(control_flow_data
->tab
);
1569 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1570 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1572 #endif //EXTRA_CHECK
1573 Drawing_t
*drawing
= control_flow_data
->drawing
;
1574 guint width
= drawing
->width
;
1576 convert_time_to_pixels(
1582 if(likely(hashed_process_data_child
->x
.over
!= new_x
)) {
1583 hashed_process_data_child
->x
.over
= new_x
;
1584 hashed_process_data_child
->x
.over_used
= FALSE
;
1585 hashed_process_data_child
->x
.over_marked
= FALSE
;
1587 if(likely(hashed_process_data_child
->x
.middle
!= new_x
)) {
1588 hashed_process_data_child
->x
.middle
= new_x
;
1589 hashed_process_data_child
->x
.middle_used
= FALSE
;
1590 hashed_process_data_child
->x
.middle_marked
= FALSE
;
1592 if(likely(hashed_process_data_child
->x
.under
!= new_x
)) {
1593 hashed_process_data_child
->x
.under
= new_x
;
1594 hashed_process_data_child
->x
.under_used
= FALSE
;
1595 hashed_process_data_child
->x
.under_marked
= FALSE
;
1603 /* after_process_exit_hook
1605 * Create the processlist entry for the child process. Put the last
1606 * position in x at the current time value.
1608 * @param hook_data ControlFlowData structure of the viewer.
1609 * @param call_data Event context.
1611 * This function adds items to be drawn in a queue for each process.
1614 int after_process_exit_hook(void *hook_data
, void *call_data
)
1616 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1617 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1618 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1620 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1622 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1624 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1627 e
= ltt_tracefile_get_event(tfc
->tf
);
1629 LttvFilter
*filter
= control_flow_data
->filter
;
1630 if(filter
!= NULL
&& filter
->head
!= NULL
)
1631 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1632 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1635 LttTime evtime
= ltt_event_time(e
);
1637 /* Add process to process list (if not present) */
1638 //LttvProcessState *process = tfs->process;
1639 guint cpu
= tfs
->cpu
;
1640 guint trace_num
= ts
->parent
.index
;
1641 LttvProcessState
*process
= ts
->running_process
[cpu
];
1643 /* It should exist, because we are after the state update. */
1644 g_assert(process
!= NULL
);
1646 guint pid
= process
->pid
;
1648 guint pl_height
= 0;
1649 HashedProcessData
*hashed_process_data
= NULL
;
1651 ProcessList
*process_list
= control_flow_data
->process_list
;
1653 birth
= process
->creation_time
;
1655 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
) ){
1656 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1658 hashed_process_data
= processlist_get_process_data(process_list
,
1663 if(unlikely(hashed_process_data
== NULL
))
1665 g_assert(pid
== 0 || pid
!= process
->ppid
);
1666 /* Process not present */
1667 Drawing_t
*drawing
= control_flow_data
->drawing
;
1668 ProcessInfo
*process_info
;
1669 processlist_add(process_list
,
1681 &hashed_process_data
);
1682 gtk_widget_set_size_request(drawing
->drawing_area
,
1685 gtk_widget_queue_draw(drawing
->drawing_area
);
1688 /* Set the current process */
1689 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1690 hashed_process_data
;
1693 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
1696 TimeWindow time_window
=
1697 lttvwindow_get_time_window(control_flow_data
->tab
);
1700 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1701 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1703 #endif //EXTRA_CHECK
1704 Drawing_t
*drawing
= control_flow_data
->drawing
;
1705 guint width
= drawing
->width
;
1707 convert_time_to_pixels(
1712 if(unlikely(hashed_process_data
->x
.middle
!= new_x
)) {
1713 hashed_process_data
->x
.middle
= new_x
;
1714 hashed_process_data
->x
.middle_used
= FALSE
;
1715 hashed_process_data
->x
.middle_marked
= FALSE
;
1723 /* Get the filename of the process to print */
1724 int after_fs_exec_hook(void *hook_data
, void *call_data
)
1726 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1727 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1728 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1730 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1732 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1734 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1737 e
= ltt_tracefile_get_event(tfc
->tf
);
1739 LttvFilter
*filter
= control_flow_data
->filter
;
1740 if(filter
!= NULL
&& filter
->head
!= NULL
)
1741 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1742 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1745 guint cpu
= tfs
->cpu
;
1746 guint trace_num
= ts
->parent
.index
;
1747 LttvProcessState
*process
= ts
->running_process
[cpu
];
1748 g_assert(process
!= NULL
);
1750 guint pid
= process
->pid
;
1752 /* Well, the process_out existed : we must get it in the process hash
1753 * or add it, and draw its items.
1755 /* Add process to process list (if not present) */
1756 guint pl_height
= 0;
1757 HashedProcessData
*hashed_process_data
= NULL
;
1758 ProcessList
*process_list
= control_flow_data
->process_list
;
1759 LttTime birth
= process
->creation_time
;
1761 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1762 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1764 hashed_process_data
= processlist_get_process_data(process_list
,
1769 if(unlikely(hashed_process_data
== NULL
))
1771 g_assert(pid
== 0 || pid
!= process
->ppid
);
1772 ProcessInfo
*process_info
;
1773 /* Process not present */
1774 Drawing_t
*drawing
= control_flow_data
->drawing
;
1775 processlist_add(process_list
,
1787 &hashed_process_data
);
1788 gtk_widget_set_size_request(drawing
->drawing_area
,
1791 gtk_widget_queue_draw(drawing
->drawing_area
);
1793 /* Set the current process */
1794 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1795 hashed_process_data
;
1798 processlist_set_name(process_list
, process
->name
, hashed_process_data
);
1804 /* Get the filename of the process to print */
1805 int after_user_generic_thread_brand_hook(void *hook_data
, void *call_data
)
1807 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1808 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1809 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1811 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1813 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1815 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1818 e
= ltt_tracefile_get_event(tfc
->tf
);
1820 LttvFilter
*filter
= control_flow_data
->filter
;
1821 if(filter
!= NULL
&& filter
->head
!= NULL
)
1822 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1823 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1826 guint cpu
= tfs
->cpu
;
1827 guint trace_num
= ts
->parent
.index
;
1828 LttvProcessState
*process
= ts
->running_process
[cpu
];
1829 g_assert(process
!= NULL
);
1831 guint pid
= process
->pid
;
1833 /* Well, the process_out existed : we must get it in the process hash
1834 * or add it, and draw its items.
1836 /* Add process to process list (if not present) */
1837 guint pl_height
= 0;
1838 HashedProcessData
*hashed_process_data
= NULL
;
1839 ProcessList
*process_list
= control_flow_data
->process_list
;
1840 LttTime birth
= process
->creation_time
;
1842 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1843 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1845 hashed_process_data
= processlist_get_process_data(process_list
,
1850 if(unlikely(hashed_process_data
== NULL
))
1852 g_assert(pid
== 0 || pid
!= process
->ppid
);
1853 ProcessInfo
*process_info
;
1854 /* Process not present */
1855 Drawing_t
*drawing
= control_flow_data
->drawing
;
1856 processlist_add(process_list
,
1868 &hashed_process_data
);
1869 gtk_widget_set_size_request(drawing
->drawing_area
,
1872 gtk_widget_queue_draw(drawing
->drawing_area
);
1874 /* Set the current process */
1875 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1876 hashed_process_data
;
1879 processlist_set_brand(process_list
, process
->brand
, hashed_process_data
);
1886 /* after_event_enum_process_hook
1888 * Create the processlist entry for the child process. Put the last
1889 * position in x at the current time value.
1891 * @param hook_data ControlFlowData structure of the viewer.
1892 * @param call_data Event context.
1894 * This function adds items to be drawn in a queue for each process.
1897 int after_event_enum_process_hook(void *hook_data
, void *call_data
)
1899 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1900 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1901 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1903 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1905 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1907 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1909 guint first_cpu
, nb_cpus
, cpu
;
1912 e
= ltt_tracefile_get_event(tfc
->tf
);
1914 LttvFilter
*filter
= control_flow_data
->filter
;
1915 if(filter
!= NULL
&& filter
->head
!= NULL
)
1916 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1917 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1920 LttTime evtime
= ltt_event_time(e
);
1922 /* Add process to process list (if not present) */
1923 LttvProcessState
*process_in
;
1925 guint pl_height
= 0;
1926 HashedProcessData
*hashed_process_data_in
= NULL
;
1928 ProcessList
*process_list
= control_flow_data
->process_list
;
1929 guint trace_num
= ts
->parent
.index
;
1933 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f1
);
1938 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1940 first_cpu
= ANY_CPU
;
1941 nb_cpus
= ANY_CPU
+1;
1944 for(cpu
= first_cpu
; cpu
< nb_cpus
; cpu
++) {
1945 /* Find process pid_in in the list... */
1946 process_in
= lttv_state_find_process(ts
, cpu
, pid_in
);
1947 //process_in = tfs->process;
1948 //guint cpu = tfs->cpu;
1949 //guint trace_num = ts->parent.index;
1950 //process_in = ts->running_process[cpu];
1951 /* It should exist, because we are after the state update. */
1953 //g_assert(process_in != NULL);
1954 #endif //EXTRA_CHECK
1955 birth
= process_in
->creation_time
;
1957 hashed_process_data_in
= processlist_get_process_data(process_list
,
1962 if(hashed_process_data_in
== NULL
)
1964 if(pid_in
!= 0 && pid_in
== process_in
->ppid
)
1965 g_critical("TEST %u , %u", pid_in
, process_in
->ppid
);
1966 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
1967 ProcessInfo
*process_info
;
1968 Drawing_t
*drawing
= control_flow_data
->drawing
;
1969 /* Process not present */
1970 processlist_add(process_list
,
1982 &hashed_process_data_in
);
1983 gtk_widget_set_size_request(drawing
->drawing_area
,
1986 gtk_widget_queue_draw(drawing
->drawing_area
);
1988 processlist_set_name(process_list
, process_in
->name
,
1989 hashed_process_data_in
);
1990 processlist_set_ppid(process_list
, process_in
->ppid
,
1991 hashed_process_data_in
);
1992 processlist_set_tgid(process_list
, process_in
->tgid
,
1993 hashed_process_data_in
);
2000 gint
update_time_window_hook(void *hook_data
, void *call_data
)
2002 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2003 Drawing_t
*drawing
= control_flow_data
->drawing
;
2004 ProcessList
*process_list
= control_flow_data
->process_list
;
2006 const TimeWindowNotifyData
*time_window_nofify_data
=
2007 ((const TimeWindowNotifyData
*)call_data
);
2009 TimeWindow
*old_time_window
=
2010 time_window_nofify_data
->old_time_window
;
2011 TimeWindow
*new_time_window
=
2012 time_window_nofify_data
->new_time_window
;
2014 /* Update the ruler */
2015 drawing_update_ruler(control_flow_data
->drawing
,
2019 /* Two cases : zoom in/out or scrolling */
2021 /* In order to make sure we can reuse the old drawing, the scale must
2022 * be the same and the new time interval being partly located in the
2023 * currently shown time interval. (reuse is only for scrolling)
2026 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
2027 old_time_window
->start_time
.tv_sec
,
2028 old_time_window
->start_time
.tv_nsec
,
2029 old_time_window
->time_width
.tv_sec
,
2030 old_time_window
->time_width
.tv_nsec
);
2032 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
2033 new_time_window
->start_time
.tv_sec
,
2034 new_time_window
->start_time
.tv_nsec
,
2035 new_time_window
->time_width
.tv_sec
,
2036 new_time_window
->time_width
.tv_nsec
);
2038 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
2039 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
2041 /* Same scale (scrolling) */
2042 g_info("scrolling");
2043 LttTime
*ns
= &new_time_window
->start_time
;
2044 LttTime
*nw
= &new_time_window
->time_width
;
2045 LttTime
*os
= &old_time_window
->start_time
;
2046 LttTime
*ow
= &old_time_window
->time_width
;
2047 LttTime old_end
= old_time_window
->end_time
;
2048 LttTime new_end
= new_time_window
->end_time
;
2050 //if(ns<os+w && os+w<ns+w)
2051 //if(ns<old_end && os<ns)
2052 if(ltt_time_compare(*ns
, old_end
) == -1
2053 && ltt_time_compare(*os
, *ns
) == -1)
2055 g_info("scrolling near right");
2056 /* Scroll right, keep right part of the screen */
2058 guint width
= control_flow_data
->drawing
->width
;
2059 convert_time_to_pixels(
2065 /* Copy old data to new location */
2066 copy_pixmap_region(process_list
,
2068 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2072 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
2074 if(drawing
->damage_begin
== drawing
->damage_end
)
2075 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
2077 drawing
->damage_begin
= 0;
2079 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2081 /* Clear the data request background, but not SAFETY */
2082 rectangle_pixmap(process_list
,
2083 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2085 drawing
->damage_begin
+SAFETY
, 0,
2086 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2088 gtk_widget_queue_draw(drawing
->drawing_area
);
2089 //gtk_widget_queue_draw_area (drawing->drawing_area,
2091 // control_flow_data->drawing->width,
2092 // control_flow_data->drawing->height);
2094 /* Get new data for the rest. */
2095 drawing_data_request(control_flow_data
->drawing
,
2096 drawing
->damage_begin
, 0,
2097 drawing
->damage_end
- drawing
->damage_begin
,
2098 control_flow_data
->drawing
->height
);
2101 //if(ns<os && os<ns+w)
2102 //if(ns<os && os<new_end)
2103 if(ltt_time_compare(*ns
,*os
) == -1
2104 && ltt_time_compare(*os
,new_end
) == -1)
2106 g_info("scrolling near left");
2107 /* Scroll left, keep left part of the screen */
2109 guint width
= control_flow_data
->drawing
->width
;
2110 convert_time_to_pixels(
2116 /* Copy old data to new location */
2117 copy_pixmap_region (process_list
,
2119 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2125 if(drawing
->damage_begin
== drawing
->damage_end
)
2126 drawing
->damage_end
= x
;
2128 drawing
->damage_end
=
2129 control_flow_data
->drawing
->width
;
2131 drawing
->damage_begin
= 0;
2133 rectangle_pixmap (process_list
,
2134 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2136 drawing
->damage_begin
, 0,
2137 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2140 gtk_widget_queue_draw(drawing
->drawing_area
);
2141 //gtk_widget_queue_draw_area (drawing->drawing_area,
2143 // control_flow_data->drawing->width,
2144 // control_flow_data->drawing->height);
2147 /* Get new data for the rest. */
2148 drawing_data_request(control_flow_data
->drawing
,
2149 drawing
->damage_begin
, 0,
2150 drawing
->damage_end
- drawing
->damage_begin
,
2151 control_flow_data
->drawing
->height
);
2154 if(ltt_time_compare(*ns
,*os
) == 0)
2156 g_info("not scrolling");
2158 g_info("scrolling far");
2159 /* Cannot reuse any part of the screen : far jump */
2162 rectangle_pixmap (process_list
,
2163 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2166 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2169 //gtk_widget_queue_draw_area (drawing->drawing_area,
2171 // control_flow_data->drawing->width,
2172 // control_flow_data->drawing->height);
2173 gtk_widget_queue_draw(drawing
->drawing_area
);
2175 drawing
->damage_begin
= 0;
2176 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2178 drawing_data_request(control_flow_data
->drawing
,
2180 control_flow_data
->drawing
->width
,
2181 control_flow_data
->drawing
->height
);
2187 /* Different scale (zoom) */
2190 rectangle_pixmap (process_list
,
2191 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2194 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2197 //gtk_widget_queue_draw_area (drawing->drawing_area,
2199 // control_flow_data->drawing->width,
2200 // control_flow_data->drawing->height);
2201 gtk_widget_queue_draw(drawing
->drawing_area
);
2203 drawing
->damage_begin
= 0;
2204 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2206 drawing_data_request(control_flow_data
->drawing
,
2208 control_flow_data
->drawing
->width
,
2209 control_flow_data
->drawing
->height
);
2212 /* Update directly when scrolling */
2213 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2219 gint
traceset_notify(void *hook_data
, void *call_data
)
2221 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2222 Drawing_t
*drawing
= control_flow_data
->drawing
;
2224 if(unlikely(drawing
->gc
== NULL
)) {
2227 if(drawing
->dotted_gc
== NULL
) {
2231 drawing_clear(control_flow_data
->drawing
);
2232 processlist_clear(control_flow_data
->process_list
);
2233 gtk_widget_set_size_request(
2234 control_flow_data
->drawing
->drawing_area
,
2235 -1, processlist_get_height(control_flow_data
->process_list
));
2236 redraw_notify(control_flow_data
, NULL
);
2238 request_background_data(control_flow_data
);
2243 gint
redraw_notify(void *hook_data
, void *call_data
)
2245 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2246 Drawing_t
*drawing
= control_flow_data
->drawing
;
2247 GtkWidget
*widget
= drawing
->drawing_area
;
2249 drawing
->damage_begin
= 0;
2250 drawing
->damage_end
= drawing
->width
;
2252 /* fun feature, to be separated someday... */
2253 drawing_clear(control_flow_data
->drawing
);
2254 processlist_clear(control_flow_data
->process_list
);
2255 gtk_widget_set_size_request(
2256 control_flow_data
->drawing
->drawing_area
,
2257 -1, processlist_get_height(control_flow_data
->process_list
));
2259 rectangle_pixmap (control_flow_data
->process_list
,
2260 widget
->style
->black_gc
,
2263 drawing
->alloc_width
,
2266 gtk_widget_queue_draw(drawing
->drawing_area
);
2268 if(drawing
->damage_begin
< drawing
->damage_end
)
2270 drawing_data_request(drawing
,
2271 drawing
->damage_begin
,
2273 drawing
->damage_end
-drawing
->damage_begin
,
2277 //gtk_widget_queue_draw_area(drawing->drawing_area,
2280 // drawing->height);
2286 gint
continue_notify(void *hook_data
, void *call_data
)
2288 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2289 Drawing_t
*drawing
= control_flow_data
->drawing
;
2291 //g_assert(widget->allocation.width == drawing->damage_end);
2293 if(drawing
->damage_begin
< drawing
->damage_end
)
2295 drawing_data_request(drawing
,
2296 drawing
->damage_begin
,
2298 drawing
->damage_end
-drawing
->damage_begin
,
2306 gint
update_current_time_hook(void *hook_data
, void *call_data
)
2308 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
2309 Drawing_t
*drawing
= control_flow_data
->drawing
;
2311 LttTime current_time
= *((LttTime
*)call_data
);
2313 TimeWindow time_window
=
2314 lttvwindow_get_time_window(control_flow_data
->tab
);
2316 LttTime time_begin
= time_window
.start_time
;
2317 LttTime width
= time_window
.time_width
;
2320 guint64 time_ll
= ltt_time_to_uint64(width
);
2321 time_ll
= time_ll
>> 1; /* divide by two */
2322 half_width
= ltt_time_from_uint64(time_ll
);
2324 LttTime time_end
= ltt_time_add(time_begin
, width
);
2326 LttvTracesetContext
* tsc
=
2327 lttvwindow_get_traceset_context(control_flow_data
->tab
);
2329 LttTime trace_start
= tsc
->time_span
.start_time
;
2330 LttTime trace_end
= tsc
->time_span
.end_time
;
2332 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
2333 current_time
.tv_nsec
);
2337 /* If current time is inside time interval, just move the highlight
2340 /* Else, we have to change the time interval. We have to tell it
2341 * to the main window. */
2342 /* The time interval change will take care of placing the current
2343 * time at the center of the visible area, or nearest possible if we are
2344 * at one end of the trace. */
2347 if(ltt_time_compare(current_time
, time_begin
) < 0)
2349 TimeWindow new_time_window
;
2351 if(ltt_time_compare(current_time
,
2352 ltt_time_add(trace_start
,half_width
)) < 0)
2353 time_begin
= trace_start
;
2355 time_begin
= ltt_time_sub(current_time
,half_width
);
2357 new_time_window
.start_time
= time_begin
;
2358 new_time_window
.time_width
= width
;
2359 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2360 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2362 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2364 else if(ltt_time_compare(current_time
, time_end
) > 0)
2366 TimeWindow new_time_window
;
2368 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
2369 time_begin
= ltt_time_sub(trace_end
,width
);
2371 time_begin
= ltt_time_sub(current_time
,half_width
);
2373 new_time_window
.start_time
= time_begin
;
2374 new_time_window
.time_width
= width
;
2375 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2376 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2378 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2381 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2383 /* Update directly when scrolling */
2384 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2390 typedef struct _ClosureData
{
2391 EventsRequest
*events_request
;
2392 LttvTracesetState
*tss
;
2398 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
2400 ProcessInfo
*process_info
= (ProcessInfo
*)key
;
2401 HashedProcessData
*hashed_process_data
= (HashedProcessData
*)value
;
2402 ClosureData
*closure_data
= (ClosureData
*)user_data
;
2404 EventsRequest
*events_request
= closure_data
->events_request
;
2405 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2407 LttvTracesetState
*tss
= closure_data
->tss
;
2408 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)tss
;
2410 LttTime evtime
= closure_data
->end_time
;
2412 gboolean dodraw
= TRUE
;
2415 /* For the process */
2416 /* First, check if the current process is in the state computation
2417 * process list. If it is there, that means we must add it right now and
2418 * draw items from the beginning of the read for it. If it is not
2419 * present, it's a new process and it was not present : it will
2420 * be added after the state update. */
2422 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
2423 #endif //EXTRA_CHECK
2424 LttvTraceContext
*tc
= tsc
->traces
[process_info
->trace_num
];
2425 LttvTraceState
*ts
= (LttvTraceState
*)tc
;
2428 //FIXME : optimize data structures.
2429 LttvTracefileState
*tfs
;
2430 LttvTracefileContext
*tfc
;
2432 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
2433 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
2434 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
2435 && tfs
->cpu
== process_info
->cpu
)
2439 g_assert(i
<tc
->tracefiles
->len
);
2440 tfs
= LTTV_TRACEFILE_STATE(tfc
);
2442 // LttvTracefileState *tfs =
2443 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2444 // tracefiles[process_info->cpu];
2446 LttvProcessState
*process
;
2447 process
= lttv_state_find_process(ts
, process_info
->cpu
,
2450 if(unlikely(process
!= NULL
)) {
2452 LttvFilter
*filter
= control_flow_data
->filter
;
2453 if(filter
!= NULL
&& filter
->head
!= NULL
)
2454 if(!lttv_filter_tree_parse(filter
->head
,NULL
,NULL
,
2455 tc
->t
,NULL
,process
,tc
))
2458 /* Only draw for processes that are currently in the trace states */
2460 ProcessList
*process_list
= control_flow_data
->process_list
;
2462 /* Should be alike when background info is ready */
2463 if(control_flow_data
->background_info_waiting
==0)
2464 g_assert(ltt_time_compare(process
->creation_time
,
2465 process_info
->birth
) == 0);
2466 #endif //EXTRA_CHECK
2468 /* Now, the process is in the state hash and our own process hash.
2469 * We definitely can draw the items related to the ending state.
2472 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2475 TimeWindow time_window
=
2476 lttvwindow_get_time_window(control_flow_data
->tab
);
2479 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2480 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2482 #endif //EXTRA_CHECK
2483 Drawing_t
*drawing
= control_flow_data
->drawing
;
2484 guint width
= drawing
->width
;
2486 guint x
= closure_data
->x_end
;
2488 DrawContext draw_context
;
2490 /* Now create the drawing context that will be used to draw
2491 * items related to the last state. */
2492 draw_context
.drawable
= hashed_process_data
->pixmap
;
2493 draw_context
.gc
= drawing
->gc
;
2494 draw_context
.pango_layout
= drawing
->pango_layout
;
2495 draw_context
.drawinfo
.end
.x
= x
;
2497 draw_context
.drawinfo
.y
.over
= 1;
2498 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2499 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2501 draw_context
.drawinfo
.start
.offset
.over
= 0;
2502 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2503 draw_context
.drawinfo
.start
.offset
.under
= 0;
2504 draw_context
.drawinfo
.end
.offset
.over
= 0;
2505 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2506 draw_context
.drawinfo
.end
.offset
.under
= 0;
2508 /* Jump over draw if we are at the same x position */
2509 if(x
== hashed_process_data
->x
.over
)
2513 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2515 PropertiesLine prop_line
= prepare_execmode_line(process
);
2516 draw_line((void*)&prop_line
, (void*)&draw_context
);
2518 hashed_process_data
->x
.over
= x
;
2522 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2523 hashed_process_data
->x
.middle_used
)) {
2524 #if 0 /* do not mark closure : not missing information */
2525 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2526 /* Draw collision indicator */
2527 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2528 gdk_draw_point(drawing
->pixmap
,
2532 hashed_process_data
->x
.middle_marked
= TRUE
;
2537 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2540 PropertiesLine prop_line
= prepare_s_e_line(process
);
2541 draw_line((void*)&prop_line
, (void*)&draw_context
);
2544 /* become the last x position */
2545 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2546 hashed_process_data
->x
.middle
= x
;
2547 /* but don't use the pixel */
2548 hashed_process_data
->x
.middle_used
= FALSE
;
2550 /* Calculate the next good time */
2551 convert_pixels_to_time(width
, x
+1, time_window
,
2552 &hashed_process_data
->next_good_time
);
2561 int before_chunk(void *hook_data
, void *call_data
)
2563 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2564 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2565 ControlFlowData
*cfd
= (ControlFlowData
*)events_request
->viewer_data
;
2567 /* Desactivate sort */
2568 gtk_tree_sortable_set_sort_column_id(
2569 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2571 GTK_SORT_ASCENDING
);
2573 drawing_chunk_begin(events_request
, tss
);
2578 int before_request(void *hook_data
, void *call_data
)
2580 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2581 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2583 drawing_data_request_begin(events_request
, tss
);
2590 * after request is necessary in addition of after chunk in order to draw
2591 * lines until the end of the screen. after chunk just draws lines until
2598 int after_request(void *hook_data
, void *call_data
)
2600 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2601 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2602 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2604 ProcessList
*process_list
= control_flow_data
->process_list
;
2605 LttTime 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
);
2622 /* Draw last items */
2623 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2624 (void*)&closure_data
);
2627 /* Request expose */
2628 drawing_request_expose(events_request
, tss
, end_time
);
2637 int after_chunk(void *hook_data
, void *call_data
)
2639 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2640 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2641 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2642 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)call_data
;
2643 LttvTracefileContext
*tfc
= lttv_traceset_context_get_current_tfc(tsc
);
2646 ProcessList
*process_list
= control_flow_data
->process_list
;
2648 LttvTraceset
*traceset
= tsc
->ts
;
2649 guint nb_trace
= lttv_traceset_number(traceset
);
2651 /* Only execute when called for the first trace's events request */
2652 if(!process_list
->current_hash_data
) return;
2654 for(i
= 0 ; i
< nb_trace
; i
++) {
2655 g_free(process_list
->current_hash_data
[i
]);
2657 g_free(process_list
->current_hash_data
);
2658 process_list
->current_hash_data
= NULL
;
2661 end_time
= LTT_TIME_MIN(tfc
->timestamp
, events_request
->end_time
);
2662 else /* end of traceset, or position now out of request : end */
2663 end_time
= events_request
->end_time
;
2665 ClosureData closure_data
;
2666 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2667 closure_data
.tss
= tss
;
2668 closure_data
.end_time
= end_time
;
2670 TimeWindow time_window
=
2671 lttvwindow_get_time_window(control_flow_data
->tab
);
2672 guint width
= control_flow_data
->drawing
->width
;
2673 convert_time_to_pixels(
2677 &closure_data
.x_end
);
2679 /* Draw last items */
2680 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2681 (void*)&closure_data
);
2683 /* Reactivate sort */
2684 gtk_tree_sortable_set_sort_column_id(
2685 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2686 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2687 GTK_SORT_ASCENDING
);
2689 update_index_to_pixmap(control_flow_data
->process_list
);
2690 /* Request a full expose : drawing scrambled */
2691 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2693 /* Request expose (updates damages zone also) */
2694 drawing_request_expose(events_request
, tss
, end_time
);
2699 /* after_statedump_end
2701 * @param hook_data ControlFlowData structure of the viewer.
2702 * @param call_data Event context.
2704 * This function adds items to be drawn in a queue for each process.
2707 int before_statedump_end(void *hook_data
, void *call_data
)
2709 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2710 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
2711 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2713 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2715 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
2717 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
2719 LttvTracesetState
*tss
= (LttvTracesetState
*)tfc
->t_context
->ts_context
;
2720 ProcessList
*process_list
= control_flow_data
->process_list
;
2723 e
= ltt_tracefile_get_event(tfc
->tf
);
2725 LttvFilter
*filter
= control_flow_data
->filter
;
2726 if(filter
!= NULL
&& filter
->head
!= NULL
)
2727 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2728 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2731 LttTime evtime
= ltt_event_time(e
);
2733 ClosureData closure_data
;
2734 closure_data
.events_request
= events_request
;
2735 closure_data
.tss
= tss
;
2736 closure_data
.end_time
= evtime
;
2738 TimeWindow time_window
=
2739 lttvwindow_get_time_window(control_flow_data
->tab
);
2740 guint width
= control_flow_data
->drawing
->width
;
2741 convert_time_to_pixels(
2745 &closure_data
.x_end
);
2747 /* Draw last items */
2748 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2749 (void*)&closure_data
);
2751 /* Reactivate sort */
2752 gtk_tree_sortable_set_sort_column_id(
2753 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2754 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2755 GTK_SORT_ASCENDING
);
2757 update_index_to_pixmap(control_flow_data
->process_list
);
2758 /* Request a full expose : drawing scrambled */
2759 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2761 /* Request expose (updates damages zone also) */
2762 drawing_request_expose(events_request
, tss
, evtime
);