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(
143 main_window_get_widget(control_flow_data
->tab
), trace
, "state");
144 lttvwindowtraces_background_notify_queue(control_flow_data
,
148 background_ready_hook
);
149 control_flow_data
->background_info_waiting
++;
150 } else { /* in progress */
152 lttvwindowtraces_background_notify_current(control_flow_data
,
156 background_ready_hook
);
157 control_flow_data
->background_info_waiting
++;
160 /* Data ready. Be its nature, this viewer doesn't need to have
161 * its data ready hook called there, because a background
162 * request is always linked with a redraw.
168 lttv_hooks_destroy(background_ready_hook
);
175 * Event Viewer's constructor hook
177 * This constructor is given as a parameter to the menuitem and toolbar button
178 * registration. It creates the list.
179 * @param tab A pointer to the parent tab.
180 * @return The widget created.
183 h_guicontrolflow(Tab
*tab
)
185 g_info("h_guicontrolflow, %p", tab
);
186 ControlFlowData
*control_flow_data
= guicontrolflow(tab
) ;
188 control_flow_data
->tab
= tab
;
190 // Unreg done in the GuiControlFlow_Destructor
191 lttvwindow_register_traceset_notify(tab
,
195 lttvwindow_register_time_window_notify(tab
,
196 update_time_window_hook
,
198 lttvwindow_register_current_time_notify(tab
,
199 update_current_time_hook
,
201 lttvwindow_register_redraw_notify(tab
,
204 lttvwindow_register_continue_notify(tab
,
207 request_background_data(control_flow_data
);
210 return guicontrolflow_get_widget(control_flow_data
) ;
214 void legend_destructor(GtkWindow
*legend
)
216 g_legend_list
= g_slist_remove(g_legend_list
, legend
);
219 /* Create a popup legend */
223 g_info("h_legend, %p", tab
);
225 GtkWindow
*legend
= GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL
));
227 g_legend_list
= g_slist_append(
231 g_object_set_data_full(
235 (GDestroyNotify
)legend_destructor
);
237 gtk_window_set_title(legend
, "Control Flow View Legend");
239 GtkWidget
*pixmap
= create_pixmap(GTK_WIDGET(legend
), "lttv-color-list.png");
241 // GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixmap(
242 // GDK_PIXMAP(pixmap), NULL));
244 gtk_container_add(GTK_CONTAINER(legend
), GTK_WIDGET(pixmap
));
246 gtk_widget_show(GTK_WIDGET(pixmap
));
247 gtk_widget_show(GTK_WIDGET(legend
));
250 return NULL
; /* This is a popup window */
254 int event_selected_hook(void *hook_data
, void *call_data
)
256 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
257 guint
*event_number
= (guint
*) call_data
;
259 g_debug("DEBUG : event selected by main window : %u", *event_number
);
264 /* Function that selects the color of status&exemode line */
265 static inline PropertiesLine
prepare_s_e_line(LttvProcessState
*process
)
267 PropertiesLine prop_line
;
268 prop_line
.line_width
= 2;
269 prop_line
.style
= GDK_LINE_SOLID
;
270 prop_line
.y
= MIDDLE
;
271 //GdkColormap *colormap = gdk_colormap_get_system();
273 if(process
->state
->s
== LTTV_STATE_RUN
) {
274 if(process
->state
->t
== LTTV_STATE_USER_MODE
)
275 prop_line
.color
= drawing_colors
[COL_RUN_USER_MODE
];
276 else if(process
->state
->t
== LTTV_STATE_SYSCALL
)
277 prop_line
.color
= drawing_colors
[COL_RUN_SYSCALL
];
278 else if(process
->state
->t
== LTTV_STATE_TRAP
)
279 prop_line
.color
= drawing_colors
[COL_RUN_TRAP
];
280 else if(process
->state
->t
== LTTV_STATE_IRQ
)
281 prop_line
.color
= drawing_colors
[COL_RUN_IRQ
];
282 else if(process
->state
->t
== LTTV_STATE_SOFT_IRQ
)
283 prop_line
.color
= drawing_colors
[COL_RUN_SOFT_IRQ
];
284 else if(process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
)
285 prop_line
.color
= drawing_colors
[COL_MODE_UNKNOWN
];
287 g_assert(FALSE
); /* RUNNING MODE UNKNOWN */
288 } else if(process
->state
->s
== LTTV_STATE_WAIT
) {
289 /* We don't show if we wait while in user mode, trap, irq or syscall */
290 prop_line
.color
= drawing_colors
[COL_WAIT
];
291 } else if(process
->state
->s
== LTTV_STATE_WAIT_CPU
) {
292 /* We don't show if we wait for CPU while in user mode, trap, irq
294 prop_line
.color
= drawing_colors
[COL_WAIT_CPU
];
295 } else if(process
->state
->s
== LTTV_STATE_ZOMBIE
) {
296 prop_line
.color
= drawing_colors
[COL_ZOMBIE
];
297 } else if(process
->state
->s
== LTTV_STATE_WAIT_FORK
) {
298 prop_line
.color
= drawing_colors
[COL_WAIT_FORK
];
299 } else if(process
->state
->s
== LTTV_STATE_EXIT
) {
300 prop_line
.color
= drawing_colors
[COL_EXIT
];
301 } else if(process
->state
->s
== LTTV_STATE_UNNAMED
) {
302 prop_line
.color
= drawing_colors
[COL_UNNAMED
];
304 g_critical("unknown state : %s", g_quark_to_string(process
->state
->s
));
305 g_assert(FALSE
); /* UNKNOWN STATE */
313 /* before_schedchange_hook
315 * This function basically draw lines and icons. Two types of lines are drawn :
316 * one small (3 pixels?) representing the state of the process and the second
317 * type is thicker (10 pixels?) representing on which CPU a process is running
318 * (and this only in running state).
320 * Extremums of the lines :
321 * x_min : time of the last event context for this process kept in memory.
322 * x_max : time of the current event.
323 * y : middle of the process in the process list. The process is found in the
324 * list, therefore is it's position in pixels.
326 * The choice of lines'color is defined by the context of the last event for this
331 int before_schedchange_hook(void *hook_data
, void *call_data
)
333 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
334 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
335 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
337 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
339 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
340 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
343 e
= ltt_tracefile_get_event(tfc
->tf
);
345 LttTime evtime
= ltt_event_time(e
);
347 /* we are in a schedchange, before the state update. We must draw the
348 * items corresponding to the state before it changes : now is the right
355 pid_out
= ltt_event_get_long_unsigned(e
, thf
->f1
);
356 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f2
);
360 /* For the pid_out */
361 /* First, check if the current process is in the state computation
362 * process list. If it is there, that means we must add it right now and
363 * draw items from the beginning of the read for it. If it is not
364 * present, it's a new process and it was not present : it will
365 * be added after the state update. */
366 guint cpu
= ltt_tracefile_num(tfc
->tf
);
367 LttvProcessState
*process
= ts
->running_process
[cpu
];
368 /* unknown state, bad current pid */
369 if(process
->pid
!= pid_out
)
370 process
= lttv_state_find_process(ts
,
371 ltt_tracefile_num(tfc
->tf
), pid_out
);
373 if(process
!= NULL
) {
374 /* Well, the process_out existed : we must get it in the process hash
375 * or add it, and draw its items.
377 /* Add process to process list (if not present) */
379 HashedProcessData
*hashed_process_data
= NULL
;
380 ProcessList
*process_list
= control_flow_data
->process_list
;
381 LttTime birth
= process
->creation_time
;
383 hashed_process_data
= processlist_get_process_data(process_list
,
387 tfc
->t_context
->index
);
388 if(hashed_process_data
== NULL
)
390 g_assert(pid_out
== 0 || pid_out
!= process
->ppid
);
391 /* Process not present */
392 ProcessInfo
*process_info
;
393 Drawing_t
*drawing
= control_flow_data
->drawing
;
394 processlist_add(process_list
,
400 tfc
->t_context
->index
,
404 &hashed_process_data
);
405 gtk_widget_set_size_request(drawing
->drawing_area
,
408 gtk_widget_queue_draw(drawing
->drawing_area
);
412 /* Now, the process is in the state hash and our own process hash.
413 * We definitely can draw the items related to the ending state.
416 if(ltt_time_compare(hashed_process_data
->next_good_time
,
419 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
421 TimeWindow time_window
=
422 lttvwindow_get_time_window(control_flow_data
->tab
);
424 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
425 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
428 Drawing_t
*drawing
= control_flow_data
->drawing
;
429 guint width
= drawing
->width
;
431 convert_time_to_pixels(
437 /* Draw collision indicator */
438 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
439 gdk_draw_point(hashed_process_data
->pixmap
,
442 (hashed_process_data
->height
/2)-3);
443 hashed_process_data
->x
.middle_marked
= TRUE
;
446 TimeWindow time_window
=
447 lttvwindow_get_time_window(control_flow_data
->tab
);
449 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
450 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
453 Drawing_t
*drawing
= control_flow_data
->drawing
;
454 guint width
= drawing
->width
;
456 convert_time_to_pixels(
463 /* Jump over draw if we are at the same x position */
464 if(x
== hashed_process_data
->x
.middle
&&
465 hashed_process_data
->x
.middle_used
)
467 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
468 /* Draw collision indicator */
469 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
470 gdk_draw_point(hashed_process_data
->pixmap
,
473 (hashed_process_data
->height
/2)-3);
474 hashed_process_data
->x
.middle_marked
= TRUE
;
478 DrawContext draw_context
;
480 /* Now create the drawing context that will be used to draw
481 * items related to the last state. */
482 draw_context
.drawable
= hashed_process_data
->pixmap
;
483 draw_context
.gc
= drawing
->gc
;
484 draw_context
.pango_layout
= drawing
->pango_layout
;
485 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
486 draw_context
.drawinfo
.end
.x
= x
;
488 draw_context
.drawinfo
.y
.over
= 1;
489 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
490 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
492 draw_context
.drawinfo
.start
.offset
.over
= 0;
493 draw_context
.drawinfo
.start
.offset
.middle
= 0;
494 draw_context
.drawinfo
.start
.offset
.under
= 0;
495 draw_context
.drawinfo
.end
.offset
.over
= 0;
496 draw_context
.drawinfo
.end
.offset
.middle
= 0;
497 draw_context
.drawinfo
.end
.offset
.under
= 0;
501 PropertiesLine prop_line
= prepare_s_e_line(process
);
502 draw_line((void*)&prop_line
, (void*)&draw_context
);
505 /* become the last x position */
506 hashed_process_data
->x
.middle
= x
;
507 hashed_process_data
->x
.middle_used
= TRUE
;
508 hashed_process_data
->x
.middle_marked
= FALSE
;
510 /* Calculate the next good time */
511 convert_pixels_to_time(width
, x
+1, time_window
,
512 &hashed_process_data
->next_good_time
);
520 /* First, check if the current process is in the state computation
521 * process list. If it is there, that means we must add it right now and
522 * draw items from the beginning of the read for it. If it is not
523 * present, it's a new process and it was not present : it will
524 * be added after the state update. */
525 LttvProcessState
*process
;
526 process
= lttv_state_find_process(ts
,
527 ltt_tracefile_num(tfc
->tf
), pid_in
);
529 if(process
!= NULL
) {
530 /* Well, the process existed : we must get it in the process hash
531 * or add it, and draw its items.
533 /* Add process to process list (if not present) */
535 HashedProcessData
*hashed_process_data
= NULL
;
536 ProcessList
*process_list
= control_flow_data
->process_list
;
537 LttTime birth
= process
->creation_time
;
539 hashed_process_data
= processlist_get_process_data(process_list
,
541 ltt_tracefile_num(tfc
->tf
),
543 tfc
->t_context
->index
);
544 if(hashed_process_data
== NULL
)
546 g_assert(pid_in
== 0 || pid_in
!= process
->ppid
);
547 /* Process not present */
548 ProcessInfo
*process_info
;
549 Drawing_t
*drawing
= control_flow_data
->drawing
;
550 processlist_add(process_list
,
553 ltt_tracefile_num(tfc
->tf
),
556 tfc
->t_context
->index
,
560 &hashed_process_data
);
561 gtk_widget_set_size_request(drawing
->drawing_area
,
564 gtk_widget_queue_draw(drawing
->drawing_area
);
567 //We could set the current process and hash here, but will be done
568 //by after schedchange hook
570 /* Now, the process is in the state hash and our own process hash.
571 * We definitely can draw the items related to the ending state.
574 if(ltt_time_compare(hashed_process_data
->next_good_time
,
577 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
579 TimeWindow time_window
=
580 lttvwindow_get_time_window(control_flow_data
->tab
);
582 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
583 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
586 Drawing_t
*drawing
= control_flow_data
->drawing
;
587 guint width
= drawing
->width
;
589 convert_time_to_pixels(
595 /* Draw collision indicator */
596 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
597 gdk_draw_point(hashed_process_data
->pixmap
,
600 (hashed_process_data
->height
/2)-3);
601 hashed_process_data
->x
.middle_marked
= TRUE
;
604 TimeWindow time_window
=
605 lttvwindow_get_time_window(control_flow_data
->tab
);
607 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
608 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
611 Drawing_t
*drawing
= control_flow_data
->drawing
;
612 guint width
= drawing
->width
;
615 convert_time_to_pixels(
622 /* Jump over draw if we are at the same x position */
623 if(x
== hashed_process_data
->x
.middle
&&
624 hashed_process_data
->x
.middle_used
)
626 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
627 /* Draw collision indicator */
628 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
629 gdk_draw_point(hashed_process_data
->pixmap
,
632 (hashed_process_data
->height
/2)-3);
633 hashed_process_data
->x
.middle_marked
= TRUE
;
637 DrawContext draw_context
;
639 /* Now create the drawing context that will be used to draw
640 * items related to the last state. */
641 draw_context
.drawable
= hashed_process_data
->pixmap
;
642 draw_context
.gc
= drawing
->gc
;
643 draw_context
.pango_layout
= drawing
->pango_layout
;
644 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
645 draw_context
.drawinfo
.end
.x
= x
;
647 draw_context
.drawinfo
.y
.over
= 1;
648 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
649 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
651 draw_context
.drawinfo
.start
.offset
.over
= 0;
652 draw_context
.drawinfo
.start
.offset
.middle
= 0;
653 draw_context
.drawinfo
.start
.offset
.under
= 0;
654 draw_context
.drawinfo
.end
.offset
.over
= 0;
655 draw_context
.drawinfo
.end
.offset
.middle
= 0;
656 draw_context
.drawinfo
.end
.offset
.under
= 0;
660 PropertiesLine prop_line
= prepare_s_e_line(process
);
661 draw_line((void*)&prop_line
, (void*)&draw_context
);
665 /* become the last x position */
666 hashed_process_data
->x
.middle
= x
;
667 hashed_process_data
->x
.middle_used
= TRUE
;
668 hashed_process_data
->x
.middle_marked
= FALSE
;
670 /* Calculate the next good time */
671 convert_pixels_to_time(width
, x
+1, time_window
,
672 &hashed_process_data
->next_good_time
);
676 g_warning("Cannot find pin_in in schedchange %u", pid_in
);
685 GString
*string
= g_string_new("");;
686 gboolean field_names
= TRUE
, state
= TRUE
;
688 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
689 g_string_append_printf(string
,"\n");
692 g_string_append_printf(string
, " %s",
693 g_quark_to_string(tfs
->process
->state
->s
));
696 g_info("%s",string
->str
);
698 g_string_free(string
, TRUE
);
700 /* End of text dump */
705 /* after_schedchange_hook
707 * The draw after hook is called by the reading API to have a
708 * particular event drawn on the screen.
709 * @param hook_data ControlFlowData structure of the viewer.
710 * @param call_data Event context.
712 * This function adds items to be drawn in a queue for each process.
715 int after_schedchange_hook(void *hook_data
, void *call_data
)
717 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
718 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
719 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
721 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
723 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
725 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
728 e
= ltt_tracefile_get_event(tfc
->tf
);
730 LttTime evtime
= ltt_event_time(e
);
732 /* Add process to process list (if not present) */
733 LttvProcessState
*process_in
;
736 HashedProcessData
*hashed_process_data_in
= NULL
;
738 ProcessList
*process_list
= control_flow_data
->process_list
;
743 pid_out
= ltt_event_get_long_unsigned(e
, thf
->f1
);
744 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f2
);
748 /* Find process pid_in in the list... */
749 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
750 //process_in = tfs->process;
751 guint cpu
= ltt_tracefile_num(tfc
->tf
);
752 process_in
= ts
->running_process
[cpu
];
753 /* It should exist, because we are after the state update. */
755 g_assert(process_in
!= NULL
);
757 birth
= process_in
->creation_time
;
759 hashed_process_data_in
= processlist_get_process_data(process_list
,
763 tfc
->t_context
->index
);
764 if(hashed_process_data_in
== NULL
)
766 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
767 ProcessInfo
*process_info
;
768 Drawing_t
*drawing
= control_flow_data
->drawing
;
769 /* Process not present */
770 processlist_add(process_list
,
776 tfc
->t_context
->index
,
780 &hashed_process_data_in
);
781 gtk_widget_set_size_request(drawing
->drawing_area
,
784 gtk_widget_queue_draw(drawing
->drawing_area
);
786 /* Set the current process */
787 process_list
->current_hash_data
[process_in
->cpu
] =
788 hashed_process_data_in
;
790 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
793 TimeWindow time_window
=
794 lttvwindow_get_time_window(control_flow_data
->tab
);
797 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
798 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
801 Drawing_t
*drawing
= control_flow_data
->drawing
;
802 guint width
= drawing
->width
;
805 convert_time_to_pixels(
811 if(hashed_process_data_in
->x
.middle
!= new_x
) {
812 hashed_process_data_in
->x
.middle
= new_x
;
813 hashed_process_data_in
->x
.middle_used
= FALSE
;
814 hashed_process_data_in
->x
.middle_marked
= FALSE
;
823 /* before_execmode_hook
825 * This function basically draw lines and icons. Two types of lines are drawn :
826 * one small (3 pixels?) representing the state of the process and the second
827 * type is thicker (10 pixels?) representing on which CPU a process is running
828 * (and this only in running state).
830 * Extremums of the lines :
831 * x_min : time of the last event context for this process kept in memory.
832 * x_max : time of the current event.
833 * y : middle of the process in the process list. The process is found in the
834 * list, therefore is it's position in pixels.
836 * The choice of lines'color is defined by the context of the last event for this
841 int before_execmode_hook(void *hook_data
, void *call_data
)
843 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
844 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
845 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
847 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
849 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
851 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
854 e
= ltt_tracefile_get_event(tfc
->tf
);
856 LttTime evtime
= ltt_event_time(e
);
858 /* we are in a execmode, before the state update. We must draw the
859 * items corresponding to the state before it changes : now is the right
863 //LttvProcessState *process = tfs->process;
864 guint cpu
= ltt_tracefile_num(tfc
->tf
);
865 LttvProcessState
*process
= ts
->running_process
[cpu
];
866 g_assert(process
!= NULL
);
868 guint pid
= process
->pid
;
870 /* Well, the process_out existed : we must get it in the process hash
871 * or add it, and draw its items.
873 /* Add process to process list (if not present) */
875 HashedProcessData
*hashed_process_data
= NULL
;
876 ProcessList
*process_list
= control_flow_data
->process_list
;
877 LttTime birth
= process
->creation_time
;
879 if(likely(process_list
->current_hash_data
[cpu
] != NULL
)) {
880 hashed_process_data
= process_list
->current_hash_data
[cpu
];
882 hashed_process_data
= processlist_get_process_data(process_list
,
886 tfc
->t_context
->index
);
887 if(unlikely(hashed_process_data
== NULL
))
889 g_assert(pid
== 0 || pid
!= process
->ppid
);
890 ProcessInfo
*process_info
;
891 /* Process not present */
892 Drawing_t
*drawing
= control_flow_data
->drawing
;
893 processlist_add(process_list
,
899 tfc
->t_context
->index
,
903 &hashed_process_data
);
904 gtk_widget_set_size_request(drawing
->drawing_area
,
907 gtk_widget_queue_draw(drawing
->drawing_area
);
909 /* Set the current process */
910 process_list
->current_hash_data
[process
->cpu
] =
914 /* Now, the process is in the state hash and our own process hash.
915 * We definitely can draw the items related to the ending state.
918 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
921 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
922 TimeWindow time_window
=
923 lttvwindow_get_time_window(control_flow_data
->tab
);
926 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
927 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
930 Drawing_t
*drawing
= control_flow_data
->drawing
;
931 guint width
= drawing
->width
;
933 convert_time_to_pixels(
939 /* Draw collision indicator */
940 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
941 gdk_draw_point(hashed_process_data
->pixmap
,
944 (hashed_process_data
->height
/2)-3);
945 hashed_process_data
->x
.middle_marked
= TRUE
;
948 TimeWindow time_window
=
949 lttvwindow_get_time_window(control_flow_data
->tab
);
952 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
953 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
956 Drawing_t
*drawing
= control_flow_data
->drawing
;
957 guint width
= drawing
->width
;
960 convert_time_to_pixels(
967 /* Jump over draw if we are at the same x position */
968 if(unlikely(x
== hashed_process_data
->x
.middle
&&
969 hashed_process_data
->x
.middle_used
))
971 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
972 /* Draw collision indicator */
973 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
974 gdk_draw_point(hashed_process_data
->pixmap
,
977 (hashed_process_data
->height
/2)-3);
978 hashed_process_data
->x
.middle_marked
= TRUE
;
983 DrawContext draw_context
;
984 /* Now create the drawing context that will be used to draw
985 * items related to the last state. */
986 draw_context
.drawable
= hashed_process_data
->pixmap
;
987 draw_context
.gc
= drawing
->gc
;
988 draw_context
.pango_layout
= drawing
->pango_layout
;
989 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
990 draw_context
.drawinfo
.end
.x
= x
;
992 draw_context
.drawinfo
.y
.over
= 1;
993 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
994 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
996 draw_context
.drawinfo
.start
.offset
.over
= 0;
997 draw_context
.drawinfo
.start
.offset
.middle
= 0;
998 draw_context
.drawinfo
.start
.offset
.under
= 0;
999 draw_context
.drawinfo
.end
.offset
.over
= 0;
1000 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1001 draw_context
.drawinfo
.end
.offset
.under
= 0;
1005 PropertiesLine prop_line
= prepare_s_e_line(process
);
1006 draw_line((void*)&prop_line
, (void*)&draw_context
);
1009 /* become the last x position */
1010 hashed_process_data
->x
.middle
= x
;
1011 hashed_process_data
->x
.middle_used
= TRUE
;
1012 hashed_process_data
->x
.middle_marked
= FALSE
;
1014 /* Calculate the next good time */
1015 convert_pixels_to_time(width
, x
+1, time_window
,
1016 &hashed_process_data
->next_good_time
);
1023 /* before_process_exit_hook
1025 * Draw lines for process event.
1027 * @param hook_data ControlFlowData structure of the viewer.
1028 * @param call_data Event context.
1030 * This function adds items to be drawn in a queue for each process.
1035 int before_process_exit_hook(void *hook_data
, void *call_data
)
1037 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1038 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1040 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1042 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1044 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1046 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1049 e
= ltt_tracefile_get_event(tfc
->tf
);
1051 LttTime evtime
= ltt_event_time(e
);
1053 /* Add process to process list (if not present) */
1054 //LttvProcessState *process = tfs->process;
1055 guint cpu
= ltt_tracefile_num(tfc
->tf
);
1056 LttvProcessState
*process
= ts
->running_process
[cpu
];
1057 guint pid
= process
->pid
;
1059 guint pl_height
= 0;
1060 HashedProcessData
*hashed_process_data
= NULL
;
1062 ProcessList
*process_list
= control_flow_data
->process_list
;
1064 g_assert(process
!= NULL
);
1066 birth
= process
->creation_time
;
1068 if(likely(process_list
->current_hash_data
[cpu
] != NULL
)) {
1069 hashed_process_data
= process_list
->current_hash_data
[cpu
];
1071 hashed_process_data
= processlist_get_process_data(process_list
,
1075 tfc
->t_context
->index
);
1076 if(unlikely(hashed_process_data
== NULL
))
1078 g_assert(pid
== 0 || pid
!= process
->ppid
);
1079 /* Process not present */
1080 Drawing_t
*drawing
= control_flow_data
->drawing
;
1081 ProcessInfo
*process_info
;
1082 processlist_add(process_list
,
1088 tfc
->t_context
->index
,
1092 &hashed_process_data
);
1093 gtk_widget_set_size_request(drawing
->drawing_area
,
1096 gtk_widget_queue_draw(drawing
->drawing_area
);
1100 /* Now, the process is in the state hash and our own process hash.
1101 * We definitely can draw the items related to the ending state.
1104 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1107 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1108 TimeWindow time_window
=
1109 lttvwindow_get_time_window(control_flow_data
->tab
);
1112 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1113 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1115 #endif //EXTRA_CHECK
1116 Drawing_t
*drawing
= control_flow_data
->drawing
;
1117 guint width
= drawing
->width
;
1119 convert_time_to_pixels(
1125 /* Draw collision indicator */
1126 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1127 gdk_draw_point(hashed_process_data
->pixmap
,
1130 (hashed_process_data
->height
/2)-3);
1131 hashed_process_data
->x
.middle_marked
= TRUE
;
1134 TimeWindow time_window
=
1135 lttvwindow_get_time_window(control_flow_data
->tab
);
1138 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1139 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1141 #endif //EXTRA_CHECK
1142 Drawing_t
*drawing
= control_flow_data
->drawing
;
1143 guint width
= drawing
->width
;
1146 convert_time_to_pixels(
1153 /* Jump over draw if we are at the same x position */
1154 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1155 hashed_process_data
->x
.middle_used
))
1157 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1158 /* Draw collision indicator */
1159 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1160 gdk_draw_point(hashed_process_data
->pixmap
,
1163 (hashed_process_data
->height
/2)-3);
1164 hashed_process_data
->x
.middle_marked
= TRUE
;
1168 DrawContext draw_context
;
1170 /* Now create the drawing context that will be used to draw
1171 * items related to the last state. */
1172 draw_context
.drawable
= hashed_process_data
->pixmap
;
1173 draw_context
.gc
= drawing
->gc
;
1174 draw_context
.pango_layout
= drawing
->pango_layout
;
1175 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1176 draw_context
.drawinfo
.end
.x
= x
;
1178 draw_context
.drawinfo
.y
.over
= 1;
1179 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1180 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1182 draw_context
.drawinfo
.start
.offset
.over
= 0;
1183 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1184 draw_context
.drawinfo
.start
.offset
.under
= 0;
1185 draw_context
.drawinfo
.end
.offset
.over
= 0;
1186 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1187 draw_context
.drawinfo
.end
.offset
.under
= 0;
1191 PropertiesLine prop_line
= prepare_s_e_line(process
);
1192 draw_line((void*)&prop_line
, (void*)&draw_context
);
1195 /* become the last x position */
1196 hashed_process_data
->x
.middle
= x
;
1197 hashed_process_data
->x
.middle_used
= TRUE
;
1198 hashed_process_data
->x
.middle_marked
= FALSE
;
1200 /* Calculate the next good time */
1201 convert_pixels_to_time(width
, x
+1, time_window
,
1202 &hashed_process_data
->next_good_time
);
1212 /* before_process_release_hook
1214 * Draw lines for process event.
1216 * @param hook_data ControlFlowData structure of the viewer.
1217 * @param call_data Event context.
1219 * This function adds items to be drawn in a queue for each process.
1224 int before_process_release_hook(void *hook_data
, void *call_data
)
1226 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1227 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1229 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1231 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1233 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1235 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1238 e
= ltt_tracefile_get_event(tfc
->tf
);
1240 LttTime evtime
= ltt_event_time(e
);
1245 pid
= ltt_event_get_long_unsigned(e
, thf
->f1
);
1248 /* Add process to process list (if not present) */
1249 /* Don't care about the process if it's not in the state hash already :
1250 * that means a process that has never done anything in the trace and
1251 * unknown suddently gets destroyed : no state meaningful to show. */
1252 LttvProcessState
*process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1254 if(process
!= NULL
) {
1256 guint pl_height
= 0;
1257 HashedProcessData
*hashed_process_data
= NULL
;
1259 ProcessList
*process_list
= control_flow_data
->process_list
;
1261 birth
= process
->creation_time
;
1263 /* Cannot use current process : this event happens on another process,
1264 * action done by the parent. */
1265 hashed_process_data
= processlist_get_process_data(process_list
,
1269 tfc
->t_context
->index
);
1270 if(unlikely(hashed_process_data
== NULL
))
1272 g_assert(pid
== 0 || pid
!= process
->ppid
);
1273 /* Process not present */
1274 Drawing_t
*drawing
= control_flow_data
->drawing
;
1275 ProcessInfo
*process_info
;
1276 processlist_add(process_list
,
1282 tfc
->t_context
->index
,
1286 &hashed_process_data
);
1287 gtk_widget_set_size_request(drawing
->drawing_area
,
1290 gtk_widget_queue_draw(drawing
->drawing_area
);
1293 /* Now, the process is in the state hash and our own process hash.
1294 * We definitely can draw the items related to the ending state.
1297 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1300 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1301 TimeWindow time_window
=
1302 lttvwindow_get_time_window(control_flow_data
->tab
);
1305 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1306 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1308 #endif //EXTRA_CHECK
1309 Drawing_t
*drawing
= control_flow_data
->drawing
;
1310 guint width
= drawing
->width
;
1312 convert_time_to_pixels(
1318 /* Draw collision indicator */
1319 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1320 gdk_draw_point(hashed_process_data
->pixmap
,
1323 (hashed_process_data
->height
/2)-3);
1324 hashed_process_data
->x
.middle_marked
= TRUE
;
1327 TimeWindow time_window
=
1328 lttvwindow_get_time_window(control_flow_data
->tab
);
1331 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1332 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1334 #endif //EXTRA_CHECK
1335 Drawing_t
*drawing
= control_flow_data
->drawing
;
1336 guint width
= drawing
->width
;
1339 convert_time_to_pixels(
1346 /* Jump over draw if we are at the same x position */
1347 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1348 hashed_process_data
->x
.middle_used
))
1350 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1351 /* Draw collision indicator */
1352 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1353 gdk_draw_point(hashed_process_data
->pixmap
,
1356 (hashed_process_data
->height
/2)-3);
1357 hashed_process_data
->x
.middle_marked
= TRUE
;
1361 DrawContext draw_context
;
1363 /* Now create the drawing context that will be used to draw
1364 * items related to the last state. */
1365 draw_context
.drawable
= hashed_process_data
->pixmap
;
1366 draw_context
.gc
= drawing
->gc
;
1367 draw_context
.pango_layout
= drawing
->pango_layout
;
1368 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1369 draw_context
.drawinfo
.end
.x
= x
;
1371 draw_context
.drawinfo
.y
.over
= 1;
1372 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1373 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1375 draw_context
.drawinfo
.start
.offset
.over
= 0;
1376 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1377 draw_context
.drawinfo
.start
.offset
.under
= 0;
1378 draw_context
.drawinfo
.end
.offset
.over
= 0;
1379 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1380 draw_context
.drawinfo
.end
.offset
.under
= 0;
1384 PropertiesLine prop_line
= prepare_s_e_line(process
);
1385 draw_line((void*)&prop_line
, (void*)&draw_context
);
1388 /* become the last x position */
1389 hashed_process_data
->x
.middle
= x
;
1390 hashed_process_data
->x
.middle_used
= TRUE
;
1391 hashed_process_data
->x
.middle_marked
= FALSE
;
1393 /* Calculate the next good time */
1394 convert_pixels_to_time(width
, x
+1, time_window
,
1395 &hashed_process_data
->next_good_time
);
1407 /* after_process_fork_hook
1409 * Create the processlist entry for the child process. Put the last
1410 * position in x at the current time value.
1412 * @param hook_data ControlFlowData structure of the viewer.
1413 * @param call_data Event context.
1415 * This function adds items to be drawn in a queue for each process.
1418 int after_process_fork_hook(void *hook_data
, void *call_data
)
1420 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1421 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1422 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1424 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1426 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1428 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1431 e
= ltt_tracefile_get_event(tfc
->tf
);
1433 LttTime evtime
= ltt_event_time(e
);
1437 child_pid
= ltt_event_get_long_unsigned(e
, thf
->f2
);
1440 /* Add process to process list (if not present) */
1441 LttvProcessState
*process_child
;
1443 guint pl_height
= 0;
1444 HashedProcessData
*hashed_process_data_child
= NULL
;
1446 ProcessList
*process_list
= control_flow_data
->process_list
;
1448 /* Find child in the list... */
1449 process_child
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1450 /* It should exist, because we are after the state update. */
1451 g_assert(process_child
!= NULL
);
1453 birth
= process_child
->creation_time
;
1455 /* Cannot use current process, because this action is done by the parent
1457 hashed_process_data_child
= processlist_get_process_data(process_list
,
1461 tfc
->t_context
->index
);
1462 if(likely(hashed_process_data_child
== NULL
))
1464 g_assert(child_pid
== 0 || child_pid
!= process_child
->ppid
);
1465 /* Process not present */
1466 Drawing_t
*drawing
= control_flow_data
->drawing
;
1467 ProcessInfo
*process_info
;
1468 processlist_add(process_list
,
1472 process_child
->ppid
,
1474 tfc
->t_context
->index
,
1475 process_child
->name
,
1478 &hashed_process_data_child
);
1479 gtk_widget_set_size_request(drawing
->drawing_area
,
1482 gtk_widget_queue_draw(drawing
->drawing_area
);
1486 if(likely(ltt_time_compare(hashed_process_data_child
->next_good_time
,
1489 TimeWindow time_window
=
1490 lttvwindow_get_time_window(control_flow_data
->tab
);
1493 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1494 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1496 #endif //EXTRA_CHECK
1497 Drawing_t
*drawing
= control_flow_data
->drawing
;
1498 guint width
= drawing
->width
;
1500 convert_time_to_pixels(
1506 if(likely(hashed_process_data_child
->x
.over
!= new_x
)) {
1507 hashed_process_data_child
->x
.over
= new_x
;
1508 hashed_process_data_child
->x
.over_used
= FALSE
;
1509 hashed_process_data_child
->x
.over_marked
= FALSE
;
1511 if(likely(hashed_process_data_child
->x
.middle
!= new_x
)) {
1512 hashed_process_data_child
->x
.middle
= new_x
;
1513 hashed_process_data_child
->x
.middle_used
= FALSE
;
1514 hashed_process_data_child
->x
.middle_marked
= FALSE
;
1516 if(likely(hashed_process_data_child
->x
.under
!= new_x
)) {
1517 hashed_process_data_child
->x
.under
= new_x
;
1518 hashed_process_data_child
->x
.under_used
= FALSE
;
1519 hashed_process_data_child
->x
.under_marked
= FALSE
;
1527 /* after_process_exit_hook
1529 * Create the processlist entry for the child process. Put the last
1530 * position in x at the current time value.
1532 * @param hook_data ControlFlowData structure of the viewer.
1533 * @param call_data Event context.
1535 * This function adds items to be drawn in a queue for each process.
1538 int after_process_exit_hook(void *hook_data
, void *call_data
)
1540 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1541 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1542 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1544 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1546 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1548 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1551 e
= ltt_tracefile_get_event(tfc
->tf
);
1553 LttTime evtime
= ltt_event_time(e
);
1555 /* Add process to process list (if not present) */
1556 //LttvProcessState *process = tfs->process;
1557 guint cpu
= ltt_tracefile_num(tfc
->tf
);
1558 LttvProcessState
*process
= ts
->running_process
[cpu
];
1560 /* It should exist, because we are after the state update. */
1561 g_assert(process
!= NULL
);
1563 guint pid
= process
->pid
;
1565 guint pl_height
= 0;
1566 HashedProcessData
*hashed_process_data
= NULL
;
1568 ProcessList
*process_list
= control_flow_data
->process_list
;
1570 birth
= process
->creation_time
;
1572 if(likely(process_list
->current_hash_data
[cpu
] != NULL
) ){
1573 hashed_process_data
= process_list
->current_hash_data
[cpu
];
1575 hashed_process_data
= processlist_get_process_data(process_list
,
1579 tfc
->t_context
->index
);
1580 if(unlikely(hashed_process_data
== NULL
))
1582 g_assert(pid
== 0 || pid
!= process
->ppid
);
1583 /* Process not present */
1584 Drawing_t
*drawing
= control_flow_data
->drawing
;
1585 ProcessInfo
*process_info
;
1586 processlist_add(process_list
,
1592 tfc
->t_context
->index
,
1596 &hashed_process_data
);
1597 gtk_widget_set_size_request(drawing
->drawing_area
,
1600 gtk_widget_queue_draw(drawing
->drawing_area
);
1603 /* Set the current process */
1604 process_list
->current_hash_data
[process
->cpu
] =
1605 hashed_process_data
;
1608 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
1611 TimeWindow time_window
=
1612 lttvwindow_get_time_window(control_flow_data
->tab
);
1615 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1616 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1618 #endif //EXTRA_CHECK
1619 Drawing_t
*drawing
= control_flow_data
->drawing
;
1620 guint width
= drawing
->width
;
1622 convert_time_to_pixels(
1627 if(unlikely(hashed_process_data
->x
.middle
!= new_x
)) {
1628 hashed_process_data
->x
.middle
= new_x
;
1629 hashed_process_data
->x
.middle_used
= FALSE
;
1630 hashed_process_data
->x
.middle_marked
= FALSE
;
1638 /* Get the filename of the process to print */
1639 int after_fs_exec_hook(void *hook_data
, void *call_data
)
1641 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1642 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1643 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1645 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1647 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1649 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1651 guint cpu
= ltt_tracefile_num(tfc
->tf
);
1652 LttvProcessState
*process
= ts
->running_process
[cpu
];
1653 g_assert(process
!= NULL
);
1655 guint pid
= process
->pid
;
1657 /* Well, the process_out existed : we must get it in the process hash
1658 * or add it, and draw its items.
1660 /* Add process to process list (if not present) */
1661 guint pl_height
= 0;
1662 HashedProcessData
*hashed_process_data
= NULL
;
1663 ProcessList
*process_list
= control_flow_data
->process_list
;
1664 LttTime birth
= process
->creation_time
;
1666 if(likely(process_list
->current_hash_data
[cpu
] != NULL
)) {
1667 hashed_process_data
= process_list
->current_hash_data
[cpu
];
1669 hashed_process_data
= processlist_get_process_data(process_list
,
1673 tfc
->t_context
->index
);
1674 if(unlikely(hashed_process_data
== NULL
))
1676 g_assert(pid
== 0 || pid
!= process
->ppid
);
1677 ProcessInfo
*process_info
;
1678 /* Process not present */
1679 Drawing_t
*drawing
= control_flow_data
->drawing
;
1680 processlist_add(process_list
,
1686 tfc
->t_context
->index
,
1690 &hashed_process_data
);
1691 gtk_widget_set_size_request(drawing
->drawing_area
,
1694 gtk_widget_queue_draw(drawing
->drawing_area
);
1696 /* Set the current process */
1697 process_list
->current_hash_data
[process
->cpu
] =
1698 hashed_process_data
;
1701 processlist_set_name(process_list
, process
->name
, hashed_process_data
);
1707 /* after_event_enum_process_hook
1709 * DOES EXACTLY THE SAME AS after_schedchange_hook, for the "in" process.
1710 * Create the processlist entry for the child process. Put the last
1711 * position in x at the current time value.
1713 * @param hook_data ControlFlowData structure of the viewer.
1714 * @param call_data Event context.
1716 * This function adds items to be drawn in a queue for each process.
1719 int after_event_enum_process_hook(void *hook_data
, void *call_data
)
1721 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1722 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1723 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1725 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1727 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1729 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1732 e
= ltt_tracefile_get_event(tfc
->tf
);
1734 LttTime evtime
= ltt_event_time(e
);
1736 /* Add process to process list (if not present) */
1737 LttvProcessState
*process_in
;
1739 guint pl_height
= 0;
1740 HashedProcessData
*hashed_process_data_in
= NULL
;
1742 ProcessList
*process_list
= control_flow_data
->process_list
;
1746 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f1
);
1750 /* Find process pid_in in the list... */
1751 process_in
= lttv_state_find_process(ts
, ANY_CPU
, pid_in
);
1752 //process_in = tfs->process;
1753 //guint cpu = ltt_tracefile_num(tfc->tf);
1754 //process_in = ts->running_process[cpu];
1755 /* It should exist, because we are after the state update. */
1757 //g_assert(process_in != NULL);
1758 #endif //EXTRA_CHECK
1759 birth
= process_in
->creation_time
;
1761 hashed_process_data_in
= processlist_get_process_data(process_list
,
1765 tfc
->t_context
->index
);
1766 if(hashed_process_data_in
== NULL
)
1768 if(pid_in
!= 0 && pid_in
== process_in
->ppid
)
1769 g_critical("TEST %u , %u", pid_in
, process_in
->ppid
);
1770 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
1771 ProcessInfo
*process_info
;
1772 Drawing_t
*drawing
= control_flow_data
->drawing
;
1773 /* Process not present */
1774 processlist_add(process_list
,
1780 tfc
->t_context
->index
,
1784 &hashed_process_data_in
);
1785 gtk_widget_set_size_request(drawing
->drawing_area
,
1788 gtk_widget_queue_draw(drawing
->drawing_area
);
1790 /* Set the current process */
1791 process_list
->current_hash_data
[process_in
->cpu
] =
1792 hashed_process_data_in
;
1794 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
1797 TimeWindow time_window
=
1798 lttvwindow_get_time_window(control_flow_data
->tab
);
1801 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1802 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1804 #endif //EXTRA_CHECK
1805 Drawing_t
*drawing
= control_flow_data
->drawing
;
1806 guint width
= drawing
->width
;
1809 convert_time_to_pixels(
1815 if(hashed_process_data_in
->x
.middle
!= new_x
) {
1816 hashed_process_data_in
->x
.middle
= new_x
;
1817 hashed_process_data_in
->x
.middle_used
= FALSE
;
1818 hashed_process_data_in
->x
.middle_marked
= FALSE
;
1825 gint
update_time_window_hook(void *hook_data
, void *call_data
)
1827 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1828 Drawing_t
*drawing
= control_flow_data
->drawing
;
1829 ProcessList
*process_list
= control_flow_data
->process_list
;
1831 const TimeWindowNotifyData
*time_window_nofify_data
=
1832 ((const TimeWindowNotifyData
*)call_data
);
1834 TimeWindow
*old_time_window
=
1835 time_window_nofify_data
->old_time_window
;
1836 TimeWindow
*new_time_window
=
1837 time_window_nofify_data
->new_time_window
;
1839 /* Update the ruler */
1840 drawing_update_ruler(control_flow_data
->drawing
,
1844 /* Two cases : zoom in/out or scrolling */
1846 /* In order to make sure we can reuse the old drawing, the scale must
1847 * be the same and the new time interval being partly located in the
1848 * currently shown time interval. (reuse is only for scrolling)
1851 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
1852 old_time_window
->start_time
.tv_sec
,
1853 old_time_window
->start_time
.tv_nsec
,
1854 old_time_window
->time_width
.tv_sec
,
1855 old_time_window
->time_width
.tv_nsec
);
1857 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
1858 new_time_window
->start_time
.tv_sec
,
1859 new_time_window
->start_time
.tv_nsec
,
1860 new_time_window
->time_width
.tv_sec
,
1861 new_time_window
->time_width
.tv_nsec
);
1863 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
1864 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
1866 /* Same scale (scrolling) */
1867 g_info("scrolling");
1868 LttTime
*ns
= &new_time_window
->start_time
;
1869 LttTime
*nw
= &new_time_window
->time_width
;
1870 LttTime
*os
= &old_time_window
->start_time
;
1871 LttTime
*ow
= &old_time_window
->time_width
;
1872 LttTime old_end
= old_time_window
->end_time
;
1873 LttTime new_end
= new_time_window
->end_time
;
1875 //if(ns<os+w && os+w<ns+w)
1876 //if(ns<old_end && os<ns)
1877 if(ltt_time_compare(*ns
, old_end
) == -1
1878 && ltt_time_compare(*os
, *ns
) == -1)
1880 g_info("scrolling near right");
1881 /* Scroll right, keep right part of the screen */
1883 guint width
= control_flow_data
->drawing
->width
;
1884 convert_time_to_pixels(
1890 /* Copy old data to new location */
1891 copy_pixmap_region(process_list
,
1893 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1897 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
1899 if(drawing
->damage_begin
== drawing
->damage_end
)
1900 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
1902 drawing
->damage_begin
= 0;
1904 drawing
->damage_end
= control_flow_data
->drawing
->width
;
1906 /* Clear the data request background, but not SAFETY */
1907 rectangle_pixmap(process_list
,
1908 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1910 drawing
->damage_begin
+SAFETY
, 0,
1911 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
1913 gtk_widget_queue_draw(drawing
->drawing_area
);
1914 //gtk_widget_queue_draw_area (drawing->drawing_area,
1916 // control_flow_data->drawing->width,
1917 // control_flow_data->drawing->height);
1919 /* Get new data for the rest. */
1920 drawing_data_request(control_flow_data
->drawing
,
1921 drawing
->damage_begin
, 0,
1922 drawing
->damage_end
- drawing
->damage_begin
,
1923 control_flow_data
->drawing
->height
);
1926 //if(ns<os && os<ns+w)
1927 //if(ns<os && os<new_end)
1928 if(ltt_time_compare(*ns
,*os
) == -1
1929 && ltt_time_compare(*os
,new_end
) == -1)
1931 g_info("scrolling near left");
1932 /* Scroll left, keep left part of the screen */
1934 guint width
= control_flow_data
->drawing
->width
;
1935 convert_time_to_pixels(
1941 /* Copy old data to new location */
1942 copy_pixmap_region (process_list
,
1944 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1950 if(drawing
->damage_begin
== drawing
->damage_end
)
1951 drawing
->damage_end
= x
;
1953 drawing
->damage_end
=
1954 control_flow_data
->drawing
->width
;
1956 drawing
->damage_begin
= 0;
1958 rectangle_pixmap (process_list
,
1959 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1961 drawing
->damage_begin
, 0,
1962 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
1965 gtk_widget_queue_draw(drawing
->drawing_area
);
1966 //gtk_widget_queue_draw_area (drawing->drawing_area,
1968 // control_flow_data->drawing->width,
1969 // control_flow_data->drawing->height);
1972 /* Get new data for the rest. */
1973 drawing_data_request(control_flow_data
->drawing
,
1974 drawing
->damage_begin
, 0,
1975 drawing
->damage_end
- drawing
->damage_begin
,
1976 control_flow_data
->drawing
->height
);
1979 if(ltt_time_compare(*ns
,*os
) == 0)
1981 g_info("not scrolling");
1983 g_info("scrolling far");
1984 /* Cannot reuse any part of the screen : far jump */
1987 rectangle_pixmap (process_list
,
1988 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1991 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
1994 //gtk_widget_queue_draw_area (drawing->drawing_area,
1996 // control_flow_data->drawing->width,
1997 // control_flow_data->drawing->height);
1998 gtk_widget_queue_draw(drawing
->drawing_area
);
2000 drawing
->damage_begin
= 0;
2001 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2003 drawing_data_request(control_flow_data
->drawing
,
2005 control_flow_data
->drawing
->width
,
2006 control_flow_data
->drawing
->height
);
2012 /* Different scale (zoom) */
2015 rectangle_pixmap (process_list
,
2016 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2019 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2022 //gtk_widget_queue_draw_area (drawing->drawing_area,
2024 // control_flow_data->drawing->width,
2025 // control_flow_data->drawing->height);
2026 gtk_widget_queue_draw(drawing
->drawing_area
);
2028 drawing
->damage_begin
= 0;
2029 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2031 drawing_data_request(control_flow_data
->drawing
,
2033 control_flow_data
->drawing
->width
,
2034 control_flow_data
->drawing
->height
);
2037 /* Update directly when scrolling */
2038 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2044 gint
traceset_notify(void *hook_data
, void *call_data
)
2046 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2047 Drawing_t
*drawing
= control_flow_data
->drawing
;
2049 if(unlikely(drawing
->gc
== NULL
)) {
2052 if(drawing
->dotted_gc
== NULL
) {
2056 drawing_clear(control_flow_data
->drawing
);
2057 processlist_clear(control_flow_data
->process_list
);
2058 gtk_widget_set_size_request(
2059 control_flow_data
->drawing
->drawing_area
,
2060 -1, processlist_get_height(control_flow_data
->process_list
));
2061 redraw_notify(control_flow_data
, NULL
);
2063 request_background_data(control_flow_data
);
2068 gint
redraw_notify(void *hook_data
, void *call_data
)
2070 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2071 Drawing_t
*drawing
= control_flow_data
->drawing
;
2072 GtkWidget
*widget
= drawing
->drawing_area
;
2074 drawing
->damage_begin
= 0;
2075 drawing
->damage_end
= drawing
->width
;
2077 /* fun feature, to be separated someday... */
2078 drawing_clear(control_flow_data
->drawing
);
2079 processlist_clear(control_flow_data
->process_list
);
2080 gtk_widget_set_size_request(
2081 control_flow_data
->drawing
->drawing_area
,
2082 -1, processlist_get_height(control_flow_data
->process_list
));
2084 rectangle_pixmap (control_flow_data
->process_list
,
2085 widget
->style
->black_gc
,
2088 drawing
->alloc_width
,
2091 gtk_widget_queue_draw(drawing
->drawing_area
);
2093 if(drawing
->damage_begin
< drawing
->damage_end
)
2095 drawing_data_request(drawing
,
2096 drawing
->damage_begin
,
2098 drawing
->damage_end
-drawing
->damage_begin
,
2102 //gtk_widget_queue_draw_area(drawing->drawing_area,
2105 // drawing->height);
2111 gint
continue_notify(void *hook_data
, void *call_data
)
2113 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2114 Drawing_t
*drawing
= control_flow_data
->drawing
;
2116 //g_assert(widget->allocation.width == drawing->damage_end);
2118 if(drawing
->damage_begin
< drawing
->damage_end
)
2120 drawing_data_request(drawing
,
2121 drawing
->damage_begin
,
2123 drawing
->damage_end
-drawing
->damage_begin
,
2131 gint
update_current_time_hook(void *hook_data
, void *call_data
)
2133 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
2134 Drawing_t
*drawing
= control_flow_data
->drawing
;
2136 LttTime current_time
= *((LttTime
*)call_data
);
2138 TimeWindow time_window
=
2139 lttvwindow_get_time_window(control_flow_data
->tab
);
2141 LttTime time_begin
= time_window
.start_time
;
2142 LttTime width
= time_window
.time_width
;
2145 guint64 time_ll
= ltt_time_to_uint64(width
);
2146 time_ll
= time_ll
>> 1; /* divide by two */
2147 half_width
= ltt_time_from_uint64(time_ll
);
2149 LttTime time_end
= ltt_time_add(time_begin
, width
);
2151 LttvTracesetContext
* tsc
=
2152 lttvwindow_get_traceset_context(control_flow_data
->tab
);
2154 LttTime trace_start
= tsc
->time_span
.start_time
;
2155 LttTime trace_end
= tsc
->time_span
.end_time
;
2157 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
2158 current_time
.tv_nsec
);
2162 /* If current time is inside time interval, just move the highlight
2165 /* Else, we have to change the time interval. We have to tell it
2166 * to the main window. */
2167 /* The time interval change will take care of placing the current
2168 * time at the center of the visible area, or nearest possible if we are
2169 * at one end of the trace. */
2172 if(ltt_time_compare(current_time
, time_begin
) < 0)
2174 TimeWindow new_time_window
;
2176 if(ltt_time_compare(current_time
,
2177 ltt_time_add(trace_start
,half_width
)) < 0)
2178 time_begin
= trace_start
;
2180 time_begin
= ltt_time_sub(current_time
,half_width
);
2182 new_time_window
.start_time
= time_begin
;
2183 new_time_window
.time_width
= width
;
2184 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2185 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2187 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2189 else if(ltt_time_compare(current_time
, time_end
) > 0)
2191 TimeWindow new_time_window
;
2193 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
2194 time_begin
= ltt_time_sub(trace_end
,width
);
2196 time_begin
= ltt_time_sub(current_time
,half_width
);
2198 new_time_window
.start_time
= time_begin
;
2199 new_time_window
.time_width
= width
;
2200 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2201 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2203 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2206 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2208 /* Update directly when scrolling */
2209 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2215 typedef struct _ClosureData
{
2216 EventsRequest
*events_request
;
2217 LttvTracesetState
*tss
;
2223 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
2225 ProcessInfo
*process_info
= (ProcessInfo
*)key
;
2226 HashedProcessData
*hashed_process_data
= (HashedProcessData
*)value
;
2227 ClosureData
*closure_data
= (ClosureData
*)user_data
;
2229 EventsRequest
*events_request
= closure_data
->events_request
;
2230 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2232 LttvTracesetState
*tss
= closure_data
->tss
;
2233 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)tss
;
2235 LttTime evtime
= closure_data
->end_time
;
2238 /* For the process */
2239 /* First, check if the current process is in the state computation
2240 * process list. If it is there, that means we must add it right now and
2241 * draw items from the beginning of the read for it. If it is not
2242 * present, it's a new process and it was not present : it will
2243 * be added after the state update. */
2245 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
2246 #endif //EXTRA_CHECK
2247 LttvTraceContext
*tc
= tsc
->traces
[process_info
->trace_num
];
2248 LttvTraceState
*ts
= (LttvTraceState
*)tc
;
2251 //FIXME : optimize data structures.
2252 LttvTracefileState
*tfs
;
2253 LttvTracefileContext
*tfc
;
2255 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
2256 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
2257 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
2258 && ltt_tracefile_num(tfc
->tf
) == process_info
->cpu
)
2262 g_assert(i
<tc
->tracefiles
->len
);
2263 tfs
= LTTV_TRACEFILE_STATE(tfc
);
2265 // LttvTracefileState *tfs =
2266 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2267 // tracefiles[process_info->cpu];
2269 LttvProcessState
*process
;
2270 process
= lttv_state_find_process(ts
, process_info
->cpu
,
2273 if(unlikely(process
!= NULL
)) {
2275 /* Only draw for processes that are currently in the trace states */
2277 ProcessList
*process_list
= control_flow_data
->process_list
;
2279 /* Should be alike when background info is ready */
2280 if(control_flow_data
->background_info_waiting
==0)
2281 g_assert(ltt_time_compare(process
->creation_time
,
2282 process_info
->birth
) == 0);
2283 #endif //EXTRA_CHECK
2285 /* Now, the process is in the state hash and our own process hash.
2286 * We definitely can draw the items related to the ending state.
2289 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2292 TimeWindow time_window
=
2293 lttvwindow_get_time_window(control_flow_data
->tab
);
2296 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2297 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2299 #endif //EXTRA_CHECK
2300 Drawing_t
*drawing
= control_flow_data
->drawing
;
2301 guint width
= drawing
->width
;
2303 guint x
= closure_data
->x_end
;
2305 DrawContext draw_context
;
2307 /* Now create the drawing context that will be used to draw
2308 * items related to the last state. */
2309 draw_context
.drawable
= hashed_process_data
->pixmap
;
2310 draw_context
.gc
= drawing
->gc
;
2311 draw_context
.pango_layout
= drawing
->pango_layout
;
2312 draw_context
.drawinfo
.end
.x
= x
;
2314 draw_context
.drawinfo
.y
.over
= 1;
2315 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2316 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2318 draw_context
.drawinfo
.start
.offset
.over
= 0;
2319 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2320 draw_context
.drawinfo
.start
.offset
.under
= 0;
2321 draw_context
.drawinfo
.end
.offset
.over
= 0;
2322 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2323 draw_context
.drawinfo
.end
.offset
.under
= 0;
2325 /* Jump over draw if we are at the same x position */
2326 if(x
== hashed_process_data
->x
.over
)
2330 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2332 PropertiesLine prop_line
= prepare_execmode_line(process
);
2333 draw_line((void*)&prop_line
, (void*)&draw_context
);
2335 hashed_process_data
->x
.over
= x
;
2339 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2340 hashed_process_data
->x
.middle_used
)) {
2341 #if 0 /* do not mark closure : not missing information */
2342 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2343 /* Draw collision indicator */
2344 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2345 gdk_draw_point(drawing
->pixmap
,
2349 hashed_process_data
->x
.middle_marked
= TRUE
;
2354 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2356 PropertiesLine prop_line
= prepare_s_e_line(process
);
2357 draw_line((void*)&prop_line
, (void*)&draw_context
);
2359 /* become the last x position */
2360 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2361 hashed_process_data
->x
.middle
= x
;
2362 /* but don't use the pixel */
2363 hashed_process_data
->x
.middle_used
= FALSE
;
2365 /* Calculate the next good time */
2366 convert_pixels_to_time(width
, x
+1, time_window
,
2367 &hashed_process_data
->next_good_time
);
2376 int before_chunk(void *hook_data
, void *call_data
)
2378 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2379 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2380 ControlFlowData
*cfd
= (ControlFlowData
*)events_request
->viewer_data
;
2382 /* Desactivate sort */
2383 gtk_tree_sortable_set_sort_column_id(
2384 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2386 GTK_SORT_ASCENDING
);
2388 drawing_chunk_begin(events_request
, tss
);
2393 int before_request(void *hook_data
, void *call_data
)
2395 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2396 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2398 drawing_data_request_begin(events_request
, tss
);
2405 * after request is necessary in addition of after chunk in order to draw
2406 * lines until the end of the screen. after chunk just draws lines until
2413 int after_request(void *hook_data
, void *call_data
)
2415 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2416 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2417 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2419 ProcessList
*process_list
= control_flow_data
->process_list
;
2420 LttTime end_time
= events_request
->end_time
;
2422 ClosureData closure_data
;
2423 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2424 closure_data
.tss
= tss
;
2425 closure_data
.end_time
= end_time
;
2427 TimeWindow time_window
=
2428 lttvwindow_get_time_window(control_flow_data
->tab
);
2429 guint width
= control_flow_data
->drawing
->width
;
2430 convert_time_to_pixels(
2434 &closure_data
.x_end
);
2437 /* Draw last items */
2438 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2439 (void*)&closure_data
);
2442 /* Request expose */
2443 drawing_request_expose(events_request
, tss
, end_time
);
2452 int after_chunk(void *hook_data
, void *call_data
)
2454 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2455 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2456 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2457 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)call_data
;
2458 LttvTracefileContext
*tfc
= lttv_traceset_context_get_current_tfc(tsc
);
2461 ProcessList
*process_list
= control_flow_data
->process_list
;
2463 g_free(process_list
->current_hash_data
);
2464 process_list
->current_hash_data
= NULL
;
2467 end_time
= LTT_TIME_MIN(tfc
->timestamp
, events_request
->end_time
);
2468 else /* end of traceset, or position now out of request : end */
2469 end_time
= events_request
->end_time
;
2471 ClosureData closure_data
;
2472 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2473 closure_data
.tss
= tss
;
2474 closure_data
.end_time
= end_time
;
2476 TimeWindow time_window
=
2477 lttvwindow_get_time_window(control_flow_data
->tab
);
2478 guint width
= control_flow_data
->drawing
->width
;
2479 convert_time_to_pixels(
2483 &closure_data
.x_end
);
2485 /* Draw last items */
2486 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2487 (void*)&closure_data
);
2489 /* Reactivate sort */
2490 gtk_tree_sortable_set_sort_column_id(
2491 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2492 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2493 GTK_SORT_ASCENDING
);
2495 update_index_to_pixmap(control_flow_data
->process_list
);
2496 /* Request a full expose : drawing scrambled */
2497 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2499 /* Request expose (updates damages zone also) */
2500 drawing_request_expose(events_request
, tss
, end_time
);