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>
64 #include <ltt/trace.h>
66 #include <lttv/lttv.h>
67 #include <lttv/hook.h>
68 #include <lttv/state.h>
69 #include <lttvwindow/lttvwindow.h>
70 #include <lttvwindow/lttvwindowtraces.h>
71 #include <lttvwindow/support.h>
74 #include "eventhooks.h"
76 #include "processlist.h"
80 #define MAX_PATH_LEN 256
81 #define STATE_LINE_WIDTH 6
82 #define COLLISION_POSITION(height) (((height - STATE_LINE_WIDTH)/2) -3)
84 extern GSList
*g_legend_list
;
87 /* Action to do when background computation completed.
89 * Wait for all the awaited computations to be over.
92 static gint
background_ready(void *hook_data
, void *call_data
)
94 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
96 control_flow_data
->background_info_waiting
--;
98 if(control_flow_data
->background_info_waiting
== 0) {
99 g_message("control flow viewer : background computation data ready.");
101 drawing_clear(control_flow_data
->drawing
);
102 processlist_clear(control_flow_data
->process_list
);
103 gtk_widget_set_size_request(
104 control_flow_data
->drawing
->drawing_area
,
105 -1, processlist_get_height(control_flow_data
->process_list
));
106 redraw_notify(control_flow_data
, NULL
);
113 /* Request background computation. Verify if it is in progress or ready first.
114 * Only for each trace in the tab's traceset.
116 static void request_background_data(ControlFlowData
*control_flow_data
)
118 LttvTracesetContext
* tsc
=
119 lttvwindow_get_traceset_context(control_flow_data
->tab
);
120 gint num_traces
= lttv_traceset_number(tsc
->ts
);
123 LttvTraceState
*tstate
;
125 LttvHooks
*background_ready_hook
=
127 lttv_hooks_add(background_ready_hook
, background_ready
, control_flow_data
,
129 control_flow_data
->background_info_waiting
= 0;
131 for(i
=0;i
<num_traces
;i
++) {
132 trace
= lttv_traceset_get(tsc
->ts
, i
);
133 tstate
= LTTV_TRACE_STATE(tsc
->traces
[i
]);
135 if(lttvwindowtraces_get_ready(g_quark_from_string("state"),trace
)==FALSE
136 && !tstate
->has_precomputed_states
) {
138 if(lttvwindowtraces_get_in_progress(g_quark_from_string("state"),
140 /* We first remove requests that could have been done for the same
141 * information. Happens when two viewers ask for it before servicing
144 if(!lttvwindowtraces_background_request_find(trace
, "state"))
145 lttvwindowtraces_background_request_queue(
146 main_window_get_widget(control_flow_data
->tab
), trace
, "state");
147 lttvwindowtraces_background_notify_queue(control_flow_data
,
151 background_ready_hook
);
152 control_flow_data
->background_info_waiting
++;
153 } else { /* in progress */
155 lttvwindowtraces_background_notify_current(control_flow_data
,
159 background_ready_hook
);
160 control_flow_data
->background_info_waiting
++;
163 /* Data ready. By its nature, this viewer doesn't need to have
164 * its data ready hook called there, because a background
165 * request is always linked with a redraw.
171 lttv_hooks_destroy(background_ready_hook
);
178 * Event Viewer's constructor hook
180 * This constructor is given as a parameter to the menuitem and toolbar button
181 * registration. It creates the list.
182 * @param tab A pointer to the parent tab.
183 * @return The widget created.
186 h_guicontrolflow(LttvPlugin
*plugin
)
188 LttvPluginTab
*ptab
= LTTV_PLUGIN_TAB(plugin
);
189 Tab
*tab
= ptab
->tab
;
190 g_info("h_guicontrolflow, %p", tab
);
191 ControlFlowData
*control_flow_data
= guicontrolflow(ptab
);
193 control_flow_data
->tab
= tab
;
195 // Unreg done in the GuiControlFlow_Destructor
196 lttvwindow_register_traceset_notify(tab
,
200 lttvwindow_register_time_window_notify(tab
,
201 update_time_window_hook
,
203 lttvwindow_register_current_time_notify(tab
,
204 update_current_time_hook
,
206 lttvwindow_register_redraw_notify(tab
,
209 lttvwindow_register_continue_notify(tab
,
212 request_background_data(control_flow_data
);
215 return guicontrolflow_get_widget(control_flow_data
) ;
219 int event_selected_hook(void *hook_data
, void *call_data
)
221 guint
*event_number
= (guint
*) call_data
;
223 g_debug("DEBUG : event selected by main window : %u", *event_number
);
228 /* Function that selects the color of status&exemode line */
229 static inline PropertiesLine
prepare_s_e_line(LttvProcessState
*process
)
231 PropertiesLine prop_line
;
232 prop_line
.line_width
= STATE_LINE_WIDTH
;
233 prop_line
.style
= GDK_LINE_SOLID
;
234 prop_line
.y
= MIDDLE
;
235 //GdkColormap *colormap = gdk_colormap_get_system();
237 if(process
->state
->s
== LTTV_STATE_RUN
) {
238 if(process
->state
->t
== LTTV_STATE_USER_MODE
)
239 prop_line
.color
= drawing_colors
[COL_RUN_USER_MODE
];
240 else if(process
->state
->t
== LTTV_STATE_SYSCALL
)
241 prop_line
.color
= drawing_colors
[COL_RUN_SYSCALL
];
242 else if(process
->state
->t
== LTTV_STATE_TRAP
)
243 prop_line
.color
= drawing_colors
[COL_RUN_TRAP
];
244 else if(process
->state
->t
== LTTV_STATE_IRQ
)
245 prop_line
.color
= drawing_colors
[COL_RUN_IRQ
];
246 else if(process
->state
->t
== LTTV_STATE_SOFT_IRQ
)
247 prop_line
.color
= drawing_colors
[COL_RUN_SOFT_IRQ
];
248 else if(process
->state
->t
== LTTV_STATE_MAYBE_SYSCALL
)
249 prop_line
.color
= drawing_colors
[COL_MODE_UNKNOWN
];
250 else if(process
->state
->t
== LTTV_STATE_MAYBE_USER_MODE
)
251 prop_line
.color
= drawing_colors
[COL_MODE_UNKNOWN
];
252 else if(process
->state
->t
== LTTV_STATE_MAYBE_TRAP
)
253 prop_line
.color
= drawing_colors
[COL_MODE_UNKNOWN
];
254 else if(process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
)
255 prop_line
.color
= drawing_colors
[COL_MODE_UNKNOWN
];
257 g_assert(FALSE
); /* RUNNING MODE UNKNOWN */
258 } else if(process
->state
->s
== LTTV_STATE_WAIT
) {
259 /* We don't show if we wait while in user mode, trap, irq or syscall */
260 prop_line
.color
= drawing_colors
[COL_WAIT
];
261 } else if(process
->state
->s
== LTTV_STATE_WAIT_CPU
) {
262 /* We don't show if we wait for CPU while in user mode, trap, irq
264 prop_line
.color
= drawing_colors
[COL_WAIT_CPU
];
265 } else if(process
->state
->s
== LTTV_STATE_ZOMBIE
) {
266 prop_line
.color
= drawing_colors
[COL_ZOMBIE
];
267 } else if(process
->state
->s
== LTTV_STATE_WAIT_FORK
) {
268 prop_line
.color
= drawing_colors
[COL_WAIT_FORK
];
269 } else if(process
->state
->s
== LTTV_STATE_EXIT
) {
270 prop_line
.color
= drawing_colors
[COL_EXIT
];
271 } else if(process
->state
->s
== LTTV_STATE_UNNAMED
) {
272 prop_line
.color
= drawing_colors
[COL_UNNAMED
];
273 } else if(process
->state
->s
== LTTV_STATE_DEAD
) {
274 prop_line
.color
= drawing_colors
[COL_DEAD
];
276 g_critical("unknown state : %s", g_quark_to_string(process
->state
->s
));
277 g_assert(FALSE
); /* UNKNOWN STATE */
284 /* Before try-wake-up hook. A process is being woken; we need to draw its line up to this point in time
285 in that colour. This is basically like exec-state, but the change applies to a process other than that
286 which is currently running. */
288 int before_trywakeup_hook(void *hook_data
, void *call_data
)
290 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
291 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
292 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
294 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
296 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
298 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
299 gint target_pid_saved
= tfc
->target_pid
;
301 LttTime evtime
= ltt_event_time(e
);
302 LttvFilter
*filter
= control_flow_data
->filter
;
307 woken_pid
= ltt_event_get_int(e
, lttv_trace_get_hook_field(th
, 0));
308 woken_cpu
= ltt_event_get_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
310 tfc
->target_pid
= woken_pid
;
311 if(!filter
|| !filter
->head
||
312 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
313 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
315 /* First, check if the woken process is in the state computation
316 * process list. If it is there, that means we must add it right now and
317 * draw items from the beginning of the read for it. If it is not
318 * present, it's a new process and it was not present : it will
319 * be added after the state update. TOCHECK: What does that last para mean? */
320 guint trace_num
= ts
->parent
.index
;
321 LttvProcessState
*process
= lttv_state_find_process(ts
, woken_cpu
, woken_pid
);
323 if(process
!= NULL
) {
324 /* Well, the woken process existed : we must get it in the process hash
325 * or add it, and draw its items.
327 /* Add process to process list (if not present) */
329 HashedProcessData
*hashed_process_data
= NULL
;
330 ProcessList
*process_list
= control_flow_data
->process_list
;
331 LttTime birth
= process
->creation_time
;
333 hashed_process_data
= processlist_get_process_data(process_list
,
338 if(hashed_process_data
== NULL
)
340 g_assert(woken_pid
!= process
->ppid
);
341 /* Process not present */
342 ProcessInfo
*process_info
;
343 Drawing_t
*drawing
= control_flow_data
->drawing
;
344 processlist_add(process_list
,
356 &hashed_process_data
);
357 gtk_widget_set_size_request(drawing
->drawing_area
,
360 gtk_widget_queue_draw(drawing
->drawing_area
);
364 /* Now, the process is in the state hash and our own process hash.
365 * We definitely can draw the items related to the ending state.
368 if(ltt_time_compare(hashed_process_data
->next_good_time
,
371 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
373 TimeWindow time_window
=
374 lttvwindow_get_time_window(control_flow_data
->tab
);
376 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
377 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
380 Drawing_t
*drawing
= control_flow_data
->drawing
;
381 guint width
= drawing
->width
;
383 convert_time_to_pixels(
389 /* Draw collision indicator */
390 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
391 gdk_draw_point(hashed_process_data
->pixmap
,
394 COLLISION_POSITION(hashed_process_data
->height
));
395 hashed_process_data
->x
.middle_marked
= TRUE
;
398 TimeWindow time_window
=
399 lttvwindow_get_time_window(control_flow_data
->tab
);
401 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
402 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
405 Drawing_t
*drawing
= control_flow_data
->drawing
;
406 guint width
= drawing
->width
;
408 convert_time_to_pixels(
415 /* Jump over draw if we are at the same x position */
416 if(x
== hashed_process_data
->x
.middle
&&
417 hashed_process_data
->x
.middle_used
)
419 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
420 /* Draw collision indicator */
421 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
422 gdk_draw_point(hashed_process_data
->pixmap
,
425 COLLISION_POSITION(hashed_process_data
->height
));
426 hashed_process_data
->x
.middle_marked
= TRUE
;
430 DrawContext draw_context
;
432 /* Now create the drawing context that will be used to draw
433 * items related to the last state. */
434 draw_context
.drawable
= hashed_process_data
->pixmap
;
435 draw_context
.gc
= drawing
->gc
;
436 draw_context
.pango_layout
= drawing
->pango_layout
;
437 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
438 draw_context
.drawinfo
.end
.x
= x
;
440 draw_context
.drawinfo
.y
.over
= 1;
441 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
442 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
444 draw_context
.drawinfo
.start
.offset
.over
= 0;
445 draw_context
.drawinfo
.start
.offset
.middle
= 0;
446 draw_context
.drawinfo
.start
.offset
.under
= 0;
447 draw_context
.drawinfo
.end
.offset
.over
= 0;
448 draw_context
.drawinfo
.end
.offset
.middle
= 0;
449 draw_context
.drawinfo
.end
.offset
.under
= 0;
453 PropertiesLine prop_line
= prepare_s_e_line(process
);
454 draw_line((void*)&prop_line
, (void*)&draw_context
);
457 /* become the last x position */
458 hashed_process_data
->x
.middle
= x
;
459 hashed_process_data
->x
.middle_used
= TRUE
;
460 hashed_process_data
->x
.middle_marked
= FALSE
;
462 /* Calculate the next good time */
463 convert_pixels_to_time(width
, x
+1, time_window
,
464 &hashed_process_data
->next_good_time
);
470 tfc
->target_pid
= target_pid_saved
;
476 /* before_schedchange_hook
478 * This function basically draw lines and icons. Two types of lines are drawn :
479 * one small (3 pixels?) representing the state of the process and the second
480 * type is thicker (10 pixels?) representing on which CPU a process is running
481 * (and this only in running state).
483 * Extremums of the lines :
484 * x_min : time of the last event context for this process kept in memory.
485 * x_max : time of the current event.
486 * y : middle of the process in the process list. The process is found in the
487 * list, therefore is it's position in pixels.
489 * The choice of lines'color is defined by the context of the last event for this
494 int before_schedchange_hook(void *hook_data
, void *call_data
)
496 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
497 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
498 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
500 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
502 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
503 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
506 e
= ltt_tracefile_get_event(tfc
->tf
);
507 gint target_pid_saved
= tfc
->target_pid
;
509 LttTime evtime
= ltt_event_time(e
);
510 LttvFilter
*filter
= control_flow_data
->filter
;
512 /* we are in a schedchange, before the state update. We must draw the
513 * items corresponding to the state before it changes : now is the right
520 pid_out
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
521 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
524 tfc
->target_pid
= pid_out
;
525 if(!filter
|| !filter
->head
||
526 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
527 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
528 /* For the pid_out */
529 /* First, check if the current process is in the state computation
530 * process list. If it is there, that means we must add it right now and
531 * draw items from the beginning of the read for it. If it is not
532 * present, it's a new process and it was not present : it will
533 * be added after the state update. */
534 guint cpu
= tfs
->cpu
;
535 guint trace_num
= ts
->parent
.index
;
536 LttvProcessState
*process
= ts
->running_process
[cpu
];
537 /* unknown state, bad current pid */
538 if(process
->pid
!= pid_out
)
539 process
= lttv_state_find_process(ts
,
542 if(process
!= NULL
) {
543 /* Well, the process_out existed : we must get it in the process hash
544 * or add it, and draw its items.
546 /* Add process to process list (if not present) */
548 HashedProcessData
*hashed_process_data
= NULL
;
549 ProcessList
*process_list
= control_flow_data
->process_list
;
550 LttTime birth
= process
->creation_time
;
552 hashed_process_data
= processlist_get_process_data(process_list
,
557 if(hashed_process_data
== NULL
)
559 g_assert(pid_out
== 0 || pid_out
!= process
->ppid
);
560 /* Process not present */
561 ProcessInfo
*process_info
;
562 Drawing_t
*drawing
= control_flow_data
->drawing
;
563 processlist_add(process_list
,
575 &hashed_process_data
);
576 gtk_widget_set_size_request(drawing
->drawing_area
,
579 gtk_widget_queue_draw(drawing
->drawing_area
);
583 /* Now, the process is in the state hash and our own process hash.
584 * We definitely can draw the items related to the ending state.
587 if(ltt_time_compare(hashed_process_data
->next_good_time
,
590 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
592 TimeWindow time_window
=
593 lttvwindow_get_time_window(control_flow_data
->tab
);
595 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
596 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
599 Drawing_t
*drawing
= control_flow_data
->drawing
;
600 guint width
= drawing
->width
;
602 convert_time_to_pixels(
608 /* Draw collision indicator */
609 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
610 gdk_draw_point(hashed_process_data
->pixmap
,
613 COLLISION_POSITION(hashed_process_data
->height
));
614 hashed_process_data
->x
.middle_marked
= TRUE
;
617 TimeWindow time_window
=
618 lttvwindow_get_time_window(control_flow_data
->tab
);
620 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
621 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
624 Drawing_t
*drawing
= control_flow_data
->drawing
;
625 guint width
= drawing
->width
;
627 convert_time_to_pixels(
634 /* Jump over draw if we are at the same x position */
635 if(x
== hashed_process_data
->x
.middle
&&
636 hashed_process_data
->x
.middle_used
)
638 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
639 /* Draw collision indicator */
640 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
641 gdk_draw_point(hashed_process_data
->pixmap
,
644 COLLISION_POSITION(hashed_process_data
->height
));
645 hashed_process_data
->x
.middle_marked
= TRUE
;
649 DrawContext draw_context
;
651 /* Now create the drawing context that will be used to draw
652 * items related to the last state. */
653 draw_context
.drawable
= hashed_process_data
->pixmap
;
654 draw_context
.gc
= drawing
->gc
;
655 draw_context
.pango_layout
= drawing
->pango_layout
;
656 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
657 draw_context
.drawinfo
.end
.x
= x
;
659 draw_context
.drawinfo
.y
.over
= 1;
660 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
661 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
663 draw_context
.drawinfo
.start
.offset
.over
= 0;
664 draw_context
.drawinfo
.start
.offset
.middle
= 0;
665 draw_context
.drawinfo
.start
.offset
.under
= 0;
666 draw_context
.drawinfo
.end
.offset
.over
= 0;
667 draw_context
.drawinfo
.end
.offset
.middle
= 0;
668 draw_context
.drawinfo
.end
.offset
.under
= 0;
672 PropertiesLine prop_line
= prepare_s_e_line(process
);
673 draw_line((void*)&prop_line
, (void*)&draw_context
);
676 /* become the last x position */
677 hashed_process_data
->x
.middle
= x
;
678 hashed_process_data
->x
.middle_used
= TRUE
;
679 hashed_process_data
->x
.middle_marked
= FALSE
;
681 /* Calculate the next good time */
682 convert_pixels_to_time(width
, x
+1, time_window
,
683 &hashed_process_data
->next_good_time
);
689 tfc
->target_pid
= pid_in
;
690 if(!filter
|| !filter
->head
||
691 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
692 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
694 /* First, check if the current process is in the state computation
695 * process list. If it is there, that means we must add it right now and
696 * draw items from the beginning of the read for it. If it is not
697 * present, it's a new process and it was not present : it will
698 * be added after the state update. */
699 LttvProcessState
*process
;
700 process
= lttv_state_find_process(ts
,
702 guint trace_num
= ts
->parent
.index
;
704 if(process
!= NULL
) {
705 /* Well, the process existed : we must get it in the process hash
706 * or add it, and draw its items.
708 /* Add process to process list (if not present) */
710 HashedProcessData
*hashed_process_data
= NULL
;
711 ProcessList
*process_list
= control_flow_data
->process_list
;
712 LttTime birth
= process
->creation_time
;
714 hashed_process_data
= processlist_get_process_data(process_list
,
719 if(hashed_process_data
== NULL
)
721 g_assert(pid_in
== 0 || pid_in
!= process
->ppid
);
722 /* Process not present */
723 ProcessInfo
*process_info
;
724 Drawing_t
*drawing
= control_flow_data
->drawing
;
725 processlist_add(process_list
,
737 &hashed_process_data
);
738 gtk_widget_set_size_request(drawing
->drawing_area
,
741 gtk_widget_queue_draw(drawing
->drawing_area
);
744 //We could set the current process and hash here, but will be done
745 //by after schedchange hook
747 /* Now, the process is in the state hash and our own process hash.
748 * We definitely can draw the items related to the ending state.
751 if(ltt_time_compare(hashed_process_data
->next_good_time
,
754 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
756 TimeWindow time_window
=
757 lttvwindow_get_time_window(control_flow_data
->tab
);
759 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
760 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
763 Drawing_t
*drawing
= control_flow_data
->drawing
;
764 guint width
= drawing
->width
;
766 convert_time_to_pixels(
772 /* Draw collision indicator */
773 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
774 gdk_draw_point(hashed_process_data
->pixmap
,
777 COLLISION_POSITION(hashed_process_data
->height
));
778 hashed_process_data
->x
.middle_marked
= TRUE
;
781 TimeWindow time_window
=
782 lttvwindow_get_time_window(control_flow_data
->tab
);
784 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
785 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
788 Drawing_t
*drawing
= control_flow_data
->drawing
;
789 guint width
= drawing
->width
;
792 convert_time_to_pixels(
799 /* Jump over draw if we are at the same x position */
800 if(x
== hashed_process_data
->x
.middle
&&
801 hashed_process_data
->x
.middle_used
)
803 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
804 /* Draw collision indicator */
805 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
806 gdk_draw_point(hashed_process_data
->pixmap
,
809 COLLISION_POSITION(hashed_process_data
->height
));
810 hashed_process_data
->x
.middle_marked
= TRUE
;
814 DrawContext draw_context
;
816 /* Now create the drawing context that will be used to draw
817 * items related to the last state. */
818 draw_context
.drawable
= hashed_process_data
->pixmap
;
819 draw_context
.gc
= drawing
->gc
;
820 draw_context
.pango_layout
= drawing
->pango_layout
;
821 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
822 draw_context
.drawinfo
.end
.x
= x
;
824 draw_context
.drawinfo
.y
.over
= 1;
825 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
826 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
828 draw_context
.drawinfo
.start
.offset
.over
= 0;
829 draw_context
.drawinfo
.start
.offset
.middle
= 0;
830 draw_context
.drawinfo
.start
.offset
.under
= 0;
831 draw_context
.drawinfo
.end
.offset
.over
= 0;
832 draw_context
.drawinfo
.end
.offset
.middle
= 0;
833 draw_context
.drawinfo
.end
.offset
.under
= 0;
837 PropertiesLine prop_line
= prepare_s_e_line(process
);
838 draw_line((void*)&prop_line
, (void*)&draw_context
);
842 /* become the last x position */
843 hashed_process_data
->x
.middle
= x
;
844 hashed_process_data
->x
.middle_used
= TRUE
;
845 hashed_process_data
->x
.middle_marked
= FALSE
;
847 /* Calculate the next good time */
848 convert_pixels_to_time(width
, x
+1, time_window
,
849 &hashed_process_data
->next_good_time
);
853 g_warning("Cannot find pin_in in schedchange %u", pid_in
);
855 tfc
->target_pid
= target_pid_saved
;
863 GString
*string
= g_string_new("");;
864 gboolean field_names
= TRUE
, state
= TRUE
;
866 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
867 g_string_append_printf(string
,"\n");
870 g_string_append_printf(string
, " %s",
871 g_quark_to_string(tfs
->process
->state
->s
));
874 g_info("%s",string
->str
);
876 g_string_free(string
, TRUE
);
878 /* End of text dump */
883 /* after_schedchange_hook
885 * The draw after hook is called by the reading API to have a
886 * particular event drawn on the screen.
887 * @param hook_data ControlFlowData structure of the viewer.
888 * @param call_data Event context.
890 * This function adds items to be drawn in a queue for each process.
893 int after_schedchange_hook(void *hook_data
, void *call_data
)
895 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
896 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
897 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
899 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
901 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
903 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
906 e
= ltt_tracefile_get_event(tfc
->tf
);
908 LttvFilter
*filter
= control_flow_data
->filter
;
909 LttTime evtime
= ltt_event_time(e
);
911 /* Add process to process list (if not present) */
912 LttvProcessState
*process_in
;
915 HashedProcessData
*hashed_process_data_in
= NULL
;
917 ProcessList
*process_list
= control_flow_data
->process_list
;
921 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
924 tfc
->target_pid
= pid_in
;
925 if(!filter
|| !filter
->head
||
926 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
927 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
928 /* Find process pid_in in the list... */
929 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
930 //process_in = tfs->process;
931 guint cpu
= tfs
->cpu
;
932 guint trace_num
= ts
->parent
.index
;
933 process_in
= ts
->running_process
[cpu
];
934 /* It should exist, because we are after the state update. */
936 g_assert(process_in
!= NULL
);
938 birth
= process_in
->creation_time
;
940 hashed_process_data_in
= processlist_get_process_data(process_list
,
945 if(hashed_process_data_in
== NULL
)
947 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
948 ProcessInfo
*process_info
;
949 Drawing_t
*drawing
= control_flow_data
->drawing
;
950 /* Process not present */
951 processlist_add(process_list
,
963 &hashed_process_data_in
);
964 gtk_widget_set_size_request(drawing
->drawing_area
,
967 gtk_widget_queue_draw(drawing
->drawing_area
);
969 /* Set the current process */
970 process_list
->current_hash_data
[trace_num
][process_in
->cpu
] =
971 hashed_process_data_in
;
973 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
976 TimeWindow time_window
=
977 lttvwindow_get_time_window(control_flow_data
->tab
);
980 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
981 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
984 Drawing_t
*drawing
= control_flow_data
->drawing
;
985 guint width
= drawing
->width
;
988 convert_time_to_pixels(
994 if(hashed_process_data_in
->x
.middle
!= new_x
) {
995 hashed_process_data_in
->x
.middle
= new_x
;
996 hashed_process_data_in
->x
.middle_used
= FALSE
;
997 hashed_process_data_in
->x
.middle_marked
= FALSE
;
1008 /* before_execmode_hook
1010 * This function basically draw lines and icons. Two types of lines are drawn :
1011 * one small (3 pixels?) representing the state of the process and the second
1012 * type is thicker (10 pixels?) representing on which CPU a process is running
1013 * (and this only in running state).
1015 * Extremums of the lines :
1016 * x_min : time of the last event context for this process kept in memory.
1017 * x_max : time of the current event.
1018 * y : middle of the process in the process list. The process is found in the
1019 * list, therefore is it's position in pixels.
1021 * The choice of lines'color is defined by the context of the last event for this
1026 int before_execmode_hook(void *hook_data
, void *call_data
)
1028 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1029 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1030 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1032 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1034 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1036 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1039 e
= ltt_tracefile_get_event(tfc
->tf
);
1041 LttvFilter
*filter
= control_flow_data
->filter
;
1042 if(filter
!= NULL
&& filter
->head
!= NULL
)
1043 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1044 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1047 LttTime evtime
= ltt_event_time(e
);
1049 /* we are in a execmode, before the state update. We must draw the
1050 * items corresponding to the state before it changes : now is the right
1054 //LttvProcessState *process = tfs->process;
1055 guint cpu
= tfs
->cpu
;
1056 guint trace_num
= ts
->parent
.index
;
1057 LttvProcessState
*process
= ts
->running_process
[cpu
];
1058 g_assert(process
!= NULL
);
1060 guint pid
= process
->pid
;
1062 /* Well, the process_out existed : we must get it in the process hash
1063 * or add it, and draw its items.
1065 /* Add process to process list (if not present) */
1066 guint pl_height
= 0;
1067 HashedProcessData
*hashed_process_data
= NULL
;
1068 ProcessList
*process_list
= control_flow_data
->process_list
;
1069 LttTime birth
= process
->creation_time
;
1071 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1072 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1074 hashed_process_data
= processlist_get_process_data(process_list
,
1079 if(unlikely(hashed_process_data
== NULL
))
1081 g_assert(pid
== 0 || pid
!= process
->ppid
);
1082 ProcessInfo
*process_info
;
1083 /* Process not present */
1084 Drawing_t
*drawing
= control_flow_data
->drawing
;
1085 processlist_add(process_list
,
1097 &hashed_process_data
);
1098 gtk_widget_set_size_request(drawing
->drawing_area
,
1101 gtk_widget_queue_draw(drawing
->drawing_area
);
1103 /* Set the current process */
1104 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1105 hashed_process_data
;
1108 /* Now, the process is in the state hash and our own process hash.
1109 * We definitely can draw the items related to the ending state.
1112 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1115 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1116 TimeWindow time_window
=
1117 lttvwindow_get_time_window(control_flow_data
->tab
);
1120 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1121 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1123 #endif //EXTRA_CHECK
1124 Drawing_t
*drawing
= control_flow_data
->drawing
;
1125 guint width
= drawing
->width
;
1127 convert_time_to_pixels(
1133 /* Draw collision indicator */
1134 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1135 gdk_draw_point(hashed_process_data
->pixmap
,
1138 COLLISION_POSITION(hashed_process_data
->height
));
1139 hashed_process_data
->x
.middle_marked
= TRUE
;
1142 TimeWindow time_window
=
1143 lttvwindow_get_time_window(control_flow_data
->tab
);
1146 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1147 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1149 #endif //EXTRA_CHECK
1150 Drawing_t
*drawing
= control_flow_data
->drawing
;
1151 guint width
= drawing
->width
;
1154 convert_time_to_pixels(
1161 /* Jump over draw if we are at the same x position */
1162 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1163 hashed_process_data
->x
.middle_used
))
1165 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1166 /* Draw collision indicator */
1167 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1168 gdk_draw_point(hashed_process_data
->pixmap
,
1171 COLLISION_POSITION(hashed_process_data
->height
));
1172 hashed_process_data
->x
.middle_marked
= TRUE
;
1177 DrawContext draw_context
;
1178 /* Now create the drawing context that will be used to draw
1179 * items related to the last state. */
1180 draw_context
.drawable
= hashed_process_data
->pixmap
;
1181 draw_context
.gc
= drawing
->gc
;
1182 draw_context
.pango_layout
= drawing
->pango_layout
;
1183 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1184 draw_context
.drawinfo
.end
.x
= x
;
1186 draw_context
.drawinfo
.y
.over
= 1;
1187 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1188 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1190 draw_context
.drawinfo
.start
.offset
.over
= 0;
1191 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1192 draw_context
.drawinfo
.start
.offset
.under
= 0;
1193 draw_context
.drawinfo
.end
.offset
.over
= 0;
1194 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1195 draw_context
.drawinfo
.end
.offset
.under
= 0;
1199 PropertiesLine prop_line
= prepare_s_e_line(process
);
1200 draw_line((void*)&prop_line
, (void*)&draw_context
);
1203 /* become the last x position */
1204 hashed_process_data
->x
.middle
= x
;
1205 hashed_process_data
->x
.middle_used
= TRUE
;
1206 hashed_process_data
->x
.middle_marked
= FALSE
;
1208 /* Calculate the next good time */
1209 convert_pixels_to_time(width
, x
+1, time_window
,
1210 &hashed_process_data
->next_good_time
);
1217 /* before_process_exit_hook
1219 * Draw lines for process event.
1221 * @param hook_data ControlFlowData structure of the viewer.
1222 * @param call_data Event context.
1224 * This function adds items to be drawn in a queue for each process.
1229 int before_process_exit_hook(void *hook_data
, void *call_data
)
1231 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1232 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1234 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1236 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1238 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1240 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1243 e
= ltt_tracefile_get_event(tfc
->tf
);
1245 LttvFilter
*filter
= control_flow_data
->filter
;
1246 if(filter
!= NULL
&& filter
->head
!= NULL
)
1247 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1248 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1251 LttTime evtime
= ltt_event_time(e
);
1253 /* Add process to process list (if not present) */
1254 //LttvProcessState *process = tfs->process;
1255 guint cpu
= tfs
->cpu
;
1256 guint trace_num
= ts
->parent
.index
;
1257 LttvProcessState
*process
= ts
->running_process
[cpu
];
1258 guint pid
= process
->pid
;
1260 guint pl_height
= 0;
1261 HashedProcessData
*hashed_process_data
= NULL
;
1263 ProcessList
*process_list
= control_flow_data
->process_list
;
1265 g_assert(process
!= NULL
);
1267 birth
= process
->creation_time
;
1269 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1270 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1272 hashed_process_data
= processlist_get_process_data(process_list
,
1277 if(unlikely(hashed_process_data
== NULL
))
1279 g_assert(pid
== 0 || pid
!= process
->ppid
);
1280 /* Process not present */
1281 Drawing_t
*drawing
= control_flow_data
->drawing
;
1282 ProcessInfo
*process_info
;
1283 processlist_add(process_list
,
1295 &hashed_process_data
);
1296 gtk_widget_set_size_request(drawing
->drawing_area
,
1299 gtk_widget_queue_draw(drawing
->drawing_area
);
1303 /* Now, the process is in the state hash and our own process hash.
1304 * We definitely can draw the items related to the ending state.
1307 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1310 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1311 TimeWindow time_window
=
1312 lttvwindow_get_time_window(control_flow_data
->tab
);
1315 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1316 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1318 #endif //EXTRA_CHECK
1319 Drawing_t
*drawing
= control_flow_data
->drawing
;
1320 guint width
= drawing
->width
;
1322 convert_time_to_pixels(
1328 /* Draw collision indicator */
1329 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1330 gdk_draw_point(hashed_process_data
->pixmap
,
1333 COLLISION_POSITION(hashed_process_data
->height
));
1334 hashed_process_data
->x
.middle_marked
= TRUE
;
1337 TimeWindow time_window
=
1338 lttvwindow_get_time_window(control_flow_data
->tab
);
1341 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1342 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1344 #endif //EXTRA_CHECK
1345 Drawing_t
*drawing
= control_flow_data
->drawing
;
1346 guint width
= drawing
->width
;
1349 convert_time_to_pixels(
1356 /* Jump over draw if we are at the same x position */
1357 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1358 hashed_process_data
->x
.middle_used
))
1360 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1361 /* Draw collision indicator */
1362 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1363 gdk_draw_point(hashed_process_data
->pixmap
,
1366 COLLISION_POSITION(hashed_process_data
->height
));
1367 hashed_process_data
->x
.middle_marked
= TRUE
;
1371 DrawContext draw_context
;
1373 /* Now create the drawing context that will be used to draw
1374 * items related to the last state. */
1375 draw_context
.drawable
= hashed_process_data
->pixmap
;
1376 draw_context
.gc
= drawing
->gc
;
1377 draw_context
.pango_layout
= drawing
->pango_layout
;
1378 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1379 draw_context
.drawinfo
.end
.x
= x
;
1381 draw_context
.drawinfo
.y
.over
= 1;
1382 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1383 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1385 draw_context
.drawinfo
.start
.offset
.over
= 0;
1386 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1387 draw_context
.drawinfo
.start
.offset
.under
= 0;
1388 draw_context
.drawinfo
.end
.offset
.over
= 0;
1389 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1390 draw_context
.drawinfo
.end
.offset
.under
= 0;
1394 PropertiesLine prop_line
= prepare_s_e_line(process
);
1395 draw_line((void*)&prop_line
, (void*)&draw_context
);
1398 /* become the last x position */
1399 hashed_process_data
->x
.middle
= x
;
1400 hashed_process_data
->x
.middle_used
= TRUE
;
1401 hashed_process_data
->x
.middle_marked
= FALSE
;
1403 /* Calculate the next good time */
1404 convert_pixels_to_time(width
, x
+1, time_window
,
1405 &hashed_process_data
->next_good_time
);
1415 /* before_process_release_hook
1417 * Draw lines for process event.
1419 * @param hook_data ControlFlowData structure of the viewer.
1420 * @param call_data Event context.
1422 * This function adds items to be drawn in a queue for each process.
1427 int before_process_release_hook(void *hook_data
, void *call_data
)
1429 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1430 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1432 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1434 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1436 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1439 e
= ltt_tracefile_get_event(tfc
->tf
);
1441 LttvFilter
*filter
= control_flow_data
->filter
;
1442 if(filter
!= NULL
&& filter
->head
!= NULL
)
1443 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1444 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1447 LttTime evtime
= ltt_event_time(e
);
1449 guint trace_num
= ts
->parent
.index
;
1453 pid
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
1456 /* Add process to process list (if not present) */
1457 /* Don't care about the process if it's not in the state hash already :
1458 * that means a process that has never done anything in the trace and
1459 * unknown suddently gets destroyed : no state meaningful to show. */
1460 LttvProcessState
*process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1462 if(process
!= NULL
) {
1464 HashedProcessData
*hashed_process_data
= NULL
;
1466 ProcessList
*process_list
= control_flow_data
->process_list
;
1468 birth
= process
->creation_time
;
1470 /* Cannot use current process : this event happens on another process,
1471 * action done by the parent. */
1472 hashed_process_data
= processlist_get_process_data(process_list
,
1477 if(unlikely(hashed_process_data
== NULL
))
1479 * Process already been scheduled out EXIT_DEAD, not in the process list
1480 * anymore. Just return.
1484 /* Now, the process is in the state hash and our own process hash.
1485 * We definitely can draw the items related to the ending state.
1488 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1491 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1492 TimeWindow time_window
=
1493 lttvwindow_get_time_window(control_flow_data
->tab
);
1496 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1497 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1499 #endif //EXTRA_CHECK
1500 Drawing_t
*drawing
= control_flow_data
->drawing
;
1501 guint width
= drawing
->width
;
1503 convert_time_to_pixels(
1509 /* Draw collision indicator */
1510 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1511 gdk_draw_point(hashed_process_data
->pixmap
,
1514 COLLISION_POSITION(hashed_process_data
->height
));
1515 hashed_process_data
->x
.middle_marked
= TRUE
;
1518 TimeWindow time_window
=
1519 lttvwindow_get_time_window(control_flow_data
->tab
);
1522 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1523 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1525 #endif //EXTRA_CHECK
1526 Drawing_t
*drawing
= control_flow_data
->drawing
;
1527 guint width
= drawing
->width
;
1530 convert_time_to_pixels(
1537 /* Jump over draw if we are at the same x position */
1538 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1539 hashed_process_data
->x
.middle_used
))
1541 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1542 /* Draw collision indicator */
1543 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1544 gdk_draw_point(hashed_process_data
->pixmap
,
1547 COLLISION_POSITION(hashed_process_data
->height
));
1548 hashed_process_data
->x
.middle_marked
= TRUE
;
1552 DrawContext draw_context
;
1554 /* Now create the drawing context that will be used to draw
1555 * items related to the last state. */
1556 draw_context
.drawable
= hashed_process_data
->pixmap
;
1557 draw_context
.gc
= drawing
->gc
;
1558 draw_context
.pango_layout
= drawing
->pango_layout
;
1559 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1560 draw_context
.drawinfo
.end
.x
= x
;
1562 draw_context
.drawinfo
.y
.over
= 1;
1563 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1564 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1566 draw_context
.drawinfo
.start
.offset
.over
= 0;
1567 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1568 draw_context
.drawinfo
.start
.offset
.under
= 0;
1569 draw_context
.drawinfo
.end
.offset
.over
= 0;
1570 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1571 draw_context
.drawinfo
.end
.offset
.under
= 0;
1575 PropertiesLine prop_line
= prepare_s_e_line(process
);
1576 draw_line((void*)&prop_line
, (void*)&draw_context
);
1579 /* become the last x position */
1580 hashed_process_data
->x
.middle
= x
;
1581 hashed_process_data
->x
.middle_used
= TRUE
;
1582 hashed_process_data
->x
.middle_marked
= FALSE
;
1584 /* Calculate the next good time */
1585 convert_pixels_to_time(width
, x
+1, time_window
,
1586 &hashed_process_data
->next_good_time
);
1598 /* after_process_fork_hook
1600 * Create the processlist entry for the child process. Put the last
1601 * position in x at the current time value.
1603 * @param hook_data ControlFlowData structure of the viewer.
1604 * @param call_data Event context.
1606 * This function adds items to be drawn in a queue for each process.
1609 int after_process_fork_hook(void *hook_data
, void *call_data
)
1611 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1612 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1613 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1615 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1617 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1620 e
= ltt_tracefile_get_event(tfc
->tf
);
1622 LttvFilter
*filter
= control_flow_data
->filter
;
1623 if(filter
!= NULL
&& filter
->head
!= NULL
)
1624 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1625 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1628 LttTime evtime
= ltt_event_time(e
);
1632 child_pid
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
1635 /* Add process to process list (if not present) */
1636 LttvProcessState
*process_child
;
1638 guint pl_height
= 0;
1639 HashedProcessData
*hashed_process_data_child
= NULL
;
1641 ProcessList
*process_list
= control_flow_data
->process_list
;
1643 /* Find child in the list... */
1644 process_child
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1645 /* It should exist, because we are after the state update. */
1646 g_assert(process_child
!= NULL
);
1648 birth
= process_child
->creation_time
;
1649 guint trace_num
= ts
->parent
.index
;
1651 /* Cannot use current process, because this action is done by the parent
1653 hashed_process_data_child
= processlist_get_process_data(process_list
,
1658 if(likely(hashed_process_data_child
== NULL
))
1660 g_assert(child_pid
== 0 || child_pid
!= process_child
->ppid
);
1661 /* Process not present */
1662 Drawing_t
*drawing
= control_flow_data
->drawing
;
1663 ProcessInfo
*process_info
;
1664 processlist_add(process_list
,
1667 process_child
->tgid
,
1669 process_child
->ppid
,
1672 process_child
->name
,
1673 process_child
->brand
,
1676 &hashed_process_data_child
);
1677 gtk_widget_set_size_request(drawing
->drawing_area
,
1680 gtk_widget_queue_draw(drawing
->drawing_area
);
1682 processlist_set_ppid(process_list
, process_child
->ppid
,
1683 hashed_process_data_child
);
1684 processlist_set_tgid(process_list
, process_child
->tgid
,
1685 hashed_process_data_child
);
1689 if(likely(ltt_time_compare(hashed_process_data_child
->next_good_time
,
1692 TimeWindow time_window
=
1693 lttvwindow_get_time_window(control_flow_data
->tab
);
1696 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1697 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1699 #endif //EXTRA_CHECK
1700 Drawing_t
*drawing
= control_flow_data
->drawing
;
1701 guint width
= drawing
->width
;
1703 convert_time_to_pixels(
1709 if(likely(hashed_process_data_child
->x
.over
!= new_x
)) {
1710 hashed_process_data_child
->x
.over
= new_x
;
1711 hashed_process_data_child
->x
.over_used
= FALSE
;
1712 hashed_process_data_child
->x
.over_marked
= FALSE
;
1714 if(likely(hashed_process_data_child
->x
.middle
!= new_x
)) {
1715 hashed_process_data_child
->x
.middle
= new_x
;
1716 hashed_process_data_child
->x
.middle_used
= FALSE
;
1717 hashed_process_data_child
->x
.middle_marked
= FALSE
;
1719 if(likely(hashed_process_data_child
->x
.under
!= new_x
)) {
1720 hashed_process_data_child
->x
.under
= new_x
;
1721 hashed_process_data_child
->x
.under_used
= FALSE
;
1722 hashed_process_data_child
->x
.under_marked
= FALSE
;
1730 /* after_process_exit_hook
1732 * Create the processlist entry for the child process. Put the last
1733 * position in x at the current time value.
1735 * @param hook_data ControlFlowData structure of the viewer.
1736 * @param call_data Event context.
1738 * This function adds items to be drawn in a queue for each process.
1741 int after_process_exit_hook(void *hook_data
, void *call_data
)
1743 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1744 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1745 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1747 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1749 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1751 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1754 e
= ltt_tracefile_get_event(tfc
->tf
);
1756 LttvFilter
*filter
= control_flow_data
->filter
;
1757 if(filter
!= NULL
&& filter
->head
!= NULL
)
1758 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1759 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1762 LttTime evtime
= ltt_event_time(e
);
1764 /* Add process to process list (if not present) */
1765 //LttvProcessState *process = tfs->process;
1766 guint cpu
= tfs
->cpu
;
1767 guint trace_num
= ts
->parent
.index
;
1768 LttvProcessState
*process
= ts
->running_process
[cpu
];
1770 /* It should exist, because we are after the state update. */
1771 g_assert(process
!= NULL
);
1773 guint pid
= process
->pid
;
1775 guint pl_height
= 0;
1776 HashedProcessData
*hashed_process_data
= NULL
;
1778 ProcessList
*process_list
= control_flow_data
->process_list
;
1780 birth
= process
->creation_time
;
1782 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
) ){
1783 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1785 hashed_process_data
= processlist_get_process_data(process_list
,
1790 if(unlikely(hashed_process_data
== NULL
))
1792 g_assert(pid
== 0 || pid
!= process
->ppid
);
1793 /* Process not present */
1794 Drawing_t
*drawing
= control_flow_data
->drawing
;
1795 ProcessInfo
*process_info
;
1796 processlist_add(process_list
,
1808 &hashed_process_data
);
1809 gtk_widget_set_size_request(drawing
->drawing_area
,
1812 gtk_widget_queue_draw(drawing
->drawing_area
);
1815 /* Set the current process */
1816 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1817 hashed_process_data
;
1820 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
1823 TimeWindow time_window
=
1824 lttvwindow_get_time_window(control_flow_data
->tab
);
1827 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1828 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1830 #endif //EXTRA_CHECK
1831 Drawing_t
*drawing
= control_flow_data
->drawing
;
1832 guint width
= drawing
->width
;
1834 convert_time_to_pixels(
1839 if(unlikely(hashed_process_data
->x
.middle
!= new_x
)) {
1840 hashed_process_data
->x
.middle
= new_x
;
1841 hashed_process_data
->x
.middle_used
= FALSE
;
1842 hashed_process_data
->x
.middle_marked
= FALSE
;
1850 /* Get the filename of the process to print */
1851 int after_fs_exec_hook(void *hook_data
, void *call_data
)
1853 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1854 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1855 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1857 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1859 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1861 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1864 e
= ltt_tracefile_get_event(tfc
->tf
);
1866 LttvFilter
*filter
= control_flow_data
->filter
;
1867 if(filter
!= NULL
&& filter
->head
!= NULL
)
1868 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1869 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1872 guint cpu
= tfs
->cpu
;
1873 guint trace_num
= ts
->parent
.index
;
1874 LttvProcessState
*process
= ts
->running_process
[cpu
];
1875 g_assert(process
!= NULL
);
1877 guint pid
= process
->pid
;
1879 /* Well, the process_out existed : we must get it in the process hash
1880 * or add it, and draw its items.
1882 /* Add process to process list (if not present) */
1883 guint pl_height
= 0;
1884 HashedProcessData
*hashed_process_data
= NULL
;
1885 ProcessList
*process_list
= control_flow_data
->process_list
;
1886 LttTime birth
= process
->creation_time
;
1888 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1889 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1891 hashed_process_data
= processlist_get_process_data(process_list
,
1896 if(unlikely(hashed_process_data
== NULL
))
1898 g_assert(pid
== 0 || pid
!= process
->ppid
);
1899 ProcessInfo
*process_info
;
1900 /* Process not present */
1901 Drawing_t
*drawing
= control_flow_data
->drawing
;
1902 processlist_add(process_list
,
1914 &hashed_process_data
);
1915 gtk_widget_set_size_request(drawing
->drawing_area
,
1918 gtk_widget_queue_draw(drawing
->drawing_area
);
1920 /* Set the current process */
1921 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1922 hashed_process_data
;
1925 processlist_set_name(process_list
, process
->name
, hashed_process_data
);
1931 /* Get the filename of the process to print */
1932 int after_user_generic_thread_brand_hook(void *hook_data
, void *call_data
)
1934 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1935 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1936 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1938 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1940 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1942 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1945 e
= ltt_tracefile_get_event(tfc
->tf
);
1947 LttvFilter
*filter
= control_flow_data
->filter
;
1948 if(filter
!= NULL
&& filter
->head
!= NULL
)
1949 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1950 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1953 guint cpu
= tfs
->cpu
;
1954 guint trace_num
= ts
->parent
.index
;
1955 LttvProcessState
*process
= ts
->running_process
[cpu
];
1956 g_assert(process
!= NULL
);
1958 guint pid
= process
->pid
;
1960 /* Well, the process_out existed : we must get it in the process hash
1961 * or add it, and draw its items.
1963 /* Add process to process list (if not present) */
1964 guint pl_height
= 0;
1965 HashedProcessData
*hashed_process_data
= NULL
;
1966 ProcessList
*process_list
= control_flow_data
->process_list
;
1967 LttTime birth
= process
->creation_time
;
1969 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1970 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1972 hashed_process_data
= processlist_get_process_data(process_list
,
1977 if(unlikely(hashed_process_data
== NULL
))
1979 g_assert(pid
== 0 || pid
!= process
->ppid
);
1980 ProcessInfo
*process_info
;
1981 /* Process not present */
1982 Drawing_t
*drawing
= control_flow_data
->drawing
;
1983 processlist_add(process_list
,
1995 &hashed_process_data
);
1996 gtk_widget_set_size_request(drawing
->drawing_area
,
1999 gtk_widget_queue_draw(drawing
->drawing_area
);
2001 /* Set the current process */
2002 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
2003 hashed_process_data
;
2006 processlist_set_brand(process_list
, process
->brand
, hashed_process_data
);
2013 /* after_event_enum_process_hook
2015 * Create the processlist entry for the child process. Put the last
2016 * position in x at the current time value.
2018 * @param hook_data ControlFlowData structure of the viewer.
2019 * @param call_data Event context.
2021 * This function adds items to be drawn in a queue for each process.
2024 int after_event_enum_process_hook(void *hook_data
, void *call_data
)
2026 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2027 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
2028 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2030 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2032 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
2034 guint first_cpu
, nb_cpus
, cpu
;
2037 e
= ltt_tracefile_get_event(tfc
->tf
);
2039 LttvFilter
*filter
= control_flow_data
->filter
;
2040 if(filter
!= NULL
&& filter
->head
!= NULL
)
2041 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2042 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2045 /* Add process to process list (if not present) */
2046 LttvProcessState
*process_in
;
2048 guint pl_height
= 0;
2049 HashedProcessData
*hashed_process_data_in
= NULL
;
2051 ProcessList
*process_list
= control_flow_data
->process_list
;
2052 guint trace_num
= ts
->parent
.index
;
2056 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2061 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2063 first_cpu
= ANY_CPU
;
2064 nb_cpus
= ANY_CPU
+1;
2067 for(cpu
= first_cpu
; cpu
< nb_cpus
; cpu
++) {
2068 /* Find process pid_in in the list... */
2069 process_in
= lttv_state_find_process(ts
, cpu
, pid_in
);
2070 //process_in = tfs->process;
2071 //guint cpu = tfs->cpu;
2072 //guint trace_num = ts->parent.index;
2073 //process_in = ts->running_process[cpu];
2074 /* It should exist, because we are after the state update. */
2076 //g_assert(process_in != NULL);
2077 #endif //EXTRA_CHECK
2078 birth
= process_in
->creation_time
;
2080 hashed_process_data_in
= processlist_get_process_data(process_list
,
2085 if(hashed_process_data_in
== NULL
)
2087 if(pid_in
!= 0 && pid_in
== process_in
->ppid
)
2088 g_critical("TEST %u , %u", pid_in
, process_in
->ppid
);
2089 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
2090 ProcessInfo
*process_info
;
2091 Drawing_t
*drawing
= control_flow_data
->drawing
;
2092 /* Process not present */
2093 processlist_add(process_list
,
2105 &hashed_process_data_in
);
2106 gtk_widget_set_size_request(drawing
->drawing_area
,
2109 gtk_widget_queue_draw(drawing
->drawing_area
);
2111 processlist_set_name(process_list
, process_in
->name
,
2112 hashed_process_data_in
);
2113 processlist_set_ppid(process_list
, process_in
->ppid
,
2114 hashed_process_data_in
);
2115 processlist_set_tgid(process_list
, process_in
->tgid
,
2116 hashed_process_data_in
);
2123 gint
update_time_window_hook(void *hook_data
, void *call_data
)
2125 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2126 Drawing_t
*drawing
= control_flow_data
->drawing
;
2127 ProcessList
*process_list
= control_flow_data
->process_list
;
2129 const TimeWindowNotifyData
*time_window_nofify_data
=
2130 ((const TimeWindowNotifyData
*)call_data
);
2132 TimeWindow
*old_time_window
=
2133 time_window_nofify_data
->old_time_window
;
2134 TimeWindow
*new_time_window
=
2135 time_window_nofify_data
->new_time_window
;
2137 /* Update the ruler */
2138 drawing_update_ruler(control_flow_data
->drawing
,
2142 /* Two cases : zoom in/out or scrolling */
2144 /* In order to make sure we can reuse the old drawing, the scale must
2145 * be the same and the new time interval being partly located in the
2146 * currently shown time interval. (reuse is only for scrolling)
2149 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
2150 old_time_window
->start_time
.tv_sec
,
2151 old_time_window
->start_time
.tv_nsec
,
2152 old_time_window
->time_width
.tv_sec
,
2153 old_time_window
->time_width
.tv_nsec
);
2155 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
2156 new_time_window
->start_time
.tv_sec
,
2157 new_time_window
->start_time
.tv_nsec
,
2158 new_time_window
->time_width
.tv_sec
,
2159 new_time_window
->time_width
.tv_nsec
);
2161 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
2162 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
2164 /* Same scale (scrolling) */
2165 g_info("scrolling");
2166 LttTime
*ns
= &new_time_window
->start_time
;
2167 LttTime
*os
= &old_time_window
->start_time
;
2168 LttTime old_end
= old_time_window
->end_time
;
2169 LttTime new_end
= new_time_window
->end_time
;
2171 //if(ns<os+w && os+w<ns+w)
2172 //if(ns<old_end && os<ns)
2173 if(ltt_time_compare(*ns
, old_end
) == -1
2174 && ltt_time_compare(*os
, *ns
) == -1)
2176 g_info("scrolling near right");
2177 /* Scroll right, keep right part of the screen */
2179 guint width
= control_flow_data
->drawing
->width
;
2180 convert_time_to_pixels(
2186 /* Copy old data to new location */
2187 copy_pixmap_region(process_list
,
2189 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2193 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
2195 if(drawing
->damage_begin
== drawing
->damage_end
)
2196 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
2198 drawing
->damage_begin
= 0;
2200 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2202 /* Clear the data request background, but not SAFETY */
2203 rectangle_pixmap(process_list
,
2204 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2206 drawing
->damage_begin
+SAFETY
, 0,
2207 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2209 gtk_widget_queue_draw(drawing
->drawing_area
);
2210 //gtk_widget_queue_draw_area (drawing->drawing_area,
2212 // control_flow_data->drawing->width,
2213 // control_flow_data->drawing->height);
2215 /* Get new data for the rest. */
2216 drawing_data_request(control_flow_data
->drawing
,
2217 drawing
->damage_begin
, 0,
2218 drawing
->damage_end
- drawing
->damage_begin
,
2219 control_flow_data
->drawing
->height
);
2222 //if(ns<os && os<ns+w)
2223 //if(ns<os && os<new_end)
2224 if(ltt_time_compare(*ns
,*os
) == -1
2225 && ltt_time_compare(*os
,new_end
) == -1)
2227 g_info("scrolling near left");
2228 /* Scroll left, keep left part of the screen */
2230 guint width
= control_flow_data
->drawing
->width
;
2231 convert_time_to_pixels(
2237 /* Copy old data to new location */
2238 copy_pixmap_region (process_list
,
2240 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2246 if(drawing
->damage_begin
== drawing
->damage_end
)
2247 drawing
->damage_end
= x
;
2249 drawing
->damage_end
=
2250 control_flow_data
->drawing
->width
;
2252 drawing
->damage_begin
= 0;
2254 rectangle_pixmap (process_list
,
2255 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2257 drawing
->damage_begin
, 0,
2258 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2261 gtk_widget_queue_draw(drawing
->drawing_area
);
2262 //gtk_widget_queue_draw_area (drawing->drawing_area,
2264 // control_flow_data->drawing->width,
2265 // control_flow_data->drawing->height);
2268 /* Get new data for the rest. */
2269 drawing_data_request(control_flow_data
->drawing
,
2270 drawing
->damage_begin
, 0,
2271 drawing
->damage_end
- drawing
->damage_begin
,
2272 control_flow_data
->drawing
->height
);
2275 if(ltt_time_compare(*ns
,*os
) == 0)
2277 g_info("not scrolling");
2279 g_info("scrolling far");
2280 /* Cannot reuse any part of the screen : far jump */
2283 rectangle_pixmap (process_list
,
2284 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2287 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2290 //gtk_widget_queue_draw_area (drawing->drawing_area,
2292 // control_flow_data->drawing->width,
2293 // control_flow_data->drawing->height);
2294 gtk_widget_queue_draw(drawing
->drawing_area
);
2296 drawing
->damage_begin
= 0;
2297 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2299 drawing_data_request(control_flow_data
->drawing
,
2301 control_flow_data
->drawing
->width
,
2302 control_flow_data
->drawing
->height
);
2308 /* Different scale (zoom) */
2311 rectangle_pixmap (process_list
,
2312 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2315 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2318 //gtk_widget_queue_draw_area (drawing->drawing_area,
2320 // control_flow_data->drawing->width,
2321 // control_flow_data->drawing->height);
2322 gtk_widget_queue_draw(drawing
->drawing_area
);
2324 drawing
->damage_begin
= 0;
2325 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2327 drawing_data_request(control_flow_data
->drawing
,
2329 control_flow_data
->drawing
->width
,
2330 control_flow_data
->drawing
->height
);
2333 /* Update directly when scrolling */
2334 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2340 gint
traceset_notify(void *hook_data
, void *call_data
)
2342 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2343 Drawing_t
*drawing
= control_flow_data
->drawing
;
2345 if(unlikely(drawing
->gc
== NULL
)) {
2348 if(drawing
->dotted_gc
== NULL
) {
2352 drawing_clear(control_flow_data
->drawing
);
2353 processlist_clear(control_flow_data
->process_list
);
2354 gtk_widget_set_size_request(
2355 control_flow_data
->drawing
->drawing_area
,
2356 -1, processlist_get_height(control_flow_data
->process_list
));
2357 redraw_notify(control_flow_data
, NULL
);
2359 request_background_data(control_flow_data
);
2364 gint
redraw_notify(void *hook_data
, void *call_data
)
2366 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2367 Drawing_t
*drawing
= control_flow_data
->drawing
;
2368 GtkWidget
*widget
= drawing
->drawing_area
;
2370 drawing
->damage_begin
= 0;
2371 drawing
->damage_end
= drawing
->width
;
2373 /* fun feature, to be separated someday... */
2374 drawing_clear(control_flow_data
->drawing
);
2375 processlist_clear(control_flow_data
->process_list
);
2376 gtk_widget_set_size_request(
2377 control_flow_data
->drawing
->drawing_area
,
2378 -1, processlist_get_height(control_flow_data
->process_list
));
2380 rectangle_pixmap (control_flow_data
->process_list
,
2381 widget
->style
->black_gc
,
2384 drawing
->alloc_width
,
2387 gtk_widget_queue_draw(drawing
->drawing_area
);
2389 if(drawing
->damage_begin
< drawing
->damage_end
)
2391 drawing_data_request(drawing
,
2392 drawing
->damage_begin
,
2394 drawing
->damage_end
-drawing
->damage_begin
,
2398 //gtk_widget_queue_draw_area(drawing->drawing_area,
2401 // drawing->height);
2407 gint
continue_notify(void *hook_data
, void *call_data
)
2409 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2410 Drawing_t
*drawing
= control_flow_data
->drawing
;
2412 //g_assert(widget->allocation.width == drawing->damage_end);
2414 if(drawing
->damage_begin
< drawing
->damage_end
)
2416 drawing_data_request(drawing
,
2417 drawing
->damage_begin
,
2419 drawing
->damage_end
-drawing
->damage_begin
,
2427 gint
update_current_time_hook(void *hook_data
, void *call_data
)
2429 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
2431 LttTime current_time
= *((LttTime
*)call_data
);
2433 TimeWindow time_window
=
2434 lttvwindow_get_time_window(control_flow_data
->tab
);
2436 LttTime time_begin
= time_window
.start_time
;
2437 LttTime width
= time_window
.time_width
;
2440 guint64 time_ll
= ltt_time_to_uint64(width
);
2441 time_ll
= time_ll
>> 1; /* divide by two */
2442 half_width
= ltt_time_from_uint64(time_ll
);
2444 LttTime time_end
= ltt_time_add(time_begin
, width
);
2446 LttvTracesetContext
* tsc
=
2447 lttvwindow_get_traceset_context(control_flow_data
->tab
);
2449 LttTime trace_start
= tsc
->time_span
.start_time
;
2450 LttTime trace_end
= tsc
->time_span
.end_time
;
2452 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
2453 current_time
.tv_nsec
);
2457 /* If current time is inside time interval, just move the highlight
2460 /* Else, we have to change the time interval. We have to tell it
2461 * to the main window. */
2462 /* The time interval change will take care of placing the current
2463 * time at the center of the visible area, or nearest possible if we are
2464 * at one end of the trace. */
2467 if(ltt_time_compare(current_time
, time_begin
) < 0)
2469 TimeWindow new_time_window
;
2471 if(ltt_time_compare(current_time
,
2472 ltt_time_add(trace_start
,half_width
)) < 0)
2473 time_begin
= trace_start
;
2475 time_begin
= ltt_time_sub(current_time
,half_width
);
2477 new_time_window
.start_time
= time_begin
;
2478 new_time_window
.time_width
= width
;
2479 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2480 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2482 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2484 else if(ltt_time_compare(current_time
, time_end
) > 0)
2486 TimeWindow new_time_window
;
2488 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
2489 time_begin
= ltt_time_sub(trace_end
,width
);
2491 time_begin
= ltt_time_sub(current_time
,half_width
);
2493 new_time_window
.start_time
= time_begin
;
2494 new_time_window
.time_width
= width
;
2495 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2496 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2498 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2501 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2503 /* Update directly when scrolling */
2504 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2510 typedef struct _ClosureData
{
2511 EventsRequest
*events_request
;
2512 LttvTracesetState
*tss
;
2518 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
2520 ProcessInfo
*process_info
= (ProcessInfo
*)key
;
2521 HashedProcessData
*hashed_process_data
= (HashedProcessData
*)value
;
2522 ClosureData
*closure_data
= (ClosureData
*)user_data
;
2524 EventsRequest
*events_request
= closure_data
->events_request
;
2525 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2527 LttvTracesetState
*tss
= closure_data
->tss
;
2528 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)tss
;
2530 LttTime evtime
= closure_data
->end_time
;
2532 gboolean dodraw
= TRUE
;
2535 /* For the process */
2536 /* First, check if the current process is in the state computation
2537 * process list. If it is there, that means we must add it right now and
2538 * draw items from the beginning of the read for it. If it is not
2539 * present, it's a new process and it was not present : it will
2540 * be added after the state update. */
2542 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
2543 #endif //EXTRA_CHECK
2544 LttvTraceContext
*tc
= tsc
->traces
[process_info
->trace_num
];
2545 LttvTraceState
*ts
= (LttvTraceState
*)tc
;
2548 //FIXME : optimize data structures.
2549 LttvTracefileState
*tfs
;
2550 LttvTracefileContext
*tfc
;
2552 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
2553 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
2554 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
2555 && tfs
->cpu
== process_info
->cpu
)
2559 g_assert(i
<tc
->tracefiles
->len
);
2560 tfs
= LTTV_TRACEFILE_STATE(tfc
);
2562 // LttvTracefileState *tfs =
2563 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2564 // tracefiles[process_info->cpu];
2566 LttvProcessState
*process
;
2567 process
= lttv_state_find_process(ts
, process_info
->cpu
,
2570 if(unlikely(process
!= NULL
)) {
2572 LttvFilter
*filter
= control_flow_data
->filter
;
2573 if(filter
!= NULL
&& filter
->head
!= NULL
)
2574 if(!lttv_filter_tree_parse(filter
->head
,NULL
,NULL
,
2575 tc
->t
,NULL
,process
,tc
))
2578 /* Only draw for processes that are currently in the trace states */
2581 /* Should be alike when background info is ready */
2582 if(control_flow_data
->background_info_waiting
==0)
2583 g_assert(ltt_time_compare(process
->creation_time
,
2584 process_info
->birth
) == 0);
2585 #endif //EXTRA_CHECK
2587 /* Now, the process is in the state hash and our own process hash.
2588 * We definitely can draw the items related to the ending state.
2591 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2594 TimeWindow time_window
=
2595 lttvwindow_get_time_window(control_flow_data
->tab
);
2598 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2599 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2601 #endif //EXTRA_CHECK
2602 Drawing_t
*drawing
= control_flow_data
->drawing
;
2603 guint width
= drawing
->width
;
2605 guint x
= closure_data
->x_end
;
2607 DrawContext draw_context
;
2609 /* Now create the drawing context that will be used to draw
2610 * items related to the last state. */
2611 draw_context
.drawable
= hashed_process_data
->pixmap
;
2612 draw_context
.gc
= drawing
->gc
;
2613 draw_context
.pango_layout
= drawing
->pango_layout
;
2614 draw_context
.drawinfo
.end
.x
= x
;
2616 draw_context
.drawinfo
.y
.over
= 1;
2617 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2618 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2620 draw_context
.drawinfo
.start
.offset
.over
= 0;
2621 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2622 draw_context
.drawinfo
.start
.offset
.under
= 0;
2623 draw_context
.drawinfo
.end
.offset
.over
= 0;
2624 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2625 draw_context
.drawinfo
.end
.offset
.under
= 0;
2627 /* Jump over draw if we are at the same x position */
2628 if(x
== hashed_process_data
->x
.over
)
2632 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2634 PropertiesLine prop_line
= prepare_execmode_line(process
);
2635 draw_line((void*)&prop_line
, (void*)&draw_context
);
2637 hashed_process_data
->x
.over
= x
;
2641 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2642 hashed_process_data
->x
.middle_used
)) {
2643 #if 0 /* do not mark closure : not missing information */
2644 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2645 /* Draw collision indicator */
2646 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2647 gdk_draw_point(drawing
->pixmap
,
2651 hashed_process_data
->x
.middle_marked
= TRUE
;
2656 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2659 PropertiesLine prop_line
= prepare_s_e_line(process
);
2660 draw_line((void*)&prop_line
, (void*)&draw_context
);
2663 /* become the last x position */
2664 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2665 hashed_process_data
->x
.middle
= x
;
2666 /* but don't use the pixel */
2667 hashed_process_data
->x
.middle_used
= FALSE
;
2669 /* Calculate the next good time */
2670 convert_pixels_to_time(width
, x
+1, time_window
,
2671 &hashed_process_data
->next_good_time
);
2680 int before_chunk(void *hook_data
, void *call_data
)
2682 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2683 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2685 /* Desactivate sort */
2686 gtk_tree_sortable_set_sort_column_id(
2687 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2689 GTK_SORT_ASCENDING
);
2691 drawing_chunk_begin(events_request
, tss
);
2696 int before_request(void *hook_data
, void *call_data
)
2698 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2699 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2701 drawing_data_request_begin(events_request
, tss
);
2708 * after request is necessary in addition of after chunk in order to draw
2709 * lines until the end of the screen. after chunk just draws lines until
2716 int after_request(void *hook_data
, void *call_data
)
2718 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2719 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2720 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2722 ProcessList
*process_list
= control_flow_data
->process_list
;
2723 LttTime end_time
= events_request
->end_time
;
2725 ClosureData closure_data
;
2726 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2727 closure_data
.tss
= tss
;
2728 closure_data
.end_time
= end_time
;
2730 TimeWindow time_window
=
2731 lttvwindow_get_time_window(control_flow_data
->tab
);
2732 guint width
= control_flow_data
->drawing
->width
;
2733 convert_time_to_pixels(
2737 &closure_data
.x_end
);
2740 /* Draw last items */
2741 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2742 (void*)&closure_data
);
2745 /* Request expose */
2746 drawing_request_expose(events_request
, tss
, end_time
);
2755 int after_chunk(void *hook_data
, void *call_data
)
2757 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2758 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2759 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2760 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)call_data
;
2761 LttvTracefileContext
*tfc
= lttv_traceset_context_get_current_tfc(tsc
);
2764 ProcessList
*process_list
= control_flow_data
->process_list
;
2766 LttvTraceset
*traceset
= tsc
->ts
;
2767 guint nb_trace
= lttv_traceset_number(traceset
);
2769 /* Only execute when called for the first trace's events request */
2770 if(!process_list
->current_hash_data
)
2773 for(i
= 0 ; i
< nb_trace
; i
++) {
2774 g_free(process_list
->current_hash_data
[i
]);
2776 g_free(process_list
->current_hash_data
);
2777 process_list
->current_hash_data
= NULL
;
2780 end_time
= LTT_TIME_MIN(tfc
->timestamp
, events_request
->end_time
);
2781 else /* end of traceset, or position now out of request : end */
2782 end_time
= events_request
->end_time
;
2784 ClosureData closure_data
;
2785 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2786 closure_data
.tss
= tss
;
2787 closure_data
.end_time
= end_time
;
2789 TimeWindow time_window
=
2790 lttvwindow_get_time_window(control_flow_data
->tab
);
2791 guint width
= control_flow_data
->drawing
->width
;
2792 convert_time_to_pixels(
2796 &closure_data
.x_end
);
2798 /* Draw last items */
2799 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2800 (void*)&closure_data
);
2802 /* Reactivate sort */
2803 gtk_tree_sortable_set_sort_column_id(
2804 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2805 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2806 GTK_SORT_ASCENDING
);
2808 update_index_to_pixmap(control_flow_data
->process_list
);
2809 /* Request a full expose : drawing scrambled */
2810 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2812 /* Request expose (updates damages zone also) */
2813 drawing_request_expose(events_request
, tss
, end_time
);
2818 /* after_statedump_end
2820 * @param hook_data ControlFlowData structure of the viewer.
2821 * @param call_data Event context.
2823 * This function adds items to be drawn in a queue for each process.
2826 int before_statedump_end(void *hook_data
, void *call_data
)
2828 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2829 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
2830 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2832 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2834 LttvTracesetState
*tss
= (LttvTracesetState
*)tfc
->t_context
->ts_context
;
2835 ProcessList
*process_list
= control_flow_data
->process_list
;
2838 e
= ltt_tracefile_get_event(tfc
->tf
);
2840 LttvFilter
*filter
= control_flow_data
->filter
;
2841 if(filter
!= NULL
&& filter
->head
!= NULL
)
2842 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2843 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2846 LttTime evtime
= ltt_event_time(e
);
2848 ClosureData closure_data
;
2849 closure_data
.events_request
= events_request
;
2850 closure_data
.tss
= tss
;
2851 closure_data
.end_time
= evtime
;
2853 TimeWindow time_window
=
2854 lttvwindow_get_time_window(control_flow_data
->tab
);
2855 guint width
= control_flow_data
->drawing
->width
;
2856 convert_time_to_pixels(
2860 &closure_data
.x_end
);
2862 /* Draw last items */
2863 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2864 (void*)&closure_data
);
2866 /* Reactivate sort */
2867 gtk_tree_sortable_set_sort_column_id(
2868 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2869 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2870 GTK_SORT_ASCENDING
);
2872 update_index_to_pixmap(control_flow_data
->process_list
);
2873 /* Request a full expose : drawing scrambled */
2874 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2876 /* Request expose (updates damages zone also) */
2877 drawing_request_expose(events_request
, tss
, evtime
);