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
= tfs
->cpu
;
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
,
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
,
401 tfc
->t_context
->index
,
406 &hashed_process_data
);
407 gtk_widget_set_size_request(drawing
->drawing_area
,
410 gtk_widget_queue_draw(drawing
->drawing_area
);
414 /* Now, the process is in the state hash and our own process hash.
415 * We definitely can draw the items related to the ending state.
418 if(ltt_time_compare(hashed_process_data
->next_good_time
,
421 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
423 TimeWindow time_window
=
424 lttvwindow_get_time_window(control_flow_data
->tab
);
426 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
427 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
430 Drawing_t
*drawing
= control_flow_data
->drawing
;
431 guint width
= drawing
->width
;
433 convert_time_to_pixels(
439 /* Draw collision indicator */
440 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
441 gdk_draw_point(hashed_process_data
->pixmap
,
444 (hashed_process_data
->height
/2)-3);
445 hashed_process_data
->x
.middle_marked
= TRUE
;
448 TimeWindow time_window
=
449 lttvwindow_get_time_window(control_flow_data
->tab
);
451 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
452 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
455 Drawing_t
*drawing
= control_flow_data
->drawing
;
456 guint width
= drawing
->width
;
458 convert_time_to_pixels(
465 /* Jump over draw if we are at the same x position */
466 if(x
== hashed_process_data
->x
.middle
&&
467 hashed_process_data
->x
.middle_used
)
469 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
470 /* Draw collision indicator */
471 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
472 gdk_draw_point(hashed_process_data
->pixmap
,
475 (hashed_process_data
->height
/2)-3);
476 hashed_process_data
->x
.middle_marked
= TRUE
;
480 DrawContext draw_context
;
482 /* Now create the drawing context that will be used to draw
483 * items related to the last state. */
484 draw_context
.drawable
= hashed_process_data
->pixmap
;
485 draw_context
.gc
= drawing
->gc
;
486 draw_context
.pango_layout
= drawing
->pango_layout
;
487 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
488 draw_context
.drawinfo
.end
.x
= x
;
490 draw_context
.drawinfo
.y
.over
= 1;
491 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
492 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
494 draw_context
.drawinfo
.start
.offset
.over
= 0;
495 draw_context
.drawinfo
.start
.offset
.middle
= 0;
496 draw_context
.drawinfo
.start
.offset
.under
= 0;
497 draw_context
.drawinfo
.end
.offset
.over
= 0;
498 draw_context
.drawinfo
.end
.offset
.middle
= 0;
499 draw_context
.drawinfo
.end
.offset
.under
= 0;
503 PropertiesLine prop_line
= prepare_s_e_line(process
);
504 draw_line((void*)&prop_line
, (void*)&draw_context
);
507 /* become the last x position */
508 hashed_process_data
->x
.middle
= x
;
509 hashed_process_data
->x
.middle_used
= TRUE
;
510 hashed_process_data
->x
.middle_marked
= FALSE
;
512 /* Calculate the next good time */
513 convert_pixels_to_time(width
, x
+1, time_window
,
514 &hashed_process_data
->next_good_time
);
522 /* First, check if the current process is in the state computation
523 * process list. If it is there, that means we must add it right now and
524 * draw items from the beginning of the read for it. If it is not
525 * present, it's a new process and it was not present : it will
526 * be added after the state update. */
527 LttvProcessState
*process
;
528 process
= lttv_state_find_process(ts
,
531 if(process
!= NULL
) {
532 /* Well, the process existed : we must get it in the process hash
533 * or add it, and draw its items.
535 /* Add process to process list (if not present) */
537 HashedProcessData
*hashed_process_data
= NULL
;
538 ProcessList
*process_list
= control_flow_data
->process_list
;
539 LttTime birth
= process
->creation_time
;
541 hashed_process_data
= processlist_get_process_data(process_list
,
545 tfc
->t_context
->index
);
546 if(hashed_process_data
== NULL
)
548 g_assert(pid_in
== 0 || pid_in
!= process
->ppid
);
549 /* Process not present */
550 ProcessInfo
*process_info
;
551 Drawing_t
*drawing
= control_flow_data
->drawing
;
552 processlist_add(process_list
,
559 tfc
->t_context
->index
,
564 &hashed_process_data
);
565 gtk_widget_set_size_request(drawing
->drawing_area
,
568 gtk_widget_queue_draw(drawing
->drawing_area
);
571 //We could set the current process and hash here, but will be done
572 //by after schedchange hook
574 /* Now, the process is in the state hash and our own process hash.
575 * We definitely can draw the items related to the ending state.
578 if(ltt_time_compare(hashed_process_data
->next_good_time
,
581 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
583 TimeWindow time_window
=
584 lttvwindow_get_time_window(control_flow_data
->tab
);
586 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
587 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
590 Drawing_t
*drawing
= control_flow_data
->drawing
;
591 guint width
= drawing
->width
;
593 convert_time_to_pixels(
599 /* Draw collision indicator */
600 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
601 gdk_draw_point(hashed_process_data
->pixmap
,
604 (hashed_process_data
->height
/2)-3);
605 hashed_process_data
->x
.middle_marked
= TRUE
;
608 TimeWindow time_window
=
609 lttvwindow_get_time_window(control_flow_data
->tab
);
611 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
612 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
615 Drawing_t
*drawing
= control_flow_data
->drawing
;
616 guint width
= drawing
->width
;
619 convert_time_to_pixels(
626 /* Jump over draw if we are at the same x position */
627 if(x
== hashed_process_data
->x
.middle
&&
628 hashed_process_data
->x
.middle_used
)
630 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
631 /* Draw collision indicator */
632 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
633 gdk_draw_point(hashed_process_data
->pixmap
,
636 (hashed_process_data
->height
/2)-3);
637 hashed_process_data
->x
.middle_marked
= TRUE
;
641 DrawContext draw_context
;
643 /* Now create the drawing context that will be used to draw
644 * items related to the last state. */
645 draw_context
.drawable
= hashed_process_data
->pixmap
;
646 draw_context
.gc
= drawing
->gc
;
647 draw_context
.pango_layout
= drawing
->pango_layout
;
648 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
649 draw_context
.drawinfo
.end
.x
= x
;
651 draw_context
.drawinfo
.y
.over
= 1;
652 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
653 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
655 draw_context
.drawinfo
.start
.offset
.over
= 0;
656 draw_context
.drawinfo
.start
.offset
.middle
= 0;
657 draw_context
.drawinfo
.start
.offset
.under
= 0;
658 draw_context
.drawinfo
.end
.offset
.over
= 0;
659 draw_context
.drawinfo
.end
.offset
.middle
= 0;
660 draw_context
.drawinfo
.end
.offset
.under
= 0;
664 PropertiesLine prop_line
= prepare_s_e_line(process
);
665 draw_line((void*)&prop_line
, (void*)&draw_context
);
669 /* become the last x position */
670 hashed_process_data
->x
.middle
= x
;
671 hashed_process_data
->x
.middle_used
= TRUE
;
672 hashed_process_data
->x
.middle_marked
= FALSE
;
674 /* Calculate the next good time */
675 convert_pixels_to_time(width
, x
+1, time_window
,
676 &hashed_process_data
->next_good_time
);
680 g_warning("Cannot find pin_in in schedchange %u", pid_in
);
689 GString
*string
= g_string_new("");;
690 gboolean field_names
= TRUE
, state
= TRUE
;
692 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
693 g_string_append_printf(string
,"\n");
696 g_string_append_printf(string
, " %s",
697 g_quark_to_string(tfs
->process
->state
->s
));
700 g_info("%s",string
->str
);
702 g_string_free(string
, TRUE
);
704 /* End of text dump */
709 /* after_schedchange_hook
711 * The draw after hook is called by the reading API to have a
712 * particular event drawn on the screen.
713 * @param hook_data ControlFlowData structure of the viewer.
714 * @param call_data Event context.
716 * This function adds items to be drawn in a queue for each process.
719 int after_schedchange_hook(void *hook_data
, void *call_data
)
721 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
722 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
723 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
725 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
727 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
729 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
732 e
= ltt_tracefile_get_event(tfc
->tf
);
734 LttTime evtime
= ltt_event_time(e
);
736 /* Add process to process list (if not present) */
737 LttvProcessState
*process_in
;
740 HashedProcessData
*hashed_process_data_in
= NULL
;
742 ProcessList
*process_list
= control_flow_data
->process_list
;
747 pid_out
= ltt_event_get_long_unsigned(e
, thf
->f1
);
748 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f2
);
752 /* Find process pid_in in the list... */
753 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
754 //process_in = tfs->process;
755 guint cpu
= tfs
->cpu
;
756 process_in
= ts
->running_process
[cpu
];
757 /* It should exist, because we are after the state update. */
759 g_assert(process_in
!= NULL
);
761 birth
= process_in
->creation_time
;
763 hashed_process_data_in
= processlist_get_process_data(process_list
,
767 tfc
->t_context
->index
);
768 if(hashed_process_data_in
== NULL
)
770 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
771 ProcessInfo
*process_info
;
772 Drawing_t
*drawing
= control_flow_data
->drawing
;
773 /* Process not present */
774 processlist_add(process_list
,
781 tfc
->t_context
->index
,
786 &hashed_process_data_in
);
787 gtk_widget_set_size_request(drawing
->drawing_area
,
790 gtk_widget_queue_draw(drawing
->drawing_area
);
792 /* Set the current process */
793 process_list
->current_hash_data
[process_in
->cpu
] =
794 hashed_process_data_in
;
796 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
799 TimeWindow time_window
=
800 lttvwindow_get_time_window(control_flow_data
->tab
);
803 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
804 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
807 Drawing_t
*drawing
= control_flow_data
->drawing
;
808 guint width
= drawing
->width
;
811 convert_time_to_pixels(
817 if(hashed_process_data_in
->x
.middle
!= new_x
) {
818 hashed_process_data_in
->x
.middle
= new_x
;
819 hashed_process_data_in
->x
.middle_used
= FALSE
;
820 hashed_process_data_in
->x
.middle_marked
= FALSE
;
829 /* before_execmode_hook
831 * This function basically draw lines and icons. Two types of lines are drawn :
832 * one small (3 pixels?) representing the state of the process and the second
833 * type is thicker (10 pixels?) representing on which CPU a process is running
834 * (and this only in running state).
836 * Extremums of the lines :
837 * x_min : time of the last event context for this process kept in memory.
838 * x_max : time of the current event.
839 * y : middle of the process in the process list. The process is found in the
840 * list, therefore is it's position in pixels.
842 * The choice of lines'color is defined by the context of the last event for this
847 int before_execmode_hook(void *hook_data
, void *call_data
)
849 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
850 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
851 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
853 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
855 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
857 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
860 e
= ltt_tracefile_get_event(tfc
->tf
);
862 LttTime evtime
= ltt_event_time(e
);
864 /* we are in a execmode, before the state update. We must draw the
865 * items corresponding to the state before it changes : now is the right
869 //LttvProcessState *process = tfs->process;
870 guint cpu
= tfs
->cpu
;
871 LttvProcessState
*process
= ts
->running_process
[cpu
];
872 g_assert(process
!= NULL
);
874 guint pid
= process
->pid
;
876 /* Well, the process_out existed : we must get it in the process hash
877 * or add it, and draw its items.
879 /* Add process to process list (if not present) */
881 HashedProcessData
*hashed_process_data
= NULL
;
882 ProcessList
*process_list
= control_flow_data
->process_list
;
883 LttTime birth
= process
->creation_time
;
885 if(likely(process_list
->current_hash_data
[cpu
] != NULL
)) {
886 hashed_process_data
= process_list
->current_hash_data
[cpu
];
888 hashed_process_data
= processlist_get_process_data(process_list
,
892 tfc
->t_context
->index
);
893 if(unlikely(hashed_process_data
== NULL
))
895 g_assert(pid
== 0 || pid
!= process
->ppid
);
896 ProcessInfo
*process_info
;
897 /* Process not present */
898 Drawing_t
*drawing
= control_flow_data
->drawing
;
899 processlist_add(process_list
,
906 tfc
->t_context
->index
,
911 &hashed_process_data
);
912 gtk_widget_set_size_request(drawing
->drawing_area
,
915 gtk_widget_queue_draw(drawing
->drawing_area
);
917 /* Set the current process */
918 process_list
->current_hash_data
[process
->cpu
] =
922 /* Now, the process is in the state hash and our own process hash.
923 * We definitely can draw the items related to the ending state.
926 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
929 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
930 TimeWindow time_window
=
931 lttvwindow_get_time_window(control_flow_data
->tab
);
934 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
935 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
938 Drawing_t
*drawing
= control_flow_data
->drawing
;
939 guint width
= drawing
->width
;
941 convert_time_to_pixels(
947 /* Draw collision indicator */
948 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
949 gdk_draw_point(hashed_process_data
->pixmap
,
952 (hashed_process_data
->height
/2)-3);
953 hashed_process_data
->x
.middle_marked
= TRUE
;
956 TimeWindow time_window
=
957 lttvwindow_get_time_window(control_flow_data
->tab
);
960 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
961 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
964 Drawing_t
*drawing
= control_flow_data
->drawing
;
965 guint width
= drawing
->width
;
968 convert_time_to_pixels(
975 /* Jump over draw if we are at the same x position */
976 if(unlikely(x
== hashed_process_data
->x
.middle
&&
977 hashed_process_data
->x
.middle_used
))
979 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
980 /* Draw collision indicator */
981 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
982 gdk_draw_point(hashed_process_data
->pixmap
,
985 (hashed_process_data
->height
/2)-3);
986 hashed_process_data
->x
.middle_marked
= TRUE
;
991 DrawContext draw_context
;
992 /* Now create the drawing context that will be used to draw
993 * items related to the last state. */
994 draw_context
.drawable
= hashed_process_data
->pixmap
;
995 draw_context
.gc
= drawing
->gc
;
996 draw_context
.pango_layout
= drawing
->pango_layout
;
997 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
998 draw_context
.drawinfo
.end
.x
= x
;
1000 draw_context
.drawinfo
.y
.over
= 1;
1001 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1002 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1004 draw_context
.drawinfo
.start
.offset
.over
= 0;
1005 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1006 draw_context
.drawinfo
.start
.offset
.under
= 0;
1007 draw_context
.drawinfo
.end
.offset
.over
= 0;
1008 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1009 draw_context
.drawinfo
.end
.offset
.under
= 0;
1013 PropertiesLine prop_line
= prepare_s_e_line(process
);
1014 draw_line((void*)&prop_line
, (void*)&draw_context
);
1017 /* become the last x position */
1018 hashed_process_data
->x
.middle
= x
;
1019 hashed_process_data
->x
.middle_used
= TRUE
;
1020 hashed_process_data
->x
.middle_marked
= FALSE
;
1022 /* Calculate the next good time */
1023 convert_pixels_to_time(width
, x
+1, time_window
,
1024 &hashed_process_data
->next_good_time
);
1031 /* before_process_exit_hook
1033 * Draw lines for process event.
1035 * @param hook_data ControlFlowData structure of the viewer.
1036 * @param call_data Event context.
1038 * This function adds items to be drawn in a queue for each process.
1043 int before_process_exit_hook(void *hook_data
, void *call_data
)
1045 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1046 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1048 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1050 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1052 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1054 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1057 e
= ltt_tracefile_get_event(tfc
->tf
);
1059 LttTime evtime
= ltt_event_time(e
);
1061 /* Add process to process list (if not present) */
1062 //LttvProcessState *process = tfs->process;
1063 guint cpu
= tfs
->cpu
;
1064 LttvProcessState
*process
= ts
->running_process
[cpu
];
1065 guint pid
= process
->pid
;
1067 guint pl_height
= 0;
1068 HashedProcessData
*hashed_process_data
= NULL
;
1070 ProcessList
*process_list
= control_flow_data
->process_list
;
1072 g_assert(process
!= NULL
);
1074 birth
= process
->creation_time
;
1076 if(likely(process_list
->current_hash_data
[cpu
] != NULL
)) {
1077 hashed_process_data
= process_list
->current_hash_data
[cpu
];
1079 hashed_process_data
= processlist_get_process_data(process_list
,
1083 tfc
->t_context
->index
);
1084 if(unlikely(hashed_process_data
== NULL
))
1086 g_assert(pid
== 0 || pid
!= process
->ppid
);
1087 /* Process not present */
1088 Drawing_t
*drawing
= control_flow_data
->drawing
;
1089 ProcessInfo
*process_info
;
1090 processlist_add(process_list
,
1097 tfc
->t_context
->index
,
1102 &hashed_process_data
);
1103 gtk_widget_set_size_request(drawing
->drawing_area
,
1106 gtk_widget_queue_draw(drawing
->drawing_area
);
1110 /* Now, the process is in the state hash and our own process hash.
1111 * We definitely can draw the items related to the ending state.
1114 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1117 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1118 TimeWindow time_window
=
1119 lttvwindow_get_time_window(control_flow_data
->tab
);
1122 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1123 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1125 #endif //EXTRA_CHECK
1126 Drawing_t
*drawing
= control_flow_data
->drawing
;
1127 guint width
= drawing
->width
;
1129 convert_time_to_pixels(
1135 /* Draw collision indicator */
1136 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1137 gdk_draw_point(hashed_process_data
->pixmap
,
1140 (hashed_process_data
->height
/2)-3);
1141 hashed_process_data
->x
.middle_marked
= TRUE
;
1144 TimeWindow time_window
=
1145 lttvwindow_get_time_window(control_flow_data
->tab
);
1148 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1149 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1151 #endif //EXTRA_CHECK
1152 Drawing_t
*drawing
= control_flow_data
->drawing
;
1153 guint width
= drawing
->width
;
1156 convert_time_to_pixels(
1163 /* Jump over draw if we are at the same x position */
1164 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1165 hashed_process_data
->x
.middle_used
))
1167 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1168 /* Draw collision indicator */
1169 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1170 gdk_draw_point(hashed_process_data
->pixmap
,
1173 (hashed_process_data
->height
/2)-3);
1174 hashed_process_data
->x
.middle_marked
= TRUE
;
1178 DrawContext draw_context
;
1180 /* Now create the drawing context that will be used to draw
1181 * items related to the last state. */
1182 draw_context
.drawable
= hashed_process_data
->pixmap
;
1183 draw_context
.gc
= drawing
->gc
;
1184 draw_context
.pango_layout
= drawing
->pango_layout
;
1185 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1186 draw_context
.drawinfo
.end
.x
= x
;
1188 draw_context
.drawinfo
.y
.over
= 1;
1189 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1190 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1192 draw_context
.drawinfo
.start
.offset
.over
= 0;
1193 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1194 draw_context
.drawinfo
.start
.offset
.under
= 0;
1195 draw_context
.drawinfo
.end
.offset
.over
= 0;
1196 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1197 draw_context
.drawinfo
.end
.offset
.under
= 0;
1201 PropertiesLine prop_line
= prepare_s_e_line(process
);
1202 draw_line((void*)&prop_line
, (void*)&draw_context
);
1205 /* become the last x position */
1206 hashed_process_data
->x
.middle
= x
;
1207 hashed_process_data
->x
.middle_used
= TRUE
;
1208 hashed_process_data
->x
.middle_marked
= FALSE
;
1210 /* Calculate the next good time */
1211 convert_pixels_to_time(width
, x
+1, time_window
,
1212 &hashed_process_data
->next_good_time
);
1222 /* before_process_release_hook
1224 * Draw lines for process event.
1226 * @param hook_data ControlFlowData structure of the viewer.
1227 * @param call_data Event context.
1229 * This function adds items to be drawn in a queue for each process.
1234 int before_process_release_hook(void *hook_data
, void *call_data
)
1236 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1237 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1239 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1241 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1243 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1245 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1248 e
= ltt_tracefile_get_event(tfc
->tf
);
1250 LttTime evtime
= ltt_event_time(e
);
1255 pid
= ltt_event_get_long_unsigned(e
, thf
->f1
);
1258 /* Add process to process list (if not present) */
1259 /* Don't care about the process if it's not in the state hash already :
1260 * that means a process that has never done anything in the trace and
1261 * unknown suddently gets destroyed : no state meaningful to show. */
1262 LttvProcessState
*process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1264 if(process
!= NULL
) {
1266 guint pl_height
= 0;
1267 HashedProcessData
*hashed_process_data
= NULL
;
1269 ProcessList
*process_list
= control_flow_data
->process_list
;
1271 birth
= process
->creation_time
;
1273 /* Cannot use current process : this event happens on another process,
1274 * action done by the parent. */
1275 hashed_process_data
= processlist_get_process_data(process_list
,
1279 tfc
->t_context
->index
);
1280 if(unlikely(hashed_process_data
== NULL
))
1282 g_assert(pid
== 0 || pid
!= process
->ppid
);
1283 /* Process not present */
1284 Drawing_t
*drawing
= control_flow_data
->drawing
;
1285 ProcessInfo
*process_info
;
1286 processlist_add(process_list
,
1293 tfc
->t_context
->index
,
1298 &hashed_process_data
);
1299 gtk_widget_set_size_request(drawing
->drawing_area
,
1302 gtk_widget_queue_draw(drawing
->drawing_area
);
1305 /* Now, the process is in the state hash and our own process hash.
1306 * We definitely can draw the items related to the ending state.
1309 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1312 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1313 TimeWindow time_window
=
1314 lttvwindow_get_time_window(control_flow_data
->tab
);
1317 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1318 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1320 #endif //EXTRA_CHECK
1321 Drawing_t
*drawing
= control_flow_data
->drawing
;
1322 guint width
= drawing
->width
;
1324 convert_time_to_pixels(
1330 /* Draw collision indicator */
1331 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1332 gdk_draw_point(hashed_process_data
->pixmap
,
1335 (hashed_process_data
->height
/2)-3);
1336 hashed_process_data
->x
.middle_marked
= TRUE
;
1339 TimeWindow time_window
=
1340 lttvwindow_get_time_window(control_flow_data
->tab
);
1343 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1344 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1346 #endif //EXTRA_CHECK
1347 Drawing_t
*drawing
= control_flow_data
->drawing
;
1348 guint width
= drawing
->width
;
1351 convert_time_to_pixels(
1358 /* Jump over draw if we are at the same x position */
1359 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1360 hashed_process_data
->x
.middle_used
))
1362 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1363 /* Draw collision indicator */
1364 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1365 gdk_draw_point(hashed_process_data
->pixmap
,
1368 (hashed_process_data
->height
/2)-3);
1369 hashed_process_data
->x
.middle_marked
= TRUE
;
1373 DrawContext draw_context
;
1375 /* Now create the drawing context that will be used to draw
1376 * items related to the last state. */
1377 draw_context
.drawable
= hashed_process_data
->pixmap
;
1378 draw_context
.gc
= drawing
->gc
;
1379 draw_context
.pango_layout
= drawing
->pango_layout
;
1380 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1381 draw_context
.drawinfo
.end
.x
= x
;
1383 draw_context
.drawinfo
.y
.over
= 1;
1384 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1385 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1387 draw_context
.drawinfo
.start
.offset
.over
= 0;
1388 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1389 draw_context
.drawinfo
.start
.offset
.under
= 0;
1390 draw_context
.drawinfo
.end
.offset
.over
= 0;
1391 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1392 draw_context
.drawinfo
.end
.offset
.under
= 0;
1396 PropertiesLine prop_line
= prepare_s_e_line(process
);
1397 draw_line((void*)&prop_line
, (void*)&draw_context
);
1400 /* become the last x position */
1401 hashed_process_data
->x
.middle
= x
;
1402 hashed_process_data
->x
.middle_used
= TRUE
;
1403 hashed_process_data
->x
.middle_marked
= FALSE
;
1405 /* Calculate the next good time */
1406 convert_pixels_to_time(width
, x
+1, time_window
,
1407 &hashed_process_data
->next_good_time
);
1419 /* after_process_fork_hook
1421 * Create the processlist entry for the child process. Put the last
1422 * position in x at the current time value.
1424 * @param hook_data ControlFlowData structure of the viewer.
1425 * @param call_data Event context.
1427 * This function adds items to be drawn in a queue for each process.
1430 int after_process_fork_hook(void *hook_data
, void *call_data
)
1432 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1433 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1434 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1436 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1438 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1440 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1443 e
= ltt_tracefile_get_event(tfc
->tf
);
1445 LttTime evtime
= ltt_event_time(e
);
1449 child_pid
= ltt_event_get_long_unsigned(e
, thf
->f2
);
1452 /* Add process to process list (if not present) */
1453 LttvProcessState
*process_child
;
1455 guint pl_height
= 0;
1456 HashedProcessData
*hashed_process_data_child
= NULL
;
1458 ProcessList
*process_list
= control_flow_data
->process_list
;
1460 /* Find child in the list... */
1461 process_child
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1462 /* It should exist, because we are after the state update. */
1463 g_assert(process_child
!= NULL
);
1465 birth
= process_child
->creation_time
;
1467 /* Cannot use current process, because this action is done by the parent
1469 hashed_process_data_child
= processlist_get_process_data(process_list
,
1473 tfc
->t_context
->index
);
1474 if(likely(hashed_process_data_child
== NULL
))
1476 g_assert(child_pid
== 0 || child_pid
!= process_child
->ppid
);
1477 /* Process not present */
1478 Drawing_t
*drawing
= control_flow_data
->drawing
;
1479 ProcessInfo
*process_info
;
1480 processlist_add(process_list
,
1483 process_child
->tgid
,
1485 process_child
->ppid
,
1487 tfc
->t_context
->index
,
1488 process_child
->name
,
1489 process_child
->brand
,
1492 &hashed_process_data_child
);
1493 gtk_widget_set_size_request(drawing
->drawing_area
,
1496 gtk_widget_queue_draw(drawing
->drawing_area
);
1498 processlist_set_ppid(process_list
, process_child
->ppid
,
1499 hashed_process_data_child
);
1500 processlist_set_tgid(process_list
, process_child
->tgid
,
1501 hashed_process_data_child
);
1505 if(likely(ltt_time_compare(hashed_process_data_child
->next_good_time
,
1508 TimeWindow time_window
=
1509 lttvwindow_get_time_window(control_flow_data
->tab
);
1512 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1513 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1515 #endif //EXTRA_CHECK
1516 Drawing_t
*drawing
= control_flow_data
->drawing
;
1517 guint width
= drawing
->width
;
1519 convert_time_to_pixels(
1525 if(likely(hashed_process_data_child
->x
.over
!= new_x
)) {
1526 hashed_process_data_child
->x
.over
= new_x
;
1527 hashed_process_data_child
->x
.over_used
= FALSE
;
1528 hashed_process_data_child
->x
.over_marked
= FALSE
;
1530 if(likely(hashed_process_data_child
->x
.middle
!= new_x
)) {
1531 hashed_process_data_child
->x
.middle
= new_x
;
1532 hashed_process_data_child
->x
.middle_used
= FALSE
;
1533 hashed_process_data_child
->x
.middle_marked
= FALSE
;
1535 if(likely(hashed_process_data_child
->x
.under
!= new_x
)) {
1536 hashed_process_data_child
->x
.under
= new_x
;
1537 hashed_process_data_child
->x
.under_used
= FALSE
;
1538 hashed_process_data_child
->x
.under_marked
= FALSE
;
1546 /* after_process_exit_hook
1548 * Create the processlist entry for the child process. Put the last
1549 * position in x at the current time value.
1551 * @param hook_data ControlFlowData structure of the viewer.
1552 * @param call_data Event context.
1554 * This function adds items to be drawn in a queue for each process.
1557 int after_process_exit_hook(void *hook_data
, void *call_data
)
1559 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1560 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1561 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1563 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1565 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1567 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1570 e
= ltt_tracefile_get_event(tfc
->tf
);
1572 LttTime evtime
= ltt_event_time(e
);
1574 /* Add process to process list (if not present) */
1575 //LttvProcessState *process = tfs->process;
1576 guint cpu
= tfs
->cpu
;
1577 LttvProcessState
*process
= ts
->running_process
[cpu
];
1579 /* It should exist, because we are after the state update. */
1580 g_assert(process
!= NULL
);
1582 guint pid
= process
->pid
;
1584 guint pl_height
= 0;
1585 HashedProcessData
*hashed_process_data
= NULL
;
1587 ProcessList
*process_list
= control_flow_data
->process_list
;
1589 birth
= process
->creation_time
;
1591 if(likely(process_list
->current_hash_data
[cpu
] != NULL
) ){
1592 hashed_process_data
= process_list
->current_hash_data
[cpu
];
1594 hashed_process_data
= processlist_get_process_data(process_list
,
1598 tfc
->t_context
->index
);
1599 if(unlikely(hashed_process_data
== NULL
))
1601 g_assert(pid
== 0 || pid
!= process
->ppid
);
1602 /* Process not present */
1603 Drawing_t
*drawing
= control_flow_data
->drawing
;
1604 ProcessInfo
*process_info
;
1605 processlist_add(process_list
,
1612 tfc
->t_context
->index
,
1617 &hashed_process_data
);
1618 gtk_widget_set_size_request(drawing
->drawing_area
,
1621 gtk_widget_queue_draw(drawing
->drawing_area
);
1624 /* Set the current process */
1625 process_list
->current_hash_data
[process
->cpu
] =
1626 hashed_process_data
;
1629 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
1632 TimeWindow time_window
=
1633 lttvwindow_get_time_window(control_flow_data
->tab
);
1636 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1637 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1639 #endif //EXTRA_CHECK
1640 Drawing_t
*drawing
= control_flow_data
->drawing
;
1641 guint width
= drawing
->width
;
1643 convert_time_to_pixels(
1648 if(unlikely(hashed_process_data
->x
.middle
!= new_x
)) {
1649 hashed_process_data
->x
.middle
= new_x
;
1650 hashed_process_data
->x
.middle_used
= FALSE
;
1651 hashed_process_data
->x
.middle_marked
= FALSE
;
1659 /* Get the filename of the process to print */
1660 int after_fs_exec_hook(void *hook_data
, void *call_data
)
1662 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1663 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1664 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1666 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1668 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1670 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1672 guint cpu
= tfs
->cpu
;
1673 LttvProcessState
*process
= ts
->running_process
[cpu
];
1674 g_assert(process
!= NULL
);
1676 guint pid
= process
->pid
;
1678 /* Well, the process_out existed : we must get it in the process hash
1679 * or add it, and draw its items.
1681 /* Add process to process list (if not present) */
1682 guint pl_height
= 0;
1683 HashedProcessData
*hashed_process_data
= NULL
;
1684 ProcessList
*process_list
= control_flow_data
->process_list
;
1685 LttTime birth
= process
->creation_time
;
1687 if(likely(process_list
->current_hash_data
[cpu
] != NULL
)) {
1688 hashed_process_data
= process_list
->current_hash_data
[cpu
];
1690 hashed_process_data
= processlist_get_process_data(process_list
,
1694 tfc
->t_context
->index
);
1695 if(unlikely(hashed_process_data
== NULL
))
1697 g_assert(pid
== 0 || pid
!= process
->ppid
);
1698 ProcessInfo
*process_info
;
1699 /* Process not present */
1700 Drawing_t
*drawing
= control_flow_data
->drawing
;
1701 processlist_add(process_list
,
1708 tfc
->t_context
->index
,
1713 &hashed_process_data
);
1714 gtk_widget_set_size_request(drawing
->drawing_area
,
1717 gtk_widget_queue_draw(drawing
->drawing_area
);
1719 /* Set the current process */
1720 process_list
->current_hash_data
[process
->cpu
] =
1721 hashed_process_data
;
1724 processlist_set_name(process_list
, process
->name
, hashed_process_data
);
1730 /* Get the filename of the process to print */
1731 int after_user_generic_thread_brand_hook(void *hook_data
, void *call_data
)
1733 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1734 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1735 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1737 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1739 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1741 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1743 guint cpu
= tfs
->cpu
;
1744 LttvProcessState
*process
= ts
->running_process
[cpu
];
1745 g_assert(process
!= NULL
);
1747 guint pid
= process
->pid
;
1749 /* Well, the process_out existed : we must get it in the process hash
1750 * or add it, and draw its items.
1752 /* Add process to process list (if not present) */
1753 guint pl_height
= 0;
1754 HashedProcessData
*hashed_process_data
= NULL
;
1755 ProcessList
*process_list
= control_flow_data
->process_list
;
1756 LttTime birth
= process
->creation_time
;
1758 if(likely(process_list
->current_hash_data
[cpu
] != NULL
)) {
1759 hashed_process_data
= process_list
->current_hash_data
[cpu
];
1761 hashed_process_data
= processlist_get_process_data(process_list
,
1765 tfc
->t_context
->index
);
1766 if(unlikely(hashed_process_data
== NULL
))
1768 g_assert(pid
== 0 || pid
!= process
->ppid
);
1769 ProcessInfo
*process_info
;
1770 /* Process not present */
1771 Drawing_t
*drawing
= control_flow_data
->drawing
;
1772 processlist_add(process_list
,
1779 tfc
->t_context
->index
,
1784 &hashed_process_data
);
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
->cpu
] =
1792 hashed_process_data
;
1795 processlist_set_brand(process_list
, process
->brand
, hashed_process_data
);
1802 /* after_event_enum_process_hook
1804 * Create the processlist entry for the child process. Put the last
1805 * position in x at the current time value.
1807 * @param hook_data ControlFlowData structure of the viewer.
1808 * @param call_data Event context.
1810 * This function adds items to be drawn in a queue for each process.
1813 int after_event_enum_process_hook(void *hook_data
, void *call_data
)
1815 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1816 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1817 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1819 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1821 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1823 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1826 e
= ltt_tracefile_get_event(tfc
->tf
);
1828 LttTime evtime
= ltt_event_time(e
);
1830 /* Add process to process list (if not present) */
1831 LttvProcessState
*process_in
;
1833 guint pl_height
= 0;
1834 HashedProcessData
*hashed_process_data_in
= NULL
;
1836 ProcessList
*process_list
= control_flow_data
->process_list
;
1840 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f1
);
1844 /* Find process pid_in in the list... */
1845 process_in
= lttv_state_find_process(ts
, ANY_CPU
, pid_in
);
1846 //process_in = tfs->process;
1847 //guint cpu = tfs->cpu;
1848 //process_in = ts->running_process[cpu];
1849 /* It should exist, because we are after the state update. */
1851 //g_assert(process_in != NULL);
1852 #endif //EXTRA_CHECK
1853 birth
= process_in
->creation_time
;
1855 hashed_process_data_in
= processlist_get_process_data(process_list
,
1859 tfc
->t_context
->index
);
1860 if(hashed_process_data_in
== NULL
)
1862 if(pid_in
!= 0 && pid_in
== process_in
->ppid
)
1863 g_critical("TEST %u , %u", pid_in
, process_in
->ppid
);
1864 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
1865 ProcessInfo
*process_info
;
1866 Drawing_t
*drawing
= control_flow_data
->drawing
;
1867 /* Process not present */
1868 processlist_add(process_list
,
1875 tfc
->t_context
->index
,
1880 &hashed_process_data_in
);
1881 gtk_widget_set_size_request(drawing
->drawing_area
,
1884 gtk_widget_queue_draw(drawing
->drawing_area
);
1886 processlist_set_name(process_list
, process_in
->name
,
1887 hashed_process_data_in
);
1888 processlist_set_ppid(process_list
, process_in
->ppid
,
1889 hashed_process_data_in
);
1890 processlist_set_tgid(process_list
, process_in
->tgid
,
1891 hashed_process_data_in
);
1897 gint
update_time_window_hook(void *hook_data
, void *call_data
)
1899 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1900 Drawing_t
*drawing
= control_flow_data
->drawing
;
1901 ProcessList
*process_list
= control_flow_data
->process_list
;
1903 const TimeWindowNotifyData
*time_window_nofify_data
=
1904 ((const TimeWindowNotifyData
*)call_data
);
1906 TimeWindow
*old_time_window
=
1907 time_window_nofify_data
->old_time_window
;
1908 TimeWindow
*new_time_window
=
1909 time_window_nofify_data
->new_time_window
;
1911 /* Update the ruler */
1912 drawing_update_ruler(control_flow_data
->drawing
,
1916 /* Two cases : zoom in/out or scrolling */
1918 /* In order to make sure we can reuse the old drawing, the scale must
1919 * be the same and the new time interval being partly located in the
1920 * currently shown time interval. (reuse is only for scrolling)
1923 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
1924 old_time_window
->start_time
.tv_sec
,
1925 old_time_window
->start_time
.tv_nsec
,
1926 old_time_window
->time_width
.tv_sec
,
1927 old_time_window
->time_width
.tv_nsec
);
1929 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
1930 new_time_window
->start_time
.tv_sec
,
1931 new_time_window
->start_time
.tv_nsec
,
1932 new_time_window
->time_width
.tv_sec
,
1933 new_time_window
->time_width
.tv_nsec
);
1935 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
1936 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
1938 /* Same scale (scrolling) */
1939 g_info("scrolling");
1940 LttTime
*ns
= &new_time_window
->start_time
;
1941 LttTime
*nw
= &new_time_window
->time_width
;
1942 LttTime
*os
= &old_time_window
->start_time
;
1943 LttTime
*ow
= &old_time_window
->time_width
;
1944 LttTime old_end
= old_time_window
->end_time
;
1945 LttTime new_end
= new_time_window
->end_time
;
1947 //if(ns<os+w && os+w<ns+w)
1948 //if(ns<old_end && os<ns)
1949 if(ltt_time_compare(*ns
, old_end
) == -1
1950 && ltt_time_compare(*os
, *ns
) == -1)
1952 g_info("scrolling near right");
1953 /* Scroll right, keep right part of the screen */
1955 guint width
= control_flow_data
->drawing
->width
;
1956 convert_time_to_pixels(
1962 /* Copy old data to new location */
1963 copy_pixmap_region(process_list
,
1965 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1969 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
1971 if(drawing
->damage_begin
== drawing
->damage_end
)
1972 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
1974 drawing
->damage_begin
= 0;
1976 drawing
->damage_end
= control_flow_data
->drawing
->width
;
1978 /* Clear the data request background, but not SAFETY */
1979 rectangle_pixmap(process_list
,
1980 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1982 drawing
->damage_begin
+SAFETY
, 0,
1983 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
1985 gtk_widget_queue_draw(drawing
->drawing_area
);
1986 //gtk_widget_queue_draw_area (drawing->drawing_area,
1988 // control_flow_data->drawing->width,
1989 // control_flow_data->drawing->height);
1991 /* Get new data for the rest. */
1992 drawing_data_request(control_flow_data
->drawing
,
1993 drawing
->damage_begin
, 0,
1994 drawing
->damage_end
- drawing
->damage_begin
,
1995 control_flow_data
->drawing
->height
);
1998 //if(ns<os && os<ns+w)
1999 //if(ns<os && os<new_end)
2000 if(ltt_time_compare(*ns
,*os
) == -1
2001 && ltt_time_compare(*os
,new_end
) == -1)
2003 g_info("scrolling near left");
2004 /* Scroll left, keep left part of the screen */
2006 guint width
= control_flow_data
->drawing
->width
;
2007 convert_time_to_pixels(
2013 /* Copy old data to new location */
2014 copy_pixmap_region (process_list
,
2016 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2022 if(drawing
->damage_begin
== drawing
->damage_end
)
2023 drawing
->damage_end
= x
;
2025 drawing
->damage_end
=
2026 control_flow_data
->drawing
->width
;
2028 drawing
->damage_begin
= 0;
2030 rectangle_pixmap (process_list
,
2031 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2033 drawing
->damage_begin
, 0,
2034 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2037 gtk_widget_queue_draw(drawing
->drawing_area
);
2038 //gtk_widget_queue_draw_area (drawing->drawing_area,
2040 // control_flow_data->drawing->width,
2041 // control_flow_data->drawing->height);
2044 /* Get new data for the rest. */
2045 drawing_data_request(control_flow_data
->drawing
,
2046 drawing
->damage_begin
, 0,
2047 drawing
->damage_end
- drawing
->damage_begin
,
2048 control_flow_data
->drawing
->height
);
2051 if(ltt_time_compare(*ns
,*os
) == 0)
2053 g_info("not scrolling");
2055 g_info("scrolling far");
2056 /* Cannot reuse any part of the screen : far jump */
2059 rectangle_pixmap (process_list
,
2060 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2063 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2066 //gtk_widget_queue_draw_area (drawing->drawing_area,
2068 // control_flow_data->drawing->width,
2069 // control_flow_data->drawing->height);
2070 gtk_widget_queue_draw(drawing
->drawing_area
);
2072 drawing
->damage_begin
= 0;
2073 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2075 drawing_data_request(control_flow_data
->drawing
,
2077 control_flow_data
->drawing
->width
,
2078 control_flow_data
->drawing
->height
);
2084 /* Different scale (zoom) */
2087 rectangle_pixmap (process_list
,
2088 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2091 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2094 //gtk_widget_queue_draw_area (drawing->drawing_area,
2096 // control_flow_data->drawing->width,
2097 // control_flow_data->drawing->height);
2098 gtk_widget_queue_draw(drawing
->drawing_area
);
2100 drawing
->damage_begin
= 0;
2101 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2103 drawing_data_request(control_flow_data
->drawing
,
2105 control_flow_data
->drawing
->width
,
2106 control_flow_data
->drawing
->height
);
2109 /* Update directly when scrolling */
2110 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2116 gint
traceset_notify(void *hook_data
, void *call_data
)
2118 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2119 Drawing_t
*drawing
= control_flow_data
->drawing
;
2121 if(unlikely(drawing
->gc
== NULL
)) {
2124 if(drawing
->dotted_gc
== NULL
) {
2128 drawing_clear(control_flow_data
->drawing
);
2129 processlist_clear(control_flow_data
->process_list
);
2130 gtk_widget_set_size_request(
2131 control_flow_data
->drawing
->drawing_area
,
2132 -1, processlist_get_height(control_flow_data
->process_list
));
2133 redraw_notify(control_flow_data
, NULL
);
2135 request_background_data(control_flow_data
);
2140 gint
redraw_notify(void *hook_data
, void *call_data
)
2142 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2143 Drawing_t
*drawing
= control_flow_data
->drawing
;
2144 GtkWidget
*widget
= drawing
->drawing_area
;
2146 drawing
->damage_begin
= 0;
2147 drawing
->damage_end
= drawing
->width
;
2149 /* fun feature, to be separated someday... */
2150 drawing_clear(control_flow_data
->drawing
);
2151 processlist_clear(control_flow_data
->process_list
);
2152 gtk_widget_set_size_request(
2153 control_flow_data
->drawing
->drawing_area
,
2154 -1, processlist_get_height(control_flow_data
->process_list
));
2156 rectangle_pixmap (control_flow_data
->process_list
,
2157 widget
->style
->black_gc
,
2160 drawing
->alloc_width
,
2163 gtk_widget_queue_draw(drawing
->drawing_area
);
2165 if(drawing
->damage_begin
< drawing
->damage_end
)
2167 drawing_data_request(drawing
,
2168 drawing
->damage_begin
,
2170 drawing
->damage_end
-drawing
->damage_begin
,
2174 //gtk_widget_queue_draw_area(drawing->drawing_area,
2177 // drawing->height);
2183 gint
continue_notify(void *hook_data
, void *call_data
)
2185 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2186 Drawing_t
*drawing
= control_flow_data
->drawing
;
2188 //g_assert(widget->allocation.width == drawing->damage_end);
2190 if(drawing
->damage_begin
< drawing
->damage_end
)
2192 drawing_data_request(drawing
,
2193 drawing
->damage_begin
,
2195 drawing
->damage_end
-drawing
->damage_begin
,
2203 gint
update_current_time_hook(void *hook_data
, void *call_data
)
2205 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
2206 Drawing_t
*drawing
= control_flow_data
->drawing
;
2208 LttTime current_time
= *((LttTime
*)call_data
);
2210 TimeWindow time_window
=
2211 lttvwindow_get_time_window(control_flow_data
->tab
);
2213 LttTime time_begin
= time_window
.start_time
;
2214 LttTime width
= time_window
.time_width
;
2217 guint64 time_ll
= ltt_time_to_uint64(width
);
2218 time_ll
= time_ll
>> 1; /* divide by two */
2219 half_width
= ltt_time_from_uint64(time_ll
);
2221 LttTime time_end
= ltt_time_add(time_begin
, width
);
2223 LttvTracesetContext
* tsc
=
2224 lttvwindow_get_traceset_context(control_flow_data
->tab
);
2226 LttTime trace_start
= tsc
->time_span
.start_time
;
2227 LttTime trace_end
= tsc
->time_span
.end_time
;
2229 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
2230 current_time
.tv_nsec
);
2234 /* If current time is inside time interval, just move the highlight
2237 /* Else, we have to change the time interval. We have to tell it
2238 * to the main window. */
2239 /* The time interval change will take care of placing the current
2240 * time at the center of the visible area, or nearest possible if we are
2241 * at one end of the trace. */
2244 if(ltt_time_compare(current_time
, time_begin
) < 0)
2246 TimeWindow new_time_window
;
2248 if(ltt_time_compare(current_time
,
2249 ltt_time_add(trace_start
,half_width
)) < 0)
2250 time_begin
= trace_start
;
2252 time_begin
= ltt_time_sub(current_time
,half_width
);
2254 new_time_window
.start_time
= time_begin
;
2255 new_time_window
.time_width
= width
;
2256 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2257 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2259 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2261 else if(ltt_time_compare(current_time
, time_end
) > 0)
2263 TimeWindow new_time_window
;
2265 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
2266 time_begin
= ltt_time_sub(trace_end
,width
);
2268 time_begin
= ltt_time_sub(current_time
,half_width
);
2270 new_time_window
.start_time
= time_begin
;
2271 new_time_window
.time_width
= width
;
2272 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2273 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2275 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2278 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2280 /* Update directly when scrolling */
2281 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2287 typedef struct _ClosureData
{
2288 EventsRequest
*events_request
;
2289 LttvTracesetState
*tss
;
2295 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
2297 ProcessInfo
*process_info
= (ProcessInfo
*)key
;
2298 HashedProcessData
*hashed_process_data
= (HashedProcessData
*)value
;
2299 ClosureData
*closure_data
= (ClosureData
*)user_data
;
2301 EventsRequest
*events_request
= closure_data
->events_request
;
2302 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2304 LttvTracesetState
*tss
= closure_data
->tss
;
2305 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)tss
;
2307 LttTime evtime
= closure_data
->end_time
;
2310 /* For the process */
2311 /* First, check if the current process is in the state computation
2312 * process list. If it is there, that means we must add it right now and
2313 * draw items from the beginning of the read for it. If it is not
2314 * present, it's a new process and it was not present : it will
2315 * be added after the state update. */
2317 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
2318 #endif //EXTRA_CHECK
2319 LttvTraceContext
*tc
= tsc
->traces
[process_info
->trace_num
];
2320 LttvTraceState
*ts
= (LttvTraceState
*)tc
;
2323 //FIXME : optimize data structures.
2324 LttvTracefileState
*tfs
;
2325 LttvTracefileContext
*tfc
;
2327 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
2328 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
2329 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
2330 && tfs
->cpu
== process_info
->cpu
)
2334 g_assert(i
<tc
->tracefiles
->len
);
2335 tfs
= LTTV_TRACEFILE_STATE(tfc
);
2337 // LttvTracefileState *tfs =
2338 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2339 // tracefiles[process_info->cpu];
2341 LttvProcessState
*process
;
2342 process
= lttv_state_find_process(ts
, process_info
->cpu
,
2345 if(unlikely(process
!= NULL
)) {
2347 /* Only draw for processes that are currently in the trace states */
2349 ProcessList
*process_list
= control_flow_data
->process_list
;
2351 /* Should be alike when background info is ready */
2352 if(control_flow_data
->background_info_waiting
==0)
2353 g_assert(ltt_time_compare(process
->creation_time
,
2354 process_info
->birth
) == 0);
2355 #endif //EXTRA_CHECK
2357 /* Now, the process is in the state hash and our own process hash.
2358 * We definitely can draw the items related to the ending state.
2361 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2364 TimeWindow time_window
=
2365 lttvwindow_get_time_window(control_flow_data
->tab
);
2368 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2369 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2371 #endif //EXTRA_CHECK
2372 Drawing_t
*drawing
= control_flow_data
->drawing
;
2373 guint width
= drawing
->width
;
2375 guint x
= closure_data
->x_end
;
2377 DrawContext draw_context
;
2379 /* Now create the drawing context that will be used to draw
2380 * items related to the last state. */
2381 draw_context
.drawable
= hashed_process_data
->pixmap
;
2382 draw_context
.gc
= drawing
->gc
;
2383 draw_context
.pango_layout
= drawing
->pango_layout
;
2384 draw_context
.drawinfo
.end
.x
= x
;
2386 draw_context
.drawinfo
.y
.over
= 1;
2387 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2388 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2390 draw_context
.drawinfo
.start
.offset
.over
= 0;
2391 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2392 draw_context
.drawinfo
.start
.offset
.under
= 0;
2393 draw_context
.drawinfo
.end
.offset
.over
= 0;
2394 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2395 draw_context
.drawinfo
.end
.offset
.under
= 0;
2397 /* Jump over draw if we are at the same x position */
2398 if(x
== hashed_process_data
->x
.over
)
2402 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2404 PropertiesLine prop_line
= prepare_execmode_line(process
);
2405 draw_line((void*)&prop_line
, (void*)&draw_context
);
2407 hashed_process_data
->x
.over
= x
;
2411 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2412 hashed_process_data
->x
.middle_used
)) {
2413 #if 0 /* do not mark closure : not missing information */
2414 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2415 /* Draw collision indicator */
2416 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2417 gdk_draw_point(drawing
->pixmap
,
2421 hashed_process_data
->x
.middle_marked
= TRUE
;
2426 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2428 PropertiesLine prop_line
= prepare_s_e_line(process
);
2429 draw_line((void*)&prop_line
, (void*)&draw_context
);
2431 /* become the last x position */
2432 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2433 hashed_process_data
->x
.middle
= x
;
2434 /* but don't use the pixel */
2435 hashed_process_data
->x
.middle_used
= FALSE
;
2437 /* Calculate the next good time */
2438 convert_pixels_to_time(width
, x
+1, time_window
,
2439 &hashed_process_data
->next_good_time
);
2448 int before_chunk(void *hook_data
, void *call_data
)
2450 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2451 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2452 ControlFlowData
*cfd
= (ControlFlowData
*)events_request
->viewer_data
;
2454 /* Desactivate sort */
2455 gtk_tree_sortable_set_sort_column_id(
2456 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2458 GTK_SORT_ASCENDING
);
2460 drawing_chunk_begin(events_request
, tss
);
2465 int before_request(void *hook_data
, void *call_data
)
2467 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2468 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2470 drawing_data_request_begin(events_request
, tss
);
2477 * after request is necessary in addition of after chunk in order to draw
2478 * lines until the end of the screen. after chunk just draws lines until
2485 int after_request(void *hook_data
, void *call_data
)
2487 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2488 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2489 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2491 ProcessList
*process_list
= control_flow_data
->process_list
;
2492 LttTime end_time
= events_request
->end_time
;
2494 ClosureData closure_data
;
2495 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2496 closure_data
.tss
= tss
;
2497 closure_data
.end_time
= end_time
;
2499 TimeWindow time_window
=
2500 lttvwindow_get_time_window(control_flow_data
->tab
);
2501 guint width
= control_flow_data
->drawing
->width
;
2502 convert_time_to_pixels(
2506 &closure_data
.x_end
);
2509 /* Draw last items */
2510 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2511 (void*)&closure_data
);
2514 /* Request expose */
2515 drawing_request_expose(events_request
, tss
, end_time
);
2524 int after_chunk(void *hook_data
, void *call_data
)
2526 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2527 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2528 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2529 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)call_data
;
2530 LttvTracefileContext
*tfc
= lttv_traceset_context_get_current_tfc(tsc
);
2533 ProcessList
*process_list
= control_flow_data
->process_list
;
2535 g_free(process_list
->current_hash_data
);
2536 process_list
->current_hash_data
= NULL
;
2539 end_time
= LTT_TIME_MIN(tfc
->timestamp
, events_request
->end_time
);
2540 else /* end of traceset, or position now out of request : end */
2541 end_time
= events_request
->end_time
;
2543 ClosureData closure_data
;
2544 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2545 closure_data
.tss
= tss
;
2546 closure_data
.end_time
= end_time
;
2548 TimeWindow time_window
=
2549 lttvwindow_get_time_window(control_flow_data
->tab
);
2550 guint width
= control_flow_data
->drawing
->width
;
2551 convert_time_to_pixels(
2555 &closure_data
.x_end
);
2557 /* Draw last items */
2558 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2559 (void*)&closure_data
);
2561 /* Reactivate sort */
2562 gtk_tree_sortable_set_sort_column_id(
2563 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2564 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2565 GTK_SORT_ASCENDING
);
2567 update_index_to_pixmap(control_flow_data
->process_list
);
2568 /* Request a full expose : drawing scrambled */
2569 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2571 /* Request expose (updates damages zone also) */
2572 drawing_request_expose(events_request
, tss
, end_time
);