1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Mathieu Desnoyers
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20 /*****************************************************************************
21 * Hooks to be called by the main window *
22 *****************************************************************************/
25 /* Event hooks are the drawing hooks called during traceset read. They draw the
26 * icons, text, lines and background color corresponding to the events read.
28 * Two hooks are used for drawing : before_schedchange and after_schedchange hooks. The
29 * before_schedchange is called before the state update that occurs with an event and
30 * the after_schedchange hook is called after this state update.
32 * The before_schedchange hooks fulfill the task of drawing the visible objects that
33 * corresponds to the data accumulated by the after_schedchange hook.
35 * The after_schedchange hook accumulates the data that need to be shown on the screen
36 * (items) into a queue. Then, the next before_schedchange hook will draw what that
37 * queue contains. That's the Right Way (TM) of drawing items on the screen,
38 * because we need to draw the background first (and then add icons, text, ...
39 * over it), but we only know the length of a background region once the state
40 * corresponding to it is over, which happens to be at the next before_schedchange
43 * We also have a hook called at the end of a chunk to draw the information left
44 * undrawn in each process queue. We use the current time as end of
52 //#define PANGO_ENABLE_BACKEND
60 //#include <pango/pango.h>
62 #include <ltt/event.h>
65 #include <ltt/trace.h>
67 #include <lttv/lttv.h>
68 #include <lttv/hook.h>
69 #include <lttv/state.h>
70 #include <lttvwindow/lttvwindow.h>
71 #include <lttvwindow/lttvwindowtraces.h>
72 #include <lttvwindow/support.h>
75 #include "eventhooks.h"
77 #include "processlist.h"
81 #define MAX_PATH_LEN 256
82 #define STATE_LINE_WIDTH 4
83 #define COLLISION_POSITION(height) (((height - STATE_LINE_WIDTH)/2) -3)
85 extern GSList
*g_legend_list
;
88 /* Action to do when background computation completed.
90 * Wait for all the awaited computations to be over.
93 static gint
background_ready(void *hook_data
, void *call_data
)
95 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
96 LttvTrace
*trace
= (LttvTrace
*)call_data
;
98 control_flow_data
->background_info_waiting
--;
100 if(control_flow_data
->background_info_waiting
== 0) {
101 g_message("control flow viewer : background computation data ready.");
103 drawing_clear(control_flow_data
->drawing
);
104 processlist_clear(control_flow_data
->process_list
);
105 gtk_widget_set_size_request(
106 control_flow_data
->drawing
->drawing_area
,
107 -1, processlist_get_height(control_flow_data
->process_list
));
108 redraw_notify(control_flow_data
, NULL
);
115 /* Request background computation. Verify if it is in progress or ready first.
116 * Only for each trace in the tab's traceset.
118 static void request_background_data(ControlFlowData
*control_flow_data
)
120 LttvTracesetContext
* tsc
=
121 lttvwindow_get_traceset_context(control_flow_data
->tab
);
122 gint num_traces
= lttv_traceset_number(tsc
->ts
);
125 LttvTraceState
*tstate
;
127 LttvHooks
*background_ready_hook
=
129 lttv_hooks_add(background_ready_hook
, background_ready
, control_flow_data
,
131 control_flow_data
->background_info_waiting
= 0;
133 for(i
=0;i
<num_traces
;i
++) {
134 trace
= lttv_traceset_get(tsc
->ts
, i
);
135 tstate
= LTTV_TRACE_STATE(tsc
->traces
[i
]);
137 if(lttvwindowtraces_get_ready(g_quark_from_string("state"),trace
)==FALSE
138 && !tstate
->has_precomputed_states
) {
140 if(lttvwindowtraces_get_in_progress(g_quark_from_string("state"),
142 /* We first remove requests that could have been done for the same
143 * information. Happens when two viewers ask for it before servicing
146 if(!lttvwindowtraces_background_request_find(trace
, "state"))
147 lttvwindowtraces_background_request_queue(
148 main_window_get_widget(control_flow_data
->tab
), trace
, "state");
149 lttvwindowtraces_background_notify_queue(control_flow_data
,
153 background_ready_hook
);
154 control_flow_data
->background_info_waiting
++;
155 } else { /* in progress */
157 lttvwindowtraces_background_notify_current(control_flow_data
,
161 background_ready_hook
);
162 control_flow_data
->background_info_waiting
++;
165 /* Data ready. By its nature, this viewer doesn't need to have
166 * its data ready hook called there, because a background
167 * request is always linked with a redraw.
173 lttv_hooks_destroy(background_ready_hook
);
180 * Event Viewer's constructor hook
182 * This constructor is given as a parameter to the menuitem and toolbar button
183 * registration. It creates the list.
184 * @param tab A pointer to the parent tab.
185 * @return The widget created.
188 h_guicontrolflow(LttvPlugin
*plugin
)
190 LttvPluginTab
*ptab
= LTTV_PLUGIN_TAB(plugin
);
191 Tab
*tab
= ptab
->tab
;
192 g_info("h_guicontrolflow, %p", tab
);
193 ControlFlowData
*control_flow_data
= guicontrolflow(ptab
);
195 control_flow_data
->tab
= tab
;
197 // Unreg done in the GuiControlFlow_Destructor
198 lttvwindow_register_traceset_notify(tab
,
202 lttvwindow_register_time_window_notify(tab
,
203 update_time_window_hook
,
205 lttvwindow_register_current_time_notify(tab
,
206 update_current_time_hook
,
208 lttvwindow_register_redraw_notify(tab
,
211 lttvwindow_register_continue_notify(tab
,
214 request_background_data(control_flow_data
);
217 return guicontrolflow_get_widget(control_flow_data
) ;
221 void legend_destructor(GtkWindow
*legend
)
223 g_legend_list
= g_slist_remove(g_legend_list
, legend
);
226 /* Create a popup legend */
228 h_legend(LttvPlugin
*plugin
)
230 LttvPluginTab
*ptab
= LTTV_PLUGIN_TAB(plugin
);
231 Tab
*tab
= ptab
->tab
;
232 g_info("h_legend, %p", tab
);
234 GtkWindow
*legend
= GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL
));
236 g_legend_list
= g_slist_append(
240 g_object_set_data_full(
244 (GDestroyNotify
)legend_destructor
);
246 gtk_window_set_title(legend
, "Control Flow View Legend");
248 GtkWidget
*pixmap
= create_pixmap(GTK_WIDGET(legend
), "lttv-color-list.png");
250 // GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixmap(
251 // GDK_PIXMAP(pixmap), NULL));
253 gtk_container_add(GTK_CONTAINER(legend
), GTK_WIDGET(pixmap
));
255 gtk_widget_show(GTK_WIDGET(pixmap
));
256 gtk_widget_show(GTK_WIDGET(legend
));
259 return NULL
; /* This is a popup window */
263 int event_selected_hook(void *hook_data
, void *call_data
)
265 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
266 guint
*event_number
= (guint
*) call_data
;
268 g_debug("DEBUG : event selected by main window : %u", *event_number
);
273 /* Function that selects the color of status&exemode line */
274 static inline PropertiesLine
prepare_s_e_line(LttvProcessState
*process
)
276 PropertiesLine prop_line
;
277 prop_line
.line_width
= STATE_LINE_WIDTH
;
278 prop_line
.style
= GDK_LINE_SOLID
;
279 prop_line
.y
= MIDDLE
;
280 //GdkColormap *colormap = gdk_colormap_get_system();
282 if(process
->state
->s
== LTTV_STATE_RUN
) {
283 if(process
->state
->t
== LTTV_STATE_USER_MODE
)
284 prop_line
.color
= drawing_colors
[COL_RUN_USER_MODE
];
285 else if(process
->state
->t
== LTTV_STATE_SYSCALL
)
286 prop_line
.color
= drawing_colors
[COL_RUN_SYSCALL
];
287 else if(process
->state
->t
== LTTV_STATE_TRAP
)
288 prop_line
.color
= drawing_colors
[COL_RUN_TRAP
];
289 else if(process
->state
->t
== LTTV_STATE_IRQ
)
290 prop_line
.color
= drawing_colors
[COL_RUN_IRQ
];
291 else if(process
->state
->t
== LTTV_STATE_SOFT_IRQ
)
292 prop_line
.color
= drawing_colors
[COL_RUN_SOFT_IRQ
];
293 else if(process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
)
294 prop_line
.color
= drawing_colors
[COL_MODE_UNKNOWN
];
296 g_assert(FALSE
); /* RUNNING MODE UNKNOWN */
297 } else if(process
->state
->s
== LTTV_STATE_WAIT
) {
298 /* We don't show if we wait while in user mode, trap, irq or syscall */
299 prop_line
.color
= drawing_colors
[COL_WAIT
];
300 } else if(process
->state
->s
== LTTV_STATE_WAIT_CPU
) {
301 /* We don't show if we wait for CPU while in user mode, trap, irq
303 prop_line
.color
= drawing_colors
[COL_WAIT_CPU
];
304 } else if(process
->state
->s
== LTTV_STATE_ZOMBIE
) {
305 prop_line
.color
= drawing_colors
[COL_ZOMBIE
];
306 } else if(process
->state
->s
== LTTV_STATE_WAIT_FORK
) {
307 prop_line
.color
= drawing_colors
[COL_WAIT_FORK
];
308 } else if(process
->state
->s
== LTTV_STATE_EXIT
) {
309 prop_line
.color
= drawing_colors
[COL_EXIT
];
310 } else if(process
->state
->s
== LTTV_STATE_UNNAMED
) {
311 prop_line
.color
= drawing_colors
[COL_UNNAMED
];
313 g_critical("unknown state : %s", g_quark_to_string(process
->state
->s
));
314 g_assert(FALSE
); /* UNKNOWN STATE */
322 /* before_schedchange_hook
324 * This function basically draw lines and icons. Two types of lines are drawn :
325 * one small (3 pixels?) representing the state of the process and the second
326 * type is thicker (10 pixels?) representing on which CPU a process is running
327 * (and this only in running state).
329 * Extremums of the lines :
330 * x_min : time of the last event context for this process kept in memory.
331 * x_max : time of the current event.
332 * y : middle of the process in the process list. The process is found in the
333 * list, therefore is it's position in pixels.
335 * The choice of lines'color is defined by the context of the last event for this
340 int before_schedchange_hook(void *hook_data
, void *call_data
)
342 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
343 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
344 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
346 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
348 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
349 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
352 e
= ltt_tracefile_get_event(tfc
->tf
);
353 gint target_pid_saved
= tfc
->target_pid
;
355 LttTime evtime
= ltt_event_time(e
);
356 LttvFilter
*filter
= control_flow_data
->filter
;
358 /* we are in a schedchange, before the state update. We must draw the
359 * items corresponding to the state before it changes : now is the right
366 pid_out
= ltt_event_get_long_unsigned(e
, thf
->f1
);
367 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f2
);
370 tfc
->target_pid
= pid_out
;
371 if(!filter
|| !filter
->head
||
372 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
373 tfc
->t_context
->t
,tfc
)) {
374 /* For the pid_out */
375 /* First, check if the current process is in the state computation
376 * process list. If it is there, that means we must add it right now and
377 * draw items from the beginning of the read for it. If it is not
378 * present, it's a new process and it was not present : it will
379 * be added after the state update. */
380 guint cpu
= tfs
->cpu
;
381 guint trace_num
= ts
->parent
.index
;
382 LttvProcessState
*process
= ts
->running_process
[cpu
];
383 /* unknown state, bad current pid */
384 if(process
->pid
!= pid_out
)
385 process
= lttv_state_find_process(ts
,
388 if(process
!= NULL
) {
389 /* Well, the process_out existed : we must get it in the process hash
390 * or add it, and draw its items.
392 /* Add process to process list (if not present) */
394 HashedProcessData
*hashed_process_data
= NULL
;
395 ProcessList
*process_list
= control_flow_data
->process_list
;
396 LttTime birth
= process
->creation_time
;
398 hashed_process_data
= processlist_get_process_data(process_list
,
403 if(hashed_process_data
== NULL
)
405 g_assert(pid_out
== 0 || pid_out
!= process
->ppid
);
406 /* Process not present */
407 ProcessInfo
*process_info
;
408 Drawing_t
*drawing
= control_flow_data
->drawing
;
409 processlist_add(process_list
,
421 &hashed_process_data
);
422 gtk_widget_set_size_request(drawing
->drawing_area
,
425 gtk_widget_queue_draw(drawing
->drawing_area
);
429 /* Now, the process is in the state hash and our own process hash.
430 * We definitely can draw the items related to the ending state.
433 if(ltt_time_compare(hashed_process_data
->next_good_time
,
436 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
438 TimeWindow time_window
=
439 lttvwindow_get_time_window(control_flow_data
->tab
);
441 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
442 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
445 Drawing_t
*drawing
= control_flow_data
->drawing
;
446 guint width
= drawing
->width
;
448 convert_time_to_pixels(
454 /* Draw collision indicator */
455 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
456 gdk_draw_point(hashed_process_data
->pixmap
,
459 COLLISION_POSITION(hashed_process_data
->height
));
460 hashed_process_data
->x
.middle_marked
= TRUE
;
463 TimeWindow time_window
=
464 lttvwindow_get_time_window(control_flow_data
->tab
);
466 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
467 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
470 Drawing_t
*drawing
= control_flow_data
->drawing
;
471 guint width
= drawing
->width
;
473 convert_time_to_pixels(
480 /* Jump over draw if we are at the same x position */
481 if(x
== hashed_process_data
->x
.middle
&&
482 hashed_process_data
->x
.middle_used
)
484 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
485 /* Draw collision indicator */
486 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
487 gdk_draw_point(hashed_process_data
->pixmap
,
490 COLLISION_POSITION(hashed_process_data
->height
));
491 hashed_process_data
->x
.middle_marked
= TRUE
;
495 DrawContext draw_context
;
497 /* Now create the drawing context that will be used to draw
498 * items related to the last state. */
499 draw_context
.drawable
= hashed_process_data
->pixmap
;
500 draw_context
.gc
= drawing
->gc
;
501 draw_context
.pango_layout
= drawing
->pango_layout
;
502 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
503 draw_context
.drawinfo
.end
.x
= x
;
505 draw_context
.drawinfo
.y
.over
= 1;
506 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
507 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
509 draw_context
.drawinfo
.start
.offset
.over
= 0;
510 draw_context
.drawinfo
.start
.offset
.middle
= 0;
511 draw_context
.drawinfo
.start
.offset
.under
= 0;
512 draw_context
.drawinfo
.end
.offset
.over
= 0;
513 draw_context
.drawinfo
.end
.offset
.middle
= 0;
514 draw_context
.drawinfo
.end
.offset
.under
= 0;
518 PropertiesLine prop_line
= prepare_s_e_line(process
);
519 draw_line((void*)&prop_line
, (void*)&draw_context
);
522 /* become the last x position */
523 hashed_process_data
->x
.middle
= x
;
524 hashed_process_data
->x
.middle_used
= TRUE
;
525 hashed_process_data
->x
.middle_marked
= FALSE
;
527 /* Calculate the next good time */
528 convert_pixels_to_time(width
, x
+1, time_window
,
529 &hashed_process_data
->next_good_time
);
535 tfc
->target_pid
= pid_in
;
536 if(!filter
|| !filter
->head
||
537 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
538 tfc
->t_context
->t
,tfc
)) {
540 /* First, check if the current process is in the state computation
541 * process list. If it is there, that means we must add it right now and
542 * draw items from the beginning of the read for it. If it is not
543 * present, it's a new process and it was not present : it will
544 * be added after the state update. */
545 LttvProcessState
*process
;
546 process
= lttv_state_find_process(ts
,
548 guint trace_num
= ts
->parent
.index
;
550 if(process
!= NULL
) {
551 /* Well, the process existed : we must get it in the process hash
552 * or add it, and draw its items.
554 /* Add process to process list (if not present) */
556 HashedProcessData
*hashed_process_data
= NULL
;
557 ProcessList
*process_list
= control_flow_data
->process_list
;
558 LttTime birth
= process
->creation_time
;
560 hashed_process_data
= processlist_get_process_data(process_list
,
565 if(hashed_process_data
== NULL
)
567 g_assert(pid_in
== 0 || pid_in
!= process
->ppid
);
568 /* Process not present */
569 ProcessInfo
*process_info
;
570 Drawing_t
*drawing
= control_flow_data
->drawing
;
571 processlist_add(process_list
,
583 &hashed_process_data
);
584 gtk_widget_set_size_request(drawing
->drawing_area
,
587 gtk_widget_queue_draw(drawing
->drawing_area
);
590 //We could set the current process and hash here, but will be done
591 //by after schedchange hook
593 /* Now, the process is in the state hash and our own process hash.
594 * We definitely can draw the items related to the ending state.
597 if(ltt_time_compare(hashed_process_data
->next_good_time
,
600 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
602 TimeWindow time_window
=
603 lttvwindow_get_time_window(control_flow_data
->tab
);
605 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
606 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
609 Drawing_t
*drawing
= control_flow_data
->drawing
;
610 guint width
= drawing
->width
;
612 convert_time_to_pixels(
618 /* Draw collision indicator */
619 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
620 gdk_draw_point(hashed_process_data
->pixmap
,
623 COLLISION_POSITION(hashed_process_data
->height
));
624 hashed_process_data
->x
.middle_marked
= TRUE
;
627 TimeWindow time_window
=
628 lttvwindow_get_time_window(control_flow_data
->tab
);
630 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
631 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
634 Drawing_t
*drawing
= control_flow_data
->drawing
;
635 guint width
= drawing
->width
;
638 convert_time_to_pixels(
645 /* Jump over draw if we are at the same x position */
646 if(x
== hashed_process_data
->x
.middle
&&
647 hashed_process_data
->x
.middle_used
)
649 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
650 /* Draw collision indicator */
651 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
652 gdk_draw_point(hashed_process_data
->pixmap
,
655 COLLISION_POSITION(hashed_process_data
->height
));
656 hashed_process_data
->x
.middle_marked
= TRUE
;
660 DrawContext draw_context
;
662 /* Now create the drawing context that will be used to draw
663 * items related to the last state. */
664 draw_context
.drawable
= hashed_process_data
->pixmap
;
665 draw_context
.gc
= drawing
->gc
;
666 draw_context
.pango_layout
= drawing
->pango_layout
;
667 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
668 draw_context
.drawinfo
.end
.x
= x
;
670 draw_context
.drawinfo
.y
.over
= 1;
671 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
672 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
674 draw_context
.drawinfo
.start
.offset
.over
= 0;
675 draw_context
.drawinfo
.start
.offset
.middle
= 0;
676 draw_context
.drawinfo
.start
.offset
.under
= 0;
677 draw_context
.drawinfo
.end
.offset
.over
= 0;
678 draw_context
.drawinfo
.end
.offset
.middle
= 0;
679 draw_context
.drawinfo
.end
.offset
.under
= 0;
683 PropertiesLine prop_line
= prepare_s_e_line(process
);
684 draw_line((void*)&prop_line
, (void*)&draw_context
);
688 /* become the last x position */
689 hashed_process_data
->x
.middle
= x
;
690 hashed_process_data
->x
.middle_used
= TRUE
;
691 hashed_process_data
->x
.middle_marked
= FALSE
;
693 /* Calculate the next good time */
694 convert_pixels_to_time(width
, x
+1, time_window
,
695 &hashed_process_data
->next_good_time
);
699 g_warning("Cannot find pin_in in schedchange %u", pid_in
);
701 tfc
->target_pid
= target_pid_saved
;
709 GString
*string
= g_string_new("");;
710 gboolean field_names
= TRUE
, state
= TRUE
;
712 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
713 g_string_append_printf(string
,"\n");
716 g_string_append_printf(string
, " %s",
717 g_quark_to_string(tfs
->process
->state
->s
));
720 g_info("%s",string
->str
);
722 g_string_free(string
, TRUE
);
724 /* End of text dump */
729 /* after_schedchange_hook
731 * The draw after hook is called by the reading API to have a
732 * particular event drawn on the screen.
733 * @param hook_data ControlFlowData structure of the viewer.
734 * @param call_data Event context.
736 * This function adds items to be drawn in a queue for each process.
739 int after_schedchange_hook(void *hook_data
, void *call_data
)
741 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
742 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
743 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
745 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
747 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
749 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
752 e
= ltt_tracefile_get_event(tfc
->tf
);
754 LttvFilter
*filter
= control_flow_data
->filter
;
755 if(filter
!= NULL
&& filter
->head
!= NULL
)
756 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
757 tfc
->t_context
->t
,tfc
))
760 LttTime evtime
= ltt_event_time(e
);
762 /* Add process to process list (if not present) */
763 LttvProcessState
*process_in
;
766 HashedProcessData
*hashed_process_data_in
= NULL
;
768 ProcessList
*process_list
= control_flow_data
->process_list
;
773 pid_out
= ltt_event_get_long_unsigned(e
, thf
->f1
);
774 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f2
);
778 /* Find process pid_in in the list... */
779 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
780 //process_in = tfs->process;
781 guint cpu
= tfs
->cpu
;
782 guint trace_num
= ts
->parent
.index
;
783 process_in
= ts
->running_process
[cpu
];
784 /* It should exist, because we are after the state update. */
786 g_assert(process_in
!= NULL
);
788 birth
= process_in
->creation_time
;
790 hashed_process_data_in
= processlist_get_process_data(process_list
,
795 if(hashed_process_data_in
== NULL
)
797 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
798 ProcessInfo
*process_info
;
799 Drawing_t
*drawing
= control_flow_data
->drawing
;
800 /* Process not present */
801 processlist_add(process_list
,
813 &hashed_process_data_in
);
814 gtk_widget_set_size_request(drawing
->drawing_area
,
817 gtk_widget_queue_draw(drawing
->drawing_area
);
819 /* Set the current process */
820 process_list
->current_hash_data
[trace_num
][process_in
->cpu
] =
821 hashed_process_data_in
;
823 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
826 TimeWindow time_window
=
827 lttvwindow_get_time_window(control_flow_data
->tab
);
830 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
831 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
834 Drawing_t
*drawing
= control_flow_data
->drawing
;
835 guint width
= drawing
->width
;
838 convert_time_to_pixels(
844 if(hashed_process_data_in
->x
.middle
!= new_x
) {
845 hashed_process_data_in
->x
.middle
= new_x
;
846 hashed_process_data_in
->x
.middle_used
= FALSE
;
847 hashed_process_data_in
->x
.middle_marked
= FALSE
;
856 /* before_execmode_hook
858 * This function basically draw lines and icons. Two types of lines are drawn :
859 * one small (3 pixels?) representing the state of the process and the second
860 * type is thicker (10 pixels?) representing on which CPU a process is running
861 * (and this only in running state).
863 * Extremums of the lines :
864 * x_min : time of the last event context for this process kept in memory.
865 * x_max : time of the current event.
866 * y : middle of the process in the process list. The process is found in the
867 * list, therefore is it's position in pixels.
869 * The choice of lines'color is defined by the context of the last event for this
874 int before_execmode_hook(void *hook_data
, void *call_data
)
876 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
877 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
878 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
880 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
882 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
884 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
887 e
= ltt_tracefile_get_event(tfc
->tf
);
889 LttvFilter
*filter
= control_flow_data
->filter
;
890 if(filter
!= NULL
&& filter
->head
!= NULL
)
891 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
892 tfc
->t_context
->t
,tfc
))
895 LttTime evtime
= ltt_event_time(e
);
897 /* we are in a execmode, before the state update. We must draw the
898 * items corresponding to the state before it changes : now is the right
902 //LttvProcessState *process = tfs->process;
903 guint cpu
= tfs
->cpu
;
904 guint trace_num
= ts
->parent
.index
;
905 LttvProcessState
*process
= ts
->running_process
[cpu
];
906 g_assert(process
!= NULL
);
908 guint pid
= process
->pid
;
910 /* Well, the process_out existed : we must get it in the process hash
911 * or add it, and draw its items.
913 /* Add process to process list (if not present) */
915 HashedProcessData
*hashed_process_data
= NULL
;
916 ProcessList
*process_list
= control_flow_data
->process_list
;
917 LttTime birth
= process
->creation_time
;
919 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
920 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
922 hashed_process_data
= processlist_get_process_data(process_list
,
927 if(unlikely(hashed_process_data
== NULL
))
929 g_assert(pid
== 0 || pid
!= process
->ppid
);
930 ProcessInfo
*process_info
;
931 /* Process not present */
932 Drawing_t
*drawing
= control_flow_data
->drawing
;
933 processlist_add(process_list
,
945 &hashed_process_data
);
946 gtk_widget_set_size_request(drawing
->drawing_area
,
949 gtk_widget_queue_draw(drawing
->drawing_area
);
951 /* Set the current process */
952 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
956 /* Now, the process is in the state hash and our own process hash.
957 * We definitely can draw the items related to the ending state.
960 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
963 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
964 TimeWindow time_window
=
965 lttvwindow_get_time_window(control_flow_data
->tab
);
968 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
969 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
972 Drawing_t
*drawing
= control_flow_data
->drawing
;
973 guint width
= drawing
->width
;
975 convert_time_to_pixels(
981 /* Draw collision indicator */
982 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
983 gdk_draw_point(hashed_process_data
->pixmap
,
986 COLLISION_POSITION(hashed_process_data
->height
));
987 hashed_process_data
->x
.middle_marked
= TRUE
;
990 TimeWindow time_window
=
991 lttvwindow_get_time_window(control_flow_data
->tab
);
994 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
995 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
998 Drawing_t
*drawing
= control_flow_data
->drawing
;
999 guint width
= drawing
->width
;
1002 convert_time_to_pixels(
1009 /* Jump over draw if we are at the same x position */
1010 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1011 hashed_process_data
->x
.middle_used
))
1013 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1014 /* Draw collision indicator */
1015 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1016 gdk_draw_point(hashed_process_data
->pixmap
,
1019 COLLISION_POSITION(hashed_process_data
->height
));
1020 hashed_process_data
->x
.middle_marked
= TRUE
;
1025 DrawContext draw_context
;
1026 /* Now create the drawing context that will be used to draw
1027 * items related to the last state. */
1028 draw_context
.drawable
= hashed_process_data
->pixmap
;
1029 draw_context
.gc
= drawing
->gc
;
1030 draw_context
.pango_layout
= drawing
->pango_layout
;
1031 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1032 draw_context
.drawinfo
.end
.x
= x
;
1034 draw_context
.drawinfo
.y
.over
= 1;
1035 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1036 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1038 draw_context
.drawinfo
.start
.offset
.over
= 0;
1039 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1040 draw_context
.drawinfo
.start
.offset
.under
= 0;
1041 draw_context
.drawinfo
.end
.offset
.over
= 0;
1042 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1043 draw_context
.drawinfo
.end
.offset
.under
= 0;
1047 PropertiesLine prop_line
= prepare_s_e_line(process
);
1048 draw_line((void*)&prop_line
, (void*)&draw_context
);
1051 /* become the last x position */
1052 hashed_process_data
->x
.middle
= x
;
1053 hashed_process_data
->x
.middle_used
= TRUE
;
1054 hashed_process_data
->x
.middle_marked
= FALSE
;
1056 /* Calculate the next good time */
1057 convert_pixels_to_time(width
, x
+1, time_window
,
1058 &hashed_process_data
->next_good_time
);
1065 /* before_process_exit_hook
1067 * Draw lines for process event.
1069 * @param hook_data ControlFlowData structure of the viewer.
1070 * @param call_data Event context.
1072 * This function adds items to be drawn in a queue for each process.
1077 int before_process_exit_hook(void *hook_data
, void *call_data
)
1079 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1080 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1082 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1084 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1086 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1088 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1091 e
= ltt_tracefile_get_event(tfc
->tf
);
1093 LttvFilter
*filter
= control_flow_data
->filter
;
1094 if(filter
!= NULL
&& filter
->head
!= NULL
)
1095 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1096 tfc
->t_context
->t
,tfc
))
1099 LttTime evtime
= ltt_event_time(e
);
1101 /* Add process to process list (if not present) */
1102 //LttvProcessState *process = tfs->process;
1103 guint cpu
= tfs
->cpu
;
1104 guint trace_num
= ts
->parent
.index
;
1105 LttvProcessState
*process
= ts
->running_process
[cpu
];
1106 guint pid
= process
->pid
;
1108 guint pl_height
= 0;
1109 HashedProcessData
*hashed_process_data
= NULL
;
1111 ProcessList
*process_list
= control_flow_data
->process_list
;
1113 g_assert(process
!= NULL
);
1115 birth
= process
->creation_time
;
1117 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1118 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1120 hashed_process_data
= processlist_get_process_data(process_list
,
1125 if(unlikely(hashed_process_data
== NULL
))
1127 g_assert(pid
== 0 || pid
!= process
->ppid
);
1128 /* Process not present */
1129 Drawing_t
*drawing
= control_flow_data
->drawing
;
1130 ProcessInfo
*process_info
;
1131 processlist_add(process_list
,
1143 &hashed_process_data
);
1144 gtk_widget_set_size_request(drawing
->drawing_area
,
1147 gtk_widget_queue_draw(drawing
->drawing_area
);
1151 /* Now, the process is in the state hash and our own process hash.
1152 * We definitely can draw the items related to the ending state.
1155 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1158 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1159 TimeWindow time_window
=
1160 lttvwindow_get_time_window(control_flow_data
->tab
);
1163 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1164 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1166 #endif //EXTRA_CHECK
1167 Drawing_t
*drawing
= control_flow_data
->drawing
;
1168 guint width
= drawing
->width
;
1170 convert_time_to_pixels(
1176 /* Draw collision indicator */
1177 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1178 gdk_draw_point(hashed_process_data
->pixmap
,
1181 COLLISION_POSITION(hashed_process_data
->height
));
1182 hashed_process_data
->x
.middle_marked
= TRUE
;
1185 TimeWindow time_window
=
1186 lttvwindow_get_time_window(control_flow_data
->tab
);
1189 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1190 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1192 #endif //EXTRA_CHECK
1193 Drawing_t
*drawing
= control_flow_data
->drawing
;
1194 guint width
= drawing
->width
;
1197 convert_time_to_pixels(
1204 /* Jump over draw if we are at the same x position */
1205 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1206 hashed_process_data
->x
.middle_used
))
1208 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1209 /* Draw collision indicator */
1210 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1211 gdk_draw_point(hashed_process_data
->pixmap
,
1214 COLLISION_POSITION(hashed_process_data
->height
));
1215 hashed_process_data
->x
.middle_marked
= TRUE
;
1219 DrawContext draw_context
;
1221 /* Now create the drawing context that will be used to draw
1222 * items related to the last state. */
1223 draw_context
.drawable
= hashed_process_data
->pixmap
;
1224 draw_context
.gc
= drawing
->gc
;
1225 draw_context
.pango_layout
= drawing
->pango_layout
;
1226 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1227 draw_context
.drawinfo
.end
.x
= x
;
1229 draw_context
.drawinfo
.y
.over
= 1;
1230 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1231 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1233 draw_context
.drawinfo
.start
.offset
.over
= 0;
1234 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1235 draw_context
.drawinfo
.start
.offset
.under
= 0;
1236 draw_context
.drawinfo
.end
.offset
.over
= 0;
1237 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1238 draw_context
.drawinfo
.end
.offset
.under
= 0;
1242 PropertiesLine prop_line
= prepare_s_e_line(process
);
1243 draw_line((void*)&prop_line
, (void*)&draw_context
);
1246 /* become the last x position */
1247 hashed_process_data
->x
.middle
= x
;
1248 hashed_process_data
->x
.middle_used
= TRUE
;
1249 hashed_process_data
->x
.middle_marked
= FALSE
;
1251 /* Calculate the next good time */
1252 convert_pixels_to_time(width
, x
+1, time_window
,
1253 &hashed_process_data
->next_good_time
);
1263 /* before_process_release_hook
1265 * Draw lines for process event.
1267 * @param hook_data ControlFlowData structure of the viewer.
1268 * @param call_data Event context.
1270 * This function adds items to be drawn in a queue for each process.
1275 int before_process_release_hook(void *hook_data
, void *call_data
)
1277 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1278 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1280 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1282 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1284 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1286 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1289 e
= ltt_tracefile_get_event(tfc
->tf
);
1291 LttvFilter
*filter
= control_flow_data
->filter
;
1292 if(filter
!= NULL
&& filter
->head
!= NULL
)
1293 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1294 tfc
->t_context
->t
,tfc
))
1297 LttTime evtime
= ltt_event_time(e
);
1299 guint trace_num
= ts
->parent
.index
;
1303 pid
= ltt_event_get_long_unsigned(e
, thf
->f1
);
1306 /* Add process to process list (if not present) */
1307 /* Don't care about the process if it's not in the state hash already :
1308 * that means a process that has never done anything in the trace and
1309 * unknown suddently gets destroyed : no state meaningful to show. */
1310 LttvProcessState
*process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1312 if(process
!= NULL
) {
1314 guint pl_height
= 0;
1315 HashedProcessData
*hashed_process_data
= NULL
;
1317 ProcessList
*process_list
= control_flow_data
->process_list
;
1319 birth
= process
->creation_time
;
1321 /* Cannot use current process : this event happens on another process,
1322 * action done by the parent. */
1323 hashed_process_data
= processlist_get_process_data(process_list
,
1328 if(unlikely(hashed_process_data
== NULL
))
1330 g_assert(pid
== 0 || pid
!= process
->ppid
);
1331 /* Process not present */
1332 Drawing_t
*drawing
= control_flow_data
->drawing
;
1333 ProcessInfo
*process_info
;
1334 processlist_add(process_list
,
1346 &hashed_process_data
);
1347 gtk_widget_set_size_request(drawing
->drawing_area
,
1350 gtk_widget_queue_draw(drawing
->drawing_area
);
1353 /* Now, the process is in the state hash and our own process hash.
1354 * We definitely can draw the items related to the ending state.
1357 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1360 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1361 TimeWindow time_window
=
1362 lttvwindow_get_time_window(control_flow_data
->tab
);
1365 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1366 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1368 #endif //EXTRA_CHECK
1369 Drawing_t
*drawing
= control_flow_data
->drawing
;
1370 guint width
= drawing
->width
;
1372 convert_time_to_pixels(
1378 /* Draw collision indicator */
1379 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1380 gdk_draw_point(hashed_process_data
->pixmap
,
1383 COLLISION_POSITION(hashed_process_data
->height
));
1384 hashed_process_data
->x
.middle_marked
= TRUE
;
1387 TimeWindow time_window
=
1388 lttvwindow_get_time_window(control_flow_data
->tab
);
1391 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1392 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1394 #endif //EXTRA_CHECK
1395 Drawing_t
*drawing
= control_flow_data
->drawing
;
1396 guint width
= drawing
->width
;
1399 convert_time_to_pixels(
1406 /* Jump over draw if we are at the same x position */
1407 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1408 hashed_process_data
->x
.middle_used
))
1410 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1411 /* Draw collision indicator */
1412 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1413 gdk_draw_point(hashed_process_data
->pixmap
,
1416 COLLISION_POSITION(hashed_process_data
->height
));
1417 hashed_process_data
->x
.middle_marked
= TRUE
;
1421 DrawContext draw_context
;
1423 /* Now create the drawing context that will be used to draw
1424 * items related to the last state. */
1425 draw_context
.drawable
= hashed_process_data
->pixmap
;
1426 draw_context
.gc
= drawing
->gc
;
1427 draw_context
.pango_layout
= drawing
->pango_layout
;
1428 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1429 draw_context
.drawinfo
.end
.x
= x
;
1431 draw_context
.drawinfo
.y
.over
= 1;
1432 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1433 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1435 draw_context
.drawinfo
.start
.offset
.over
= 0;
1436 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1437 draw_context
.drawinfo
.start
.offset
.under
= 0;
1438 draw_context
.drawinfo
.end
.offset
.over
= 0;
1439 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1440 draw_context
.drawinfo
.end
.offset
.under
= 0;
1444 PropertiesLine prop_line
= prepare_s_e_line(process
);
1445 draw_line((void*)&prop_line
, (void*)&draw_context
);
1448 /* become the last x position */
1449 hashed_process_data
->x
.middle
= x
;
1450 hashed_process_data
->x
.middle_used
= TRUE
;
1451 hashed_process_data
->x
.middle_marked
= FALSE
;
1453 /* Calculate the next good time */
1454 convert_pixels_to_time(width
, x
+1, time_window
,
1455 &hashed_process_data
->next_good_time
);
1467 /* after_process_fork_hook
1469 * Create the processlist entry for the child process. Put the last
1470 * position in x at the current time value.
1472 * @param hook_data ControlFlowData structure of the viewer.
1473 * @param call_data Event context.
1475 * This function adds items to be drawn in a queue for each process.
1478 int after_process_fork_hook(void *hook_data
, void *call_data
)
1480 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1481 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1482 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1484 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1486 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1488 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1491 e
= ltt_tracefile_get_event(tfc
->tf
);
1493 LttvFilter
*filter
= control_flow_data
->filter
;
1494 if(filter
!= NULL
&& filter
->head
!= NULL
)
1495 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1496 tfc
->t_context
->t
,tfc
))
1499 LttTime evtime
= ltt_event_time(e
);
1503 child_pid
= ltt_event_get_long_unsigned(e
, thf
->f2
);
1506 /* Add process to process list (if not present) */
1507 LttvProcessState
*process_child
;
1509 guint pl_height
= 0;
1510 HashedProcessData
*hashed_process_data_child
= NULL
;
1512 ProcessList
*process_list
= control_flow_data
->process_list
;
1514 /* Find child in the list... */
1515 process_child
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1516 /* It should exist, because we are after the state update. */
1517 g_assert(process_child
!= NULL
);
1519 birth
= process_child
->creation_time
;
1520 guint trace_num
= ts
->parent
.index
;
1522 /* Cannot use current process, because this action is done by the parent
1524 hashed_process_data_child
= processlist_get_process_data(process_list
,
1529 if(likely(hashed_process_data_child
== NULL
))
1531 g_assert(child_pid
== 0 || child_pid
!= process_child
->ppid
);
1532 /* Process not present */
1533 Drawing_t
*drawing
= control_flow_data
->drawing
;
1534 ProcessInfo
*process_info
;
1535 processlist_add(process_list
,
1538 process_child
->tgid
,
1540 process_child
->ppid
,
1543 process_child
->name
,
1544 process_child
->brand
,
1547 &hashed_process_data_child
);
1548 gtk_widget_set_size_request(drawing
->drawing_area
,
1551 gtk_widget_queue_draw(drawing
->drawing_area
);
1553 processlist_set_ppid(process_list
, process_child
->ppid
,
1554 hashed_process_data_child
);
1555 processlist_set_tgid(process_list
, process_child
->tgid
,
1556 hashed_process_data_child
);
1560 if(likely(ltt_time_compare(hashed_process_data_child
->next_good_time
,
1563 TimeWindow time_window
=
1564 lttvwindow_get_time_window(control_flow_data
->tab
);
1567 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1568 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1570 #endif //EXTRA_CHECK
1571 Drawing_t
*drawing
= control_flow_data
->drawing
;
1572 guint width
= drawing
->width
;
1574 convert_time_to_pixels(
1580 if(likely(hashed_process_data_child
->x
.over
!= new_x
)) {
1581 hashed_process_data_child
->x
.over
= new_x
;
1582 hashed_process_data_child
->x
.over_used
= FALSE
;
1583 hashed_process_data_child
->x
.over_marked
= FALSE
;
1585 if(likely(hashed_process_data_child
->x
.middle
!= new_x
)) {
1586 hashed_process_data_child
->x
.middle
= new_x
;
1587 hashed_process_data_child
->x
.middle_used
= FALSE
;
1588 hashed_process_data_child
->x
.middle_marked
= FALSE
;
1590 if(likely(hashed_process_data_child
->x
.under
!= new_x
)) {
1591 hashed_process_data_child
->x
.under
= new_x
;
1592 hashed_process_data_child
->x
.under_used
= FALSE
;
1593 hashed_process_data_child
->x
.under_marked
= FALSE
;
1601 /* after_process_exit_hook
1603 * Create the processlist entry for the child process. Put the last
1604 * position in x at the current time value.
1606 * @param hook_data ControlFlowData structure of the viewer.
1607 * @param call_data Event context.
1609 * This function adds items to be drawn in a queue for each process.
1612 int after_process_exit_hook(void *hook_data
, void *call_data
)
1614 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1615 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1616 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1618 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1620 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1622 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1625 e
= ltt_tracefile_get_event(tfc
->tf
);
1627 LttvFilter
*filter
= control_flow_data
->filter
;
1628 if(filter
!= NULL
&& filter
->head
!= NULL
)
1629 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1630 tfc
->t_context
->t
,tfc
))
1633 LttTime evtime
= ltt_event_time(e
);
1635 /* Add process to process list (if not present) */
1636 //LttvProcessState *process = tfs->process;
1637 guint cpu
= tfs
->cpu
;
1638 guint trace_num
= ts
->parent
.index
;
1639 LttvProcessState
*process
= ts
->running_process
[cpu
];
1641 /* It should exist, because we are after the state update. */
1642 g_assert(process
!= NULL
);
1644 guint pid
= process
->pid
;
1646 guint pl_height
= 0;
1647 HashedProcessData
*hashed_process_data
= NULL
;
1649 ProcessList
*process_list
= control_flow_data
->process_list
;
1651 birth
= process
->creation_time
;
1653 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
) ){
1654 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1656 hashed_process_data
= processlist_get_process_data(process_list
,
1661 if(unlikely(hashed_process_data
== NULL
))
1663 g_assert(pid
== 0 || pid
!= process
->ppid
);
1664 /* Process not present */
1665 Drawing_t
*drawing
= control_flow_data
->drawing
;
1666 ProcessInfo
*process_info
;
1667 processlist_add(process_list
,
1679 &hashed_process_data
);
1680 gtk_widget_set_size_request(drawing
->drawing_area
,
1683 gtk_widget_queue_draw(drawing
->drawing_area
);
1686 /* Set the current process */
1687 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1688 hashed_process_data
;
1691 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
1694 TimeWindow time_window
=
1695 lttvwindow_get_time_window(control_flow_data
->tab
);
1698 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1699 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1701 #endif //EXTRA_CHECK
1702 Drawing_t
*drawing
= control_flow_data
->drawing
;
1703 guint width
= drawing
->width
;
1705 convert_time_to_pixels(
1710 if(unlikely(hashed_process_data
->x
.middle
!= new_x
)) {
1711 hashed_process_data
->x
.middle
= new_x
;
1712 hashed_process_data
->x
.middle_used
= FALSE
;
1713 hashed_process_data
->x
.middle_marked
= FALSE
;
1721 /* Get the filename of the process to print */
1722 int after_fs_exec_hook(void *hook_data
, void *call_data
)
1724 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1725 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1726 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1728 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1730 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1732 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1735 e
= ltt_tracefile_get_event(tfc
->tf
);
1737 LttvFilter
*filter
= control_flow_data
->filter
;
1738 if(filter
!= NULL
&& filter
->head
!= NULL
)
1739 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1740 tfc
->t_context
->t
,tfc
))
1743 guint cpu
= tfs
->cpu
;
1744 guint trace_num
= ts
->parent
.index
;
1745 LttvProcessState
*process
= ts
->running_process
[cpu
];
1746 g_assert(process
!= NULL
);
1748 guint pid
= process
->pid
;
1750 /* Well, the process_out existed : we must get it in the process hash
1751 * or add it, and draw its items.
1753 /* Add process to process list (if not present) */
1754 guint pl_height
= 0;
1755 HashedProcessData
*hashed_process_data
= NULL
;
1756 ProcessList
*process_list
= control_flow_data
->process_list
;
1757 LttTime birth
= process
->creation_time
;
1759 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1760 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1762 hashed_process_data
= processlist_get_process_data(process_list
,
1767 if(unlikely(hashed_process_data
== NULL
))
1769 g_assert(pid
== 0 || pid
!= process
->ppid
);
1770 ProcessInfo
*process_info
;
1771 /* Process not present */
1772 Drawing_t
*drawing
= control_flow_data
->drawing
;
1773 processlist_add(process_list
,
1785 &hashed_process_data
);
1786 gtk_widget_set_size_request(drawing
->drawing_area
,
1789 gtk_widget_queue_draw(drawing
->drawing_area
);
1791 /* Set the current process */
1792 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1793 hashed_process_data
;
1796 processlist_set_name(process_list
, process
->name
, hashed_process_data
);
1802 /* Get the filename of the process to print */
1803 int after_user_generic_thread_brand_hook(void *hook_data
, void *call_data
)
1805 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1806 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1807 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1809 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1811 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1813 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1816 e
= ltt_tracefile_get_event(tfc
->tf
);
1818 LttvFilter
*filter
= control_flow_data
->filter
;
1819 if(filter
!= NULL
&& filter
->head
!= NULL
)
1820 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1821 tfc
->t_context
->t
,tfc
))
1824 guint cpu
= tfs
->cpu
;
1825 guint trace_num
= ts
->parent
.index
;
1826 LttvProcessState
*process
= ts
->running_process
[cpu
];
1827 g_assert(process
!= NULL
);
1829 guint pid
= process
->pid
;
1831 /* Well, the process_out existed : we must get it in the process hash
1832 * or add it, and draw its items.
1834 /* Add process to process list (if not present) */
1835 guint pl_height
= 0;
1836 HashedProcessData
*hashed_process_data
= NULL
;
1837 ProcessList
*process_list
= control_flow_data
->process_list
;
1838 LttTime birth
= process
->creation_time
;
1840 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1841 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1843 hashed_process_data
= processlist_get_process_data(process_list
,
1848 if(unlikely(hashed_process_data
== NULL
))
1850 g_assert(pid
== 0 || pid
!= process
->ppid
);
1851 ProcessInfo
*process_info
;
1852 /* Process not present */
1853 Drawing_t
*drawing
= control_flow_data
->drawing
;
1854 processlist_add(process_list
,
1866 &hashed_process_data
);
1867 gtk_widget_set_size_request(drawing
->drawing_area
,
1870 gtk_widget_queue_draw(drawing
->drawing_area
);
1872 /* Set the current process */
1873 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1874 hashed_process_data
;
1877 processlist_set_brand(process_list
, process
->brand
, hashed_process_data
);
1884 /* after_event_enum_process_hook
1886 * Create the processlist entry for the child process. Put the last
1887 * position in x at the current time value.
1889 * @param hook_data ControlFlowData structure of the viewer.
1890 * @param call_data Event context.
1892 * This function adds items to be drawn in a queue for each process.
1895 int after_event_enum_process_hook(void *hook_data
, void *call_data
)
1897 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1898 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1899 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1901 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1903 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1905 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1908 e
= ltt_tracefile_get_event(tfc
->tf
);
1910 LttvFilter
*filter
= control_flow_data
->filter
;
1911 if(filter
!= NULL
&& filter
->head
!= NULL
)
1912 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1913 tfc
->t_context
->t
,tfc
))
1916 LttTime evtime
= ltt_event_time(e
);
1918 /* Add process to process list (if not present) */
1919 LttvProcessState
*process_in
;
1921 guint pl_height
= 0;
1922 HashedProcessData
*hashed_process_data_in
= NULL
;
1924 ProcessList
*process_list
= control_flow_data
->process_list
;
1925 guint trace_num
= ts
->parent
.index
;
1929 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f1
);
1933 /* Find process pid_in in the list... */
1934 process_in
= lttv_state_find_process(ts
, ANY_CPU
, pid_in
);
1935 //process_in = tfs->process;
1936 //guint cpu = tfs->cpu;
1937 //guint trace_num = ts->parent.index;
1938 //process_in = ts->running_process[cpu];
1939 /* It should exist, because we are after the state update. */
1941 //g_assert(process_in != NULL);
1942 #endif //EXTRA_CHECK
1943 birth
= process_in
->creation_time
;
1945 hashed_process_data_in
= processlist_get_process_data(process_list
,
1950 if(hashed_process_data_in
== NULL
)
1952 if(pid_in
!= 0 && pid_in
== process_in
->ppid
)
1953 g_critical("TEST %u , %u", pid_in
, process_in
->ppid
);
1954 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
1955 ProcessInfo
*process_info
;
1956 Drawing_t
*drawing
= control_flow_data
->drawing
;
1957 /* Process not present */
1958 processlist_add(process_list
,
1970 &hashed_process_data_in
);
1971 gtk_widget_set_size_request(drawing
->drawing_area
,
1974 gtk_widget_queue_draw(drawing
->drawing_area
);
1976 processlist_set_name(process_list
, process_in
->name
,
1977 hashed_process_data_in
);
1978 processlist_set_ppid(process_list
, process_in
->ppid
,
1979 hashed_process_data_in
);
1980 processlist_set_tgid(process_list
, process_in
->tgid
,
1981 hashed_process_data_in
);
1987 gint
update_time_window_hook(void *hook_data
, void *call_data
)
1989 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1990 Drawing_t
*drawing
= control_flow_data
->drawing
;
1991 ProcessList
*process_list
= control_flow_data
->process_list
;
1993 const TimeWindowNotifyData
*time_window_nofify_data
=
1994 ((const TimeWindowNotifyData
*)call_data
);
1996 TimeWindow
*old_time_window
=
1997 time_window_nofify_data
->old_time_window
;
1998 TimeWindow
*new_time_window
=
1999 time_window_nofify_data
->new_time_window
;
2001 /* Update the ruler */
2002 drawing_update_ruler(control_flow_data
->drawing
,
2006 /* Two cases : zoom in/out or scrolling */
2008 /* In order to make sure we can reuse the old drawing, the scale must
2009 * be the same and the new time interval being partly located in the
2010 * currently shown time interval. (reuse is only for scrolling)
2013 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
2014 old_time_window
->start_time
.tv_sec
,
2015 old_time_window
->start_time
.tv_nsec
,
2016 old_time_window
->time_width
.tv_sec
,
2017 old_time_window
->time_width
.tv_nsec
);
2019 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
2020 new_time_window
->start_time
.tv_sec
,
2021 new_time_window
->start_time
.tv_nsec
,
2022 new_time_window
->time_width
.tv_sec
,
2023 new_time_window
->time_width
.tv_nsec
);
2025 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
2026 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
2028 /* Same scale (scrolling) */
2029 g_info("scrolling");
2030 LttTime
*ns
= &new_time_window
->start_time
;
2031 LttTime
*nw
= &new_time_window
->time_width
;
2032 LttTime
*os
= &old_time_window
->start_time
;
2033 LttTime
*ow
= &old_time_window
->time_width
;
2034 LttTime old_end
= old_time_window
->end_time
;
2035 LttTime new_end
= new_time_window
->end_time
;
2037 //if(ns<os+w && os+w<ns+w)
2038 //if(ns<old_end && os<ns)
2039 if(ltt_time_compare(*ns
, old_end
) == -1
2040 && ltt_time_compare(*os
, *ns
) == -1)
2042 g_info("scrolling near right");
2043 /* Scroll right, keep right part of the screen */
2045 guint width
= control_flow_data
->drawing
->width
;
2046 convert_time_to_pixels(
2052 /* Copy old data to new location */
2053 copy_pixmap_region(process_list
,
2055 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2059 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
2061 if(drawing
->damage_begin
== drawing
->damage_end
)
2062 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
2064 drawing
->damage_begin
= 0;
2066 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2068 /* Clear the data request background, but not SAFETY */
2069 rectangle_pixmap(process_list
,
2070 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2072 drawing
->damage_begin
+SAFETY
, 0,
2073 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2075 gtk_widget_queue_draw(drawing
->drawing_area
);
2076 //gtk_widget_queue_draw_area (drawing->drawing_area,
2078 // control_flow_data->drawing->width,
2079 // control_flow_data->drawing->height);
2081 /* Get new data for the rest. */
2082 drawing_data_request(control_flow_data
->drawing
,
2083 drawing
->damage_begin
, 0,
2084 drawing
->damage_end
- drawing
->damage_begin
,
2085 control_flow_data
->drawing
->height
);
2088 //if(ns<os && os<ns+w)
2089 //if(ns<os && os<new_end)
2090 if(ltt_time_compare(*ns
,*os
) == -1
2091 && ltt_time_compare(*os
,new_end
) == -1)
2093 g_info("scrolling near left");
2094 /* Scroll left, keep left part of the screen */
2096 guint width
= control_flow_data
->drawing
->width
;
2097 convert_time_to_pixels(
2103 /* Copy old data to new location */
2104 copy_pixmap_region (process_list
,
2106 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2112 if(drawing
->damage_begin
== drawing
->damage_end
)
2113 drawing
->damage_end
= x
;
2115 drawing
->damage_end
=
2116 control_flow_data
->drawing
->width
;
2118 drawing
->damage_begin
= 0;
2120 rectangle_pixmap (process_list
,
2121 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2123 drawing
->damage_begin
, 0,
2124 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2127 gtk_widget_queue_draw(drawing
->drawing_area
);
2128 //gtk_widget_queue_draw_area (drawing->drawing_area,
2130 // control_flow_data->drawing->width,
2131 // control_flow_data->drawing->height);
2134 /* Get new data for the rest. */
2135 drawing_data_request(control_flow_data
->drawing
,
2136 drawing
->damage_begin
, 0,
2137 drawing
->damage_end
- drawing
->damage_begin
,
2138 control_flow_data
->drawing
->height
);
2141 if(ltt_time_compare(*ns
,*os
) == 0)
2143 g_info("not scrolling");
2145 g_info("scrolling far");
2146 /* Cannot reuse any part of the screen : far jump */
2149 rectangle_pixmap (process_list
,
2150 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2153 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2156 //gtk_widget_queue_draw_area (drawing->drawing_area,
2158 // control_flow_data->drawing->width,
2159 // control_flow_data->drawing->height);
2160 gtk_widget_queue_draw(drawing
->drawing_area
);
2162 drawing
->damage_begin
= 0;
2163 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2165 drawing_data_request(control_flow_data
->drawing
,
2167 control_flow_data
->drawing
->width
,
2168 control_flow_data
->drawing
->height
);
2174 /* Different scale (zoom) */
2177 rectangle_pixmap (process_list
,
2178 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2181 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2184 //gtk_widget_queue_draw_area (drawing->drawing_area,
2186 // control_flow_data->drawing->width,
2187 // control_flow_data->drawing->height);
2188 gtk_widget_queue_draw(drawing
->drawing_area
);
2190 drawing
->damage_begin
= 0;
2191 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2193 drawing_data_request(control_flow_data
->drawing
,
2195 control_flow_data
->drawing
->width
,
2196 control_flow_data
->drawing
->height
);
2199 /* Update directly when scrolling */
2200 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2206 gint
traceset_notify(void *hook_data
, void *call_data
)
2208 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2209 Drawing_t
*drawing
= control_flow_data
->drawing
;
2211 if(unlikely(drawing
->gc
== NULL
)) {
2214 if(drawing
->dotted_gc
== NULL
) {
2218 drawing_clear(control_flow_data
->drawing
);
2219 processlist_clear(control_flow_data
->process_list
);
2220 gtk_widget_set_size_request(
2221 control_flow_data
->drawing
->drawing_area
,
2222 -1, processlist_get_height(control_flow_data
->process_list
));
2223 redraw_notify(control_flow_data
, NULL
);
2225 request_background_data(control_flow_data
);
2230 gint
redraw_notify(void *hook_data
, void *call_data
)
2232 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2233 Drawing_t
*drawing
= control_flow_data
->drawing
;
2234 GtkWidget
*widget
= drawing
->drawing_area
;
2236 drawing
->damage_begin
= 0;
2237 drawing
->damage_end
= drawing
->width
;
2239 /* fun feature, to be separated someday... */
2240 drawing_clear(control_flow_data
->drawing
);
2241 processlist_clear(control_flow_data
->process_list
);
2242 gtk_widget_set_size_request(
2243 control_flow_data
->drawing
->drawing_area
,
2244 -1, processlist_get_height(control_flow_data
->process_list
));
2246 rectangle_pixmap (control_flow_data
->process_list
,
2247 widget
->style
->black_gc
,
2250 drawing
->alloc_width
,
2253 gtk_widget_queue_draw(drawing
->drawing_area
);
2255 if(drawing
->damage_begin
< drawing
->damage_end
)
2257 drawing_data_request(drawing
,
2258 drawing
->damage_begin
,
2260 drawing
->damage_end
-drawing
->damage_begin
,
2264 //gtk_widget_queue_draw_area(drawing->drawing_area,
2267 // drawing->height);
2273 gint
continue_notify(void *hook_data
, void *call_data
)
2275 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2276 Drawing_t
*drawing
= control_flow_data
->drawing
;
2278 //g_assert(widget->allocation.width == drawing->damage_end);
2280 if(drawing
->damage_begin
< drawing
->damage_end
)
2282 drawing_data_request(drawing
,
2283 drawing
->damage_begin
,
2285 drawing
->damage_end
-drawing
->damage_begin
,
2293 gint
update_current_time_hook(void *hook_data
, void *call_data
)
2295 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
2296 Drawing_t
*drawing
= control_flow_data
->drawing
;
2298 LttTime current_time
= *((LttTime
*)call_data
);
2300 TimeWindow time_window
=
2301 lttvwindow_get_time_window(control_flow_data
->tab
);
2303 LttTime time_begin
= time_window
.start_time
;
2304 LttTime width
= time_window
.time_width
;
2307 guint64 time_ll
= ltt_time_to_uint64(width
);
2308 time_ll
= time_ll
>> 1; /* divide by two */
2309 half_width
= ltt_time_from_uint64(time_ll
);
2311 LttTime time_end
= ltt_time_add(time_begin
, width
);
2313 LttvTracesetContext
* tsc
=
2314 lttvwindow_get_traceset_context(control_flow_data
->tab
);
2316 LttTime trace_start
= tsc
->time_span
.start_time
;
2317 LttTime trace_end
= tsc
->time_span
.end_time
;
2319 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
2320 current_time
.tv_nsec
);
2324 /* If current time is inside time interval, just move the highlight
2327 /* Else, we have to change the time interval. We have to tell it
2328 * to the main window. */
2329 /* The time interval change will take care of placing the current
2330 * time at the center of the visible area, or nearest possible if we are
2331 * at one end of the trace. */
2334 if(ltt_time_compare(current_time
, time_begin
) < 0)
2336 TimeWindow new_time_window
;
2338 if(ltt_time_compare(current_time
,
2339 ltt_time_add(trace_start
,half_width
)) < 0)
2340 time_begin
= trace_start
;
2342 time_begin
= ltt_time_sub(current_time
,half_width
);
2344 new_time_window
.start_time
= time_begin
;
2345 new_time_window
.time_width
= width
;
2346 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2347 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2349 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2351 else if(ltt_time_compare(current_time
, time_end
) > 0)
2353 TimeWindow new_time_window
;
2355 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
2356 time_begin
= ltt_time_sub(trace_end
,width
);
2358 time_begin
= ltt_time_sub(current_time
,half_width
);
2360 new_time_window
.start_time
= time_begin
;
2361 new_time_window
.time_width
= width
;
2362 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2363 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2365 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2368 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2370 /* Update directly when scrolling */
2371 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2377 typedef struct _ClosureData
{
2378 EventsRequest
*events_request
;
2379 LttvTracesetState
*tss
;
2385 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
2387 ProcessInfo
*process_info
= (ProcessInfo
*)key
;
2388 HashedProcessData
*hashed_process_data
= (HashedProcessData
*)value
;
2389 ClosureData
*closure_data
= (ClosureData
*)user_data
;
2391 EventsRequest
*events_request
= closure_data
->events_request
;
2392 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2394 LttvTracesetState
*tss
= closure_data
->tss
;
2395 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)tss
;
2397 LttTime evtime
= closure_data
->end_time
;
2400 /* For the process */
2401 /* First, check if the current process is in the state computation
2402 * process list. If it is there, that means we must add it right now and
2403 * draw items from the beginning of the read for it. If it is not
2404 * present, it's a new process and it was not present : it will
2405 * be added after the state update. */
2407 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
2408 #endif //EXTRA_CHECK
2409 LttvTraceContext
*tc
= tsc
->traces
[process_info
->trace_num
];
2410 LttvTraceState
*ts
= (LttvTraceState
*)tc
;
2413 //FIXME : optimize data structures.
2414 LttvTracefileState
*tfs
;
2415 LttvTracefileContext
*tfc
;
2417 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
2418 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
2419 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
2420 && tfs
->cpu
== process_info
->cpu
)
2424 g_assert(i
<tc
->tracefiles
->len
);
2425 tfs
= LTTV_TRACEFILE_STATE(tfc
);
2427 // LttvTracefileState *tfs =
2428 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2429 // tracefiles[process_info->cpu];
2431 LttvProcessState
*process
;
2432 process
= lttv_state_find_process(ts
, process_info
->cpu
,
2435 if(unlikely(process
!= NULL
)) {
2437 /* Only draw for processes that are currently in the trace states */
2439 ProcessList
*process_list
= control_flow_data
->process_list
;
2441 /* Should be alike when background info is ready */
2442 if(control_flow_data
->background_info_waiting
==0)
2443 g_assert(ltt_time_compare(process
->creation_time
,
2444 process_info
->birth
) == 0);
2445 #endif //EXTRA_CHECK
2447 /* Now, the process is in the state hash and our own process hash.
2448 * We definitely can draw the items related to the ending state.
2451 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2454 TimeWindow time_window
=
2455 lttvwindow_get_time_window(control_flow_data
->tab
);
2458 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2459 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2461 #endif //EXTRA_CHECK
2462 Drawing_t
*drawing
= control_flow_data
->drawing
;
2463 guint width
= drawing
->width
;
2465 guint x
= closure_data
->x_end
;
2467 DrawContext draw_context
;
2469 /* Now create the drawing context that will be used to draw
2470 * items related to the last state. */
2471 draw_context
.drawable
= hashed_process_data
->pixmap
;
2472 draw_context
.gc
= drawing
->gc
;
2473 draw_context
.pango_layout
= drawing
->pango_layout
;
2474 draw_context
.drawinfo
.end
.x
= x
;
2476 draw_context
.drawinfo
.y
.over
= 1;
2477 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2478 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2480 draw_context
.drawinfo
.start
.offset
.over
= 0;
2481 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2482 draw_context
.drawinfo
.start
.offset
.under
= 0;
2483 draw_context
.drawinfo
.end
.offset
.over
= 0;
2484 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2485 draw_context
.drawinfo
.end
.offset
.under
= 0;
2487 /* Jump over draw if we are at the same x position */
2488 if(x
== hashed_process_data
->x
.over
)
2492 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2494 PropertiesLine prop_line
= prepare_execmode_line(process
);
2495 draw_line((void*)&prop_line
, (void*)&draw_context
);
2497 hashed_process_data
->x
.over
= x
;
2501 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2502 hashed_process_data
->x
.middle_used
)) {
2503 #if 0 /* do not mark closure : not missing information */
2504 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2505 /* Draw collision indicator */
2506 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2507 gdk_draw_point(drawing
->pixmap
,
2511 hashed_process_data
->x
.middle_marked
= TRUE
;
2516 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2518 PropertiesLine prop_line
= prepare_s_e_line(process
);
2519 draw_line((void*)&prop_line
, (void*)&draw_context
);
2521 /* become the last x position */
2522 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2523 hashed_process_data
->x
.middle
= x
;
2524 /* but don't use the pixel */
2525 hashed_process_data
->x
.middle_used
= FALSE
;
2527 /* Calculate the next good time */
2528 convert_pixels_to_time(width
, x
+1, time_window
,
2529 &hashed_process_data
->next_good_time
);
2538 int before_chunk(void *hook_data
, void *call_data
)
2540 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2541 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2542 ControlFlowData
*cfd
= (ControlFlowData
*)events_request
->viewer_data
;
2544 /* Desactivate sort */
2545 gtk_tree_sortable_set_sort_column_id(
2546 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2548 GTK_SORT_ASCENDING
);
2550 drawing_chunk_begin(events_request
, tss
);
2555 int before_request(void *hook_data
, void *call_data
)
2557 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2558 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2560 drawing_data_request_begin(events_request
, tss
);
2567 * after request is necessary in addition of after chunk in order to draw
2568 * lines until the end of the screen. after chunk just draws lines until
2575 int after_request(void *hook_data
, void *call_data
)
2577 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2578 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2579 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2581 ProcessList
*process_list
= control_flow_data
->process_list
;
2582 LttTime end_time
= events_request
->end_time
;
2584 ClosureData closure_data
;
2585 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2586 closure_data
.tss
= tss
;
2587 closure_data
.end_time
= end_time
;
2589 TimeWindow time_window
=
2590 lttvwindow_get_time_window(control_flow_data
->tab
);
2591 guint width
= control_flow_data
->drawing
->width
;
2592 convert_time_to_pixels(
2596 &closure_data
.x_end
);
2599 /* Draw last items */
2600 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2601 (void*)&closure_data
);
2604 /* Request expose */
2605 drawing_request_expose(events_request
, tss
, end_time
);
2614 int after_chunk(void *hook_data
, void *call_data
)
2616 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2617 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2618 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2619 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)call_data
;
2620 LttvTracefileContext
*tfc
= lttv_traceset_context_get_current_tfc(tsc
);
2623 ProcessList
*process_list
= control_flow_data
->process_list
;
2625 LttvTraceset
*traceset
= tsc
->ts
;
2626 guint nb_trace
= lttv_traceset_number(traceset
);
2628 /* Only execute when called for the first trace's events request */
2629 if(!process_list
->current_hash_data
) return;
2631 for(i
= 0 ; i
< nb_trace
; i
++) {
2632 g_free(process_list
->current_hash_data
[i
]);
2634 g_free(process_list
->current_hash_data
);
2635 process_list
->current_hash_data
= NULL
;
2638 end_time
= LTT_TIME_MIN(tfc
->timestamp
, events_request
->end_time
);
2639 else /* end of traceset, or position now out of request : end */
2640 end_time
= events_request
->end_time
;
2642 ClosureData closure_data
;
2643 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2644 closure_data
.tss
= tss
;
2645 closure_data
.end_time
= end_time
;
2647 TimeWindow time_window
=
2648 lttvwindow_get_time_window(control_flow_data
->tab
);
2649 guint width
= control_flow_data
->drawing
->width
;
2650 convert_time_to_pixels(
2654 &closure_data
.x_end
);
2656 /* Draw last items */
2657 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2658 (void*)&closure_data
);
2660 /* Reactivate sort */
2661 gtk_tree_sortable_set_sort_column_id(
2662 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2663 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2664 GTK_SORT_ASCENDING
);
2666 update_index_to_pixmap(control_flow_data
->process_list
);
2667 /* Request a full expose : drawing scrambled */
2668 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2670 /* Request expose (updates damages zone also) */
2671 drawing_request_expose(events_request
, tss
, end_time
);