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
);
370 tfc
->target_pid
= pid_out
;
371 if(!filter
|| !filter
->head
||
372 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
373 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
374 /* For the pid_out */
375 /* First, check if the current process is in the state computation
376 * process list. If it is there, that means we must add it right now and
377 * draw items from the beginning of the read for it. If it is not
378 * present, it's a new process and it was not present : it will
379 * be added after the state update. */
380 guint cpu
= tfs
->cpu
;
381 guint trace_num
= ts
->parent
.index
;
382 LttvProcessState
*process
= ts
->running_process
[cpu
];
383 /* unknown state, bad current pid */
384 if(process
->pid
!= pid_out
)
385 process
= lttv_state_find_process(ts
,
388 if(process
!= NULL
) {
389 /* Well, the process_out existed : we must get it in the process hash
390 * or add it, and draw its items.
392 /* Add process to process list (if not present) */
394 HashedProcessData
*hashed_process_data
= NULL
;
395 ProcessList
*process_list
= control_flow_data
->process_list
;
396 LttTime birth
= process
->creation_time
;
398 hashed_process_data
= processlist_get_process_data(process_list
,
403 if(hashed_process_data
== NULL
)
405 g_assert(pid_out
== 0 || pid_out
!= process
->ppid
);
406 /* Process not present */
407 ProcessInfo
*process_info
;
408 Drawing_t
*drawing
= control_flow_data
->drawing
;
409 processlist_add(process_list
,
421 &hashed_process_data
);
422 gtk_widget_set_size_request(drawing
->drawing_area
,
425 gtk_widget_queue_draw(drawing
->drawing_area
);
429 /* Now, the process is in the state hash and our own process hash.
430 * We definitely can draw the items related to the ending state.
433 if(ltt_time_compare(hashed_process_data
->next_good_time
,
436 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
438 TimeWindow time_window
=
439 lttvwindow_get_time_window(control_flow_data
->tab
);
441 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
442 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
445 Drawing_t
*drawing
= control_flow_data
->drawing
;
446 guint width
= drawing
->width
;
448 convert_time_to_pixels(
454 /* Draw collision indicator */
455 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
456 gdk_draw_point(hashed_process_data
->pixmap
,
459 COLLISION_POSITION(hashed_process_data
->height
));
460 hashed_process_data
->x
.middle_marked
= TRUE
;
463 TimeWindow time_window
=
464 lttvwindow_get_time_window(control_flow_data
->tab
);
466 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
467 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
470 Drawing_t
*drawing
= control_flow_data
->drawing
;
471 guint width
= drawing
->width
;
473 convert_time_to_pixels(
480 /* Jump over draw if we are at the same x position */
481 if(x
== hashed_process_data
->x
.middle
&&
482 hashed_process_data
->x
.middle_used
)
484 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
485 /* Draw collision indicator */
486 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
487 gdk_draw_point(hashed_process_data
->pixmap
,
490 COLLISION_POSITION(hashed_process_data
->height
));
491 hashed_process_data
->x
.middle_marked
= TRUE
;
495 DrawContext draw_context
;
497 /* Now create the drawing context that will be used to draw
498 * items related to the last state. */
499 draw_context
.drawable
= hashed_process_data
->pixmap
;
500 draw_context
.gc
= drawing
->gc
;
501 draw_context
.pango_layout
= drawing
->pango_layout
;
502 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
503 draw_context
.drawinfo
.end
.x
= x
;
505 draw_context
.drawinfo
.y
.over
= 1;
506 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
507 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
509 draw_context
.drawinfo
.start
.offset
.over
= 0;
510 draw_context
.drawinfo
.start
.offset
.middle
= 0;
511 draw_context
.drawinfo
.start
.offset
.under
= 0;
512 draw_context
.drawinfo
.end
.offset
.over
= 0;
513 draw_context
.drawinfo
.end
.offset
.middle
= 0;
514 draw_context
.drawinfo
.end
.offset
.under
= 0;
518 PropertiesLine prop_line
= prepare_s_e_line(process
);
519 draw_line((void*)&prop_line
, (void*)&draw_context
);
522 /* become the last x position */
523 hashed_process_data
->x
.middle
= x
;
524 hashed_process_data
->x
.middle_used
= TRUE
;
525 hashed_process_data
->x
.middle_marked
= FALSE
;
527 /* Calculate the next good time */
528 convert_pixels_to_time(width
, x
+1, time_window
,
529 &hashed_process_data
->next_good_time
);
535 tfc
->target_pid
= pid_in
;
536 if(!filter
|| !filter
->head
||
537 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
538 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
540 /* First, check if the current process is in the state computation
541 * process list. If it is there, that means we must add it right now and
542 * draw items from the beginning of the read for it. If it is not
543 * present, it's a new process and it was not present : it will
544 * be added after the state update. */
545 LttvProcessState
*process
;
546 process
= lttv_state_find_process(ts
,
548 guint trace_num
= ts
->parent
.index
;
550 if(process
!= NULL
) {
551 /* Well, the process existed : we must get it in the process hash
552 * or add it, and draw its items.
554 /* Add process to process list (if not present) */
556 HashedProcessData
*hashed_process_data
= NULL
;
557 ProcessList
*process_list
= control_flow_data
->process_list
;
558 LttTime birth
= process
->creation_time
;
560 hashed_process_data
= processlist_get_process_data(process_list
,
565 if(hashed_process_data
== NULL
)
567 g_assert(pid_in
== 0 || pid_in
!= process
->ppid
);
568 /* Process not present */
569 ProcessInfo
*process_info
;
570 Drawing_t
*drawing
= control_flow_data
->drawing
;
571 processlist_add(process_list
,
583 &hashed_process_data
);
584 gtk_widget_set_size_request(drawing
->drawing_area
,
587 gtk_widget_queue_draw(drawing
->drawing_area
);
590 //We could set the current process and hash here, but will be done
591 //by after schedchange hook
593 /* Now, the process is in the state hash and our own process hash.
594 * We definitely can draw the items related to the ending state.
597 if(ltt_time_compare(hashed_process_data
->next_good_time
,
600 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
602 TimeWindow time_window
=
603 lttvwindow_get_time_window(control_flow_data
->tab
);
605 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
606 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
609 Drawing_t
*drawing
= control_flow_data
->drawing
;
610 guint width
= drawing
->width
;
612 convert_time_to_pixels(
618 /* Draw collision indicator */
619 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
620 gdk_draw_point(hashed_process_data
->pixmap
,
623 COLLISION_POSITION(hashed_process_data
->height
));
624 hashed_process_data
->x
.middle_marked
= TRUE
;
627 TimeWindow time_window
=
628 lttvwindow_get_time_window(control_flow_data
->tab
);
630 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
631 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
634 Drawing_t
*drawing
= control_flow_data
->drawing
;
635 guint width
= drawing
->width
;
638 convert_time_to_pixels(
645 /* Jump over draw if we are at the same x position */
646 if(x
== hashed_process_data
->x
.middle
&&
647 hashed_process_data
->x
.middle_used
)
649 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
650 /* Draw collision indicator */
651 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
652 gdk_draw_point(hashed_process_data
->pixmap
,
655 COLLISION_POSITION(hashed_process_data
->height
));
656 hashed_process_data
->x
.middle_marked
= TRUE
;
660 DrawContext draw_context
;
662 /* Now create the drawing context that will be used to draw
663 * items related to the last state. */
664 draw_context
.drawable
= hashed_process_data
->pixmap
;
665 draw_context
.gc
= drawing
->gc
;
666 draw_context
.pango_layout
= drawing
->pango_layout
;
667 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
668 draw_context
.drawinfo
.end
.x
= x
;
670 draw_context
.drawinfo
.y
.over
= 1;
671 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
672 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
674 draw_context
.drawinfo
.start
.offset
.over
= 0;
675 draw_context
.drawinfo
.start
.offset
.middle
= 0;
676 draw_context
.drawinfo
.start
.offset
.under
= 0;
677 draw_context
.drawinfo
.end
.offset
.over
= 0;
678 draw_context
.drawinfo
.end
.offset
.middle
= 0;
679 draw_context
.drawinfo
.end
.offset
.under
= 0;
683 PropertiesLine prop_line
= prepare_s_e_line(process
);
684 draw_line((void*)&prop_line
, (void*)&draw_context
);
688 /* become the last x position */
689 hashed_process_data
->x
.middle
= x
;
690 hashed_process_data
->x
.middle_used
= TRUE
;
691 hashed_process_data
->x
.middle_marked
= FALSE
;
693 /* Calculate the next good time */
694 convert_pixels_to_time(width
, x
+1, time_window
,
695 &hashed_process_data
->next_good_time
);
699 g_warning("Cannot find pin_in in schedchange %u", pid_in
);
701 tfc
->target_pid
= target_pid_saved
;
709 GString
*string
= g_string_new("");;
710 gboolean field_names
= TRUE
, state
= TRUE
;
712 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
713 g_string_append_printf(string
,"\n");
716 g_string_append_printf(string
, " %s",
717 g_quark_to_string(tfs
->process
->state
->s
));
720 g_info("%s",string
->str
);
722 g_string_free(string
, TRUE
);
724 /* End of text dump */
729 /* after_schedchange_hook
731 * The draw after hook is called by the reading API to have a
732 * particular event drawn on the screen.
733 * @param hook_data ControlFlowData structure of the viewer.
734 * @param call_data Event context.
736 * This function adds items to be drawn in a queue for each process.
739 int after_schedchange_hook(void *hook_data
, void *call_data
)
741 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
742 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
743 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
745 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
747 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
749 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
752 e
= ltt_tracefile_get_event(tfc
->tf
);
754 LttvFilter
*filter
= control_flow_data
->filter
;
755 if(filter
!= NULL
&& filter
->head
!= NULL
)
756 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
757 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
760 LttTime evtime
= ltt_event_time(e
);
762 /* Add process to process list (if not present) */
763 LttvProcessState
*process_in
;
766 HashedProcessData
*hashed_process_data_in
= NULL
;
768 ProcessList
*process_list
= control_flow_data
->process_list
;
773 pid_out
= ltt_event_get_long_unsigned(e
, thf
->f1
);
774 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f2
);
778 /* Find process pid_in in the list... */
779 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
780 //process_in = tfs->process;
781 guint cpu
= tfs
->cpu
;
782 guint trace_num
= ts
->parent
.index
;
783 process_in
= ts
->running_process
[cpu
];
784 /* It should exist, because we are after the state update. */
786 g_assert(process_in
!= NULL
);
788 birth
= process_in
->creation_time
;
790 hashed_process_data_in
= processlist_get_process_data(process_list
,
795 if(hashed_process_data_in
== NULL
)
797 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
798 ProcessInfo
*process_info
;
799 Drawing_t
*drawing
= control_flow_data
->drawing
;
800 /* Process not present */
801 processlist_add(process_list
,
813 &hashed_process_data_in
);
814 gtk_widget_set_size_request(drawing
->drawing_area
,
817 gtk_widget_queue_draw(drawing
->drawing_area
);
819 /* Set the current process */
820 process_list
->current_hash_data
[trace_num
][process_in
->cpu
] =
821 hashed_process_data_in
;
823 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
826 TimeWindow time_window
=
827 lttvwindow_get_time_window(control_flow_data
->tab
);
830 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
831 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
834 Drawing_t
*drawing
= control_flow_data
->drawing
;
835 guint width
= drawing
->width
;
838 convert_time_to_pixels(
844 if(hashed_process_data_in
->x
.middle
!= new_x
) {
845 hashed_process_data_in
->x
.middle
= new_x
;
846 hashed_process_data_in
->x
.middle_used
= FALSE
;
847 hashed_process_data_in
->x
.middle_marked
= FALSE
;
856 /* before_execmode_hook
858 * This function basically draw lines and icons. Two types of lines are drawn :
859 * one small (3 pixels?) representing the state of the process and the second
860 * type is thicker (10 pixels?) representing on which CPU a process is running
861 * (and this only in running state).
863 * Extremums of the lines :
864 * x_min : time of the last event context for this process kept in memory.
865 * x_max : time of the current event.
866 * y : middle of the process in the process list. The process is found in the
867 * list, therefore is it's position in pixels.
869 * The choice of lines'color is defined by the context of the last event for this
874 int before_execmode_hook(void *hook_data
, void *call_data
)
876 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
877 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
878 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
880 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
882 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
884 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
887 e
= ltt_tracefile_get_event(tfc
->tf
);
889 LttvFilter
*filter
= control_flow_data
->filter
;
890 if(filter
!= NULL
&& filter
->head
!= NULL
)
891 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
892 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
895 LttTime evtime
= ltt_event_time(e
);
897 /* we are in a execmode, before the state update. We must draw the
898 * items corresponding to the state before it changes : now is the right
902 //LttvProcessState *process = tfs->process;
903 guint cpu
= tfs
->cpu
;
904 guint trace_num
= ts
->parent
.index
;
905 LttvProcessState
*process
= ts
->running_process
[cpu
];
906 g_assert(process
!= NULL
);
908 guint pid
= process
->pid
;
910 /* Well, the process_out existed : we must get it in the process hash
911 * or add it, and draw its items.
913 /* Add process to process list (if not present) */
915 HashedProcessData
*hashed_process_data
= NULL
;
916 ProcessList
*process_list
= control_flow_data
->process_list
;
917 LttTime birth
= process
->creation_time
;
919 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
920 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
922 hashed_process_data
= processlist_get_process_data(process_list
,
927 if(unlikely(hashed_process_data
== NULL
))
929 g_assert(pid
== 0 || pid
!= process
->ppid
);
930 ProcessInfo
*process_info
;
931 /* Process not present */
932 Drawing_t
*drawing
= control_flow_data
->drawing
;
933 processlist_add(process_list
,
945 &hashed_process_data
);
946 gtk_widget_set_size_request(drawing
->drawing_area
,
949 gtk_widget_queue_draw(drawing
->drawing_area
);
951 /* Set the current process */
952 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
956 /* Now, the process is in the state hash and our own process hash.
957 * We definitely can draw the items related to the ending state.
960 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
963 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
964 TimeWindow time_window
=
965 lttvwindow_get_time_window(control_flow_data
->tab
);
968 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
969 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
972 Drawing_t
*drawing
= control_flow_data
->drawing
;
973 guint width
= drawing
->width
;
975 convert_time_to_pixels(
981 /* Draw collision indicator */
982 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
983 gdk_draw_point(hashed_process_data
->pixmap
,
986 COLLISION_POSITION(hashed_process_data
->height
));
987 hashed_process_data
->x
.middle_marked
= TRUE
;
990 TimeWindow time_window
=
991 lttvwindow_get_time_window(control_flow_data
->tab
);
994 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
995 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
998 Drawing_t
*drawing
= control_flow_data
->drawing
;
999 guint width
= drawing
->width
;
1002 convert_time_to_pixels(
1009 /* Jump over draw if we are at the same x position */
1010 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1011 hashed_process_data
->x
.middle_used
))
1013 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1014 /* Draw collision indicator */
1015 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1016 gdk_draw_point(hashed_process_data
->pixmap
,
1019 COLLISION_POSITION(hashed_process_data
->height
));
1020 hashed_process_data
->x
.middle_marked
= TRUE
;
1025 DrawContext draw_context
;
1026 /* Now create the drawing context that will be used to draw
1027 * items related to the last state. */
1028 draw_context
.drawable
= hashed_process_data
->pixmap
;
1029 draw_context
.gc
= drawing
->gc
;
1030 draw_context
.pango_layout
= drawing
->pango_layout
;
1031 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1032 draw_context
.drawinfo
.end
.x
= x
;
1034 draw_context
.drawinfo
.y
.over
= 1;
1035 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1036 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1038 draw_context
.drawinfo
.start
.offset
.over
= 0;
1039 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1040 draw_context
.drawinfo
.start
.offset
.under
= 0;
1041 draw_context
.drawinfo
.end
.offset
.over
= 0;
1042 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1043 draw_context
.drawinfo
.end
.offset
.under
= 0;
1047 PropertiesLine prop_line
= prepare_s_e_line(process
);
1048 draw_line((void*)&prop_line
, (void*)&draw_context
);
1051 /* become the last x position */
1052 hashed_process_data
->x
.middle
= x
;
1053 hashed_process_data
->x
.middle_used
= TRUE
;
1054 hashed_process_data
->x
.middle_marked
= FALSE
;
1056 /* Calculate the next good time */
1057 convert_pixels_to_time(width
, x
+1, time_window
,
1058 &hashed_process_data
->next_good_time
);
1065 /* before_process_exit_hook
1067 * Draw lines for process event.
1069 * @param hook_data ControlFlowData structure of the viewer.
1070 * @param call_data Event context.
1072 * This function adds items to be drawn in a queue for each process.
1077 int before_process_exit_hook(void *hook_data
, void *call_data
)
1079 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1080 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1082 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1084 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1086 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1088 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1091 e
= ltt_tracefile_get_event(tfc
->tf
);
1093 LttvFilter
*filter
= control_flow_data
->filter
;
1094 if(filter
!= NULL
&& filter
->head
!= NULL
)
1095 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1096 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1099 LttTime evtime
= ltt_event_time(e
);
1101 /* Add process to process list (if not present) */
1102 //LttvProcessState *process = tfs->process;
1103 guint cpu
= tfs
->cpu
;
1104 guint trace_num
= ts
->parent
.index
;
1105 LttvProcessState
*process
= ts
->running_process
[cpu
];
1106 guint pid
= process
->pid
;
1108 guint pl_height
= 0;
1109 HashedProcessData
*hashed_process_data
= NULL
;
1111 ProcessList
*process_list
= control_flow_data
->process_list
;
1113 g_assert(process
!= NULL
);
1115 birth
= process
->creation_time
;
1117 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1118 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1120 hashed_process_data
= processlist_get_process_data(process_list
,
1125 if(unlikely(hashed_process_data
== NULL
))
1127 g_assert(pid
== 0 || pid
!= process
->ppid
);
1128 /* Process not present */
1129 Drawing_t
*drawing
= control_flow_data
->drawing
;
1130 ProcessInfo
*process_info
;
1131 processlist_add(process_list
,
1143 &hashed_process_data
);
1144 gtk_widget_set_size_request(drawing
->drawing_area
,
1147 gtk_widget_queue_draw(drawing
->drawing_area
);
1151 /* Now, the process is in the state hash and our own process hash.
1152 * We definitely can draw the items related to the ending state.
1155 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1158 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1159 TimeWindow time_window
=
1160 lttvwindow_get_time_window(control_flow_data
->tab
);
1163 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1164 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1166 #endif //EXTRA_CHECK
1167 Drawing_t
*drawing
= control_flow_data
->drawing
;
1168 guint width
= drawing
->width
;
1170 convert_time_to_pixels(
1176 /* Draw collision indicator */
1177 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1178 gdk_draw_point(hashed_process_data
->pixmap
,
1181 COLLISION_POSITION(hashed_process_data
->height
));
1182 hashed_process_data
->x
.middle_marked
= TRUE
;
1185 TimeWindow time_window
=
1186 lttvwindow_get_time_window(control_flow_data
->tab
);
1189 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1190 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1192 #endif //EXTRA_CHECK
1193 Drawing_t
*drawing
= control_flow_data
->drawing
;
1194 guint width
= drawing
->width
;
1197 convert_time_to_pixels(
1204 /* Jump over draw if we are at the same x position */
1205 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1206 hashed_process_data
->x
.middle_used
))
1208 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1209 /* Draw collision indicator */
1210 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1211 gdk_draw_point(hashed_process_data
->pixmap
,
1214 COLLISION_POSITION(hashed_process_data
->height
));
1215 hashed_process_data
->x
.middle_marked
= TRUE
;
1219 DrawContext draw_context
;
1221 /* Now create the drawing context that will be used to draw
1222 * items related to the last state. */
1223 draw_context
.drawable
= hashed_process_data
->pixmap
;
1224 draw_context
.gc
= drawing
->gc
;
1225 draw_context
.pango_layout
= drawing
->pango_layout
;
1226 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1227 draw_context
.drawinfo
.end
.x
= x
;
1229 draw_context
.drawinfo
.y
.over
= 1;
1230 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1231 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1233 draw_context
.drawinfo
.start
.offset
.over
= 0;
1234 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1235 draw_context
.drawinfo
.start
.offset
.under
= 0;
1236 draw_context
.drawinfo
.end
.offset
.over
= 0;
1237 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1238 draw_context
.drawinfo
.end
.offset
.under
= 0;
1242 PropertiesLine prop_line
= prepare_s_e_line(process
);
1243 draw_line((void*)&prop_line
, (void*)&draw_context
);
1246 /* become the last x position */
1247 hashed_process_data
->x
.middle
= x
;
1248 hashed_process_data
->x
.middle_used
= TRUE
;
1249 hashed_process_data
->x
.middle_marked
= FALSE
;
1251 /* Calculate the next good time */
1252 convert_pixels_to_time(width
, x
+1, time_window
,
1253 &hashed_process_data
->next_good_time
);
1263 /* before_process_release_hook
1265 * Draw lines for process event.
1267 * @param hook_data ControlFlowData structure of the viewer.
1268 * @param call_data Event context.
1270 * This function adds items to be drawn in a queue for each process.
1275 int before_process_release_hook(void *hook_data
, void *call_data
)
1277 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1278 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1280 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1282 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1284 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1286 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1289 e
= ltt_tracefile_get_event(tfc
->tf
);
1291 LttvFilter
*filter
= control_flow_data
->filter
;
1292 if(filter
!= NULL
&& filter
->head
!= NULL
)
1293 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1294 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1297 LttTime evtime
= ltt_event_time(e
);
1299 guint trace_num
= ts
->parent
.index
;
1303 pid
= ltt_event_get_long_unsigned(e
, thf
->f1
);
1306 /* Add process to process list (if not present) */
1307 /* Don't care about the process if it's not in the state hash already :
1308 * that means a process that has never done anything in the trace and
1309 * unknown suddently gets destroyed : no state meaningful to show. */
1310 LttvProcessState
*process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1312 if(process
!= NULL
) {
1314 guint pl_height
= 0;
1315 HashedProcessData
*hashed_process_data
= NULL
;
1317 ProcessList
*process_list
= control_flow_data
->process_list
;
1319 birth
= process
->creation_time
;
1321 /* Cannot use current process : this event happens on another process,
1322 * action done by the parent. */
1323 hashed_process_data
= processlist_get_process_data(process_list
,
1328 if(unlikely(hashed_process_data
== NULL
))
1330 g_assert(pid
== 0 || pid
!= process
->ppid
);
1331 /* Process not present */
1332 Drawing_t
*drawing
= control_flow_data
->drawing
;
1333 ProcessInfo
*process_info
;
1334 processlist_add(process_list
,
1346 &hashed_process_data
);
1347 gtk_widget_set_size_request(drawing
->drawing_area
,
1350 gtk_widget_queue_draw(drawing
->drawing_area
);
1353 /* Now, the process is in the state hash and our own process hash.
1354 * We definitely can draw the items related to the ending state.
1357 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1360 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1361 TimeWindow time_window
=
1362 lttvwindow_get_time_window(control_flow_data
->tab
);
1365 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1366 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1368 #endif //EXTRA_CHECK
1369 Drawing_t
*drawing
= control_flow_data
->drawing
;
1370 guint width
= drawing
->width
;
1372 convert_time_to_pixels(
1378 /* Draw collision indicator */
1379 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1380 gdk_draw_point(hashed_process_data
->pixmap
,
1383 COLLISION_POSITION(hashed_process_data
->height
));
1384 hashed_process_data
->x
.middle_marked
= TRUE
;
1387 TimeWindow time_window
=
1388 lttvwindow_get_time_window(control_flow_data
->tab
);
1391 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1392 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1394 #endif //EXTRA_CHECK
1395 Drawing_t
*drawing
= control_flow_data
->drawing
;
1396 guint width
= drawing
->width
;
1399 convert_time_to_pixels(
1406 /* Jump over draw if we are at the same x position */
1407 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1408 hashed_process_data
->x
.middle_used
))
1410 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1411 /* Draw collision indicator */
1412 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1413 gdk_draw_point(hashed_process_data
->pixmap
,
1416 COLLISION_POSITION(hashed_process_data
->height
));
1417 hashed_process_data
->x
.middle_marked
= TRUE
;
1421 DrawContext draw_context
;
1423 /* Now create the drawing context that will be used to draw
1424 * items related to the last state. */
1425 draw_context
.drawable
= hashed_process_data
->pixmap
;
1426 draw_context
.gc
= drawing
->gc
;
1427 draw_context
.pango_layout
= drawing
->pango_layout
;
1428 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1429 draw_context
.drawinfo
.end
.x
= x
;
1431 draw_context
.drawinfo
.y
.over
= 1;
1432 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1433 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1435 draw_context
.drawinfo
.start
.offset
.over
= 0;
1436 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1437 draw_context
.drawinfo
.start
.offset
.under
= 0;
1438 draw_context
.drawinfo
.end
.offset
.over
= 0;
1439 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1440 draw_context
.drawinfo
.end
.offset
.under
= 0;
1444 PropertiesLine prop_line
= prepare_s_e_line(process
);
1445 draw_line((void*)&prop_line
, (void*)&draw_context
);
1448 /* become the last x position */
1449 hashed_process_data
->x
.middle
= x
;
1450 hashed_process_data
->x
.middle_used
= TRUE
;
1451 hashed_process_data
->x
.middle_marked
= FALSE
;
1453 /* Calculate the next good time */
1454 convert_pixels_to_time(width
, x
+1, time_window
,
1455 &hashed_process_data
->next_good_time
);
1467 /* after_process_fork_hook
1469 * Create the processlist entry for the child process. Put the last
1470 * position in x at the current time value.
1472 * @param hook_data ControlFlowData structure of the viewer.
1473 * @param call_data Event context.
1475 * This function adds items to be drawn in a queue for each process.
1478 int after_process_fork_hook(void *hook_data
, void *call_data
)
1480 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1481 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1482 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1484 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1486 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1488 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1491 e
= ltt_tracefile_get_event(tfc
->tf
);
1493 LttvFilter
*filter
= control_flow_data
->filter
;
1494 if(filter
!= NULL
&& filter
->head
!= NULL
)
1495 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1496 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1499 LttTime evtime
= ltt_event_time(e
);
1503 child_pid
= ltt_event_get_long_unsigned(e
, thf
->f2
);
1506 /* Add process to process list (if not present) */
1507 LttvProcessState
*process_child
;
1509 guint pl_height
= 0;
1510 HashedProcessData
*hashed_process_data_child
= NULL
;
1512 ProcessList
*process_list
= control_flow_data
->process_list
;
1514 /* Find child in the list... */
1515 process_child
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1516 /* It should exist, because we are after the state update. */
1517 g_assert(process_child
!= NULL
);
1519 birth
= process_child
->creation_time
;
1520 guint trace_num
= ts
->parent
.index
;
1522 /* Cannot use current process, because this action is done by the parent
1524 hashed_process_data_child
= processlist_get_process_data(process_list
,
1529 if(likely(hashed_process_data_child
== NULL
))
1531 g_assert(child_pid
== 0 || child_pid
!= process_child
->ppid
);
1532 /* Process not present */
1533 Drawing_t
*drawing
= control_flow_data
->drawing
;
1534 ProcessInfo
*process_info
;
1535 processlist_add(process_list
,
1538 process_child
->tgid
,
1540 process_child
->ppid
,
1543 process_child
->name
,
1544 process_child
->brand
,
1547 &hashed_process_data_child
);
1548 gtk_widget_set_size_request(drawing
->drawing_area
,
1551 gtk_widget_queue_draw(drawing
->drawing_area
);
1553 processlist_set_ppid(process_list
, process_child
->ppid
,
1554 hashed_process_data_child
);
1555 processlist_set_tgid(process_list
, process_child
->tgid
,
1556 hashed_process_data_child
);
1560 if(likely(ltt_time_compare(hashed_process_data_child
->next_good_time
,
1563 TimeWindow time_window
=
1564 lttvwindow_get_time_window(control_flow_data
->tab
);
1567 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1568 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1570 #endif //EXTRA_CHECK
1571 Drawing_t
*drawing
= control_flow_data
->drawing
;
1572 guint width
= drawing
->width
;
1574 convert_time_to_pixels(
1580 if(likely(hashed_process_data_child
->x
.over
!= new_x
)) {
1581 hashed_process_data_child
->x
.over
= new_x
;
1582 hashed_process_data_child
->x
.over_used
= FALSE
;
1583 hashed_process_data_child
->x
.over_marked
= FALSE
;
1585 if(likely(hashed_process_data_child
->x
.middle
!= new_x
)) {
1586 hashed_process_data_child
->x
.middle
= new_x
;
1587 hashed_process_data_child
->x
.middle_used
= FALSE
;
1588 hashed_process_data_child
->x
.middle_marked
= FALSE
;
1590 if(likely(hashed_process_data_child
->x
.under
!= new_x
)) {
1591 hashed_process_data_child
->x
.under
= new_x
;
1592 hashed_process_data_child
->x
.under_used
= FALSE
;
1593 hashed_process_data_child
->x
.under_marked
= FALSE
;
1601 /* after_process_exit_hook
1603 * Create the processlist entry for the child process. Put the last
1604 * position in x at the current time value.
1606 * @param hook_data ControlFlowData structure of the viewer.
1607 * @param call_data Event context.
1609 * This function adds items to be drawn in a queue for each process.
1612 int after_process_exit_hook(void *hook_data
, void *call_data
)
1614 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1615 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1616 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1618 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1620 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1622 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1625 e
= ltt_tracefile_get_event(tfc
->tf
);
1627 LttvFilter
*filter
= control_flow_data
->filter
;
1628 if(filter
!= NULL
&& filter
->head
!= NULL
)
1629 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1630 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1633 LttTime evtime
= ltt_event_time(e
);
1635 /* Add process to process list (if not present) */
1636 //LttvProcessState *process = tfs->process;
1637 guint cpu
= tfs
->cpu
;
1638 guint trace_num
= ts
->parent
.index
;
1639 LttvProcessState
*process
= ts
->running_process
[cpu
];
1641 /* It should exist, because we are after the state update. */
1642 g_assert(process
!= NULL
);
1644 guint pid
= process
->pid
;
1646 guint pl_height
= 0;
1647 HashedProcessData
*hashed_process_data
= NULL
;
1649 ProcessList
*process_list
= control_flow_data
->process_list
;
1651 birth
= process
->creation_time
;
1653 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
) ){
1654 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1656 hashed_process_data
= processlist_get_process_data(process_list
,
1661 if(unlikely(hashed_process_data
== NULL
))
1663 g_assert(pid
== 0 || pid
!= process
->ppid
);
1664 /* Process not present */
1665 Drawing_t
*drawing
= control_flow_data
->drawing
;
1666 ProcessInfo
*process_info
;
1667 processlist_add(process_list
,
1679 &hashed_process_data
);
1680 gtk_widget_set_size_request(drawing
->drawing_area
,
1683 gtk_widget_queue_draw(drawing
->drawing_area
);
1686 /* Set the current process */
1687 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1688 hashed_process_data
;
1691 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
1694 TimeWindow time_window
=
1695 lttvwindow_get_time_window(control_flow_data
->tab
);
1698 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1699 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1701 #endif //EXTRA_CHECK
1702 Drawing_t
*drawing
= control_flow_data
->drawing
;
1703 guint width
= drawing
->width
;
1705 convert_time_to_pixels(
1710 if(unlikely(hashed_process_data
->x
.middle
!= new_x
)) {
1711 hashed_process_data
->x
.middle
= new_x
;
1712 hashed_process_data
->x
.middle_used
= FALSE
;
1713 hashed_process_data
->x
.middle_marked
= FALSE
;
1721 /* Get the filename of the process to print */
1722 int after_fs_exec_hook(void *hook_data
, void *call_data
)
1724 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1725 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1726 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1728 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1730 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1732 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1735 e
= ltt_tracefile_get_event(tfc
->tf
);
1737 LttvFilter
*filter
= control_flow_data
->filter
;
1738 if(filter
!= NULL
&& filter
->head
!= NULL
)
1739 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1740 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1743 guint cpu
= tfs
->cpu
;
1744 guint trace_num
= ts
->parent
.index
;
1745 LttvProcessState
*process
= ts
->running_process
[cpu
];
1746 g_assert(process
!= NULL
);
1748 guint pid
= process
->pid
;
1750 /* Well, the process_out existed : we must get it in the process hash
1751 * or add it, and draw its items.
1753 /* Add process to process list (if not present) */
1754 guint pl_height
= 0;
1755 HashedProcessData
*hashed_process_data
= NULL
;
1756 ProcessList
*process_list
= control_flow_data
->process_list
;
1757 LttTime birth
= process
->creation_time
;
1759 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1760 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1762 hashed_process_data
= processlist_get_process_data(process_list
,
1767 if(unlikely(hashed_process_data
== NULL
))
1769 g_assert(pid
== 0 || pid
!= process
->ppid
);
1770 ProcessInfo
*process_info
;
1771 /* Process not present */
1772 Drawing_t
*drawing
= control_flow_data
->drawing
;
1773 processlist_add(process_list
,
1785 &hashed_process_data
);
1786 gtk_widget_set_size_request(drawing
->drawing_area
,
1789 gtk_widget_queue_draw(drawing
->drawing_area
);
1791 /* Set the current process */
1792 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1793 hashed_process_data
;
1796 processlist_set_name(process_list
, process
->name
, hashed_process_data
);
1802 /* Get the filename of the process to print */
1803 int after_user_generic_thread_brand_hook(void *hook_data
, void *call_data
)
1805 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1806 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1807 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1809 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1811 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1813 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1816 e
= ltt_tracefile_get_event(tfc
->tf
);
1818 LttvFilter
*filter
= control_flow_data
->filter
;
1819 if(filter
!= NULL
&& filter
->head
!= NULL
)
1820 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1821 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1824 guint cpu
= tfs
->cpu
;
1825 guint trace_num
= ts
->parent
.index
;
1826 LttvProcessState
*process
= ts
->running_process
[cpu
];
1827 g_assert(process
!= NULL
);
1829 guint pid
= process
->pid
;
1831 /* Well, the process_out existed : we must get it in the process hash
1832 * or add it, and draw its items.
1834 /* Add process to process list (if not present) */
1835 guint pl_height
= 0;
1836 HashedProcessData
*hashed_process_data
= NULL
;
1837 ProcessList
*process_list
= control_flow_data
->process_list
;
1838 LttTime birth
= process
->creation_time
;
1840 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1841 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1843 hashed_process_data
= processlist_get_process_data(process_list
,
1848 if(unlikely(hashed_process_data
== NULL
))
1850 g_assert(pid
== 0 || pid
!= process
->ppid
);
1851 ProcessInfo
*process_info
;
1852 /* Process not present */
1853 Drawing_t
*drawing
= control_flow_data
->drawing
;
1854 processlist_add(process_list
,
1866 &hashed_process_data
);
1867 gtk_widget_set_size_request(drawing
->drawing_area
,
1870 gtk_widget_queue_draw(drawing
->drawing_area
);
1872 /* Set the current process */
1873 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1874 hashed_process_data
;
1877 processlist_set_brand(process_list
, process
->brand
, hashed_process_data
);
1884 /* after_event_enum_process_hook
1886 * Create the processlist entry for the child process. Put the last
1887 * position in x at the current time value.
1889 * @param hook_data ControlFlowData structure of the viewer.
1890 * @param call_data Event context.
1892 * This function adds items to be drawn in a queue for each process.
1895 int after_event_enum_process_hook(void *hook_data
, void *call_data
)
1897 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1898 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1899 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1901 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1903 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1905 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1907 guint first_cpu
, nb_cpus
, cpu
;
1910 e
= ltt_tracefile_get_event(tfc
->tf
);
1912 LttvFilter
*filter
= control_flow_data
->filter
;
1913 if(filter
!= NULL
&& filter
->head
!= NULL
)
1914 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1915 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1918 LttTime evtime
= ltt_event_time(e
);
1920 /* Add process to process list (if not present) */
1921 LttvProcessState
*process_in
;
1923 guint pl_height
= 0;
1924 HashedProcessData
*hashed_process_data_in
= NULL
;
1926 ProcessList
*process_list
= control_flow_data
->process_list
;
1927 guint trace_num
= ts
->parent
.index
;
1931 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f1
);
1936 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
1938 first_cpu
= ANY_CPU
;
1939 nb_cpus
= ANY_CPU
+1;
1942 for(cpu
= first_cpu
; cpu
< nb_cpus
; cpu
++) {
1943 /* Find process pid_in in the list... */
1944 process_in
= lttv_state_find_process(ts
, cpu
, pid_in
);
1945 //process_in = tfs->process;
1946 //guint cpu = tfs->cpu;
1947 //guint trace_num = ts->parent.index;
1948 //process_in = ts->running_process[cpu];
1949 /* It should exist, because we are after the state update. */
1951 //g_assert(process_in != NULL);
1952 #endif //EXTRA_CHECK
1953 birth
= process_in
->creation_time
;
1955 hashed_process_data_in
= processlist_get_process_data(process_list
,
1960 if(hashed_process_data_in
== NULL
)
1962 if(pid_in
!= 0 && pid_in
== process_in
->ppid
)
1963 g_critical("TEST %u , %u", pid_in
, process_in
->ppid
);
1964 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
1965 ProcessInfo
*process_info
;
1966 Drawing_t
*drawing
= control_flow_data
->drawing
;
1967 /* Process not present */
1968 processlist_add(process_list
,
1980 &hashed_process_data_in
);
1981 gtk_widget_set_size_request(drawing
->drawing_area
,
1984 gtk_widget_queue_draw(drawing
->drawing_area
);
1986 processlist_set_name(process_list
, process_in
->name
,
1987 hashed_process_data_in
);
1988 processlist_set_ppid(process_list
, process_in
->ppid
,
1989 hashed_process_data_in
);
1990 processlist_set_tgid(process_list
, process_in
->tgid
,
1991 hashed_process_data_in
);
1998 gint
update_time_window_hook(void *hook_data
, void *call_data
)
2000 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2001 Drawing_t
*drawing
= control_flow_data
->drawing
;
2002 ProcessList
*process_list
= control_flow_data
->process_list
;
2004 const TimeWindowNotifyData
*time_window_nofify_data
=
2005 ((const TimeWindowNotifyData
*)call_data
);
2007 TimeWindow
*old_time_window
=
2008 time_window_nofify_data
->old_time_window
;
2009 TimeWindow
*new_time_window
=
2010 time_window_nofify_data
->new_time_window
;
2012 /* Update the ruler */
2013 drawing_update_ruler(control_flow_data
->drawing
,
2017 /* Two cases : zoom in/out or scrolling */
2019 /* In order to make sure we can reuse the old drawing, the scale must
2020 * be the same and the new time interval being partly located in the
2021 * currently shown time interval. (reuse is only for scrolling)
2024 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
2025 old_time_window
->start_time
.tv_sec
,
2026 old_time_window
->start_time
.tv_nsec
,
2027 old_time_window
->time_width
.tv_sec
,
2028 old_time_window
->time_width
.tv_nsec
);
2030 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
2031 new_time_window
->start_time
.tv_sec
,
2032 new_time_window
->start_time
.tv_nsec
,
2033 new_time_window
->time_width
.tv_sec
,
2034 new_time_window
->time_width
.tv_nsec
);
2036 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
2037 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
2039 /* Same scale (scrolling) */
2040 g_info("scrolling");
2041 LttTime
*ns
= &new_time_window
->start_time
;
2042 LttTime
*nw
= &new_time_window
->time_width
;
2043 LttTime
*os
= &old_time_window
->start_time
;
2044 LttTime
*ow
= &old_time_window
->time_width
;
2045 LttTime old_end
= old_time_window
->end_time
;
2046 LttTime new_end
= new_time_window
->end_time
;
2048 //if(ns<os+w && os+w<ns+w)
2049 //if(ns<old_end && os<ns)
2050 if(ltt_time_compare(*ns
, old_end
) == -1
2051 && ltt_time_compare(*os
, *ns
) == -1)
2053 g_info("scrolling near right");
2054 /* Scroll right, keep right part of the screen */
2056 guint width
= control_flow_data
->drawing
->width
;
2057 convert_time_to_pixels(
2063 /* Copy old data to new location */
2064 copy_pixmap_region(process_list
,
2066 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2070 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
2072 if(drawing
->damage_begin
== drawing
->damage_end
)
2073 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
2075 drawing
->damage_begin
= 0;
2077 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2079 /* Clear the data request background, but not SAFETY */
2080 rectangle_pixmap(process_list
,
2081 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2083 drawing
->damage_begin
+SAFETY
, 0,
2084 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2086 gtk_widget_queue_draw(drawing
->drawing_area
);
2087 //gtk_widget_queue_draw_area (drawing->drawing_area,
2089 // control_flow_data->drawing->width,
2090 // control_flow_data->drawing->height);
2092 /* Get new data for the rest. */
2093 drawing_data_request(control_flow_data
->drawing
,
2094 drawing
->damage_begin
, 0,
2095 drawing
->damage_end
- drawing
->damage_begin
,
2096 control_flow_data
->drawing
->height
);
2099 //if(ns<os && os<ns+w)
2100 //if(ns<os && os<new_end)
2101 if(ltt_time_compare(*ns
,*os
) == -1
2102 && ltt_time_compare(*os
,new_end
) == -1)
2104 g_info("scrolling near left");
2105 /* Scroll left, keep left part of the screen */
2107 guint width
= control_flow_data
->drawing
->width
;
2108 convert_time_to_pixels(
2114 /* Copy old data to new location */
2115 copy_pixmap_region (process_list
,
2117 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2123 if(drawing
->damage_begin
== drawing
->damage_end
)
2124 drawing
->damage_end
= x
;
2126 drawing
->damage_end
=
2127 control_flow_data
->drawing
->width
;
2129 drawing
->damage_begin
= 0;
2131 rectangle_pixmap (process_list
,
2132 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2134 drawing
->damage_begin
, 0,
2135 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2138 gtk_widget_queue_draw(drawing
->drawing_area
);
2139 //gtk_widget_queue_draw_area (drawing->drawing_area,
2141 // control_flow_data->drawing->width,
2142 // control_flow_data->drawing->height);
2145 /* Get new data for the rest. */
2146 drawing_data_request(control_flow_data
->drawing
,
2147 drawing
->damage_begin
, 0,
2148 drawing
->damage_end
- drawing
->damage_begin
,
2149 control_flow_data
->drawing
->height
);
2152 if(ltt_time_compare(*ns
,*os
) == 0)
2154 g_info("not scrolling");
2156 g_info("scrolling far");
2157 /* Cannot reuse any part of the screen : far jump */
2160 rectangle_pixmap (process_list
,
2161 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2164 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2167 //gtk_widget_queue_draw_area (drawing->drawing_area,
2169 // control_flow_data->drawing->width,
2170 // control_flow_data->drawing->height);
2171 gtk_widget_queue_draw(drawing
->drawing_area
);
2173 drawing
->damage_begin
= 0;
2174 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2176 drawing_data_request(control_flow_data
->drawing
,
2178 control_flow_data
->drawing
->width
,
2179 control_flow_data
->drawing
->height
);
2185 /* Different scale (zoom) */
2188 rectangle_pixmap (process_list
,
2189 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2192 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2195 //gtk_widget_queue_draw_area (drawing->drawing_area,
2197 // control_flow_data->drawing->width,
2198 // control_flow_data->drawing->height);
2199 gtk_widget_queue_draw(drawing
->drawing_area
);
2201 drawing
->damage_begin
= 0;
2202 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2204 drawing_data_request(control_flow_data
->drawing
,
2206 control_flow_data
->drawing
->width
,
2207 control_flow_data
->drawing
->height
);
2210 /* Update directly when scrolling */
2211 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2217 gint
traceset_notify(void *hook_data
, void *call_data
)
2219 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2220 Drawing_t
*drawing
= control_flow_data
->drawing
;
2222 if(unlikely(drawing
->gc
== NULL
)) {
2225 if(drawing
->dotted_gc
== NULL
) {
2229 drawing_clear(control_flow_data
->drawing
);
2230 processlist_clear(control_flow_data
->process_list
);
2231 gtk_widget_set_size_request(
2232 control_flow_data
->drawing
->drawing_area
,
2233 -1, processlist_get_height(control_flow_data
->process_list
));
2234 redraw_notify(control_flow_data
, NULL
);
2236 request_background_data(control_flow_data
);
2241 gint
redraw_notify(void *hook_data
, void *call_data
)
2243 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2244 Drawing_t
*drawing
= control_flow_data
->drawing
;
2245 GtkWidget
*widget
= drawing
->drawing_area
;
2247 drawing
->damage_begin
= 0;
2248 drawing
->damage_end
= drawing
->width
;
2250 /* fun feature, to be separated someday... */
2251 drawing_clear(control_flow_data
->drawing
);
2252 processlist_clear(control_flow_data
->process_list
);
2253 gtk_widget_set_size_request(
2254 control_flow_data
->drawing
->drawing_area
,
2255 -1, processlist_get_height(control_flow_data
->process_list
));
2257 rectangle_pixmap (control_flow_data
->process_list
,
2258 widget
->style
->black_gc
,
2261 drawing
->alloc_width
,
2264 gtk_widget_queue_draw(drawing
->drawing_area
);
2266 if(drawing
->damage_begin
< drawing
->damage_end
)
2268 drawing_data_request(drawing
,
2269 drawing
->damage_begin
,
2271 drawing
->damage_end
-drawing
->damage_begin
,
2275 //gtk_widget_queue_draw_area(drawing->drawing_area,
2278 // drawing->height);
2284 gint
continue_notify(void *hook_data
, void *call_data
)
2286 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2287 Drawing_t
*drawing
= control_flow_data
->drawing
;
2289 //g_assert(widget->allocation.width == drawing->damage_end);
2291 if(drawing
->damage_begin
< drawing
->damage_end
)
2293 drawing_data_request(drawing
,
2294 drawing
->damage_begin
,
2296 drawing
->damage_end
-drawing
->damage_begin
,
2304 gint
update_current_time_hook(void *hook_data
, void *call_data
)
2306 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
2307 Drawing_t
*drawing
= control_flow_data
->drawing
;
2309 LttTime current_time
= *((LttTime
*)call_data
);
2311 TimeWindow time_window
=
2312 lttvwindow_get_time_window(control_flow_data
->tab
);
2314 LttTime time_begin
= time_window
.start_time
;
2315 LttTime width
= time_window
.time_width
;
2318 guint64 time_ll
= ltt_time_to_uint64(width
);
2319 time_ll
= time_ll
>> 1; /* divide by two */
2320 half_width
= ltt_time_from_uint64(time_ll
);
2322 LttTime time_end
= ltt_time_add(time_begin
, width
);
2324 LttvTracesetContext
* tsc
=
2325 lttvwindow_get_traceset_context(control_flow_data
->tab
);
2327 LttTime trace_start
= tsc
->time_span
.start_time
;
2328 LttTime trace_end
= tsc
->time_span
.end_time
;
2330 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
2331 current_time
.tv_nsec
);
2335 /* If current time is inside time interval, just move the highlight
2338 /* Else, we have to change the time interval. We have to tell it
2339 * to the main window. */
2340 /* The time interval change will take care of placing the current
2341 * time at the center of the visible area, or nearest possible if we are
2342 * at one end of the trace. */
2345 if(ltt_time_compare(current_time
, time_begin
) < 0)
2347 TimeWindow new_time_window
;
2349 if(ltt_time_compare(current_time
,
2350 ltt_time_add(trace_start
,half_width
)) < 0)
2351 time_begin
= trace_start
;
2353 time_begin
= ltt_time_sub(current_time
,half_width
);
2355 new_time_window
.start_time
= time_begin
;
2356 new_time_window
.time_width
= width
;
2357 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2358 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2360 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2362 else if(ltt_time_compare(current_time
, time_end
) > 0)
2364 TimeWindow new_time_window
;
2366 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
2367 time_begin
= ltt_time_sub(trace_end
,width
);
2369 time_begin
= ltt_time_sub(current_time
,half_width
);
2371 new_time_window
.start_time
= time_begin
;
2372 new_time_window
.time_width
= width
;
2373 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2374 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2376 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2379 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2381 /* Update directly when scrolling */
2382 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2388 typedef struct _ClosureData
{
2389 EventsRequest
*events_request
;
2390 LttvTracesetState
*tss
;
2396 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
2398 ProcessInfo
*process_info
= (ProcessInfo
*)key
;
2399 HashedProcessData
*hashed_process_data
= (HashedProcessData
*)value
;
2400 ClosureData
*closure_data
= (ClosureData
*)user_data
;
2402 EventsRequest
*events_request
= closure_data
->events_request
;
2403 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2405 LttvTracesetState
*tss
= closure_data
->tss
;
2406 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)tss
;
2408 LttTime evtime
= closure_data
->end_time
;
2410 gboolean dodraw
= TRUE
;
2413 /* For the process */
2414 /* First, check if the current process is in the state computation
2415 * process list. If it is there, that means we must add it right now and
2416 * draw items from the beginning of the read for it. If it is not
2417 * present, it's a new process and it was not present : it will
2418 * be added after the state update. */
2420 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
2421 #endif //EXTRA_CHECK
2422 LttvTraceContext
*tc
= tsc
->traces
[process_info
->trace_num
];
2423 LttvTraceState
*ts
= (LttvTraceState
*)tc
;
2426 //FIXME : optimize data structures.
2427 LttvTracefileState
*tfs
;
2428 LttvTracefileContext
*tfc
;
2430 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
2431 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
2432 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
2433 && tfs
->cpu
== process_info
->cpu
)
2437 g_assert(i
<tc
->tracefiles
->len
);
2438 tfs
= LTTV_TRACEFILE_STATE(tfc
);
2440 // LttvTracefileState *tfs =
2441 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2442 // tracefiles[process_info->cpu];
2444 LttvProcessState
*process
;
2445 process
= lttv_state_find_process(ts
, process_info
->cpu
,
2448 if(unlikely(process
!= NULL
)) {
2450 LttvFilter
*filter
= control_flow_data
->filter
;
2451 if(filter
!= NULL
&& filter
->head
!= NULL
)
2452 if(!lttv_filter_tree_parse(filter
->head
,NULL
,NULL
,
2453 tc
->t
,NULL
,process
,tc
))
2456 /* Only draw for processes that are currently in the trace states */
2458 ProcessList
*process_list
= control_flow_data
->process_list
;
2460 /* Should be alike when background info is ready */
2461 if(control_flow_data
->background_info_waiting
==0)
2462 g_assert(ltt_time_compare(process
->creation_time
,
2463 process_info
->birth
) == 0);
2464 #endif //EXTRA_CHECK
2466 /* Now, the process is in the state hash and our own process hash.
2467 * We definitely can draw the items related to the ending state.
2470 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2473 TimeWindow time_window
=
2474 lttvwindow_get_time_window(control_flow_data
->tab
);
2477 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2478 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2480 #endif //EXTRA_CHECK
2481 Drawing_t
*drawing
= control_flow_data
->drawing
;
2482 guint width
= drawing
->width
;
2484 guint x
= closure_data
->x_end
;
2486 DrawContext draw_context
;
2488 /* Now create the drawing context that will be used to draw
2489 * items related to the last state. */
2490 draw_context
.drawable
= hashed_process_data
->pixmap
;
2491 draw_context
.gc
= drawing
->gc
;
2492 draw_context
.pango_layout
= drawing
->pango_layout
;
2493 draw_context
.drawinfo
.end
.x
= x
;
2495 draw_context
.drawinfo
.y
.over
= 1;
2496 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2497 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2499 draw_context
.drawinfo
.start
.offset
.over
= 0;
2500 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2501 draw_context
.drawinfo
.start
.offset
.under
= 0;
2502 draw_context
.drawinfo
.end
.offset
.over
= 0;
2503 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2504 draw_context
.drawinfo
.end
.offset
.under
= 0;
2506 /* Jump over draw if we are at the same x position */
2507 if(x
== hashed_process_data
->x
.over
)
2511 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2513 PropertiesLine prop_line
= prepare_execmode_line(process
);
2514 draw_line((void*)&prop_line
, (void*)&draw_context
);
2516 hashed_process_data
->x
.over
= x
;
2520 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2521 hashed_process_data
->x
.middle_used
)) {
2522 #if 0 /* do not mark closure : not missing information */
2523 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2524 /* Draw collision indicator */
2525 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2526 gdk_draw_point(drawing
->pixmap
,
2530 hashed_process_data
->x
.middle_marked
= TRUE
;
2535 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2538 PropertiesLine prop_line
= prepare_s_e_line(process
);
2539 draw_line((void*)&prop_line
, (void*)&draw_context
);
2542 /* become the last x position */
2543 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2544 hashed_process_data
->x
.middle
= x
;
2545 /* but don't use the pixel */
2546 hashed_process_data
->x
.middle_used
= FALSE
;
2548 /* Calculate the next good time */
2549 convert_pixels_to_time(width
, x
+1, time_window
,
2550 &hashed_process_data
->next_good_time
);
2559 int before_chunk(void *hook_data
, void *call_data
)
2561 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2562 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2563 ControlFlowData
*cfd
= (ControlFlowData
*)events_request
->viewer_data
;
2565 /* Desactivate sort */
2566 gtk_tree_sortable_set_sort_column_id(
2567 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2569 GTK_SORT_ASCENDING
);
2571 drawing_chunk_begin(events_request
, tss
);
2576 int before_request(void *hook_data
, void *call_data
)
2578 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2579 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2581 drawing_data_request_begin(events_request
, tss
);
2588 * after request is necessary in addition of after chunk in order to draw
2589 * lines until the end of the screen. after chunk just draws lines until
2596 int after_request(void *hook_data
, void *call_data
)
2598 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2599 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2600 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2602 ProcessList
*process_list
= control_flow_data
->process_list
;
2603 LttTime end_time
= events_request
->end_time
;
2605 ClosureData closure_data
;
2606 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2607 closure_data
.tss
= tss
;
2608 closure_data
.end_time
= end_time
;
2610 TimeWindow time_window
=
2611 lttvwindow_get_time_window(control_flow_data
->tab
);
2612 guint width
= control_flow_data
->drawing
->width
;
2613 convert_time_to_pixels(
2617 &closure_data
.x_end
);
2620 /* Draw last items */
2621 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2622 (void*)&closure_data
);
2625 /* Request expose */
2626 drawing_request_expose(events_request
, tss
, end_time
);
2635 int after_chunk(void *hook_data
, void *call_data
)
2637 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2638 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2639 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2640 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)call_data
;
2641 LttvTracefileContext
*tfc
= lttv_traceset_context_get_current_tfc(tsc
);
2644 ProcessList
*process_list
= control_flow_data
->process_list
;
2646 LttvTraceset
*traceset
= tsc
->ts
;
2647 guint nb_trace
= lttv_traceset_number(traceset
);
2649 /* Only execute when called for the first trace's events request */
2650 if(!process_list
->current_hash_data
) return;
2652 for(i
= 0 ; i
< nb_trace
; i
++) {
2653 g_free(process_list
->current_hash_data
[i
]);
2655 g_free(process_list
->current_hash_data
);
2656 process_list
->current_hash_data
= NULL
;
2659 end_time
= LTT_TIME_MIN(tfc
->timestamp
, events_request
->end_time
);
2660 else /* end of traceset, or position now out of request : end */
2661 end_time
= events_request
->end_time
;
2663 ClosureData closure_data
;
2664 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2665 closure_data
.tss
= tss
;
2666 closure_data
.end_time
= end_time
;
2668 TimeWindow time_window
=
2669 lttvwindow_get_time_window(control_flow_data
->tab
);
2670 guint width
= control_flow_data
->drawing
->width
;
2671 convert_time_to_pixels(
2675 &closure_data
.x_end
);
2677 /* Draw last items */
2678 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2679 (void*)&closure_data
);
2681 /* Reactivate sort */
2682 gtk_tree_sortable_set_sort_column_id(
2683 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2684 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2685 GTK_SORT_ASCENDING
);
2687 update_index_to_pixmap(control_flow_data
->process_list
);
2688 /* Request a full expose : drawing scrambled */
2689 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2691 /* Request expose (updates damages zone also) */
2692 drawing_request_expose(events_request
, tss
, end_time
);
2697 /* after_statedump_end
2699 * @param hook_data ControlFlowData structure of the viewer.
2700 * @param call_data Event context.
2702 * This function adds items to be drawn in a queue for each process.
2705 int before_statedump_end(void *hook_data
, void *call_data
)
2707 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2708 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
2709 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2711 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2713 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
2715 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
2717 LttvTracesetState
*tss
= (LttvTracesetState
*)tfc
->t_context
->ts_context
;
2718 ProcessList
*process_list
= control_flow_data
->process_list
;
2721 e
= ltt_tracefile_get_event(tfc
->tf
);
2723 LttvFilter
*filter
= control_flow_data
->filter
;
2724 if(filter
!= NULL
&& filter
->head
!= NULL
)
2725 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2726 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2729 LttTime evtime
= ltt_event_time(e
);
2731 ClosureData closure_data
;
2732 closure_data
.events_request
= events_request
;
2733 closure_data
.tss
= tss
;
2734 closure_data
.end_time
= evtime
;
2736 TimeWindow time_window
=
2737 lttvwindow_get_time_window(control_flow_data
->tab
);
2738 guint width
= control_flow_data
->drawing
->width
;
2739 convert_time_to_pixels(
2743 &closure_data
.x_end
);
2745 /* Draw last items */
2746 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2747 (void*)&closure_data
);
2749 /* Reactivate sort */
2750 gtk_tree_sortable_set_sort_column_id(
2751 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2752 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2753 GTK_SORT_ASCENDING
);
2755 update_index_to_pixmap(control_flow_data
->process_list
);
2756 /* Request a full expose : drawing scrambled */
2757 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2759 /* Request expose (updates damages zone also) */
2760 drawing_request_expose(events_request
, tss
, evtime
);