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
);
126 LttvHooks
*background_ready_hook
=
128 lttv_hooks_add(background_ready_hook
, background_ready
, control_flow_data
,
130 control_flow_data
->background_info_waiting
= 0;
132 for(i
=0;i
<num_traces
;i
++) {
133 trace
= lttv_traceset_get(tsc
->ts
, i
);
135 if(lttvwindowtraces_get_ready(g_quark_from_string("state"),trace
)==FALSE
) {
137 if(lttvwindowtraces_get_in_progress(g_quark_from_string("state"),
139 /* We first remove requests that could have been done for the same
140 * information. Happens when two viewers ask for it before servicing
143 if(!lttvwindowtraces_background_request_find(trace
, "state"))
144 lttvwindowtraces_background_request_queue(
145 main_window_get_widget(control_flow_data
->tab
), trace
, "state");
146 lttvwindowtraces_background_notify_queue(control_flow_data
,
150 background_ready_hook
);
151 control_flow_data
->background_info_waiting
++;
152 } else { /* in progress */
154 lttvwindowtraces_background_notify_current(control_flow_data
,
158 background_ready_hook
);
159 control_flow_data
->background_info_waiting
++;
162 /* Data ready. Be its nature, this viewer doesn't need to have
163 * its data ready hook called there, because a background
164 * request is always linked with a redraw.
170 lttv_hooks_destroy(background_ready_hook
);
177 * Event Viewer's constructor hook
179 * This constructor is given as a parameter to the menuitem and toolbar button
180 * registration. It creates the list.
181 * @param tab A pointer to the parent tab.
182 * @return The widget created.
185 h_guicontrolflow(LttvPlugin
*plugin
)
187 LttvPluginTab
*ptab
= LTTV_PLUGIN_TAB(plugin
);
188 Tab
*tab
= ptab
->tab
;
189 g_info("h_guicontrolflow, %p", tab
);
190 ControlFlowData
*control_flow_data
= guicontrolflow(ptab
);
192 control_flow_data
->tab
= tab
;
194 // Unreg done in the GuiControlFlow_Destructor
195 lttvwindow_register_traceset_notify(tab
,
199 lttvwindow_register_time_window_notify(tab
,
200 update_time_window_hook
,
202 lttvwindow_register_current_time_notify(tab
,
203 update_current_time_hook
,
205 lttvwindow_register_redraw_notify(tab
,
208 lttvwindow_register_continue_notify(tab
,
211 request_background_data(control_flow_data
);
214 return guicontrolflow_get_widget(control_flow_data
) ;
218 void legend_destructor(GtkWindow
*legend
)
220 g_legend_list
= g_slist_remove(g_legend_list
, legend
);
223 /* Create a popup legend */
225 h_legend(LttvPlugin
*plugin
)
227 LttvPluginTab
*ptab
= LTTV_PLUGIN_TAB(plugin
);
228 Tab
*tab
= ptab
->tab
;
229 g_info("h_legend, %p", tab
);
231 GtkWindow
*legend
= GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL
));
233 g_legend_list
= g_slist_append(
237 g_object_set_data_full(
241 (GDestroyNotify
)legend_destructor
);
243 gtk_window_set_title(legend
, "Control Flow View Legend");
245 GtkWidget
*pixmap
= create_pixmap(GTK_WIDGET(legend
), "lttv-color-list.png");
247 // GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixmap(
248 // GDK_PIXMAP(pixmap), NULL));
250 gtk_container_add(GTK_CONTAINER(legend
), GTK_WIDGET(pixmap
));
252 gtk_widget_show(GTK_WIDGET(pixmap
));
253 gtk_widget_show(GTK_WIDGET(legend
));
256 return NULL
; /* This is a popup window */
260 int event_selected_hook(void *hook_data
, void *call_data
)
262 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
263 guint
*event_number
= (guint
*) call_data
;
265 g_debug("DEBUG : event selected by main window : %u", *event_number
);
270 /* Function that selects the color of status&exemode line */
271 static inline PropertiesLine
prepare_s_e_line(LttvProcessState
*process
)
273 PropertiesLine prop_line
;
274 prop_line
.line_width
= STATE_LINE_WIDTH
;
275 prop_line
.style
= GDK_LINE_SOLID
;
276 prop_line
.y
= MIDDLE
;
277 //GdkColormap *colormap = gdk_colormap_get_system();
279 if(process
->state
->s
== LTTV_STATE_RUN
) {
280 if(process
->state
->t
== LTTV_STATE_USER_MODE
)
281 prop_line
.color
= drawing_colors
[COL_RUN_USER_MODE
];
282 else if(process
->state
->t
== LTTV_STATE_SYSCALL
)
283 prop_line
.color
= drawing_colors
[COL_RUN_SYSCALL
];
284 else if(process
->state
->t
== LTTV_STATE_TRAP
)
285 prop_line
.color
= drawing_colors
[COL_RUN_TRAP
];
286 else if(process
->state
->t
== LTTV_STATE_IRQ
)
287 prop_line
.color
= drawing_colors
[COL_RUN_IRQ
];
288 else if(process
->state
->t
== LTTV_STATE_SOFT_IRQ
)
289 prop_line
.color
= drawing_colors
[COL_RUN_SOFT_IRQ
];
290 else if(process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
)
291 prop_line
.color
= drawing_colors
[COL_MODE_UNKNOWN
];
293 g_assert(FALSE
); /* RUNNING MODE UNKNOWN */
294 } else if(process
->state
->s
== LTTV_STATE_WAIT
) {
295 /* We don't show if we wait while in user mode, trap, irq or syscall */
296 prop_line
.color
= drawing_colors
[COL_WAIT
];
297 } else if(process
->state
->s
== LTTV_STATE_WAIT_CPU
) {
298 /* We don't show if we wait for CPU while in user mode, trap, irq
300 prop_line
.color
= drawing_colors
[COL_WAIT_CPU
];
301 } else if(process
->state
->s
== LTTV_STATE_ZOMBIE
) {
302 prop_line
.color
= drawing_colors
[COL_ZOMBIE
];
303 } else if(process
->state
->s
== LTTV_STATE_WAIT_FORK
) {
304 prop_line
.color
= drawing_colors
[COL_WAIT_FORK
];
305 } else if(process
->state
->s
== LTTV_STATE_EXIT
) {
306 prop_line
.color
= drawing_colors
[COL_EXIT
];
307 } else if(process
->state
->s
== LTTV_STATE_UNNAMED
) {
308 prop_line
.color
= drawing_colors
[COL_UNNAMED
];
310 g_critical("unknown state : %s", g_quark_to_string(process
->state
->s
));
311 g_assert(FALSE
); /* UNKNOWN STATE */
319 /* before_schedchange_hook
321 * This function basically draw lines and icons. Two types of lines are drawn :
322 * one small (3 pixels?) representing the state of the process and the second
323 * type is thicker (10 pixels?) representing on which CPU a process is running
324 * (and this only in running state).
326 * Extremums of the lines :
327 * x_min : time of the last event context for this process kept in memory.
328 * x_max : time of the current event.
329 * y : middle of the process in the process list. The process is found in the
330 * list, therefore is it's position in pixels.
332 * The choice of lines'color is defined by the context of the last event for this
337 int before_schedchange_hook(void *hook_data
, void *call_data
)
339 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
340 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
341 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
343 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
345 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
346 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
349 e
= ltt_tracefile_get_event(tfc
->tf
);
350 gint target_pid_saved
= tfc
->target_pid
;
352 LttTime evtime
= ltt_event_time(e
);
353 LttvFilter
*filter
= control_flow_data
->filter
;
355 /* we are in a schedchange, before the state update. We must draw the
356 * items corresponding to the state before it changes : now is the right
363 pid_out
= ltt_event_get_long_unsigned(e
, thf
->f1
);
364 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f2
);
367 tfc
->target_pid
= pid_out
;
368 if(!filter
|| !filter
->head
||
369 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
370 tfc
->t_context
->t
,tfc
)) {
371 /* For the pid_out */
372 /* First, check if the current process is in the state computation
373 * process list. If it is there, that means we must add it right now and
374 * draw items from the beginning of the read for it. If it is not
375 * present, it's a new process and it was not present : it will
376 * be added after the state update. */
377 guint cpu
= tfs
->cpu
;
378 guint trace_num
= ts
->parent
.index
;
379 LttvProcessState
*process
= ts
->running_process
[cpu
];
380 /* unknown state, bad current pid */
381 if(process
->pid
!= pid_out
)
382 process
= lttv_state_find_process(ts
,
385 if(process
!= NULL
) {
386 /* Well, the process_out existed : we must get it in the process hash
387 * or add it, and draw its items.
389 /* Add process to process list (if not present) */
391 HashedProcessData
*hashed_process_data
= NULL
;
392 ProcessList
*process_list
= control_flow_data
->process_list
;
393 LttTime birth
= process
->creation_time
;
395 hashed_process_data
= processlist_get_process_data(process_list
,
400 if(hashed_process_data
== NULL
)
402 g_assert(pid_out
== 0 || pid_out
!= process
->ppid
);
403 /* Process not present */
404 ProcessInfo
*process_info
;
405 Drawing_t
*drawing
= control_flow_data
->drawing
;
406 processlist_add(process_list
,
418 &hashed_process_data
);
419 gtk_widget_set_size_request(drawing
->drawing_area
,
422 gtk_widget_queue_draw(drawing
->drawing_area
);
426 /* Now, the process is in the state hash and our own process hash.
427 * We definitely can draw the items related to the ending state.
430 if(ltt_time_compare(hashed_process_data
->next_good_time
,
433 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
435 TimeWindow time_window
=
436 lttvwindow_get_time_window(control_flow_data
->tab
);
438 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
439 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
442 Drawing_t
*drawing
= control_flow_data
->drawing
;
443 guint width
= drawing
->width
;
445 convert_time_to_pixels(
451 /* Draw collision indicator */
452 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
453 gdk_draw_point(hashed_process_data
->pixmap
,
456 COLLISION_POSITION(hashed_process_data
->height
));
457 hashed_process_data
->x
.middle_marked
= TRUE
;
460 TimeWindow time_window
=
461 lttvwindow_get_time_window(control_flow_data
->tab
);
463 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
464 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
467 Drawing_t
*drawing
= control_flow_data
->drawing
;
468 guint width
= drawing
->width
;
470 convert_time_to_pixels(
477 /* Jump over draw if we are at the same x position */
478 if(x
== hashed_process_data
->x
.middle
&&
479 hashed_process_data
->x
.middle_used
)
481 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
482 /* Draw collision indicator */
483 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
484 gdk_draw_point(hashed_process_data
->pixmap
,
487 COLLISION_POSITION(hashed_process_data
->height
));
488 hashed_process_data
->x
.middle_marked
= TRUE
;
492 DrawContext draw_context
;
494 /* Now create the drawing context that will be used to draw
495 * items related to the last state. */
496 draw_context
.drawable
= hashed_process_data
->pixmap
;
497 draw_context
.gc
= drawing
->gc
;
498 draw_context
.pango_layout
= drawing
->pango_layout
;
499 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
500 draw_context
.drawinfo
.end
.x
= x
;
502 draw_context
.drawinfo
.y
.over
= 1;
503 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
504 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
506 draw_context
.drawinfo
.start
.offset
.over
= 0;
507 draw_context
.drawinfo
.start
.offset
.middle
= 0;
508 draw_context
.drawinfo
.start
.offset
.under
= 0;
509 draw_context
.drawinfo
.end
.offset
.over
= 0;
510 draw_context
.drawinfo
.end
.offset
.middle
= 0;
511 draw_context
.drawinfo
.end
.offset
.under
= 0;
515 PropertiesLine prop_line
= prepare_s_e_line(process
);
516 draw_line((void*)&prop_line
, (void*)&draw_context
);
519 /* become the last x position */
520 hashed_process_data
->x
.middle
= x
;
521 hashed_process_data
->x
.middle_used
= TRUE
;
522 hashed_process_data
->x
.middle_marked
= FALSE
;
524 /* Calculate the next good time */
525 convert_pixels_to_time(width
, x
+1, time_window
,
526 &hashed_process_data
->next_good_time
);
532 tfc
->target_pid
= pid_in
;
533 if(!filter
|| !filter
->head
||
534 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
535 tfc
->t_context
->t
,tfc
)) {
537 /* First, check if the current process is in the state computation
538 * process list. If it is there, that means we must add it right now and
539 * draw items from the beginning of the read for it. If it is not
540 * present, it's a new process and it was not present : it will
541 * be added after the state update. */
542 LttvProcessState
*process
;
543 process
= lttv_state_find_process(ts
,
545 guint trace_num
= ts
->parent
.index
;
547 if(process
!= NULL
) {
548 /* Well, the process existed : we must get it in the process hash
549 * or add it, and draw its items.
551 /* Add process to process list (if not present) */
553 HashedProcessData
*hashed_process_data
= NULL
;
554 ProcessList
*process_list
= control_flow_data
->process_list
;
555 LttTime birth
= process
->creation_time
;
557 hashed_process_data
= processlist_get_process_data(process_list
,
562 if(hashed_process_data
== NULL
)
564 g_assert(pid_in
== 0 || pid_in
!= process
->ppid
);
565 /* Process not present */
566 ProcessInfo
*process_info
;
567 Drawing_t
*drawing
= control_flow_data
->drawing
;
568 processlist_add(process_list
,
580 &hashed_process_data
);
581 gtk_widget_set_size_request(drawing
->drawing_area
,
584 gtk_widget_queue_draw(drawing
->drawing_area
);
587 //We could set the current process and hash here, but will be done
588 //by after schedchange hook
590 /* Now, the process is in the state hash and our own process hash.
591 * We definitely can draw the items related to the ending state.
594 if(ltt_time_compare(hashed_process_data
->next_good_time
,
597 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
599 TimeWindow time_window
=
600 lttvwindow_get_time_window(control_flow_data
->tab
);
602 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
603 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
606 Drawing_t
*drawing
= control_flow_data
->drawing
;
607 guint width
= drawing
->width
;
609 convert_time_to_pixels(
615 /* Draw collision indicator */
616 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
617 gdk_draw_point(hashed_process_data
->pixmap
,
620 COLLISION_POSITION(hashed_process_data
->height
));
621 hashed_process_data
->x
.middle_marked
= TRUE
;
624 TimeWindow time_window
=
625 lttvwindow_get_time_window(control_flow_data
->tab
);
627 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
628 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
631 Drawing_t
*drawing
= control_flow_data
->drawing
;
632 guint width
= drawing
->width
;
635 convert_time_to_pixels(
642 /* Jump over draw if we are at the same x position */
643 if(x
== hashed_process_data
->x
.middle
&&
644 hashed_process_data
->x
.middle_used
)
646 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
647 /* Draw collision indicator */
648 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
649 gdk_draw_point(hashed_process_data
->pixmap
,
652 COLLISION_POSITION(hashed_process_data
->height
));
653 hashed_process_data
->x
.middle_marked
= TRUE
;
657 DrawContext draw_context
;
659 /* Now create the drawing context that will be used to draw
660 * items related to the last state. */
661 draw_context
.drawable
= hashed_process_data
->pixmap
;
662 draw_context
.gc
= drawing
->gc
;
663 draw_context
.pango_layout
= drawing
->pango_layout
;
664 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
665 draw_context
.drawinfo
.end
.x
= x
;
667 draw_context
.drawinfo
.y
.over
= 1;
668 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
669 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
671 draw_context
.drawinfo
.start
.offset
.over
= 0;
672 draw_context
.drawinfo
.start
.offset
.middle
= 0;
673 draw_context
.drawinfo
.start
.offset
.under
= 0;
674 draw_context
.drawinfo
.end
.offset
.over
= 0;
675 draw_context
.drawinfo
.end
.offset
.middle
= 0;
676 draw_context
.drawinfo
.end
.offset
.under
= 0;
680 PropertiesLine prop_line
= prepare_s_e_line(process
);
681 draw_line((void*)&prop_line
, (void*)&draw_context
);
685 /* become the last x position */
686 hashed_process_data
->x
.middle
= x
;
687 hashed_process_data
->x
.middle_used
= TRUE
;
688 hashed_process_data
->x
.middle_marked
= FALSE
;
690 /* Calculate the next good time */
691 convert_pixels_to_time(width
, x
+1, time_window
,
692 &hashed_process_data
->next_good_time
);
696 g_warning("Cannot find pin_in in schedchange %u", pid_in
);
698 tfc
->target_pid
= target_pid_saved
;
706 GString
*string
= g_string_new("");;
707 gboolean field_names
= TRUE
, state
= TRUE
;
709 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
710 g_string_append_printf(string
,"\n");
713 g_string_append_printf(string
, " %s",
714 g_quark_to_string(tfs
->process
->state
->s
));
717 g_info("%s",string
->str
);
719 g_string_free(string
, TRUE
);
721 /* End of text dump */
726 /* after_schedchange_hook
728 * The draw after hook is called by the reading API to have a
729 * particular event drawn on the screen.
730 * @param hook_data ControlFlowData structure of the viewer.
731 * @param call_data Event context.
733 * This function adds items to be drawn in a queue for each process.
736 int after_schedchange_hook(void *hook_data
, void *call_data
)
738 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
739 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
740 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
742 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
744 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
746 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
749 e
= ltt_tracefile_get_event(tfc
->tf
);
751 LttvFilter
*filter
= control_flow_data
->filter
;
752 if(filter
!= NULL
&& filter
->head
!= NULL
)
753 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
754 tfc
->t_context
->t
,tfc
))
757 LttTime evtime
= ltt_event_time(e
);
759 /* Add process to process list (if not present) */
760 LttvProcessState
*process_in
;
763 HashedProcessData
*hashed_process_data_in
= NULL
;
765 ProcessList
*process_list
= control_flow_data
->process_list
;
770 pid_out
= ltt_event_get_long_unsigned(e
, thf
->f1
);
771 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f2
);
775 /* Find process pid_in in the list... */
776 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
777 //process_in = tfs->process;
778 guint cpu
= tfs
->cpu
;
779 guint trace_num
= ts
->parent
.index
;
780 process_in
= ts
->running_process
[cpu
];
781 /* It should exist, because we are after the state update. */
783 g_assert(process_in
!= NULL
);
785 birth
= process_in
->creation_time
;
787 hashed_process_data_in
= processlist_get_process_data(process_list
,
792 if(hashed_process_data_in
== NULL
)
794 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
795 ProcessInfo
*process_info
;
796 Drawing_t
*drawing
= control_flow_data
->drawing
;
797 /* Process not present */
798 processlist_add(process_list
,
810 &hashed_process_data_in
);
811 gtk_widget_set_size_request(drawing
->drawing_area
,
814 gtk_widget_queue_draw(drawing
->drawing_area
);
816 /* Set the current process */
817 process_list
->current_hash_data
[trace_num
][process_in
->cpu
] =
818 hashed_process_data_in
;
820 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
823 TimeWindow time_window
=
824 lttvwindow_get_time_window(control_flow_data
->tab
);
827 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
828 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
831 Drawing_t
*drawing
= control_flow_data
->drawing
;
832 guint width
= drawing
->width
;
835 convert_time_to_pixels(
841 if(hashed_process_data_in
->x
.middle
!= new_x
) {
842 hashed_process_data_in
->x
.middle
= new_x
;
843 hashed_process_data_in
->x
.middle_used
= FALSE
;
844 hashed_process_data_in
->x
.middle_marked
= FALSE
;
853 /* before_execmode_hook
855 * This function basically draw lines and icons. Two types of lines are drawn :
856 * one small (3 pixels?) representing the state of the process and the second
857 * type is thicker (10 pixels?) representing on which CPU a process is running
858 * (and this only in running state).
860 * Extremums of the lines :
861 * x_min : time of the last event context for this process kept in memory.
862 * x_max : time of the current event.
863 * y : middle of the process in the process list. The process is found in the
864 * list, therefore is it's position in pixels.
866 * The choice of lines'color is defined by the context of the last event for this
871 int before_execmode_hook(void *hook_data
, void *call_data
)
873 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
874 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
875 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
877 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
879 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
881 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
884 e
= ltt_tracefile_get_event(tfc
->tf
);
886 LttvFilter
*filter
= control_flow_data
->filter
;
887 if(filter
!= NULL
&& filter
->head
!= NULL
)
888 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
889 tfc
->t_context
->t
,tfc
))
892 LttTime evtime
= ltt_event_time(e
);
894 /* we are in a execmode, before the state update. We must draw the
895 * items corresponding to the state before it changes : now is the right
899 //LttvProcessState *process = tfs->process;
900 guint cpu
= tfs
->cpu
;
901 guint trace_num
= ts
->parent
.index
;
902 LttvProcessState
*process
= ts
->running_process
[cpu
];
903 g_assert(process
!= NULL
);
905 guint pid
= process
->pid
;
907 /* Well, the process_out existed : we must get it in the process hash
908 * or add it, and draw its items.
910 /* Add process to process list (if not present) */
912 HashedProcessData
*hashed_process_data
= NULL
;
913 ProcessList
*process_list
= control_flow_data
->process_list
;
914 LttTime birth
= process
->creation_time
;
916 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
917 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
919 hashed_process_data
= processlist_get_process_data(process_list
,
924 if(unlikely(hashed_process_data
== NULL
))
926 g_assert(pid
== 0 || pid
!= process
->ppid
);
927 ProcessInfo
*process_info
;
928 /* Process not present */
929 Drawing_t
*drawing
= control_flow_data
->drawing
;
930 processlist_add(process_list
,
942 &hashed_process_data
);
943 gtk_widget_set_size_request(drawing
->drawing_area
,
946 gtk_widget_queue_draw(drawing
->drawing_area
);
948 /* Set the current process */
949 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
953 /* Now, the process is in the state hash and our own process hash.
954 * We definitely can draw the items related to the ending state.
957 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
960 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
961 TimeWindow time_window
=
962 lttvwindow_get_time_window(control_flow_data
->tab
);
965 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
966 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
969 Drawing_t
*drawing
= control_flow_data
->drawing
;
970 guint width
= drawing
->width
;
972 convert_time_to_pixels(
978 /* Draw collision indicator */
979 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
980 gdk_draw_point(hashed_process_data
->pixmap
,
983 COLLISION_POSITION(hashed_process_data
->height
));
984 hashed_process_data
->x
.middle_marked
= TRUE
;
987 TimeWindow time_window
=
988 lttvwindow_get_time_window(control_flow_data
->tab
);
991 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
992 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
995 Drawing_t
*drawing
= control_flow_data
->drawing
;
996 guint width
= drawing
->width
;
999 convert_time_to_pixels(
1006 /* Jump over draw if we are at the same x position */
1007 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1008 hashed_process_data
->x
.middle_used
))
1010 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1011 /* Draw collision indicator */
1012 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1013 gdk_draw_point(hashed_process_data
->pixmap
,
1016 COLLISION_POSITION(hashed_process_data
->height
));
1017 hashed_process_data
->x
.middle_marked
= TRUE
;
1022 DrawContext draw_context
;
1023 /* Now create the drawing context that will be used to draw
1024 * items related to the last state. */
1025 draw_context
.drawable
= hashed_process_data
->pixmap
;
1026 draw_context
.gc
= drawing
->gc
;
1027 draw_context
.pango_layout
= drawing
->pango_layout
;
1028 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1029 draw_context
.drawinfo
.end
.x
= x
;
1031 draw_context
.drawinfo
.y
.over
= 1;
1032 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1033 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1035 draw_context
.drawinfo
.start
.offset
.over
= 0;
1036 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1037 draw_context
.drawinfo
.start
.offset
.under
= 0;
1038 draw_context
.drawinfo
.end
.offset
.over
= 0;
1039 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1040 draw_context
.drawinfo
.end
.offset
.under
= 0;
1044 PropertiesLine prop_line
= prepare_s_e_line(process
);
1045 draw_line((void*)&prop_line
, (void*)&draw_context
);
1048 /* become the last x position */
1049 hashed_process_data
->x
.middle
= x
;
1050 hashed_process_data
->x
.middle_used
= TRUE
;
1051 hashed_process_data
->x
.middle_marked
= FALSE
;
1053 /* Calculate the next good time */
1054 convert_pixels_to_time(width
, x
+1, time_window
,
1055 &hashed_process_data
->next_good_time
);
1062 /* before_process_exit_hook
1064 * Draw lines for process event.
1066 * @param hook_data ControlFlowData structure of the viewer.
1067 * @param call_data Event context.
1069 * This function adds items to be drawn in a queue for each process.
1074 int before_process_exit_hook(void *hook_data
, void *call_data
)
1076 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1077 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1079 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1081 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1083 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1085 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1088 e
= ltt_tracefile_get_event(tfc
->tf
);
1090 LttvFilter
*filter
= control_flow_data
->filter
;
1091 if(filter
!= NULL
&& filter
->head
!= NULL
)
1092 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1093 tfc
->t_context
->t
,tfc
))
1096 LttTime evtime
= ltt_event_time(e
);
1098 /* Add process to process list (if not present) */
1099 //LttvProcessState *process = tfs->process;
1100 guint cpu
= tfs
->cpu
;
1101 guint trace_num
= ts
->parent
.index
;
1102 LttvProcessState
*process
= ts
->running_process
[cpu
];
1103 guint pid
= process
->pid
;
1105 guint pl_height
= 0;
1106 HashedProcessData
*hashed_process_data
= NULL
;
1108 ProcessList
*process_list
= control_flow_data
->process_list
;
1110 g_assert(process
!= NULL
);
1112 birth
= process
->creation_time
;
1114 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1115 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1117 hashed_process_data
= processlist_get_process_data(process_list
,
1122 if(unlikely(hashed_process_data
== NULL
))
1124 g_assert(pid
== 0 || pid
!= process
->ppid
);
1125 /* Process not present */
1126 Drawing_t
*drawing
= control_flow_data
->drawing
;
1127 ProcessInfo
*process_info
;
1128 processlist_add(process_list
,
1140 &hashed_process_data
);
1141 gtk_widget_set_size_request(drawing
->drawing_area
,
1144 gtk_widget_queue_draw(drawing
->drawing_area
);
1148 /* Now, the process is in the state hash and our own process hash.
1149 * We definitely can draw the items related to the ending state.
1152 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1155 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1156 TimeWindow time_window
=
1157 lttvwindow_get_time_window(control_flow_data
->tab
);
1160 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1161 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1163 #endif //EXTRA_CHECK
1164 Drawing_t
*drawing
= control_flow_data
->drawing
;
1165 guint width
= drawing
->width
;
1167 convert_time_to_pixels(
1173 /* Draw collision indicator */
1174 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1175 gdk_draw_point(hashed_process_data
->pixmap
,
1178 COLLISION_POSITION(hashed_process_data
->height
));
1179 hashed_process_data
->x
.middle_marked
= TRUE
;
1182 TimeWindow time_window
=
1183 lttvwindow_get_time_window(control_flow_data
->tab
);
1186 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1187 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1189 #endif //EXTRA_CHECK
1190 Drawing_t
*drawing
= control_flow_data
->drawing
;
1191 guint width
= drawing
->width
;
1194 convert_time_to_pixels(
1201 /* Jump over draw if we are at the same x position */
1202 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1203 hashed_process_data
->x
.middle_used
))
1205 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1206 /* Draw collision indicator */
1207 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1208 gdk_draw_point(hashed_process_data
->pixmap
,
1211 COLLISION_POSITION(hashed_process_data
->height
));
1212 hashed_process_data
->x
.middle_marked
= TRUE
;
1216 DrawContext draw_context
;
1218 /* Now create the drawing context that will be used to draw
1219 * items related to the last state. */
1220 draw_context
.drawable
= hashed_process_data
->pixmap
;
1221 draw_context
.gc
= drawing
->gc
;
1222 draw_context
.pango_layout
= drawing
->pango_layout
;
1223 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1224 draw_context
.drawinfo
.end
.x
= x
;
1226 draw_context
.drawinfo
.y
.over
= 1;
1227 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1228 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1230 draw_context
.drawinfo
.start
.offset
.over
= 0;
1231 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1232 draw_context
.drawinfo
.start
.offset
.under
= 0;
1233 draw_context
.drawinfo
.end
.offset
.over
= 0;
1234 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1235 draw_context
.drawinfo
.end
.offset
.under
= 0;
1239 PropertiesLine prop_line
= prepare_s_e_line(process
);
1240 draw_line((void*)&prop_line
, (void*)&draw_context
);
1243 /* become the last x position */
1244 hashed_process_data
->x
.middle
= x
;
1245 hashed_process_data
->x
.middle_used
= TRUE
;
1246 hashed_process_data
->x
.middle_marked
= FALSE
;
1248 /* Calculate the next good time */
1249 convert_pixels_to_time(width
, x
+1, time_window
,
1250 &hashed_process_data
->next_good_time
);
1260 /* before_process_release_hook
1262 * Draw lines for process event.
1264 * @param hook_data ControlFlowData structure of the viewer.
1265 * @param call_data Event context.
1267 * This function adds items to be drawn in a queue for each process.
1272 int before_process_release_hook(void *hook_data
, void *call_data
)
1274 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1275 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1277 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1279 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1281 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1283 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1286 e
= ltt_tracefile_get_event(tfc
->tf
);
1288 LttvFilter
*filter
= control_flow_data
->filter
;
1289 if(filter
!= NULL
&& filter
->head
!= NULL
)
1290 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1291 tfc
->t_context
->t
,tfc
))
1294 LttTime evtime
= ltt_event_time(e
);
1296 guint trace_num
= ts
->parent
.index
;
1300 pid
= ltt_event_get_long_unsigned(e
, thf
->f1
);
1303 /* Add process to process list (if not present) */
1304 /* Don't care about the process if it's not in the state hash already :
1305 * that means a process that has never done anything in the trace and
1306 * unknown suddently gets destroyed : no state meaningful to show. */
1307 LttvProcessState
*process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1309 if(process
!= NULL
) {
1311 guint pl_height
= 0;
1312 HashedProcessData
*hashed_process_data
= NULL
;
1314 ProcessList
*process_list
= control_flow_data
->process_list
;
1316 birth
= process
->creation_time
;
1318 /* Cannot use current process : this event happens on another process,
1319 * action done by the parent. */
1320 hashed_process_data
= processlist_get_process_data(process_list
,
1325 if(unlikely(hashed_process_data
== NULL
))
1327 g_assert(pid
== 0 || pid
!= process
->ppid
);
1328 /* Process not present */
1329 Drawing_t
*drawing
= control_flow_data
->drawing
;
1330 ProcessInfo
*process_info
;
1331 processlist_add(process_list
,
1343 &hashed_process_data
);
1344 gtk_widget_set_size_request(drawing
->drawing_area
,
1347 gtk_widget_queue_draw(drawing
->drawing_area
);
1350 /* Now, the process is in the state hash and our own process hash.
1351 * We definitely can draw the items related to the ending state.
1354 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1357 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1358 TimeWindow time_window
=
1359 lttvwindow_get_time_window(control_flow_data
->tab
);
1362 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1363 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1365 #endif //EXTRA_CHECK
1366 Drawing_t
*drawing
= control_flow_data
->drawing
;
1367 guint width
= drawing
->width
;
1369 convert_time_to_pixels(
1375 /* Draw collision indicator */
1376 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1377 gdk_draw_point(hashed_process_data
->pixmap
,
1380 COLLISION_POSITION(hashed_process_data
->height
));
1381 hashed_process_data
->x
.middle_marked
= TRUE
;
1384 TimeWindow time_window
=
1385 lttvwindow_get_time_window(control_flow_data
->tab
);
1388 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1389 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1391 #endif //EXTRA_CHECK
1392 Drawing_t
*drawing
= control_flow_data
->drawing
;
1393 guint width
= drawing
->width
;
1396 convert_time_to_pixels(
1403 /* Jump over draw if we are at the same x position */
1404 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1405 hashed_process_data
->x
.middle_used
))
1407 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1408 /* Draw collision indicator */
1409 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1410 gdk_draw_point(hashed_process_data
->pixmap
,
1413 COLLISION_POSITION(hashed_process_data
->height
));
1414 hashed_process_data
->x
.middle_marked
= TRUE
;
1418 DrawContext draw_context
;
1420 /* Now create the drawing context that will be used to draw
1421 * items related to the last state. */
1422 draw_context
.drawable
= hashed_process_data
->pixmap
;
1423 draw_context
.gc
= drawing
->gc
;
1424 draw_context
.pango_layout
= drawing
->pango_layout
;
1425 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1426 draw_context
.drawinfo
.end
.x
= x
;
1428 draw_context
.drawinfo
.y
.over
= 1;
1429 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1430 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1432 draw_context
.drawinfo
.start
.offset
.over
= 0;
1433 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1434 draw_context
.drawinfo
.start
.offset
.under
= 0;
1435 draw_context
.drawinfo
.end
.offset
.over
= 0;
1436 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1437 draw_context
.drawinfo
.end
.offset
.under
= 0;
1441 PropertiesLine prop_line
= prepare_s_e_line(process
);
1442 draw_line((void*)&prop_line
, (void*)&draw_context
);
1445 /* become the last x position */
1446 hashed_process_data
->x
.middle
= x
;
1447 hashed_process_data
->x
.middle_used
= TRUE
;
1448 hashed_process_data
->x
.middle_marked
= FALSE
;
1450 /* Calculate the next good time */
1451 convert_pixels_to_time(width
, x
+1, time_window
,
1452 &hashed_process_data
->next_good_time
);
1464 /* after_process_fork_hook
1466 * Create the processlist entry for the child process. Put the last
1467 * position in x at the current time value.
1469 * @param hook_data ControlFlowData structure of the viewer.
1470 * @param call_data Event context.
1472 * This function adds items to be drawn in a queue for each process.
1475 int after_process_fork_hook(void *hook_data
, void *call_data
)
1477 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1478 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1479 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1481 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1483 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1485 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1488 e
= ltt_tracefile_get_event(tfc
->tf
);
1490 LttvFilter
*filter
= control_flow_data
->filter
;
1491 if(filter
!= NULL
&& filter
->head
!= NULL
)
1492 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1493 tfc
->t_context
->t
,tfc
))
1496 LttTime evtime
= ltt_event_time(e
);
1500 child_pid
= ltt_event_get_long_unsigned(e
, thf
->f2
);
1503 /* Add process to process list (if not present) */
1504 LttvProcessState
*process_child
;
1506 guint pl_height
= 0;
1507 HashedProcessData
*hashed_process_data_child
= NULL
;
1509 ProcessList
*process_list
= control_flow_data
->process_list
;
1511 /* Find child in the list... */
1512 process_child
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1513 /* It should exist, because we are after the state update. */
1514 g_assert(process_child
!= NULL
);
1516 birth
= process_child
->creation_time
;
1517 guint trace_num
= ts
->parent
.index
;
1519 /* Cannot use current process, because this action is done by the parent
1521 hashed_process_data_child
= processlist_get_process_data(process_list
,
1526 if(likely(hashed_process_data_child
== NULL
))
1528 g_assert(child_pid
== 0 || child_pid
!= process_child
->ppid
);
1529 /* Process not present */
1530 Drawing_t
*drawing
= control_flow_data
->drawing
;
1531 ProcessInfo
*process_info
;
1532 processlist_add(process_list
,
1535 process_child
->tgid
,
1537 process_child
->ppid
,
1540 process_child
->name
,
1541 process_child
->brand
,
1544 &hashed_process_data_child
);
1545 gtk_widget_set_size_request(drawing
->drawing_area
,
1548 gtk_widget_queue_draw(drawing
->drawing_area
);
1550 processlist_set_ppid(process_list
, process_child
->ppid
,
1551 hashed_process_data_child
);
1552 processlist_set_tgid(process_list
, process_child
->tgid
,
1553 hashed_process_data_child
);
1557 if(likely(ltt_time_compare(hashed_process_data_child
->next_good_time
,
1560 TimeWindow time_window
=
1561 lttvwindow_get_time_window(control_flow_data
->tab
);
1564 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1565 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1567 #endif //EXTRA_CHECK
1568 Drawing_t
*drawing
= control_flow_data
->drawing
;
1569 guint width
= drawing
->width
;
1571 convert_time_to_pixels(
1577 if(likely(hashed_process_data_child
->x
.over
!= new_x
)) {
1578 hashed_process_data_child
->x
.over
= new_x
;
1579 hashed_process_data_child
->x
.over_used
= FALSE
;
1580 hashed_process_data_child
->x
.over_marked
= FALSE
;
1582 if(likely(hashed_process_data_child
->x
.middle
!= new_x
)) {
1583 hashed_process_data_child
->x
.middle
= new_x
;
1584 hashed_process_data_child
->x
.middle_used
= FALSE
;
1585 hashed_process_data_child
->x
.middle_marked
= FALSE
;
1587 if(likely(hashed_process_data_child
->x
.under
!= new_x
)) {
1588 hashed_process_data_child
->x
.under
= new_x
;
1589 hashed_process_data_child
->x
.under_used
= FALSE
;
1590 hashed_process_data_child
->x
.under_marked
= FALSE
;
1598 /* after_process_exit_hook
1600 * Create the processlist entry for the child process. Put the last
1601 * position in x at the current time value.
1603 * @param hook_data ControlFlowData structure of the viewer.
1604 * @param call_data Event context.
1606 * This function adds items to be drawn in a queue for each process.
1609 int after_process_exit_hook(void *hook_data
, void *call_data
)
1611 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1612 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1613 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1615 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1617 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1619 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1622 e
= ltt_tracefile_get_event(tfc
->tf
);
1624 LttvFilter
*filter
= control_flow_data
->filter
;
1625 if(filter
!= NULL
&& filter
->head
!= NULL
)
1626 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1627 tfc
->t_context
->t
,tfc
))
1630 LttTime evtime
= ltt_event_time(e
);
1632 /* Add process to process list (if not present) */
1633 //LttvProcessState *process = tfs->process;
1634 guint cpu
= tfs
->cpu
;
1635 guint trace_num
= ts
->parent
.index
;
1636 LttvProcessState
*process
= ts
->running_process
[cpu
];
1638 /* It should exist, because we are after the state update. */
1639 g_assert(process
!= NULL
);
1641 guint pid
= process
->pid
;
1643 guint pl_height
= 0;
1644 HashedProcessData
*hashed_process_data
= NULL
;
1646 ProcessList
*process_list
= control_flow_data
->process_list
;
1648 birth
= process
->creation_time
;
1650 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
) ){
1651 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1653 hashed_process_data
= processlist_get_process_data(process_list
,
1658 if(unlikely(hashed_process_data
== NULL
))
1660 g_assert(pid
== 0 || pid
!= process
->ppid
);
1661 /* Process not present */
1662 Drawing_t
*drawing
= control_flow_data
->drawing
;
1663 ProcessInfo
*process_info
;
1664 processlist_add(process_list
,
1676 &hashed_process_data
);
1677 gtk_widget_set_size_request(drawing
->drawing_area
,
1680 gtk_widget_queue_draw(drawing
->drawing_area
);
1683 /* Set the current process */
1684 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1685 hashed_process_data
;
1688 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
1691 TimeWindow time_window
=
1692 lttvwindow_get_time_window(control_flow_data
->tab
);
1695 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1696 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1698 #endif //EXTRA_CHECK
1699 Drawing_t
*drawing
= control_flow_data
->drawing
;
1700 guint width
= drawing
->width
;
1702 convert_time_to_pixels(
1707 if(unlikely(hashed_process_data
->x
.middle
!= new_x
)) {
1708 hashed_process_data
->x
.middle
= new_x
;
1709 hashed_process_data
->x
.middle_used
= FALSE
;
1710 hashed_process_data
->x
.middle_marked
= FALSE
;
1718 /* Get the filename of the process to print */
1719 int after_fs_exec_hook(void *hook_data
, void *call_data
)
1721 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1722 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1723 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1725 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1727 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1729 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1732 e
= ltt_tracefile_get_event(tfc
->tf
);
1734 LttvFilter
*filter
= control_flow_data
->filter
;
1735 if(filter
!= NULL
&& filter
->head
!= NULL
)
1736 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1737 tfc
->t_context
->t
,tfc
))
1740 guint cpu
= tfs
->cpu
;
1741 guint trace_num
= ts
->parent
.index
;
1742 LttvProcessState
*process
= ts
->running_process
[cpu
];
1743 g_assert(process
!= NULL
);
1745 guint pid
= process
->pid
;
1747 /* Well, the process_out existed : we must get it in the process hash
1748 * or add it, and draw its items.
1750 /* Add process to process list (if not present) */
1751 guint pl_height
= 0;
1752 HashedProcessData
*hashed_process_data
= NULL
;
1753 ProcessList
*process_list
= control_flow_data
->process_list
;
1754 LttTime birth
= process
->creation_time
;
1756 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1757 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1759 hashed_process_data
= processlist_get_process_data(process_list
,
1764 if(unlikely(hashed_process_data
== NULL
))
1766 g_assert(pid
== 0 || pid
!= process
->ppid
);
1767 ProcessInfo
*process_info
;
1768 /* Process not present */
1769 Drawing_t
*drawing
= control_flow_data
->drawing
;
1770 processlist_add(process_list
,
1782 &hashed_process_data
);
1783 gtk_widget_set_size_request(drawing
->drawing_area
,
1786 gtk_widget_queue_draw(drawing
->drawing_area
);
1788 /* Set the current process */
1789 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1790 hashed_process_data
;
1793 processlist_set_name(process_list
, process
->name
, hashed_process_data
);
1799 /* Get the filename of the process to print */
1800 int after_user_generic_thread_brand_hook(void *hook_data
, void *call_data
)
1802 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1803 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1804 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1806 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1808 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1810 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1813 e
= ltt_tracefile_get_event(tfc
->tf
);
1815 LttvFilter
*filter
= control_flow_data
->filter
;
1816 if(filter
!= NULL
&& filter
->head
!= NULL
)
1817 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1818 tfc
->t_context
->t
,tfc
))
1821 guint cpu
= tfs
->cpu
;
1822 guint trace_num
= ts
->parent
.index
;
1823 LttvProcessState
*process
= ts
->running_process
[cpu
];
1824 g_assert(process
!= NULL
);
1826 guint pid
= process
->pid
;
1828 /* Well, the process_out existed : we must get it in the process hash
1829 * or add it, and draw its items.
1831 /* Add process to process list (if not present) */
1832 guint pl_height
= 0;
1833 HashedProcessData
*hashed_process_data
= NULL
;
1834 ProcessList
*process_list
= control_flow_data
->process_list
;
1835 LttTime birth
= process
->creation_time
;
1837 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1838 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1840 hashed_process_data
= processlist_get_process_data(process_list
,
1845 if(unlikely(hashed_process_data
== NULL
))
1847 g_assert(pid
== 0 || pid
!= process
->ppid
);
1848 ProcessInfo
*process_info
;
1849 /* Process not present */
1850 Drawing_t
*drawing
= control_flow_data
->drawing
;
1851 processlist_add(process_list
,
1863 &hashed_process_data
);
1864 gtk_widget_set_size_request(drawing
->drawing_area
,
1867 gtk_widget_queue_draw(drawing
->drawing_area
);
1869 /* Set the current process */
1870 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1871 hashed_process_data
;
1874 processlist_set_brand(process_list
, process
->brand
, hashed_process_data
);
1881 /* after_event_enum_process_hook
1883 * Create the processlist entry for the child process. Put the last
1884 * position in x at the current time value.
1886 * @param hook_data ControlFlowData structure of the viewer.
1887 * @param call_data Event context.
1889 * This function adds items to be drawn in a queue for each process.
1892 int after_event_enum_process_hook(void *hook_data
, void *call_data
)
1894 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1895 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1896 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1898 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1900 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1902 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1905 e
= ltt_tracefile_get_event(tfc
->tf
);
1907 LttvFilter
*filter
= control_flow_data
->filter
;
1908 if(filter
!= NULL
&& filter
->head
!= NULL
)
1909 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1910 tfc
->t_context
->t
,tfc
))
1913 LttTime evtime
= ltt_event_time(e
);
1915 /* Add process to process list (if not present) */
1916 LttvProcessState
*process_in
;
1918 guint pl_height
= 0;
1919 HashedProcessData
*hashed_process_data_in
= NULL
;
1921 ProcessList
*process_list
= control_flow_data
->process_list
;
1922 guint trace_num
= ts
->parent
.index
;
1926 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f1
);
1930 /* Find process pid_in in the list... */
1931 process_in
= lttv_state_find_process(ts
, ANY_CPU
, pid_in
);
1932 //process_in = tfs->process;
1933 //guint cpu = tfs->cpu;
1934 //guint trace_num = ts->parent.index;
1935 //process_in = ts->running_process[cpu];
1936 /* It should exist, because we are after the state update. */
1938 //g_assert(process_in != NULL);
1939 #endif //EXTRA_CHECK
1940 birth
= process_in
->creation_time
;
1942 hashed_process_data_in
= processlist_get_process_data(process_list
,
1947 if(hashed_process_data_in
== NULL
)
1949 if(pid_in
!= 0 && pid_in
== process_in
->ppid
)
1950 g_critical("TEST %u , %u", pid_in
, process_in
->ppid
);
1951 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
1952 ProcessInfo
*process_info
;
1953 Drawing_t
*drawing
= control_flow_data
->drawing
;
1954 /* Process not present */
1955 processlist_add(process_list
,
1967 &hashed_process_data_in
);
1968 gtk_widget_set_size_request(drawing
->drawing_area
,
1971 gtk_widget_queue_draw(drawing
->drawing_area
);
1973 processlist_set_name(process_list
, process_in
->name
,
1974 hashed_process_data_in
);
1975 processlist_set_ppid(process_list
, process_in
->ppid
,
1976 hashed_process_data_in
);
1977 processlist_set_tgid(process_list
, process_in
->tgid
,
1978 hashed_process_data_in
);
1984 gint
update_time_window_hook(void *hook_data
, void *call_data
)
1986 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1987 Drawing_t
*drawing
= control_flow_data
->drawing
;
1988 ProcessList
*process_list
= control_flow_data
->process_list
;
1990 const TimeWindowNotifyData
*time_window_nofify_data
=
1991 ((const TimeWindowNotifyData
*)call_data
);
1993 TimeWindow
*old_time_window
=
1994 time_window_nofify_data
->old_time_window
;
1995 TimeWindow
*new_time_window
=
1996 time_window_nofify_data
->new_time_window
;
1998 /* Update the ruler */
1999 drawing_update_ruler(control_flow_data
->drawing
,
2003 /* Two cases : zoom in/out or scrolling */
2005 /* In order to make sure we can reuse the old drawing, the scale must
2006 * be the same and the new time interval being partly located in the
2007 * currently shown time interval. (reuse is only for scrolling)
2010 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
2011 old_time_window
->start_time
.tv_sec
,
2012 old_time_window
->start_time
.tv_nsec
,
2013 old_time_window
->time_width
.tv_sec
,
2014 old_time_window
->time_width
.tv_nsec
);
2016 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
2017 new_time_window
->start_time
.tv_sec
,
2018 new_time_window
->start_time
.tv_nsec
,
2019 new_time_window
->time_width
.tv_sec
,
2020 new_time_window
->time_width
.tv_nsec
);
2022 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
2023 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
2025 /* Same scale (scrolling) */
2026 g_info("scrolling");
2027 LttTime
*ns
= &new_time_window
->start_time
;
2028 LttTime
*nw
= &new_time_window
->time_width
;
2029 LttTime
*os
= &old_time_window
->start_time
;
2030 LttTime
*ow
= &old_time_window
->time_width
;
2031 LttTime old_end
= old_time_window
->end_time
;
2032 LttTime new_end
= new_time_window
->end_time
;
2034 //if(ns<os+w && os+w<ns+w)
2035 //if(ns<old_end && os<ns)
2036 if(ltt_time_compare(*ns
, old_end
) == -1
2037 && ltt_time_compare(*os
, *ns
) == -1)
2039 g_info("scrolling near right");
2040 /* Scroll right, keep right part of the screen */
2042 guint width
= control_flow_data
->drawing
->width
;
2043 convert_time_to_pixels(
2049 /* Copy old data to new location */
2050 copy_pixmap_region(process_list
,
2052 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2056 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
2058 if(drawing
->damage_begin
== drawing
->damage_end
)
2059 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
2061 drawing
->damage_begin
= 0;
2063 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2065 /* Clear the data request background, but not SAFETY */
2066 rectangle_pixmap(process_list
,
2067 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2069 drawing
->damage_begin
+SAFETY
, 0,
2070 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2072 gtk_widget_queue_draw(drawing
->drawing_area
);
2073 //gtk_widget_queue_draw_area (drawing->drawing_area,
2075 // control_flow_data->drawing->width,
2076 // control_flow_data->drawing->height);
2078 /* Get new data for the rest. */
2079 drawing_data_request(control_flow_data
->drawing
,
2080 drawing
->damage_begin
, 0,
2081 drawing
->damage_end
- drawing
->damage_begin
,
2082 control_flow_data
->drawing
->height
);
2085 //if(ns<os && os<ns+w)
2086 //if(ns<os && os<new_end)
2087 if(ltt_time_compare(*ns
,*os
) == -1
2088 && ltt_time_compare(*os
,new_end
) == -1)
2090 g_info("scrolling near left");
2091 /* Scroll left, keep left part of the screen */
2093 guint width
= control_flow_data
->drawing
->width
;
2094 convert_time_to_pixels(
2100 /* Copy old data to new location */
2101 copy_pixmap_region (process_list
,
2103 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2109 if(drawing
->damage_begin
== drawing
->damage_end
)
2110 drawing
->damage_end
= x
;
2112 drawing
->damage_end
=
2113 control_flow_data
->drawing
->width
;
2115 drawing
->damage_begin
= 0;
2117 rectangle_pixmap (process_list
,
2118 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2120 drawing
->damage_begin
, 0,
2121 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2124 gtk_widget_queue_draw(drawing
->drawing_area
);
2125 //gtk_widget_queue_draw_area (drawing->drawing_area,
2127 // control_flow_data->drawing->width,
2128 // control_flow_data->drawing->height);
2131 /* Get new data for the rest. */
2132 drawing_data_request(control_flow_data
->drawing
,
2133 drawing
->damage_begin
, 0,
2134 drawing
->damage_end
- drawing
->damage_begin
,
2135 control_flow_data
->drawing
->height
);
2138 if(ltt_time_compare(*ns
,*os
) == 0)
2140 g_info("not scrolling");
2142 g_info("scrolling far");
2143 /* Cannot reuse any part of the screen : far jump */
2146 rectangle_pixmap (process_list
,
2147 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2150 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2153 //gtk_widget_queue_draw_area (drawing->drawing_area,
2155 // control_flow_data->drawing->width,
2156 // control_flow_data->drawing->height);
2157 gtk_widget_queue_draw(drawing
->drawing_area
);
2159 drawing
->damage_begin
= 0;
2160 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2162 drawing_data_request(control_flow_data
->drawing
,
2164 control_flow_data
->drawing
->width
,
2165 control_flow_data
->drawing
->height
);
2171 /* Different scale (zoom) */
2174 rectangle_pixmap (process_list
,
2175 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2178 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2181 //gtk_widget_queue_draw_area (drawing->drawing_area,
2183 // control_flow_data->drawing->width,
2184 // control_flow_data->drawing->height);
2185 gtk_widget_queue_draw(drawing
->drawing_area
);
2187 drawing
->damage_begin
= 0;
2188 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2190 drawing_data_request(control_flow_data
->drawing
,
2192 control_flow_data
->drawing
->width
,
2193 control_flow_data
->drawing
->height
);
2196 /* Update directly when scrolling */
2197 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2203 gint
traceset_notify(void *hook_data
, void *call_data
)
2205 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2206 Drawing_t
*drawing
= control_flow_data
->drawing
;
2208 if(unlikely(drawing
->gc
== NULL
)) {
2211 if(drawing
->dotted_gc
== NULL
) {
2215 drawing_clear(control_flow_data
->drawing
);
2216 processlist_clear(control_flow_data
->process_list
);
2217 gtk_widget_set_size_request(
2218 control_flow_data
->drawing
->drawing_area
,
2219 -1, processlist_get_height(control_flow_data
->process_list
));
2220 redraw_notify(control_flow_data
, NULL
);
2222 request_background_data(control_flow_data
);
2227 gint
redraw_notify(void *hook_data
, void *call_data
)
2229 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2230 Drawing_t
*drawing
= control_flow_data
->drawing
;
2231 GtkWidget
*widget
= drawing
->drawing_area
;
2233 drawing
->damage_begin
= 0;
2234 drawing
->damage_end
= drawing
->width
;
2236 /* fun feature, to be separated someday... */
2237 drawing_clear(control_flow_data
->drawing
);
2238 processlist_clear(control_flow_data
->process_list
);
2239 gtk_widget_set_size_request(
2240 control_flow_data
->drawing
->drawing_area
,
2241 -1, processlist_get_height(control_flow_data
->process_list
));
2243 rectangle_pixmap (control_flow_data
->process_list
,
2244 widget
->style
->black_gc
,
2247 drawing
->alloc_width
,
2250 gtk_widget_queue_draw(drawing
->drawing_area
);
2252 if(drawing
->damage_begin
< drawing
->damage_end
)
2254 drawing_data_request(drawing
,
2255 drawing
->damage_begin
,
2257 drawing
->damage_end
-drawing
->damage_begin
,
2261 //gtk_widget_queue_draw_area(drawing->drawing_area,
2264 // drawing->height);
2270 gint
continue_notify(void *hook_data
, void *call_data
)
2272 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2273 Drawing_t
*drawing
= control_flow_data
->drawing
;
2275 //g_assert(widget->allocation.width == drawing->damage_end);
2277 if(drawing
->damage_begin
< drawing
->damage_end
)
2279 drawing_data_request(drawing
,
2280 drawing
->damage_begin
,
2282 drawing
->damage_end
-drawing
->damage_begin
,
2290 gint
update_current_time_hook(void *hook_data
, void *call_data
)
2292 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
2293 Drawing_t
*drawing
= control_flow_data
->drawing
;
2295 LttTime current_time
= *((LttTime
*)call_data
);
2297 TimeWindow time_window
=
2298 lttvwindow_get_time_window(control_flow_data
->tab
);
2300 LttTime time_begin
= time_window
.start_time
;
2301 LttTime width
= time_window
.time_width
;
2304 guint64 time_ll
= ltt_time_to_uint64(width
);
2305 time_ll
= time_ll
>> 1; /* divide by two */
2306 half_width
= ltt_time_from_uint64(time_ll
);
2308 LttTime time_end
= ltt_time_add(time_begin
, width
);
2310 LttvTracesetContext
* tsc
=
2311 lttvwindow_get_traceset_context(control_flow_data
->tab
);
2313 LttTime trace_start
= tsc
->time_span
.start_time
;
2314 LttTime trace_end
= tsc
->time_span
.end_time
;
2316 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
2317 current_time
.tv_nsec
);
2321 /* If current time is inside time interval, just move the highlight
2324 /* Else, we have to change the time interval. We have to tell it
2325 * to the main window. */
2326 /* The time interval change will take care of placing the current
2327 * time at the center of the visible area, or nearest possible if we are
2328 * at one end of the trace. */
2331 if(ltt_time_compare(current_time
, time_begin
) < 0)
2333 TimeWindow new_time_window
;
2335 if(ltt_time_compare(current_time
,
2336 ltt_time_add(trace_start
,half_width
)) < 0)
2337 time_begin
= trace_start
;
2339 time_begin
= ltt_time_sub(current_time
,half_width
);
2341 new_time_window
.start_time
= time_begin
;
2342 new_time_window
.time_width
= width
;
2343 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2344 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2346 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2348 else if(ltt_time_compare(current_time
, time_end
) > 0)
2350 TimeWindow new_time_window
;
2352 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
2353 time_begin
= ltt_time_sub(trace_end
,width
);
2355 time_begin
= ltt_time_sub(current_time
,half_width
);
2357 new_time_window
.start_time
= time_begin
;
2358 new_time_window
.time_width
= width
;
2359 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2360 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2362 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2365 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2367 /* Update directly when scrolling */
2368 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2374 typedef struct _ClosureData
{
2375 EventsRequest
*events_request
;
2376 LttvTracesetState
*tss
;
2382 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
2384 ProcessInfo
*process_info
= (ProcessInfo
*)key
;
2385 HashedProcessData
*hashed_process_data
= (HashedProcessData
*)value
;
2386 ClosureData
*closure_data
= (ClosureData
*)user_data
;
2388 EventsRequest
*events_request
= closure_data
->events_request
;
2389 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2391 LttvTracesetState
*tss
= closure_data
->tss
;
2392 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)tss
;
2394 LttTime evtime
= closure_data
->end_time
;
2397 /* For the process */
2398 /* First, check if the current process is in the state computation
2399 * process list. If it is there, that means we must add it right now and
2400 * draw items from the beginning of the read for it. If it is not
2401 * present, it's a new process and it was not present : it will
2402 * be added after the state update. */
2404 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
2405 #endif //EXTRA_CHECK
2406 LttvTraceContext
*tc
= tsc
->traces
[process_info
->trace_num
];
2407 LttvTraceState
*ts
= (LttvTraceState
*)tc
;
2410 //FIXME : optimize data structures.
2411 LttvTracefileState
*tfs
;
2412 LttvTracefileContext
*tfc
;
2414 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
2415 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
2416 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
2417 && tfs
->cpu
== process_info
->cpu
)
2421 g_assert(i
<tc
->tracefiles
->len
);
2422 tfs
= LTTV_TRACEFILE_STATE(tfc
);
2424 // LttvTracefileState *tfs =
2425 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2426 // tracefiles[process_info->cpu];
2428 LttvProcessState
*process
;
2429 process
= lttv_state_find_process(ts
, process_info
->cpu
,
2432 if(unlikely(process
!= NULL
)) {
2434 /* Only draw for processes that are currently in the trace states */
2436 ProcessList
*process_list
= control_flow_data
->process_list
;
2438 /* Should be alike when background info is ready */
2439 if(control_flow_data
->background_info_waiting
==0)
2440 g_assert(ltt_time_compare(process
->creation_time
,
2441 process_info
->birth
) == 0);
2442 #endif //EXTRA_CHECK
2444 /* Now, the process is in the state hash and our own process hash.
2445 * We definitely can draw the items related to the ending state.
2448 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2451 TimeWindow time_window
=
2452 lttvwindow_get_time_window(control_flow_data
->tab
);
2455 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2456 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2458 #endif //EXTRA_CHECK
2459 Drawing_t
*drawing
= control_flow_data
->drawing
;
2460 guint width
= drawing
->width
;
2462 guint x
= closure_data
->x_end
;
2464 DrawContext draw_context
;
2466 /* Now create the drawing context that will be used to draw
2467 * items related to the last state. */
2468 draw_context
.drawable
= hashed_process_data
->pixmap
;
2469 draw_context
.gc
= drawing
->gc
;
2470 draw_context
.pango_layout
= drawing
->pango_layout
;
2471 draw_context
.drawinfo
.end
.x
= x
;
2473 draw_context
.drawinfo
.y
.over
= 1;
2474 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2475 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2477 draw_context
.drawinfo
.start
.offset
.over
= 0;
2478 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2479 draw_context
.drawinfo
.start
.offset
.under
= 0;
2480 draw_context
.drawinfo
.end
.offset
.over
= 0;
2481 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2482 draw_context
.drawinfo
.end
.offset
.under
= 0;
2484 /* Jump over draw if we are at the same x position */
2485 if(x
== hashed_process_data
->x
.over
)
2489 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2491 PropertiesLine prop_line
= prepare_execmode_line(process
);
2492 draw_line((void*)&prop_line
, (void*)&draw_context
);
2494 hashed_process_data
->x
.over
= x
;
2498 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2499 hashed_process_data
->x
.middle_used
)) {
2500 #if 0 /* do not mark closure : not missing information */
2501 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2502 /* Draw collision indicator */
2503 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2504 gdk_draw_point(drawing
->pixmap
,
2508 hashed_process_data
->x
.middle_marked
= TRUE
;
2513 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2515 PropertiesLine prop_line
= prepare_s_e_line(process
);
2516 draw_line((void*)&prop_line
, (void*)&draw_context
);
2518 /* become the last x position */
2519 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2520 hashed_process_data
->x
.middle
= x
;
2521 /* but don't use the pixel */
2522 hashed_process_data
->x
.middle_used
= FALSE
;
2524 /* Calculate the next good time */
2525 convert_pixels_to_time(width
, x
+1, time_window
,
2526 &hashed_process_data
->next_good_time
);
2535 int before_chunk(void *hook_data
, void *call_data
)
2537 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2538 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2539 ControlFlowData
*cfd
= (ControlFlowData
*)events_request
->viewer_data
;
2541 /* Desactivate sort */
2542 gtk_tree_sortable_set_sort_column_id(
2543 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2545 GTK_SORT_ASCENDING
);
2547 drawing_chunk_begin(events_request
, tss
);
2552 int before_request(void *hook_data
, void *call_data
)
2554 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2555 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2557 drawing_data_request_begin(events_request
, tss
);
2564 * after request is necessary in addition of after chunk in order to draw
2565 * lines until the end of the screen. after chunk just draws lines until
2572 int after_request(void *hook_data
, void *call_data
)
2574 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2575 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2576 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2578 ProcessList
*process_list
= control_flow_data
->process_list
;
2579 LttTime end_time
= events_request
->end_time
;
2581 ClosureData closure_data
;
2582 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2583 closure_data
.tss
= tss
;
2584 closure_data
.end_time
= end_time
;
2586 TimeWindow time_window
=
2587 lttvwindow_get_time_window(control_flow_data
->tab
);
2588 guint width
= control_flow_data
->drawing
->width
;
2589 convert_time_to_pixels(
2593 &closure_data
.x_end
);
2596 /* Draw last items */
2597 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2598 (void*)&closure_data
);
2601 /* Request expose */
2602 drawing_request_expose(events_request
, tss
, end_time
);
2611 int after_chunk(void *hook_data
, void *call_data
)
2613 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2614 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2615 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2616 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)call_data
;
2617 LttvTracefileContext
*tfc
= lttv_traceset_context_get_current_tfc(tsc
);
2620 ProcessList
*process_list
= control_flow_data
->process_list
;
2622 LttvTraceset
*traceset
= tsc
->ts
;
2623 guint nb_trace
= lttv_traceset_number(traceset
);
2625 /* Only execute when called for the first trace's events request */
2626 if(!process_list
->current_hash_data
) return;
2628 for(i
= 0 ; i
< nb_trace
; i
++) {
2629 g_free(process_list
->current_hash_data
[i
]);
2631 g_free(process_list
->current_hash_data
);
2632 process_list
->current_hash_data
= NULL
;
2635 end_time
= LTT_TIME_MIN(tfc
->timestamp
, events_request
->end_time
);
2636 else /* end of traceset, or position now out of request : end */
2637 end_time
= events_request
->end_time
;
2639 ClosureData closure_data
;
2640 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2641 closure_data
.tss
= tss
;
2642 closure_data
.end_time
= end_time
;
2644 TimeWindow time_window
=
2645 lttvwindow_get_time_window(control_flow_data
->tab
);
2646 guint width
= control_flow_data
->drawing
->width
;
2647 convert_time_to_pixels(
2651 &closure_data
.x_end
);
2653 /* Draw last items */
2654 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2655 (void*)&closure_data
);
2657 /* Reactivate sort */
2658 gtk_tree_sortable_set_sort_column_id(
2659 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2660 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2661 GTK_SORT_ASCENDING
);
2663 update_index_to_pixmap(control_flow_data
->process_list
);
2664 /* Request a full expose : drawing scrambled */
2665 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2667 /* Request expose (updates damages zone also) */
2668 drawing_request_expose(events_request
, tss
, end_time
);