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
,
400 tfc
->t_context
->index
,
405 &hashed_process_data
);
406 gtk_widget_set_size_request(drawing
->drawing_area
,
409 gtk_widget_queue_draw(drawing
->drawing_area
);
413 /* Now, the process is in the state hash and our own process hash.
414 * We definitely can draw the items related to the ending state.
417 if(ltt_time_compare(hashed_process_data
->next_good_time
,
420 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
422 TimeWindow time_window
=
423 lttvwindow_get_time_window(control_flow_data
->tab
);
425 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
426 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
429 Drawing_t
*drawing
= control_flow_data
->drawing
;
430 guint width
= drawing
->width
;
432 convert_time_to_pixels(
438 /* Draw collision indicator */
439 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
440 gdk_draw_point(hashed_process_data
->pixmap
,
443 (hashed_process_data
->height
/2)-3);
444 hashed_process_data
->x
.middle_marked
= TRUE
;
447 TimeWindow time_window
=
448 lttvwindow_get_time_window(control_flow_data
->tab
);
450 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
451 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
454 Drawing_t
*drawing
= control_flow_data
->drawing
;
455 guint width
= drawing
->width
;
457 convert_time_to_pixels(
464 /* Jump over draw if we are at the same x position */
465 if(x
== hashed_process_data
->x
.middle
&&
466 hashed_process_data
->x
.middle_used
)
468 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
469 /* Draw collision indicator */
470 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
471 gdk_draw_point(hashed_process_data
->pixmap
,
474 (hashed_process_data
->height
/2)-3);
475 hashed_process_data
->x
.middle_marked
= TRUE
;
479 DrawContext draw_context
;
481 /* Now create the drawing context that will be used to draw
482 * items related to the last state. */
483 draw_context
.drawable
= hashed_process_data
->pixmap
;
484 draw_context
.gc
= drawing
->gc
;
485 draw_context
.pango_layout
= drawing
->pango_layout
;
486 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
487 draw_context
.drawinfo
.end
.x
= x
;
489 draw_context
.drawinfo
.y
.over
= 1;
490 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
491 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
493 draw_context
.drawinfo
.start
.offset
.over
= 0;
494 draw_context
.drawinfo
.start
.offset
.middle
= 0;
495 draw_context
.drawinfo
.start
.offset
.under
= 0;
496 draw_context
.drawinfo
.end
.offset
.over
= 0;
497 draw_context
.drawinfo
.end
.offset
.middle
= 0;
498 draw_context
.drawinfo
.end
.offset
.under
= 0;
502 PropertiesLine prop_line
= prepare_s_e_line(process
);
503 draw_line((void*)&prop_line
, (void*)&draw_context
);
506 /* become the last x position */
507 hashed_process_data
->x
.middle
= x
;
508 hashed_process_data
->x
.middle_used
= TRUE
;
509 hashed_process_data
->x
.middle_marked
= FALSE
;
511 /* Calculate the next good time */
512 convert_pixels_to_time(width
, x
+1, time_window
,
513 &hashed_process_data
->next_good_time
);
521 /* First, check if the current process is in the state computation
522 * process list. If it is there, that means we must add it right now and
523 * draw items from the beginning of the read for it. If it is not
524 * present, it's a new process and it was not present : it will
525 * be added after the state update. */
526 LttvProcessState
*process
;
527 process
= lttv_state_find_process(ts
,
530 if(process
!= NULL
) {
531 /* Well, the process existed : we must get it in the process hash
532 * or add it, and draw its items.
534 /* Add process to process list (if not present) */
536 HashedProcessData
*hashed_process_data
= NULL
;
537 ProcessList
*process_list
= control_flow_data
->process_list
;
538 LttTime birth
= process
->creation_time
;
540 hashed_process_data
= processlist_get_process_data(process_list
,
544 tfc
->t_context
->index
);
545 if(hashed_process_data
== NULL
)
547 g_assert(pid_in
== 0 || pid_in
!= process
->ppid
);
548 /* Process not present */
549 ProcessInfo
*process_info
;
550 Drawing_t
*drawing
= control_flow_data
->drawing
;
551 processlist_add(process_list
,
557 tfc
->t_context
->index
,
562 &hashed_process_data
);
563 gtk_widget_set_size_request(drawing
->drawing_area
,
566 gtk_widget_queue_draw(drawing
->drawing_area
);
569 //We could set the current process and hash here, but will be done
570 //by after schedchange hook
572 /* Now, the process is in the state hash and our own process hash.
573 * We definitely can draw the items related to the ending state.
576 if(ltt_time_compare(hashed_process_data
->next_good_time
,
579 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
581 TimeWindow time_window
=
582 lttvwindow_get_time_window(control_flow_data
->tab
);
584 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
585 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
588 Drawing_t
*drawing
= control_flow_data
->drawing
;
589 guint width
= drawing
->width
;
591 convert_time_to_pixels(
597 /* Draw collision indicator */
598 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
599 gdk_draw_point(hashed_process_data
->pixmap
,
602 (hashed_process_data
->height
/2)-3);
603 hashed_process_data
->x
.middle_marked
= TRUE
;
606 TimeWindow time_window
=
607 lttvwindow_get_time_window(control_flow_data
->tab
);
609 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
610 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
613 Drawing_t
*drawing
= control_flow_data
->drawing
;
614 guint width
= drawing
->width
;
617 convert_time_to_pixels(
624 /* Jump over draw if we are at the same x position */
625 if(x
== hashed_process_data
->x
.middle
&&
626 hashed_process_data
->x
.middle_used
)
628 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
629 /* Draw collision indicator */
630 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
631 gdk_draw_point(hashed_process_data
->pixmap
,
634 (hashed_process_data
->height
/2)-3);
635 hashed_process_data
->x
.middle_marked
= TRUE
;
639 DrawContext draw_context
;
641 /* Now create the drawing context that will be used to draw
642 * items related to the last state. */
643 draw_context
.drawable
= hashed_process_data
->pixmap
;
644 draw_context
.gc
= drawing
->gc
;
645 draw_context
.pango_layout
= drawing
->pango_layout
;
646 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
647 draw_context
.drawinfo
.end
.x
= x
;
649 draw_context
.drawinfo
.y
.over
= 1;
650 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
651 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
653 draw_context
.drawinfo
.start
.offset
.over
= 0;
654 draw_context
.drawinfo
.start
.offset
.middle
= 0;
655 draw_context
.drawinfo
.start
.offset
.under
= 0;
656 draw_context
.drawinfo
.end
.offset
.over
= 0;
657 draw_context
.drawinfo
.end
.offset
.middle
= 0;
658 draw_context
.drawinfo
.end
.offset
.under
= 0;
662 PropertiesLine prop_line
= prepare_s_e_line(process
);
663 draw_line((void*)&prop_line
, (void*)&draw_context
);
667 /* become the last x position */
668 hashed_process_data
->x
.middle
= x
;
669 hashed_process_data
->x
.middle_used
= TRUE
;
670 hashed_process_data
->x
.middle_marked
= FALSE
;
672 /* Calculate the next good time */
673 convert_pixels_to_time(width
, x
+1, time_window
,
674 &hashed_process_data
->next_good_time
);
678 g_warning("Cannot find pin_in in schedchange %u", pid_in
);
687 GString
*string
= g_string_new("");;
688 gboolean field_names
= TRUE
, state
= TRUE
;
690 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
691 g_string_append_printf(string
,"\n");
694 g_string_append_printf(string
, " %s",
695 g_quark_to_string(tfs
->process
->state
->s
));
698 g_info("%s",string
->str
);
700 g_string_free(string
, TRUE
);
702 /* End of text dump */
707 /* after_schedchange_hook
709 * The draw after hook is called by the reading API to have a
710 * particular event drawn on the screen.
711 * @param hook_data ControlFlowData structure of the viewer.
712 * @param call_data Event context.
714 * This function adds items to be drawn in a queue for each process.
717 int after_schedchange_hook(void *hook_data
, void *call_data
)
719 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
720 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
721 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
723 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
725 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
727 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
730 e
= ltt_tracefile_get_event(tfc
->tf
);
732 LttTime evtime
= ltt_event_time(e
);
734 /* Add process to process list (if not present) */
735 LttvProcessState
*process_in
;
738 HashedProcessData
*hashed_process_data_in
= NULL
;
740 ProcessList
*process_list
= control_flow_data
->process_list
;
745 pid_out
= ltt_event_get_long_unsigned(e
, thf
->f1
);
746 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f2
);
750 /* Find process pid_in in the list... */
751 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
752 //process_in = tfs->process;
753 guint cpu
= tfs
->cpu
;
754 process_in
= ts
->running_process
[cpu
];
755 /* It should exist, because we are after the state update. */
757 g_assert(process_in
!= NULL
);
759 birth
= process_in
->creation_time
;
761 hashed_process_data_in
= processlist_get_process_data(process_list
,
765 tfc
->t_context
->index
);
766 if(hashed_process_data_in
== NULL
)
768 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
769 ProcessInfo
*process_info
;
770 Drawing_t
*drawing
= control_flow_data
->drawing
;
771 /* Process not present */
772 processlist_add(process_list
,
778 tfc
->t_context
->index
,
783 &hashed_process_data_in
);
784 gtk_widget_set_size_request(drawing
->drawing_area
,
787 gtk_widget_queue_draw(drawing
->drawing_area
);
789 /* Set the current process */
790 process_list
->current_hash_data
[process_in
->cpu
] =
791 hashed_process_data_in
;
793 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
796 TimeWindow time_window
=
797 lttvwindow_get_time_window(control_flow_data
->tab
);
800 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
801 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
804 Drawing_t
*drawing
= control_flow_data
->drawing
;
805 guint width
= drawing
->width
;
808 convert_time_to_pixels(
814 if(hashed_process_data_in
->x
.middle
!= new_x
) {
815 hashed_process_data_in
->x
.middle
= new_x
;
816 hashed_process_data_in
->x
.middle_used
= FALSE
;
817 hashed_process_data_in
->x
.middle_marked
= FALSE
;
826 /* before_execmode_hook
828 * This function basically draw lines and icons. Two types of lines are drawn :
829 * one small (3 pixels?) representing the state of the process and the second
830 * type is thicker (10 pixels?) representing on which CPU a process is running
831 * (and this only in running state).
833 * Extremums of the lines :
834 * x_min : time of the last event context for this process kept in memory.
835 * x_max : time of the current event.
836 * y : middle of the process in the process list. The process is found in the
837 * list, therefore is it's position in pixels.
839 * The choice of lines'color is defined by the context of the last event for this
844 int before_execmode_hook(void *hook_data
, void *call_data
)
846 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
847 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
848 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
850 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
852 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
854 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
857 e
= ltt_tracefile_get_event(tfc
->tf
);
859 LttTime evtime
= ltt_event_time(e
);
861 /* we are in a execmode, before the state update. We must draw the
862 * items corresponding to the state before it changes : now is the right
866 //LttvProcessState *process = tfs->process;
867 guint cpu
= tfs
->cpu
;
868 LttvProcessState
*process
= ts
->running_process
[cpu
];
869 g_assert(process
!= NULL
);
871 guint pid
= process
->pid
;
873 /* Well, the process_out existed : we must get it in the process hash
874 * or add it, and draw its items.
876 /* Add process to process list (if not present) */
878 HashedProcessData
*hashed_process_data
= NULL
;
879 ProcessList
*process_list
= control_flow_data
->process_list
;
880 LttTime birth
= process
->creation_time
;
882 if(likely(process_list
->current_hash_data
[cpu
] != NULL
)) {
883 hashed_process_data
= process_list
->current_hash_data
[cpu
];
885 hashed_process_data
= processlist_get_process_data(process_list
,
889 tfc
->t_context
->index
);
890 if(unlikely(hashed_process_data
== NULL
))
892 g_assert(pid
== 0 || pid
!= process
->ppid
);
893 ProcessInfo
*process_info
;
894 /* Process not present */
895 Drawing_t
*drawing
= control_flow_data
->drawing
;
896 processlist_add(process_list
,
902 tfc
->t_context
->index
,
907 &hashed_process_data
);
908 gtk_widget_set_size_request(drawing
->drawing_area
,
911 gtk_widget_queue_draw(drawing
->drawing_area
);
913 /* Set the current process */
914 process_list
->current_hash_data
[process
->cpu
] =
918 /* Now, the process is in the state hash and our own process hash.
919 * We definitely can draw the items related to the ending state.
922 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
925 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
926 TimeWindow time_window
=
927 lttvwindow_get_time_window(control_flow_data
->tab
);
930 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
931 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
934 Drawing_t
*drawing
= control_flow_data
->drawing
;
935 guint width
= drawing
->width
;
937 convert_time_to_pixels(
943 /* Draw collision indicator */
944 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
945 gdk_draw_point(hashed_process_data
->pixmap
,
948 (hashed_process_data
->height
/2)-3);
949 hashed_process_data
->x
.middle_marked
= TRUE
;
952 TimeWindow time_window
=
953 lttvwindow_get_time_window(control_flow_data
->tab
);
956 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
957 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
960 Drawing_t
*drawing
= control_flow_data
->drawing
;
961 guint width
= drawing
->width
;
964 convert_time_to_pixels(
971 /* Jump over draw if we are at the same x position */
972 if(unlikely(x
== hashed_process_data
->x
.middle
&&
973 hashed_process_data
->x
.middle_used
))
975 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
976 /* Draw collision indicator */
977 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
978 gdk_draw_point(hashed_process_data
->pixmap
,
981 (hashed_process_data
->height
/2)-3);
982 hashed_process_data
->x
.middle_marked
= TRUE
;
987 DrawContext draw_context
;
988 /* Now create the drawing context that will be used to draw
989 * items related to the last state. */
990 draw_context
.drawable
= hashed_process_data
->pixmap
;
991 draw_context
.gc
= drawing
->gc
;
992 draw_context
.pango_layout
= drawing
->pango_layout
;
993 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
994 draw_context
.drawinfo
.end
.x
= x
;
996 draw_context
.drawinfo
.y
.over
= 1;
997 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
998 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1000 draw_context
.drawinfo
.start
.offset
.over
= 0;
1001 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1002 draw_context
.drawinfo
.start
.offset
.under
= 0;
1003 draw_context
.drawinfo
.end
.offset
.over
= 0;
1004 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1005 draw_context
.drawinfo
.end
.offset
.under
= 0;
1009 PropertiesLine prop_line
= prepare_s_e_line(process
);
1010 draw_line((void*)&prop_line
, (void*)&draw_context
);
1013 /* become the last x position */
1014 hashed_process_data
->x
.middle
= x
;
1015 hashed_process_data
->x
.middle_used
= TRUE
;
1016 hashed_process_data
->x
.middle_marked
= FALSE
;
1018 /* Calculate the next good time */
1019 convert_pixels_to_time(width
, x
+1, time_window
,
1020 &hashed_process_data
->next_good_time
);
1027 /* before_process_exit_hook
1029 * Draw lines for process event.
1031 * @param hook_data ControlFlowData structure of the viewer.
1032 * @param call_data Event context.
1034 * This function adds items to be drawn in a queue for each process.
1039 int before_process_exit_hook(void *hook_data
, void *call_data
)
1041 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1042 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1044 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1046 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1048 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1050 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1053 e
= ltt_tracefile_get_event(tfc
->tf
);
1055 LttTime evtime
= ltt_event_time(e
);
1057 /* Add process to process list (if not present) */
1058 //LttvProcessState *process = tfs->process;
1059 guint cpu
= tfs
->cpu
;
1060 LttvProcessState
*process
= ts
->running_process
[cpu
];
1061 guint pid
= process
->pid
;
1063 guint pl_height
= 0;
1064 HashedProcessData
*hashed_process_data
= NULL
;
1066 ProcessList
*process_list
= control_flow_data
->process_list
;
1068 g_assert(process
!= NULL
);
1070 birth
= process
->creation_time
;
1072 if(likely(process_list
->current_hash_data
[cpu
] != NULL
)) {
1073 hashed_process_data
= process_list
->current_hash_data
[cpu
];
1075 hashed_process_data
= processlist_get_process_data(process_list
,
1079 tfc
->t_context
->index
);
1080 if(unlikely(hashed_process_data
== NULL
))
1082 g_assert(pid
== 0 || pid
!= process
->ppid
);
1083 /* Process not present */
1084 Drawing_t
*drawing
= control_flow_data
->drawing
;
1085 ProcessInfo
*process_info
;
1086 processlist_add(process_list
,
1092 tfc
->t_context
->index
,
1097 &hashed_process_data
);
1098 gtk_widget_set_size_request(drawing
->drawing_area
,
1101 gtk_widget_queue_draw(drawing
->drawing_area
);
1105 /* Now, the process is in the state hash and our own process hash.
1106 * We definitely can draw the items related to the ending state.
1109 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1112 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1113 TimeWindow time_window
=
1114 lttvwindow_get_time_window(control_flow_data
->tab
);
1117 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1118 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1120 #endif //EXTRA_CHECK
1121 Drawing_t
*drawing
= control_flow_data
->drawing
;
1122 guint width
= drawing
->width
;
1124 convert_time_to_pixels(
1130 /* Draw collision indicator */
1131 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1132 gdk_draw_point(hashed_process_data
->pixmap
,
1135 (hashed_process_data
->height
/2)-3);
1136 hashed_process_data
->x
.middle_marked
= TRUE
;
1139 TimeWindow time_window
=
1140 lttvwindow_get_time_window(control_flow_data
->tab
);
1143 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1144 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1146 #endif //EXTRA_CHECK
1147 Drawing_t
*drawing
= control_flow_data
->drawing
;
1148 guint width
= drawing
->width
;
1151 convert_time_to_pixels(
1158 /* Jump over draw if we are at the same x position */
1159 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1160 hashed_process_data
->x
.middle_used
))
1162 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1163 /* Draw collision indicator */
1164 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1165 gdk_draw_point(hashed_process_data
->pixmap
,
1168 (hashed_process_data
->height
/2)-3);
1169 hashed_process_data
->x
.middle_marked
= TRUE
;
1173 DrawContext draw_context
;
1175 /* Now create the drawing context that will be used to draw
1176 * items related to the last state. */
1177 draw_context
.drawable
= hashed_process_data
->pixmap
;
1178 draw_context
.gc
= drawing
->gc
;
1179 draw_context
.pango_layout
= drawing
->pango_layout
;
1180 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1181 draw_context
.drawinfo
.end
.x
= x
;
1183 draw_context
.drawinfo
.y
.over
= 1;
1184 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1185 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1187 draw_context
.drawinfo
.start
.offset
.over
= 0;
1188 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1189 draw_context
.drawinfo
.start
.offset
.under
= 0;
1190 draw_context
.drawinfo
.end
.offset
.over
= 0;
1191 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1192 draw_context
.drawinfo
.end
.offset
.under
= 0;
1196 PropertiesLine prop_line
= prepare_s_e_line(process
);
1197 draw_line((void*)&prop_line
, (void*)&draw_context
);
1200 /* become the last x position */
1201 hashed_process_data
->x
.middle
= x
;
1202 hashed_process_data
->x
.middle_used
= TRUE
;
1203 hashed_process_data
->x
.middle_marked
= FALSE
;
1205 /* Calculate the next good time */
1206 convert_pixels_to_time(width
, x
+1, time_window
,
1207 &hashed_process_data
->next_good_time
);
1217 /* before_process_release_hook
1219 * Draw lines for process event.
1221 * @param hook_data ControlFlowData structure of the viewer.
1222 * @param call_data Event context.
1224 * This function adds items to be drawn in a queue for each process.
1229 int before_process_release_hook(void *hook_data
, void *call_data
)
1231 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1232 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1234 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1236 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1238 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1240 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1243 e
= ltt_tracefile_get_event(tfc
->tf
);
1245 LttTime evtime
= ltt_event_time(e
);
1250 pid
= ltt_event_get_long_unsigned(e
, thf
->f1
);
1253 /* Add process to process list (if not present) */
1254 /* Don't care about the process if it's not in the state hash already :
1255 * that means a process that has never done anything in the trace and
1256 * unknown suddently gets destroyed : no state meaningful to show. */
1257 LttvProcessState
*process
= lttv_state_find_process(ts
, ANY_CPU
, pid
);
1259 if(process
!= NULL
) {
1261 guint pl_height
= 0;
1262 HashedProcessData
*hashed_process_data
= NULL
;
1264 ProcessList
*process_list
= control_flow_data
->process_list
;
1266 birth
= process
->creation_time
;
1268 /* Cannot use current process : this event happens on another process,
1269 * action done by the parent. */
1270 hashed_process_data
= processlist_get_process_data(process_list
,
1274 tfc
->t_context
->index
);
1275 if(unlikely(hashed_process_data
== NULL
))
1277 g_assert(pid
== 0 || pid
!= process
->ppid
);
1278 /* Process not present */
1279 Drawing_t
*drawing
= control_flow_data
->drawing
;
1280 ProcessInfo
*process_info
;
1281 processlist_add(process_list
,
1287 tfc
->t_context
->index
,
1292 &hashed_process_data
);
1293 gtk_widget_set_size_request(drawing
->drawing_area
,
1296 gtk_widget_queue_draw(drawing
->drawing_area
);
1299 /* Now, the process is in the state hash and our own process hash.
1300 * We definitely can draw the items related to the ending state.
1303 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1306 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1307 TimeWindow time_window
=
1308 lttvwindow_get_time_window(control_flow_data
->tab
);
1311 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1312 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1314 #endif //EXTRA_CHECK
1315 Drawing_t
*drawing
= control_flow_data
->drawing
;
1316 guint width
= drawing
->width
;
1318 convert_time_to_pixels(
1324 /* Draw collision indicator */
1325 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1326 gdk_draw_point(hashed_process_data
->pixmap
,
1329 (hashed_process_data
->height
/2)-3);
1330 hashed_process_data
->x
.middle_marked
= TRUE
;
1333 TimeWindow time_window
=
1334 lttvwindow_get_time_window(control_flow_data
->tab
);
1337 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1338 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1340 #endif //EXTRA_CHECK
1341 Drawing_t
*drawing
= control_flow_data
->drawing
;
1342 guint width
= drawing
->width
;
1345 convert_time_to_pixels(
1352 /* Jump over draw if we are at the same x position */
1353 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1354 hashed_process_data
->x
.middle_used
))
1356 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1357 /* Draw collision indicator */
1358 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1359 gdk_draw_point(hashed_process_data
->pixmap
,
1362 (hashed_process_data
->height
/2)-3);
1363 hashed_process_data
->x
.middle_marked
= TRUE
;
1367 DrawContext draw_context
;
1369 /* Now create the drawing context that will be used to draw
1370 * items related to the last state. */
1371 draw_context
.drawable
= hashed_process_data
->pixmap
;
1372 draw_context
.gc
= drawing
->gc
;
1373 draw_context
.pango_layout
= drawing
->pango_layout
;
1374 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1375 draw_context
.drawinfo
.end
.x
= x
;
1377 draw_context
.drawinfo
.y
.over
= 1;
1378 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1379 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1381 draw_context
.drawinfo
.start
.offset
.over
= 0;
1382 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1383 draw_context
.drawinfo
.start
.offset
.under
= 0;
1384 draw_context
.drawinfo
.end
.offset
.over
= 0;
1385 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1386 draw_context
.drawinfo
.end
.offset
.under
= 0;
1390 PropertiesLine prop_line
= prepare_s_e_line(process
);
1391 draw_line((void*)&prop_line
, (void*)&draw_context
);
1394 /* become the last x position */
1395 hashed_process_data
->x
.middle
= x
;
1396 hashed_process_data
->x
.middle_used
= TRUE
;
1397 hashed_process_data
->x
.middle_marked
= FALSE
;
1399 /* Calculate the next good time */
1400 convert_pixels_to_time(width
, x
+1, time_window
,
1401 &hashed_process_data
->next_good_time
);
1413 /* after_process_fork_hook
1415 * Create the processlist entry for the child process. Put the last
1416 * position in x at the current time value.
1418 * @param hook_data ControlFlowData structure of the viewer.
1419 * @param call_data Event context.
1421 * This function adds items to be drawn in a queue for each process.
1424 int after_process_fork_hook(void *hook_data
, void *call_data
)
1426 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1427 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1428 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1430 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1432 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1434 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1437 e
= ltt_tracefile_get_event(tfc
->tf
);
1439 LttTime evtime
= ltt_event_time(e
);
1443 child_pid
= ltt_event_get_long_unsigned(e
, thf
->f2
);
1446 /* Add process to process list (if not present) */
1447 LttvProcessState
*process_child
;
1449 guint pl_height
= 0;
1450 HashedProcessData
*hashed_process_data_child
= NULL
;
1452 ProcessList
*process_list
= control_flow_data
->process_list
;
1454 /* Find child in the list... */
1455 process_child
= lttv_state_find_process(ts
, ANY_CPU
, child_pid
);
1456 /* It should exist, because we are after the state update. */
1457 g_assert(process_child
!= NULL
);
1459 birth
= process_child
->creation_time
;
1461 /* Cannot use current process, because this action is done by the parent
1463 hashed_process_data_child
= processlist_get_process_data(process_list
,
1467 tfc
->t_context
->index
);
1468 if(likely(hashed_process_data_child
== NULL
))
1470 g_assert(child_pid
== 0 || child_pid
!= process_child
->ppid
);
1471 /* Process not present */
1472 Drawing_t
*drawing
= control_flow_data
->drawing
;
1473 ProcessInfo
*process_info
;
1474 processlist_add(process_list
,
1478 process_child
->ppid
,
1480 tfc
->t_context
->index
,
1481 process_child
->name
,
1482 process_child
->brand
,
1485 &hashed_process_data_child
);
1486 gtk_widget_set_size_request(drawing
->drawing_area
,
1489 gtk_widget_queue_draw(drawing
->drawing_area
);
1493 if(likely(ltt_time_compare(hashed_process_data_child
->next_good_time
,
1496 TimeWindow time_window
=
1497 lttvwindow_get_time_window(control_flow_data
->tab
);
1500 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1501 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1503 #endif //EXTRA_CHECK
1504 Drawing_t
*drawing
= control_flow_data
->drawing
;
1505 guint width
= drawing
->width
;
1507 convert_time_to_pixels(
1513 if(likely(hashed_process_data_child
->x
.over
!= new_x
)) {
1514 hashed_process_data_child
->x
.over
= new_x
;
1515 hashed_process_data_child
->x
.over_used
= FALSE
;
1516 hashed_process_data_child
->x
.over_marked
= FALSE
;
1518 if(likely(hashed_process_data_child
->x
.middle
!= new_x
)) {
1519 hashed_process_data_child
->x
.middle
= new_x
;
1520 hashed_process_data_child
->x
.middle_used
= FALSE
;
1521 hashed_process_data_child
->x
.middle_marked
= FALSE
;
1523 if(likely(hashed_process_data_child
->x
.under
!= new_x
)) {
1524 hashed_process_data_child
->x
.under
= new_x
;
1525 hashed_process_data_child
->x
.under_used
= FALSE
;
1526 hashed_process_data_child
->x
.under_marked
= FALSE
;
1534 /* after_process_exit_hook
1536 * Create the processlist entry for the child process. Put the last
1537 * position in x at the current time value.
1539 * @param hook_data ControlFlowData structure of the viewer.
1540 * @param call_data Event context.
1542 * This function adds items to be drawn in a queue for each process.
1545 int after_process_exit_hook(void *hook_data
, void *call_data
)
1547 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1548 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1549 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1551 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1553 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1555 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1558 e
= ltt_tracefile_get_event(tfc
->tf
);
1560 LttTime evtime
= ltt_event_time(e
);
1562 /* Add process to process list (if not present) */
1563 //LttvProcessState *process = tfs->process;
1564 guint cpu
= tfs
->cpu
;
1565 LttvProcessState
*process
= ts
->running_process
[cpu
];
1567 /* It should exist, because we are after the state update. */
1568 g_assert(process
!= NULL
);
1570 guint pid
= process
->pid
;
1572 guint pl_height
= 0;
1573 HashedProcessData
*hashed_process_data
= NULL
;
1575 ProcessList
*process_list
= control_flow_data
->process_list
;
1577 birth
= process
->creation_time
;
1579 if(likely(process_list
->current_hash_data
[cpu
] != NULL
) ){
1580 hashed_process_data
= process_list
->current_hash_data
[cpu
];
1582 hashed_process_data
= processlist_get_process_data(process_list
,
1586 tfc
->t_context
->index
);
1587 if(unlikely(hashed_process_data
== NULL
))
1589 g_assert(pid
== 0 || pid
!= process
->ppid
);
1590 /* Process not present */
1591 Drawing_t
*drawing
= control_flow_data
->drawing
;
1592 ProcessInfo
*process_info
;
1593 processlist_add(process_list
,
1599 tfc
->t_context
->index
,
1604 &hashed_process_data
);
1605 gtk_widget_set_size_request(drawing
->drawing_area
,
1608 gtk_widget_queue_draw(drawing
->drawing_area
);
1611 /* Set the current process */
1612 process_list
->current_hash_data
[process
->cpu
] =
1613 hashed_process_data
;
1616 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
1619 TimeWindow time_window
=
1620 lttvwindow_get_time_window(control_flow_data
->tab
);
1623 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1624 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1626 #endif //EXTRA_CHECK
1627 Drawing_t
*drawing
= control_flow_data
->drawing
;
1628 guint width
= drawing
->width
;
1630 convert_time_to_pixels(
1635 if(unlikely(hashed_process_data
->x
.middle
!= new_x
)) {
1636 hashed_process_data
->x
.middle
= new_x
;
1637 hashed_process_data
->x
.middle_used
= FALSE
;
1638 hashed_process_data
->x
.middle_marked
= FALSE
;
1646 /* Get the filename of the process to print */
1647 int after_fs_exec_hook(void *hook_data
, void *call_data
)
1649 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1650 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1651 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1653 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1655 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1657 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1659 guint cpu
= tfs
->cpu
;
1660 LttvProcessState
*process
= ts
->running_process
[cpu
];
1661 g_assert(process
!= NULL
);
1663 guint pid
= process
->pid
;
1665 /* Well, the process_out existed : we must get it in the process hash
1666 * or add it, and draw its items.
1668 /* Add process to process list (if not present) */
1669 guint pl_height
= 0;
1670 HashedProcessData
*hashed_process_data
= NULL
;
1671 ProcessList
*process_list
= control_flow_data
->process_list
;
1672 LttTime birth
= process
->creation_time
;
1674 if(likely(process_list
->current_hash_data
[cpu
] != NULL
)) {
1675 hashed_process_data
= process_list
->current_hash_data
[cpu
];
1677 hashed_process_data
= processlist_get_process_data(process_list
,
1681 tfc
->t_context
->index
);
1682 if(unlikely(hashed_process_data
== NULL
))
1684 g_assert(pid
== 0 || pid
!= process
->ppid
);
1685 ProcessInfo
*process_info
;
1686 /* Process not present */
1687 Drawing_t
*drawing
= control_flow_data
->drawing
;
1688 processlist_add(process_list
,
1694 tfc
->t_context
->index
,
1699 &hashed_process_data
);
1700 gtk_widget_set_size_request(drawing
->drawing_area
,
1703 gtk_widget_queue_draw(drawing
->drawing_area
);
1705 /* Set the current process */
1706 process_list
->current_hash_data
[process
->cpu
] =
1707 hashed_process_data
;
1710 processlist_set_name(process_list
, process
->name
, hashed_process_data
);
1716 /* Get the filename of the process to print */
1717 int after_user_generic_thread_brand_hook(void *hook_data
, void *call_data
)
1719 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1720 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1721 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1723 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1725 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1727 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1729 guint cpu
= tfs
->cpu
;
1730 LttvProcessState
*process
= ts
->running_process
[cpu
];
1731 g_assert(process
!= NULL
);
1733 guint pid
= process
->pid
;
1735 /* Well, the process_out existed : we must get it in the process hash
1736 * or add it, and draw its items.
1738 /* Add process to process list (if not present) */
1739 guint pl_height
= 0;
1740 HashedProcessData
*hashed_process_data
= NULL
;
1741 ProcessList
*process_list
= control_flow_data
->process_list
;
1742 LttTime birth
= process
->creation_time
;
1744 if(likely(process_list
->current_hash_data
[cpu
] != NULL
)) {
1745 hashed_process_data
= process_list
->current_hash_data
[cpu
];
1747 hashed_process_data
= processlist_get_process_data(process_list
,
1751 tfc
->t_context
->index
);
1752 if(unlikely(hashed_process_data
== NULL
))
1754 g_assert(pid
== 0 || pid
!= process
->ppid
);
1755 ProcessInfo
*process_info
;
1756 /* Process not present */
1757 Drawing_t
*drawing
= control_flow_data
->drawing
;
1758 processlist_add(process_list
,
1764 tfc
->t_context
->index
,
1769 &hashed_process_data
);
1770 gtk_widget_set_size_request(drawing
->drawing_area
,
1773 gtk_widget_queue_draw(drawing
->drawing_area
);
1775 /* Set the current process */
1776 process_list
->current_hash_data
[process
->cpu
] =
1777 hashed_process_data
;
1780 processlist_set_brand(process_list
, process
->brand
, hashed_process_data
);
1787 /* after_event_enum_process_hook
1789 * Create the processlist entry for the child process. Put the last
1790 * position in x at the current time value.
1792 * @param hook_data ControlFlowData structure of the viewer.
1793 * @param call_data Event context.
1795 * This function adds items to be drawn in a queue for each process.
1798 int after_event_enum_process_hook(void *hook_data
, void *call_data
)
1800 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1801 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1802 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1804 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1806 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1808 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1811 e
= ltt_tracefile_get_event(tfc
->tf
);
1813 LttTime evtime
= ltt_event_time(e
);
1815 /* Add process to process list (if not present) */
1816 LttvProcessState
*process_in
;
1818 guint pl_height
= 0;
1819 HashedProcessData
*hashed_process_data_in
= NULL
;
1821 ProcessList
*process_list
= control_flow_data
->process_list
;
1825 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f1
);
1829 /* Find process pid_in in the list... */
1830 process_in
= lttv_state_find_process(ts
, ANY_CPU
, pid_in
);
1831 //process_in = tfs->process;
1832 //guint cpu = tfs->cpu;
1833 //process_in = ts->running_process[cpu];
1834 /* It should exist, because we are after the state update. */
1836 //g_assert(process_in != NULL);
1837 #endif //EXTRA_CHECK
1838 birth
= process_in
->creation_time
;
1840 hashed_process_data_in
= processlist_get_process_data(process_list
,
1844 tfc
->t_context
->index
);
1845 if(hashed_process_data_in
== NULL
)
1847 if(pid_in
!= 0 && pid_in
== process_in
->ppid
)
1848 g_critical("TEST %u , %u", pid_in
, process_in
->ppid
);
1849 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
1850 ProcessInfo
*process_info
;
1851 Drawing_t
*drawing
= control_flow_data
->drawing
;
1852 /* Process not present */
1853 processlist_add(process_list
,
1859 tfc
->t_context
->index
,
1864 &hashed_process_data_in
);
1865 gtk_widget_set_size_request(drawing
->drawing_area
,
1868 gtk_widget_queue_draw(drawing
->drawing_area
);
1870 processlist_set_name(process_list
, process_in
->name
,
1871 hashed_process_data_in
);
1872 processlist_set_ppid(process_list
, process_in
->ppid
,
1873 hashed_process_data_in
);
1879 gint
update_time_window_hook(void *hook_data
, void *call_data
)
1881 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1882 Drawing_t
*drawing
= control_flow_data
->drawing
;
1883 ProcessList
*process_list
= control_flow_data
->process_list
;
1885 const TimeWindowNotifyData
*time_window_nofify_data
=
1886 ((const TimeWindowNotifyData
*)call_data
);
1888 TimeWindow
*old_time_window
=
1889 time_window_nofify_data
->old_time_window
;
1890 TimeWindow
*new_time_window
=
1891 time_window_nofify_data
->new_time_window
;
1893 /* Update the ruler */
1894 drawing_update_ruler(control_flow_data
->drawing
,
1898 /* Two cases : zoom in/out or scrolling */
1900 /* In order to make sure we can reuse the old drawing, the scale must
1901 * be the same and the new time interval being partly located in the
1902 * currently shown time interval. (reuse is only for scrolling)
1905 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
1906 old_time_window
->start_time
.tv_sec
,
1907 old_time_window
->start_time
.tv_nsec
,
1908 old_time_window
->time_width
.tv_sec
,
1909 old_time_window
->time_width
.tv_nsec
);
1911 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
1912 new_time_window
->start_time
.tv_sec
,
1913 new_time_window
->start_time
.tv_nsec
,
1914 new_time_window
->time_width
.tv_sec
,
1915 new_time_window
->time_width
.tv_nsec
);
1917 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
1918 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
1920 /* Same scale (scrolling) */
1921 g_info("scrolling");
1922 LttTime
*ns
= &new_time_window
->start_time
;
1923 LttTime
*nw
= &new_time_window
->time_width
;
1924 LttTime
*os
= &old_time_window
->start_time
;
1925 LttTime
*ow
= &old_time_window
->time_width
;
1926 LttTime old_end
= old_time_window
->end_time
;
1927 LttTime new_end
= new_time_window
->end_time
;
1929 //if(ns<os+w && os+w<ns+w)
1930 //if(ns<old_end && os<ns)
1931 if(ltt_time_compare(*ns
, old_end
) == -1
1932 && ltt_time_compare(*os
, *ns
) == -1)
1934 g_info("scrolling near right");
1935 /* Scroll right, keep right part of the screen */
1937 guint width
= control_flow_data
->drawing
->width
;
1938 convert_time_to_pixels(
1944 /* Copy old data to new location */
1945 copy_pixmap_region(process_list
,
1947 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1951 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
1953 if(drawing
->damage_begin
== drawing
->damage_end
)
1954 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
1956 drawing
->damage_begin
= 0;
1958 drawing
->damage_end
= control_flow_data
->drawing
->width
;
1960 /* Clear the data request background, but not SAFETY */
1961 rectangle_pixmap(process_list
,
1962 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1964 drawing
->damage_begin
+SAFETY
, 0,
1965 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
1967 gtk_widget_queue_draw(drawing
->drawing_area
);
1968 //gtk_widget_queue_draw_area (drawing->drawing_area,
1970 // control_flow_data->drawing->width,
1971 // control_flow_data->drawing->height);
1973 /* Get new data for the rest. */
1974 drawing_data_request(control_flow_data
->drawing
,
1975 drawing
->damage_begin
, 0,
1976 drawing
->damage_end
- drawing
->damage_begin
,
1977 control_flow_data
->drawing
->height
);
1980 //if(ns<os && os<ns+w)
1981 //if(ns<os && os<new_end)
1982 if(ltt_time_compare(*ns
,*os
) == -1
1983 && ltt_time_compare(*os
,new_end
) == -1)
1985 g_info("scrolling near left");
1986 /* Scroll left, keep left part of the screen */
1988 guint width
= control_flow_data
->drawing
->width
;
1989 convert_time_to_pixels(
1995 /* Copy old data to new location */
1996 copy_pixmap_region (process_list
,
1998 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2004 if(drawing
->damage_begin
== drawing
->damage_end
)
2005 drawing
->damage_end
= x
;
2007 drawing
->damage_end
=
2008 control_flow_data
->drawing
->width
;
2010 drawing
->damage_begin
= 0;
2012 rectangle_pixmap (process_list
,
2013 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2015 drawing
->damage_begin
, 0,
2016 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2019 gtk_widget_queue_draw(drawing
->drawing_area
);
2020 //gtk_widget_queue_draw_area (drawing->drawing_area,
2022 // control_flow_data->drawing->width,
2023 // control_flow_data->drawing->height);
2026 /* Get new data for the rest. */
2027 drawing_data_request(control_flow_data
->drawing
,
2028 drawing
->damage_begin
, 0,
2029 drawing
->damage_end
- drawing
->damage_begin
,
2030 control_flow_data
->drawing
->height
);
2033 if(ltt_time_compare(*ns
,*os
) == 0)
2035 g_info("not scrolling");
2037 g_info("scrolling far");
2038 /* Cannot reuse any part of the screen : far jump */
2041 rectangle_pixmap (process_list
,
2042 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2045 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2048 //gtk_widget_queue_draw_area (drawing->drawing_area,
2050 // control_flow_data->drawing->width,
2051 // control_flow_data->drawing->height);
2052 gtk_widget_queue_draw(drawing
->drawing_area
);
2054 drawing
->damage_begin
= 0;
2055 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2057 drawing_data_request(control_flow_data
->drawing
,
2059 control_flow_data
->drawing
->width
,
2060 control_flow_data
->drawing
->height
);
2066 /* Different scale (zoom) */
2069 rectangle_pixmap (process_list
,
2070 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2073 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2076 //gtk_widget_queue_draw_area (drawing->drawing_area,
2078 // control_flow_data->drawing->width,
2079 // control_flow_data->drawing->height);
2080 gtk_widget_queue_draw(drawing
->drawing_area
);
2082 drawing
->damage_begin
= 0;
2083 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2085 drawing_data_request(control_flow_data
->drawing
,
2087 control_flow_data
->drawing
->width
,
2088 control_flow_data
->drawing
->height
);
2091 /* Update directly when scrolling */
2092 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2098 gint
traceset_notify(void *hook_data
, void *call_data
)
2100 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2101 Drawing_t
*drawing
= control_flow_data
->drawing
;
2103 if(unlikely(drawing
->gc
== NULL
)) {
2106 if(drawing
->dotted_gc
== NULL
) {
2110 drawing_clear(control_flow_data
->drawing
);
2111 processlist_clear(control_flow_data
->process_list
);
2112 gtk_widget_set_size_request(
2113 control_flow_data
->drawing
->drawing_area
,
2114 -1, processlist_get_height(control_flow_data
->process_list
));
2115 redraw_notify(control_flow_data
, NULL
);
2117 request_background_data(control_flow_data
);
2122 gint
redraw_notify(void *hook_data
, void *call_data
)
2124 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2125 Drawing_t
*drawing
= control_flow_data
->drawing
;
2126 GtkWidget
*widget
= drawing
->drawing_area
;
2128 drawing
->damage_begin
= 0;
2129 drawing
->damage_end
= drawing
->width
;
2131 /* fun feature, to be separated someday... */
2132 drawing_clear(control_flow_data
->drawing
);
2133 processlist_clear(control_flow_data
->process_list
);
2134 gtk_widget_set_size_request(
2135 control_flow_data
->drawing
->drawing_area
,
2136 -1, processlist_get_height(control_flow_data
->process_list
));
2138 rectangle_pixmap (control_flow_data
->process_list
,
2139 widget
->style
->black_gc
,
2142 drawing
->alloc_width
,
2145 gtk_widget_queue_draw(drawing
->drawing_area
);
2147 if(drawing
->damage_begin
< drawing
->damage_end
)
2149 drawing_data_request(drawing
,
2150 drawing
->damage_begin
,
2152 drawing
->damage_end
-drawing
->damage_begin
,
2156 //gtk_widget_queue_draw_area(drawing->drawing_area,
2159 // drawing->height);
2165 gint
continue_notify(void *hook_data
, void *call_data
)
2167 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2168 Drawing_t
*drawing
= control_flow_data
->drawing
;
2170 //g_assert(widget->allocation.width == drawing->damage_end);
2172 if(drawing
->damage_begin
< drawing
->damage_end
)
2174 drawing_data_request(drawing
,
2175 drawing
->damage_begin
,
2177 drawing
->damage_end
-drawing
->damage_begin
,
2185 gint
update_current_time_hook(void *hook_data
, void *call_data
)
2187 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
2188 Drawing_t
*drawing
= control_flow_data
->drawing
;
2190 LttTime current_time
= *((LttTime
*)call_data
);
2192 TimeWindow time_window
=
2193 lttvwindow_get_time_window(control_flow_data
->tab
);
2195 LttTime time_begin
= time_window
.start_time
;
2196 LttTime width
= time_window
.time_width
;
2199 guint64 time_ll
= ltt_time_to_uint64(width
);
2200 time_ll
= time_ll
>> 1; /* divide by two */
2201 half_width
= ltt_time_from_uint64(time_ll
);
2203 LttTime time_end
= ltt_time_add(time_begin
, width
);
2205 LttvTracesetContext
* tsc
=
2206 lttvwindow_get_traceset_context(control_flow_data
->tab
);
2208 LttTime trace_start
= tsc
->time_span
.start_time
;
2209 LttTime trace_end
= tsc
->time_span
.end_time
;
2211 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
2212 current_time
.tv_nsec
);
2216 /* If current time is inside time interval, just move the highlight
2219 /* Else, we have to change the time interval. We have to tell it
2220 * to the main window. */
2221 /* The time interval change will take care of placing the current
2222 * time at the center of the visible area, or nearest possible if we are
2223 * at one end of the trace. */
2226 if(ltt_time_compare(current_time
, time_begin
) < 0)
2228 TimeWindow new_time_window
;
2230 if(ltt_time_compare(current_time
,
2231 ltt_time_add(trace_start
,half_width
)) < 0)
2232 time_begin
= trace_start
;
2234 time_begin
= ltt_time_sub(current_time
,half_width
);
2236 new_time_window
.start_time
= time_begin
;
2237 new_time_window
.time_width
= width
;
2238 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2239 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2241 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2243 else if(ltt_time_compare(current_time
, time_end
) > 0)
2245 TimeWindow new_time_window
;
2247 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
2248 time_begin
= ltt_time_sub(trace_end
,width
);
2250 time_begin
= ltt_time_sub(current_time
,half_width
);
2252 new_time_window
.start_time
= time_begin
;
2253 new_time_window
.time_width
= width
;
2254 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2255 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2257 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2260 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2262 /* Update directly when scrolling */
2263 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2269 typedef struct _ClosureData
{
2270 EventsRequest
*events_request
;
2271 LttvTracesetState
*tss
;
2277 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
2279 ProcessInfo
*process_info
= (ProcessInfo
*)key
;
2280 HashedProcessData
*hashed_process_data
= (HashedProcessData
*)value
;
2281 ClosureData
*closure_data
= (ClosureData
*)user_data
;
2283 EventsRequest
*events_request
= closure_data
->events_request
;
2284 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2286 LttvTracesetState
*tss
= closure_data
->tss
;
2287 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)tss
;
2289 LttTime evtime
= closure_data
->end_time
;
2292 /* For the process */
2293 /* First, check if the current process is in the state computation
2294 * process list. If it is there, that means we must add it right now and
2295 * draw items from the beginning of the read for it. If it is not
2296 * present, it's a new process and it was not present : it will
2297 * be added after the state update. */
2299 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
2300 #endif //EXTRA_CHECK
2301 LttvTraceContext
*tc
= tsc
->traces
[process_info
->trace_num
];
2302 LttvTraceState
*ts
= (LttvTraceState
*)tc
;
2305 //FIXME : optimize data structures.
2306 LttvTracefileState
*tfs
;
2307 LttvTracefileContext
*tfc
;
2309 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
2310 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
2311 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
2312 && tfs
->cpu
== process_info
->cpu
)
2316 g_assert(i
<tc
->tracefiles
->len
);
2317 tfs
= LTTV_TRACEFILE_STATE(tfc
);
2319 // LttvTracefileState *tfs =
2320 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2321 // tracefiles[process_info->cpu];
2323 LttvProcessState
*process
;
2324 process
= lttv_state_find_process(ts
, process_info
->cpu
,
2327 if(unlikely(process
!= NULL
)) {
2329 /* Only draw for processes that are currently in the trace states */
2331 ProcessList
*process_list
= control_flow_data
->process_list
;
2333 /* Should be alike when background info is ready */
2334 if(control_flow_data
->background_info_waiting
==0)
2335 g_assert(ltt_time_compare(process
->creation_time
,
2336 process_info
->birth
) == 0);
2337 #endif //EXTRA_CHECK
2339 /* Now, the process is in the state hash and our own process hash.
2340 * We definitely can draw the items related to the ending state.
2343 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2346 TimeWindow time_window
=
2347 lttvwindow_get_time_window(control_flow_data
->tab
);
2350 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2351 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2353 #endif //EXTRA_CHECK
2354 Drawing_t
*drawing
= control_flow_data
->drawing
;
2355 guint width
= drawing
->width
;
2357 guint x
= closure_data
->x_end
;
2359 DrawContext draw_context
;
2361 /* Now create the drawing context that will be used to draw
2362 * items related to the last state. */
2363 draw_context
.drawable
= hashed_process_data
->pixmap
;
2364 draw_context
.gc
= drawing
->gc
;
2365 draw_context
.pango_layout
= drawing
->pango_layout
;
2366 draw_context
.drawinfo
.end
.x
= x
;
2368 draw_context
.drawinfo
.y
.over
= 1;
2369 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2370 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2372 draw_context
.drawinfo
.start
.offset
.over
= 0;
2373 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2374 draw_context
.drawinfo
.start
.offset
.under
= 0;
2375 draw_context
.drawinfo
.end
.offset
.over
= 0;
2376 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2377 draw_context
.drawinfo
.end
.offset
.under
= 0;
2379 /* Jump over draw if we are at the same x position */
2380 if(x
== hashed_process_data
->x
.over
)
2384 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2386 PropertiesLine prop_line
= prepare_execmode_line(process
);
2387 draw_line((void*)&prop_line
, (void*)&draw_context
);
2389 hashed_process_data
->x
.over
= x
;
2393 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2394 hashed_process_data
->x
.middle_used
)) {
2395 #if 0 /* do not mark closure : not missing information */
2396 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2397 /* Draw collision indicator */
2398 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2399 gdk_draw_point(drawing
->pixmap
,
2403 hashed_process_data
->x
.middle_marked
= TRUE
;
2408 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2410 PropertiesLine prop_line
= prepare_s_e_line(process
);
2411 draw_line((void*)&prop_line
, (void*)&draw_context
);
2413 /* become the last x position */
2414 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2415 hashed_process_data
->x
.middle
= x
;
2416 /* but don't use the pixel */
2417 hashed_process_data
->x
.middle_used
= FALSE
;
2419 /* Calculate the next good time */
2420 convert_pixels_to_time(width
, x
+1, time_window
,
2421 &hashed_process_data
->next_good_time
);
2430 int before_chunk(void *hook_data
, void *call_data
)
2432 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2433 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2434 ControlFlowData
*cfd
= (ControlFlowData
*)events_request
->viewer_data
;
2436 /* Desactivate sort */
2437 gtk_tree_sortable_set_sort_column_id(
2438 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2440 GTK_SORT_ASCENDING
);
2442 drawing_chunk_begin(events_request
, tss
);
2447 int before_request(void *hook_data
, void *call_data
)
2449 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2450 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2452 drawing_data_request_begin(events_request
, tss
);
2459 * after request is necessary in addition of after chunk in order to draw
2460 * lines until the end of the screen. after chunk just draws lines until
2467 int after_request(void *hook_data
, void *call_data
)
2469 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2470 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2471 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2473 ProcessList
*process_list
= control_flow_data
->process_list
;
2474 LttTime end_time
= events_request
->end_time
;
2476 ClosureData closure_data
;
2477 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2478 closure_data
.tss
= tss
;
2479 closure_data
.end_time
= end_time
;
2481 TimeWindow time_window
=
2482 lttvwindow_get_time_window(control_flow_data
->tab
);
2483 guint width
= control_flow_data
->drawing
->width
;
2484 convert_time_to_pixels(
2488 &closure_data
.x_end
);
2491 /* Draw last items */
2492 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2493 (void*)&closure_data
);
2496 /* Request expose */
2497 drawing_request_expose(events_request
, tss
, end_time
);
2506 int after_chunk(void *hook_data
, void *call_data
)
2508 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2509 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2510 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2511 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)call_data
;
2512 LttvTracefileContext
*tfc
= lttv_traceset_context_get_current_tfc(tsc
);
2515 ProcessList
*process_list
= control_flow_data
->process_list
;
2517 g_free(process_list
->current_hash_data
);
2518 process_list
->current_hash_data
= NULL
;
2521 end_time
= LTT_TIME_MIN(tfc
->timestamp
, events_request
->end_time
);
2522 else /* end of traceset, or position now out of request : end */
2523 end_time
= events_request
->end_time
;
2525 ClosureData closure_data
;
2526 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2527 closure_data
.tss
= tss
;
2528 closure_data
.end_time
= end_time
;
2530 TimeWindow time_window
=
2531 lttvwindow_get_time_window(control_flow_data
->tab
);
2532 guint width
= control_flow_data
->drawing
->width
;
2533 convert_time_to_pixels(
2537 &closure_data
.x_end
);
2539 /* Draw last items */
2540 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2541 (void*)&closure_data
);
2543 /* Reactivate sort */
2544 gtk_tree_sortable_set_sort_column_id(
2545 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2546 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2547 GTK_SORT_ASCENDING
);
2549 update_index_to_pixmap(control_flow_data
->process_list
);
2550 /* Request a full expose : drawing scrambled */
2551 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2553 /* Request expose (updates damages zone also) */
2554 drawing_request_expose(events_request
, tss
, end_time
);