1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Mathieu Desnoyers
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20 /*****************************************************************************
21 * Hooks to be called by the main window *
22 *****************************************************************************/
25 /* Event hooks are the drawing hooks called during traceset read. They draw the
26 * icons, text, lines and background color corresponding to the events read.
28 * Two hooks are used for drawing : before_schedchange and after_schedchange hooks. The
29 * before_schedchange is called before the state update that occurs with an event and
30 * the after_schedchange hook is called after this state update.
32 * The before_schedchange hooks fulfill the task of drawing the visible objects that
33 * corresponds to the data accumulated by the after_schedchange hook.
35 * The after_schedchange hook accumulates the data that need to be shown on the screen
36 * (items) into a queue. Then, the next before_schedchange hook will draw what that
37 * queue contains. That's the Right Way (TM) of drawing items on the screen,
38 * because we need to draw the background first (and then add icons, text, ...
39 * over it), but we only know the length of a background region once the state
40 * corresponding to it is over, which happens to be at the next before_schedchange
43 * We also have a hook called at the end of a chunk to draw the information left
44 * undrawn in each process queue. We use the current time as end of
52 //#define PANGO_ENABLE_BACKEND
60 //#include <pango/pango.h>
62 #include <ltt/event.h>
65 #include <ltt/trace.h>
67 #include <lttv/lttv.h>
68 #include <lttv/hook.h>
69 #include <lttv/state.h>
70 #include <lttvwindow/lttvwindow.h>
71 #include <lttvwindow/lttvwindowtraces.h>
72 #include <lttvwindow/support.h>
75 #include "eventhooks.h"
77 #include "processlist.h"
81 #define MAX_PATH_LEN 256
83 extern GSList
*g_legend_list
;
86 /* Action to do when background computation completed.
88 * Wait for all the awaited computations to be over.
91 static gint
background_ready(void *hook_data
, void *call_data
)
93 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
94 LttvTrace
*trace
= (LttvTrace
*)call_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
);
124 LttvHooks
*background_ready_hook
=
126 lttv_hooks_add(background_ready_hook
, background_ready
, control_flow_data
,
128 control_flow_data
->background_info_waiting
= 0;
130 for(i
=0;i
<num_traces
;i
++) {
131 trace
= lttv_traceset_get(tsc
->ts
, i
);
133 if(lttvwindowtraces_get_ready(g_quark_from_string("state"),trace
)==FALSE
) {
135 if(lttvwindowtraces_get_in_progress(g_quark_from_string("state"),
137 /* We first remove requests that could have been done for the same
138 * information. Happens when two viewers ask for it before servicing
141 if(!lttvwindowtraces_background_request_find(trace
, "state"))
142 lttvwindowtraces_background_request_queue(trace
, "state");
143 lttvwindowtraces_background_notify_queue(control_flow_data
,
147 background_ready_hook
);
148 control_flow_data
->background_info_waiting
++;
149 } else { /* in progress */
151 lttvwindowtraces_background_notify_current(control_flow_data
,
155 background_ready_hook
);
156 control_flow_data
->background_info_waiting
++;
159 /* Data ready. Be its nature, this viewer doesn't need to have
160 * its data ready hook called htere, because a background
161 * request is always linked with a redraw.
167 lttv_hooks_destroy(background_ready_hook
);
174 * Event Viewer's constructor hook
176 * This constructor is given as a parameter to the menuitem and toolbar button
177 * registration. It creates the list.
178 * @param tab A pointer to the parent tab.
179 * @return The widget created.
182 h_guicontrolflow(Tab
*tab
)
184 g_info("h_guicontrolflow, %p", tab
);
185 ControlFlowData
*control_flow_data
= guicontrolflow() ;
187 control_flow_data
->tab
= tab
;
189 // Unreg done in the GuiControlFlow_Destructor
190 lttvwindow_register_traceset_notify(tab
,
194 lttvwindow_register_time_window_notify(tab
,
195 update_time_window_hook
,
197 lttvwindow_register_current_time_notify(tab
,
198 update_current_time_hook
,
200 lttvwindow_register_redraw_notify(tab
,
203 lttvwindow_register_continue_notify(tab
,
206 request_background_data(control_flow_data
);
209 return guicontrolflow_get_widget(control_flow_data
) ;
213 void legend_destructor(GtkWindow
*legend
)
215 g_legend_list
= g_slist_remove(g_legend_list
, legend
);
218 /* Create a popup legend */
222 g_info("h_legend, %p", tab
);
224 GtkWindow
*legend
= GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL
));
226 g_legend_list
= g_slist_append(
230 g_object_set_data_full(
234 (GDestroyNotify
)legend_destructor
);
236 gtk_window_set_title(legend
, "Control Flow View Legend");
238 GtkWidget
*pixmap
= create_pixmap(GTK_WIDGET(legend
), "lttv-color-list.png");
240 // GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixmap(
241 // GDK_PIXMAP(pixmap), NULL));
243 gtk_container_add(GTK_CONTAINER(legend
), GTK_WIDGET(pixmap
));
245 gtk_widget_show(GTK_WIDGET(pixmap
));
246 gtk_widget_show(GTK_WIDGET(legend
));
249 return NULL
; /* This is a popup window */
253 int event_selected_hook(void *hook_data
, void *call_data
)
255 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
256 guint
*event_number
= (guint
*) call_data
;
258 g_debug("DEBUG : event selected by main window : %u", *event_number
);
263 /* Function that selects the color of status&exemode line */
264 static inline PropertiesLine
prepare_s_e_line(LttvProcessState
*process
)
266 PropertiesLine prop_line
;
267 prop_line
.line_width
= 2;
268 prop_line
.style
= GDK_LINE_SOLID
;
269 prop_line
.y
= MIDDLE
;
270 //GdkColormap *colormap = gdk_colormap_get_system();
272 if(process
->state
->s
== LTTV_STATE_RUN
) {
273 if(process
->state
->t
== LTTV_STATE_USER_MODE
)
274 prop_line
.color
= drawing_colors
[COL_RUN_USER_MODE
];
275 else if(process
->state
->t
== LTTV_STATE_SYSCALL
)
276 prop_line
.color
= drawing_colors
[COL_RUN_SYSCALL
];
277 else if(process
->state
->t
== LTTV_STATE_TRAP
)
278 prop_line
.color
= drawing_colors
[COL_RUN_TRAP
];
279 else if(process
->state
->t
== LTTV_STATE_IRQ
)
280 prop_line
.color
= drawing_colors
[COL_RUN_IRQ
];
281 else if(process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
)
282 prop_line
.color
= drawing_colors
[COL_MODE_UNKNOWN
];
284 g_assert(FALSE
); /* RUNNING MODE UNKNOWN */
285 } else if(process
->state
->s
== LTTV_STATE_WAIT
) {
286 /* We don't show if we wait while in user mode, trap, irq or syscall */
287 prop_line
.color
= drawing_colors
[COL_WAIT
];
288 } else if(process
->state
->s
== LTTV_STATE_WAIT_CPU
) {
289 /* We don't show if we wait for CPU while in user mode, trap, irq
291 prop_line
.color
= drawing_colors
[COL_WAIT_CPU
];
292 } else if(process
->state
->s
== LTTV_STATE_ZOMBIE
) {
293 prop_line
.color
= drawing_colors
[COL_ZOMBIE
];
294 } else if(process
->state
->s
== LTTV_STATE_WAIT_FORK
) {
295 prop_line
.color
= drawing_colors
[COL_WAIT_FORK
];
296 } else if(process
->state
->s
== LTTV_STATE_EXIT
) {
297 prop_line
.color
= drawing_colors
[COL_EXIT
];
298 } else if(process
->state
->s
== LTTV_STATE_UNNAMED
) {
299 prop_line
.color
= drawing_colors
[COL_UNNAMED
];
301 g_assert(FALSE
); /* UNKNOWN STATE */
308 /* before_schedchange_hook
310 * This function basically draw lines and icons. Two types of lines are drawn :
311 * one small (3 pixels?) representing the state of the process and the second
312 * type is thicker (10 pixels?) representing on which CPU a process is running
313 * (and this only in running state).
315 * Extremums of the lines :
316 * x_min : time of the last event context for this process kept in memory.
317 * x_max : time of the current event.
318 * y : middle of the process in the process list. The process is found in the
319 * list, therefore is it's position in pixels.
321 * The choice of lines'color is defined by the context of the last event for this
326 int before_schedchange_hook(void *hook_data
, void *call_data
)
328 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
329 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
330 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
332 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
334 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
335 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
338 e
= ltt_tracefile_get_event(tfc
->tf
);
340 LttTime evtime
= ltt_event_time(e
);
342 /* we are in a schedchange, before the state update. We must draw the
343 * items corresponding to the state before it changes : now is the right
350 pid_out
= ltt_event_get_long_unsigned(e
, thf
->f1
);
351 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f2
);
355 /* For the pid_out */
356 /* First, check if the current process is in the state computation
357 * process list. If it is there, that means we must add it right now and
358 * draw items from the beginning of the read for it. If it is not
359 * present, it's a new process and it was not present : it will
360 * be added after the state update. */
361 guint cpu
= ltt_tracefile_num(tfc
->tf
);
362 LttvProcessState
*process
= ts
->running_process
[cpu
];
363 /* unknown state, bad current pid */
364 if(process
->pid
!= pid_out
)
365 process
= lttv_state_find_process(ts
,
366 ltt_tracefile_num(tfc
->tf
), pid_out
);
368 if(process
!= NULL
) {
369 /* Well, the process_out existed : we must get it in the process hash
370 * or add it, and draw its items.
372 /* Add process to process list (if not present) */
374 HashedProcessData
*hashed_process_data
= NULL
;
375 ProcessList
*process_list
= control_flow_data
->process_list
;
376 LttTime birth
= process
->creation_time
;
378 hashed_process_data
= processlist_get_process_data(process_list
,
382 tfc
->t_context
->index
);
383 if(hashed_process_data
== NULL
)
385 g_assert(pid_out
== 0 || pid_out
!= process
->ppid
);
386 /* Process not present */
387 ProcessInfo
*process_info
;
388 Drawing_t
*drawing
= control_flow_data
->drawing
;
389 processlist_add(process_list
,
395 tfc
->t_context
->index
,
399 &hashed_process_data
);
400 gtk_widget_set_size_request(drawing
->drawing_area
,
403 gtk_widget_queue_draw(drawing
->drawing_area
);
407 /* Now, the process is in the state hash and our own process hash.
408 * We definitely can draw the items related to the ending state.
411 if(ltt_time_compare(hashed_process_data
->next_good_time
,
414 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
416 TimeWindow time_window
=
417 lttvwindow_get_time_window(control_flow_data
->tab
);
419 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
420 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
423 Drawing_t
*drawing
= control_flow_data
->drawing
;
424 guint width
= drawing
->width
;
426 convert_time_to_pixels(
432 /* Draw collision indicator */
433 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
434 gdk_draw_point(hashed_process_data
->pixmap
,
437 (hashed_process_data
->height
/2)-3);
438 hashed_process_data
->x
.middle_marked
= TRUE
;
441 TimeWindow time_window
=
442 lttvwindow_get_time_window(control_flow_data
->tab
);
444 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
445 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
448 Drawing_t
*drawing
= control_flow_data
->drawing
;
449 guint width
= drawing
->width
;
451 convert_time_to_pixels(
458 /* Jump over draw if we are at the same x position */
459 if(x
== hashed_process_data
->x
.middle
&&
460 hashed_process_data
->x
.middle_used
)
462 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
463 /* Draw collision indicator */
464 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
465 gdk_draw_point(hashed_process_data
->pixmap
,
468 (hashed_process_data
->height
/2)-3);
469 hashed_process_data
->x
.middle_marked
= TRUE
;
473 DrawContext draw_context
;
475 /* Now create the drawing context that will be used to draw
476 * items related to the last state. */
477 draw_context
.drawable
= hashed_process_data
->pixmap
;
478 draw_context
.gc
= drawing
->gc
;
479 draw_context
.pango_layout
= drawing
->pango_layout
;
480 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
481 draw_context
.drawinfo
.end
.x
= x
;
483 draw_context
.drawinfo
.y
.over
= 1;
484 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
485 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
487 draw_context
.drawinfo
.start
.offset
.over
= 0;
488 draw_context
.drawinfo
.start
.offset
.middle
= 0;
489 draw_context
.drawinfo
.start
.offset
.under
= 0;
490 draw_context
.drawinfo
.end
.offset
.over
= 0;
491 draw_context
.drawinfo
.end
.offset
.middle
= 0;
492 draw_context
.drawinfo
.end
.offset
.under
= 0;
496 PropertiesLine prop_line
= prepare_s_e_line(process
);
497 draw_line((void*)&prop_line
, (void*)&draw_context
);
500 /* become the last x position */
501 hashed_process_data
->x
.middle
= x
;
502 hashed_process_data
->x
.middle_used
= TRUE
;
503 hashed_process_data
->x
.middle_marked
= FALSE
;
505 /* Calculate the next good time */
506 convert_pixels_to_time(width
, x
+1, time_window
,
507 &hashed_process_data
->next_good_time
);
515 /* First, check if the current process is in the state computation
516 * process list. If it is there, that means we must add it right now and
517 * draw items from the beginning of the read for it. If it is not
518 * present, it's a new process and it was not present : it will
519 * be added after the state update. */
520 LttvProcessState
*process
;
521 process
= lttv_state_find_process(ts
,
522 ltt_tracefile_num(tfc
->tf
), pid_in
);
524 if(process
!= NULL
) {
525 /* Well, the process existed : we must get it in the process hash
526 * or add it, and draw its items.
528 /* Add process to process list (if not present) */
530 HashedProcessData
*hashed_process_data
= NULL
;
531 ProcessList
*process_list
= control_flow_data
->process_list
;
532 LttTime birth
= process
->creation_time
;
534 hashed_process_data
= processlist_get_process_data(process_list
,
536 ltt_tracefile_num(tfc
->tf
),
538 tfc
->t_context
->index
);
539 if(hashed_process_data
== NULL
)
541 g_assert(pid_in
== 0 || pid_in
!= process
->ppid
);
542 /* Process not present */
543 ProcessInfo
*process_info
;
544 Drawing_t
*drawing
= control_flow_data
->drawing
;
545 processlist_add(process_list
,
548 ltt_tracefile_num(tfc
->tf
),
551 tfc
->t_context
->index
,
555 &hashed_process_data
);
556 gtk_widget_set_size_request(drawing
->drawing_area
,
559 gtk_widget_queue_draw(drawing
->drawing_area
);
562 //We could set the current process and hash here, but will be done
563 //by after schedchange hook
565 /* Now, the process is in the state hash and our own process hash.
566 * We definitely can draw the items related to the ending state.
569 if(ltt_time_compare(hashed_process_data
->next_good_time
,
572 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
574 TimeWindow time_window
=
575 lttvwindow_get_time_window(control_flow_data
->tab
);
577 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
578 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
581 Drawing_t
*drawing
= control_flow_data
->drawing
;
582 guint width
= drawing
->width
;
584 convert_time_to_pixels(
590 /* Draw collision indicator */
591 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
592 gdk_draw_point(hashed_process_data
->pixmap
,
595 (hashed_process_data
->height
/2)-3);
596 hashed_process_data
->x
.middle_marked
= TRUE
;
599 TimeWindow time_window
=
600 lttvwindow_get_time_window(control_flow_data
->tab
);
602 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
603 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
606 Drawing_t
*drawing
= control_flow_data
->drawing
;
607 guint width
= drawing
->width
;
610 convert_time_to_pixels(
617 /* Jump over draw if we are at the same x position */
618 if(x
== hashed_process_data
->x
.middle
&&
619 hashed_process_data
->x
.middle_used
)
621 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
622 /* Draw collision indicator */
623 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
624 gdk_draw_point(hashed_process_data
->pixmap
,
627 (hashed_process_data
->height
/2)-3);
628 hashed_process_data
->x
.middle_marked
= TRUE
;
632 DrawContext draw_context
;
634 /* Now create the drawing context that will be used to draw
635 * items related to the last state. */
636 draw_context
.drawable
= hashed_process_data
->pixmap
;
637 draw_context
.gc
= drawing
->gc
;
638 draw_context
.pango_layout
= drawing
->pango_layout
;
639 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
640 draw_context
.drawinfo
.end
.x
= x
;
642 draw_context
.drawinfo
.y
.over
= 1;
643 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
644 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
646 draw_context
.drawinfo
.start
.offset
.over
= 0;
647 draw_context
.drawinfo
.start
.offset
.middle
= 0;
648 draw_context
.drawinfo
.start
.offset
.under
= 0;
649 draw_context
.drawinfo
.end
.offset
.over
= 0;
650 draw_context
.drawinfo
.end
.offset
.middle
= 0;
651 draw_context
.drawinfo
.end
.offset
.under
= 0;
655 PropertiesLine prop_line
= prepare_s_e_line(process
);
656 draw_line((void*)&prop_line
, (void*)&draw_context
);
660 /* become the last x position */
661 hashed_process_data
->x
.middle
= x
;
662 hashed_process_data
->x
.middle_used
= TRUE
;
663 hashed_process_data
->x
.middle_marked
= FALSE
;
665 /* Calculate the next good time */
666 convert_pixels_to_time(width
, x
+1, time_window
,
667 &hashed_process_data
->next_good_time
);
671 g_warning("Cannot find pin_in in schedchange %u", pid_in
);
680 GString
*string
= g_string_new("");;
681 gboolean field_names
= TRUE
, state
= TRUE
;
683 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
684 g_string_append_printf(string
,"\n");
687 g_string_append_printf(string
, " %s",
688 g_quark_to_string(tfs
->process
->state
->s
));
691 g_info("%s",string
->str
);
693 g_string_free(string
, TRUE
);
695 /* End of text dump */
700 /* after_schedchange_hook
702 * The draw after hook is called by the reading API to have a
703 * particular event drawn on the screen.
704 * @param hook_data ControlFlowData structure of the viewer.
705 * @param call_data Event context.
707 * This function adds items to be drawn in a queue for each process.
710 int after_schedchange_hook(void *hook_data
, void *call_data
)
712 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
713 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
714 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
716 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
718 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
720 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
723 e
= ltt_tracefile_get_event(tfc
->tf
);
725 LttTime evtime
= ltt_event_time(e
);
727 /* Add process to process list (if not present) */
728 LttvProcessState
*process_in
;
731 HashedProcessData
*hashed_process_data_in
= NULL
;
733 ProcessList
*process_list
= control_flow_data
->process_list
;
738 pid_out
= ltt_event_get_long_unsigned(e
, thf
->f1
);
739 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f2
);
743 /* Find process pid_in in the list... */
744 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
745 //process_in = tfs->process;
746 guint cpu
= ltt_tracefile_num(tfc
->tf
);
747 process_in
= ts
->running_process
[cpu
];
748 /* It should exist, because we are after the state update. */
750 g_assert(process_in
!= NULL
);
752 birth
= process_in
->creation_time
;
754 hashed_process_data_in
= processlist_get_process_data(process_list
,
758 tfc
->t_context
->index
);
759 if(hashed_process_data_in
== NULL
)
761 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
762 ProcessInfo
*process_info
;
763 Drawing_t
*drawing
= control_flow_data
->drawing
;
764 /* Process not present */
765 processlist_add(process_list
,
771 tfc
->t_context
->index
,
775 &hashed_process_data_in
);
776 gtk_widget_set_size_request(drawing
->drawing_area
,
779 gtk_widget_queue_draw(drawing
->drawing_area
);
781 /* Set the current process */
782 process_list
->current_hash_data
[process_in
->cpu
] =
783 hashed_process_data_in
;
785 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
788 TimeWindow time_window
=
789 lttvwindow_get_time_window(control_flow_data
->tab
);
792 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
793 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
796 Drawing_t
*drawing
= control_flow_data
->drawing
;
797 guint width
= drawing
->width
;
800 convert_time_to_pixels(
806 if(hashed_process_data_in
->x
.middle
!= new_x
) {
807 hashed_process_data_in
->x
.middle
= new_x
;
808 hashed_process_data_in
->x
.middle_used
= FALSE
;
809 hashed_process_data_in
->x
.middle_marked
= FALSE
;
818 /* before_execmode_hook
820 * This function basically draw lines and icons. Two types of lines are drawn :
821 * one small (3 pixels?) representing the state of the process and the second
822 * type is thicker (10 pixels?) representing on which CPU a process is running
823 * (and this only in running state).
825 * Extremums of the lines :
826 * x_min : time of the last event context for this process kept in memory.
827 * x_max : time of the current event.
828 * y : middle of the process in the process list. The process is found in the
829 * list, therefore is it's position in pixels.
831 * The choice of lines'color is defined by the context of the last event for this
836 int before_execmode_hook(void *hook_data
, void *call_data
)
838 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
839 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
840 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
842 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
844 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
846 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
849 e
= ltt_tracefile_get_event(tfc
->tf
);
851 LttTime evtime
= ltt_event_time(e
);
853 /* we are in a execmode, before the state update. We must draw the
854 * items corresponding to the state before it changes : now is the right
858 //LttvProcessState *process = tfs->process;
859 guint cpu
= ltt_tracefile_num(tfc
->tf
);
860 LttvProcessState
*process
= ts
->running_process
[cpu
];
861 g_assert(process
!= NULL
);
863 guint pid
= process
->pid
;
865 /* Well, the process_out existed : we must get it in the process hash
866 * or add it, and draw its items.
868 /* Add process to process list (if not present) */
870 HashedProcessData
*hashed_process_data
= NULL
;
871 ProcessList
*process_list
= control_flow_data
->process_list
;
872 LttTime birth
= process
->creation_time
;
874 if(likely(process_list
->current_hash_data
[cpu
] != NULL
)) {
875 hashed_process_data
= process_list
->current_hash_data
[cpu
];
877 hashed_process_data
= processlist_get_process_data(process_list
,
881 tfc
->t_context
->index
);
882 if(unlikely(hashed_process_data
== NULL
))
884 g_assert(pid
== 0 || pid
!= process
->ppid
);
885 ProcessInfo
*process_info
;
886 /* Process not present */
887 Drawing_t
*drawing
= control_flow_data
->drawing
;
888 processlist_add(process_list
,
894 tfc
->t_context
->index
,
898 &hashed_process_data
);
899 gtk_widget_set_size_request(drawing
->drawing_area
,
902 gtk_widget_queue_draw(drawing
->drawing_area
);
904 /* Set the current process */
905 process_list
->current_hash_data
[process
->cpu
] =
909 /* Now, the process is in the state hash and our own process hash.
910 * We definitely can draw the items related to the ending state.
913 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
916 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
917 TimeWindow time_window
=
918 lttvwindow_get_time_window(control_flow_data
->tab
);
921 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
922 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
925 Drawing_t
*drawing
= control_flow_data
->drawing
;
926 guint width
= drawing
->width
;
928 convert_time_to_pixels(
934 /* Draw collision indicator */
935 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
936 gdk_draw_point(hashed_process_data
->pixmap
,
939 (hashed_process_data
->height
/2)-3);
940 hashed_process_data
->x
.middle_marked
= TRUE
;
943 TimeWindow time_window
=
944 lttvwindow_get_time_window(control_flow_data
->tab
);
947 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
948 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
951 Drawing_t
*drawing
= control_flow_data
->drawing
;
952 guint width
= drawing
->width
;
955 convert_time_to_pixels(
962 /* Jump over draw if we are at the same x position */
963 if(unlikely(x
== hashed_process_data
->x
.middle
&&
964 hashed_process_data
->x
.middle_used
))
966 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
967 /* Draw collision indicator */
968 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
969 gdk_draw_point(hashed_process_data
->pixmap
,
972 (hashed_process_data
->height
/2)-3);
973 hashed_process_data
->x
.middle_marked
= TRUE
;
978 DrawContext draw_context
;
979 /* Now create the drawing context that will be used to draw
980 * items related to the last state. */
981 draw_context
.drawable
= hashed_process_data
->pixmap
;
982 draw_context
.gc
= drawing
->gc
;
983 draw_context
.pango_layout
= drawing
->pango_layout
;
984 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
985 draw_context
.drawinfo
.end
.x
= x
;
987 draw_context
.drawinfo
.y
.over
= 1;
988 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
989 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
991 draw_context
.drawinfo
.start
.offset
.over
= 0;
992 draw_context
.drawinfo
.start
.offset
.middle
= 0;
993 draw_context
.drawinfo
.start
.offset
.under
= 0;
994 draw_context
.drawinfo
.end
.offset
.over
= 0;
995 draw_context
.drawinfo
.end
.offset
.middle
= 0;
996 draw_context
.drawinfo
.end
.offset
.under
= 0;
1000 PropertiesLine prop_line
= prepare_s_e_line(process
);
1001 draw_line((void*)&prop_line
, (void*)&draw_context
);
1004 /* become the last x position */
1005 hashed_process_data
->x
.middle
= x
;
1006 hashed_process_data
->x
.middle_used
= TRUE
;
1007 hashed_process_data
->x
.middle_marked
= FALSE
;
1009 /* Calculate the next good time */
1010 convert_pixels_to_time(width
, x
+1, time_window
,
1011 &hashed_process_data
->next_good_time
);
1018 /* before_process_exit_hook
1020 * Draw lines for process event.
1022 * @param hook_data ControlFlowData structure of the viewer.
1023 * @param call_data Event context.
1025 * This function adds items to be drawn in a queue for each process.
1030 int before_process_exit_hook(void *hook_data
, void *call_data
)
1032 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1033 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1035 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1037 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1039 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1041 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1044 e
= ltt_tracefile_get_event(tfc
->tf
);
1046 LttTime evtime
= ltt_event_time(e
);
1048 /* Add process to process list (if not present) */
1049 //LttvProcessState *process = tfs->process;
1050 guint cpu
= ltt_tracefile_num(tfc
->tf
);
1051 LttvProcessState
*process
= ts
->running_process
[cpu
];
1052 guint pid
= process
->pid
;
1054 guint pl_height
= 0;
1055 HashedProcessData
*hashed_process_data
= NULL
;
1057 ProcessList
*process_list
= control_flow_data
->process_list
;
1059 g_assert(process
!= NULL
);
1061 birth
= process
->creation_time
;
1063 if(likely(process_list
->current_hash_data
[cpu
] != NULL
)) {
1064 hashed_process_data
= process_list
->current_hash_data
[cpu
];
1066 hashed_process_data
= processlist_get_process_data(process_list
,
1070 tfc
->t_context
->index
);
1071 if(unlikely(hashed_process_data
== NULL
))
1073 g_assert(pid
== 0 || pid
!= process
->ppid
);
1074 /* Process not present */
1075 Drawing_t
*drawing
= control_flow_data
->drawing
;
1076 ProcessInfo
*process_info
;
1077 processlist_add(process_list
,
1083 tfc
->t_context
->index
,
1087 &hashed_process_data
);
1088 gtk_widget_set_size_request(drawing
->drawing_area
,
1091 gtk_widget_queue_draw(drawing
->drawing_area
);
1095 /* Now, the process is in the state hash and our own process hash.
1096 * We definitely can draw the items related to the ending state.
1099 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1102 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1103 TimeWindow time_window
=
1104 lttvwindow_get_time_window(control_flow_data
->tab
);
1107 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1108 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1110 #endif //EXTRA_CHECK
1111 Drawing_t
*drawing
= control_flow_data
->drawing
;
1112 guint width
= drawing
->width
;
1114 convert_time_to_pixels(
1120 /* Draw collision indicator */
1121 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1122 gdk_draw_point(hashed_process_data
->pixmap
,
1125 (hashed_process_data
->height
/2)-3);
1126 hashed_process_data
->x
.middle_marked
= TRUE
;
1129 TimeWindow time_window
=
1130 lttvwindow_get_time_window(control_flow_data
->tab
);
1133 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1134 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1136 #endif //EXTRA_CHECK
1137 Drawing_t
*drawing
= control_flow_data
->drawing
;
1138 guint width
= drawing
->width
;
1141 convert_time_to_pixels(
1148 /* Jump over draw if we are at the same x position */
1149 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1150 hashed_process_data
->x
.middle_used
))
1152 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1153 /* Draw collision indicator */
1154 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1155 gdk_draw_point(hashed_process_data
->pixmap
,
1158 (hashed_process_data
->height
/2)-3);
1159 hashed_process_data
->x
.middle_marked
= TRUE
;
1163 DrawContext draw_context
;
1165 /* Now create the drawing context that will be used to draw
1166 * items related to the last state. */
1167 draw_context
.drawable
= hashed_process_data
->pixmap
;
1168 draw_context
.gc
= drawing
->gc
;
1169 draw_context
.pango_layout
= drawing
->pango_layout
;
1170 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1171 draw_context
.drawinfo
.end
.x
= x
;
1173 draw_context
.drawinfo
.y
.over
= 1;
1174 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1175 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1177 draw_context
.drawinfo
.start
.offset
.over
= 0;
1178 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1179 draw_context
.drawinfo
.start
.offset
.under
= 0;
1180 draw_context
.drawinfo
.end
.offset
.over
= 0;
1181 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1182 draw_context
.drawinfo
.end
.offset
.under
= 0;
1186 PropertiesLine prop_line
= prepare_s_e_line(process
);
1187 draw_line((void*)&prop_line
, (void*)&draw_context
);
1190 /* become the last x position */
1191 hashed_process_data
->x
.middle
= x
;
1192 hashed_process_data
->x
.middle_used
= TRUE
;
1193 hashed_process_data
->x
.middle_marked
= FALSE
;
1195 /* Calculate the next good time */
1196 convert_pixels_to_time(width
, x
+1, time_window
,
1197 &hashed_process_data
->next_good_time
);
1207 /* before_process_release_hook
1209 * Draw lines for process event.
1211 * @param hook_data ControlFlowData structure of the viewer.
1212 * @param call_data Event context.
1214 * This function adds items to be drawn in a queue for each process.
1219 int before_process_release_hook(void *hook_data
, void *call_data
)
1221 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1222 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1224 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1226 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1228 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1230 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1233 e
= ltt_tracefile_get_event(tfc
->tf
);
1235 LttTime evtime
= ltt_event_time(e
);
1240 pid
= ltt_event_get_long_unsigned(e
, thf
->f1
);
1243 /* Add process to process list (if not present) */
1244 /* Don't care about the process if it's not in the state hash already :
1245 * that means a process that has never done anything in the trace and
1246 * unknown suddently gets destroyed : no state meaningful to show. */
1247 LttvProcessState
*process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1249 if(process
!= NULL
) {
1251 guint pl_height
= 0;
1252 HashedProcessData
*hashed_process_data
= NULL
;
1254 ProcessList
*process_list
= control_flow_data
->process_list
;
1256 birth
= process
->creation_time
;
1258 /* Cannot use current process : this event happens on another process,
1259 * action done by the parent. */
1260 hashed_process_data
= processlist_get_process_data(process_list
,
1264 tfc
->t_context
->index
);
1265 if(unlikely(hashed_process_data
== NULL
))
1267 g_assert(pid
== 0 || pid
!= process
->ppid
);
1268 /* Process not present */
1269 Drawing_t
*drawing
= control_flow_data
->drawing
;
1270 ProcessInfo
*process_info
;
1271 processlist_add(process_list
,
1277 tfc
->t_context
->index
,
1281 &hashed_process_data
);
1282 gtk_widget_set_size_request(drawing
->drawing_area
,
1285 gtk_widget_queue_draw(drawing
->drawing_area
);
1288 /* Now, the process is in the state hash and our own process hash.
1289 * We definitely can draw the items related to the ending state.
1292 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1295 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1296 TimeWindow time_window
=
1297 lttvwindow_get_time_window(control_flow_data
->tab
);
1300 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1301 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1303 #endif //EXTRA_CHECK
1304 Drawing_t
*drawing
= control_flow_data
->drawing
;
1305 guint width
= drawing
->width
;
1307 convert_time_to_pixels(
1313 /* Draw collision indicator */
1314 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1315 gdk_draw_point(hashed_process_data
->pixmap
,
1318 (hashed_process_data
->height
/2)-3);
1319 hashed_process_data
->x
.middle_marked
= TRUE
;
1322 TimeWindow time_window
=
1323 lttvwindow_get_time_window(control_flow_data
->tab
);
1326 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1327 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1329 #endif //EXTRA_CHECK
1330 Drawing_t
*drawing
= control_flow_data
->drawing
;
1331 guint width
= drawing
->width
;
1334 convert_time_to_pixels(
1341 /* Jump over draw if we are at the same x position */
1342 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1343 hashed_process_data
->x
.middle_used
))
1345 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1346 /* Draw collision indicator */
1347 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1348 gdk_draw_point(hashed_process_data
->pixmap
,
1351 (hashed_process_data
->height
/2)-3);
1352 hashed_process_data
->x
.middle_marked
= TRUE
;
1356 DrawContext draw_context
;
1358 /* Now create the drawing context that will be used to draw
1359 * items related to the last state. */
1360 draw_context
.drawable
= hashed_process_data
->pixmap
;
1361 draw_context
.gc
= drawing
->gc
;
1362 draw_context
.pango_layout
= drawing
->pango_layout
;
1363 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1364 draw_context
.drawinfo
.end
.x
= x
;
1366 draw_context
.drawinfo
.y
.over
= 1;
1367 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1368 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1370 draw_context
.drawinfo
.start
.offset
.over
= 0;
1371 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1372 draw_context
.drawinfo
.start
.offset
.under
= 0;
1373 draw_context
.drawinfo
.end
.offset
.over
= 0;
1374 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1375 draw_context
.drawinfo
.end
.offset
.under
= 0;
1379 PropertiesLine prop_line
= prepare_s_e_line(process
);
1380 draw_line((void*)&prop_line
, (void*)&draw_context
);
1383 /* become the last x position */
1384 hashed_process_data
->x
.middle
= x
;
1385 hashed_process_data
->x
.middle_used
= TRUE
;
1386 hashed_process_data
->x
.middle_marked
= FALSE
;
1388 /* Calculate the next good time */
1389 convert_pixels_to_time(width
, x
+1, time_window
,
1390 &hashed_process_data
->next_good_time
);
1402 /* after_process_fork_hook
1404 * Create the processlist entry for the child process. Put the last
1405 * position in x at the current time value.
1407 * @param hook_data ControlFlowData structure of the viewer.
1408 * @param call_data Event context.
1410 * This function adds items to be drawn in a queue for each process.
1413 int after_process_fork_hook(void *hook_data
, void *call_data
)
1415 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1416 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1417 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1419 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1421 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1423 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1426 e
= ltt_tracefile_get_event(tfc
->tf
);
1428 LttTime evtime
= ltt_event_time(e
);
1432 child_pid
= ltt_event_get_long_unsigned(e
, thf
->f2
);
1435 /* Add process to process list (if not present) */
1436 LttvProcessState
*process_child
;
1438 guint pl_height
= 0;
1439 HashedProcessData
*hashed_process_data_child
= NULL
;
1441 ProcessList
*process_list
= control_flow_data
->process_list
;
1443 /* Find child in the list... */
1444 process_child
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1445 /* It should exist, because we are after the state update. */
1446 g_assert(process_child
!= NULL
);
1448 birth
= process_child
->creation_time
;
1450 /* Cannot use current process, because this action is done by the parent
1452 hashed_process_data_child
= processlist_get_process_data(process_list
,
1456 tfc
->t_context
->index
);
1457 if(likely(hashed_process_data_child
== NULL
))
1459 g_assert(child_pid
== 0 || child_pid
!= process_child
->ppid
);
1460 /* Process not present */
1461 Drawing_t
*drawing
= control_flow_data
->drawing
;
1462 ProcessInfo
*process_info
;
1463 processlist_add(process_list
,
1467 process_child
->ppid
,
1469 tfc
->t_context
->index
,
1470 process_child
->name
,
1473 &hashed_process_data_child
);
1474 gtk_widget_set_size_request(drawing
->drawing_area
,
1477 gtk_widget_queue_draw(drawing
->drawing_area
);
1481 if(likely(ltt_time_compare(hashed_process_data_child
->next_good_time
,
1484 TimeWindow time_window
=
1485 lttvwindow_get_time_window(control_flow_data
->tab
);
1488 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1489 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1491 #endif //EXTRA_CHECK
1492 Drawing_t
*drawing
= control_flow_data
->drawing
;
1493 guint width
= drawing
->width
;
1495 convert_time_to_pixels(
1501 if(likely(hashed_process_data_child
->x
.over
!= new_x
)) {
1502 hashed_process_data_child
->x
.over
= new_x
;
1503 hashed_process_data_child
->x
.over_used
= FALSE
;
1504 hashed_process_data_child
->x
.over_marked
= FALSE
;
1506 if(likely(hashed_process_data_child
->x
.middle
!= new_x
)) {
1507 hashed_process_data_child
->x
.middle
= new_x
;
1508 hashed_process_data_child
->x
.middle_used
= FALSE
;
1509 hashed_process_data_child
->x
.middle_marked
= FALSE
;
1511 if(likely(hashed_process_data_child
->x
.under
!= new_x
)) {
1512 hashed_process_data_child
->x
.under
= new_x
;
1513 hashed_process_data_child
->x
.under_used
= FALSE
;
1514 hashed_process_data_child
->x
.under_marked
= FALSE
;
1522 /* after_process_exit_hook
1524 * Create the processlist entry for the child process. Put the last
1525 * position in x at the current time value.
1527 * @param hook_data ControlFlowData structure of the viewer.
1528 * @param call_data Event context.
1530 * This function adds items to be drawn in a queue for each process.
1533 int after_process_exit_hook(void *hook_data
, void *call_data
)
1535 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1536 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1537 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1539 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1541 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1543 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1546 e
= ltt_tracefile_get_event(tfc
->tf
);
1548 LttTime evtime
= ltt_event_time(e
);
1550 /* Add process to process list (if not present) */
1551 //LttvProcessState *process = tfs->process;
1552 guint cpu
= ltt_tracefile_num(tfc
->tf
);
1553 LttvProcessState
*process
= ts
->running_process
[cpu
];
1555 /* It should exist, because we are after the state update. */
1556 g_assert(process
!= NULL
);
1558 guint pid
= process
->pid
;
1560 guint pl_height
= 0;
1561 HashedProcessData
*hashed_process_data
= NULL
;
1563 ProcessList
*process_list
= control_flow_data
->process_list
;
1565 birth
= process
->creation_time
;
1567 if(likely(process_list
->current_hash_data
[cpu
] != NULL
) ){
1568 hashed_process_data
= process_list
->current_hash_data
[cpu
];
1570 hashed_process_data
= processlist_get_process_data(process_list
,
1574 tfc
->t_context
->index
);
1575 if(unlikely(hashed_process_data
== NULL
))
1577 g_assert(pid
== 0 || pid
!= process
->ppid
);
1578 /* Process not present */
1579 Drawing_t
*drawing
= control_flow_data
->drawing
;
1580 ProcessInfo
*process_info
;
1581 processlist_add(process_list
,
1587 tfc
->t_context
->index
,
1591 &hashed_process_data
);
1592 gtk_widget_set_size_request(drawing
->drawing_area
,
1595 gtk_widget_queue_draw(drawing
->drawing_area
);
1598 /* Set the current process */
1599 process_list
->current_hash_data
[process
->cpu
] =
1600 hashed_process_data
;
1603 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
1606 TimeWindow time_window
=
1607 lttvwindow_get_time_window(control_flow_data
->tab
);
1610 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1611 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1613 #endif //EXTRA_CHECK
1614 Drawing_t
*drawing
= control_flow_data
->drawing
;
1615 guint width
= drawing
->width
;
1617 convert_time_to_pixels(
1622 if(unlikely(hashed_process_data
->x
.middle
!= new_x
)) {
1623 hashed_process_data
->x
.middle
= new_x
;
1624 hashed_process_data
->x
.middle_used
= FALSE
;
1625 hashed_process_data
->x
.middle_marked
= FALSE
;
1633 /* Get the filename of the process to print */
1634 int after_fs_exec_hook(void *hook_data
, void *call_data
)
1636 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1637 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1638 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1640 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1642 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1644 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1646 guint cpu
= ltt_tracefile_num(tfc
->tf
);
1647 LttvProcessState
*process
= ts
->running_process
[cpu
];
1648 g_assert(process
!= NULL
);
1650 guint pid
= process
->pid
;
1652 /* Well, the process_out existed : we must get it in the process hash
1653 * or add it, and draw its items.
1655 /* Add process to process list (if not present) */
1656 guint pl_height
= 0;
1657 HashedProcessData
*hashed_process_data
= NULL
;
1658 ProcessList
*process_list
= control_flow_data
->process_list
;
1659 LttTime birth
= process
->creation_time
;
1661 if(likely(process_list
->current_hash_data
[cpu
] != NULL
)) {
1662 hashed_process_data
= process_list
->current_hash_data
[cpu
];
1664 hashed_process_data
= processlist_get_process_data(process_list
,
1668 tfc
->t_context
->index
);
1669 if(unlikely(hashed_process_data
== NULL
))
1671 g_assert(pid
== 0 || pid
!= process
->ppid
);
1672 ProcessInfo
*process_info
;
1673 /* Process not present */
1674 Drawing_t
*drawing
= control_flow_data
->drawing
;
1675 processlist_add(process_list
,
1681 tfc
->t_context
->index
,
1685 &hashed_process_data
);
1686 gtk_widget_set_size_request(drawing
->drawing_area
,
1689 gtk_widget_queue_draw(drawing
->drawing_area
);
1691 /* Set the current process */
1692 process_list
->current_hash_data
[process
->cpu
] =
1693 hashed_process_data
;
1696 processlist_set_name(process_list
, process
->name
, hashed_process_data
);
1705 gint
update_time_window_hook(void *hook_data
, void *call_data
)
1707 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1708 Drawing_t
*drawing
= control_flow_data
->drawing
;
1709 ProcessList
*process_list
= control_flow_data
->process_list
;
1711 const TimeWindowNotifyData
*time_window_nofify_data
=
1712 ((const TimeWindowNotifyData
*)call_data
);
1714 TimeWindow
*old_time_window
=
1715 time_window_nofify_data
->old_time_window
;
1716 TimeWindow
*new_time_window
=
1717 time_window_nofify_data
->new_time_window
;
1719 /* Update the ruler */
1720 drawing_update_ruler(control_flow_data
->drawing
,
1724 /* Two cases : zoom in/out or scrolling */
1726 /* In order to make sure we can reuse the old drawing, the scale must
1727 * be the same and the new time interval being partly located in the
1728 * currently shown time interval. (reuse is only for scrolling)
1731 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
1732 old_time_window
->start_time
.tv_sec
,
1733 old_time_window
->start_time
.tv_nsec
,
1734 old_time_window
->time_width
.tv_sec
,
1735 old_time_window
->time_width
.tv_nsec
);
1737 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
1738 new_time_window
->start_time
.tv_sec
,
1739 new_time_window
->start_time
.tv_nsec
,
1740 new_time_window
->time_width
.tv_sec
,
1741 new_time_window
->time_width
.tv_nsec
);
1743 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
1744 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
1746 /* Same scale (scrolling) */
1747 g_info("scrolling");
1748 LttTime
*ns
= &new_time_window
->start_time
;
1749 LttTime
*nw
= &new_time_window
->time_width
;
1750 LttTime
*os
= &old_time_window
->start_time
;
1751 LttTime
*ow
= &old_time_window
->time_width
;
1752 LttTime old_end
= old_time_window
->end_time
;
1753 LttTime new_end
= new_time_window
->end_time
;
1755 //if(ns<os+w && os+w<ns+w)
1756 //if(ns<old_end && os<ns)
1757 if(ltt_time_compare(*ns
, old_end
) == -1
1758 && ltt_time_compare(*os
, *ns
) == -1)
1760 g_info("scrolling near right");
1761 /* Scroll right, keep right part of the screen */
1763 guint width
= control_flow_data
->drawing
->width
;
1764 convert_time_to_pixels(
1770 /* Copy old data to new location */
1771 copy_pixmap_region(process_list
,
1773 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1777 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
1779 if(drawing
->damage_begin
== drawing
->damage_end
)
1780 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
1782 drawing
->damage_begin
= 0;
1784 drawing
->damage_end
= control_flow_data
->drawing
->width
;
1786 /* Clear the data request background, but not SAFETY */
1787 rectangle_pixmap(process_list
,
1788 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1790 drawing
->damage_begin
+SAFETY
, 0,
1791 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
1793 gtk_widget_queue_draw(drawing
->drawing_area
);
1794 //gtk_widget_queue_draw_area (drawing->drawing_area,
1796 // control_flow_data->drawing->width,
1797 // control_flow_data->drawing->height);
1799 /* Get new data for the rest. */
1800 drawing_data_request(control_flow_data
->drawing
,
1801 drawing
->damage_begin
, 0,
1802 drawing
->damage_end
- drawing
->damage_begin
,
1803 control_flow_data
->drawing
->height
);
1806 //if(ns<os && os<ns+w)
1807 //if(ns<os && os<new_end)
1808 if(ltt_time_compare(*ns
,*os
) == -1
1809 && ltt_time_compare(*os
,new_end
) == -1)
1811 g_info("scrolling near left");
1812 /* Scroll left, keep left part of the screen */
1814 guint width
= control_flow_data
->drawing
->width
;
1815 convert_time_to_pixels(
1821 /* Copy old data to new location */
1822 copy_pixmap_region (process_list
,
1824 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1830 if(drawing
->damage_begin
== drawing
->damage_end
)
1831 drawing
->damage_end
= x
;
1833 drawing
->damage_end
=
1834 control_flow_data
->drawing
->width
;
1836 drawing
->damage_begin
= 0;
1838 rectangle_pixmap (process_list
,
1839 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1841 drawing
->damage_begin
, 0,
1842 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
1845 gtk_widget_queue_draw(drawing
->drawing_area
);
1846 //gtk_widget_queue_draw_area (drawing->drawing_area,
1848 // control_flow_data->drawing->width,
1849 // control_flow_data->drawing->height);
1852 /* Get new data for the rest. */
1853 drawing_data_request(control_flow_data
->drawing
,
1854 drawing
->damage_begin
, 0,
1855 drawing
->damage_end
- drawing
->damage_begin
,
1856 control_flow_data
->drawing
->height
);
1859 if(ltt_time_compare(*ns
,*os
) == 0)
1861 g_info("not scrolling");
1863 g_info("scrolling far");
1864 /* Cannot reuse any part of the screen : far jump */
1867 rectangle_pixmap (process_list
,
1868 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1871 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
1874 //gtk_widget_queue_draw_area (drawing->drawing_area,
1876 // control_flow_data->drawing->width,
1877 // control_flow_data->drawing->height);
1878 gtk_widget_queue_draw(drawing
->drawing_area
);
1880 drawing
->damage_begin
= 0;
1881 drawing
->damage_end
= control_flow_data
->drawing
->width
;
1883 drawing_data_request(control_flow_data
->drawing
,
1885 control_flow_data
->drawing
->width
,
1886 control_flow_data
->drawing
->height
);
1892 /* Different scale (zoom) */
1895 rectangle_pixmap (process_list
,
1896 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1899 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
1902 //gtk_widget_queue_draw_area (drawing->drawing_area,
1904 // control_flow_data->drawing->width,
1905 // control_flow_data->drawing->height);
1906 gtk_widget_queue_draw(drawing
->drawing_area
);
1908 drawing
->damage_begin
= 0;
1909 drawing
->damage_end
= control_flow_data
->drawing
->width
;
1911 drawing_data_request(control_flow_data
->drawing
,
1913 control_flow_data
->drawing
->width
,
1914 control_flow_data
->drawing
->height
);
1917 /* Update directly when scrolling */
1918 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
1924 gint
traceset_notify(void *hook_data
, void *call_data
)
1926 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1927 Drawing_t
*drawing
= control_flow_data
->drawing
;
1930 drawing_clear(control_flow_data
->drawing
);
1931 processlist_clear(control_flow_data
->process_list
);
1932 gtk_widget_set_size_request(
1933 control_flow_data
->drawing
->drawing_area
,
1934 -1, processlist_get_height(control_flow_data
->process_list
));
1935 redraw_notify(control_flow_data
, NULL
);
1937 request_background_data(control_flow_data
);
1942 gint
redraw_notify(void *hook_data
, void *call_data
)
1944 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1945 Drawing_t
*drawing
= control_flow_data
->drawing
;
1946 GtkWidget
*widget
= drawing
->drawing_area
;
1948 drawing
->damage_begin
= 0;
1949 drawing
->damage_end
= drawing
->width
;
1951 /* fun feature, to be separated someday... */
1952 drawing_clear(control_flow_data
->drawing
);
1953 processlist_clear(control_flow_data
->process_list
);
1954 gtk_widget_set_size_request(
1955 control_flow_data
->drawing
->drawing_area
,
1956 -1, processlist_get_height(control_flow_data
->process_list
));
1958 rectangle_pixmap (control_flow_data
->process_list
,
1959 widget
->style
->black_gc
,
1962 drawing
->alloc_width
,
1965 gtk_widget_queue_draw(drawing
->drawing_area
);
1967 if(drawing
->damage_begin
< drawing
->damage_end
)
1969 drawing_data_request(drawing
,
1970 drawing
->damage_begin
,
1972 drawing
->damage_end
-drawing
->damage_begin
,
1976 //gtk_widget_queue_draw_area(drawing->drawing_area,
1979 // drawing->height);
1985 gint
continue_notify(void *hook_data
, void *call_data
)
1987 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1988 Drawing_t
*drawing
= control_flow_data
->drawing
;
1990 //g_assert(widget->allocation.width == drawing->damage_end);
1992 if(drawing
->damage_begin
< drawing
->damage_end
)
1994 drawing_data_request(drawing
,
1995 drawing
->damage_begin
,
1997 drawing
->damage_end
-drawing
->damage_begin
,
2005 gint
update_current_time_hook(void *hook_data
, void *call_data
)
2007 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
2008 Drawing_t
*drawing
= control_flow_data
->drawing
;
2010 LttTime current_time
= *((LttTime
*)call_data
);
2012 TimeWindow time_window
=
2013 lttvwindow_get_time_window(control_flow_data
->tab
);
2015 LttTime time_begin
= time_window
.start_time
;
2016 LttTime width
= time_window
.time_width
;
2019 guint64 time_ll
= ltt_time_to_uint64(width
);
2020 time_ll
= time_ll
>> 1; /* divide by two */
2021 half_width
= ltt_time_from_uint64(time_ll
);
2023 LttTime time_end
= ltt_time_add(time_begin
, width
);
2025 LttvTracesetContext
* tsc
=
2026 lttvwindow_get_traceset_context(control_flow_data
->tab
);
2028 LttTime trace_start
= tsc
->time_span
.start_time
;
2029 LttTime trace_end
= tsc
->time_span
.end_time
;
2031 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
2032 current_time
.tv_nsec
);
2036 /* If current time is inside time interval, just move the highlight
2039 /* Else, we have to change the time interval. We have to tell it
2040 * to the main window. */
2041 /* The time interval change will take care of placing the current
2042 * time at the center of the visible area, or nearest possible if we are
2043 * at one end of the trace. */
2046 if(ltt_time_compare(current_time
, time_begin
) < 0)
2048 TimeWindow new_time_window
;
2050 if(ltt_time_compare(current_time
,
2051 ltt_time_add(trace_start
,half_width
)) < 0)
2052 time_begin
= trace_start
;
2054 time_begin
= ltt_time_sub(current_time
,half_width
);
2056 new_time_window
.start_time
= time_begin
;
2057 new_time_window
.time_width
= width
;
2058 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2059 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2061 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2063 else if(ltt_time_compare(current_time
, time_end
) > 0)
2065 TimeWindow new_time_window
;
2067 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
2068 time_begin
= ltt_time_sub(trace_end
,width
);
2070 time_begin
= ltt_time_sub(current_time
,half_width
);
2072 new_time_window
.start_time
= time_begin
;
2073 new_time_window
.time_width
= width
;
2074 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2075 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2077 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2080 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2082 /* Update directly when scrolling */
2083 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2089 typedef struct _ClosureData
{
2090 EventsRequest
*events_request
;
2091 LttvTracesetState
*tss
;
2097 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
2099 ProcessInfo
*process_info
= (ProcessInfo
*)key
;
2100 HashedProcessData
*hashed_process_data
= (HashedProcessData
*)value
;
2101 ClosureData
*closure_data
= (ClosureData
*)user_data
;
2103 EventsRequest
*events_request
= closure_data
->events_request
;
2104 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2106 LttvTracesetState
*tss
= closure_data
->tss
;
2107 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)tss
;
2109 LttTime evtime
= closure_data
->end_time
;
2112 /* For the process */
2113 /* First, check if the current process is in the state computation
2114 * process list. If it is there, that means we must add it right now and
2115 * draw items from the beginning of the read for it. If it is not
2116 * present, it's a new process and it was not present : it will
2117 * be added after the state update. */
2119 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
2120 #endif //EXTRA_CHECK
2121 LttvTraceContext
*tc
= tsc
->traces
[process_info
->trace_num
];
2122 LttvTraceState
*ts
= (LttvTraceState
*)tc
;
2125 //FIXME : optimize data structures.
2126 LttvTracefileState
*tfs
;
2127 LttvTracefileContext
*tfc
;
2129 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
2130 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
2131 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
2132 && ltt_tracefile_num(tfc
->tf
) == process_info
->cpu
)
2136 g_assert(i
<tc
->tracefiles
->len
);
2137 tfs
= LTTV_TRACEFILE_STATE(tfc
);
2139 // LttvTracefileState *tfs =
2140 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2141 // tracefiles[process_info->cpu];
2143 LttvProcessState
*process
;
2144 process
= lttv_state_find_process(ts
, process_info
->cpu
,
2147 if(unlikely(process
!= NULL
)) {
2149 /* Only draw for processes that are currently in the trace states */
2151 ProcessList
*process_list
= control_flow_data
->process_list
;
2153 /* Should be alike when background info is ready */
2154 if(control_flow_data
->background_info_waiting
==0)
2155 g_assert(ltt_time_compare(process
->creation_time
,
2156 process_info
->birth
) == 0);
2157 #endif //EXTRA_CHECK
2159 /* Now, the process is in the state hash and our own process hash.
2160 * We definitely can draw the items related to the ending state.
2163 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2166 TimeWindow time_window
=
2167 lttvwindow_get_time_window(control_flow_data
->tab
);
2170 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2171 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2173 #endif //EXTRA_CHECK
2174 Drawing_t
*drawing
= control_flow_data
->drawing
;
2175 guint width
= drawing
->width
;
2177 guint x
= closure_data
->x_end
;
2179 DrawContext draw_context
;
2181 /* Now create the drawing context that will be used to draw
2182 * items related to the last state. */
2183 draw_context
.drawable
= hashed_process_data
->pixmap
;
2184 draw_context
.gc
= drawing
->gc
;
2185 draw_context
.pango_layout
= drawing
->pango_layout
;
2186 draw_context
.drawinfo
.end
.x
= x
;
2188 draw_context
.drawinfo
.y
.over
= 1;
2189 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2190 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2192 draw_context
.drawinfo
.start
.offset
.over
= 0;
2193 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2194 draw_context
.drawinfo
.start
.offset
.under
= 0;
2195 draw_context
.drawinfo
.end
.offset
.over
= 0;
2196 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2197 draw_context
.drawinfo
.end
.offset
.under
= 0;
2199 /* Jump over draw if we are at the same x position */
2200 if(x
== hashed_process_data
->x
.over
)
2204 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2206 PropertiesLine prop_line
= prepare_execmode_line(process
);
2207 draw_line((void*)&prop_line
, (void*)&draw_context
);
2209 hashed_process_data
->x
.over
= x
;
2213 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2214 hashed_process_data
->x
.middle_used
)) {
2215 #if 0 /* do not mark closure : not missing information */
2216 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2217 /* Draw collision indicator */
2218 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2219 gdk_draw_point(drawing
->pixmap
,
2223 hashed_process_data
->x
.middle_marked
= TRUE
;
2228 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2230 PropertiesLine prop_line
= prepare_s_e_line(process
);
2231 draw_line((void*)&prop_line
, (void*)&draw_context
);
2233 /* become the last x position */
2234 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2235 hashed_process_data
->x
.middle
= x
;
2236 /* but don't use the pixel */
2237 hashed_process_data
->x
.middle_used
= FALSE
;
2239 /* Calculate the next good time */
2240 convert_pixels_to_time(width
, x
+1, time_window
,
2241 &hashed_process_data
->next_good_time
);
2250 int before_chunk(void *hook_data
, void *call_data
)
2252 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2253 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2254 ControlFlowData
*cfd
= (ControlFlowData
*)events_request
->viewer_data
;
2256 /* Desactivate sort */
2257 gtk_tree_sortable_set_sort_column_id(
2258 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2260 GTK_SORT_ASCENDING
);
2262 drawing_chunk_begin(events_request
, tss
);
2267 int before_request(void *hook_data
, void *call_data
)
2269 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2270 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2272 drawing_data_request_begin(events_request
, tss
);
2279 * after request is necessary in addition of after chunk in order to draw
2280 * lines until the end of the screen. after chunk just draws lines until
2287 int after_request(void *hook_data
, void *call_data
)
2289 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2290 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2291 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2293 ProcessList
*process_list
= control_flow_data
->process_list
;
2294 LttTime end_time
= events_request
->end_time
;
2296 ClosureData closure_data
;
2297 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2298 closure_data
.tss
= tss
;
2299 closure_data
.end_time
= end_time
;
2301 TimeWindow time_window
=
2302 lttvwindow_get_time_window(control_flow_data
->tab
);
2303 guint width
= control_flow_data
->drawing
->width
;
2304 convert_time_to_pixels(
2308 &closure_data
.x_end
);
2311 /* Draw last items */
2312 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2313 (void*)&closure_data
);
2316 /* Request expose */
2317 drawing_request_expose(events_request
, tss
, end_time
);
2326 int after_chunk(void *hook_data
, void *call_data
)
2328 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2329 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2330 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2331 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)call_data
;
2332 LttvTracefileContext
*tfc
= lttv_traceset_context_get_current_tfc(tsc
);
2335 ProcessList
*process_list
= control_flow_data
->process_list
;
2337 g_free(process_list
->current_hash_data
);
2338 process_list
->current_hash_data
= NULL
;
2341 end_time
= LTT_TIME_MIN(tfc
->timestamp
, events_request
->end_time
);
2342 else /* end of traceset, or position now out of request : end */
2343 end_time
= events_request
->end_time
;
2345 ClosureData closure_data
;
2346 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2347 closure_data
.tss
= tss
;
2348 closure_data
.end_time
= end_time
;
2350 TimeWindow time_window
=
2351 lttvwindow_get_time_window(control_flow_data
->tab
);
2352 guint width
= control_flow_data
->drawing
->width
;
2353 convert_time_to_pixels(
2357 &closure_data
.x_end
);
2359 /* Draw last items */
2360 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2361 (void*)&closure_data
);
2363 /* Reactivate sort */
2364 gtk_tree_sortable_set_sort_column_id(
2365 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2366 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2367 GTK_SORT_ASCENDING
);
2369 update_index_to_pixmap(control_flow_data
->process_list
);
2370 /* Request a full expose : drawing scrambled */
2371 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2373 /* Request expose (updates damages zone also) */
2374 drawing_request_expose(events_request
, tss
, end_time
);