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
83 extern GSList
*g_legend_list
;
86 /* Action to do when background computation completed.
88 * Wait for all the awaited computations to be over.
91 static gint
background_ready(void *hook_data
, void *call_data
)
93 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
94 LttvTrace
*trace
= (LttvTrace
*)call_data
;
96 control_flow_data
->background_info_waiting
--;
98 if(control_flow_data
->background_info_waiting
== 0) {
99 g_message("control flow viewer : background computation data ready.");
101 drawing_clear(control_flow_data
->drawing
);
102 processlist_clear(control_flow_data
->process_list
);
103 gtk_widget_set_size_request(
104 control_flow_data
->drawing
->drawing_area
,
105 -1, processlist_get_height(control_flow_data
->process_list
));
106 redraw_notify(control_flow_data
, NULL
);
113 /* Request background computation. Verify if it is in progress or ready first.
114 * Only for each trace in the tab's traceset.
116 static void request_background_data(ControlFlowData
*control_flow_data
)
118 LttvTracesetContext
* tsc
=
119 lttvwindow_get_traceset_context(control_flow_data
->tab
);
120 gint num_traces
= lttv_traceset_number(tsc
->ts
);
124 LttvHooks
*background_ready_hook
=
126 lttv_hooks_add(background_ready_hook
, background_ready
, control_flow_data
,
128 control_flow_data
->background_info_waiting
= 0;
130 for(i
=0;i
<num_traces
;i
++) {
131 trace
= lttv_traceset_get(tsc
->ts
, i
);
133 if(lttvwindowtraces_get_ready(g_quark_from_string("state"),trace
)==FALSE
) {
135 if(lttvwindowtraces_get_in_progress(g_quark_from_string("state"),
137 /* We first remove requests that could have been done for the same
138 * information. Happens when two viewers ask for it before servicing
141 if(!lttvwindowtraces_background_request_find(trace
, "state"))
142 lttvwindowtraces_background_request_queue(
143 main_window_get_widget(control_flow_data
->tab
), trace
, "state");
144 lttvwindowtraces_background_notify_queue(control_flow_data
,
148 background_ready_hook
);
149 control_flow_data
->background_info_waiting
++;
150 } else { /* in progress */
152 lttvwindowtraces_background_notify_current(control_flow_data
,
156 background_ready_hook
);
157 control_flow_data
->background_info_waiting
++;
160 /* Data ready. Be its nature, this viewer doesn't need to have
161 * its data ready hook called there, because a background
162 * request is always linked with a redraw.
168 lttv_hooks_destroy(background_ready_hook
);
175 * Event Viewer's constructor hook
177 * This constructor is given as a parameter to the menuitem and toolbar button
178 * registration. It creates the list.
179 * @param tab A pointer to the parent tab.
180 * @return The widget created.
183 h_guicontrolflow(LttvPlugin
*plugin
)
185 LttvPluginTab
*ptab
= LTTV_PLUGIN_TAB(plugin
);
186 Tab
*tab
= ptab
->tab
;
187 g_info("h_guicontrolflow, %p", tab
);
188 ControlFlowData
*control_flow_data
= guicontrolflow(ptab
);
190 control_flow_data
->tab
= tab
;
192 // Unreg done in the GuiControlFlow_Destructor
193 lttvwindow_register_traceset_notify(tab
,
197 lttvwindow_register_time_window_notify(tab
,
198 update_time_window_hook
,
200 lttvwindow_register_current_time_notify(tab
,
201 update_current_time_hook
,
203 lttvwindow_register_redraw_notify(tab
,
206 lttvwindow_register_continue_notify(tab
,
209 request_background_data(control_flow_data
);
212 return guicontrolflow_get_widget(control_flow_data
) ;
216 void legend_destructor(GtkWindow
*legend
)
218 g_legend_list
= g_slist_remove(g_legend_list
, legend
);
221 /* Create a popup legend */
223 h_legend(LttvPlugin
*plugin
)
225 LttvPluginTab
*ptab
= LTTV_PLUGIN_TAB(plugin
);
226 Tab
*tab
= ptab
->tab
;
227 g_info("h_legend, %p", tab
);
229 GtkWindow
*legend
= GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL
));
231 g_legend_list
= g_slist_append(
235 g_object_set_data_full(
239 (GDestroyNotify
)legend_destructor
);
241 gtk_window_set_title(legend
, "Control Flow View Legend");
243 GtkWidget
*pixmap
= create_pixmap(GTK_WIDGET(legend
), "lttv-color-list.png");
245 // GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixmap(
246 // GDK_PIXMAP(pixmap), NULL));
248 gtk_container_add(GTK_CONTAINER(legend
), GTK_WIDGET(pixmap
));
250 gtk_widget_show(GTK_WIDGET(pixmap
));
251 gtk_widget_show(GTK_WIDGET(legend
));
254 return NULL
; /* This is a popup window */
258 int event_selected_hook(void *hook_data
, void *call_data
)
260 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
261 guint
*event_number
= (guint
*) call_data
;
263 g_debug("DEBUG : event selected by main window : %u", *event_number
);
268 /* Function that selects the color of status&exemode line */
269 static inline PropertiesLine
prepare_s_e_line(LttvProcessState
*process
)
271 PropertiesLine prop_line
;
272 prop_line
.line_width
= 2;
273 prop_line
.style
= GDK_LINE_SOLID
;
274 prop_line
.y
= MIDDLE
;
275 //GdkColormap *colormap = gdk_colormap_get_system();
277 if(process
->state
->s
== LTTV_STATE_RUN
) {
278 if(process
->state
->t
== LTTV_STATE_USER_MODE
)
279 prop_line
.color
= drawing_colors
[COL_RUN_USER_MODE
];
280 else if(process
->state
->t
== LTTV_STATE_SYSCALL
)
281 prop_line
.color
= drawing_colors
[COL_RUN_SYSCALL
];
282 else if(process
->state
->t
== LTTV_STATE_TRAP
)
283 prop_line
.color
= drawing_colors
[COL_RUN_TRAP
];
284 else if(process
->state
->t
== LTTV_STATE_IRQ
)
285 prop_line
.color
= drawing_colors
[COL_RUN_IRQ
];
286 else if(process
->state
->t
== LTTV_STATE_SOFT_IRQ
)
287 prop_line
.color
= drawing_colors
[COL_RUN_SOFT_IRQ
];
288 else if(process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
)
289 prop_line
.color
= drawing_colors
[COL_MODE_UNKNOWN
];
291 g_assert(FALSE
); /* RUNNING MODE UNKNOWN */
292 } else if(process
->state
->s
== LTTV_STATE_WAIT
) {
293 /* We don't show if we wait while in user mode, trap, irq or syscall */
294 prop_line
.color
= drawing_colors
[COL_WAIT
];
295 } else if(process
->state
->s
== LTTV_STATE_WAIT_CPU
) {
296 /* We don't show if we wait for CPU while in user mode, trap, irq
298 prop_line
.color
= drawing_colors
[COL_WAIT_CPU
];
299 } else if(process
->state
->s
== LTTV_STATE_ZOMBIE
) {
300 prop_line
.color
= drawing_colors
[COL_ZOMBIE
];
301 } else if(process
->state
->s
== LTTV_STATE_WAIT_FORK
) {
302 prop_line
.color
= drawing_colors
[COL_WAIT_FORK
];
303 } else if(process
->state
->s
== LTTV_STATE_EXIT
) {
304 prop_line
.color
= drawing_colors
[COL_EXIT
];
305 } else if(process
->state
->s
== LTTV_STATE_UNNAMED
) {
306 prop_line
.color
= drawing_colors
[COL_UNNAMED
];
308 g_critical("unknown state : %s", g_quark_to_string(process
->state
->s
));
309 g_assert(FALSE
); /* UNKNOWN STATE */
317 /* before_schedchange_hook
319 * This function basically draw lines and icons. Two types of lines are drawn :
320 * one small (3 pixels?) representing the state of the process and the second
321 * type is thicker (10 pixels?) representing on which CPU a process is running
322 * (and this only in running state).
324 * Extremums of the lines :
325 * x_min : time of the last event context for this process kept in memory.
326 * x_max : time of the current event.
327 * y : middle of the process in the process list. The process is found in the
328 * list, therefore is it's position in pixels.
330 * The choice of lines'color is defined by the context of the last event for this
335 int before_schedchange_hook(void *hook_data
, void *call_data
)
337 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
338 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
339 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
341 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
343 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
344 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
347 e
= ltt_tracefile_get_event(tfc
->tf
);
348 gint target_pid_saved
= tfc
->target_pid
;
350 LttTime evtime
= ltt_event_time(e
);
351 LttvFilter
*filter
= control_flow_data
->filter
;
353 /* we are in a schedchange, before the state update. We must draw the
354 * items corresponding to the state before it changes : now is the right
361 pid_out
= ltt_event_get_long_unsigned(e
, thf
->f1
);
362 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f2
);
365 tfc
->target_pid
= pid_out
;
366 if(!filter
|| !filter
->head
||
367 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
368 tfc
->t_context
->t
,tfc
)) {
369 /* For the pid_out */
370 /* First, check if the current process is in the state computation
371 * process list. If it is there, that means we must add it right now and
372 * draw items from the beginning of the read for it. If it is not
373 * present, it's a new process and it was not present : it will
374 * be added after the state update. */
375 guint cpu
= tfs
->cpu
;
376 LttvProcessState
*process
= ts
->running_process
[cpu
];
377 /* unknown state, bad current pid */
378 if(process
->pid
!= pid_out
)
379 process
= lttv_state_find_process(ts
,
382 if(process
!= NULL
) {
383 /* Well, the process_out existed : we must get it in the process hash
384 * or add it, and draw its items.
386 /* Add process to process list (if not present) */
388 HashedProcessData
*hashed_process_data
= NULL
;
389 ProcessList
*process_list
= control_flow_data
->process_list
;
390 LttTime birth
= process
->creation_time
;
392 hashed_process_data
= processlist_get_process_data(process_list
,
396 tfc
->t_context
->index
);
397 if(hashed_process_data
== NULL
)
399 g_assert(pid_out
== 0 || pid_out
!= process
->ppid
);
400 /* Process not present */
401 ProcessInfo
*process_info
;
402 Drawing_t
*drawing
= control_flow_data
->drawing
;
403 processlist_add(process_list
,
410 tfc
->t_context
->index
,
415 &hashed_process_data
);
416 gtk_widget_set_size_request(drawing
->drawing_area
,
419 gtk_widget_queue_draw(drawing
->drawing_area
);
423 /* Now, the process is in the state hash and our own process hash.
424 * We definitely can draw the items related to the ending state.
427 if(ltt_time_compare(hashed_process_data
->next_good_time
,
430 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
432 TimeWindow time_window
=
433 lttvwindow_get_time_window(control_flow_data
->tab
);
435 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
436 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
439 Drawing_t
*drawing
= control_flow_data
->drawing
;
440 guint width
= drawing
->width
;
442 convert_time_to_pixels(
448 /* Draw collision indicator */
449 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
450 gdk_draw_point(hashed_process_data
->pixmap
,
453 (hashed_process_data
->height
/2)-3);
454 hashed_process_data
->x
.middle_marked
= TRUE
;
457 TimeWindow time_window
=
458 lttvwindow_get_time_window(control_flow_data
->tab
);
460 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
461 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
464 Drawing_t
*drawing
= control_flow_data
->drawing
;
465 guint width
= drawing
->width
;
467 convert_time_to_pixels(
474 /* Jump over draw if we are at the same x position */
475 if(x
== hashed_process_data
->x
.middle
&&
476 hashed_process_data
->x
.middle_used
)
478 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
479 /* Draw collision indicator */
480 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
481 gdk_draw_point(hashed_process_data
->pixmap
,
484 (hashed_process_data
->height
/2)-3);
485 hashed_process_data
->x
.middle_marked
= TRUE
;
489 DrawContext draw_context
;
491 /* Now create the drawing context that will be used to draw
492 * items related to the last state. */
493 draw_context
.drawable
= hashed_process_data
->pixmap
;
494 draw_context
.gc
= drawing
->gc
;
495 draw_context
.pango_layout
= drawing
->pango_layout
;
496 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
497 draw_context
.drawinfo
.end
.x
= x
;
499 draw_context
.drawinfo
.y
.over
= 1;
500 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
501 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
503 draw_context
.drawinfo
.start
.offset
.over
= 0;
504 draw_context
.drawinfo
.start
.offset
.middle
= 0;
505 draw_context
.drawinfo
.start
.offset
.under
= 0;
506 draw_context
.drawinfo
.end
.offset
.over
= 0;
507 draw_context
.drawinfo
.end
.offset
.middle
= 0;
508 draw_context
.drawinfo
.end
.offset
.under
= 0;
512 PropertiesLine prop_line
= prepare_s_e_line(process
);
513 draw_line((void*)&prop_line
, (void*)&draw_context
);
516 /* become the last x position */
517 hashed_process_data
->x
.middle
= x
;
518 hashed_process_data
->x
.middle_used
= TRUE
;
519 hashed_process_data
->x
.middle_marked
= FALSE
;
521 /* Calculate the next good time */
522 convert_pixels_to_time(width
, x
+1, time_window
,
523 &hashed_process_data
->next_good_time
);
529 tfc
->target_pid
= pid_in
;
530 if(!filter
|| !filter
->head
||
531 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
532 tfc
->t_context
->t
,tfc
)) {
534 /* First, check if the current process is in the state computation
535 * process list. If it is there, that means we must add it right now and
536 * draw items from the beginning of the read for it. If it is not
537 * present, it's a new process and it was not present : it will
538 * be added after the state update. */
539 LttvProcessState
*process
;
540 process
= lttv_state_find_process(ts
,
543 if(process
!= NULL
) {
544 /* Well, the process existed : we must get it in the process hash
545 * or add it, and draw its items.
547 /* Add process to process list (if not present) */
549 HashedProcessData
*hashed_process_data
= NULL
;
550 ProcessList
*process_list
= control_flow_data
->process_list
;
551 LttTime birth
= process
->creation_time
;
553 hashed_process_data
= processlist_get_process_data(process_list
,
557 tfc
->t_context
->index
);
558 if(hashed_process_data
== NULL
)
560 g_assert(pid_in
== 0 || pid_in
!= process
->ppid
);
561 /* Process not present */
562 ProcessInfo
*process_info
;
563 Drawing_t
*drawing
= control_flow_data
->drawing
;
564 processlist_add(process_list
,
571 tfc
->t_context
->index
,
576 &hashed_process_data
);
577 gtk_widget_set_size_request(drawing
->drawing_area
,
580 gtk_widget_queue_draw(drawing
->drawing_area
);
583 //We could set the current process and hash here, but will be done
584 //by after schedchange hook
586 /* Now, the process is in the state hash and our own process hash.
587 * We definitely can draw the items related to the ending state.
590 if(ltt_time_compare(hashed_process_data
->next_good_time
,
593 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
595 TimeWindow time_window
=
596 lttvwindow_get_time_window(control_flow_data
->tab
);
598 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
599 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
602 Drawing_t
*drawing
= control_flow_data
->drawing
;
603 guint width
= drawing
->width
;
605 convert_time_to_pixels(
611 /* Draw collision indicator */
612 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
613 gdk_draw_point(hashed_process_data
->pixmap
,
616 (hashed_process_data
->height
/2)-3);
617 hashed_process_data
->x
.middle_marked
= TRUE
;
620 TimeWindow time_window
=
621 lttvwindow_get_time_window(control_flow_data
->tab
);
623 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
624 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
627 Drawing_t
*drawing
= control_flow_data
->drawing
;
628 guint width
= drawing
->width
;
631 convert_time_to_pixels(
638 /* Jump over draw if we are at the same x position */
639 if(x
== hashed_process_data
->x
.middle
&&
640 hashed_process_data
->x
.middle_used
)
642 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
643 /* Draw collision indicator */
644 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
645 gdk_draw_point(hashed_process_data
->pixmap
,
648 (hashed_process_data
->height
/2)-3);
649 hashed_process_data
->x
.middle_marked
= TRUE
;
653 DrawContext draw_context
;
655 /* Now create the drawing context that will be used to draw
656 * items related to the last state. */
657 draw_context
.drawable
= hashed_process_data
->pixmap
;
658 draw_context
.gc
= drawing
->gc
;
659 draw_context
.pango_layout
= drawing
->pango_layout
;
660 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
661 draw_context
.drawinfo
.end
.x
= x
;
663 draw_context
.drawinfo
.y
.over
= 1;
664 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
665 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
667 draw_context
.drawinfo
.start
.offset
.over
= 0;
668 draw_context
.drawinfo
.start
.offset
.middle
= 0;
669 draw_context
.drawinfo
.start
.offset
.under
= 0;
670 draw_context
.drawinfo
.end
.offset
.over
= 0;
671 draw_context
.drawinfo
.end
.offset
.middle
= 0;
672 draw_context
.drawinfo
.end
.offset
.under
= 0;
676 PropertiesLine prop_line
= prepare_s_e_line(process
);
677 draw_line((void*)&prop_line
, (void*)&draw_context
);
681 /* become the last x position */
682 hashed_process_data
->x
.middle
= x
;
683 hashed_process_data
->x
.middle_used
= TRUE
;
684 hashed_process_data
->x
.middle_marked
= FALSE
;
686 /* Calculate the next good time */
687 convert_pixels_to_time(width
, x
+1, time_window
,
688 &hashed_process_data
->next_good_time
);
692 g_warning("Cannot find pin_in in schedchange %u", pid_in
);
694 tfc
->target_pid
= target_pid_saved
;
702 GString
*string
= g_string_new("");;
703 gboolean field_names
= TRUE
, state
= TRUE
;
705 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
706 g_string_append_printf(string
,"\n");
709 g_string_append_printf(string
, " %s",
710 g_quark_to_string(tfs
->process
->state
->s
));
713 g_info("%s",string
->str
);
715 g_string_free(string
, TRUE
);
717 /* End of text dump */
722 /* after_schedchange_hook
724 * The draw after hook is called by the reading API to have a
725 * particular event drawn on the screen.
726 * @param hook_data ControlFlowData structure of the viewer.
727 * @param call_data Event context.
729 * This function adds items to be drawn in a queue for each process.
732 int after_schedchange_hook(void *hook_data
, void *call_data
)
734 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
735 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
736 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
738 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
740 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
742 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
745 e
= ltt_tracefile_get_event(tfc
->tf
);
747 LttvFilter
*filter
= control_flow_data
->filter
;
748 if(filter
!= NULL
&& filter
->head
!= NULL
)
749 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
750 tfc
->t_context
->t
,tfc
))
753 LttTime evtime
= ltt_event_time(e
);
755 /* Add process to process list (if not present) */
756 LttvProcessState
*process_in
;
759 HashedProcessData
*hashed_process_data_in
= NULL
;
761 ProcessList
*process_list
= control_flow_data
->process_list
;
766 pid_out
= ltt_event_get_long_unsigned(e
, thf
->f1
);
767 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f2
);
771 /* Find process pid_in in the list... */
772 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
773 //process_in = tfs->process;
774 guint cpu
= tfs
->cpu
;
775 process_in
= ts
->running_process
[cpu
];
776 /* It should exist, because we are after the state update. */
778 g_assert(process_in
!= NULL
);
780 birth
= process_in
->creation_time
;
782 hashed_process_data_in
= processlist_get_process_data(process_list
,
786 tfc
->t_context
->index
);
787 if(hashed_process_data_in
== NULL
)
789 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
790 ProcessInfo
*process_info
;
791 Drawing_t
*drawing
= control_flow_data
->drawing
;
792 /* Process not present */
793 processlist_add(process_list
,
800 tfc
->t_context
->index
,
805 &hashed_process_data_in
);
806 gtk_widget_set_size_request(drawing
->drawing_area
,
809 gtk_widget_queue_draw(drawing
->drawing_area
);
811 /* Set the current process */
812 process_list
->current_hash_data
[process_in
->cpu
] =
813 hashed_process_data_in
;
815 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
818 TimeWindow time_window
=
819 lttvwindow_get_time_window(control_flow_data
->tab
);
822 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
823 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
826 Drawing_t
*drawing
= control_flow_data
->drawing
;
827 guint width
= drawing
->width
;
830 convert_time_to_pixels(
836 if(hashed_process_data_in
->x
.middle
!= new_x
) {
837 hashed_process_data_in
->x
.middle
= new_x
;
838 hashed_process_data_in
->x
.middle_used
= FALSE
;
839 hashed_process_data_in
->x
.middle_marked
= FALSE
;
848 /* before_execmode_hook
850 * This function basically draw lines and icons. Two types of lines are drawn :
851 * one small (3 pixels?) representing the state of the process and the second
852 * type is thicker (10 pixels?) representing on which CPU a process is running
853 * (and this only in running state).
855 * Extremums of the lines :
856 * x_min : time of the last event context for this process kept in memory.
857 * x_max : time of the current event.
858 * y : middle of the process in the process list. The process is found in the
859 * list, therefore is it's position in pixels.
861 * The choice of lines'color is defined by the context of the last event for this
866 int before_execmode_hook(void *hook_data
, void *call_data
)
868 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
869 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
870 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
872 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
874 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
876 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
879 e
= ltt_tracefile_get_event(tfc
->tf
);
881 LttvFilter
*filter
= control_flow_data
->filter
;
882 if(filter
!= NULL
&& filter
->head
!= NULL
)
883 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
884 tfc
->t_context
->t
,tfc
))
887 LttTime evtime
= ltt_event_time(e
);
889 /* we are in a execmode, before the state update. We must draw the
890 * items corresponding to the state before it changes : now is the right
894 //LttvProcessState *process = tfs->process;
895 guint cpu
= tfs
->cpu
;
896 LttvProcessState
*process
= ts
->running_process
[cpu
];
897 g_assert(process
!= NULL
);
899 guint pid
= process
->pid
;
901 /* Well, the process_out existed : we must get it in the process hash
902 * or add it, and draw its items.
904 /* Add process to process list (if not present) */
906 HashedProcessData
*hashed_process_data
= NULL
;
907 ProcessList
*process_list
= control_flow_data
->process_list
;
908 LttTime birth
= process
->creation_time
;
910 if(likely(process_list
->current_hash_data
[cpu
] != NULL
)) {
911 hashed_process_data
= process_list
->current_hash_data
[cpu
];
913 hashed_process_data
= processlist_get_process_data(process_list
,
917 tfc
->t_context
->index
);
918 if(unlikely(hashed_process_data
== NULL
))
920 g_assert(pid
== 0 || pid
!= process
->ppid
);
921 ProcessInfo
*process_info
;
922 /* Process not present */
923 Drawing_t
*drawing
= control_flow_data
->drawing
;
924 processlist_add(process_list
,
931 tfc
->t_context
->index
,
936 &hashed_process_data
);
937 gtk_widget_set_size_request(drawing
->drawing_area
,
940 gtk_widget_queue_draw(drawing
->drawing_area
);
942 /* Set the current process */
943 process_list
->current_hash_data
[process
->cpu
] =
947 /* Now, the process is in the state hash and our own process hash.
948 * We definitely can draw the items related to the ending state.
951 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
954 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
955 TimeWindow time_window
=
956 lttvwindow_get_time_window(control_flow_data
->tab
);
959 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
960 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
963 Drawing_t
*drawing
= control_flow_data
->drawing
;
964 guint width
= drawing
->width
;
966 convert_time_to_pixels(
972 /* Draw collision indicator */
973 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
974 gdk_draw_point(hashed_process_data
->pixmap
,
977 (hashed_process_data
->height
/2)-3);
978 hashed_process_data
->x
.middle_marked
= TRUE
;
981 TimeWindow time_window
=
982 lttvwindow_get_time_window(control_flow_data
->tab
);
985 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
986 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
989 Drawing_t
*drawing
= control_flow_data
->drawing
;
990 guint width
= drawing
->width
;
993 convert_time_to_pixels(
1000 /* Jump over draw if we are at the same x position */
1001 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1002 hashed_process_data
->x
.middle_used
))
1004 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1005 /* Draw collision indicator */
1006 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1007 gdk_draw_point(hashed_process_data
->pixmap
,
1010 (hashed_process_data
->height
/2)-3);
1011 hashed_process_data
->x
.middle_marked
= TRUE
;
1016 DrawContext draw_context
;
1017 /* Now create the drawing context that will be used to draw
1018 * items related to the last state. */
1019 draw_context
.drawable
= hashed_process_data
->pixmap
;
1020 draw_context
.gc
= drawing
->gc
;
1021 draw_context
.pango_layout
= drawing
->pango_layout
;
1022 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1023 draw_context
.drawinfo
.end
.x
= x
;
1025 draw_context
.drawinfo
.y
.over
= 1;
1026 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1027 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1029 draw_context
.drawinfo
.start
.offset
.over
= 0;
1030 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1031 draw_context
.drawinfo
.start
.offset
.under
= 0;
1032 draw_context
.drawinfo
.end
.offset
.over
= 0;
1033 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1034 draw_context
.drawinfo
.end
.offset
.under
= 0;
1038 PropertiesLine prop_line
= prepare_s_e_line(process
);
1039 draw_line((void*)&prop_line
, (void*)&draw_context
);
1042 /* become the last x position */
1043 hashed_process_data
->x
.middle
= x
;
1044 hashed_process_data
->x
.middle_used
= TRUE
;
1045 hashed_process_data
->x
.middle_marked
= FALSE
;
1047 /* Calculate the next good time */
1048 convert_pixels_to_time(width
, x
+1, time_window
,
1049 &hashed_process_data
->next_good_time
);
1056 /* before_process_exit_hook
1058 * Draw lines for process event.
1060 * @param hook_data ControlFlowData structure of the viewer.
1061 * @param call_data Event context.
1063 * This function adds items to be drawn in a queue for each process.
1068 int before_process_exit_hook(void *hook_data
, void *call_data
)
1070 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1071 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1073 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1075 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1077 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1079 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1082 e
= ltt_tracefile_get_event(tfc
->tf
);
1084 LttvFilter
*filter
= control_flow_data
->filter
;
1085 if(filter
!= NULL
&& filter
->head
!= NULL
)
1086 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1087 tfc
->t_context
->t
,tfc
))
1090 LttTime evtime
= ltt_event_time(e
);
1092 /* Add process to process list (if not present) */
1093 //LttvProcessState *process = tfs->process;
1094 guint cpu
= tfs
->cpu
;
1095 LttvProcessState
*process
= ts
->running_process
[cpu
];
1096 guint pid
= process
->pid
;
1098 guint pl_height
= 0;
1099 HashedProcessData
*hashed_process_data
= NULL
;
1101 ProcessList
*process_list
= control_flow_data
->process_list
;
1103 g_assert(process
!= NULL
);
1105 birth
= process
->creation_time
;
1107 if(likely(process_list
->current_hash_data
[cpu
] != NULL
)) {
1108 hashed_process_data
= process_list
->current_hash_data
[cpu
];
1110 hashed_process_data
= processlist_get_process_data(process_list
,
1114 tfc
->t_context
->index
);
1115 if(unlikely(hashed_process_data
== NULL
))
1117 g_assert(pid
== 0 || pid
!= process
->ppid
);
1118 /* Process not present */
1119 Drawing_t
*drawing
= control_flow_data
->drawing
;
1120 ProcessInfo
*process_info
;
1121 processlist_add(process_list
,
1128 tfc
->t_context
->index
,
1133 &hashed_process_data
);
1134 gtk_widget_set_size_request(drawing
->drawing_area
,
1137 gtk_widget_queue_draw(drawing
->drawing_area
);
1141 /* Now, the process is in the state hash and our own process hash.
1142 * We definitely can draw the items related to the ending state.
1145 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1148 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1149 TimeWindow time_window
=
1150 lttvwindow_get_time_window(control_flow_data
->tab
);
1153 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1154 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1156 #endif //EXTRA_CHECK
1157 Drawing_t
*drawing
= control_flow_data
->drawing
;
1158 guint width
= drawing
->width
;
1160 convert_time_to_pixels(
1166 /* Draw collision indicator */
1167 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1168 gdk_draw_point(hashed_process_data
->pixmap
,
1171 (hashed_process_data
->height
/2)-3);
1172 hashed_process_data
->x
.middle_marked
= TRUE
;
1175 TimeWindow time_window
=
1176 lttvwindow_get_time_window(control_flow_data
->tab
);
1179 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1180 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1182 #endif //EXTRA_CHECK
1183 Drawing_t
*drawing
= control_flow_data
->drawing
;
1184 guint width
= drawing
->width
;
1187 convert_time_to_pixels(
1194 /* Jump over draw if we are at the same x position */
1195 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1196 hashed_process_data
->x
.middle_used
))
1198 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1199 /* Draw collision indicator */
1200 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1201 gdk_draw_point(hashed_process_data
->pixmap
,
1204 (hashed_process_data
->height
/2)-3);
1205 hashed_process_data
->x
.middle_marked
= TRUE
;
1209 DrawContext draw_context
;
1211 /* Now create the drawing context that will be used to draw
1212 * items related to the last state. */
1213 draw_context
.drawable
= hashed_process_data
->pixmap
;
1214 draw_context
.gc
= drawing
->gc
;
1215 draw_context
.pango_layout
= drawing
->pango_layout
;
1216 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1217 draw_context
.drawinfo
.end
.x
= x
;
1219 draw_context
.drawinfo
.y
.over
= 1;
1220 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1221 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1223 draw_context
.drawinfo
.start
.offset
.over
= 0;
1224 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1225 draw_context
.drawinfo
.start
.offset
.under
= 0;
1226 draw_context
.drawinfo
.end
.offset
.over
= 0;
1227 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1228 draw_context
.drawinfo
.end
.offset
.under
= 0;
1232 PropertiesLine prop_line
= prepare_s_e_line(process
);
1233 draw_line((void*)&prop_line
, (void*)&draw_context
);
1236 /* become the last x position */
1237 hashed_process_data
->x
.middle
= x
;
1238 hashed_process_data
->x
.middle_used
= TRUE
;
1239 hashed_process_data
->x
.middle_marked
= FALSE
;
1241 /* Calculate the next good time */
1242 convert_pixels_to_time(width
, x
+1, time_window
,
1243 &hashed_process_data
->next_good_time
);
1253 /* before_process_release_hook
1255 * Draw lines for process event.
1257 * @param hook_data ControlFlowData structure of the viewer.
1258 * @param call_data Event context.
1260 * This function adds items to be drawn in a queue for each process.
1265 int before_process_release_hook(void *hook_data
, void *call_data
)
1267 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1268 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1270 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1272 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1274 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1276 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1279 e
= ltt_tracefile_get_event(tfc
->tf
);
1281 LttvFilter
*filter
= control_flow_data
->filter
;
1282 if(filter
!= NULL
&& filter
->head
!= NULL
)
1283 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1284 tfc
->t_context
->t
,tfc
))
1287 LttTime evtime
= ltt_event_time(e
);
1292 pid
= ltt_event_get_long_unsigned(e
, thf
->f1
);
1295 /* Add process to process list (if not present) */
1296 /* Don't care about the process if it's not in the state hash already :
1297 * that means a process that has never done anything in the trace and
1298 * unknown suddently gets destroyed : no state meaningful to show. */
1299 LttvProcessState
*process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1301 if(process
!= NULL
) {
1303 guint pl_height
= 0;
1304 HashedProcessData
*hashed_process_data
= NULL
;
1306 ProcessList
*process_list
= control_flow_data
->process_list
;
1308 birth
= process
->creation_time
;
1310 /* Cannot use current process : this event happens on another process,
1311 * action done by the parent. */
1312 hashed_process_data
= processlist_get_process_data(process_list
,
1316 tfc
->t_context
->index
);
1317 if(unlikely(hashed_process_data
== NULL
))
1319 g_assert(pid
== 0 || pid
!= process
->ppid
);
1320 /* Process not present */
1321 Drawing_t
*drawing
= control_flow_data
->drawing
;
1322 ProcessInfo
*process_info
;
1323 processlist_add(process_list
,
1330 tfc
->t_context
->index
,
1335 &hashed_process_data
);
1336 gtk_widget_set_size_request(drawing
->drawing_area
,
1339 gtk_widget_queue_draw(drawing
->drawing_area
);
1342 /* Now, the process is in the state hash and our own process hash.
1343 * We definitely can draw the items related to the ending state.
1346 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1349 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1350 TimeWindow time_window
=
1351 lttvwindow_get_time_window(control_flow_data
->tab
);
1354 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1355 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1357 #endif //EXTRA_CHECK
1358 Drawing_t
*drawing
= control_flow_data
->drawing
;
1359 guint width
= drawing
->width
;
1361 convert_time_to_pixels(
1367 /* Draw collision indicator */
1368 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1369 gdk_draw_point(hashed_process_data
->pixmap
,
1372 (hashed_process_data
->height
/2)-3);
1373 hashed_process_data
->x
.middle_marked
= TRUE
;
1376 TimeWindow time_window
=
1377 lttvwindow_get_time_window(control_flow_data
->tab
);
1380 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1381 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1383 #endif //EXTRA_CHECK
1384 Drawing_t
*drawing
= control_flow_data
->drawing
;
1385 guint width
= drawing
->width
;
1388 convert_time_to_pixels(
1395 /* Jump over draw if we are at the same x position */
1396 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1397 hashed_process_data
->x
.middle_used
))
1399 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1400 /* Draw collision indicator */
1401 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1402 gdk_draw_point(hashed_process_data
->pixmap
,
1405 (hashed_process_data
->height
/2)-3);
1406 hashed_process_data
->x
.middle_marked
= TRUE
;
1410 DrawContext draw_context
;
1412 /* Now create the drawing context that will be used to draw
1413 * items related to the last state. */
1414 draw_context
.drawable
= hashed_process_data
->pixmap
;
1415 draw_context
.gc
= drawing
->gc
;
1416 draw_context
.pango_layout
= drawing
->pango_layout
;
1417 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1418 draw_context
.drawinfo
.end
.x
= x
;
1420 draw_context
.drawinfo
.y
.over
= 1;
1421 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1422 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1424 draw_context
.drawinfo
.start
.offset
.over
= 0;
1425 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1426 draw_context
.drawinfo
.start
.offset
.under
= 0;
1427 draw_context
.drawinfo
.end
.offset
.over
= 0;
1428 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1429 draw_context
.drawinfo
.end
.offset
.under
= 0;
1433 PropertiesLine prop_line
= prepare_s_e_line(process
);
1434 draw_line((void*)&prop_line
, (void*)&draw_context
);
1437 /* become the last x position */
1438 hashed_process_data
->x
.middle
= x
;
1439 hashed_process_data
->x
.middle_used
= TRUE
;
1440 hashed_process_data
->x
.middle_marked
= FALSE
;
1442 /* Calculate the next good time */
1443 convert_pixels_to_time(width
, x
+1, time_window
,
1444 &hashed_process_data
->next_good_time
);
1456 /* after_process_fork_hook
1458 * Create the processlist entry for the child process. Put the last
1459 * position in x at the current time value.
1461 * @param hook_data ControlFlowData structure of the viewer.
1462 * @param call_data Event context.
1464 * This function adds items to be drawn in a queue for each process.
1467 int after_process_fork_hook(void *hook_data
, void *call_data
)
1469 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1470 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1471 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1473 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1475 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1477 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1480 e
= ltt_tracefile_get_event(tfc
->tf
);
1482 LttvFilter
*filter
= control_flow_data
->filter
;
1483 if(filter
!= NULL
&& filter
->head
!= NULL
)
1484 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1485 tfc
->t_context
->t
,tfc
))
1488 LttTime evtime
= ltt_event_time(e
);
1492 child_pid
= ltt_event_get_long_unsigned(e
, thf
->f2
);
1495 /* Add process to process list (if not present) */
1496 LttvProcessState
*process_child
;
1498 guint pl_height
= 0;
1499 HashedProcessData
*hashed_process_data_child
= NULL
;
1501 ProcessList
*process_list
= control_flow_data
->process_list
;
1503 /* Find child in the list... */
1504 process_child
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1505 /* It should exist, because we are after the state update. */
1506 g_assert(process_child
!= NULL
);
1508 birth
= process_child
->creation_time
;
1510 /* Cannot use current process, because this action is done by the parent
1512 hashed_process_data_child
= processlist_get_process_data(process_list
,
1516 tfc
->t_context
->index
);
1517 if(likely(hashed_process_data_child
== NULL
))
1519 g_assert(child_pid
== 0 || child_pid
!= process_child
->ppid
);
1520 /* Process not present */
1521 Drawing_t
*drawing
= control_flow_data
->drawing
;
1522 ProcessInfo
*process_info
;
1523 processlist_add(process_list
,
1526 process_child
->tgid
,
1528 process_child
->ppid
,
1530 tfc
->t_context
->index
,
1531 process_child
->name
,
1532 process_child
->brand
,
1535 &hashed_process_data_child
);
1536 gtk_widget_set_size_request(drawing
->drawing_area
,
1539 gtk_widget_queue_draw(drawing
->drawing_area
);
1541 processlist_set_ppid(process_list
, process_child
->ppid
,
1542 hashed_process_data_child
);
1543 processlist_set_tgid(process_list
, process_child
->tgid
,
1544 hashed_process_data_child
);
1548 if(likely(ltt_time_compare(hashed_process_data_child
->next_good_time
,
1551 TimeWindow time_window
=
1552 lttvwindow_get_time_window(control_flow_data
->tab
);
1555 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1556 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1558 #endif //EXTRA_CHECK
1559 Drawing_t
*drawing
= control_flow_data
->drawing
;
1560 guint width
= drawing
->width
;
1562 convert_time_to_pixels(
1568 if(likely(hashed_process_data_child
->x
.over
!= new_x
)) {
1569 hashed_process_data_child
->x
.over
= new_x
;
1570 hashed_process_data_child
->x
.over_used
= FALSE
;
1571 hashed_process_data_child
->x
.over_marked
= FALSE
;
1573 if(likely(hashed_process_data_child
->x
.middle
!= new_x
)) {
1574 hashed_process_data_child
->x
.middle
= new_x
;
1575 hashed_process_data_child
->x
.middle_used
= FALSE
;
1576 hashed_process_data_child
->x
.middle_marked
= FALSE
;
1578 if(likely(hashed_process_data_child
->x
.under
!= new_x
)) {
1579 hashed_process_data_child
->x
.under
= new_x
;
1580 hashed_process_data_child
->x
.under_used
= FALSE
;
1581 hashed_process_data_child
->x
.under_marked
= FALSE
;
1589 /* after_process_exit_hook
1591 * Create the processlist entry for the child process. Put the last
1592 * position in x at the current time value.
1594 * @param hook_data ControlFlowData structure of the viewer.
1595 * @param call_data Event context.
1597 * This function adds items to be drawn in a queue for each process.
1600 int after_process_exit_hook(void *hook_data
, void *call_data
)
1602 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1603 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1604 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1606 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1608 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1610 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1613 e
= ltt_tracefile_get_event(tfc
->tf
);
1615 LttvFilter
*filter
= control_flow_data
->filter
;
1616 if(filter
!= NULL
&& filter
->head
!= NULL
)
1617 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1618 tfc
->t_context
->t
,tfc
))
1621 LttTime evtime
= ltt_event_time(e
);
1623 /* Add process to process list (if not present) */
1624 //LttvProcessState *process = tfs->process;
1625 guint cpu
= tfs
->cpu
;
1626 LttvProcessState
*process
= ts
->running_process
[cpu
];
1628 /* It should exist, because we are after the state update. */
1629 g_assert(process
!= NULL
);
1631 guint pid
= process
->pid
;
1633 guint pl_height
= 0;
1634 HashedProcessData
*hashed_process_data
= NULL
;
1636 ProcessList
*process_list
= control_flow_data
->process_list
;
1638 birth
= process
->creation_time
;
1640 if(likely(process_list
->current_hash_data
[cpu
] != NULL
) ){
1641 hashed_process_data
= process_list
->current_hash_data
[cpu
];
1643 hashed_process_data
= processlist_get_process_data(process_list
,
1647 tfc
->t_context
->index
);
1648 if(unlikely(hashed_process_data
== NULL
))
1650 g_assert(pid
== 0 || pid
!= process
->ppid
);
1651 /* Process not present */
1652 Drawing_t
*drawing
= control_flow_data
->drawing
;
1653 ProcessInfo
*process_info
;
1654 processlist_add(process_list
,
1661 tfc
->t_context
->index
,
1666 &hashed_process_data
);
1667 gtk_widget_set_size_request(drawing
->drawing_area
,
1670 gtk_widget_queue_draw(drawing
->drawing_area
);
1673 /* Set the current process */
1674 process_list
->current_hash_data
[process
->cpu
] =
1675 hashed_process_data
;
1678 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
1681 TimeWindow time_window
=
1682 lttvwindow_get_time_window(control_flow_data
->tab
);
1685 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1686 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1688 #endif //EXTRA_CHECK
1689 Drawing_t
*drawing
= control_flow_data
->drawing
;
1690 guint width
= drawing
->width
;
1692 convert_time_to_pixels(
1697 if(unlikely(hashed_process_data
->x
.middle
!= new_x
)) {
1698 hashed_process_data
->x
.middle
= new_x
;
1699 hashed_process_data
->x
.middle_used
= FALSE
;
1700 hashed_process_data
->x
.middle_marked
= FALSE
;
1708 /* Get the filename of the process to print */
1709 int after_fs_exec_hook(void *hook_data
, void *call_data
)
1711 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1712 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1713 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1715 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1717 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1719 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1722 e
= ltt_tracefile_get_event(tfc
->tf
);
1724 LttvFilter
*filter
= control_flow_data
->filter
;
1725 if(filter
!= NULL
&& filter
->head
!= NULL
)
1726 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1727 tfc
->t_context
->t
,tfc
))
1730 guint cpu
= tfs
->cpu
;
1731 LttvProcessState
*process
= ts
->running_process
[cpu
];
1732 g_assert(process
!= NULL
);
1734 guint pid
= process
->pid
;
1736 /* Well, the process_out existed : we must get it in the process hash
1737 * or add it, and draw its items.
1739 /* Add process to process list (if not present) */
1740 guint pl_height
= 0;
1741 HashedProcessData
*hashed_process_data
= NULL
;
1742 ProcessList
*process_list
= control_flow_data
->process_list
;
1743 LttTime birth
= process
->creation_time
;
1745 if(likely(process_list
->current_hash_data
[cpu
] != NULL
)) {
1746 hashed_process_data
= process_list
->current_hash_data
[cpu
];
1748 hashed_process_data
= processlist_get_process_data(process_list
,
1752 tfc
->t_context
->index
);
1753 if(unlikely(hashed_process_data
== NULL
))
1755 g_assert(pid
== 0 || pid
!= process
->ppid
);
1756 ProcessInfo
*process_info
;
1757 /* Process not present */
1758 Drawing_t
*drawing
= control_flow_data
->drawing
;
1759 processlist_add(process_list
,
1766 tfc
->t_context
->index
,
1771 &hashed_process_data
);
1772 gtk_widget_set_size_request(drawing
->drawing_area
,
1775 gtk_widget_queue_draw(drawing
->drawing_area
);
1777 /* Set the current process */
1778 process_list
->current_hash_data
[process
->cpu
] =
1779 hashed_process_data
;
1782 processlist_set_name(process_list
, process
->name
, hashed_process_data
);
1788 /* Get the filename of the process to print */
1789 int after_user_generic_thread_brand_hook(void *hook_data
, void *call_data
)
1791 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1792 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1793 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1795 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1797 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1799 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1802 e
= ltt_tracefile_get_event(tfc
->tf
);
1804 LttvFilter
*filter
= control_flow_data
->filter
;
1805 if(filter
!= NULL
&& filter
->head
!= NULL
)
1806 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1807 tfc
->t_context
->t
,tfc
))
1810 guint cpu
= tfs
->cpu
;
1811 LttvProcessState
*process
= ts
->running_process
[cpu
];
1812 g_assert(process
!= NULL
);
1814 guint pid
= process
->pid
;
1816 /* Well, the process_out existed : we must get it in the process hash
1817 * or add it, and draw its items.
1819 /* Add process to process list (if not present) */
1820 guint pl_height
= 0;
1821 HashedProcessData
*hashed_process_data
= NULL
;
1822 ProcessList
*process_list
= control_flow_data
->process_list
;
1823 LttTime birth
= process
->creation_time
;
1825 if(likely(process_list
->current_hash_data
[cpu
] != NULL
)) {
1826 hashed_process_data
= process_list
->current_hash_data
[cpu
];
1828 hashed_process_data
= processlist_get_process_data(process_list
,
1832 tfc
->t_context
->index
);
1833 if(unlikely(hashed_process_data
== NULL
))
1835 g_assert(pid
== 0 || pid
!= process
->ppid
);
1836 ProcessInfo
*process_info
;
1837 /* Process not present */
1838 Drawing_t
*drawing
= control_flow_data
->drawing
;
1839 processlist_add(process_list
,
1846 tfc
->t_context
->index
,
1851 &hashed_process_data
);
1852 gtk_widget_set_size_request(drawing
->drawing_area
,
1855 gtk_widget_queue_draw(drawing
->drawing_area
);
1857 /* Set the current process */
1858 process_list
->current_hash_data
[process
->cpu
] =
1859 hashed_process_data
;
1862 processlist_set_brand(process_list
, process
->brand
, hashed_process_data
);
1869 /* after_event_enum_process_hook
1871 * Create the processlist entry for the child process. Put the last
1872 * position in x at the current time value.
1874 * @param hook_data ControlFlowData structure of the viewer.
1875 * @param call_data Event context.
1877 * This function adds items to be drawn in a queue for each process.
1880 int after_event_enum_process_hook(void *hook_data
, void *call_data
)
1882 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1883 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1884 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1886 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1888 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1890 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1893 e
= ltt_tracefile_get_event(tfc
->tf
);
1895 LttvFilter
*filter
= control_flow_data
->filter
;
1896 if(filter
!= NULL
&& filter
->head
!= NULL
)
1897 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1898 tfc
->t_context
->t
,tfc
))
1901 LttTime evtime
= ltt_event_time(e
);
1903 /* Add process to process list (if not present) */
1904 LttvProcessState
*process_in
;
1906 guint pl_height
= 0;
1907 HashedProcessData
*hashed_process_data_in
= NULL
;
1909 ProcessList
*process_list
= control_flow_data
->process_list
;
1913 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f1
);
1917 /* Find process pid_in in the list... */
1918 process_in
= lttv_state_find_process(ts
, ANY_CPU
, pid_in
);
1919 //process_in = tfs->process;
1920 //guint cpu = tfs->cpu;
1921 //process_in = ts->running_process[cpu];
1922 /* It should exist, because we are after the state update. */
1924 //g_assert(process_in != NULL);
1925 #endif //EXTRA_CHECK
1926 birth
= process_in
->creation_time
;
1928 hashed_process_data_in
= processlist_get_process_data(process_list
,
1932 tfc
->t_context
->index
);
1933 if(hashed_process_data_in
== NULL
)
1935 if(pid_in
!= 0 && pid_in
== process_in
->ppid
)
1936 g_critical("TEST %u , %u", pid_in
, process_in
->ppid
);
1937 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
1938 ProcessInfo
*process_info
;
1939 Drawing_t
*drawing
= control_flow_data
->drawing
;
1940 /* Process not present */
1941 processlist_add(process_list
,
1948 tfc
->t_context
->index
,
1953 &hashed_process_data_in
);
1954 gtk_widget_set_size_request(drawing
->drawing_area
,
1957 gtk_widget_queue_draw(drawing
->drawing_area
);
1959 processlist_set_name(process_list
, process_in
->name
,
1960 hashed_process_data_in
);
1961 processlist_set_ppid(process_list
, process_in
->ppid
,
1962 hashed_process_data_in
);
1963 processlist_set_tgid(process_list
, process_in
->tgid
,
1964 hashed_process_data_in
);
1970 gint
update_time_window_hook(void *hook_data
, void *call_data
)
1972 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1973 Drawing_t
*drawing
= control_flow_data
->drawing
;
1974 ProcessList
*process_list
= control_flow_data
->process_list
;
1976 const TimeWindowNotifyData
*time_window_nofify_data
=
1977 ((const TimeWindowNotifyData
*)call_data
);
1979 TimeWindow
*old_time_window
=
1980 time_window_nofify_data
->old_time_window
;
1981 TimeWindow
*new_time_window
=
1982 time_window_nofify_data
->new_time_window
;
1984 /* Update the ruler */
1985 drawing_update_ruler(control_flow_data
->drawing
,
1989 /* Two cases : zoom in/out or scrolling */
1991 /* In order to make sure we can reuse the old drawing, the scale must
1992 * be the same and the new time interval being partly located in the
1993 * currently shown time interval. (reuse is only for scrolling)
1996 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
1997 old_time_window
->start_time
.tv_sec
,
1998 old_time_window
->start_time
.tv_nsec
,
1999 old_time_window
->time_width
.tv_sec
,
2000 old_time_window
->time_width
.tv_nsec
);
2002 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
2003 new_time_window
->start_time
.tv_sec
,
2004 new_time_window
->start_time
.tv_nsec
,
2005 new_time_window
->time_width
.tv_sec
,
2006 new_time_window
->time_width
.tv_nsec
);
2008 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
2009 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
2011 /* Same scale (scrolling) */
2012 g_info("scrolling");
2013 LttTime
*ns
= &new_time_window
->start_time
;
2014 LttTime
*nw
= &new_time_window
->time_width
;
2015 LttTime
*os
= &old_time_window
->start_time
;
2016 LttTime
*ow
= &old_time_window
->time_width
;
2017 LttTime old_end
= old_time_window
->end_time
;
2018 LttTime new_end
= new_time_window
->end_time
;
2020 //if(ns<os+w && os+w<ns+w)
2021 //if(ns<old_end && os<ns)
2022 if(ltt_time_compare(*ns
, old_end
) == -1
2023 && ltt_time_compare(*os
, *ns
) == -1)
2025 g_info("scrolling near right");
2026 /* Scroll right, keep right part of the screen */
2028 guint width
= control_flow_data
->drawing
->width
;
2029 convert_time_to_pixels(
2035 /* Copy old data to new location */
2036 copy_pixmap_region(process_list
,
2038 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2042 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
2044 if(drawing
->damage_begin
== drawing
->damage_end
)
2045 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
2047 drawing
->damage_begin
= 0;
2049 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2051 /* Clear the data request background, but not SAFETY */
2052 rectangle_pixmap(process_list
,
2053 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2055 drawing
->damage_begin
+SAFETY
, 0,
2056 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2058 gtk_widget_queue_draw(drawing
->drawing_area
);
2059 //gtk_widget_queue_draw_area (drawing->drawing_area,
2061 // control_flow_data->drawing->width,
2062 // control_flow_data->drawing->height);
2064 /* Get new data for the rest. */
2065 drawing_data_request(control_flow_data
->drawing
,
2066 drawing
->damage_begin
, 0,
2067 drawing
->damage_end
- drawing
->damage_begin
,
2068 control_flow_data
->drawing
->height
);
2071 //if(ns<os && os<ns+w)
2072 //if(ns<os && os<new_end)
2073 if(ltt_time_compare(*ns
,*os
) == -1
2074 && ltt_time_compare(*os
,new_end
) == -1)
2076 g_info("scrolling near left");
2077 /* Scroll left, keep left part of the screen */
2079 guint width
= control_flow_data
->drawing
->width
;
2080 convert_time_to_pixels(
2086 /* Copy old data to new location */
2087 copy_pixmap_region (process_list
,
2089 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2095 if(drawing
->damage_begin
== drawing
->damage_end
)
2096 drawing
->damage_end
= x
;
2098 drawing
->damage_end
=
2099 control_flow_data
->drawing
->width
;
2101 drawing
->damage_begin
= 0;
2103 rectangle_pixmap (process_list
,
2104 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2106 drawing
->damage_begin
, 0,
2107 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2110 gtk_widget_queue_draw(drawing
->drawing_area
);
2111 //gtk_widget_queue_draw_area (drawing->drawing_area,
2113 // control_flow_data->drawing->width,
2114 // control_flow_data->drawing->height);
2117 /* Get new data for the rest. */
2118 drawing_data_request(control_flow_data
->drawing
,
2119 drawing
->damage_begin
, 0,
2120 drawing
->damage_end
- drawing
->damage_begin
,
2121 control_flow_data
->drawing
->height
);
2124 if(ltt_time_compare(*ns
,*os
) == 0)
2126 g_info("not scrolling");
2128 g_info("scrolling far");
2129 /* Cannot reuse any part of the screen : far jump */
2132 rectangle_pixmap (process_list
,
2133 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2136 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2139 //gtk_widget_queue_draw_area (drawing->drawing_area,
2141 // control_flow_data->drawing->width,
2142 // control_flow_data->drawing->height);
2143 gtk_widget_queue_draw(drawing
->drawing_area
);
2145 drawing
->damage_begin
= 0;
2146 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2148 drawing_data_request(control_flow_data
->drawing
,
2150 control_flow_data
->drawing
->width
,
2151 control_flow_data
->drawing
->height
);
2157 /* Different scale (zoom) */
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
);
2182 /* Update directly when scrolling */
2183 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2189 gint
traceset_notify(void *hook_data
, void *call_data
)
2191 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2192 Drawing_t
*drawing
= control_flow_data
->drawing
;
2194 if(unlikely(drawing
->gc
== NULL
)) {
2197 if(drawing
->dotted_gc
== NULL
) {
2201 drawing_clear(control_flow_data
->drawing
);
2202 processlist_clear(control_flow_data
->process_list
);
2203 gtk_widget_set_size_request(
2204 control_flow_data
->drawing
->drawing_area
,
2205 -1, processlist_get_height(control_flow_data
->process_list
));
2206 redraw_notify(control_flow_data
, NULL
);
2208 request_background_data(control_flow_data
);
2213 gint
redraw_notify(void *hook_data
, void *call_data
)
2215 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2216 Drawing_t
*drawing
= control_flow_data
->drawing
;
2217 GtkWidget
*widget
= drawing
->drawing_area
;
2219 drawing
->damage_begin
= 0;
2220 drawing
->damage_end
= drawing
->width
;
2222 /* fun feature, to be separated someday... */
2223 drawing_clear(control_flow_data
->drawing
);
2224 processlist_clear(control_flow_data
->process_list
);
2225 gtk_widget_set_size_request(
2226 control_flow_data
->drawing
->drawing_area
,
2227 -1, processlist_get_height(control_flow_data
->process_list
));
2229 rectangle_pixmap (control_flow_data
->process_list
,
2230 widget
->style
->black_gc
,
2233 drawing
->alloc_width
,
2236 gtk_widget_queue_draw(drawing
->drawing_area
);
2238 if(drawing
->damage_begin
< drawing
->damage_end
)
2240 drawing_data_request(drawing
,
2241 drawing
->damage_begin
,
2243 drawing
->damage_end
-drawing
->damage_begin
,
2247 //gtk_widget_queue_draw_area(drawing->drawing_area,
2250 // drawing->height);
2256 gint
continue_notify(void *hook_data
, void *call_data
)
2258 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2259 Drawing_t
*drawing
= control_flow_data
->drawing
;
2261 //g_assert(widget->allocation.width == drawing->damage_end);
2263 if(drawing
->damage_begin
< drawing
->damage_end
)
2265 drawing_data_request(drawing
,
2266 drawing
->damage_begin
,
2268 drawing
->damage_end
-drawing
->damage_begin
,
2276 gint
update_current_time_hook(void *hook_data
, void *call_data
)
2278 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
2279 Drawing_t
*drawing
= control_flow_data
->drawing
;
2281 LttTime current_time
= *((LttTime
*)call_data
);
2283 TimeWindow time_window
=
2284 lttvwindow_get_time_window(control_flow_data
->tab
);
2286 LttTime time_begin
= time_window
.start_time
;
2287 LttTime width
= time_window
.time_width
;
2290 guint64 time_ll
= ltt_time_to_uint64(width
);
2291 time_ll
= time_ll
>> 1; /* divide by two */
2292 half_width
= ltt_time_from_uint64(time_ll
);
2294 LttTime time_end
= ltt_time_add(time_begin
, width
);
2296 LttvTracesetContext
* tsc
=
2297 lttvwindow_get_traceset_context(control_flow_data
->tab
);
2299 LttTime trace_start
= tsc
->time_span
.start_time
;
2300 LttTime trace_end
= tsc
->time_span
.end_time
;
2302 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
2303 current_time
.tv_nsec
);
2307 /* If current time is inside time interval, just move the highlight
2310 /* Else, we have to change the time interval. We have to tell it
2311 * to the main window. */
2312 /* The time interval change will take care of placing the current
2313 * time at the center of the visible area, or nearest possible if we are
2314 * at one end of the trace. */
2317 if(ltt_time_compare(current_time
, time_begin
) < 0)
2319 TimeWindow new_time_window
;
2321 if(ltt_time_compare(current_time
,
2322 ltt_time_add(trace_start
,half_width
)) < 0)
2323 time_begin
= trace_start
;
2325 time_begin
= ltt_time_sub(current_time
,half_width
);
2327 new_time_window
.start_time
= time_begin
;
2328 new_time_window
.time_width
= width
;
2329 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2330 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2332 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2334 else if(ltt_time_compare(current_time
, time_end
) > 0)
2336 TimeWindow new_time_window
;
2338 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
2339 time_begin
= ltt_time_sub(trace_end
,width
);
2341 time_begin
= ltt_time_sub(current_time
,half_width
);
2343 new_time_window
.start_time
= time_begin
;
2344 new_time_window
.time_width
= width
;
2345 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2346 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2348 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2351 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2353 /* Update directly when scrolling */
2354 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2360 typedef struct _ClosureData
{
2361 EventsRequest
*events_request
;
2362 LttvTracesetState
*tss
;
2368 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
2370 ProcessInfo
*process_info
= (ProcessInfo
*)key
;
2371 HashedProcessData
*hashed_process_data
= (HashedProcessData
*)value
;
2372 ClosureData
*closure_data
= (ClosureData
*)user_data
;
2374 EventsRequest
*events_request
= closure_data
->events_request
;
2375 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2377 LttvTracesetState
*tss
= closure_data
->tss
;
2378 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)tss
;
2380 LttTime evtime
= closure_data
->end_time
;
2383 /* For the process */
2384 /* First, check if the current process is in the state computation
2385 * process list. If it is there, that means we must add it right now and
2386 * draw items from the beginning of the read for it. If it is not
2387 * present, it's a new process and it was not present : it will
2388 * be added after the state update. */
2390 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
2391 #endif //EXTRA_CHECK
2392 LttvTraceContext
*tc
= tsc
->traces
[process_info
->trace_num
];
2393 LttvTraceState
*ts
= (LttvTraceState
*)tc
;
2396 //FIXME : optimize data structures.
2397 LttvTracefileState
*tfs
;
2398 LttvTracefileContext
*tfc
;
2400 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
2401 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
2402 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
2403 && tfs
->cpu
== process_info
->cpu
)
2407 g_assert(i
<tc
->tracefiles
->len
);
2408 tfs
= LTTV_TRACEFILE_STATE(tfc
);
2410 // LttvTracefileState *tfs =
2411 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2412 // tracefiles[process_info->cpu];
2414 LttvProcessState
*process
;
2415 process
= lttv_state_find_process(ts
, process_info
->cpu
,
2418 if(unlikely(process
!= NULL
)) {
2420 /* Only draw for processes that are currently in the trace states */
2422 ProcessList
*process_list
= control_flow_data
->process_list
;
2424 /* Should be alike when background info is ready */
2425 if(control_flow_data
->background_info_waiting
==0)
2426 g_assert(ltt_time_compare(process
->creation_time
,
2427 process_info
->birth
) == 0);
2428 #endif //EXTRA_CHECK
2430 /* Now, the process is in the state hash and our own process hash.
2431 * We definitely can draw the items related to the ending state.
2434 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2437 TimeWindow time_window
=
2438 lttvwindow_get_time_window(control_flow_data
->tab
);
2441 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2442 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2444 #endif //EXTRA_CHECK
2445 Drawing_t
*drawing
= control_flow_data
->drawing
;
2446 guint width
= drawing
->width
;
2448 guint x
= closure_data
->x_end
;
2450 DrawContext draw_context
;
2452 /* Now create the drawing context that will be used to draw
2453 * items related to the last state. */
2454 draw_context
.drawable
= hashed_process_data
->pixmap
;
2455 draw_context
.gc
= drawing
->gc
;
2456 draw_context
.pango_layout
= drawing
->pango_layout
;
2457 draw_context
.drawinfo
.end
.x
= x
;
2459 draw_context
.drawinfo
.y
.over
= 1;
2460 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2461 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2463 draw_context
.drawinfo
.start
.offset
.over
= 0;
2464 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2465 draw_context
.drawinfo
.start
.offset
.under
= 0;
2466 draw_context
.drawinfo
.end
.offset
.over
= 0;
2467 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2468 draw_context
.drawinfo
.end
.offset
.under
= 0;
2470 /* Jump over draw if we are at the same x position */
2471 if(x
== hashed_process_data
->x
.over
)
2475 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2477 PropertiesLine prop_line
= prepare_execmode_line(process
);
2478 draw_line((void*)&prop_line
, (void*)&draw_context
);
2480 hashed_process_data
->x
.over
= x
;
2484 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2485 hashed_process_data
->x
.middle_used
)) {
2486 #if 0 /* do not mark closure : not missing information */
2487 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2488 /* Draw collision indicator */
2489 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2490 gdk_draw_point(drawing
->pixmap
,
2494 hashed_process_data
->x
.middle_marked
= TRUE
;
2499 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2501 PropertiesLine prop_line
= prepare_s_e_line(process
);
2502 draw_line((void*)&prop_line
, (void*)&draw_context
);
2504 /* become the last x position */
2505 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2506 hashed_process_data
->x
.middle
= x
;
2507 /* but don't use the pixel */
2508 hashed_process_data
->x
.middle_used
= FALSE
;
2510 /* Calculate the next good time */
2511 convert_pixels_to_time(width
, x
+1, time_window
,
2512 &hashed_process_data
->next_good_time
);
2521 int before_chunk(void *hook_data
, void *call_data
)
2523 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2524 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2525 ControlFlowData
*cfd
= (ControlFlowData
*)events_request
->viewer_data
;
2527 /* Desactivate sort */
2528 gtk_tree_sortable_set_sort_column_id(
2529 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2531 GTK_SORT_ASCENDING
);
2533 drawing_chunk_begin(events_request
, tss
);
2538 int before_request(void *hook_data
, void *call_data
)
2540 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2541 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2543 drawing_data_request_begin(events_request
, tss
);
2550 * after request is necessary in addition of after chunk in order to draw
2551 * lines until the end of the screen. after chunk just draws lines until
2558 int after_request(void *hook_data
, void *call_data
)
2560 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2561 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2562 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2564 ProcessList
*process_list
= control_flow_data
->process_list
;
2565 LttTime end_time
= events_request
->end_time
;
2567 ClosureData closure_data
;
2568 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2569 closure_data
.tss
= tss
;
2570 closure_data
.end_time
= end_time
;
2572 TimeWindow time_window
=
2573 lttvwindow_get_time_window(control_flow_data
->tab
);
2574 guint width
= control_flow_data
->drawing
->width
;
2575 convert_time_to_pixels(
2579 &closure_data
.x_end
);
2582 /* Draw last items */
2583 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2584 (void*)&closure_data
);
2587 /* Request expose */
2588 drawing_request_expose(events_request
, tss
, end_time
);
2597 int after_chunk(void *hook_data
, void *call_data
)
2599 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2600 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2601 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2602 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)call_data
;
2603 LttvTracefileContext
*tfc
= lttv_traceset_context_get_current_tfc(tsc
);
2606 ProcessList
*process_list
= control_flow_data
->process_list
;
2608 g_free(process_list
->current_hash_data
);
2609 process_list
->current_hash_data
= NULL
;
2612 end_time
= LTT_TIME_MIN(tfc
->timestamp
, events_request
->end_time
);
2613 else /* end of traceset, or position now out of request : end */
2614 end_time
= events_request
->end_time
;
2616 ClosureData closure_data
;
2617 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2618 closure_data
.tss
= tss
;
2619 closure_data
.end_time
= end_time
;
2621 TimeWindow time_window
=
2622 lttvwindow_get_time_window(control_flow_data
->tab
);
2623 guint width
= control_flow_data
->drawing
->width
;
2624 convert_time_to_pixels(
2628 &closure_data
.x_end
);
2630 /* Draw last items */
2631 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2632 (void*)&closure_data
);
2634 /* Reactivate sort */
2635 gtk_tree_sortable_set_sort_column_id(
2636 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2637 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2638 GTK_SORT_ASCENDING
);
2640 update_index_to_pixmap(control_flow_data
->process_list
);
2641 /* Request a full expose : drawing scrambled */
2642 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2644 /* Request expose (updates damages zone also) */
2645 drawing_request_expose(events_request
, tss
, end_time
);