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
521 pid_out
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
522 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
523 state_out
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 2));
526 tfc
->target_pid
= pid_out
;
527 if(!filter
|| !filter
->head
||
528 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
529 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
530 /* For the pid_out */
531 /* First, check if the current process is in the state computation
532 * process list. If it is there, that means we must add it right now and
533 * draw items from the beginning of the read for it. If it is not
534 * present, it's a new process and it was not present : it will
535 * be added after the state update. */
536 guint cpu
= tfs
->cpu
;
537 guint trace_num
= ts
->parent
.index
;
538 LttvProcessState
*process
= ts
->running_process
[cpu
];
539 /* unknown state, bad current pid */
540 if(process
->pid
!= pid_out
)
541 process
= lttv_state_find_process(ts
,
544 if(process
!= NULL
) {
545 /* Well, the process_out existed : we must get it in the process hash
546 * or add it, and draw its items.
548 /* Add process to process list (if not present) */
550 HashedProcessData
*hashed_process_data
= NULL
;
551 ProcessList
*process_list
= control_flow_data
->process_list
;
552 LttTime birth
= process
->creation_time
;
554 hashed_process_data
= processlist_get_process_data(process_list
,
559 if(hashed_process_data
== NULL
)
561 g_assert(pid_out
== 0 || pid_out
!= process
->ppid
);
562 /* Process not present */
563 ProcessInfo
*process_info
;
564 Drawing_t
*drawing
= control_flow_data
->drawing
;
565 processlist_add(process_list
,
577 &hashed_process_data
);
578 gtk_widget_set_size_request(drawing
->drawing_area
,
581 gtk_widget_queue_draw(drawing
->drawing_area
);
585 /* Now, the process is in the state hash and our own process hash.
586 * We definitely can draw the items related to the ending state.
589 if(ltt_time_compare(hashed_process_data
->next_good_time
,
592 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
594 TimeWindow time_window
=
595 lttvwindow_get_time_window(control_flow_data
->tab
);
597 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
598 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
601 Drawing_t
*drawing
= control_flow_data
->drawing
;
602 guint width
= drawing
->width
;
604 convert_time_to_pixels(
610 /* Draw collision indicator */
611 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
612 gdk_draw_point(hashed_process_data
->pixmap
,
615 COLLISION_POSITION(hashed_process_data
->height
));
616 hashed_process_data
->x
.middle_marked
= TRUE
;
619 TimeWindow time_window
=
620 lttvwindow_get_time_window(control_flow_data
->tab
);
622 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
623 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
626 Drawing_t
*drawing
= control_flow_data
->drawing
;
627 guint width
= drawing
->width
;
629 convert_time_to_pixels(
636 /* Jump over draw if we are at the same x position */
637 if(x
== hashed_process_data
->x
.middle
&&
638 hashed_process_data
->x
.middle_used
)
640 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
641 /* Draw collision indicator */
642 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
643 gdk_draw_point(hashed_process_data
->pixmap
,
646 COLLISION_POSITION(hashed_process_data
->height
));
647 hashed_process_data
->x
.middle_marked
= TRUE
;
651 DrawContext draw_context
;
653 /* Now create the drawing context that will be used to draw
654 * items related to the last state. */
655 draw_context
.drawable
= hashed_process_data
->pixmap
;
656 draw_context
.gc
= drawing
->gc
;
657 draw_context
.pango_layout
= drawing
->pango_layout
;
658 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
659 draw_context
.drawinfo
.end
.x
= x
;
661 draw_context
.drawinfo
.y
.over
= 1;
662 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
663 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
665 draw_context
.drawinfo
.start
.offset
.over
= 0;
666 draw_context
.drawinfo
.start
.offset
.middle
= 0;
667 draw_context
.drawinfo
.start
.offset
.under
= 0;
668 draw_context
.drawinfo
.end
.offset
.over
= 0;
669 draw_context
.drawinfo
.end
.offset
.middle
= 0;
670 draw_context
.drawinfo
.end
.offset
.under
= 0;
674 PropertiesLine prop_line
= prepare_s_e_line(process
);
675 draw_line((void*)&prop_line
, (void*)&draw_context
);
678 /* become the last x position */
679 hashed_process_data
->x
.middle
= x
;
680 hashed_process_data
->x
.middle_used
= TRUE
;
681 hashed_process_data
->x
.middle_marked
= FALSE
;
683 /* Calculate the next good time */
684 convert_pixels_to_time(width
, x
+1, time_window
,
685 &hashed_process_data
->next_good_time
);
691 tfc
->target_pid
= pid_in
;
692 if(!filter
|| !filter
->head
||
693 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
694 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
696 /* First, check if the current process is in the state computation
697 * process list. If it is there, that means we must add it right now and
698 * draw items from the beginning of the read for it. If it is not
699 * present, it's a new process and it was not present : it will
700 * be added after the state update. */
701 LttvProcessState
*process
;
702 process
= lttv_state_find_process(ts
,
704 guint trace_num
= ts
->parent
.index
;
706 if(process
!= NULL
) {
707 /* Well, the process existed : we must get it in the process hash
708 * or add it, and draw its items.
710 /* Add process to process list (if not present) */
712 HashedProcessData
*hashed_process_data
= NULL
;
713 ProcessList
*process_list
= control_flow_data
->process_list
;
714 LttTime birth
= process
->creation_time
;
716 hashed_process_data
= processlist_get_process_data(process_list
,
721 if(hashed_process_data
== NULL
)
723 g_assert(pid_in
== 0 || pid_in
!= process
->ppid
);
724 /* Process not present */
725 ProcessInfo
*process_info
;
726 Drawing_t
*drawing
= control_flow_data
->drawing
;
727 processlist_add(process_list
,
739 &hashed_process_data
);
740 gtk_widget_set_size_request(drawing
->drawing_area
,
743 gtk_widget_queue_draw(drawing
->drawing_area
);
746 //We could set the current process and hash here, but will be done
747 //by after schedchange hook
749 /* Now, the process is in the state hash and our own process hash.
750 * We definitely can draw the items related to the ending state.
753 if(ltt_time_compare(hashed_process_data
->next_good_time
,
756 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
758 TimeWindow time_window
=
759 lttvwindow_get_time_window(control_flow_data
->tab
);
761 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
762 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
765 Drawing_t
*drawing
= control_flow_data
->drawing
;
766 guint width
= drawing
->width
;
768 convert_time_to_pixels(
774 /* Draw collision indicator */
775 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
776 gdk_draw_point(hashed_process_data
->pixmap
,
779 COLLISION_POSITION(hashed_process_data
->height
));
780 hashed_process_data
->x
.middle_marked
= TRUE
;
783 TimeWindow time_window
=
784 lttvwindow_get_time_window(control_flow_data
->tab
);
786 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
787 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
790 Drawing_t
*drawing
= control_flow_data
->drawing
;
791 guint width
= drawing
->width
;
794 convert_time_to_pixels(
801 /* Jump over draw if we are at the same x position */
802 if(x
== hashed_process_data
->x
.middle
&&
803 hashed_process_data
->x
.middle_used
)
805 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
806 /* Draw collision indicator */
807 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
808 gdk_draw_point(hashed_process_data
->pixmap
,
811 COLLISION_POSITION(hashed_process_data
->height
));
812 hashed_process_data
->x
.middle_marked
= TRUE
;
816 DrawContext draw_context
;
818 /* Now create the drawing context that will be used to draw
819 * items related to the last state. */
820 draw_context
.drawable
= hashed_process_data
->pixmap
;
821 draw_context
.gc
= drawing
->gc
;
822 draw_context
.pango_layout
= drawing
->pango_layout
;
823 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
824 draw_context
.drawinfo
.end
.x
= x
;
826 draw_context
.drawinfo
.y
.over
= 1;
827 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
828 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
830 draw_context
.drawinfo
.start
.offset
.over
= 0;
831 draw_context
.drawinfo
.start
.offset
.middle
= 0;
832 draw_context
.drawinfo
.start
.offset
.under
= 0;
833 draw_context
.drawinfo
.end
.offset
.over
= 0;
834 draw_context
.drawinfo
.end
.offset
.middle
= 0;
835 draw_context
.drawinfo
.end
.offset
.under
= 0;
839 PropertiesLine prop_line
= prepare_s_e_line(process
);
840 draw_line((void*)&prop_line
, (void*)&draw_context
);
844 /* become the last x position */
845 hashed_process_data
->x
.middle
= x
;
846 hashed_process_data
->x
.middle_used
= TRUE
;
847 hashed_process_data
->x
.middle_marked
= FALSE
;
849 /* Calculate the next good time */
850 convert_pixels_to_time(width
, x
+1, time_window
,
851 &hashed_process_data
->next_good_time
);
855 g_warning("Cannot find pin_in in schedchange %u", pid_in
);
857 tfc
->target_pid
= target_pid_saved
;
865 GString
*string
= g_string_new("");;
866 gboolean field_names
= TRUE
, state
= TRUE
;
868 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
869 g_string_append_printf(string
,"\n");
872 g_string_append_printf(string
, " %s",
873 g_quark_to_string(tfs
->process
->state
->s
));
876 g_info("%s",string
->str
);
878 g_string_free(string
, TRUE
);
880 /* End of text dump */
885 /* after_schedchange_hook
887 * The draw after hook is called by the reading API to have a
888 * particular event drawn on the screen.
889 * @param hook_data ControlFlowData structure of the viewer.
890 * @param call_data Event context.
892 * This function adds items to be drawn in a queue for each process.
895 int after_schedchange_hook(void *hook_data
, void *call_data
)
897 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
898 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
899 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
901 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
903 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
905 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
908 e
= ltt_tracefile_get_event(tfc
->tf
);
910 LttvFilter
*filter
= control_flow_data
->filter
;
911 LttTime evtime
= ltt_event_time(e
);
913 /* Add process to process list (if not present) */
914 LttvProcessState
*process_in
;
917 HashedProcessData
*hashed_process_data_in
= NULL
;
919 ProcessList
*process_list
= control_flow_data
->process_list
;
924 pid_out
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
925 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
928 tfc
->target_pid
= pid_in
;
929 if(!filter
|| !filter
->head
||
930 lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
931 tfc
->t_context
->t
,tfc
,NULL
,NULL
)) {
932 /* Find process pid_in in the list... */
933 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
934 //process_in = tfs->process;
935 guint cpu
= tfs
->cpu
;
936 guint trace_num
= ts
->parent
.index
;
937 process_in
= ts
->running_process
[cpu
];
938 /* It should exist, because we are after the state update. */
940 g_assert(process_in
!= NULL
);
942 birth
= process_in
->creation_time
;
944 hashed_process_data_in
= processlist_get_process_data(process_list
,
949 if(hashed_process_data_in
== NULL
)
951 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
952 ProcessInfo
*process_info
;
953 Drawing_t
*drawing
= control_flow_data
->drawing
;
954 /* Process not present */
955 processlist_add(process_list
,
967 &hashed_process_data_in
);
968 gtk_widget_set_size_request(drawing
->drawing_area
,
971 gtk_widget_queue_draw(drawing
->drawing_area
);
973 /* Set the current process */
974 process_list
->current_hash_data
[trace_num
][process_in
->cpu
] =
975 hashed_process_data_in
;
977 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
980 TimeWindow time_window
=
981 lttvwindow_get_time_window(control_flow_data
->tab
);
984 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
985 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
988 Drawing_t
*drawing
= control_flow_data
->drawing
;
989 guint width
= drawing
->width
;
992 convert_time_to_pixels(
998 if(hashed_process_data_in
->x
.middle
!= new_x
) {
999 hashed_process_data_in
->x
.middle
= new_x
;
1000 hashed_process_data_in
->x
.middle_used
= FALSE
;
1001 hashed_process_data_in
->x
.middle_marked
= FALSE
;
1012 /* before_execmode_hook
1014 * This function basically draw lines and icons. Two types of lines are drawn :
1015 * one small (3 pixels?) representing the state of the process and the second
1016 * type is thicker (10 pixels?) representing on which CPU a process is running
1017 * (and this only in running state).
1019 * Extremums of the lines :
1020 * x_min : time of the last event context for this process kept in memory.
1021 * x_max : time of the current event.
1022 * y : middle of the process in the process list. The process is found in the
1023 * list, therefore is it's position in pixels.
1025 * The choice of lines'color is defined by the context of the last event for this
1030 int before_execmode_hook(void *hook_data
, void *call_data
)
1032 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1033 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1034 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1036 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1038 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1040 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1043 e
= ltt_tracefile_get_event(tfc
->tf
);
1045 LttvFilter
*filter
= control_flow_data
->filter
;
1046 if(filter
!= NULL
&& filter
->head
!= NULL
)
1047 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1048 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1051 LttTime evtime
= ltt_event_time(e
);
1053 /* we are in a execmode, before the state update. We must draw the
1054 * items corresponding to the state before it changes : now is the right
1058 //LttvProcessState *process = tfs->process;
1059 guint cpu
= tfs
->cpu
;
1060 guint trace_num
= ts
->parent
.index
;
1061 LttvProcessState
*process
= ts
->running_process
[cpu
];
1062 g_assert(process
!= NULL
);
1064 guint pid
= process
->pid
;
1066 /* Well, the process_out existed : we must get it in the process hash
1067 * or add it, and draw its items.
1069 /* Add process to process list (if not present) */
1070 guint pl_height
= 0;
1071 HashedProcessData
*hashed_process_data
= NULL
;
1072 ProcessList
*process_list
= control_flow_data
->process_list
;
1073 LttTime birth
= process
->creation_time
;
1075 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1076 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1078 hashed_process_data
= processlist_get_process_data(process_list
,
1083 if(unlikely(hashed_process_data
== NULL
))
1085 g_assert(pid
== 0 || pid
!= process
->ppid
);
1086 ProcessInfo
*process_info
;
1087 /* Process not present */
1088 Drawing_t
*drawing
= control_flow_data
->drawing
;
1089 processlist_add(process_list
,
1101 &hashed_process_data
);
1102 gtk_widget_set_size_request(drawing
->drawing_area
,
1105 gtk_widget_queue_draw(drawing
->drawing_area
);
1107 /* Set the current process */
1108 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1109 hashed_process_data
;
1112 /* Now, the process is in the state hash and our own process hash.
1113 * We definitely can draw the items related to the ending state.
1116 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1119 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1120 TimeWindow time_window
=
1121 lttvwindow_get_time_window(control_flow_data
->tab
);
1124 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1125 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1127 #endif //EXTRA_CHECK
1128 Drawing_t
*drawing
= control_flow_data
->drawing
;
1129 guint width
= drawing
->width
;
1131 convert_time_to_pixels(
1137 /* Draw collision indicator */
1138 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1139 gdk_draw_point(hashed_process_data
->pixmap
,
1142 COLLISION_POSITION(hashed_process_data
->height
));
1143 hashed_process_data
->x
.middle_marked
= TRUE
;
1146 TimeWindow time_window
=
1147 lttvwindow_get_time_window(control_flow_data
->tab
);
1150 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1151 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1153 #endif //EXTRA_CHECK
1154 Drawing_t
*drawing
= control_flow_data
->drawing
;
1155 guint width
= drawing
->width
;
1158 convert_time_to_pixels(
1165 /* Jump over draw if we are at the same x position */
1166 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1167 hashed_process_data
->x
.middle_used
))
1169 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1170 /* Draw collision indicator */
1171 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1172 gdk_draw_point(hashed_process_data
->pixmap
,
1175 COLLISION_POSITION(hashed_process_data
->height
));
1176 hashed_process_data
->x
.middle_marked
= TRUE
;
1181 DrawContext draw_context
;
1182 /* Now create the drawing context that will be used to draw
1183 * items related to the last state. */
1184 draw_context
.drawable
= hashed_process_data
->pixmap
;
1185 draw_context
.gc
= drawing
->gc
;
1186 draw_context
.pango_layout
= drawing
->pango_layout
;
1187 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1188 draw_context
.drawinfo
.end
.x
= x
;
1190 draw_context
.drawinfo
.y
.over
= 1;
1191 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1192 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1194 draw_context
.drawinfo
.start
.offset
.over
= 0;
1195 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1196 draw_context
.drawinfo
.start
.offset
.under
= 0;
1197 draw_context
.drawinfo
.end
.offset
.over
= 0;
1198 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1199 draw_context
.drawinfo
.end
.offset
.under
= 0;
1203 PropertiesLine prop_line
= prepare_s_e_line(process
);
1204 draw_line((void*)&prop_line
, (void*)&draw_context
);
1207 /* become the last x position */
1208 hashed_process_data
->x
.middle
= x
;
1209 hashed_process_data
->x
.middle_used
= TRUE
;
1210 hashed_process_data
->x
.middle_marked
= FALSE
;
1212 /* Calculate the next good time */
1213 convert_pixels_to_time(width
, x
+1, time_window
,
1214 &hashed_process_data
->next_good_time
);
1221 /* before_process_exit_hook
1223 * Draw lines for process event.
1225 * @param hook_data ControlFlowData structure of the viewer.
1226 * @param call_data Event context.
1228 * This function adds items to be drawn in a queue for each process.
1233 int before_process_exit_hook(void *hook_data
, void *call_data
)
1235 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1236 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1238 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1240 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1242 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1244 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1247 e
= ltt_tracefile_get_event(tfc
->tf
);
1249 LttvFilter
*filter
= control_flow_data
->filter
;
1250 if(filter
!= NULL
&& filter
->head
!= NULL
)
1251 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1252 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1255 LttTime evtime
= ltt_event_time(e
);
1257 /* Add process to process list (if not present) */
1258 //LttvProcessState *process = tfs->process;
1259 guint cpu
= tfs
->cpu
;
1260 guint trace_num
= ts
->parent
.index
;
1261 LttvProcessState
*process
= ts
->running_process
[cpu
];
1262 guint pid
= process
->pid
;
1264 guint pl_height
= 0;
1265 HashedProcessData
*hashed_process_data
= NULL
;
1267 ProcessList
*process_list
= control_flow_data
->process_list
;
1269 g_assert(process
!= NULL
);
1271 birth
= process
->creation_time
;
1273 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1274 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1276 hashed_process_data
= processlist_get_process_data(process_list
,
1281 if(unlikely(hashed_process_data
== NULL
))
1283 g_assert(pid
== 0 || pid
!= process
->ppid
);
1284 /* Process not present */
1285 Drawing_t
*drawing
= control_flow_data
->drawing
;
1286 ProcessInfo
*process_info
;
1287 processlist_add(process_list
,
1299 &hashed_process_data
);
1300 gtk_widget_set_size_request(drawing
->drawing_area
,
1303 gtk_widget_queue_draw(drawing
->drawing_area
);
1307 /* Now, the process is in the state hash and our own process hash.
1308 * We definitely can draw the items related to the ending state.
1311 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1314 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1315 TimeWindow time_window
=
1316 lttvwindow_get_time_window(control_flow_data
->tab
);
1319 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1320 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1322 #endif //EXTRA_CHECK
1323 Drawing_t
*drawing
= control_flow_data
->drawing
;
1324 guint width
= drawing
->width
;
1326 convert_time_to_pixels(
1332 /* Draw collision indicator */
1333 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1334 gdk_draw_point(hashed_process_data
->pixmap
,
1337 COLLISION_POSITION(hashed_process_data
->height
));
1338 hashed_process_data
->x
.middle_marked
= TRUE
;
1341 TimeWindow time_window
=
1342 lttvwindow_get_time_window(control_flow_data
->tab
);
1345 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1346 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1348 #endif //EXTRA_CHECK
1349 Drawing_t
*drawing
= control_flow_data
->drawing
;
1350 guint width
= drawing
->width
;
1353 convert_time_to_pixels(
1360 /* Jump over draw if we are at the same x position */
1361 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1362 hashed_process_data
->x
.middle_used
))
1364 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1365 /* Draw collision indicator */
1366 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1367 gdk_draw_point(hashed_process_data
->pixmap
,
1370 COLLISION_POSITION(hashed_process_data
->height
));
1371 hashed_process_data
->x
.middle_marked
= TRUE
;
1375 DrawContext draw_context
;
1377 /* Now create the drawing context that will be used to draw
1378 * items related to the last state. */
1379 draw_context
.drawable
= hashed_process_data
->pixmap
;
1380 draw_context
.gc
= drawing
->gc
;
1381 draw_context
.pango_layout
= drawing
->pango_layout
;
1382 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1383 draw_context
.drawinfo
.end
.x
= x
;
1385 draw_context
.drawinfo
.y
.over
= 1;
1386 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1387 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1389 draw_context
.drawinfo
.start
.offset
.over
= 0;
1390 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1391 draw_context
.drawinfo
.start
.offset
.under
= 0;
1392 draw_context
.drawinfo
.end
.offset
.over
= 0;
1393 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1394 draw_context
.drawinfo
.end
.offset
.under
= 0;
1398 PropertiesLine prop_line
= prepare_s_e_line(process
);
1399 draw_line((void*)&prop_line
, (void*)&draw_context
);
1402 /* become the last x position */
1403 hashed_process_data
->x
.middle
= x
;
1404 hashed_process_data
->x
.middle_used
= TRUE
;
1405 hashed_process_data
->x
.middle_marked
= FALSE
;
1407 /* Calculate the next good time */
1408 convert_pixels_to_time(width
, x
+1, time_window
,
1409 &hashed_process_data
->next_good_time
);
1419 /* before_process_release_hook
1421 * Draw lines for process event.
1423 * @param hook_data ControlFlowData structure of the viewer.
1424 * @param call_data Event context.
1426 * This function adds items to be drawn in a queue for each process.
1431 int before_process_release_hook(void *hook_data
, void *call_data
)
1433 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1434 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1436 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1438 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1440 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1443 e
= ltt_tracefile_get_event(tfc
->tf
);
1445 LttvFilter
*filter
= control_flow_data
->filter
;
1446 if(filter
!= NULL
&& filter
->head
!= NULL
)
1447 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1448 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1451 LttTime evtime
= ltt_event_time(e
);
1453 guint trace_num
= ts
->parent
.index
;
1457 pid
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
1460 /* Add process to process list (if not present) */
1461 /* Don't care about the process if it's not in the state hash already :
1462 * that means a process that has never done anything in the trace and
1463 * unknown suddently gets destroyed : no state meaningful to show. */
1464 LttvProcessState
*process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1466 if(process
!= NULL
) {
1468 HashedProcessData
*hashed_process_data
= NULL
;
1470 ProcessList
*process_list
= control_flow_data
->process_list
;
1472 birth
= process
->creation_time
;
1474 /* Cannot use current process : this event happens on another process,
1475 * action done by the parent. */
1476 hashed_process_data
= processlist_get_process_data(process_list
,
1481 if(unlikely(hashed_process_data
== NULL
))
1483 * Process already been scheduled out EXIT_DEAD, not in the process list
1484 * anymore. Just return.
1488 /* Now, the process is in the state hash and our own process hash.
1489 * We definitely can draw the items related to the ending state.
1492 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1495 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1496 TimeWindow time_window
=
1497 lttvwindow_get_time_window(control_flow_data
->tab
);
1500 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1501 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1503 #endif //EXTRA_CHECK
1504 Drawing_t
*drawing
= control_flow_data
->drawing
;
1505 guint width
= drawing
->width
;
1507 convert_time_to_pixels(
1513 /* Draw collision indicator */
1514 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1515 gdk_draw_point(hashed_process_data
->pixmap
,
1518 COLLISION_POSITION(hashed_process_data
->height
));
1519 hashed_process_data
->x
.middle_marked
= TRUE
;
1522 TimeWindow time_window
=
1523 lttvwindow_get_time_window(control_flow_data
->tab
);
1526 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1527 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1529 #endif //EXTRA_CHECK
1530 Drawing_t
*drawing
= control_flow_data
->drawing
;
1531 guint width
= drawing
->width
;
1534 convert_time_to_pixels(
1541 /* Jump over draw if we are at the same x position */
1542 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1543 hashed_process_data
->x
.middle_used
))
1545 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1546 /* Draw collision indicator */
1547 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1548 gdk_draw_point(hashed_process_data
->pixmap
,
1551 COLLISION_POSITION(hashed_process_data
->height
));
1552 hashed_process_data
->x
.middle_marked
= TRUE
;
1556 DrawContext draw_context
;
1558 /* Now create the drawing context that will be used to draw
1559 * items related to the last state. */
1560 draw_context
.drawable
= hashed_process_data
->pixmap
;
1561 draw_context
.gc
= drawing
->gc
;
1562 draw_context
.pango_layout
= drawing
->pango_layout
;
1563 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1564 draw_context
.drawinfo
.end
.x
= x
;
1566 draw_context
.drawinfo
.y
.over
= 1;
1567 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1568 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1570 draw_context
.drawinfo
.start
.offset
.over
= 0;
1571 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1572 draw_context
.drawinfo
.start
.offset
.under
= 0;
1573 draw_context
.drawinfo
.end
.offset
.over
= 0;
1574 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1575 draw_context
.drawinfo
.end
.offset
.under
= 0;
1579 PropertiesLine prop_line
= prepare_s_e_line(process
);
1580 draw_line((void*)&prop_line
, (void*)&draw_context
);
1583 /* become the last x position */
1584 hashed_process_data
->x
.middle
= x
;
1585 hashed_process_data
->x
.middle_used
= TRUE
;
1586 hashed_process_data
->x
.middle_marked
= FALSE
;
1588 /* Calculate the next good time */
1589 convert_pixels_to_time(width
, x
+1, time_window
,
1590 &hashed_process_data
->next_good_time
);
1602 /* after_process_fork_hook
1604 * Create the processlist entry for the child process. Put the last
1605 * position in x at the current time value.
1607 * @param hook_data ControlFlowData structure of the viewer.
1608 * @param call_data Event context.
1610 * This function adds items to be drawn in a queue for each process.
1613 int after_process_fork_hook(void *hook_data
, void *call_data
)
1615 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1616 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1617 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1619 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1621 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1624 e
= ltt_tracefile_get_event(tfc
->tf
);
1626 LttvFilter
*filter
= control_flow_data
->filter
;
1627 if(filter
!= NULL
&& filter
->head
!= NULL
)
1628 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1629 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1632 LttTime evtime
= ltt_event_time(e
);
1636 child_pid
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
1639 /* Add process to process list (if not present) */
1640 LttvProcessState
*process_child
;
1642 guint pl_height
= 0;
1643 HashedProcessData
*hashed_process_data_child
= NULL
;
1645 ProcessList
*process_list
= control_flow_data
->process_list
;
1647 /* Find child in the list... */
1648 process_child
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1649 /* It should exist, because we are after the state update. */
1650 g_assert(process_child
!= NULL
);
1652 birth
= process_child
->creation_time
;
1653 guint trace_num
= ts
->parent
.index
;
1655 /* Cannot use current process, because this action is done by the parent
1657 hashed_process_data_child
= processlist_get_process_data(process_list
,
1662 if(likely(hashed_process_data_child
== NULL
))
1664 g_assert(child_pid
== 0 || child_pid
!= process_child
->ppid
);
1665 /* Process not present */
1666 Drawing_t
*drawing
= control_flow_data
->drawing
;
1667 ProcessInfo
*process_info
;
1668 processlist_add(process_list
,
1671 process_child
->tgid
,
1673 process_child
->ppid
,
1676 process_child
->name
,
1677 process_child
->brand
,
1680 &hashed_process_data_child
);
1681 gtk_widget_set_size_request(drawing
->drawing_area
,
1684 gtk_widget_queue_draw(drawing
->drawing_area
);
1686 processlist_set_ppid(process_list
, process_child
->ppid
,
1687 hashed_process_data_child
);
1688 processlist_set_tgid(process_list
, process_child
->tgid
,
1689 hashed_process_data_child
);
1693 if(likely(ltt_time_compare(hashed_process_data_child
->next_good_time
,
1696 TimeWindow time_window
=
1697 lttvwindow_get_time_window(control_flow_data
->tab
);
1700 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1701 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1703 #endif //EXTRA_CHECK
1704 Drawing_t
*drawing
= control_flow_data
->drawing
;
1705 guint width
= drawing
->width
;
1707 convert_time_to_pixels(
1713 if(likely(hashed_process_data_child
->x
.over
!= new_x
)) {
1714 hashed_process_data_child
->x
.over
= new_x
;
1715 hashed_process_data_child
->x
.over_used
= FALSE
;
1716 hashed_process_data_child
->x
.over_marked
= FALSE
;
1718 if(likely(hashed_process_data_child
->x
.middle
!= new_x
)) {
1719 hashed_process_data_child
->x
.middle
= new_x
;
1720 hashed_process_data_child
->x
.middle_used
= FALSE
;
1721 hashed_process_data_child
->x
.middle_marked
= FALSE
;
1723 if(likely(hashed_process_data_child
->x
.under
!= new_x
)) {
1724 hashed_process_data_child
->x
.under
= new_x
;
1725 hashed_process_data_child
->x
.under_used
= FALSE
;
1726 hashed_process_data_child
->x
.under_marked
= FALSE
;
1734 /* after_process_exit_hook
1736 * Create the processlist entry for the child process. Put the last
1737 * position in x at the current time value.
1739 * @param hook_data ControlFlowData structure of the viewer.
1740 * @param call_data Event context.
1742 * This function adds items to be drawn in a queue for each process.
1745 int after_process_exit_hook(void *hook_data
, void *call_data
)
1747 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1748 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1749 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1751 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1753 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1755 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1758 e
= ltt_tracefile_get_event(tfc
->tf
);
1760 LttvFilter
*filter
= control_flow_data
->filter
;
1761 if(filter
!= NULL
&& filter
->head
!= NULL
)
1762 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1763 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1766 LttTime evtime
= ltt_event_time(e
);
1768 /* Add process to process list (if not present) */
1769 //LttvProcessState *process = tfs->process;
1770 guint cpu
= tfs
->cpu
;
1771 guint trace_num
= ts
->parent
.index
;
1772 LttvProcessState
*process
= ts
->running_process
[cpu
];
1774 /* It should exist, because we are after the state update. */
1775 g_assert(process
!= NULL
);
1777 guint pid
= process
->pid
;
1779 guint pl_height
= 0;
1780 HashedProcessData
*hashed_process_data
= NULL
;
1782 ProcessList
*process_list
= control_flow_data
->process_list
;
1784 birth
= process
->creation_time
;
1786 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
) ){
1787 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1789 hashed_process_data
= processlist_get_process_data(process_list
,
1794 if(unlikely(hashed_process_data
== NULL
))
1796 g_assert(pid
== 0 || pid
!= process
->ppid
);
1797 /* Process not present */
1798 Drawing_t
*drawing
= control_flow_data
->drawing
;
1799 ProcessInfo
*process_info
;
1800 processlist_add(process_list
,
1812 &hashed_process_data
);
1813 gtk_widget_set_size_request(drawing
->drawing_area
,
1816 gtk_widget_queue_draw(drawing
->drawing_area
);
1819 /* Set the current process */
1820 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1821 hashed_process_data
;
1824 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
1827 TimeWindow time_window
=
1828 lttvwindow_get_time_window(control_flow_data
->tab
);
1831 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1832 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1834 #endif //EXTRA_CHECK
1835 Drawing_t
*drawing
= control_flow_data
->drawing
;
1836 guint width
= drawing
->width
;
1838 convert_time_to_pixels(
1843 if(unlikely(hashed_process_data
->x
.middle
!= new_x
)) {
1844 hashed_process_data
->x
.middle
= new_x
;
1845 hashed_process_data
->x
.middle_used
= FALSE
;
1846 hashed_process_data
->x
.middle_marked
= FALSE
;
1854 /* Get the filename of the process to print */
1855 int after_fs_exec_hook(void *hook_data
, void *call_data
)
1857 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1858 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1859 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1861 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1863 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1865 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1868 e
= ltt_tracefile_get_event(tfc
->tf
);
1870 LttvFilter
*filter
= control_flow_data
->filter
;
1871 if(filter
!= NULL
&& filter
->head
!= NULL
)
1872 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1873 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1876 guint cpu
= tfs
->cpu
;
1877 guint trace_num
= ts
->parent
.index
;
1878 LttvProcessState
*process
= ts
->running_process
[cpu
];
1879 g_assert(process
!= NULL
);
1881 guint pid
= process
->pid
;
1883 /* Well, the process_out existed : we must get it in the process hash
1884 * or add it, and draw its items.
1886 /* Add process to process list (if not present) */
1887 guint pl_height
= 0;
1888 HashedProcessData
*hashed_process_data
= NULL
;
1889 ProcessList
*process_list
= control_flow_data
->process_list
;
1890 LttTime birth
= process
->creation_time
;
1892 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1893 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1895 hashed_process_data
= processlist_get_process_data(process_list
,
1900 if(unlikely(hashed_process_data
== NULL
))
1902 g_assert(pid
== 0 || pid
!= process
->ppid
);
1903 ProcessInfo
*process_info
;
1904 /* Process not present */
1905 Drawing_t
*drawing
= control_flow_data
->drawing
;
1906 processlist_add(process_list
,
1918 &hashed_process_data
);
1919 gtk_widget_set_size_request(drawing
->drawing_area
,
1922 gtk_widget_queue_draw(drawing
->drawing_area
);
1924 /* Set the current process */
1925 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1926 hashed_process_data
;
1929 processlist_set_name(process_list
, process
->name
, hashed_process_data
);
1935 /* Get the filename of the process to print */
1936 int after_user_generic_thread_brand_hook(void *hook_data
, void *call_data
)
1938 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1939 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1940 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1942 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1944 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1946 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1949 e
= ltt_tracefile_get_event(tfc
->tf
);
1951 LttvFilter
*filter
= control_flow_data
->filter
;
1952 if(filter
!= NULL
&& filter
->head
!= NULL
)
1953 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
1954 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
1957 guint cpu
= tfs
->cpu
;
1958 guint trace_num
= ts
->parent
.index
;
1959 LttvProcessState
*process
= ts
->running_process
[cpu
];
1960 g_assert(process
!= NULL
);
1962 guint pid
= process
->pid
;
1964 /* Well, the process_out existed : we must get it in the process hash
1965 * or add it, and draw its items.
1967 /* Add process to process list (if not present) */
1968 guint pl_height
= 0;
1969 HashedProcessData
*hashed_process_data
= NULL
;
1970 ProcessList
*process_list
= control_flow_data
->process_list
;
1971 LttTime birth
= process
->creation_time
;
1973 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1974 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1976 hashed_process_data
= processlist_get_process_data(process_list
,
1981 if(unlikely(hashed_process_data
== NULL
))
1983 g_assert(pid
== 0 || pid
!= process
->ppid
);
1984 ProcessInfo
*process_info
;
1985 /* Process not present */
1986 Drawing_t
*drawing
= control_flow_data
->drawing
;
1987 processlist_add(process_list
,
1999 &hashed_process_data
);
2000 gtk_widget_set_size_request(drawing
->drawing_area
,
2003 gtk_widget_queue_draw(drawing
->drawing_area
);
2005 /* Set the current process */
2006 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
2007 hashed_process_data
;
2010 processlist_set_brand(process_list
, process
->brand
, hashed_process_data
);
2017 /* after_event_enum_process_hook
2019 * Create the processlist entry for the child process. Put the last
2020 * position in x at the current time value.
2022 * @param hook_data ControlFlowData structure of the viewer.
2023 * @param call_data Event context.
2025 * This function adds items to be drawn in a queue for each process.
2028 int after_event_enum_process_hook(void *hook_data
, void *call_data
)
2030 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2031 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
2032 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2034 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2036 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
2038 guint first_cpu
, nb_cpus
, cpu
;
2041 e
= ltt_tracefile_get_event(tfc
->tf
);
2043 LttvFilter
*filter
= control_flow_data
->filter
;
2044 if(filter
!= NULL
&& filter
->head
!= NULL
)
2045 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2046 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2049 /* Add process to process list (if not present) */
2050 LttvProcessState
*process_in
;
2052 guint pl_height
= 0;
2053 HashedProcessData
*hashed_process_data_in
= NULL
;
2055 ProcessList
*process_list
= control_flow_data
->process_list
;
2056 guint trace_num
= ts
->parent
.index
;
2060 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
2065 nb_cpus
= ltt_trace_get_num_cpu(ts
->parent
.t
);
2067 first_cpu
= ANY_CPU
;
2068 nb_cpus
= ANY_CPU
+1;
2071 for(cpu
= first_cpu
; cpu
< nb_cpus
; cpu
++) {
2072 /* Find process pid_in in the list... */
2073 process_in
= lttv_state_find_process(ts
, cpu
, pid_in
);
2074 //process_in = tfs->process;
2075 //guint cpu = tfs->cpu;
2076 //guint trace_num = ts->parent.index;
2077 //process_in = ts->running_process[cpu];
2078 /* It should exist, because we are after the state update. */
2080 //g_assert(process_in != NULL);
2081 #endif //EXTRA_CHECK
2082 birth
= process_in
->creation_time
;
2084 hashed_process_data_in
= processlist_get_process_data(process_list
,
2089 if(hashed_process_data_in
== NULL
)
2091 if(pid_in
!= 0 && pid_in
== process_in
->ppid
)
2092 g_critical("TEST %u , %u", pid_in
, process_in
->ppid
);
2093 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
2094 ProcessInfo
*process_info
;
2095 Drawing_t
*drawing
= control_flow_data
->drawing
;
2096 /* Process not present */
2097 processlist_add(process_list
,
2109 &hashed_process_data_in
);
2110 gtk_widget_set_size_request(drawing
->drawing_area
,
2113 gtk_widget_queue_draw(drawing
->drawing_area
);
2115 processlist_set_name(process_list
, process_in
->name
,
2116 hashed_process_data_in
);
2117 processlist_set_ppid(process_list
, process_in
->ppid
,
2118 hashed_process_data_in
);
2119 processlist_set_tgid(process_list
, process_in
->tgid
,
2120 hashed_process_data_in
);
2127 gint
update_time_window_hook(void *hook_data
, void *call_data
)
2129 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2130 Drawing_t
*drawing
= control_flow_data
->drawing
;
2131 ProcessList
*process_list
= control_flow_data
->process_list
;
2133 const TimeWindowNotifyData
*time_window_nofify_data
=
2134 ((const TimeWindowNotifyData
*)call_data
);
2136 TimeWindow
*old_time_window
=
2137 time_window_nofify_data
->old_time_window
;
2138 TimeWindow
*new_time_window
=
2139 time_window_nofify_data
->new_time_window
;
2141 /* Update the ruler */
2142 drawing_update_ruler(control_flow_data
->drawing
,
2146 /* Two cases : zoom in/out or scrolling */
2148 /* In order to make sure we can reuse the old drawing, the scale must
2149 * be the same and the new time interval being partly located in the
2150 * currently shown time interval. (reuse is only for scrolling)
2153 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
2154 old_time_window
->start_time
.tv_sec
,
2155 old_time_window
->start_time
.tv_nsec
,
2156 old_time_window
->time_width
.tv_sec
,
2157 old_time_window
->time_width
.tv_nsec
);
2159 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
2160 new_time_window
->start_time
.tv_sec
,
2161 new_time_window
->start_time
.tv_nsec
,
2162 new_time_window
->time_width
.tv_sec
,
2163 new_time_window
->time_width
.tv_nsec
);
2165 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
2166 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
2168 /* Same scale (scrolling) */
2169 g_info("scrolling");
2170 LttTime
*ns
= &new_time_window
->start_time
;
2171 LttTime
*os
= &old_time_window
->start_time
;
2172 LttTime old_end
= old_time_window
->end_time
;
2173 LttTime new_end
= new_time_window
->end_time
;
2175 //if(ns<os+w && os+w<ns+w)
2176 //if(ns<old_end && os<ns)
2177 if(ltt_time_compare(*ns
, old_end
) == -1
2178 && ltt_time_compare(*os
, *ns
) == -1)
2180 g_info("scrolling near right");
2181 /* Scroll right, keep right part of the screen */
2183 guint width
= control_flow_data
->drawing
->width
;
2184 convert_time_to_pixels(
2190 /* Copy old data to new location */
2191 copy_pixmap_region(process_list
,
2193 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2197 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
2199 if(drawing
->damage_begin
== drawing
->damage_end
)
2200 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
2202 drawing
->damage_begin
= 0;
2204 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2206 /* Clear the data request background, but not SAFETY */
2207 rectangle_pixmap(process_list
,
2208 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2210 drawing
->damage_begin
+SAFETY
, 0,
2211 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2213 gtk_widget_queue_draw(drawing
->drawing_area
);
2214 //gtk_widget_queue_draw_area (drawing->drawing_area,
2216 // control_flow_data->drawing->width,
2217 // control_flow_data->drawing->height);
2219 /* Get new data for the rest. */
2220 drawing_data_request(control_flow_data
->drawing
,
2221 drawing
->damage_begin
, 0,
2222 drawing
->damage_end
- drawing
->damage_begin
,
2223 control_flow_data
->drawing
->height
);
2226 //if(ns<os && os<ns+w)
2227 //if(ns<os && os<new_end)
2228 if(ltt_time_compare(*ns
,*os
) == -1
2229 && ltt_time_compare(*os
,new_end
) == -1)
2231 g_info("scrolling near left");
2232 /* Scroll left, keep left part of the screen */
2234 guint width
= control_flow_data
->drawing
->width
;
2235 convert_time_to_pixels(
2241 /* Copy old data to new location */
2242 copy_pixmap_region (process_list
,
2244 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2250 if(drawing
->damage_begin
== drawing
->damage_end
)
2251 drawing
->damage_end
= x
;
2253 drawing
->damage_end
=
2254 control_flow_data
->drawing
->width
;
2256 drawing
->damage_begin
= 0;
2258 rectangle_pixmap (process_list
,
2259 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2261 drawing
->damage_begin
, 0,
2262 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2265 gtk_widget_queue_draw(drawing
->drawing_area
);
2266 //gtk_widget_queue_draw_area (drawing->drawing_area,
2268 // control_flow_data->drawing->width,
2269 // control_flow_data->drawing->height);
2272 /* Get new data for the rest. */
2273 drawing_data_request(control_flow_data
->drawing
,
2274 drawing
->damage_begin
, 0,
2275 drawing
->damage_end
- drawing
->damage_begin
,
2276 control_flow_data
->drawing
->height
);
2279 if(ltt_time_compare(*ns
,*os
) == 0)
2281 g_info("not scrolling");
2283 g_info("scrolling far");
2284 /* Cannot reuse any part of the screen : far jump */
2287 rectangle_pixmap (process_list
,
2288 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2291 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2294 //gtk_widget_queue_draw_area (drawing->drawing_area,
2296 // control_flow_data->drawing->width,
2297 // control_flow_data->drawing->height);
2298 gtk_widget_queue_draw(drawing
->drawing_area
);
2300 drawing
->damage_begin
= 0;
2301 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2303 drawing_data_request(control_flow_data
->drawing
,
2305 control_flow_data
->drawing
->width
,
2306 control_flow_data
->drawing
->height
);
2312 /* Different scale (zoom) */
2315 rectangle_pixmap (process_list
,
2316 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2319 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2322 //gtk_widget_queue_draw_area (drawing->drawing_area,
2324 // control_flow_data->drawing->width,
2325 // control_flow_data->drawing->height);
2326 gtk_widget_queue_draw(drawing
->drawing_area
);
2328 drawing
->damage_begin
= 0;
2329 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2331 drawing_data_request(control_flow_data
->drawing
,
2333 control_flow_data
->drawing
->width
,
2334 control_flow_data
->drawing
->height
);
2337 /* Update directly when scrolling */
2338 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2344 gint
traceset_notify(void *hook_data
, void *call_data
)
2346 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2347 Drawing_t
*drawing
= control_flow_data
->drawing
;
2349 if(unlikely(drawing
->gc
== NULL
)) {
2352 if(drawing
->dotted_gc
== NULL
) {
2356 drawing_clear(control_flow_data
->drawing
);
2357 processlist_clear(control_flow_data
->process_list
);
2358 gtk_widget_set_size_request(
2359 control_flow_data
->drawing
->drawing_area
,
2360 -1, processlist_get_height(control_flow_data
->process_list
));
2361 redraw_notify(control_flow_data
, NULL
);
2363 request_background_data(control_flow_data
);
2368 gint
redraw_notify(void *hook_data
, void *call_data
)
2370 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2371 Drawing_t
*drawing
= control_flow_data
->drawing
;
2372 GtkWidget
*widget
= drawing
->drawing_area
;
2374 drawing
->damage_begin
= 0;
2375 drawing
->damage_end
= drawing
->width
;
2377 /* fun feature, to be separated someday... */
2378 drawing_clear(control_flow_data
->drawing
);
2379 processlist_clear(control_flow_data
->process_list
);
2380 gtk_widget_set_size_request(
2381 control_flow_data
->drawing
->drawing_area
,
2382 -1, processlist_get_height(control_flow_data
->process_list
));
2384 rectangle_pixmap (control_flow_data
->process_list
,
2385 widget
->style
->black_gc
,
2388 drawing
->alloc_width
,
2391 gtk_widget_queue_draw(drawing
->drawing_area
);
2393 if(drawing
->damage_begin
< drawing
->damage_end
)
2395 drawing_data_request(drawing
,
2396 drawing
->damage_begin
,
2398 drawing
->damage_end
-drawing
->damage_begin
,
2402 //gtk_widget_queue_draw_area(drawing->drawing_area,
2405 // drawing->height);
2411 gint
continue_notify(void *hook_data
, void *call_data
)
2413 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2414 Drawing_t
*drawing
= control_flow_data
->drawing
;
2416 //g_assert(widget->allocation.width == drawing->damage_end);
2418 if(drawing
->damage_begin
< drawing
->damage_end
)
2420 drawing_data_request(drawing
,
2421 drawing
->damage_begin
,
2423 drawing
->damage_end
-drawing
->damage_begin
,
2431 gint
update_current_time_hook(void *hook_data
, void *call_data
)
2433 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
2435 LttTime current_time
= *((LttTime
*)call_data
);
2437 TimeWindow time_window
=
2438 lttvwindow_get_time_window(control_flow_data
->tab
);
2440 LttTime time_begin
= time_window
.start_time
;
2441 LttTime width
= time_window
.time_width
;
2444 guint64 time_ll
= ltt_time_to_uint64(width
);
2445 time_ll
= time_ll
>> 1; /* divide by two */
2446 half_width
= ltt_time_from_uint64(time_ll
);
2448 LttTime time_end
= ltt_time_add(time_begin
, width
);
2450 LttvTracesetContext
* tsc
=
2451 lttvwindow_get_traceset_context(control_flow_data
->tab
);
2453 LttTime trace_start
= tsc
->time_span
.start_time
;
2454 LttTime trace_end
= tsc
->time_span
.end_time
;
2456 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
2457 current_time
.tv_nsec
);
2461 /* If current time is inside time interval, just move the highlight
2464 /* Else, we have to change the time interval. We have to tell it
2465 * to the main window. */
2466 /* The time interval change will take care of placing the current
2467 * time at the center of the visible area, or nearest possible if we are
2468 * at one end of the trace. */
2471 if(ltt_time_compare(current_time
, time_begin
) < 0)
2473 TimeWindow new_time_window
;
2475 if(ltt_time_compare(current_time
,
2476 ltt_time_add(trace_start
,half_width
)) < 0)
2477 time_begin
= trace_start
;
2479 time_begin
= ltt_time_sub(current_time
,half_width
);
2481 new_time_window
.start_time
= time_begin
;
2482 new_time_window
.time_width
= width
;
2483 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2484 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2486 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2488 else if(ltt_time_compare(current_time
, time_end
) > 0)
2490 TimeWindow new_time_window
;
2492 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
2493 time_begin
= ltt_time_sub(trace_end
,width
);
2495 time_begin
= ltt_time_sub(current_time
,half_width
);
2497 new_time_window
.start_time
= time_begin
;
2498 new_time_window
.time_width
= width
;
2499 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2500 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2502 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2505 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2507 /* Update directly when scrolling */
2508 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2514 typedef struct _ClosureData
{
2515 EventsRequest
*events_request
;
2516 LttvTracesetState
*tss
;
2522 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
2524 ProcessInfo
*process_info
= (ProcessInfo
*)key
;
2525 HashedProcessData
*hashed_process_data
= (HashedProcessData
*)value
;
2526 ClosureData
*closure_data
= (ClosureData
*)user_data
;
2528 EventsRequest
*events_request
= closure_data
->events_request
;
2529 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2531 LttvTracesetState
*tss
= closure_data
->tss
;
2532 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)tss
;
2534 LttTime evtime
= closure_data
->end_time
;
2536 gboolean dodraw
= TRUE
;
2539 /* For the process */
2540 /* First, check if the current process is in the state computation
2541 * process list. If it is there, that means we must add it right now and
2542 * draw items from the beginning of the read for it. If it is not
2543 * present, it's a new process and it was not present : it will
2544 * be added after the state update. */
2546 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
2547 #endif //EXTRA_CHECK
2548 LttvTraceContext
*tc
= tsc
->traces
[process_info
->trace_num
];
2549 LttvTraceState
*ts
= (LttvTraceState
*)tc
;
2552 //FIXME : optimize data structures.
2553 LttvTracefileState
*tfs
;
2554 LttvTracefileContext
*tfc
;
2556 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
2557 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
2558 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
2559 && tfs
->cpu
== process_info
->cpu
)
2563 g_assert(i
<tc
->tracefiles
->len
);
2564 tfs
= LTTV_TRACEFILE_STATE(tfc
);
2566 // LttvTracefileState *tfs =
2567 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2568 // tracefiles[process_info->cpu];
2570 LttvProcessState
*process
;
2571 process
= lttv_state_find_process(ts
, process_info
->cpu
,
2574 if(unlikely(process
!= NULL
)) {
2576 LttvFilter
*filter
= control_flow_data
->filter
;
2577 if(filter
!= NULL
&& filter
->head
!= NULL
)
2578 if(!lttv_filter_tree_parse(filter
->head
,NULL
,NULL
,
2579 tc
->t
,NULL
,process
,tc
))
2582 /* Only draw for processes that are currently in the trace states */
2585 /* Should be alike when background info is ready */
2586 if(control_flow_data
->background_info_waiting
==0)
2587 g_assert(ltt_time_compare(process
->creation_time
,
2588 process_info
->birth
) == 0);
2589 #endif //EXTRA_CHECK
2591 /* Now, the process is in the state hash and our own process hash.
2592 * We definitely can draw the items related to the ending state.
2595 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2598 TimeWindow time_window
=
2599 lttvwindow_get_time_window(control_flow_data
->tab
);
2602 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2603 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2605 #endif //EXTRA_CHECK
2606 Drawing_t
*drawing
= control_flow_data
->drawing
;
2607 guint width
= drawing
->width
;
2609 guint x
= closure_data
->x_end
;
2611 DrawContext draw_context
;
2613 /* Now create the drawing context that will be used to draw
2614 * items related to the last state. */
2615 draw_context
.drawable
= hashed_process_data
->pixmap
;
2616 draw_context
.gc
= drawing
->gc
;
2617 draw_context
.pango_layout
= drawing
->pango_layout
;
2618 draw_context
.drawinfo
.end
.x
= x
;
2620 draw_context
.drawinfo
.y
.over
= 1;
2621 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2622 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2624 draw_context
.drawinfo
.start
.offset
.over
= 0;
2625 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2626 draw_context
.drawinfo
.start
.offset
.under
= 0;
2627 draw_context
.drawinfo
.end
.offset
.over
= 0;
2628 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2629 draw_context
.drawinfo
.end
.offset
.under
= 0;
2631 /* Jump over draw if we are at the same x position */
2632 if(x
== hashed_process_data
->x
.over
)
2636 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2638 PropertiesLine prop_line
= prepare_execmode_line(process
);
2639 draw_line((void*)&prop_line
, (void*)&draw_context
);
2641 hashed_process_data
->x
.over
= x
;
2645 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2646 hashed_process_data
->x
.middle_used
)) {
2647 #if 0 /* do not mark closure : not missing information */
2648 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2649 /* Draw collision indicator */
2650 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2651 gdk_draw_point(drawing
->pixmap
,
2655 hashed_process_data
->x
.middle_marked
= TRUE
;
2660 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2663 PropertiesLine prop_line
= prepare_s_e_line(process
);
2664 draw_line((void*)&prop_line
, (void*)&draw_context
);
2667 /* become the last x position */
2668 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2669 hashed_process_data
->x
.middle
= x
;
2670 /* but don't use the pixel */
2671 hashed_process_data
->x
.middle_used
= FALSE
;
2673 /* Calculate the next good time */
2674 convert_pixels_to_time(width
, x
+1, time_window
,
2675 &hashed_process_data
->next_good_time
);
2684 int before_chunk(void *hook_data
, void *call_data
)
2686 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2687 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2689 /* Desactivate sort */
2690 gtk_tree_sortable_set_sort_column_id(
2691 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2693 GTK_SORT_ASCENDING
);
2695 drawing_chunk_begin(events_request
, tss
);
2700 int before_request(void *hook_data
, void *call_data
)
2702 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2703 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2705 drawing_data_request_begin(events_request
, tss
);
2712 * after request is necessary in addition of after chunk in order to draw
2713 * lines until the end of the screen. after chunk just draws lines until
2720 int after_request(void *hook_data
, void *call_data
)
2722 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2723 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2724 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2726 ProcessList
*process_list
= control_flow_data
->process_list
;
2727 LttTime end_time
= events_request
->end_time
;
2729 ClosureData closure_data
;
2730 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2731 closure_data
.tss
= tss
;
2732 closure_data
.end_time
= end_time
;
2734 TimeWindow time_window
=
2735 lttvwindow_get_time_window(control_flow_data
->tab
);
2736 guint width
= control_flow_data
->drawing
->width
;
2737 convert_time_to_pixels(
2741 &closure_data
.x_end
);
2744 /* Draw last items */
2745 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2746 (void*)&closure_data
);
2749 /* Request expose */
2750 drawing_request_expose(events_request
, tss
, end_time
);
2759 int after_chunk(void *hook_data
, void *call_data
)
2761 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2762 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2763 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2764 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)call_data
;
2765 LttvTracefileContext
*tfc
= lttv_traceset_context_get_current_tfc(tsc
);
2768 ProcessList
*process_list
= control_flow_data
->process_list
;
2770 LttvTraceset
*traceset
= tsc
->ts
;
2771 guint nb_trace
= lttv_traceset_number(traceset
);
2773 /* Only execute when called for the first trace's events request */
2774 if(!process_list
->current_hash_data
)
2777 for(i
= 0 ; i
< nb_trace
; i
++) {
2778 g_free(process_list
->current_hash_data
[i
]);
2780 g_free(process_list
->current_hash_data
);
2781 process_list
->current_hash_data
= NULL
;
2784 end_time
= LTT_TIME_MIN(tfc
->timestamp
, events_request
->end_time
);
2785 else /* end of traceset, or position now out of request : end */
2786 end_time
= events_request
->end_time
;
2788 ClosureData closure_data
;
2789 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2790 closure_data
.tss
= tss
;
2791 closure_data
.end_time
= end_time
;
2793 TimeWindow time_window
=
2794 lttvwindow_get_time_window(control_flow_data
->tab
);
2795 guint width
= control_flow_data
->drawing
->width
;
2796 convert_time_to_pixels(
2800 &closure_data
.x_end
);
2802 /* Draw last items */
2803 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2804 (void*)&closure_data
);
2806 /* Reactivate sort */
2807 gtk_tree_sortable_set_sort_column_id(
2808 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2809 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2810 GTK_SORT_ASCENDING
);
2812 update_index_to_pixmap(control_flow_data
->process_list
);
2813 /* Request a full expose : drawing scrambled */
2814 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2816 /* Request expose (updates damages zone also) */
2817 drawing_request_expose(events_request
, tss
, end_time
);
2822 /* after_statedump_end
2824 * @param hook_data ControlFlowData structure of the viewer.
2825 * @param call_data Event context.
2827 * This function adds items to be drawn in a queue for each process.
2830 int before_statedump_end(void *hook_data
, void *call_data
)
2832 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2833 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
2834 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2836 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2838 LttvTracesetState
*tss
= (LttvTracesetState
*)tfc
->t_context
->ts_context
;
2839 ProcessList
*process_list
= control_flow_data
->process_list
;
2842 e
= ltt_tracefile_get_event(tfc
->tf
);
2844 LttvFilter
*filter
= control_flow_data
->filter
;
2845 if(filter
!= NULL
&& filter
->head
!= NULL
)
2846 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2847 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2850 LttTime evtime
= ltt_event_time(e
);
2852 ClosureData closure_data
;
2853 closure_data
.events_request
= events_request
;
2854 closure_data
.tss
= tss
;
2855 closure_data
.end_time
= evtime
;
2857 TimeWindow time_window
=
2858 lttvwindow_get_time_window(control_flow_data
->tab
);
2859 guint width
= control_flow_data
->drawing
->width
;
2860 convert_time_to_pixels(
2864 &closure_data
.x_end
);
2866 /* Draw last items */
2867 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2868 (void*)&closure_data
);
2870 /* Reactivate sort */
2871 gtk_tree_sortable_set_sort_column_id(
2872 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2873 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2874 GTK_SORT_ASCENDING
);
2876 update_index_to_pixmap(control_flow_data
->process_list
);
2877 /* Request a full expose : drawing scrambled */
2878 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2880 /* Request expose (updates damages zone also) */
2881 drawing_request_expose(events_request
, tss
, evtime
);