1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Mathieu Desnoyers
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20 /*****************************************************************************
21 * Hooks to be called by the main window *
22 *****************************************************************************/
25 /* Event hooks are the drawing hooks called during traceset read. They draw the
26 * icons, text, lines and background color corresponding to the events read.
28 * Two hooks are used for drawing : before_schedchange and after_schedchange hooks. The
29 * before_schedchange is called before the state update that occurs with an event and
30 * the after_schedchange hook is called after this state update.
32 * The before_schedchange hooks fulfill the task of drawing the visible objects that
33 * corresponds to the data accumulated by the after_schedchange hook.
35 * The after_schedchange hook accumulates the data that need to be shown on the screen
36 * (items) into a queue. Then, the next before_schedchange hook will draw what that
37 * queue contains. That's the Right Way (TM) of drawing items on the screen,
38 * because we need to draw the background first (and then add icons, text, ...
39 * over it), but we only know the length of a background region once the state
40 * corresponding to it is over, which happens to be at the next before_schedchange
43 * We also have a hook called at the end of a chunk to draw the information left
44 * undrawn in each process queue. We use the current time as end of
52 //#define PANGO_ENABLE_BACKEND
60 //#include <pango/pango.h>
62 #include <ltt/event.h>
65 #include <ltt/trace.h>
67 #include <lttv/lttv.h>
68 #include <lttv/hook.h>
69 #include <lttv/state.h>
70 #include <lttvwindow/lttvwindow.h>
71 #include <lttvwindow/lttvwindowtraces.h>
72 #include <lttvwindow/support.h>
75 #include "eventhooks.h"
77 #include "processlist.h"
81 #define MAX_PATH_LEN 256
82 #define STATE_LINE_WIDTH 4
83 #define COLLISION_POSITION(height) (((height - STATE_LINE_WIDTH)/2) -3)
85 extern GSList
*g_legend_list
;
88 /* Action to do when background computation completed.
90 * Wait for all the awaited computations to be over.
93 static gint
background_ready(void *hook_data
, void *call_data
)
95 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
96 LttvTrace
*trace
= (LttvTrace
*)call_data
;
98 control_flow_data
->background_info_waiting
--;
100 if(control_flow_data
->background_info_waiting
== 0) {
101 g_message("control flow viewer : background computation data ready.");
103 drawing_clear(control_flow_data
->drawing
);
104 processlist_clear(control_flow_data
->process_list
);
105 gtk_widget_set_size_request(
106 control_flow_data
->drawing
->drawing_area
,
107 -1, processlist_get_height(control_flow_data
->process_list
));
108 redraw_notify(control_flow_data
, NULL
);
115 /* Request background computation. Verify if it is in progress or ready first.
116 * Only for each trace in the tab's traceset.
118 static void request_background_data(ControlFlowData
*control_flow_data
)
120 LttvTracesetContext
* tsc
=
121 lttvwindow_get_traceset_context(control_flow_data
->tab
);
122 gint num_traces
= lttv_traceset_number(tsc
->ts
);
125 LttvTraceState
*tstate
;
127 LttvHooks
*background_ready_hook
=
129 lttv_hooks_add(background_ready_hook
, background_ready
, control_flow_data
,
131 control_flow_data
->background_info_waiting
= 0;
133 for(i
=0;i
<num_traces
;i
++) {
134 trace
= lttv_traceset_get(tsc
->ts
, i
);
135 tstate
= LTTV_TRACE_STATE(tsc
->traces
[i
]);
137 if(lttvwindowtraces_get_ready(g_quark_from_string("state"),trace
)==FALSE
138 && !tstate
->has_precomputed_states
) {
140 if(lttvwindowtraces_get_in_progress(g_quark_from_string("state"),
142 /* We first remove requests that could have been done for the same
143 * information. Happens when two viewers ask for it before servicing
146 if(!lttvwindowtraces_background_request_find(trace
, "state"))
147 lttvwindowtraces_background_request_queue(
148 main_window_get_widget(control_flow_data
->tab
), trace
, "state");
149 lttvwindowtraces_background_notify_queue(control_flow_data
,
153 background_ready_hook
);
154 control_flow_data
->background_info_waiting
++;
155 } else { /* in progress */
157 lttvwindowtraces_background_notify_current(control_flow_data
,
161 background_ready_hook
);
162 control_flow_data
->background_info_waiting
++;
165 /* Data ready. By its nature, this viewer doesn't need to have
166 * its data ready hook called there, because a background
167 * request is always linked with a redraw.
173 lttv_hooks_destroy(background_ready_hook
);
180 * Event Viewer's constructor hook
182 * This constructor is given as a parameter to the menuitem and toolbar button
183 * registration. It creates the list.
184 * @param tab A pointer to the parent tab.
185 * @return The widget created.
188 h_guicontrolflow(LttvPlugin
*plugin
)
190 LttvPluginTab
*ptab
= LTTV_PLUGIN_TAB(plugin
);
191 Tab
*tab
= ptab
->tab
;
192 g_info("h_guicontrolflow, %p", tab
);
193 ControlFlowData
*control_flow_data
= guicontrolflow(ptab
);
195 control_flow_data
->tab
= tab
;
197 // Unreg done in the GuiControlFlow_Destructor
198 lttvwindow_register_traceset_notify(tab
,
202 lttvwindow_register_time_window_notify(tab
,
203 update_time_window_hook
,
205 lttvwindow_register_current_time_notify(tab
,
206 update_current_time_hook
,
208 lttvwindow_register_redraw_notify(tab
,
211 lttvwindow_register_continue_notify(tab
,
214 request_background_data(control_flow_data
);
217 return guicontrolflow_get_widget(control_flow_data
) ;
222 void legend_destructor(GtkWindow
*legend
)
224 g_legend_list
= g_slist_remove(g_legend_list
, legend
);
227 /* Create a popup legend */
229 h_legend(LttvPlugin
*plugin
)
231 LttvPluginTab
*ptab
= LTTV_PLUGIN_TAB(plugin
);
232 Tab
*tab
= ptab
->tab
;
233 g_info("h_legend, %p", tab
);
235 GtkWindow
*legend
= GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL
));
237 g_legend_list
= g_slist_append(
241 g_object_set_data_full(
245 (GDestroyNotify
)legend_destructor
);
247 gtk_window_set_title(legend
, "Control Flow View Legend");
249 GtkWidget
*pixmap
= create_pixmap(GTK_WIDGET(legend
), "lttv-color-list.png");
251 // GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixmap(
252 // GDK_PIXMAP(pixmap), NULL));
254 gtk_container_add(GTK_CONTAINER(legend
), GTK_WIDGET(pixmap
));
256 gtk_widget_show(GTK_WIDGET(pixmap
));
257 gtk_widget_show(GTK_WIDGET(legend
));
260 return NULL
; /* This is a popup window */
264 int event_selected_hook(void *hook_data
, void *call_data
)
266 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
267 guint
*event_number
= (guint
*) call_data
;
269 g_debug("DEBUG : event selected by main window : %u", *event_number
);
274 /* Function that selects the color of status&exemode line */
275 static inline PropertiesLine
prepare_s_e_line(LttvProcessState
*process
)
277 PropertiesLine prop_line
;
278 prop_line
.line_width
= STATE_LINE_WIDTH
;
279 prop_line
.style
= GDK_LINE_SOLID
;
280 prop_line
.y
= MIDDLE
;
281 //GdkColormap *colormap = gdk_colormap_get_system();
283 if(process
->state
->s
== LTTV_STATE_RUN
) {
284 if(process
->state
->t
== LTTV_STATE_USER_MODE
)
285 prop_line
.color
= drawing_colors
[COL_RUN_USER_MODE
];
286 else if(process
->state
->t
== LTTV_STATE_SYSCALL
)
287 prop_line
.color
= drawing_colors
[COL_RUN_SYSCALL
];
288 else if(process
->state
->t
== LTTV_STATE_TRAP
)
289 prop_line
.color
= drawing_colors
[COL_RUN_TRAP
];
290 else if(process
->state
->t
== LTTV_STATE_IRQ
)
291 prop_line
.color
= drawing_colors
[COL_RUN_IRQ
];
292 else if(process
->state
->t
== LTTV_STATE_SOFT_IRQ
)
293 prop_line
.color
= drawing_colors
[COL_RUN_SOFT_IRQ
];
294 else if(process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
)
295 prop_line
.color
= drawing_colors
[COL_MODE_UNKNOWN
];
297 g_assert(FALSE
); /* RUNNING MODE UNKNOWN */
298 } else if(process
->state
->s
== LTTV_STATE_WAIT
) {
299 /* We don't show if we wait while in user mode, trap, irq or syscall */
300 prop_line
.color
= drawing_colors
[COL_WAIT
];
301 } else if(process
->state
->s
== LTTV_STATE_WAIT_CPU
) {
302 /* We don't show if we wait for CPU while in user mode, trap, irq
304 prop_line
.color
= drawing_colors
[COL_WAIT_CPU
];
305 } else if(process
->state
->s
== LTTV_STATE_ZOMBIE
) {
306 prop_line
.color
= drawing_colors
[COL_ZOMBIE
];
307 } else if(process
->state
->s
== LTTV_STATE_WAIT_FORK
) {
308 prop_line
.color
= drawing_colors
[COL_WAIT_FORK
];
309 } else if(process
->state
->s
== LTTV_STATE_EXIT
) {
310 prop_line
.color
= drawing_colors
[COL_EXIT
];
311 } else if(process
->state
->s
== LTTV_STATE_UNNAMED
) {
312 prop_line
.color
= drawing_colors
[COL_UNNAMED
];
314 g_critical("unknown state : %s", g_quark_to_string(process
->state
->s
));
315 g_assert(FALSE
); /* UNKNOWN STATE */
323 /* before_schedchange_hook
325 * This function basically draw lines and icons. Two types of lines are drawn :
326 * one small (3 pixels?) representing the state of the process and the second
327 * type is thicker (10 pixels?) representing on which CPU a process is running
328 * (and this only in running state).
330 * Extremums of the lines :
331 * x_min : time of the last event context for this process kept in memory.
332 * x_max : time of the current event.
333 * y : middle of the process in the process list. The process is found in the
334 * list, therefore is it's position in pixels.
336 * The choice of lines'color is defined by the context of the last event for this
341 int before_schedchange_hook(void *hook_data
, void *call_data
)
343 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
344 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
345 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
347 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
349 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
350 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
353 e
= ltt_tracefile_get_event(tfc
->tf
);
354 gint target_pid_saved
= tfc
->target_pid
;
356 LttTime evtime
= ltt_event_time(e
);
357 LttvFilter
*filter
= control_flow_data
->filter
;
359 /* we are in a schedchange, before the state update. We must draw the
360 * items corresponding to the state before it changes : now is the right
367 pid_out
= ltt_event_get_long_unsigned(e
, thf
->f1
);
368 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f2
);
371 tfc
->target_pid
= pid_out
;
372 if(!filter
|| !filter
->head
||
373 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
374 tfc
->t_context
->t
,tfc
)) {
375 /* For the pid_out */
376 /* First, check if the current process is in the state computation
377 * process list. If it is there, that means we must add it right now and
378 * draw items from the beginning of the read for it. If it is not
379 * present, it's a new process and it was not present : it will
380 * be added after the state update. */
381 guint cpu
= tfs
->cpu
;
382 guint trace_num
= ts
->parent
.index
;
383 LttvProcessState
*process
= ts
->running_process
[cpu
];
384 /* unknown state, bad current pid */
385 if(process
->pid
!= pid_out
)
386 process
= lttv_state_find_process(ts
,
389 if(process
!= NULL
) {
390 /* Well, the process_out existed : we must get it in the process hash
391 * or add it, and draw its items.
393 /* Add process to process list (if not present) */
395 HashedProcessData
*hashed_process_data
= NULL
;
396 ProcessList
*process_list
= control_flow_data
->process_list
;
397 LttTime birth
= process
->creation_time
;
399 hashed_process_data
= processlist_get_process_data(process_list
,
404 if(hashed_process_data
== NULL
)
406 g_assert(pid_out
== 0 || pid_out
!= process
->ppid
);
407 /* Process not present */
408 ProcessInfo
*process_info
;
409 Drawing_t
*drawing
= control_flow_data
->drawing
;
410 processlist_add(process_list
,
422 &hashed_process_data
);
423 gtk_widget_set_size_request(drawing
->drawing_area
,
426 gtk_widget_queue_draw(drawing
->drawing_area
);
430 /* Now, the process is in the state hash and our own process hash.
431 * We definitely can draw the items related to the ending state.
434 if(ltt_time_compare(hashed_process_data
->next_good_time
,
437 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
439 TimeWindow time_window
=
440 lttvwindow_get_time_window(control_flow_data
->tab
);
442 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
443 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
446 Drawing_t
*drawing
= control_flow_data
->drawing
;
447 guint width
= drawing
->width
;
449 convert_time_to_pixels(
455 /* Draw collision indicator */
456 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
457 gdk_draw_point(hashed_process_data
->pixmap
,
460 COLLISION_POSITION(hashed_process_data
->height
));
461 hashed_process_data
->x
.middle_marked
= TRUE
;
464 TimeWindow time_window
=
465 lttvwindow_get_time_window(control_flow_data
->tab
);
467 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
468 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
471 Drawing_t
*drawing
= control_flow_data
->drawing
;
472 guint width
= drawing
->width
;
474 convert_time_to_pixels(
481 /* Jump over draw if we are at the same x position */
482 if(x
== hashed_process_data
->x
.middle
&&
483 hashed_process_data
->x
.middle_used
)
485 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
486 /* Draw collision indicator */
487 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
488 gdk_draw_point(hashed_process_data
->pixmap
,
491 COLLISION_POSITION(hashed_process_data
->height
));
492 hashed_process_data
->x
.middle_marked
= TRUE
;
496 DrawContext draw_context
;
498 /* Now create the drawing context that will be used to draw
499 * items related to the last state. */
500 draw_context
.drawable
= hashed_process_data
->pixmap
;
501 draw_context
.gc
= drawing
->gc
;
502 draw_context
.pango_layout
= drawing
->pango_layout
;
503 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
504 draw_context
.drawinfo
.end
.x
= x
;
506 draw_context
.drawinfo
.y
.over
= 1;
507 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
508 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
510 draw_context
.drawinfo
.start
.offset
.over
= 0;
511 draw_context
.drawinfo
.start
.offset
.middle
= 0;
512 draw_context
.drawinfo
.start
.offset
.under
= 0;
513 draw_context
.drawinfo
.end
.offset
.over
= 0;
514 draw_context
.drawinfo
.end
.offset
.middle
= 0;
515 draw_context
.drawinfo
.end
.offset
.under
= 0;
519 PropertiesLine prop_line
= prepare_s_e_line(process
);
520 draw_line((void*)&prop_line
, (void*)&draw_context
);
523 /* become the last x position */
524 hashed_process_data
->x
.middle
= x
;
525 hashed_process_data
->x
.middle_used
= TRUE
;
526 hashed_process_data
->x
.middle_marked
= FALSE
;
528 /* Calculate the next good time */
529 convert_pixels_to_time(width
, x
+1, time_window
,
530 &hashed_process_data
->next_good_time
);
536 tfc
->target_pid
= pid_in
;
537 if(!filter
|| !filter
->head
||
538 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
539 tfc
->t_context
->t
,tfc
)) {
541 /* First, check if the current process is in the state computation
542 * process list. If it is there, that means we must add it right now and
543 * draw items from the beginning of the read for it. If it is not
544 * present, it's a new process and it was not present : it will
545 * be added after the state update. */
546 LttvProcessState
*process
;
547 process
= lttv_state_find_process(ts
,
549 guint trace_num
= ts
->parent
.index
;
551 if(process
!= NULL
) {
552 /* Well, the process existed : we must get it in the process hash
553 * or add it, and draw its items.
555 /* Add process to process list (if not present) */
557 HashedProcessData
*hashed_process_data
= NULL
;
558 ProcessList
*process_list
= control_flow_data
->process_list
;
559 LttTime birth
= process
->creation_time
;
561 hashed_process_data
= processlist_get_process_data(process_list
,
566 if(hashed_process_data
== NULL
)
568 g_assert(pid_in
== 0 || pid_in
!= process
->ppid
);
569 /* Process not present */
570 ProcessInfo
*process_info
;
571 Drawing_t
*drawing
= control_flow_data
->drawing
;
572 processlist_add(process_list
,
584 &hashed_process_data
);
585 gtk_widget_set_size_request(drawing
->drawing_area
,
588 gtk_widget_queue_draw(drawing
->drawing_area
);
591 //We could set the current process and hash here, but will be done
592 //by after schedchange hook
594 /* Now, the process is in the state hash and our own process hash.
595 * We definitely can draw the items related to the ending state.
598 if(ltt_time_compare(hashed_process_data
->next_good_time
,
601 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
603 TimeWindow time_window
=
604 lttvwindow_get_time_window(control_flow_data
->tab
);
606 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
607 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
610 Drawing_t
*drawing
= control_flow_data
->drawing
;
611 guint width
= drawing
->width
;
613 convert_time_to_pixels(
619 /* Draw collision indicator */
620 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
621 gdk_draw_point(hashed_process_data
->pixmap
,
624 COLLISION_POSITION(hashed_process_data
->height
));
625 hashed_process_data
->x
.middle_marked
= TRUE
;
628 TimeWindow time_window
=
629 lttvwindow_get_time_window(control_flow_data
->tab
);
631 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
632 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
635 Drawing_t
*drawing
= control_flow_data
->drawing
;
636 guint width
= drawing
->width
;
639 convert_time_to_pixels(
646 /* Jump over draw if we are at the same x position */
647 if(x
== hashed_process_data
->x
.middle
&&
648 hashed_process_data
->x
.middle_used
)
650 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
651 /* Draw collision indicator */
652 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
653 gdk_draw_point(hashed_process_data
->pixmap
,
656 COLLISION_POSITION(hashed_process_data
->height
));
657 hashed_process_data
->x
.middle_marked
= TRUE
;
661 DrawContext draw_context
;
663 /* Now create the drawing context that will be used to draw
664 * items related to the last state. */
665 draw_context
.drawable
= hashed_process_data
->pixmap
;
666 draw_context
.gc
= drawing
->gc
;
667 draw_context
.pango_layout
= drawing
->pango_layout
;
668 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
669 draw_context
.drawinfo
.end
.x
= x
;
671 draw_context
.drawinfo
.y
.over
= 1;
672 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
673 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
675 draw_context
.drawinfo
.start
.offset
.over
= 0;
676 draw_context
.drawinfo
.start
.offset
.middle
= 0;
677 draw_context
.drawinfo
.start
.offset
.under
= 0;
678 draw_context
.drawinfo
.end
.offset
.over
= 0;
679 draw_context
.drawinfo
.end
.offset
.middle
= 0;
680 draw_context
.drawinfo
.end
.offset
.under
= 0;
684 PropertiesLine prop_line
= prepare_s_e_line(process
);
685 draw_line((void*)&prop_line
, (void*)&draw_context
);
689 /* become the last x position */
690 hashed_process_data
->x
.middle
= x
;
691 hashed_process_data
->x
.middle_used
= TRUE
;
692 hashed_process_data
->x
.middle_marked
= FALSE
;
694 /* Calculate the next good time */
695 convert_pixels_to_time(width
, x
+1, time_window
,
696 &hashed_process_data
->next_good_time
);
700 g_warning("Cannot find pin_in in schedchange %u", pid_in
);
702 tfc
->target_pid
= target_pid_saved
;
710 GString
*string
= g_string_new("");;
711 gboolean field_names
= TRUE
, state
= TRUE
;
713 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
714 g_string_append_printf(string
,"\n");
717 g_string_append_printf(string
, " %s",
718 g_quark_to_string(tfs
->process
->state
->s
));
721 g_info("%s",string
->str
);
723 g_string_free(string
, TRUE
);
725 /* End of text dump */
730 /* after_schedchange_hook
732 * The draw after hook is called by the reading API to have a
733 * particular event drawn on the screen.
734 * @param hook_data ControlFlowData structure of the viewer.
735 * @param call_data Event context.
737 * This function adds items to be drawn in a queue for each process.
740 int after_schedchange_hook(void *hook_data
, void *call_data
)
742 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
743 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
744 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
746 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
748 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
750 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
753 e
= ltt_tracefile_get_event(tfc
->tf
);
755 LttvFilter
*filter
= control_flow_data
->filter
;
756 if(filter
!= NULL
&& filter
->head
!= NULL
)
757 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
758 tfc
->t_context
->t
,tfc
))
761 LttTime evtime
= ltt_event_time(e
);
763 /* Add process to process list (if not present) */
764 LttvProcessState
*process_in
;
767 HashedProcessData
*hashed_process_data_in
= NULL
;
769 ProcessList
*process_list
= control_flow_data
->process_list
;
774 pid_out
= ltt_event_get_long_unsigned(e
, thf
->f1
);
775 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f2
);
779 /* Find process pid_in in the list... */
780 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
781 //process_in = tfs->process;
782 guint cpu
= tfs
->cpu
;
783 guint trace_num
= ts
->parent
.index
;
784 process_in
= ts
->running_process
[cpu
];
785 /* It should exist, because we are after the state update. */
787 g_assert(process_in
!= NULL
);
789 birth
= process_in
->creation_time
;
791 hashed_process_data_in
= processlist_get_process_data(process_list
,
796 if(hashed_process_data_in
== NULL
)
798 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
799 ProcessInfo
*process_info
;
800 Drawing_t
*drawing
= control_flow_data
->drawing
;
801 /* Process not present */
802 processlist_add(process_list
,
814 &hashed_process_data_in
);
815 gtk_widget_set_size_request(drawing
->drawing_area
,
818 gtk_widget_queue_draw(drawing
->drawing_area
);
820 /* Set the current process */
821 process_list
->current_hash_data
[trace_num
][process_in
->cpu
] =
822 hashed_process_data_in
;
824 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
827 TimeWindow time_window
=
828 lttvwindow_get_time_window(control_flow_data
->tab
);
831 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
832 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
835 Drawing_t
*drawing
= control_flow_data
->drawing
;
836 guint width
= drawing
->width
;
839 convert_time_to_pixels(
845 if(hashed_process_data_in
->x
.middle
!= new_x
) {
846 hashed_process_data_in
->x
.middle
= new_x
;
847 hashed_process_data_in
->x
.middle_used
= FALSE
;
848 hashed_process_data_in
->x
.middle_marked
= FALSE
;
857 /* before_execmode_hook
859 * This function basically draw lines and icons. Two types of lines are drawn :
860 * one small (3 pixels?) representing the state of the process and the second
861 * type is thicker (10 pixels?) representing on which CPU a process is running
862 * (and this only in running state).
864 * Extremums of the lines :
865 * x_min : time of the last event context for this process kept in memory.
866 * x_max : time of the current event.
867 * y : middle of the process in the process list. The process is found in the
868 * list, therefore is it's position in pixels.
870 * The choice of lines'color is defined by the context of the last event for this
875 int before_execmode_hook(void *hook_data
, void *call_data
)
877 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
878 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
879 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
881 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
883 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
885 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
888 e
= ltt_tracefile_get_event(tfc
->tf
);
890 LttvFilter
*filter
= control_flow_data
->filter
;
891 if(filter
!= NULL
&& filter
->head
!= NULL
)
892 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
893 tfc
->t_context
->t
,tfc
))
896 LttTime evtime
= ltt_event_time(e
);
898 /* we are in a execmode, before the state update. We must draw the
899 * items corresponding to the state before it changes : now is the right
903 //LttvProcessState *process = tfs->process;
904 guint cpu
= tfs
->cpu
;
905 guint trace_num
= ts
->parent
.index
;
906 LttvProcessState
*process
= ts
->running_process
[cpu
];
907 g_assert(process
!= NULL
);
909 guint pid
= process
->pid
;
911 /* Well, the process_out existed : we must get it in the process hash
912 * or add it, and draw its items.
914 /* Add process to process list (if not present) */
916 HashedProcessData
*hashed_process_data
= NULL
;
917 ProcessList
*process_list
= control_flow_data
->process_list
;
918 LttTime birth
= process
->creation_time
;
920 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
921 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
923 hashed_process_data
= processlist_get_process_data(process_list
,
928 if(unlikely(hashed_process_data
== NULL
))
930 g_assert(pid
== 0 || pid
!= process
->ppid
);
931 ProcessInfo
*process_info
;
932 /* Process not present */
933 Drawing_t
*drawing
= control_flow_data
->drawing
;
934 processlist_add(process_list
,
946 &hashed_process_data
);
947 gtk_widget_set_size_request(drawing
->drawing_area
,
950 gtk_widget_queue_draw(drawing
->drawing_area
);
952 /* Set the current process */
953 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
957 /* Now, the process is in the state hash and our own process hash.
958 * We definitely can draw the items related to the ending state.
961 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
964 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
965 TimeWindow time_window
=
966 lttvwindow_get_time_window(control_flow_data
->tab
);
969 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
970 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
973 Drawing_t
*drawing
= control_flow_data
->drawing
;
974 guint width
= drawing
->width
;
976 convert_time_to_pixels(
982 /* Draw collision indicator */
983 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
984 gdk_draw_point(hashed_process_data
->pixmap
,
987 COLLISION_POSITION(hashed_process_data
->height
));
988 hashed_process_data
->x
.middle_marked
= TRUE
;
991 TimeWindow time_window
=
992 lttvwindow_get_time_window(control_flow_data
->tab
);
995 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
996 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
999 Drawing_t
*drawing
= control_flow_data
->drawing
;
1000 guint width
= drawing
->width
;
1003 convert_time_to_pixels(
1010 /* Jump over draw if we are at the same x position */
1011 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1012 hashed_process_data
->x
.middle_used
))
1014 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1015 /* Draw collision indicator */
1016 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1017 gdk_draw_point(hashed_process_data
->pixmap
,
1020 COLLISION_POSITION(hashed_process_data
->height
));
1021 hashed_process_data
->x
.middle_marked
= TRUE
;
1026 DrawContext draw_context
;
1027 /* Now create the drawing context that will be used to draw
1028 * items related to the last state. */
1029 draw_context
.drawable
= hashed_process_data
->pixmap
;
1030 draw_context
.gc
= drawing
->gc
;
1031 draw_context
.pango_layout
= drawing
->pango_layout
;
1032 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1033 draw_context
.drawinfo
.end
.x
= x
;
1035 draw_context
.drawinfo
.y
.over
= 1;
1036 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1037 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1039 draw_context
.drawinfo
.start
.offset
.over
= 0;
1040 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1041 draw_context
.drawinfo
.start
.offset
.under
= 0;
1042 draw_context
.drawinfo
.end
.offset
.over
= 0;
1043 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1044 draw_context
.drawinfo
.end
.offset
.under
= 0;
1048 PropertiesLine prop_line
= prepare_s_e_line(process
);
1049 draw_line((void*)&prop_line
, (void*)&draw_context
);
1052 /* become the last x position */
1053 hashed_process_data
->x
.middle
= x
;
1054 hashed_process_data
->x
.middle_used
= TRUE
;
1055 hashed_process_data
->x
.middle_marked
= FALSE
;
1057 /* Calculate the next good time */
1058 convert_pixels_to_time(width
, x
+1, time_window
,
1059 &hashed_process_data
->next_good_time
);
1066 /* before_process_exit_hook
1068 * Draw lines for process event.
1070 * @param hook_data ControlFlowData structure of the viewer.
1071 * @param call_data Event context.
1073 * This function adds items to be drawn in a queue for each process.
1078 int before_process_exit_hook(void *hook_data
, void *call_data
)
1080 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1081 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1083 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1085 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1087 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1089 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1092 e
= ltt_tracefile_get_event(tfc
->tf
);
1094 LttvFilter
*filter
= control_flow_data
->filter
;
1095 if(filter
!= NULL
&& filter
->head
!= NULL
)
1096 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1097 tfc
->t_context
->t
,tfc
))
1100 LttTime evtime
= ltt_event_time(e
);
1102 /* Add process to process list (if not present) */
1103 //LttvProcessState *process = tfs->process;
1104 guint cpu
= tfs
->cpu
;
1105 guint trace_num
= ts
->parent
.index
;
1106 LttvProcessState
*process
= ts
->running_process
[cpu
];
1107 guint pid
= process
->pid
;
1109 guint pl_height
= 0;
1110 HashedProcessData
*hashed_process_data
= NULL
;
1112 ProcessList
*process_list
= control_flow_data
->process_list
;
1114 g_assert(process
!= NULL
);
1116 birth
= process
->creation_time
;
1118 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1119 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1121 hashed_process_data
= processlist_get_process_data(process_list
,
1126 if(unlikely(hashed_process_data
== NULL
))
1128 g_assert(pid
== 0 || pid
!= process
->ppid
);
1129 /* Process not present */
1130 Drawing_t
*drawing
= control_flow_data
->drawing
;
1131 ProcessInfo
*process_info
;
1132 processlist_add(process_list
,
1144 &hashed_process_data
);
1145 gtk_widget_set_size_request(drawing
->drawing_area
,
1148 gtk_widget_queue_draw(drawing
->drawing_area
);
1152 /* Now, the process is in the state hash and our own process hash.
1153 * We definitely can draw the items related to the ending state.
1156 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1159 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1160 TimeWindow time_window
=
1161 lttvwindow_get_time_window(control_flow_data
->tab
);
1164 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1165 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1167 #endif //EXTRA_CHECK
1168 Drawing_t
*drawing
= control_flow_data
->drawing
;
1169 guint width
= drawing
->width
;
1171 convert_time_to_pixels(
1177 /* Draw collision indicator */
1178 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1179 gdk_draw_point(hashed_process_data
->pixmap
,
1182 COLLISION_POSITION(hashed_process_data
->height
));
1183 hashed_process_data
->x
.middle_marked
= TRUE
;
1186 TimeWindow time_window
=
1187 lttvwindow_get_time_window(control_flow_data
->tab
);
1190 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1191 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1193 #endif //EXTRA_CHECK
1194 Drawing_t
*drawing
= control_flow_data
->drawing
;
1195 guint width
= drawing
->width
;
1198 convert_time_to_pixels(
1205 /* Jump over draw if we are at the same x position */
1206 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1207 hashed_process_data
->x
.middle_used
))
1209 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1210 /* Draw collision indicator */
1211 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1212 gdk_draw_point(hashed_process_data
->pixmap
,
1215 COLLISION_POSITION(hashed_process_data
->height
));
1216 hashed_process_data
->x
.middle_marked
= TRUE
;
1220 DrawContext draw_context
;
1222 /* Now create the drawing context that will be used to draw
1223 * items related to the last state. */
1224 draw_context
.drawable
= hashed_process_data
->pixmap
;
1225 draw_context
.gc
= drawing
->gc
;
1226 draw_context
.pango_layout
= drawing
->pango_layout
;
1227 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1228 draw_context
.drawinfo
.end
.x
= x
;
1230 draw_context
.drawinfo
.y
.over
= 1;
1231 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1232 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1234 draw_context
.drawinfo
.start
.offset
.over
= 0;
1235 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1236 draw_context
.drawinfo
.start
.offset
.under
= 0;
1237 draw_context
.drawinfo
.end
.offset
.over
= 0;
1238 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1239 draw_context
.drawinfo
.end
.offset
.under
= 0;
1243 PropertiesLine prop_line
= prepare_s_e_line(process
);
1244 draw_line((void*)&prop_line
, (void*)&draw_context
);
1247 /* become the last x position */
1248 hashed_process_data
->x
.middle
= x
;
1249 hashed_process_data
->x
.middle_used
= TRUE
;
1250 hashed_process_data
->x
.middle_marked
= FALSE
;
1252 /* Calculate the next good time */
1253 convert_pixels_to_time(width
, x
+1, time_window
,
1254 &hashed_process_data
->next_good_time
);
1264 /* before_process_release_hook
1266 * Draw lines for process event.
1268 * @param hook_data ControlFlowData structure of the viewer.
1269 * @param call_data Event context.
1271 * This function adds items to be drawn in a queue for each process.
1276 int before_process_release_hook(void *hook_data
, void *call_data
)
1278 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1279 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1281 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1283 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1285 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1287 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1290 e
= ltt_tracefile_get_event(tfc
->tf
);
1292 LttvFilter
*filter
= control_flow_data
->filter
;
1293 if(filter
!= NULL
&& filter
->head
!= NULL
)
1294 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1295 tfc
->t_context
->t
,tfc
))
1298 LttTime evtime
= ltt_event_time(e
);
1300 guint trace_num
= ts
->parent
.index
;
1304 pid
= ltt_event_get_long_unsigned(e
, thf
->f1
);
1307 /* Add process to process list (if not present) */
1308 /* Don't care about the process if it's not in the state hash already :
1309 * that means a process that has never done anything in the trace and
1310 * unknown suddently gets destroyed : no state meaningful to show. */
1311 LttvProcessState
*process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1313 if(process
!= NULL
) {
1315 guint pl_height
= 0;
1316 HashedProcessData
*hashed_process_data
= NULL
;
1318 ProcessList
*process_list
= control_flow_data
->process_list
;
1320 birth
= process
->creation_time
;
1322 /* Cannot use current process : this event happens on another process,
1323 * action done by the parent. */
1324 hashed_process_data
= processlist_get_process_data(process_list
,
1329 if(unlikely(hashed_process_data
== NULL
))
1331 g_assert(pid
== 0 || pid
!= process
->ppid
);
1332 /* Process not present */
1333 Drawing_t
*drawing
= control_flow_data
->drawing
;
1334 ProcessInfo
*process_info
;
1335 processlist_add(process_list
,
1347 &hashed_process_data
);
1348 gtk_widget_set_size_request(drawing
->drawing_area
,
1351 gtk_widget_queue_draw(drawing
->drawing_area
);
1354 /* Now, the process is in the state hash and our own process hash.
1355 * We definitely can draw the items related to the ending state.
1358 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1361 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1362 TimeWindow time_window
=
1363 lttvwindow_get_time_window(control_flow_data
->tab
);
1366 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1367 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1369 #endif //EXTRA_CHECK
1370 Drawing_t
*drawing
= control_flow_data
->drawing
;
1371 guint width
= drawing
->width
;
1373 convert_time_to_pixels(
1379 /* Draw collision indicator */
1380 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1381 gdk_draw_point(hashed_process_data
->pixmap
,
1384 COLLISION_POSITION(hashed_process_data
->height
));
1385 hashed_process_data
->x
.middle_marked
= TRUE
;
1388 TimeWindow time_window
=
1389 lttvwindow_get_time_window(control_flow_data
->tab
);
1392 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1393 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1395 #endif //EXTRA_CHECK
1396 Drawing_t
*drawing
= control_flow_data
->drawing
;
1397 guint width
= drawing
->width
;
1400 convert_time_to_pixels(
1407 /* Jump over draw if we are at the same x position */
1408 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1409 hashed_process_data
->x
.middle_used
))
1411 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1412 /* Draw collision indicator */
1413 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1414 gdk_draw_point(hashed_process_data
->pixmap
,
1417 COLLISION_POSITION(hashed_process_data
->height
));
1418 hashed_process_data
->x
.middle_marked
= TRUE
;
1422 DrawContext draw_context
;
1424 /* Now create the drawing context that will be used to draw
1425 * items related to the last state. */
1426 draw_context
.drawable
= hashed_process_data
->pixmap
;
1427 draw_context
.gc
= drawing
->gc
;
1428 draw_context
.pango_layout
= drawing
->pango_layout
;
1429 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1430 draw_context
.drawinfo
.end
.x
= x
;
1432 draw_context
.drawinfo
.y
.over
= 1;
1433 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1434 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1436 draw_context
.drawinfo
.start
.offset
.over
= 0;
1437 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1438 draw_context
.drawinfo
.start
.offset
.under
= 0;
1439 draw_context
.drawinfo
.end
.offset
.over
= 0;
1440 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1441 draw_context
.drawinfo
.end
.offset
.under
= 0;
1445 PropertiesLine prop_line
= prepare_s_e_line(process
);
1446 draw_line((void*)&prop_line
, (void*)&draw_context
);
1449 /* become the last x position */
1450 hashed_process_data
->x
.middle
= x
;
1451 hashed_process_data
->x
.middle_used
= TRUE
;
1452 hashed_process_data
->x
.middle_marked
= FALSE
;
1454 /* Calculate the next good time */
1455 convert_pixels_to_time(width
, x
+1, time_window
,
1456 &hashed_process_data
->next_good_time
);
1468 /* after_process_fork_hook
1470 * Create the processlist entry for the child process. Put the last
1471 * position in x at the current time value.
1473 * @param hook_data ControlFlowData structure of the viewer.
1474 * @param call_data Event context.
1476 * This function adds items to be drawn in a queue for each process.
1479 int after_process_fork_hook(void *hook_data
, void *call_data
)
1481 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1482 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1483 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1485 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1487 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1489 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1492 e
= ltt_tracefile_get_event(tfc
->tf
);
1494 LttvFilter
*filter
= control_flow_data
->filter
;
1495 if(filter
!= NULL
&& filter
->head
!= NULL
)
1496 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1497 tfc
->t_context
->t
,tfc
))
1500 LttTime evtime
= ltt_event_time(e
);
1504 child_pid
= ltt_event_get_long_unsigned(e
, thf
->f2
);
1507 /* Add process to process list (if not present) */
1508 LttvProcessState
*process_child
;
1510 guint pl_height
= 0;
1511 HashedProcessData
*hashed_process_data_child
= NULL
;
1513 ProcessList
*process_list
= control_flow_data
->process_list
;
1515 /* Find child in the list... */
1516 process_child
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1517 /* It should exist, because we are after the state update. */
1518 g_assert(process_child
!= NULL
);
1520 birth
= process_child
->creation_time
;
1521 guint trace_num
= ts
->parent
.index
;
1523 /* Cannot use current process, because this action is done by the parent
1525 hashed_process_data_child
= processlist_get_process_data(process_list
,
1530 if(likely(hashed_process_data_child
== NULL
))
1532 g_assert(child_pid
== 0 || child_pid
!= process_child
->ppid
);
1533 /* Process not present */
1534 Drawing_t
*drawing
= control_flow_data
->drawing
;
1535 ProcessInfo
*process_info
;
1536 processlist_add(process_list
,
1539 process_child
->tgid
,
1541 process_child
->ppid
,
1544 process_child
->name
,
1545 process_child
->brand
,
1548 &hashed_process_data_child
);
1549 gtk_widget_set_size_request(drawing
->drawing_area
,
1552 gtk_widget_queue_draw(drawing
->drawing_area
);
1554 processlist_set_ppid(process_list
, process_child
->ppid
,
1555 hashed_process_data_child
);
1556 processlist_set_tgid(process_list
, process_child
->tgid
,
1557 hashed_process_data_child
);
1561 if(likely(ltt_time_compare(hashed_process_data_child
->next_good_time
,
1564 TimeWindow time_window
=
1565 lttvwindow_get_time_window(control_flow_data
->tab
);
1568 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1569 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1571 #endif //EXTRA_CHECK
1572 Drawing_t
*drawing
= control_flow_data
->drawing
;
1573 guint width
= drawing
->width
;
1575 convert_time_to_pixels(
1581 if(likely(hashed_process_data_child
->x
.over
!= new_x
)) {
1582 hashed_process_data_child
->x
.over
= new_x
;
1583 hashed_process_data_child
->x
.over_used
= FALSE
;
1584 hashed_process_data_child
->x
.over_marked
= FALSE
;
1586 if(likely(hashed_process_data_child
->x
.middle
!= new_x
)) {
1587 hashed_process_data_child
->x
.middle
= new_x
;
1588 hashed_process_data_child
->x
.middle_used
= FALSE
;
1589 hashed_process_data_child
->x
.middle_marked
= FALSE
;
1591 if(likely(hashed_process_data_child
->x
.under
!= new_x
)) {
1592 hashed_process_data_child
->x
.under
= new_x
;
1593 hashed_process_data_child
->x
.under_used
= FALSE
;
1594 hashed_process_data_child
->x
.under_marked
= FALSE
;
1602 /* after_process_exit_hook
1604 * Create the processlist entry for the child process. Put the last
1605 * position in x at the current time value.
1607 * @param hook_data ControlFlowData structure of the viewer.
1608 * @param call_data Event context.
1610 * This function adds items to be drawn in a queue for each process.
1613 int after_process_exit_hook(void *hook_data
, void *call_data
)
1615 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1616 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1617 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1619 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1621 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1623 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1626 e
= ltt_tracefile_get_event(tfc
->tf
);
1628 LttvFilter
*filter
= control_flow_data
->filter
;
1629 if(filter
!= NULL
&& filter
->head
!= NULL
)
1630 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1631 tfc
->t_context
->t
,tfc
))
1634 LttTime evtime
= ltt_event_time(e
);
1636 /* Add process to process list (if not present) */
1637 //LttvProcessState *process = tfs->process;
1638 guint cpu
= tfs
->cpu
;
1639 guint trace_num
= ts
->parent
.index
;
1640 LttvProcessState
*process
= ts
->running_process
[cpu
];
1642 /* It should exist, because we are after the state update. */
1643 g_assert(process
!= NULL
);
1645 guint pid
= process
->pid
;
1647 guint pl_height
= 0;
1648 HashedProcessData
*hashed_process_data
= NULL
;
1650 ProcessList
*process_list
= control_flow_data
->process_list
;
1652 birth
= process
->creation_time
;
1654 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
) ){
1655 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1657 hashed_process_data
= processlist_get_process_data(process_list
,
1662 if(unlikely(hashed_process_data
== NULL
))
1664 g_assert(pid
== 0 || pid
!= process
->ppid
);
1665 /* Process not present */
1666 Drawing_t
*drawing
= control_flow_data
->drawing
;
1667 ProcessInfo
*process_info
;
1668 processlist_add(process_list
,
1680 &hashed_process_data
);
1681 gtk_widget_set_size_request(drawing
->drawing_area
,
1684 gtk_widget_queue_draw(drawing
->drawing_area
);
1687 /* Set the current process */
1688 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1689 hashed_process_data
;
1692 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
1695 TimeWindow time_window
=
1696 lttvwindow_get_time_window(control_flow_data
->tab
);
1699 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1700 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1702 #endif //EXTRA_CHECK
1703 Drawing_t
*drawing
= control_flow_data
->drawing
;
1704 guint width
= drawing
->width
;
1706 convert_time_to_pixels(
1711 if(unlikely(hashed_process_data
->x
.middle
!= new_x
)) {
1712 hashed_process_data
->x
.middle
= new_x
;
1713 hashed_process_data
->x
.middle_used
= FALSE
;
1714 hashed_process_data
->x
.middle_marked
= FALSE
;
1722 /* Get the filename of the process to print */
1723 int after_fs_exec_hook(void *hook_data
, void *call_data
)
1725 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1726 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1727 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1729 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1731 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1733 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1736 e
= ltt_tracefile_get_event(tfc
->tf
);
1738 LttvFilter
*filter
= control_flow_data
->filter
;
1739 if(filter
!= NULL
&& filter
->head
!= NULL
)
1740 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1741 tfc
->t_context
->t
,tfc
))
1744 guint cpu
= tfs
->cpu
;
1745 guint trace_num
= ts
->parent
.index
;
1746 LttvProcessState
*process
= ts
->running_process
[cpu
];
1747 g_assert(process
!= NULL
);
1749 guint pid
= process
->pid
;
1751 /* Well, the process_out existed : we must get it in the process hash
1752 * or add it, and draw its items.
1754 /* Add process to process list (if not present) */
1755 guint pl_height
= 0;
1756 HashedProcessData
*hashed_process_data
= NULL
;
1757 ProcessList
*process_list
= control_flow_data
->process_list
;
1758 LttTime birth
= process
->creation_time
;
1760 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1761 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1763 hashed_process_data
= processlist_get_process_data(process_list
,
1768 if(unlikely(hashed_process_data
== NULL
))
1770 g_assert(pid
== 0 || pid
!= process
->ppid
);
1771 ProcessInfo
*process_info
;
1772 /* Process not present */
1773 Drawing_t
*drawing
= control_flow_data
->drawing
;
1774 processlist_add(process_list
,
1786 &hashed_process_data
);
1787 gtk_widget_set_size_request(drawing
->drawing_area
,
1790 gtk_widget_queue_draw(drawing
->drawing_area
);
1792 /* Set the current process */
1793 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1794 hashed_process_data
;
1797 processlist_set_name(process_list
, process
->name
, hashed_process_data
);
1803 /* Get the filename of the process to print */
1804 int after_user_generic_thread_brand_hook(void *hook_data
, void *call_data
)
1806 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1807 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1808 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1810 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1812 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1814 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1817 e
= ltt_tracefile_get_event(tfc
->tf
);
1819 LttvFilter
*filter
= control_flow_data
->filter
;
1820 if(filter
!= NULL
&& filter
->head
!= NULL
)
1821 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1822 tfc
->t_context
->t
,tfc
))
1825 guint cpu
= tfs
->cpu
;
1826 guint trace_num
= ts
->parent
.index
;
1827 LttvProcessState
*process
= ts
->running_process
[cpu
];
1828 g_assert(process
!= NULL
);
1830 guint pid
= process
->pid
;
1832 /* Well, the process_out existed : we must get it in the process hash
1833 * or add it, and draw its items.
1835 /* Add process to process list (if not present) */
1836 guint pl_height
= 0;
1837 HashedProcessData
*hashed_process_data
= NULL
;
1838 ProcessList
*process_list
= control_flow_data
->process_list
;
1839 LttTime birth
= process
->creation_time
;
1841 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1842 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1844 hashed_process_data
= processlist_get_process_data(process_list
,
1849 if(unlikely(hashed_process_data
== NULL
))
1851 g_assert(pid
== 0 || pid
!= process
->ppid
);
1852 ProcessInfo
*process_info
;
1853 /* Process not present */
1854 Drawing_t
*drawing
= control_flow_data
->drawing
;
1855 processlist_add(process_list
,
1867 &hashed_process_data
);
1868 gtk_widget_set_size_request(drawing
->drawing_area
,
1871 gtk_widget_queue_draw(drawing
->drawing_area
);
1873 /* Set the current process */
1874 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1875 hashed_process_data
;
1878 processlist_set_brand(process_list
, process
->brand
, hashed_process_data
);
1885 /* after_event_enum_process_hook
1887 * Create the processlist entry for the child process. Put the last
1888 * position in x at the current time value.
1890 * @param hook_data ControlFlowData structure of the viewer.
1891 * @param call_data Event context.
1893 * This function adds items to be drawn in a queue for each process.
1896 int after_event_enum_process_hook(void *hook_data
, void *call_data
)
1898 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1899 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1900 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1902 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1904 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1906 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1909 e
= ltt_tracefile_get_event(tfc
->tf
);
1911 LttvFilter
*filter
= control_flow_data
->filter
;
1912 if(filter
!= NULL
&& filter
->head
!= NULL
)
1913 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1914 tfc
->t_context
->t
,tfc
))
1917 LttTime evtime
= ltt_event_time(e
);
1919 /* Add process to process list (if not present) */
1920 LttvProcessState
*process_in
;
1922 guint pl_height
= 0;
1923 HashedProcessData
*hashed_process_data_in
= NULL
;
1925 ProcessList
*process_list
= control_flow_data
->process_list
;
1926 guint trace_num
= ts
->parent
.index
;
1930 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f1
);
1934 /* Find process pid_in in the list... */
1935 process_in
= lttv_state_find_process(ts
, ANY_CPU
, pid_in
);
1936 //process_in = tfs->process;
1937 //guint cpu = tfs->cpu;
1938 //guint trace_num = ts->parent.index;
1939 //process_in = ts->running_process[cpu];
1940 /* It should exist, because we are after the state update. */
1942 //g_assert(process_in != NULL);
1943 #endif //EXTRA_CHECK
1944 birth
= process_in
->creation_time
;
1946 hashed_process_data_in
= processlist_get_process_data(process_list
,
1951 if(hashed_process_data_in
== NULL
)
1953 if(pid_in
!= 0 && pid_in
== process_in
->ppid
)
1954 g_critical("TEST %u , %u", pid_in
, process_in
->ppid
);
1955 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
1956 ProcessInfo
*process_info
;
1957 Drawing_t
*drawing
= control_flow_data
->drawing
;
1958 /* Process not present */
1959 processlist_add(process_list
,
1971 &hashed_process_data_in
);
1972 gtk_widget_set_size_request(drawing
->drawing_area
,
1975 gtk_widget_queue_draw(drawing
->drawing_area
);
1977 processlist_set_name(process_list
, process_in
->name
,
1978 hashed_process_data_in
);
1979 processlist_set_ppid(process_list
, process_in
->ppid
,
1980 hashed_process_data_in
);
1981 processlist_set_tgid(process_list
, process_in
->tgid
,
1982 hashed_process_data_in
);
1988 gint
update_time_window_hook(void *hook_data
, void *call_data
)
1990 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1991 Drawing_t
*drawing
= control_flow_data
->drawing
;
1992 ProcessList
*process_list
= control_flow_data
->process_list
;
1994 const TimeWindowNotifyData
*time_window_nofify_data
=
1995 ((const TimeWindowNotifyData
*)call_data
);
1997 TimeWindow
*old_time_window
=
1998 time_window_nofify_data
->old_time_window
;
1999 TimeWindow
*new_time_window
=
2000 time_window_nofify_data
->new_time_window
;
2002 /* Update the ruler */
2003 drawing_update_ruler(control_flow_data
->drawing
,
2007 /* Two cases : zoom in/out or scrolling */
2009 /* In order to make sure we can reuse the old drawing, the scale must
2010 * be the same and the new time interval being partly located in the
2011 * currently shown time interval. (reuse is only for scrolling)
2014 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
2015 old_time_window
->start_time
.tv_sec
,
2016 old_time_window
->start_time
.tv_nsec
,
2017 old_time_window
->time_width
.tv_sec
,
2018 old_time_window
->time_width
.tv_nsec
);
2020 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
2021 new_time_window
->start_time
.tv_sec
,
2022 new_time_window
->start_time
.tv_nsec
,
2023 new_time_window
->time_width
.tv_sec
,
2024 new_time_window
->time_width
.tv_nsec
);
2026 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
2027 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
2029 /* Same scale (scrolling) */
2030 g_info("scrolling");
2031 LttTime
*ns
= &new_time_window
->start_time
;
2032 LttTime
*nw
= &new_time_window
->time_width
;
2033 LttTime
*os
= &old_time_window
->start_time
;
2034 LttTime
*ow
= &old_time_window
->time_width
;
2035 LttTime old_end
= old_time_window
->end_time
;
2036 LttTime new_end
= new_time_window
->end_time
;
2038 //if(ns<os+w && os+w<ns+w)
2039 //if(ns<old_end && os<ns)
2040 if(ltt_time_compare(*ns
, old_end
) == -1
2041 && ltt_time_compare(*os
, *ns
) == -1)
2043 g_info("scrolling near right");
2044 /* Scroll right, keep right part of the screen */
2046 guint width
= control_flow_data
->drawing
->width
;
2047 convert_time_to_pixels(
2053 /* Copy old data to new location */
2054 copy_pixmap_region(process_list
,
2056 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2060 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
2062 if(drawing
->damage_begin
== drawing
->damage_end
)
2063 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
2065 drawing
->damage_begin
= 0;
2067 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2069 /* Clear the data request background, but not SAFETY */
2070 rectangle_pixmap(process_list
,
2071 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2073 drawing
->damage_begin
+SAFETY
, 0,
2074 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2076 gtk_widget_queue_draw(drawing
->drawing_area
);
2077 //gtk_widget_queue_draw_area (drawing->drawing_area,
2079 // control_flow_data->drawing->width,
2080 // control_flow_data->drawing->height);
2082 /* Get new data for the rest. */
2083 drawing_data_request(control_flow_data
->drawing
,
2084 drawing
->damage_begin
, 0,
2085 drawing
->damage_end
- drawing
->damage_begin
,
2086 control_flow_data
->drawing
->height
);
2089 //if(ns<os && os<ns+w)
2090 //if(ns<os && os<new_end)
2091 if(ltt_time_compare(*ns
,*os
) == -1
2092 && ltt_time_compare(*os
,new_end
) == -1)
2094 g_info("scrolling near left");
2095 /* Scroll left, keep left part of the screen */
2097 guint width
= control_flow_data
->drawing
->width
;
2098 convert_time_to_pixels(
2104 /* Copy old data to new location */
2105 copy_pixmap_region (process_list
,
2107 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2113 if(drawing
->damage_begin
== drawing
->damage_end
)
2114 drawing
->damage_end
= x
;
2116 drawing
->damage_end
=
2117 control_flow_data
->drawing
->width
;
2119 drawing
->damage_begin
= 0;
2121 rectangle_pixmap (process_list
,
2122 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2124 drawing
->damage_begin
, 0,
2125 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2128 gtk_widget_queue_draw(drawing
->drawing_area
);
2129 //gtk_widget_queue_draw_area (drawing->drawing_area,
2131 // control_flow_data->drawing->width,
2132 // control_flow_data->drawing->height);
2135 /* Get new data for the rest. */
2136 drawing_data_request(control_flow_data
->drawing
,
2137 drawing
->damage_begin
, 0,
2138 drawing
->damage_end
- drawing
->damage_begin
,
2139 control_flow_data
->drawing
->height
);
2142 if(ltt_time_compare(*ns
,*os
) == 0)
2144 g_info("not scrolling");
2146 g_info("scrolling far");
2147 /* Cannot reuse any part of the screen : far jump */
2150 rectangle_pixmap (process_list
,
2151 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2154 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2157 //gtk_widget_queue_draw_area (drawing->drawing_area,
2159 // control_flow_data->drawing->width,
2160 // control_flow_data->drawing->height);
2161 gtk_widget_queue_draw(drawing
->drawing_area
);
2163 drawing
->damage_begin
= 0;
2164 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2166 drawing_data_request(control_flow_data
->drawing
,
2168 control_flow_data
->drawing
->width
,
2169 control_flow_data
->drawing
->height
);
2175 /* Different scale (zoom) */
2178 rectangle_pixmap (process_list
,
2179 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2182 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2185 //gtk_widget_queue_draw_area (drawing->drawing_area,
2187 // control_flow_data->drawing->width,
2188 // control_flow_data->drawing->height);
2189 gtk_widget_queue_draw(drawing
->drawing_area
);
2191 drawing
->damage_begin
= 0;
2192 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2194 drawing_data_request(control_flow_data
->drawing
,
2196 control_flow_data
->drawing
->width
,
2197 control_flow_data
->drawing
->height
);
2200 /* Update directly when scrolling */
2201 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2207 gint
traceset_notify(void *hook_data
, void *call_data
)
2209 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2210 Drawing_t
*drawing
= control_flow_data
->drawing
;
2212 if(unlikely(drawing
->gc
== NULL
)) {
2215 if(drawing
->dotted_gc
== NULL
) {
2219 drawing_clear(control_flow_data
->drawing
);
2220 processlist_clear(control_flow_data
->process_list
);
2221 gtk_widget_set_size_request(
2222 control_flow_data
->drawing
->drawing_area
,
2223 -1, processlist_get_height(control_flow_data
->process_list
));
2224 redraw_notify(control_flow_data
, NULL
);
2226 request_background_data(control_flow_data
);
2231 gint
redraw_notify(void *hook_data
, void *call_data
)
2233 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2234 Drawing_t
*drawing
= control_flow_data
->drawing
;
2235 GtkWidget
*widget
= drawing
->drawing_area
;
2237 drawing
->damage_begin
= 0;
2238 drawing
->damage_end
= drawing
->width
;
2240 /* fun feature, to be separated someday... */
2241 drawing_clear(control_flow_data
->drawing
);
2242 processlist_clear(control_flow_data
->process_list
);
2243 gtk_widget_set_size_request(
2244 control_flow_data
->drawing
->drawing_area
,
2245 -1, processlist_get_height(control_flow_data
->process_list
));
2247 rectangle_pixmap (control_flow_data
->process_list
,
2248 widget
->style
->black_gc
,
2251 drawing
->alloc_width
,
2254 gtk_widget_queue_draw(drawing
->drawing_area
);
2256 if(drawing
->damage_begin
< drawing
->damage_end
)
2258 drawing_data_request(drawing
,
2259 drawing
->damage_begin
,
2261 drawing
->damage_end
-drawing
->damage_begin
,
2265 //gtk_widget_queue_draw_area(drawing->drawing_area,
2268 // drawing->height);
2274 gint
continue_notify(void *hook_data
, void *call_data
)
2276 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2277 Drawing_t
*drawing
= control_flow_data
->drawing
;
2279 //g_assert(widget->allocation.width == drawing->damage_end);
2281 if(drawing
->damage_begin
< drawing
->damage_end
)
2283 drawing_data_request(drawing
,
2284 drawing
->damage_begin
,
2286 drawing
->damage_end
-drawing
->damage_begin
,
2294 gint
update_current_time_hook(void *hook_data
, void *call_data
)
2296 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
2297 Drawing_t
*drawing
= control_flow_data
->drawing
;
2299 LttTime current_time
= *((LttTime
*)call_data
);
2301 TimeWindow time_window
=
2302 lttvwindow_get_time_window(control_flow_data
->tab
);
2304 LttTime time_begin
= time_window
.start_time
;
2305 LttTime width
= time_window
.time_width
;
2308 guint64 time_ll
= ltt_time_to_uint64(width
);
2309 time_ll
= time_ll
>> 1; /* divide by two */
2310 half_width
= ltt_time_from_uint64(time_ll
);
2312 LttTime time_end
= ltt_time_add(time_begin
, width
);
2314 LttvTracesetContext
* tsc
=
2315 lttvwindow_get_traceset_context(control_flow_data
->tab
);
2317 LttTime trace_start
= tsc
->time_span
.start_time
;
2318 LttTime trace_end
= tsc
->time_span
.end_time
;
2320 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
2321 current_time
.tv_nsec
);
2325 /* If current time is inside time interval, just move the highlight
2328 /* Else, we have to change the time interval. We have to tell it
2329 * to the main window. */
2330 /* The time interval change will take care of placing the current
2331 * time at the center of the visible area, or nearest possible if we are
2332 * at one end of the trace. */
2335 if(ltt_time_compare(current_time
, time_begin
) < 0)
2337 TimeWindow new_time_window
;
2339 if(ltt_time_compare(current_time
,
2340 ltt_time_add(trace_start
,half_width
)) < 0)
2341 time_begin
= trace_start
;
2343 time_begin
= ltt_time_sub(current_time
,half_width
);
2345 new_time_window
.start_time
= time_begin
;
2346 new_time_window
.time_width
= width
;
2347 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2348 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2350 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2352 else if(ltt_time_compare(current_time
, time_end
) > 0)
2354 TimeWindow new_time_window
;
2356 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
2357 time_begin
= ltt_time_sub(trace_end
,width
);
2359 time_begin
= ltt_time_sub(current_time
,half_width
);
2361 new_time_window
.start_time
= time_begin
;
2362 new_time_window
.time_width
= width
;
2363 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2364 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2366 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2369 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2371 /* Update directly when scrolling */
2372 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2378 typedef struct _ClosureData
{
2379 EventsRequest
*events_request
;
2380 LttvTracesetState
*tss
;
2386 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
2388 ProcessInfo
*process_info
= (ProcessInfo
*)key
;
2389 HashedProcessData
*hashed_process_data
= (HashedProcessData
*)value
;
2390 ClosureData
*closure_data
= (ClosureData
*)user_data
;
2392 EventsRequest
*events_request
= closure_data
->events_request
;
2393 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2395 LttvTracesetState
*tss
= closure_data
->tss
;
2396 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)tss
;
2398 LttTime evtime
= closure_data
->end_time
;
2401 /* For the process */
2402 /* First, check if the current process is in the state computation
2403 * process list. If it is there, that means we must add it right now and
2404 * draw items from the beginning of the read for it. If it is not
2405 * present, it's a new process and it was not present : it will
2406 * be added after the state update. */
2408 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
2409 #endif //EXTRA_CHECK
2410 LttvTraceContext
*tc
= tsc
->traces
[process_info
->trace_num
];
2411 LttvTraceState
*ts
= (LttvTraceState
*)tc
;
2414 //FIXME : optimize data structures.
2415 LttvTracefileState
*tfs
;
2416 LttvTracefileContext
*tfc
;
2418 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
2419 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
2420 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
2421 && tfs
->cpu
== process_info
->cpu
)
2425 g_assert(i
<tc
->tracefiles
->len
);
2426 tfs
= LTTV_TRACEFILE_STATE(tfc
);
2428 // LttvTracefileState *tfs =
2429 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2430 // tracefiles[process_info->cpu];
2432 LttvProcessState
*process
;
2433 process
= lttv_state_find_process(ts
, process_info
->cpu
,
2436 if(unlikely(process
!= NULL
)) {
2438 /* Only draw for processes that are currently in the trace states */
2440 ProcessList
*process_list
= control_flow_data
->process_list
;
2442 /* Should be alike when background info is ready */
2443 if(control_flow_data
->background_info_waiting
==0)
2444 g_assert(ltt_time_compare(process
->creation_time
,
2445 process_info
->birth
) == 0);
2446 #endif //EXTRA_CHECK
2448 /* Now, the process is in the state hash and our own process hash.
2449 * We definitely can draw the items related to the ending state.
2452 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2455 TimeWindow time_window
=
2456 lttvwindow_get_time_window(control_flow_data
->tab
);
2459 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2460 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2462 #endif //EXTRA_CHECK
2463 Drawing_t
*drawing
= control_flow_data
->drawing
;
2464 guint width
= drawing
->width
;
2466 guint x
= closure_data
->x_end
;
2468 DrawContext draw_context
;
2470 /* Now create the drawing context that will be used to draw
2471 * items related to the last state. */
2472 draw_context
.drawable
= hashed_process_data
->pixmap
;
2473 draw_context
.gc
= drawing
->gc
;
2474 draw_context
.pango_layout
= drawing
->pango_layout
;
2475 draw_context
.drawinfo
.end
.x
= x
;
2477 draw_context
.drawinfo
.y
.over
= 1;
2478 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2479 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2481 draw_context
.drawinfo
.start
.offset
.over
= 0;
2482 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2483 draw_context
.drawinfo
.start
.offset
.under
= 0;
2484 draw_context
.drawinfo
.end
.offset
.over
= 0;
2485 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2486 draw_context
.drawinfo
.end
.offset
.under
= 0;
2488 /* Jump over draw if we are at the same x position */
2489 if(x
== hashed_process_data
->x
.over
)
2493 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2495 PropertiesLine prop_line
= prepare_execmode_line(process
);
2496 draw_line((void*)&prop_line
, (void*)&draw_context
);
2498 hashed_process_data
->x
.over
= x
;
2502 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2503 hashed_process_data
->x
.middle_used
)) {
2504 #if 0 /* do not mark closure : not missing information */
2505 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2506 /* Draw collision indicator */
2507 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2508 gdk_draw_point(drawing
->pixmap
,
2512 hashed_process_data
->x
.middle_marked
= TRUE
;
2517 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2519 PropertiesLine prop_line
= prepare_s_e_line(process
);
2520 draw_line((void*)&prop_line
, (void*)&draw_context
);
2522 /* become the last x position */
2523 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2524 hashed_process_data
->x
.middle
= x
;
2525 /* but don't use the pixel */
2526 hashed_process_data
->x
.middle_used
= FALSE
;
2528 /* Calculate the next good time */
2529 convert_pixels_to_time(width
, x
+1, time_window
,
2530 &hashed_process_data
->next_good_time
);
2539 int before_chunk(void *hook_data
, void *call_data
)
2541 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2542 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2543 ControlFlowData
*cfd
= (ControlFlowData
*)events_request
->viewer_data
;
2545 /* Desactivate sort */
2546 gtk_tree_sortable_set_sort_column_id(
2547 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2549 GTK_SORT_ASCENDING
);
2551 drawing_chunk_begin(events_request
, tss
);
2556 int before_request(void *hook_data
, void *call_data
)
2558 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2559 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2561 drawing_data_request_begin(events_request
, tss
);
2568 * after request is necessary in addition of after chunk in order to draw
2569 * lines until the end of the screen. after chunk just draws lines until
2576 int after_request(void *hook_data
, void *call_data
)
2578 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2579 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2580 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2582 ProcessList
*process_list
= control_flow_data
->process_list
;
2583 LttTime end_time
= events_request
->end_time
;
2585 ClosureData closure_data
;
2586 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2587 closure_data
.tss
= tss
;
2588 closure_data
.end_time
= end_time
;
2590 TimeWindow time_window
=
2591 lttvwindow_get_time_window(control_flow_data
->tab
);
2592 guint width
= control_flow_data
->drawing
->width
;
2593 convert_time_to_pixels(
2597 &closure_data
.x_end
);
2600 /* Draw last items */
2601 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2602 (void*)&closure_data
);
2605 /* Request expose */
2606 drawing_request_expose(events_request
, tss
, end_time
);
2615 int after_chunk(void *hook_data
, void *call_data
)
2617 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2618 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2619 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2620 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)call_data
;
2621 LttvTracefileContext
*tfc
= lttv_traceset_context_get_current_tfc(tsc
);
2624 ProcessList
*process_list
= control_flow_data
->process_list
;
2626 LttvTraceset
*traceset
= tsc
->ts
;
2627 guint nb_trace
= lttv_traceset_number(traceset
);
2629 /* Only execute when called for the first trace's events request */
2630 if(!process_list
->current_hash_data
) return;
2632 for(i
= 0 ; i
< nb_trace
; i
++) {
2633 g_free(process_list
->current_hash_data
[i
]);
2635 g_free(process_list
->current_hash_data
);
2636 process_list
->current_hash_data
= NULL
;
2639 end_time
= LTT_TIME_MIN(tfc
->timestamp
, events_request
->end_time
);
2640 else /* end of traceset, or position now out of request : end */
2641 end_time
= events_request
->end_time
;
2643 ClosureData closure_data
;
2644 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2645 closure_data
.tss
= tss
;
2646 closure_data
.end_time
= end_time
;
2648 TimeWindow time_window
=
2649 lttvwindow_get_time_window(control_flow_data
->tab
);
2650 guint width
= control_flow_data
->drawing
->width
;
2651 convert_time_to_pixels(
2655 &closure_data
.x_end
);
2657 /* Draw last items */
2658 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2659 (void*)&closure_data
);
2661 /* Reactivate sort */
2662 gtk_tree_sortable_set_sort_column_id(
2663 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2664 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2665 GTK_SORT_ASCENDING
);
2667 update_index_to_pixmap(control_flow_data
->process_list
);
2668 /* Request a full expose : drawing scrambled */
2669 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2671 /* Request expose (updates damages zone also) */
2672 drawing_request_expose(events_request
, tss
, end_time
);