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
82 #define STATE_LINE_WIDTH 4
83 #define COLLISION_POSITION(height) (((height - STATE_LINE_WIDTH)/2) -3)
85 extern GSList
*g_legend_list
;
88 /* Action to do when background computation completed.
90 * Wait for all the awaited computations to be over.
93 static gint
background_ready(void *hook_data
, void *call_data
)
95 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
96 LttvTrace
*trace
= (LttvTrace
*)call_data
;
98 control_flow_data
->background_info_waiting
--;
100 if(control_flow_data
->background_info_waiting
== 0) {
101 g_message("control flow viewer : background computation data ready.");
103 drawing_clear(control_flow_data
->drawing
);
104 processlist_clear(control_flow_data
->process_list
);
105 gtk_widget_set_size_request(
106 control_flow_data
->drawing
->drawing_area
,
107 -1, processlist_get_height(control_flow_data
->process_list
));
108 redraw_notify(control_flow_data
, NULL
);
115 /* Request background computation. Verify if it is in progress or ready first.
116 * Only for each trace in the tab's traceset.
118 static void request_background_data(ControlFlowData
*control_flow_data
)
120 LttvTracesetContext
* tsc
=
121 lttvwindow_get_traceset_context(control_flow_data
->tab
);
122 gint num_traces
= lttv_traceset_number(tsc
->ts
);
125 LttvTraceState
*tstate
;
127 LttvHooks
*background_ready_hook
=
129 lttv_hooks_add(background_ready_hook
, background_ready
, control_flow_data
,
131 control_flow_data
->background_info_waiting
= 0;
133 for(i
=0;i
<num_traces
;i
++) {
134 trace
= lttv_traceset_get(tsc
->ts
, i
);
135 tstate
= LTTV_TRACE_STATE(tsc
->traces
[i
]);
137 if(lttvwindowtraces_get_ready(g_quark_from_string("state"),trace
)==FALSE
138 && !tstate
->has_precomputed_states
) {
140 if(lttvwindowtraces_get_in_progress(g_quark_from_string("state"),
142 /* We first remove requests that could have been done for the same
143 * information. Happens when two viewers ask for it before servicing
146 if(!lttvwindowtraces_background_request_find(trace
, "state"))
147 lttvwindowtraces_background_request_queue(
148 main_window_get_widget(control_flow_data
->tab
), trace
, "state");
149 lttvwindowtraces_background_notify_queue(control_flow_data
,
153 background_ready_hook
);
154 control_flow_data
->background_info_waiting
++;
155 } else { /* in progress */
157 lttvwindowtraces_background_notify_current(control_flow_data
,
161 background_ready_hook
);
162 control_flow_data
->background_info_waiting
++;
165 /* Data ready. By its nature, this viewer doesn't need to have
166 * its data ready hook called there, because a background
167 * request is always linked with a redraw.
173 lttv_hooks_destroy(background_ready_hook
);
180 * Event Viewer's constructor hook
182 * This constructor is given as a parameter to the menuitem and toolbar button
183 * registration. It creates the list.
184 * @param tab A pointer to the parent tab.
185 * @return The widget created.
188 h_resourceview(LttvPlugin
*plugin
)
190 LttvPluginTab
*ptab
= LTTV_PLUGIN_TAB(plugin
);
191 Tab
*tab
= ptab
->tab
;
192 g_info("h_guicontrolflow, %p", tab
);
193 ControlFlowData
*control_flow_data
= resourceview(ptab
);
195 control_flow_data
->tab
= tab
;
197 // Unreg done in the GuiControlFlow_Destructor
198 lttvwindow_register_traceset_notify(tab
,
202 lttvwindow_register_time_window_notify(tab
,
203 update_time_window_hook
,
205 lttvwindow_register_current_time_notify(tab
,
206 update_current_time_hook
,
208 lttvwindow_register_redraw_notify(tab
,
211 lttvwindow_register_continue_notify(tab
,
214 request_background_data(control_flow_data
);
217 return guicontrolflow_get_widget(control_flow_data
) ;
221 void legend_destructor(GtkWindow
*legend
)
223 g_legend_list
= g_slist_remove(g_legend_list
, legend
);
226 /* Create a popup legend */
228 h_legend(LttvPlugin
*plugin
)
230 LttvPluginTab
*ptab
= LTTV_PLUGIN_TAB(plugin
);
231 Tab
*tab
= ptab
->tab
;
232 g_info("h_legend, %p", tab
);
234 GtkWindow
*legend
= GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL
));
236 g_legend_list
= g_slist_append(
240 g_object_set_data_full(
244 (GDestroyNotify
)legend_destructor
);
246 gtk_window_set_title(legend
, "Control Flow View Legend");
248 GtkWidget
*pixmap
= create_pixmap(GTK_WIDGET(legend
), "lttv-color-list.png");
250 // GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixmap(
251 // GDK_PIXMAP(pixmap), NULL));
253 gtk_container_add(GTK_CONTAINER(legend
), GTK_WIDGET(pixmap
));
255 gtk_widget_show(GTK_WIDGET(pixmap
));
256 gtk_widget_show(GTK_WIDGET(legend
));
259 return NULL
; /* This is a popup window */
263 int event_selected_hook(void *hook_data
, void *call_data
)
265 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
266 guint
*event_number
= (guint
*) call_data
;
268 g_debug("DEBUG : event selected by main window : %u", *event_number
);
273 /* Function that selects the color of status&exemode line */
274 static inline PropertiesLine
prepare_s_e_line(LttvProcessState
*process
)
276 PropertiesLine prop_line
;
277 prop_line
.line_width
= STATE_LINE_WIDTH
;
278 prop_line
.style
= GDK_LINE_SOLID
;
279 prop_line
.y
= MIDDLE
;
281 if(process
->state
->s
== LTTV_STATE_RUN
) {
282 if(process
->state
->t
== LTTV_STATE_USER_MODE
)
283 prop_line
.color
= drawing_colors
[COL_RUN_USER_MODE
];
284 else if(process
->state
->t
== LTTV_STATE_SYSCALL
)
285 prop_line
.color
= drawing_colors
[COL_RUN_SYSCALL
];
286 else if(process
->state
->t
== LTTV_STATE_TRAP
)
287 prop_line
.color
= drawing_colors
[COL_RUN_TRAP
];
288 else if(process
->state
->t
== LTTV_STATE_IRQ
)
289 prop_line
.color
= drawing_colors
[COL_RUN_IRQ
];
290 else if(process
->state
->t
== LTTV_STATE_SOFT_IRQ
)
291 prop_line
.color
= drawing_colors
[COL_RUN_SOFT_IRQ
];
292 else if(process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
)
293 prop_line
.color
= drawing_colors
[COL_MODE_UNKNOWN
];
295 g_assert(FALSE
); /* RUNNING MODE UNKNOWN */
296 } else if(process
->state
->s
== LTTV_STATE_WAIT
) {
297 /* We don't show if we wait while in user mode, trap, irq or syscall */
298 prop_line
.color
= drawing_colors
[COL_WAIT
];
299 } else if(process
->state
->s
== LTTV_STATE_WAIT_CPU
) {
300 /* We don't show if we wait for CPU while in user mode, trap, irq
302 prop_line
.color
= drawing_colors
[COL_WAIT_CPU
];
303 } else if(process
->state
->s
== LTTV_STATE_ZOMBIE
) {
304 prop_line
.color
= drawing_colors
[COL_ZOMBIE
];
305 } else if(process
->state
->s
== LTTV_STATE_WAIT_FORK
) {
306 prop_line
.color
= drawing_colors
[COL_WAIT_FORK
];
307 } else if(process
->state
->s
== LTTV_STATE_EXIT
) {
308 prop_line
.color
= drawing_colors
[COL_EXIT
];
309 } else if(process
->state
->s
== LTTV_STATE_UNNAMED
) {
310 prop_line
.color
= drawing_colors
[COL_UNNAMED
];
312 g_critical("unknown state : %s", g_quark_to_string(process
->state
->s
));
313 g_assert(FALSE
); /* UNKNOWN STATE */
320 static void cpu_set_line_color(PropertiesLine
*prop_line
, LttvCPUState
*s
)
322 GQuark present_state
= ((GQuark
*)s
->mode_stack
->data
)[s
->mode_stack
->len
-1];
324 if(present_state
== LTTV_CPU_UNKNOWN
) {
325 prop_line
->color
= drawing_colors_cpu
[COL_CPU_UNKNOWN
];
327 else if(present_state
== LTTV_CPU_IDLE
) {
328 prop_line
->color
= drawing_colors_cpu
[COL_CPU_IDLE
];
330 else if(present_state
== LTTV_CPU_BUSY
) {
331 prop_line
->color
= drawing_colors_cpu
[COL_CPU_BUSY
];
333 else if(present_state
== LTTV_CPU_IRQ
) {
334 prop_line
->color
= drawing_colors_cpu
[COL_CPU_IRQ
];
336 else if(present_state
== LTTV_CPU_TRAP
) {
337 prop_line
->color
= drawing_colors_cpu
[COL_CPU_TRAP
];
341 /* before_schedchange_hook
343 * This function basically draw lines and icons. Two types of lines are drawn :
344 * one small (3 pixels?) representing the state of the process and the second
345 * type is thicker (10 pixels?) representing on which CPU a process is running
346 * (and this only in running state).
348 * Extremums of the lines :
349 * x_min : time of the last event context for this process kept in memory.
350 * x_max : time of the current event.
351 * y : middle of the process in the process list. The process is found in the
352 * list, therefore is it's position in pixels.
354 * The choice of lines'color is defined by the context of the last event for this
359 int before_schedchange_hook(void *hook_data
, void *call_data
)
361 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
362 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
363 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
365 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
367 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
368 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
371 e
= ltt_tracefile_get_event(tfc
->tf
);
372 gint target_pid_saved
= tfc
->target_pid
;
374 LttTime evtime
= ltt_event_time(e
);
375 LttvFilter
*filter
= control_flow_data
->filter
;
379 /* we are in a schedchange, before the state update. We must draw the
380 * items corresponding to the state before it changes : now is the right
386 pid_out
= ltt_event_get_long_unsigned(e
, thf
->f1
);
387 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f2
);
388 // if(pid_in != 0 && pid_out != 0) {
389 // /* not a transition to/from idle */
393 tfc
->target_pid
= pid_out
;
394 // if(!filter || !filter->head ||
395 // lttv_filter_tree_parse(filter->head,e,tfc->tf,
396 // tfc->t_context->t,tfc,NULL,NULL)) {
397 /* For the pid_out */
398 /* First, check if the current process is in the state computation
399 * process list. If it is there, that means we must add it right now and
400 * draw items from the beginning of the read for it. If it is not
401 * present, it's a new process and it was not present : it will
402 * be added after the state update. */
403 guint cpu
= tfs
->cpu
;
406 cpustr
= g_strdup_printf("CPU%u", cpu
);
407 cpuq
= g_quark_from_string(cpustr
);
411 guint trace_num
= ts
->parent
.index
;
412 // LttvProcessState *process = ts->running_process[cpu];
413 /* unknown state, bad current pid */
414 // if(process->pid != pid_out)
415 // process = lttv_state_find_process(ts,
416 // tfs->cpu, pid_out);
418 // if(process != NULL) {
419 /* Well, the process_out existed : we must get it in the process hash
420 * or add it, and draw its items.
422 /* Add process to process list (if not present) */
424 HashedResourceData
*hashed_process_data
= NULL
;
425 ProcessList
*process_list
= control_flow_data
->process_list
;
426 // LttTime birth = process->creation_time;
428 hashed_process_data
= processlist_get_process_data(process_list
, cpuq
, trace_num
);
429 // hashed_process_data = processlist_get_process_data(process_list,
434 if(hashed_process_data
== NULL
)
436 // g_assert(pid_out == 0 || pid_out != process->ppid);
437 /* Process not present */
438 ResourceInfo
*process_info
;
439 Drawing_t
*drawing
= control_flow_data
->drawing
;
440 resourcelist_add(process_list
,
443 cpuq
, //process->name,
448 &hashed_process_data
);
449 gtk_widget_set_size_request(drawing
->drawing_area
,
452 gtk_widget_queue_draw(drawing
->drawing_area
);
456 /* Now, the process is in the state hash and our own process hash.
457 * We definitely can draw the items related to the ending state.
460 if(ltt_time_compare(hashed_process_data
->next_good_time
,
463 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
465 TimeWindow time_window
=
466 lttvwindow_get_time_window(control_flow_data
->tab
);
468 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
469 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
472 Drawing_t
*drawing
= control_flow_data
->drawing
;
473 guint width
= drawing
->width
;
475 convert_time_to_pixels(
481 /* Draw collision indicator */
482 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
483 gdk_draw_point(hashed_process_data
->pixmap
,
486 COLLISION_POSITION(hashed_process_data
->height
));
487 hashed_process_data
->x
.middle_marked
= TRUE
;
490 TimeWindow time_window
=
491 lttvwindow_get_time_window(control_flow_data
->tab
);
493 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
494 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
497 Drawing_t
*drawing
= control_flow_data
->drawing
;
498 guint width
= drawing
->width
;
500 convert_time_to_pixels(
507 /* Jump over draw if we are at the same x position */
508 if(x
== hashed_process_data
->x
.middle
&&
509 hashed_process_data
->x
.middle_used
)
511 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
512 /* Draw collision indicator */
513 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
514 gdk_draw_point(hashed_process_data
->pixmap
,
517 COLLISION_POSITION(hashed_process_data
->height
));
518 hashed_process_data
->x
.middle_marked
= TRUE
;
522 DrawContext draw_context
;
524 /* Now create the drawing context that will be used to draw
525 * items related to the last state. */
526 draw_context
.drawable
= hashed_process_data
->pixmap
;
527 draw_context
.gc
= drawing
->gc
;
528 draw_context
.pango_layout
= drawing
->pango_layout
;
529 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
530 draw_context
.drawinfo
.end
.x
= x
;
532 draw_context
.drawinfo
.y
.over
= 1;
533 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
534 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
536 draw_context
.drawinfo
.start
.offset
.over
= 0;
537 draw_context
.drawinfo
.start
.offset
.middle
= 0;
538 draw_context
.drawinfo
.start
.offset
.under
= 0;
539 draw_context
.drawinfo
.end
.offset
.over
= 0;
540 draw_context
.drawinfo
.end
.offset
.middle
= 0;
541 draw_context
.drawinfo
.end
.offset
.under
= 0;
545 //PropertiesLine prop_line = prepare_s_e_line(process);
546 PropertiesLine prop_line
;
547 prop_line
.line_width
= STATE_LINE_WIDTH
;
548 prop_line
.style
= GDK_LINE_SOLID
;
549 prop_line
.y
= MIDDLE
;
550 cpu_set_line_color(&prop_line
, tfs
->cpu_state
);
551 draw_line((void*)&prop_line
, (void*)&draw_context
);
554 /* become the last x position */
555 hashed_process_data
->x
.middle
= x
;
556 hashed_process_data
->x
.middle_used
= TRUE
;
557 hashed_process_data
->x
.middle_marked
= FALSE
;
559 /* Calculate the next good time */
560 convert_pixels_to_time(width
, x
+1, time_window
,
561 &hashed_process_data
->next_good_time
);
567 // tfc->target_pid = pid_in;
568 // if(!filter || !filter->head ||
569 // lttv_filter_tree_parse(filter->head,e,tfc->tf,
570 // tfc->t_context->t,tfc,NULL,NULL)) {
571 // /* For the pid_in */
572 // /* First, check if the current process is in the state computation
573 // * process list. If it is there, that means we must add it right now and
574 // * draw items from the beginning of the read for it. If it is not
575 // * present, it's a new process and it was not present : it will
576 // * be added after the state update. */
577 // LttvProcessState *process;
578 // process = lttv_state_find_process(ts,
579 // tfs->cpu, pid_in);
580 // guint trace_num = ts->parent.index;
582 // if(process != NULL) {
583 // /* Well, the process existed : we must get it in the process hash
584 // * or add it, and draw its items.
586 // /* Add process to process list (if not present) */
587 // guint pl_height = 0;
588 // HashedResourceData *hashed_process_data = NULL;
589 // ProcessList *process_list = control_flow_data->process_list;
590 // LttTime birth = process->creation_time;
592 // hashed_process_data = processlist_get_process_data(process_list, cpuq);
593 //// hashed_process_data = processlist_get_process_data(process_list,
598 // if(hashed_process_data == NULL)
600 // g_assert(pid_in == 0 || pid_in != process->ppid);
601 // /* Process not present */
602 // ResourceInfo *process_info;
603 // Drawing_t *drawing = control_flow_data->drawing;
604 // resourcelist_add(process_list,
616 // &hashed_process_data);
617 // gtk_widget_set_size_request(drawing->drawing_area,
620 // gtk_widget_queue_draw(drawing->drawing_area);
623 // //We could set the current process and hash here, but will be done
624 // //by after schedchange hook
626 // /* Now, the process is in the state hash and our own process hash.
627 // * We definitely can draw the items related to the ending state.
630 // if(ltt_time_compare(hashed_process_data->next_good_time,
633 // if(hashed_process_data->x.middle_marked == FALSE) {
635 // TimeWindow time_window =
636 // lttvwindow_get_time_window(control_flow_data->tab);
638 // if(ltt_time_compare(evtime, time_window.start_time) == -1
639 // || ltt_time_compare(evtime, time_window.end_time) == 1)
641 //#endif //EXTRA_CHECK
642 // Drawing_t *drawing = control_flow_data->drawing;
643 // guint width = drawing->width;
645 // convert_time_to_pixels(
651 // /* Draw collision indicator */
652 // gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
653 // gdk_draw_point(hashed_process_data->pixmap,
656 // COLLISION_POSITION(hashed_process_data->height));
657 // hashed_process_data->x.middle_marked = TRUE;
660 // TimeWindow time_window =
661 // lttvwindow_get_time_window(control_flow_data->tab);
663 // if(ltt_time_compare(evtime, time_window.start_time) == -1
664 // || ltt_time_compare(evtime, time_window.end_time) == 1)
666 //#endif //EXTRA_CHECK
667 // Drawing_t *drawing = control_flow_data->drawing;
668 // guint width = drawing->width;
671 // convert_time_to_pixels(
678 // /* Jump over draw if we are at the same x position */
679 // if(x == hashed_process_data->x.middle &&
680 // hashed_process_data->x.middle_used)
682 // if(hashed_process_data->x.middle_marked == FALSE) {
683 // /* Draw collision indicator */
684 // gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
685 // gdk_draw_point(hashed_process_data->pixmap,
688 // COLLISION_POSITION(hashed_process_data->height));
689 // hashed_process_data->x.middle_marked = TRUE;
693 // DrawContext draw_context;
695 // /* Now create the drawing context that will be used to draw
696 // * items related to the last state. */
697 // draw_context.drawable = hashed_process_data->pixmap;
698 // draw_context.gc = drawing->gc;
699 // draw_context.pango_layout = drawing->pango_layout;
700 // draw_context.drawinfo.start.x = hashed_process_data->x.middle;
701 // draw_context.drawinfo.end.x = x;
703 // draw_context.drawinfo.y.over = 1;
704 // draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
705 // draw_context.drawinfo.y.under = hashed_process_data->height;
707 // draw_context.drawinfo.start.offset.over = 0;
708 // draw_context.drawinfo.start.offset.middle = 0;
709 // draw_context.drawinfo.start.offset.under = 0;
710 // draw_context.drawinfo.end.offset.over = 0;
711 // draw_context.drawinfo.end.offset.middle = 0;
712 // draw_context.drawinfo.end.offset.under = 0;
715 // /* Draw the line */
716 // PropertiesLine prop_line = prepare_s_e_line(process);
717 // draw_line((void*)&prop_line, (void*)&draw_context);
721 // /* become the last x position */
722 // hashed_process_data->x.middle = x;
723 // hashed_process_data->x.middle_used = TRUE;
724 // hashed_process_data->x.middle_marked = FALSE;
726 // /* Calculate the next good time */
727 // convert_pixels_to_time(width, x+1, time_window,
728 // &hashed_process_data->next_good_time);
732 // g_warning("Cannot find pin_in in schedchange %u", pid_in);
734 // tfc->target_pid = target_pid_saved;
742 GString
*string
= g_string_new("");;
743 gboolean field_names
= TRUE
, state
= TRUE
;
745 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
746 g_string_append_printf(string
,"\n");
749 g_string_append_printf(string
, " %s",
750 g_quark_to_string(tfs
->process
->state
->s
));
753 g_info("%s",string
->str
);
755 g_string_free(string
, TRUE
);
757 /* End of text dump */
762 /* after_schedchange_hook
764 * The draw after hook is called by the reading API to have a
765 * particular event drawn on the screen.
766 * @param hook_data ControlFlowData structure of the viewer.
767 * @param call_data Event context.
769 * This function adds items to be drawn in a queue for each process.
772 int after_schedchange_hook(void *hook_data
, void *call_data
)
774 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
775 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
776 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
778 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
780 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
782 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
785 e
= ltt_tracefile_get_event(tfc
->tf
);
787 LttvFilter
*filter
= control_flow_data
->filter
;
788 if(filter
!= NULL
&& filter
->head
!= NULL
)
789 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
790 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
793 LttTime evtime
= ltt_event_time(e
);
797 /* Add process to process list (if not present) */
798 LttvProcessState
*process_in
;
801 HashedResourceData
*hashed_process_data_in
= NULL
;
803 ProcessList
*process_list
= control_flow_data
->process_list
;
808 pid_out
= ltt_event_get_long_unsigned(e
, thf
->f1
);
809 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f2
);
813 /* Find process pid_in in the list... */
814 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
815 //process_in = tfs->process;
816 guint cpu
= tfs
->cpu
;
819 cpustr
= g_strdup_printf("CPU%u", cpu
);
820 cpuq
= g_quark_from_string(cpustr
);
823 guint trace_num
= ts
->parent
.index
;
824 process_in
= ts
->running_process
[cpu
];
825 /* It should exist, because we are after the state update. */
827 g_assert(process_in
!= NULL
);
829 birth
= process_in
->creation_time
;
831 hashed_process_data_in
= processlist_get_process_data(process_list
, cpuq
, trace_num
);
832 // hashed_process_data_in = processlist_get_process_data(process_list,
837 if(hashed_process_data_in
== NULL
)
839 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
840 ResourceInfo
*process_info
;
841 Drawing_t
*drawing
= control_flow_data
->drawing
;
842 /* Process not present */
843 resourcelist_add(process_list
,
851 &hashed_process_data_in
);
852 gtk_widget_set_size_request(drawing
->drawing_area
,
855 gtk_widget_queue_draw(drawing
->drawing_area
);
857 /* Set the current process */
858 process_list
->current_hash_data
[trace_num
][process_in
->cpu
] =
859 hashed_process_data_in
;
861 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
864 TimeWindow time_window
=
865 lttvwindow_get_time_window(control_flow_data
->tab
);
868 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
869 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
872 Drawing_t
*drawing
= control_flow_data
->drawing
;
873 guint width
= drawing
->width
;
876 convert_time_to_pixels(
882 if(hashed_process_data_in
->x
.middle
!= new_x
) {
883 hashed_process_data_in
->x
.middle
= new_x
;
884 hashed_process_data_in
->x
.middle_used
= FALSE
;
885 hashed_process_data_in
->x
.middle_marked
= FALSE
;
891 /* before_execmode_hook
893 * This function basically draw lines and icons. Two types of lines are drawn :
894 * one small (3 pixels?) representing the state of the process and the second
895 * type is thicker (10 pixels?) representing on which CPU a process is running
896 * (and this only in running state).
898 * Extremums of the lines :
899 * x_min : time of the last event context for this process kept in memory.
900 * x_max : time of the current event.
901 * y : middle of the process in the process list. The process is found in the
902 * list, therefore is it's position in pixels.
904 * The choice of lines'color is defined by the context of the last event for this
908 int before_execmode_hook(void *hook_data
, void *call_data
)
910 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
911 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
912 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
914 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
916 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
917 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
920 e
= ltt_tracefile_get_event(tfc
->tf
);
922 LttTime evtime
= ltt_event_time(e
);
926 /* we are in a execmode, before the state update. We must draw the
927 * items corresponding to the state before it changes : now is the right
931 //LttvProcessState *process = tfs->process;
932 guint cpu
= tfs
->cpu
;
935 cpustr
= g_strdup_printf("CPU%u", cpu
);
936 cpuq
= g_quark_from_string(cpustr
);
939 guint trace_num
= ts
->parent
.index
;
940 LttvProcessState
*process
= ts
->running_process
[cpu
];
941 g_assert(process
!= NULL
);
943 // guint pid = process->pid;
945 /* Well, the process_out existed : we must get it in the process hash
946 * or add it, and draw its items.
948 /* Add process to process list (if not present) */
950 HashedResourceData
*hashed_process_data
= NULL
;
951 ProcessList
*process_list
= control_flow_data
->process_list
;
952 LttTime birth
= process
->creation_time
;
954 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
955 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
957 hashed_process_data
= processlist_get_process_data(process_list
, cpuq
, trace_num
);
958 // hashed_process_data = processlist_get_process_data(process_list,
963 if(unlikely(hashed_process_data
== NULL
))
965 //g_assert(pid == 0 || pid != process->ppid);
966 ResourceInfo
*process_info
;
967 /* Process not present */
968 Drawing_t
*drawing
= control_flow_data
->drawing
;
969 resourcelist_add(process_list
,
972 cpuq
, //process->name,
977 &hashed_process_data
);
978 gtk_widget_set_size_request(drawing
->drawing_area
,
981 gtk_widget_queue_draw(drawing
->drawing_area
);
983 /* Set the current process */
984 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
988 /* Now, the process is in the state hash and our own process hash.
989 * We definitely can draw the items related to the ending state.
992 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
995 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
996 TimeWindow time_window
=
997 lttvwindow_get_time_window(control_flow_data
->tab
);
1000 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1001 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1003 #endif //EXTRA_CHECK
1004 Drawing_t
*drawing
= control_flow_data
->drawing
;
1005 guint width
= drawing
->width
;
1007 convert_time_to_pixels(
1013 /* Draw collision indicator */
1014 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1015 gdk_draw_point(hashed_process_data
->pixmap
,
1018 COLLISION_POSITION(hashed_process_data
->height
));
1019 hashed_process_data
->x
.middle_marked
= TRUE
;
1023 TimeWindow time_window
=
1024 lttvwindow_get_time_window(control_flow_data
->tab
);
1027 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1028 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1030 #endif //EXTRA_CHECK
1031 Drawing_t
*drawing
= control_flow_data
->drawing
;
1032 guint width
= drawing
->width
;
1035 convert_time_to_pixels(
1042 /* Jump over draw if we are at the same x position */
1043 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1044 hashed_process_data
->x
.middle_used
))
1046 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1047 /* Draw collision indicator */
1048 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1049 gdk_draw_point(hashed_process_data
->pixmap
,
1052 COLLISION_POSITION(hashed_process_data
->height
));
1053 hashed_process_data
->x
.middle_marked
= TRUE
;
1059 DrawContext draw_context
;
1060 /* Now create the drawing context that will be used to draw
1061 * items related to the last state. */
1062 draw_context
.drawable
= hashed_process_data
->pixmap
;
1063 draw_context
.gc
= drawing
->gc
;
1064 draw_context
.pango_layout
= drawing
->pango_layout
;
1065 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1066 draw_context
.drawinfo
.end
.x
= x
;
1068 draw_context
.drawinfo
.y
.over
= 1;
1069 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1070 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1072 draw_context
.drawinfo
.start
.offset
.over
= 0;
1073 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1074 draw_context
.drawinfo
.start
.offset
.under
= 0;
1075 draw_context
.drawinfo
.end
.offset
.over
= 0;
1076 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1077 draw_context
.drawinfo
.end
.offset
.under
= 0;
1081 PropertiesLine prop_line
;
1082 prop_line
.line_width
= STATE_LINE_WIDTH
;
1083 prop_line
.style
= GDK_LINE_SOLID
;
1084 prop_line
.y
= MIDDLE
;
1085 cpu_set_line_color(&prop_line
, tfs
->cpu_state
);
1086 draw_line((void*)&prop_line
, (void*)&draw_context
);
1088 /* become the last x position */
1089 hashed_process_data
->x
.middle
= x
;
1090 hashed_process_data
->x
.middle_used
= TRUE
;
1091 hashed_process_data
->x
.middle_marked
= FALSE
;
1093 /* Calculate the next good time */
1094 convert_pixels_to_time(width
, x
+1, time_window
,
1095 &hashed_process_data
->next_good_time
);
1102 /* before_process_exit_hook
1104 * Draw lines for process event.
1106 * @param hook_data ControlFlowData structure of the viewer.
1107 * @param call_data Event context.
1109 * This function adds items to be drawn in a queue for each process.
1113 //int before_process_exit_hook(void *hook_data, void *call_data)
1115 // LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1116 // EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1118 // ControlFlowData *control_flow_data = events_request->viewer_data;
1120 // LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1122 // LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1124 // LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1127 // e = ltt_tracefile_get_event(tfc->tf);
1129 // LttvFilter *filter = control_flow_data->filter;
1130 // if(filter != NULL && filter->head != NULL)
1131 // if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1132 // tfc->t_context->t,tfc,NULL,NULL))
1135 // LttTime evtime = ltt_event_time(e);
1137 // /* Add process to process list (if not present) */
1138 // //LttvProcessState *process = tfs->process;
1139 // guint cpu = tfs->cpu;
1140 // guint trace_num = ts->parent.index;
1141 // LttvProcessState *process = ts->running_process[cpu];
1142 // guint pid = process->pid;
1144 // guint pl_height = 0;
1145 // HashedResourceData *hashed_process_data = NULL;
1147 // ProcessList *process_list = control_flow_data->process_list;
1149 // g_assert(process != NULL);
1151 // birth = process->creation_time;
1153 // if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1154 // hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1156 // hashed_process_data = processlist_get_process_data(process_list, "CPU0");
1157 //// hashed_process_data = processlist_get_process_data(process_list,
1162 // if(unlikely(hashed_process_data == NULL))
1164 // g_assert(pid == 0 || pid != process->ppid);
1165 // /* Process not present */
1166 // Drawing_t *drawing = control_flow_data->drawing;
1167 // ResourceInfo *process_info;
1168 // processlist_add(process_list,
1180 // &hashed_process_data);
1181 // gtk_widget_set_size_request(drawing->drawing_area,
1184 // gtk_widget_queue_draw(drawing->drawing_area);
1188 // /* Now, the process is in the state hash and our own process hash.
1189 // * We definitely can draw the items related to the ending state.
1192 // if(likely(ltt_time_compare(hashed_process_data->next_good_time,
1195 // if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1196 // TimeWindow time_window =
1197 // lttvwindow_get_time_window(control_flow_data->tab);
1199 //#ifdef EXTRA_CHECK
1200 // if(ltt_time_compare(evtime, time_window.start_time) == -1
1201 // || ltt_time_compare(evtime, time_window.end_time) == 1)
1203 //#endif //EXTRA_CHECK
1204 // Drawing_t *drawing = control_flow_data->drawing;
1205 // guint width = drawing->width;
1207 // convert_time_to_pixels(
1213 // /* Draw collision indicator */
1214 // gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1215 // gdk_draw_point(hashed_process_data->pixmap,
1218 // COLLISION_POSITION(hashed_process_data->height));
1219 // hashed_process_data->x.middle_marked = TRUE;
1222 // TimeWindow time_window =
1223 // lttvwindow_get_time_window(control_flow_data->tab);
1225 //#ifdef EXTRA_CHECK
1226 // if(ltt_time_compare(evtime, time_window.start_time) == -1
1227 // || ltt_time_compare(evtime, time_window.end_time) == 1)
1229 //#endif //EXTRA_CHECK
1230 // Drawing_t *drawing = control_flow_data->drawing;
1231 // guint width = drawing->width;
1234 // convert_time_to_pixels(
1241 // /* Jump over draw if we are at the same x position */
1242 // if(unlikely(x == hashed_process_data->x.middle &&
1243 // hashed_process_data->x.middle_used))
1245 // if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1246 // /* Draw collision indicator */
1247 // gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1248 // gdk_draw_point(hashed_process_data->pixmap,
1251 // COLLISION_POSITION(hashed_process_data->height));
1252 // hashed_process_data->x.middle_marked = TRUE;
1256 // DrawContext draw_context;
1258 // /* Now create the drawing context that will be used to draw
1259 // * items related to the last state. */
1260 // draw_context.drawable = hashed_process_data->pixmap;
1261 // draw_context.gc = drawing->gc;
1262 // draw_context.pango_layout = drawing->pango_layout;
1263 // draw_context.drawinfo.start.x = hashed_process_data->x.middle;
1264 // draw_context.drawinfo.end.x = x;
1266 // draw_context.drawinfo.y.over = 1;
1267 // draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
1268 // draw_context.drawinfo.y.under = hashed_process_data->height;
1270 // draw_context.drawinfo.start.offset.over = 0;
1271 // draw_context.drawinfo.start.offset.middle = 0;
1272 // draw_context.drawinfo.start.offset.under = 0;
1273 // draw_context.drawinfo.end.offset.over = 0;
1274 // draw_context.drawinfo.end.offset.middle = 0;
1275 // draw_context.drawinfo.end.offset.under = 0;
1278 // /* Draw the line */
1279 // PropertiesLine prop_line = prepare_s_e_line(process);
1280 // draw_line((void*)&prop_line, (void*)&draw_context);
1283 // /* become the last x position */
1284 // hashed_process_data->x.middle = x;
1285 // hashed_process_data->x.middle_used = TRUE;
1286 // hashed_process_data->x.middle_marked = FALSE;
1288 // /* Calculate the next good time */
1289 // convert_pixels_to_time(width, x+1, time_window,
1290 // &hashed_process_data->next_good_time);
1299 /* before_process_release_hook
1301 * Draw lines for process event.
1303 * @param hook_data ControlFlowData structure of the viewer.
1304 * @param call_data Event context.
1306 * This function adds items to be drawn in a queue for each process.
1310 //int before_process_release_hook(void *hook_data, void *call_data)
1312 // LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1313 // EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1315 // ControlFlowData *control_flow_data = events_request->viewer_data;
1317 // LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1319 // LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1321 // LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1324 // e = ltt_tracefile_get_event(tfc->tf);
1326 // LttvFilter *filter = control_flow_data->filter;
1327 // if(filter != NULL && filter->head != NULL)
1328 // if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1329 // tfc->t_context->t,tfc,NULL,NULL))
1332 // LttTime evtime = ltt_event_time(e);
1334 // guint trace_num = ts->parent.index;
1338 // pid = ltt_event_get_long_unsigned(e, thf->f1);
1341 // /* Add process to process list (if not present) */
1342 // /* Don't care about the process if it's not in the state hash already :
1343 // * that means a process that has never done anything in the trace and
1344 // * unknown suddently gets destroyed : no state meaningful to show. */
1345 // LttvProcessState *process = lttv_state_find_process(ts, ANY_CPU, pid);
1347 // if(process != NULL) {
1349 // guint pl_height = 0;
1350 // HashedResourceData *hashed_process_data = NULL;
1352 // ProcessList *process_list = control_flow_data->process_list;
1354 // birth = process->creation_time;
1356 // /* Cannot use current process : this event happens on another process,
1357 // * action done by the parent. */
1358 // hashed_process_data = processlist_get_process_data(process_list, "CPU0");
1359 //// hashed_process_data = processlist_get_process_data(process_list,
1364 // if(unlikely(hashed_process_data == NULL))
1366 // g_assert(pid == 0 || pid != process->ppid);
1367 // /* Process not present */
1368 // Drawing_t *drawing = control_flow_data->drawing;
1369 // ResourceInfo *process_info;
1370 // processlist_add(process_list,
1382 // &hashed_process_data);
1383 // gtk_widget_set_size_request(drawing->drawing_area,
1386 // gtk_widget_queue_draw(drawing->drawing_area);
1389 // /* Now, the process is in the state hash and our own process hash.
1390 // * We definitely can draw the items related to the ending state.
1393 // if(likely(ltt_time_compare(hashed_process_data->next_good_time,
1396 // if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1397 // TimeWindow time_window =
1398 // lttvwindow_get_time_window(control_flow_data->tab);
1400 //#ifdef EXTRA_CHECK
1401 // if(ltt_time_compare(evtime, time_window.start_time) == -1
1402 // || ltt_time_compare(evtime, time_window.end_time) == 1)
1404 //#endif //EXTRA_CHECK
1405 // Drawing_t *drawing = control_flow_data->drawing;
1406 // guint width = drawing->width;
1408 // convert_time_to_pixels(
1414 // /* Draw collision indicator */
1415 // gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1416 // gdk_draw_point(hashed_process_data->pixmap,
1419 // COLLISION_POSITION(hashed_process_data->height));
1420 // hashed_process_data->x.middle_marked = TRUE;
1423 // TimeWindow time_window =
1424 // lttvwindow_get_time_window(control_flow_data->tab);
1426 //#ifdef EXTRA_CHECK
1427 // if(ltt_time_compare(evtime, time_window.start_time) == -1
1428 // || ltt_time_compare(evtime, time_window.end_time) == 1)
1430 //#endif //EXTRA_CHECK
1431 // Drawing_t *drawing = control_flow_data->drawing;
1432 // guint width = drawing->width;
1435 // convert_time_to_pixels(
1442 // /* Jump over draw if we are at the same x position */
1443 // if(unlikely(x == hashed_process_data->x.middle &&
1444 // hashed_process_data->x.middle_used))
1446 // if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1447 // /* Draw collision indicator */
1448 // gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1449 // gdk_draw_point(hashed_process_data->pixmap,
1452 // COLLISION_POSITION(hashed_process_data->height));
1453 // hashed_process_data->x.middle_marked = TRUE;
1457 // DrawContext draw_context;
1459 // /* Now create the drawing context that will be used to draw
1460 // * items related to the last state. */
1461 // draw_context.drawable = hashed_process_data->pixmap;
1462 // draw_context.gc = drawing->gc;
1463 // draw_context.pango_layout = drawing->pango_layout;
1464 // draw_context.drawinfo.start.x = hashed_process_data->x.middle;
1465 // draw_context.drawinfo.end.x = x;
1467 // draw_context.drawinfo.y.over = 1;
1468 // draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
1469 // draw_context.drawinfo.y.under = hashed_process_data->height;
1471 // draw_context.drawinfo.start.offset.over = 0;
1472 // draw_context.drawinfo.start.offset.middle = 0;
1473 // draw_context.drawinfo.start.offset.under = 0;
1474 // draw_context.drawinfo.end.offset.over = 0;
1475 // draw_context.drawinfo.end.offset.middle = 0;
1476 // draw_context.drawinfo.end.offset.under = 0;
1479 // /* Draw the line */
1480 // PropertiesLine prop_line = prepare_s_e_line(process);
1481 // draw_line((void*)&prop_line, (void*)&draw_context);
1484 // /* become the last x position */
1485 // hashed_process_data->x.middle = x;
1486 // hashed_process_data->x.middle_used = TRUE;
1487 // hashed_process_data->x.middle_marked = FALSE;
1489 // /* Calculate the next good time */
1490 // convert_pixels_to_time(width, x+1, time_window,
1491 // &hashed_process_data->next_good_time);
1499 /* after_process_fork_hook
1501 * Create the processlist entry for the child process. Put the last
1502 * position in x at the current time value.
1504 * @param hook_data ControlFlowData structure of the viewer.
1505 * @param call_data Event context.
1507 * This function adds items to be drawn in a queue for each process.
1510 //int after_process_fork_hook(void *hook_data, void *call_data)
1512 // LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1513 // EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1514 // ControlFlowData *control_flow_data = events_request->viewer_data;
1516 // LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1518 // LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1520 // LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1523 // e = ltt_tracefile_get_event(tfc->tf);
1525 // LttvFilter *filter = control_flow_data->filter;
1526 // if(filter != NULL && filter->head != NULL)
1527 // if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1528 // tfc->t_context->t,tfc,NULL,NULL))
1531 // LttTime evtime = ltt_event_time(e);
1535 // child_pid = ltt_event_get_long_unsigned(e, thf->f2);
1538 // /* Add process to process list (if not present) */
1539 // LttvProcessState *process_child;
1541 // guint pl_height = 0;
1542 // HashedResourceData *hashed_process_data_child = NULL;
1544 // ProcessList *process_list = control_flow_data->process_list;
1546 // /* Find child in the list... */
1547 // process_child = lttv_state_find_process(ts, ANY_CPU, child_pid);
1548 // /* It should exist, because we are after the state update. */
1549 // g_assert(process_child != NULL);
1551 // birth = process_child->creation_time;
1552 // guint trace_num = ts->parent.index;
1554 // /* Cannot use current process, because this action is done by the parent
1555 // * on its child. */
1556 // hashed_process_data_child = processlist_get_process_data(process_list, "CPU0");
1557 //// hashed_process_data_child = processlist_get_process_data(process_list,
1559 //// process_child->cpu,
1562 // if(likely(hashed_process_data_child == NULL))
1564 // g_assert(child_pid == 0 || child_pid != process_child->ppid);
1565 // /* Process not present */
1566 // Drawing_t *drawing = control_flow_data->drawing;
1567 // ResourceInfo *process_info;
1568 // processlist_add(process_list,
1571 // process_child->tgid,
1572 // process_child->cpu,
1573 // process_child->ppid,
1576 // process_child->name,
1577 // process_child->brand,
1580 // &hashed_process_data_child);
1581 // gtk_widget_set_size_request(drawing->drawing_area,
1584 // gtk_widget_queue_draw(drawing->drawing_area);
1586 // processlist_set_ppid(process_list, process_child->ppid,
1587 // hashed_process_data_child);
1588 // processlist_set_tgid(process_list, process_child->tgid,
1589 // hashed_process_data_child);
1593 // if(likely(ltt_time_compare(hashed_process_data_child->next_good_time,
1596 // TimeWindow time_window =
1597 // lttvwindow_get_time_window(control_flow_data->tab);
1599 //#ifdef EXTRA_CHECK
1600 // if(ltt_time_compare(evtime, time_window.start_time) == -1
1601 // || ltt_time_compare(evtime, time_window.end_time) == 1)
1603 //#endif //EXTRA_CHECK
1604 // Drawing_t *drawing = control_flow_data->drawing;
1605 // guint width = drawing->width;
1607 // convert_time_to_pixels(
1613 // if(likely(hashed_process_data_child->x.over != new_x)) {
1614 // hashed_process_data_child->x.over = new_x;
1615 // hashed_process_data_child->x.over_used = FALSE;
1616 // hashed_process_data_child->x.over_marked = FALSE;
1618 // if(likely(hashed_process_data_child->x.middle != new_x)) {
1619 // hashed_process_data_child->x.middle = new_x;
1620 // hashed_process_data_child->x.middle_used = FALSE;
1621 // hashed_process_data_child->x.middle_marked = FALSE;
1623 // if(likely(hashed_process_data_child->x.under != new_x)) {
1624 // hashed_process_data_child->x.under = new_x;
1625 // hashed_process_data_child->x.under_used = FALSE;
1626 // hashed_process_data_child->x.under_marked = FALSE;
1634 /* after_process_exit_hook
1636 * Create the processlist entry for the child process. Put the last
1637 * position in x at the current time value.
1639 * @param hook_data ControlFlowData structure of the viewer.
1640 * @param call_data Event context.
1642 * This function adds items to be drawn in a queue for each process.
1645 //int after_process_exit_hook(void *hook_data, void *call_data)
1647 // LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1648 // EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1649 // ControlFlowData *control_flow_data = events_request->viewer_data;
1651 // LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1653 // LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1655 // LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1658 // e = ltt_tracefile_get_event(tfc->tf);
1660 // LttvFilter *filter = control_flow_data->filter;
1661 // if(filter != NULL && filter->head != NULL)
1662 // if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1663 // tfc->t_context->t,tfc,NULL,NULL))
1666 // LttTime evtime = ltt_event_time(e);
1668 // /* Add process to process list (if not present) */
1669 // //LttvProcessState *process = tfs->process;
1670 // guint cpu = tfs->cpu;
1671 // guint trace_num = ts->parent.index;
1672 // LttvProcessState *process = ts->running_process[cpu];
1674 // /* It should exist, because we are after the state update. */
1675 // g_assert(process != NULL);
1677 // guint pid = process->pid;
1679 // guint pl_height = 0;
1680 // HashedResourceData *hashed_process_data = NULL;
1682 // ProcessList *process_list = control_flow_data->process_list;
1684 // birth = process->creation_time;
1686 // if(likely(process_list->current_hash_data[trace_num][cpu] != NULL) ){
1687 // hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1689 // hashed_process_data = processlist_get_process_data(process_list, "CPU0");
1690 //// hashed_process_data = processlist_get_process_data(process_list,
1695 // if(unlikely(hashed_process_data == NULL))
1697 // g_assert(pid == 0 || pid != process->ppid);
1698 // /* Process not present */
1699 // Drawing_t *drawing = control_flow_data->drawing;
1700 // ResourceInfo *process_info;
1701 // processlist_add(process_list,
1713 // &hashed_process_data);
1714 // gtk_widget_set_size_request(drawing->drawing_area,
1717 // gtk_widget_queue_draw(drawing->drawing_area);
1720 // /* Set the current process */
1721 // process_list->current_hash_data[trace_num][process->cpu] =
1722 // hashed_process_data;
1725 // if(unlikely(ltt_time_compare(hashed_process_data->next_good_time,
1728 // TimeWindow time_window =
1729 // lttvwindow_get_time_window(control_flow_data->tab);
1731 //#ifdef EXTRA_CHECK
1732 // if(ltt_time_compare(evtime, time_window.start_time) == -1
1733 // || ltt_time_compare(evtime, time_window.end_time) == 1)
1735 //#endif //EXTRA_CHECK
1736 // Drawing_t *drawing = control_flow_data->drawing;
1737 // guint width = drawing->width;
1739 // convert_time_to_pixels(
1744 // if(unlikely(hashed_process_data->x.middle != new_x)) {
1745 // hashed_process_data->x.middle = new_x;
1746 // hashed_process_data->x.middle_used = FALSE;
1747 // hashed_process_data->x.middle_marked = FALSE;
1755 /* Get the filename of the process to print */
1756 //int after_fs_exec_hook(void *hook_data, void *call_data)
1758 // LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1759 // EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1760 // ControlFlowData *control_flow_data = events_request->viewer_data;
1762 // LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1764 // LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1766 // LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1769 // e = ltt_tracefile_get_event(tfc->tf);
1771 // LttvFilter *filter = control_flow_data->filter;
1772 // if(filter != NULL && filter->head != NULL)
1773 // if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1774 // tfc->t_context->t,tfc,NULL,NULL))
1777 // guint cpu = tfs->cpu;
1778 // guint trace_num = ts->parent.index;
1779 // LttvProcessState *process = ts->running_process[cpu];
1780 // g_assert(process != NULL);
1782 // guint pid = process->pid;
1784 // /* Well, the process_out existed : we must get it in the process hash
1785 // * or add it, and draw its items.
1787 // /* Add process to process list (if not present) */
1788 // guint pl_height = 0;
1789 // HashedResourceData *hashed_process_data = NULL;
1790 // ProcessList *process_list = control_flow_data->process_list;
1791 // LttTime birth = process->creation_time;
1793 // if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1794 // hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1796 // hashed_process_data = processlist_get_process_data(process_list, "CPU0");
1797 //// hashed_process_data = processlist_get_process_data(process_list,
1802 // if(unlikely(hashed_process_data == NULL))
1804 // g_assert(pid == 0 || pid != process->ppid);
1805 // ResourceInfo *process_info;
1806 // /* Process not present */
1807 // Drawing_t *drawing = control_flow_data->drawing;
1808 // processlist_add(process_list,
1820 // &hashed_process_data);
1821 // gtk_widget_set_size_request(drawing->drawing_area,
1824 // gtk_widget_queue_draw(drawing->drawing_area);
1826 // /* Set the current process */
1827 // process_list->current_hash_data[trace_num][process->cpu] =
1828 // hashed_process_data;
1831 // processlist_set_name(process_list, process->name, hashed_process_data);
1837 /* Get the filename of the process to print */
1838 //int after_user_generic_thread_brand_hook(void *hook_data, void *call_data)
1840 // LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1841 // EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1842 // ControlFlowData *control_flow_data = events_request->viewer_data;
1844 // LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1846 // LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1848 // LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1851 // e = ltt_tracefile_get_event(tfc->tf);
1853 // LttvFilter *filter = control_flow_data->filter;
1854 // if(filter != NULL && filter->head != NULL)
1855 // if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1856 // tfc->t_context->t,tfc,NULL,NULL))
1859 // guint cpu = tfs->cpu;
1860 // guint trace_num = ts->parent.index;
1861 // LttvProcessState *process = ts->running_process[cpu];
1862 // g_assert(process != NULL);
1864 // guint pid = process->pid;
1866 // /* Well, the process_out existed : we must get it in the process hash
1867 // * or add it, and draw its items.
1869 // /* Add process to process list (if not present) */
1870 // guint pl_height = 0;
1871 // HashedResourceData *hashed_process_data = NULL;
1872 // ProcessList *process_list = control_flow_data->process_list;
1873 // LttTime birth = process->creation_time;
1875 // if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1876 // hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1878 // hashed_process_data = processlist_get_process_data(process_list, "CPU0");
1879 //// hashed_process_data = processlist_get_process_data(process_list,
1884 // if(unlikely(hashed_process_data == NULL))
1886 // g_assert(pid == 0 || pid != process->ppid);
1887 // ResourceInfo *process_info;
1888 // /* Process not present */
1889 // Drawing_t *drawing = control_flow_data->drawing;
1890 // processlist_add(process_list,
1902 // &hashed_process_data);
1903 // gtk_widget_set_size_request(drawing->drawing_area,
1906 // gtk_widget_queue_draw(drawing->drawing_area);
1908 // /* Set the current process */
1909 // process_list->current_hash_data[trace_num][process->cpu] =
1910 // hashed_process_data;
1913 // processlist_set_brand(process_list, process->brand, hashed_process_data);
1920 /* after_event_enum_process_hook
1922 * Create the processlist entry for the child process. Put the last
1923 * position in x at the current time value.
1925 * @param hook_data ControlFlowData structure of the viewer.
1926 * @param call_data Event context.
1928 * This function adds items to be drawn in a queue for each process.
1931 //int after_event_enum_process_hook(void *hook_data, void *call_data)
1933 // LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1934 // EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1935 // ControlFlowData *control_flow_data = events_request->viewer_data;
1937 // LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1939 // LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1941 // LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1943 // guint first_cpu, nb_cpus, cpu;
1946 // e = ltt_tracefile_get_event(tfc->tf);
1948 // LttvFilter *filter = control_flow_data->filter;
1949 // if(filter != NULL && filter->head != NULL)
1950 // if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1951 // tfc->t_context->t,tfc,NULL,NULL))
1954 // LttTime evtime = ltt_event_time(e);
1956 // /* Add process to process list (if not present) */
1957 // LttvProcessState *process_in;
1959 // guint pl_height = 0;
1960 // HashedResourceData *hashed_process_data_in = NULL;
1962 // ProcessList *process_list = control_flow_data->process_list;
1963 // guint trace_num = ts->parent.index;
1967 // pid_in = ltt_event_get_long_unsigned(e, thf->f1);
1970 // if(pid_in == 0) {
1972 // nb_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1974 // first_cpu = ANY_CPU;
1975 // nb_cpus = ANY_CPU+1;
1978 // for(cpu = first_cpu; cpu < nb_cpus; cpu++) {
1979 // /* Find process pid_in in the list... */
1980 // process_in = lttv_state_find_process(ts, cpu, pid_in);
1981 // //process_in = tfs->process;
1982 // //guint cpu = tfs->cpu;
1983 // //guint trace_num = ts->parent.index;
1984 // //process_in = ts->running_process[cpu];
1985 // /* It should exist, because we are after the state update. */
1986 // #ifdef EXTRA_CHECK
1987 // //g_assert(process_in != NULL);
1988 // #endif //EXTRA_CHECK
1989 // birth = process_in->creation_time;
1991 // hashed_process_data_in = processlist_get_process_data(process_list, "CPU0");
1992 //// hashed_process_data_in = processlist_get_process_data(process_list,
1994 //// process_in->cpu,
1997 // if(hashed_process_data_in == NULL)
1999 // if(pid_in != 0 && pid_in == process_in->ppid)
2000 // g_critical("TEST %u , %u", pid_in, process_in->ppid);
2001 // g_assert(pid_in == 0 || pid_in != process_in->ppid);
2002 // ResourceInfo *process_info;
2003 // Drawing_t *drawing = control_flow_data->drawing;
2004 // /* Process not present */
2005 // processlist_add(process_list,
2008 // process_in->tgid,
2010 // process_in->ppid,
2013 // process_in->name,
2014 // process_in->brand,
2017 // &hashed_process_data_in);
2018 // gtk_widget_set_size_request(drawing->drawing_area,
2021 // gtk_widget_queue_draw(drawing->drawing_area);
2023 // processlist_set_name(process_list, process_in->name,
2024 // hashed_process_data_in);
2025 // processlist_set_ppid(process_list, process_in->ppid,
2026 // hashed_process_data_in);
2027 // processlist_set_tgid(process_list, process_in->tgid,
2028 // hashed_process_data_in);
2035 gint
update_time_window_hook(void *hook_data
, void *call_data
)
2037 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2038 Drawing_t
*drawing
= control_flow_data
->drawing
;
2039 ProcessList
*process_list
= control_flow_data
->process_list
;
2041 const TimeWindowNotifyData
*time_window_nofify_data
=
2042 ((const TimeWindowNotifyData
*)call_data
);
2044 TimeWindow
*old_time_window
=
2045 time_window_nofify_data
->old_time_window
;
2046 TimeWindow
*new_time_window
=
2047 time_window_nofify_data
->new_time_window
;
2049 /* Update the ruler */
2050 drawing_update_ruler(control_flow_data
->drawing
,
2054 /* Two cases : zoom in/out or scrolling */
2056 /* In order to make sure we can reuse the old drawing, the scale must
2057 * be the same and the new time interval being partly located in the
2058 * currently shown time interval. (reuse is only for scrolling)
2061 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
2062 old_time_window
->start_time
.tv_sec
,
2063 old_time_window
->start_time
.tv_nsec
,
2064 old_time_window
->time_width
.tv_sec
,
2065 old_time_window
->time_width
.tv_nsec
);
2067 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
2068 new_time_window
->start_time
.tv_sec
,
2069 new_time_window
->start_time
.tv_nsec
,
2070 new_time_window
->time_width
.tv_sec
,
2071 new_time_window
->time_width
.tv_nsec
);
2073 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
2074 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
2076 /* Same scale (scrolling) */
2077 g_info("scrolling");
2078 LttTime
*ns
= &new_time_window
->start_time
;
2079 LttTime
*nw
= &new_time_window
->time_width
;
2080 LttTime
*os
= &old_time_window
->start_time
;
2081 LttTime
*ow
= &old_time_window
->time_width
;
2082 LttTime old_end
= old_time_window
->end_time
;
2083 LttTime new_end
= new_time_window
->end_time
;
2085 //if(ns<os+w && os+w<ns+w)
2086 //if(ns<old_end && os<ns)
2087 if(ltt_time_compare(*ns
, old_end
) == -1
2088 && ltt_time_compare(*os
, *ns
) == -1)
2090 g_info("scrolling near right");
2091 /* Scroll right, keep right part of the screen */
2093 guint width
= control_flow_data
->drawing
->width
;
2094 convert_time_to_pixels(
2100 /* Copy old data to new location */
2101 copy_pixmap_region(process_list
,
2103 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2107 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
2109 if(drawing
->damage_begin
== drawing
->damage_end
)
2110 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
2112 drawing
->damage_begin
= 0;
2114 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2116 /* Clear the data request background, but not SAFETY */
2117 rectangle_pixmap(process_list
,
2118 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2120 drawing
->damage_begin
+SAFETY
, 0,
2121 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2123 gtk_widget_queue_draw(drawing
->drawing_area
);
2124 //gtk_widget_queue_draw_area (drawing->drawing_area,
2126 // control_flow_data->drawing->width,
2127 // control_flow_data->drawing->height);
2129 /* Get new data for the rest. */
2130 drawing_data_request(control_flow_data
->drawing
,
2131 drawing
->damage_begin
, 0,
2132 drawing
->damage_end
- drawing
->damage_begin
,
2133 control_flow_data
->drawing
->height
);
2136 //if(ns<os && os<ns+w)
2137 //if(ns<os && os<new_end)
2138 if(ltt_time_compare(*ns
,*os
) == -1
2139 && ltt_time_compare(*os
,new_end
) == -1)
2141 g_info("scrolling near left");
2142 /* Scroll left, keep left part of the screen */
2144 guint width
= control_flow_data
->drawing
->width
;
2145 convert_time_to_pixels(
2151 /* Copy old data to new location */
2152 copy_pixmap_region (process_list
,
2154 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2160 if(drawing
->damage_begin
== drawing
->damage_end
)
2161 drawing
->damage_end
= x
;
2163 drawing
->damage_end
=
2164 control_flow_data
->drawing
->width
;
2166 drawing
->damage_begin
= 0;
2168 rectangle_pixmap (process_list
,
2169 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2171 drawing
->damage_begin
, 0,
2172 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2175 gtk_widget_queue_draw(drawing
->drawing_area
);
2176 //gtk_widget_queue_draw_area (drawing->drawing_area,
2178 // control_flow_data->drawing->width,
2179 // control_flow_data->drawing->height);
2182 /* Get new data for the rest. */
2183 drawing_data_request(control_flow_data
->drawing
,
2184 drawing
->damage_begin
, 0,
2185 drawing
->damage_end
- drawing
->damage_begin
,
2186 control_flow_data
->drawing
->height
);
2189 if(ltt_time_compare(*ns
,*os
) == 0)
2191 g_info("not scrolling");
2193 g_info("scrolling far");
2194 /* Cannot reuse any part of the screen : far jump */
2197 rectangle_pixmap (process_list
,
2198 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2201 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2204 //gtk_widget_queue_draw_area (drawing->drawing_area,
2206 // control_flow_data->drawing->width,
2207 // control_flow_data->drawing->height);
2208 gtk_widget_queue_draw(drawing
->drawing_area
);
2210 drawing
->damage_begin
= 0;
2211 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2213 drawing_data_request(control_flow_data
->drawing
,
2215 control_flow_data
->drawing
->width
,
2216 control_flow_data
->drawing
->height
);
2222 /* Different scale (zoom) */
2225 rectangle_pixmap (process_list
,
2226 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2229 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2232 //gtk_widget_queue_draw_area (drawing->drawing_area,
2234 // control_flow_data->drawing->width,
2235 // control_flow_data->drawing->height);
2236 gtk_widget_queue_draw(drawing
->drawing_area
);
2238 drawing
->damage_begin
= 0;
2239 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2241 drawing_data_request(control_flow_data
->drawing
,
2243 control_flow_data
->drawing
->width
,
2244 control_flow_data
->drawing
->height
);
2247 /* Update directly when scrolling */
2248 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2254 gint
traceset_notify(void *hook_data
, void *call_data
)
2256 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2257 Drawing_t
*drawing
= control_flow_data
->drawing
;
2259 if(unlikely(drawing
->gc
== NULL
)) {
2262 if(drawing
->dotted_gc
== NULL
) {
2266 drawing_clear(control_flow_data
->drawing
);
2267 processlist_clear(control_flow_data
->process_list
);
2268 gtk_widget_set_size_request(
2269 control_flow_data
->drawing
->drawing_area
,
2270 -1, processlist_get_height(control_flow_data
->process_list
));
2271 redraw_notify(control_flow_data
, NULL
);
2273 request_background_data(control_flow_data
);
2278 gint
redraw_notify(void *hook_data
, void *call_data
)
2280 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2281 Drawing_t
*drawing
= control_flow_data
->drawing
;
2282 GtkWidget
*widget
= drawing
->drawing_area
;
2284 drawing
->damage_begin
= 0;
2285 drawing
->damage_end
= drawing
->width
;
2287 /* fun feature, to be separated someday... */
2288 drawing_clear(control_flow_data
->drawing
);
2289 processlist_clear(control_flow_data
->process_list
);
2290 gtk_widget_set_size_request(
2291 control_flow_data
->drawing
->drawing_area
,
2292 -1, processlist_get_height(control_flow_data
->process_list
));
2294 rectangle_pixmap (control_flow_data
->process_list
,
2295 widget
->style
->black_gc
,
2298 drawing
->alloc_width
,
2301 gtk_widget_queue_draw(drawing
->drawing_area
);
2303 if(drawing
->damage_begin
< drawing
->damage_end
)
2305 drawing_data_request(drawing
,
2306 drawing
->damage_begin
,
2308 drawing
->damage_end
-drawing
->damage_begin
,
2312 //gtk_widget_queue_draw_area(drawing->drawing_area,
2315 // drawing->height);
2321 gint
continue_notify(void *hook_data
, void *call_data
)
2323 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2324 Drawing_t
*drawing
= control_flow_data
->drawing
;
2326 //g_assert(widget->allocation.width == drawing->damage_end);
2328 if(drawing
->damage_begin
< drawing
->damage_end
)
2330 drawing_data_request(drawing
,
2331 drawing
->damage_begin
,
2333 drawing
->damage_end
-drawing
->damage_begin
,
2341 gint
update_current_time_hook(void *hook_data
, void *call_data
)
2343 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
2344 Drawing_t
*drawing
= control_flow_data
->drawing
;
2346 LttTime current_time
= *((LttTime
*)call_data
);
2348 TimeWindow time_window
=
2349 lttvwindow_get_time_window(control_flow_data
->tab
);
2351 LttTime time_begin
= time_window
.start_time
;
2352 LttTime width
= time_window
.time_width
;
2355 guint64 time_ll
= ltt_time_to_uint64(width
);
2356 time_ll
= time_ll
>> 1; /* divide by two */
2357 half_width
= ltt_time_from_uint64(time_ll
);
2359 LttTime time_end
= ltt_time_add(time_begin
, width
);
2361 LttvTracesetContext
* tsc
=
2362 lttvwindow_get_traceset_context(control_flow_data
->tab
);
2364 LttTime trace_start
= tsc
->time_span
.start_time
;
2365 LttTime trace_end
= tsc
->time_span
.end_time
;
2367 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
2368 current_time
.tv_nsec
);
2372 /* If current time is inside time interval, just move the highlight
2375 /* Else, we have to change the time interval. We have to tell it
2376 * to the main window. */
2377 /* The time interval change will take care of placing the current
2378 * time at the center of the visible area, or nearest possible if we are
2379 * at one end of the trace. */
2382 if(ltt_time_compare(current_time
, time_begin
) < 0)
2384 TimeWindow new_time_window
;
2386 if(ltt_time_compare(current_time
,
2387 ltt_time_add(trace_start
,half_width
)) < 0)
2388 time_begin
= trace_start
;
2390 time_begin
= ltt_time_sub(current_time
,half_width
);
2392 new_time_window
.start_time
= time_begin
;
2393 new_time_window
.time_width
= width
;
2394 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2395 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2397 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2399 else if(ltt_time_compare(current_time
, time_end
) > 0)
2401 TimeWindow new_time_window
;
2403 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
2404 time_begin
= ltt_time_sub(trace_end
,width
);
2406 time_begin
= ltt_time_sub(current_time
,half_width
);
2408 new_time_window
.start_time
= time_begin
;
2409 new_time_window
.time_width
= width
;
2410 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2411 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2413 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2416 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2418 /* Update directly when scrolling */
2419 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2425 typedef struct _ClosureData
{
2426 EventsRequest
*events_request
;
2427 LttvTracesetState
*tss
;
2432 /* Draw line until end of the screen */
2434 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
2436 ResourceInfo
*process_info
= (ResourceInfo
*)key
;
2437 HashedResourceData
*hashed_process_data
= (HashedResourceData
*)value
;
2438 ClosureData
*closure_data
= (ClosureData
*)user_data
;
2440 EventsRequest
*events_request
= closure_data
->events_request
;
2441 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2443 LttvTracesetState
*tss
= closure_data
->tss
;
2444 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)tss
;
2446 LttTime evtime
= closure_data
->end_time
;
2448 gboolean dodraw
= TRUE
;
2451 /* For the process */
2452 /* First, check if the current process is in the state computation
2453 * process list. If it is there, that means we must add it right now and
2454 * draw items from the beginning of the read for it. If it is not
2455 * present, it's a new process and it was not present : it will
2456 * be added after the state update. */
2458 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
2459 #endif //EXTRA_CHECK
2460 LttvTraceContext
*tc
= tsc
->traces
[process_info
->trace_num
];
2461 LttvTraceState
*ts
= (LttvTraceState
*)tc
;
2464 //FIXME : optimize data structures.
2465 LttvTracefileState
*tfs
;
2466 LttvTracefileContext
*tfc
;
2468 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
2469 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
2470 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
2471 && tfs
->cpu
== process_info
->cpu
)
2475 g_assert(i
<tc
->tracefiles
->len
);
2476 tfs
= LTTV_TRACEFILE_STATE(tfc
);
2478 // LttvTracefileState *tfs =
2479 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2480 // tracefiles[process_info->cpu];
2482 // LttvProcessState *process;
2483 // process = lttv_state_find_process(ts, process_info->cpu,
2484 // process_info->pid);
2486 // if(unlikely(process != NULL)) {
2488 // LttvFilter *filter = control_flow_data->filter;
2489 // if(filter != NULL && filter->head != NULL)
2490 // if(!lttv_filter_tree_parse(filter->head,NULL,NULL,
2491 // tc->t,NULL,process,tc))
2494 /* Only draw for processes that are currently in the trace states */
2496 ProcessList
*process_list
= control_flow_data
->process_list
;
2498 /* Should be alike when background info is ready */
2499 if(control_flow_data
->background_info_waiting
==0)
2500 g_assert(ltt_time_compare(process
->creation_time
,
2501 process_info
->birth
) == 0);
2502 #endif //EXTRA_CHECK
2504 /* Now, the process is in the state hash and our own process hash.
2505 * We definitely can draw the items related to the ending state.
2508 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2511 TimeWindow time_window
=
2512 lttvwindow_get_time_window(control_flow_data
->tab
);
2515 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2516 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2518 #endif //EXTRA_CHECK
2519 Drawing_t
*drawing
= control_flow_data
->drawing
;
2520 guint width
= drawing
->width
;
2522 guint x
= closure_data
->x_end
;
2524 DrawContext draw_context
;
2526 /* Now create the drawing context that will be used to draw
2527 * items related to the last state. */
2528 draw_context
.drawable
= hashed_process_data
->pixmap
;
2529 draw_context
.gc
= drawing
->gc
;
2530 draw_context
.pango_layout
= drawing
->pango_layout
;
2531 draw_context
.drawinfo
.end
.x
= x
;
2533 draw_context
.drawinfo
.y
.over
= 1;
2534 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2535 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2537 draw_context
.drawinfo
.start
.offset
.over
= 0;
2538 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2539 draw_context
.drawinfo
.start
.offset
.under
= 0;
2540 draw_context
.drawinfo
.end
.offset
.over
= 0;
2541 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2542 draw_context
.drawinfo
.end
.offset
.under
= 0;
2544 /* Jump over draw if we are at the same x position */
2545 if(x
== hashed_process_data
->x
.over
)
2549 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2551 PropertiesLine prop_line
= prepare_execmode_line(process
);
2552 draw_line((void*)&prop_line
, (void*)&draw_context
);
2554 hashed_process_data
->x
.over
= x
;
2558 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2559 hashed_process_data
->x
.middle_used
)) {
2560 #if 0 /* do not mark closure : not missing information */
2561 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2562 /* Draw collision indicator */
2563 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2564 gdk_draw_point(drawing
->pixmap
,
2568 hashed_process_data
->x
.middle_marked
= TRUE
;
2573 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2576 PropertiesLine prop_line
;
2577 prop_line
.line_width
= STATE_LINE_WIDTH
;
2578 prop_line
.style
= GDK_LINE_SOLID
;
2579 prop_line
.y
= MIDDLE
;
2580 cpu_set_line_color(&prop_line
, &ts
->cpu_states
[process_info
->id
]);
2582 draw_line((void*)&prop_line
, (void*)&draw_context
);
2585 /* become the last x position */
2586 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2587 hashed_process_data
->x
.middle
= x
;
2588 /* but don't use the pixel */
2589 hashed_process_data
->x
.middle_used
= FALSE
;
2591 /* Calculate the next good time */
2592 convert_pixels_to_time(width
, x
+1, time_window
,
2593 &hashed_process_data
->next_good_time
);
2602 int before_chunk(void *hook_data
, void *call_data
)
2604 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2605 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2606 ControlFlowData
*cfd
= (ControlFlowData
*)events_request
->viewer_data
;
2608 /* Desactivate sort */
2609 gtk_tree_sortable_set_sort_column_id(
2610 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2612 GTK_SORT_ASCENDING
);
2614 drawing_chunk_begin(events_request
, tss
);
2619 int before_request(void *hook_data
, void *call_data
)
2621 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2622 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2624 drawing_data_request_begin(events_request
, tss
);
2631 * after request is necessary in addition of after chunk in order to draw
2632 * lines until the end of the screen. after chunk just draws lines until
2639 // TODO pmf: reenable this
2640 int after_request(void *hook_data
, void *call_data
)
2642 // EventsRequest *events_request = (EventsRequest*)hook_data;
2643 // ControlFlowData *control_flow_data = events_request->viewer_data;
2644 // LttvTracesetState *tss = (LttvTracesetState*)call_data;
2646 // ProcessList *process_list = control_flow_data->process_list;
2647 // LttTime end_time = events_request->end_time;
2649 // ClosureData closure_data;
2650 // closure_data.events_request = (EventsRequest*)hook_data;
2651 // closure_data.tss = tss;
2652 // closure_data.end_time = end_time;
2654 // TimeWindow time_window =
2655 // lttvwindow_get_time_window(control_flow_data->tab);
2656 // guint width = control_flow_data->drawing->width;
2657 // convert_time_to_pixels(
2661 // &closure_data.x_end);
2664 // /* Draw last items */
2665 // g_hash_table_foreach(process_list->process_hash, draw_closure,
2666 // (void*)&closure_data);
2669 // /* Request expose */
2670 // drawing_request_expose(events_request, tss, end_time);
2679 int after_chunk(void *hook_data
, void *call_data
)
2681 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2682 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2683 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2684 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)call_data
;
2685 LttvTracefileContext
*tfc
= lttv_traceset_context_get_current_tfc(tsc
);
2688 ProcessList
*process_list
= control_flow_data
->process_list
;
2690 LttvTraceset
*traceset
= tsc
->ts
;
2691 guint nb_trace
= lttv_traceset_number(traceset
);
2693 /* Only execute when called for the first trace's events request */
2694 if(!process_list
->current_hash_data
) return;
2696 for(i
= 0 ; i
< nb_trace
; i
++) {
2697 g_free(process_list
->current_hash_data
[i
]);
2699 g_free(process_list
->current_hash_data
);
2700 process_list
->current_hash_data
= NULL
;
2703 end_time
= LTT_TIME_MIN(tfc
->timestamp
, events_request
->end_time
);
2704 else /* end of traceset, or position now out of request : end */
2705 end_time
= events_request
->end_time
;
2707 ClosureData closure_data
;
2708 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2709 closure_data
.tss
= tss
;
2710 closure_data
.end_time
= end_time
;
2712 TimeWindow time_window
=
2713 lttvwindow_get_time_window(control_flow_data
->tab
);
2714 guint width
= control_flow_data
->drawing
->width
;
2715 convert_time_to_pixels(
2719 &closure_data
.x_end
);
2721 /* Draw last items */
2722 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2723 (void*)&closure_data
);
2725 /* Reactivate sort */
2726 gtk_tree_sortable_set_sort_column_id(
2727 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2728 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2729 GTK_SORT_ASCENDING
);
2731 update_index_to_pixmap(control_flow_data
->process_list
);
2732 /* Request a full expose : drawing scrambled */
2733 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2735 /* Request expose (updates damages zone also) */
2736 drawing_request_expose(events_request
, tss
, end_time
);
2741 /* after_statedump_end
2743 * @param hook_data ControlFlowData structure of the viewer.
2744 * @param call_data Event context.
2746 * This function adds items to be drawn in a queue for each process.
2749 int before_statedump_end(void *hook_data
, void *call_data
)
2751 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2752 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
2753 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2755 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2757 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
2759 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
2761 LttvTracesetState
*tss
= (LttvTracesetState
*)tfc
->t_context
->ts_context
;
2762 ProcessList
*process_list
= control_flow_data
->process_list
;
2765 e
= ltt_tracefile_get_event(tfc
->tf
);
2767 LttvFilter
*filter
= control_flow_data
->filter
;
2768 if(filter
!= NULL
&& filter
->head
!= NULL
)
2769 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2770 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2773 LttTime evtime
= ltt_event_time(e
);
2775 ClosureData closure_data
;
2776 closure_data
.events_request
= events_request
;
2777 closure_data
.tss
= tss
;
2778 closure_data
.end_time
= evtime
;
2780 TimeWindow time_window
=
2781 lttvwindow_get_time_window(control_flow_data
->tab
);
2782 guint width
= control_flow_data
->drawing
->width
;
2783 convert_time_to_pixels(
2787 &closure_data
.x_end
);
2789 /* Draw last items */
2790 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2791 (void*)&closure_data
);
2793 /* Reactivate sort */
2794 gtk_tree_sortable_set_sort_column_id(
2795 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2796 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2797 GTK_SORT_ASCENDING
);
2799 update_index_to_pixmap(control_flow_data
->process_list
);
2800 /* Request a full expose : drawing scrambled */
2801 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2803 /* Request expose (updates damages zone also) */
2804 drawing_request_expose(events_request
, tss
, evtime
);