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 set_line_color_cpu(PropertiesLine
*prop_line
, GQuark present_state
)
322 if(present_state
== LTTV_CPU_IDLE
) {
323 prop_line
->color
= drawing_colors_cpu
[COL_CPU_IDLE
];
325 else if(present_state
== LTTV_CPU_BUSY
) {
326 prop_line
->color
= drawing_colors_cpu
[COL_CPU_BUSY
];
328 else if(present_state
== LTTV_CPU_IRQ
) {
329 prop_line
->color
= drawing_colors_cpu
[COL_CPU_IRQ
];
333 /* before_schedchange_hook
335 * This function basically draw lines and icons. Two types of lines are drawn :
336 * one small (3 pixels?) representing the state of the process and the second
337 * type is thicker (10 pixels?) representing on which CPU a process is running
338 * (and this only in running state).
340 * Extremums of the lines :
341 * x_min : time of the last event context for this process kept in memory.
342 * x_max : time of the current event.
343 * y : middle of the process in the process list. The process is found in the
344 * list, therefore is it's position in pixels.
346 * The choice of lines'color is defined by the context of the last event for this
351 int before_schedchange_hook(void *hook_data
, void *call_data
)
353 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
354 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
355 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
357 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
359 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
360 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
363 e
= ltt_tracefile_get_event(tfc
->tf
);
364 gint target_pid_saved
= tfc
->target_pid
;
366 LttTime evtime
= ltt_event_time(e
);
367 LttvFilter
*filter
= control_flow_data
->filter
;
371 /* we are in a schedchange, before the state update. We must draw the
372 * items corresponding to the state before it changes : now is the right
378 pid_out
= ltt_event_get_long_unsigned(e
, thf
->f1
);
379 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f2
);
380 // if(pid_in != 0 && pid_out != 0) {
381 // /* not a transition to/from idle */
387 tfc
->target_pid
= pid_out
;
388 // if(!filter || !filter->head ||
389 // lttv_filter_tree_parse(filter->head,e,tfc->tf,
390 // tfc->t_context->t,tfc,NULL,NULL)) {
391 /* For the pid_out */
392 /* First, check if the current process is in the state computation
393 * process list. If it is there, that means we must add it right now and
394 * draw items from the beginning of the read for it. If it is not
395 * present, it's a new process and it was not present : it will
396 * be added after the state update. */
397 guint cpu
= tfs
->cpu
;
400 cpustr
= g_strdup_printf("CPU%u", cpu
);
401 cpuq
= g_quark_from_string(cpustr
);
405 guint trace_num
= ts
->parent
.index
;
406 // LttvProcessState *process = ts->running_process[cpu];
407 /* unknown state, bad current pid */
408 // if(process->pid != pid_out)
409 // process = lttv_state_find_process(ts,
410 // tfs->cpu, pid_out);
412 // if(process != NULL) {
413 /* Well, the process_out existed : we must get it in the process hash
414 * or add it, and draw its items.
416 /* Add process to process list (if not present) */
418 HashedResourceData
*hashed_process_data
= NULL
;
419 ProcessList
*process_list
= control_flow_data
->process_list
;
420 // LttTime birth = process->creation_time;
422 hashed_process_data
= processlist_get_process_data(process_list
, cpuq
, trace_num
);
423 // hashed_process_data = processlist_get_process_data(process_list,
428 if(hashed_process_data
== NULL
)
430 // g_assert(pid_out == 0 || pid_out != process->ppid);
431 /* Process not present */
432 ResourceInfo
*process_info
;
433 Drawing_t
*drawing
= control_flow_data
->drawing
;
434 resourcelist_add(process_list
,
437 cpuq
, //process->name,
442 &hashed_process_data
);
443 gtk_widget_set_size_request(drawing
->drawing_area
,
446 gtk_widget_queue_draw(drawing
->drawing_area
);
450 /* Now, the process is in the state hash and our own process hash.
451 * We definitely can draw the items related to the ending state.
454 if(ltt_time_compare(hashed_process_data
->next_good_time
,
457 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
459 TimeWindow time_window
=
460 lttvwindow_get_time_window(control_flow_data
->tab
);
462 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
463 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
466 Drawing_t
*drawing
= control_flow_data
->drawing
;
467 guint width
= drawing
->width
;
469 convert_time_to_pixels(
475 /* Draw collision indicator */
476 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
477 gdk_draw_point(hashed_process_data
->pixmap
,
480 COLLISION_POSITION(hashed_process_data
->height
));
481 hashed_process_data
->x
.middle_marked
= TRUE
;
484 TimeWindow time_window
=
485 lttvwindow_get_time_window(control_flow_data
->tab
);
487 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
488 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
491 Drawing_t
*drawing
= control_flow_data
->drawing
;
492 guint width
= drawing
->width
;
494 convert_time_to_pixels(
501 /* Jump over draw if we are at the same x position */
502 if(x
== hashed_process_data
->x
.middle
&&
503 hashed_process_data
->x
.middle_used
)
505 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
506 /* Draw collision indicator */
507 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
508 gdk_draw_point(hashed_process_data
->pixmap
,
511 COLLISION_POSITION(hashed_process_data
->height
));
512 hashed_process_data
->x
.middle_marked
= TRUE
;
516 DrawContext draw_context
;
518 /* Now create the drawing context that will be used to draw
519 * items related to the last state. */
520 draw_context
.drawable
= hashed_process_data
->pixmap
;
521 draw_context
.gc
= drawing
->gc
;
522 draw_context
.pango_layout
= drawing
->pango_layout
;
523 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
524 draw_context
.drawinfo
.end
.x
= x
;
526 draw_context
.drawinfo
.y
.over
= 1;
527 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
528 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
530 draw_context
.drawinfo
.start
.offset
.over
= 0;
531 draw_context
.drawinfo
.start
.offset
.middle
= 0;
532 draw_context
.drawinfo
.start
.offset
.under
= 0;
533 draw_context
.drawinfo
.end
.offset
.over
= 0;
534 draw_context
.drawinfo
.end
.offset
.middle
= 0;
535 draw_context
.drawinfo
.end
.offset
.under
= 0;
539 //PropertiesLine prop_line = prepare_s_e_line(process);
540 PropertiesLine prop_line
;
541 prop_line
.line_width
= STATE_LINE_WIDTH
;
542 prop_line
.style
= GDK_LINE_SOLID
;
543 prop_line
.y
= MIDDLE
;
544 cpu_set_line_color(&prop_line
, tfs
->cpu_state
->present_state
);
545 draw_line((void*)&prop_line
, (void*)&draw_context
);
548 /* become the last x position */
549 hashed_process_data
->x
.middle
= x
;
550 hashed_process_data
->x
.middle_used
= TRUE
;
551 hashed_process_data
->x
.middle_marked
= FALSE
;
553 /* Calculate the next good time */
554 convert_pixels_to_time(width
, x
+1, time_window
,
555 &hashed_process_data
->next_good_time
);
561 // tfc->target_pid = pid_in;
562 // if(!filter || !filter->head ||
563 // lttv_filter_tree_parse(filter->head,e,tfc->tf,
564 // tfc->t_context->t,tfc,NULL,NULL)) {
565 // /* For the pid_in */
566 // /* First, check if the current process is in the state computation
567 // * process list. If it is there, that means we must add it right now and
568 // * draw items from the beginning of the read for it. If it is not
569 // * present, it's a new process and it was not present : it will
570 // * be added after the state update. */
571 // LttvProcessState *process;
572 // process = lttv_state_find_process(ts,
573 // tfs->cpu, pid_in);
574 // guint trace_num = ts->parent.index;
576 // if(process != NULL) {
577 // /* Well, the process existed : we must get it in the process hash
578 // * or add it, and draw its items.
580 // /* Add process to process list (if not present) */
581 // guint pl_height = 0;
582 // HashedResourceData *hashed_process_data = NULL;
583 // ProcessList *process_list = control_flow_data->process_list;
584 // LttTime birth = process->creation_time;
586 // hashed_process_data = processlist_get_process_data(process_list, cpuq);
587 //// hashed_process_data = processlist_get_process_data(process_list,
592 // if(hashed_process_data == NULL)
594 // g_assert(pid_in == 0 || pid_in != process->ppid);
595 // /* Process not present */
596 // ResourceInfo *process_info;
597 // Drawing_t *drawing = control_flow_data->drawing;
598 // resourcelist_add(process_list,
610 // &hashed_process_data);
611 // gtk_widget_set_size_request(drawing->drawing_area,
614 // gtk_widget_queue_draw(drawing->drawing_area);
617 // //We could set the current process and hash here, but will be done
618 // //by after schedchange hook
620 // /* Now, the process is in the state hash and our own process hash.
621 // * We definitely can draw the items related to the ending state.
624 // if(ltt_time_compare(hashed_process_data->next_good_time,
627 // if(hashed_process_data->x.middle_marked == FALSE) {
629 // TimeWindow time_window =
630 // lttvwindow_get_time_window(control_flow_data->tab);
632 // if(ltt_time_compare(evtime, time_window.start_time) == -1
633 // || ltt_time_compare(evtime, time_window.end_time) == 1)
635 //#endif //EXTRA_CHECK
636 // Drawing_t *drawing = control_flow_data->drawing;
637 // guint width = drawing->width;
639 // convert_time_to_pixels(
645 // /* Draw collision indicator */
646 // gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
647 // gdk_draw_point(hashed_process_data->pixmap,
650 // COLLISION_POSITION(hashed_process_data->height));
651 // hashed_process_data->x.middle_marked = TRUE;
654 // TimeWindow time_window =
655 // lttvwindow_get_time_window(control_flow_data->tab);
657 // if(ltt_time_compare(evtime, time_window.start_time) == -1
658 // || ltt_time_compare(evtime, time_window.end_time) == 1)
660 //#endif //EXTRA_CHECK
661 // Drawing_t *drawing = control_flow_data->drawing;
662 // guint width = drawing->width;
665 // convert_time_to_pixels(
672 // /* Jump over draw if we are at the same x position */
673 // if(x == hashed_process_data->x.middle &&
674 // hashed_process_data->x.middle_used)
676 // if(hashed_process_data->x.middle_marked == FALSE) {
677 // /* Draw collision indicator */
678 // gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
679 // gdk_draw_point(hashed_process_data->pixmap,
682 // COLLISION_POSITION(hashed_process_data->height));
683 // hashed_process_data->x.middle_marked = TRUE;
687 // DrawContext draw_context;
689 // /* Now create the drawing context that will be used to draw
690 // * items related to the last state. */
691 // draw_context.drawable = hashed_process_data->pixmap;
692 // draw_context.gc = drawing->gc;
693 // draw_context.pango_layout = drawing->pango_layout;
694 // draw_context.drawinfo.start.x = hashed_process_data->x.middle;
695 // draw_context.drawinfo.end.x = x;
697 // draw_context.drawinfo.y.over = 1;
698 // draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
699 // draw_context.drawinfo.y.under = hashed_process_data->height;
701 // draw_context.drawinfo.start.offset.over = 0;
702 // draw_context.drawinfo.start.offset.middle = 0;
703 // draw_context.drawinfo.start.offset.under = 0;
704 // draw_context.drawinfo.end.offset.over = 0;
705 // draw_context.drawinfo.end.offset.middle = 0;
706 // draw_context.drawinfo.end.offset.under = 0;
709 // /* Draw the line */
710 // PropertiesLine prop_line = prepare_s_e_line(process);
711 // draw_line((void*)&prop_line, (void*)&draw_context);
715 // /* become the last x position */
716 // hashed_process_data->x.middle = x;
717 // hashed_process_data->x.middle_used = TRUE;
718 // hashed_process_data->x.middle_marked = FALSE;
720 // /* Calculate the next good time */
721 // convert_pixels_to_time(width, x+1, time_window,
722 // &hashed_process_data->next_good_time);
726 // g_warning("Cannot find pin_in in schedchange %u", pid_in);
728 // tfc->target_pid = target_pid_saved;
736 GString
*string
= g_string_new("");;
737 gboolean field_names
= TRUE
, state
= TRUE
;
739 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
740 g_string_append_printf(string
,"\n");
743 g_string_append_printf(string
, " %s",
744 g_quark_to_string(tfs
->process
->state
->s
));
747 g_info("%s",string
->str
);
749 g_string_free(string
, TRUE
);
751 /* End of text dump */
756 /* after_schedchange_hook
758 * The draw after hook is called by the reading API to have a
759 * particular event drawn on the screen.
760 * @param hook_data ControlFlowData structure of the viewer.
761 * @param call_data Event context.
763 * This function adds items to be drawn in a queue for each process.
766 int after_schedchange_hook(void *hook_data
, void *call_data
)
768 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
769 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
770 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
772 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
774 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
776 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
779 e
= ltt_tracefile_get_event(tfc
->tf
);
781 LttvFilter
*filter
= control_flow_data
->filter
;
782 if(filter
!= NULL
&& filter
->head
!= NULL
)
783 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
784 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
787 LttTime evtime
= ltt_event_time(e
);
791 /* Add process to process list (if not present) */
792 LttvProcessState
*process_in
;
795 HashedResourceData
*hashed_process_data_in
= NULL
;
797 ProcessList
*process_list
= control_flow_data
->process_list
;
802 pid_out
= ltt_event_get_long_unsigned(e
, thf
->f1
);
803 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f2
);
807 /* Find process pid_in in the list... */
808 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
809 //process_in = tfs->process;
810 guint cpu
= tfs
->cpu
;
813 cpustr
= g_strdup_printf("CPU%u", cpu
);
814 cpuq
= g_quark_from_string(cpustr
);
817 guint trace_num
= ts
->parent
.index
;
818 process_in
= ts
->running_process
[cpu
];
819 /* It should exist, because we are after the state update. */
821 g_assert(process_in
!= NULL
);
823 birth
= process_in
->creation_time
;
825 hashed_process_data_in
= processlist_get_process_data(process_list
, cpuq
, trace_num
);
826 // hashed_process_data_in = processlist_get_process_data(process_list,
831 if(hashed_process_data_in
== NULL
)
833 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
834 ResourceInfo
*process_info
;
835 Drawing_t
*drawing
= control_flow_data
->drawing
;
836 /* Process not present */
837 resourcelist_add(process_list
,
845 &hashed_process_data_in
);
846 gtk_widget_set_size_request(drawing
->drawing_area
,
849 gtk_widget_queue_draw(drawing
->drawing_area
);
851 /* Set the current process */
852 process_list
->current_hash_data
[trace_num
][process_in
->cpu
] =
853 hashed_process_data_in
;
855 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
858 TimeWindow time_window
=
859 lttvwindow_get_time_window(control_flow_data
->tab
);
862 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
863 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
866 Drawing_t
*drawing
= control_flow_data
->drawing
;
867 guint width
= drawing
->width
;
870 convert_time_to_pixels(
876 if(hashed_process_data_in
->x
.middle
!= new_x
) {
877 hashed_process_data_in
->x
.middle
= new_x
;
878 hashed_process_data_in
->x
.middle_used
= FALSE
;
879 hashed_process_data_in
->x
.middle_marked
= FALSE
;
885 /* before_execmode_hook
887 * This function basically draw lines and icons. Two types of lines are drawn :
888 * one small (3 pixels?) representing the state of the process and the second
889 * type is thicker (10 pixels?) representing on which CPU a process is running
890 * (and this only in running state).
892 * Extremums of the lines :
893 * x_min : time of the last event context for this process kept in memory.
894 * x_max : time of the current event.
895 * y : middle of the process in the process list. The process is found in the
896 * list, therefore is it's position in pixels.
898 * The choice of lines'color is defined by the context of the last event for this
902 int before_execmode_hook(void *hook_data
, void *call_data
)
904 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
905 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
906 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
908 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
910 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
911 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
914 e
= ltt_tracefile_get_event(tfc
->tf
);
916 LttTime evtime
= ltt_event_time(e
);
920 /* we are in a execmode, before the state update. We must draw the
921 * items corresponding to the state before it changes : now is the right
925 //LttvProcessState *process = tfs->process;
926 guint cpu
= tfs
->cpu
;
929 cpustr
= g_strdup_printf("CPU%u", cpu
);
930 cpuq
= g_quark_from_string(cpustr
);
933 guint trace_num
= ts
->parent
.index
;
934 LttvProcessState
*process
= ts
->running_process
[cpu
];
935 g_assert(process
!= NULL
);
937 // guint pid = process->pid;
939 /* Well, the process_out existed : we must get it in the process hash
940 * or add it, and draw its items.
942 /* Add process to process list (if not present) */
944 HashedResourceData
*hashed_process_data
= NULL
;
945 ProcessList
*process_list
= control_flow_data
->process_list
;
946 LttTime birth
= process
->creation_time
;
948 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
949 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
951 hashed_process_data
= processlist_get_process_data(process_list
, cpuq
, trace_num
);
952 // hashed_process_data = processlist_get_process_data(process_list,
957 if(unlikely(hashed_process_data
== NULL
))
959 //g_assert(pid == 0 || pid != process->ppid);
960 ResourceInfo
*process_info
;
961 /* Process not present */
962 Drawing_t
*drawing
= control_flow_data
->drawing
;
963 ressourcelist_add(process_list
,
966 cpuq
, //process->name,
971 &hashed_process_data
);
972 gtk_widget_set_size_request(drawing
->drawing_area
,
975 gtk_widget_queue_draw(drawing
->drawing_area
);
977 /* Set the current process */
978 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
982 /* Now, the process is in the state hash and our own process hash.
983 * We definitely can draw the items related to the ending state.
986 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
989 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
990 TimeWindow time_window
=
991 lttvwindow_get_time_window(control_flow_data
->tab
);
994 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
995 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
998 Drawing_t
*drawing
= control_flow_data
->drawing
;
999 guint width
= drawing
->width
;
1001 convert_time_to_pixels(
1007 /* Draw collision indicator */
1008 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1009 gdk_draw_point(hashed_process_data
->pixmap
,
1012 COLLISION_POSITION(hashed_process_data
->height
));
1013 hashed_process_data
->x
.middle_marked
= TRUE
;
1016 TimeWindow time_window
=
1017 lttvwindow_get_time_window(control_flow_data
->tab
);
1020 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1021 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1023 #endif //EXTRA_CHECK
1024 Drawing_t
*drawing
= control_flow_data
->drawing
;
1025 guint width
= drawing
->width
;
1028 convert_time_to_pixels(
1035 /* Jump over draw if we are at the same x position */
1036 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1037 hashed_process_data
->x
.middle_used
))
1039 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1040 /* Draw collision indicator */
1041 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1042 gdk_draw_point(hashed_process_data
->pixmap
,
1045 COLLISION_POSITION(hashed_process_data
->height
));
1046 hashed_process_data
->x
.middle_marked
= TRUE
;
1051 DrawContext draw_context
;
1052 /* Now create the drawing context that will be used to draw
1053 * items related to the last state. */
1054 draw_context
.drawable
= hashed_process_data
->pixmap
;
1055 draw_context
.gc
= drawing
->gc
;
1056 draw_context
.pango_layout
= drawing
->pango_layout
;
1057 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1058 draw_context
.drawinfo
.end
.x
= x
;
1060 draw_context
.drawinfo
.y
.over
= 1;
1061 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1062 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1064 draw_context
.drawinfo
.start
.offset
.over
= 0;
1065 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1066 draw_context
.drawinfo
.start
.offset
.under
= 0;
1067 draw_context
.drawinfo
.end
.offset
.over
= 0;
1068 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1069 draw_context
.drawinfo
.end
.offset
.under
= 0;
1073 PropertiesLine prop_line
;
1074 cpu_set_line_color(&prop_line
, tfs
->cpu_state
->present_state
);
1075 printf("current state: %s\n", g_quark_to_string(tfs
->cpu_state
->present_state
));
1076 draw_line((void*)&prop_line
, (void*)&draw_context
);
1078 /* become the last x position */
1079 hashed_process_data
->x
.middle
= x
;
1080 hashed_process_data
->x
.middle_used
= TRUE
;
1081 hashed_process_data
->x
.middle_marked
= FALSE
;
1083 /* Calculate the next good time */
1084 convert_pixels_to_time(width
, x
+1, time_window
,
1085 &hashed_process_data
->next_good_time
);
1092 /* before_process_exit_hook
1094 * Draw lines for process event.
1096 * @param hook_data ControlFlowData structure of the viewer.
1097 * @param call_data Event context.
1099 * This function adds items to be drawn in a queue for each process.
1103 //int before_process_exit_hook(void *hook_data, void *call_data)
1105 // LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1106 // EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1108 // ControlFlowData *control_flow_data = events_request->viewer_data;
1110 // LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1112 // LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1114 // LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1117 // e = ltt_tracefile_get_event(tfc->tf);
1119 // LttvFilter *filter = control_flow_data->filter;
1120 // if(filter != NULL && filter->head != NULL)
1121 // if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1122 // tfc->t_context->t,tfc,NULL,NULL))
1125 // LttTime evtime = ltt_event_time(e);
1127 // /* Add process to process list (if not present) */
1128 // //LttvProcessState *process = tfs->process;
1129 // guint cpu = tfs->cpu;
1130 // guint trace_num = ts->parent.index;
1131 // LttvProcessState *process = ts->running_process[cpu];
1132 // guint pid = process->pid;
1134 // guint pl_height = 0;
1135 // HashedResourceData *hashed_process_data = NULL;
1137 // ProcessList *process_list = control_flow_data->process_list;
1139 // g_assert(process != NULL);
1141 // birth = process->creation_time;
1143 // if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1144 // hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1146 // hashed_process_data = processlist_get_process_data(process_list, "CPU0");
1147 //// hashed_process_data = processlist_get_process_data(process_list,
1152 // if(unlikely(hashed_process_data == NULL))
1154 // g_assert(pid == 0 || pid != process->ppid);
1155 // /* Process not present */
1156 // Drawing_t *drawing = control_flow_data->drawing;
1157 // ResourceInfo *process_info;
1158 // processlist_add(process_list,
1170 // &hashed_process_data);
1171 // gtk_widget_set_size_request(drawing->drawing_area,
1174 // gtk_widget_queue_draw(drawing->drawing_area);
1178 // /* Now, the process is in the state hash and our own process hash.
1179 // * We definitely can draw the items related to the ending state.
1182 // if(likely(ltt_time_compare(hashed_process_data->next_good_time,
1185 // if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1186 // TimeWindow time_window =
1187 // lttvwindow_get_time_window(control_flow_data->tab);
1189 //#ifdef EXTRA_CHECK
1190 // if(ltt_time_compare(evtime, time_window.start_time) == -1
1191 // || ltt_time_compare(evtime, time_window.end_time) == 1)
1193 //#endif //EXTRA_CHECK
1194 // Drawing_t *drawing = control_flow_data->drawing;
1195 // guint width = drawing->width;
1197 // convert_time_to_pixels(
1203 // /* Draw collision indicator */
1204 // gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1205 // gdk_draw_point(hashed_process_data->pixmap,
1208 // COLLISION_POSITION(hashed_process_data->height));
1209 // hashed_process_data->x.middle_marked = TRUE;
1212 // TimeWindow time_window =
1213 // lttvwindow_get_time_window(control_flow_data->tab);
1215 //#ifdef EXTRA_CHECK
1216 // if(ltt_time_compare(evtime, time_window.start_time) == -1
1217 // || ltt_time_compare(evtime, time_window.end_time) == 1)
1219 //#endif //EXTRA_CHECK
1220 // Drawing_t *drawing = control_flow_data->drawing;
1221 // guint width = drawing->width;
1224 // convert_time_to_pixels(
1231 // /* Jump over draw if we are at the same x position */
1232 // if(unlikely(x == hashed_process_data->x.middle &&
1233 // hashed_process_data->x.middle_used))
1235 // if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1236 // /* Draw collision indicator */
1237 // gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1238 // gdk_draw_point(hashed_process_data->pixmap,
1241 // COLLISION_POSITION(hashed_process_data->height));
1242 // hashed_process_data->x.middle_marked = TRUE;
1246 // DrawContext draw_context;
1248 // /* Now create the drawing context that will be used to draw
1249 // * items related to the last state. */
1250 // draw_context.drawable = hashed_process_data->pixmap;
1251 // draw_context.gc = drawing->gc;
1252 // draw_context.pango_layout = drawing->pango_layout;
1253 // draw_context.drawinfo.start.x = hashed_process_data->x.middle;
1254 // draw_context.drawinfo.end.x = x;
1256 // draw_context.drawinfo.y.over = 1;
1257 // draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
1258 // draw_context.drawinfo.y.under = hashed_process_data->height;
1260 // draw_context.drawinfo.start.offset.over = 0;
1261 // draw_context.drawinfo.start.offset.middle = 0;
1262 // draw_context.drawinfo.start.offset.under = 0;
1263 // draw_context.drawinfo.end.offset.over = 0;
1264 // draw_context.drawinfo.end.offset.middle = 0;
1265 // draw_context.drawinfo.end.offset.under = 0;
1268 // /* Draw the line */
1269 // PropertiesLine prop_line = prepare_s_e_line(process);
1270 // draw_line((void*)&prop_line, (void*)&draw_context);
1273 // /* become the last x position */
1274 // hashed_process_data->x.middle = x;
1275 // hashed_process_data->x.middle_used = TRUE;
1276 // hashed_process_data->x.middle_marked = FALSE;
1278 // /* Calculate the next good time */
1279 // convert_pixels_to_time(width, x+1, time_window,
1280 // &hashed_process_data->next_good_time);
1289 /* before_process_release_hook
1291 * Draw lines for process event.
1293 * @param hook_data ControlFlowData structure of the viewer.
1294 * @param call_data Event context.
1296 * This function adds items to be drawn in a queue for each process.
1300 //int before_process_release_hook(void *hook_data, void *call_data)
1302 // LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1303 // EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1305 // ControlFlowData *control_flow_data = events_request->viewer_data;
1307 // LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1309 // LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1311 // LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1314 // e = ltt_tracefile_get_event(tfc->tf);
1316 // LttvFilter *filter = control_flow_data->filter;
1317 // if(filter != NULL && filter->head != NULL)
1318 // if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1319 // tfc->t_context->t,tfc,NULL,NULL))
1322 // LttTime evtime = ltt_event_time(e);
1324 // guint trace_num = ts->parent.index;
1328 // pid = ltt_event_get_long_unsigned(e, thf->f1);
1331 // /* Add process to process list (if not present) */
1332 // /* Don't care about the process if it's not in the state hash already :
1333 // * that means a process that has never done anything in the trace and
1334 // * unknown suddently gets destroyed : no state meaningful to show. */
1335 // LttvProcessState *process = lttv_state_find_process(ts, ANY_CPU, pid);
1337 // if(process != NULL) {
1339 // guint pl_height = 0;
1340 // HashedResourceData *hashed_process_data = NULL;
1342 // ProcessList *process_list = control_flow_data->process_list;
1344 // birth = process->creation_time;
1346 // /* Cannot use current process : this event happens on another process,
1347 // * action done by the parent. */
1348 // hashed_process_data = processlist_get_process_data(process_list, "CPU0");
1349 //// hashed_process_data = processlist_get_process_data(process_list,
1354 // if(unlikely(hashed_process_data == NULL))
1356 // g_assert(pid == 0 || pid != process->ppid);
1357 // /* Process not present */
1358 // Drawing_t *drawing = control_flow_data->drawing;
1359 // ResourceInfo *process_info;
1360 // processlist_add(process_list,
1372 // &hashed_process_data);
1373 // gtk_widget_set_size_request(drawing->drawing_area,
1376 // gtk_widget_queue_draw(drawing->drawing_area);
1379 // /* Now, the process is in the state hash and our own process hash.
1380 // * We definitely can draw the items related to the ending state.
1383 // if(likely(ltt_time_compare(hashed_process_data->next_good_time,
1386 // if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1387 // TimeWindow time_window =
1388 // lttvwindow_get_time_window(control_flow_data->tab);
1390 //#ifdef EXTRA_CHECK
1391 // if(ltt_time_compare(evtime, time_window.start_time) == -1
1392 // || ltt_time_compare(evtime, time_window.end_time) == 1)
1394 //#endif //EXTRA_CHECK
1395 // Drawing_t *drawing = control_flow_data->drawing;
1396 // guint width = drawing->width;
1398 // convert_time_to_pixels(
1404 // /* Draw collision indicator */
1405 // gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1406 // gdk_draw_point(hashed_process_data->pixmap,
1409 // COLLISION_POSITION(hashed_process_data->height));
1410 // hashed_process_data->x.middle_marked = TRUE;
1413 // TimeWindow time_window =
1414 // lttvwindow_get_time_window(control_flow_data->tab);
1416 //#ifdef EXTRA_CHECK
1417 // if(ltt_time_compare(evtime, time_window.start_time) == -1
1418 // || ltt_time_compare(evtime, time_window.end_time) == 1)
1420 //#endif //EXTRA_CHECK
1421 // Drawing_t *drawing = control_flow_data->drawing;
1422 // guint width = drawing->width;
1425 // convert_time_to_pixels(
1432 // /* Jump over draw if we are at the same x position */
1433 // if(unlikely(x == hashed_process_data->x.middle &&
1434 // hashed_process_data->x.middle_used))
1436 // if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1437 // /* Draw collision indicator */
1438 // gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1439 // gdk_draw_point(hashed_process_data->pixmap,
1442 // COLLISION_POSITION(hashed_process_data->height));
1443 // hashed_process_data->x.middle_marked = TRUE;
1447 // DrawContext draw_context;
1449 // /* Now create the drawing context that will be used to draw
1450 // * items related to the last state. */
1451 // draw_context.drawable = hashed_process_data->pixmap;
1452 // draw_context.gc = drawing->gc;
1453 // draw_context.pango_layout = drawing->pango_layout;
1454 // draw_context.drawinfo.start.x = hashed_process_data->x.middle;
1455 // draw_context.drawinfo.end.x = x;
1457 // draw_context.drawinfo.y.over = 1;
1458 // draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
1459 // draw_context.drawinfo.y.under = hashed_process_data->height;
1461 // draw_context.drawinfo.start.offset.over = 0;
1462 // draw_context.drawinfo.start.offset.middle = 0;
1463 // draw_context.drawinfo.start.offset.under = 0;
1464 // draw_context.drawinfo.end.offset.over = 0;
1465 // draw_context.drawinfo.end.offset.middle = 0;
1466 // draw_context.drawinfo.end.offset.under = 0;
1469 // /* Draw the line */
1470 // PropertiesLine prop_line = prepare_s_e_line(process);
1471 // draw_line((void*)&prop_line, (void*)&draw_context);
1474 // /* become the last x position */
1475 // hashed_process_data->x.middle = x;
1476 // hashed_process_data->x.middle_used = TRUE;
1477 // hashed_process_data->x.middle_marked = FALSE;
1479 // /* Calculate the next good time */
1480 // convert_pixels_to_time(width, x+1, time_window,
1481 // &hashed_process_data->next_good_time);
1489 /* after_process_fork_hook
1491 * Create the processlist entry for the child process. Put the last
1492 * position in x at the current time value.
1494 * @param hook_data ControlFlowData structure of the viewer.
1495 * @param call_data Event context.
1497 * This function adds items to be drawn in a queue for each process.
1500 //int after_process_fork_hook(void *hook_data, void *call_data)
1502 // LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1503 // EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1504 // ControlFlowData *control_flow_data = events_request->viewer_data;
1506 // LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1508 // LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1510 // LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1513 // e = ltt_tracefile_get_event(tfc->tf);
1515 // LttvFilter *filter = control_flow_data->filter;
1516 // if(filter != NULL && filter->head != NULL)
1517 // if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1518 // tfc->t_context->t,tfc,NULL,NULL))
1521 // LttTime evtime = ltt_event_time(e);
1525 // child_pid = ltt_event_get_long_unsigned(e, thf->f2);
1528 // /* Add process to process list (if not present) */
1529 // LttvProcessState *process_child;
1531 // guint pl_height = 0;
1532 // HashedResourceData *hashed_process_data_child = NULL;
1534 // ProcessList *process_list = control_flow_data->process_list;
1536 // /* Find child in the list... */
1537 // process_child = lttv_state_find_process(ts, ANY_CPU, child_pid);
1538 // /* It should exist, because we are after the state update. */
1539 // g_assert(process_child != NULL);
1541 // birth = process_child->creation_time;
1542 // guint trace_num = ts->parent.index;
1544 // /* Cannot use current process, because this action is done by the parent
1545 // * on its child. */
1546 // hashed_process_data_child = processlist_get_process_data(process_list, "CPU0");
1547 //// hashed_process_data_child = processlist_get_process_data(process_list,
1549 //// process_child->cpu,
1552 // if(likely(hashed_process_data_child == NULL))
1554 // g_assert(child_pid == 0 || child_pid != process_child->ppid);
1555 // /* Process not present */
1556 // Drawing_t *drawing = control_flow_data->drawing;
1557 // ResourceInfo *process_info;
1558 // processlist_add(process_list,
1561 // process_child->tgid,
1562 // process_child->cpu,
1563 // process_child->ppid,
1566 // process_child->name,
1567 // process_child->brand,
1570 // &hashed_process_data_child);
1571 // gtk_widget_set_size_request(drawing->drawing_area,
1574 // gtk_widget_queue_draw(drawing->drawing_area);
1576 // processlist_set_ppid(process_list, process_child->ppid,
1577 // hashed_process_data_child);
1578 // processlist_set_tgid(process_list, process_child->tgid,
1579 // hashed_process_data_child);
1583 // if(likely(ltt_time_compare(hashed_process_data_child->next_good_time,
1586 // TimeWindow time_window =
1587 // lttvwindow_get_time_window(control_flow_data->tab);
1589 //#ifdef EXTRA_CHECK
1590 // if(ltt_time_compare(evtime, time_window.start_time) == -1
1591 // || ltt_time_compare(evtime, time_window.end_time) == 1)
1593 //#endif //EXTRA_CHECK
1594 // Drawing_t *drawing = control_flow_data->drawing;
1595 // guint width = drawing->width;
1597 // convert_time_to_pixels(
1603 // if(likely(hashed_process_data_child->x.over != new_x)) {
1604 // hashed_process_data_child->x.over = new_x;
1605 // hashed_process_data_child->x.over_used = FALSE;
1606 // hashed_process_data_child->x.over_marked = FALSE;
1608 // if(likely(hashed_process_data_child->x.middle != new_x)) {
1609 // hashed_process_data_child->x.middle = new_x;
1610 // hashed_process_data_child->x.middle_used = FALSE;
1611 // hashed_process_data_child->x.middle_marked = FALSE;
1613 // if(likely(hashed_process_data_child->x.under != new_x)) {
1614 // hashed_process_data_child->x.under = new_x;
1615 // hashed_process_data_child->x.under_used = FALSE;
1616 // hashed_process_data_child->x.under_marked = FALSE;
1624 /* after_process_exit_hook
1626 * Create the processlist entry for the child process. Put the last
1627 * position in x at the current time value.
1629 * @param hook_data ControlFlowData structure of the viewer.
1630 * @param call_data Event context.
1632 * This function adds items to be drawn in a queue for each process.
1635 //int after_process_exit_hook(void *hook_data, void *call_data)
1637 // LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1638 // EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1639 // ControlFlowData *control_flow_data = events_request->viewer_data;
1641 // LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1643 // LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1645 // LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1648 // e = ltt_tracefile_get_event(tfc->tf);
1650 // LttvFilter *filter = control_flow_data->filter;
1651 // if(filter != NULL && filter->head != NULL)
1652 // if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1653 // tfc->t_context->t,tfc,NULL,NULL))
1656 // LttTime evtime = ltt_event_time(e);
1658 // /* Add process to process list (if not present) */
1659 // //LttvProcessState *process = tfs->process;
1660 // guint cpu = tfs->cpu;
1661 // guint trace_num = ts->parent.index;
1662 // LttvProcessState *process = ts->running_process[cpu];
1664 // /* It should exist, because we are after the state update. */
1665 // g_assert(process != NULL);
1667 // guint pid = process->pid;
1669 // guint pl_height = 0;
1670 // HashedResourceData *hashed_process_data = NULL;
1672 // ProcessList *process_list = control_flow_data->process_list;
1674 // birth = process->creation_time;
1676 // if(likely(process_list->current_hash_data[trace_num][cpu] != NULL) ){
1677 // hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1679 // hashed_process_data = processlist_get_process_data(process_list, "CPU0");
1680 //// hashed_process_data = processlist_get_process_data(process_list,
1685 // if(unlikely(hashed_process_data == NULL))
1687 // g_assert(pid == 0 || pid != process->ppid);
1688 // /* Process not present */
1689 // Drawing_t *drawing = control_flow_data->drawing;
1690 // ResourceInfo *process_info;
1691 // processlist_add(process_list,
1703 // &hashed_process_data);
1704 // gtk_widget_set_size_request(drawing->drawing_area,
1707 // gtk_widget_queue_draw(drawing->drawing_area);
1710 // /* Set the current process */
1711 // process_list->current_hash_data[trace_num][process->cpu] =
1712 // hashed_process_data;
1715 // if(unlikely(ltt_time_compare(hashed_process_data->next_good_time,
1718 // TimeWindow time_window =
1719 // lttvwindow_get_time_window(control_flow_data->tab);
1721 //#ifdef EXTRA_CHECK
1722 // if(ltt_time_compare(evtime, time_window.start_time) == -1
1723 // || ltt_time_compare(evtime, time_window.end_time) == 1)
1725 //#endif //EXTRA_CHECK
1726 // Drawing_t *drawing = control_flow_data->drawing;
1727 // guint width = drawing->width;
1729 // convert_time_to_pixels(
1734 // if(unlikely(hashed_process_data->x.middle != new_x)) {
1735 // hashed_process_data->x.middle = new_x;
1736 // hashed_process_data->x.middle_used = FALSE;
1737 // hashed_process_data->x.middle_marked = FALSE;
1745 /* Get the filename of the process to print */
1746 //int after_fs_exec_hook(void *hook_data, void *call_data)
1748 // LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1749 // EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1750 // ControlFlowData *control_flow_data = events_request->viewer_data;
1752 // LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1754 // LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1756 // LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1759 // e = ltt_tracefile_get_event(tfc->tf);
1761 // LttvFilter *filter = control_flow_data->filter;
1762 // if(filter != NULL && filter->head != NULL)
1763 // if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1764 // tfc->t_context->t,tfc,NULL,NULL))
1767 // guint cpu = tfs->cpu;
1768 // guint trace_num = ts->parent.index;
1769 // LttvProcessState *process = ts->running_process[cpu];
1770 // g_assert(process != NULL);
1772 // guint pid = process->pid;
1774 // /* Well, the process_out existed : we must get it in the process hash
1775 // * or add it, and draw its items.
1777 // /* Add process to process list (if not present) */
1778 // guint pl_height = 0;
1779 // HashedResourceData *hashed_process_data = NULL;
1780 // ProcessList *process_list = control_flow_data->process_list;
1781 // LttTime birth = process->creation_time;
1783 // if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1784 // hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1786 // hashed_process_data = processlist_get_process_data(process_list, "CPU0");
1787 //// hashed_process_data = processlist_get_process_data(process_list,
1792 // if(unlikely(hashed_process_data == NULL))
1794 // g_assert(pid == 0 || pid != process->ppid);
1795 // ResourceInfo *process_info;
1796 // /* Process not present */
1797 // Drawing_t *drawing = control_flow_data->drawing;
1798 // processlist_add(process_list,
1810 // &hashed_process_data);
1811 // gtk_widget_set_size_request(drawing->drawing_area,
1814 // gtk_widget_queue_draw(drawing->drawing_area);
1816 // /* Set the current process */
1817 // process_list->current_hash_data[trace_num][process->cpu] =
1818 // hashed_process_data;
1821 // processlist_set_name(process_list, process->name, hashed_process_data);
1827 /* Get the filename of the process to print */
1828 //int after_user_generic_thread_brand_hook(void *hook_data, void *call_data)
1830 // LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1831 // EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1832 // ControlFlowData *control_flow_data = events_request->viewer_data;
1834 // LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1836 // LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1838 // LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1841 // e = ltt_tracefile_get_event(tfc->tf);
1843 // LttvFilter *filter = control_flow_data->filter;
1844 // if(filter != NULL && filter->head != NULL)
1845 // if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1846 // tfc->t_context->t,tfc,NULL,NULL))
1849 // guint cpu = tfs->cpu;
1850 // guint trace_num = ts->parent.index;
1851 // LttvProcessState *process = ts->running_process[cpu];
1852 // g_assert(process != NULL);
1854 // guint pid = process->pid;
1856 // /* Well, the process_out existed : we must get it in the process hash
1857 // * or add it, and draw its items.
1859 // /* Add process to process list (if not present) */
1860 // guint pl_height = 0;
1861 // HashedResourceData *hashed_process_data = NULL;
1862 // ProcessList *process_list = control_flow_data->process_list;
1863 // LttTime birth = process->creation_time;
1865 // if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1866 // hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1868 // hashed_process_data = processlist_get_process_data(process_list, "CPU0");
1869 //// hashed_process_data = processlist_get_process_data(process_list,
1874 // if(unlikely(hashed_process_data == NULL))
1876 // g_assert(pid == 0 || pid != process->ppid);
1877 // ResourceInfo *process_info;
1878 // /* Process not present */
1879 // Drawing_t *drawing = control_flow_data->drawing;
1880 // processlist_add(process_list,
1892 // &hashed_process_data);
1893 // gtk_widget_set_size_request(drawing->drawing_area,
1896 // gtk_widget_queue_draw(drawing->drawing_area);
1898 // /* Set the current process */
1899 // process_list->current_hash_data[trace_num][process->cpu] =
1900 // hashed_process_data;
1903 // processlist_set_brand(process_list, process->brand, hashed_process_data);
1910 /* after_event_enum_process_hook
1912 * Create the processlist entry for the child process. Put the last
1913 * position in x at the current time value.
1915 * @param hook_data ControlFlowData structure of the viewer.
1916 * @param call_data Event context.
1918 * This function adds items to be drawn in a queue for each process.
1921 //int after_event_enum_process_hook(void *hook_data, void *call_data)
1923 // LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data;
1924 // EventsRequest *events_request = (EventsRequest*)thf->hook_data;
1925 // ControlFlowData *control_flow_data = events_request->viewer_data;
1927 // LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1929 // LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1931 // LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1933 // guint first_cpu, nb_cpus, cpu;
1936 // e = ltt_tracefile_get_event(tfc->tf);
1938 // LttvFilter *filter = control_flow_data->filter;
1939 // if(filter != NULL && filter->head != NULL)
1940 // if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1941 // tfc->t_context->t,tfc,NULL,NULL))
1944 // LttTime evtime = ltt_event_time(e);
1946 // /* Add process to process list (if not present) */
1947 // LttvProcessState *process_in;
1949 // guint pl_height = 0;
1950 // HashedResourceData *hashed_process_data_in = NULL;
1952 // ProcessList *process_list = control_flow_data->process_list;
1953 // guint trace_num = ts->parent.index;
1957 // pid_in = ltt_event_get_long_unsigned(e, thf->f1);
1960 // if(pid_in == 0) {
1962 // nb_cpus = ltt_trace_get_num_cpu(ts->parent.t);
1964 // first_cpu = ANY_CPU;
1965 // nb_cpus = ANY_CPU+1;
1968 // for(cpu = first_cpu; cpu < nb_cpus; cpu++) {
1969 // /* Find process pid_in in the list... */
1970 // process_in = lttv_state_find_process(ts, cpu, pid_in);
1971 // //process_in = tfs->process;
1972 // //guint cpu = tfs->cpu;
1973 // //guint trace_num = ts->parent.index;
1974 // //process_in = ts->running_process[cpu];
1975 // /* It should exist, because we are after the state update. */
1976 // #ifdef EXTRA_CHECK
1977 // //g_assert(process_in != NULL);
1978 // #endif //EXTRA_CHECK
1979 // birth = process_in->creation_time;
1981 // hashed_process_data_in = processlist_get_process_data(process_list, "CPU0");
1982 //// hashed_process_data_in = processlist_get_process_data(process_list,
1984 //// process_in->cpu,
1987 // if(hashed_process_data_in == NULL)
1989 // if(pid_in != 0 && pid_in == process_in->ppid)
1990 // g_critical("TEST %u , %u", pid_in, process_in->ppid);
1991 // g_assert(pid_in == 0 || pid_in != process_in->ppid);
1992 // ResourceInfo *process_info;
1993 // Drawing_t *drawing = control_flow_data->drawing;
1994 // /* Process not present */
1995 // processlist_add(process_list,
1998 // process_in->tgid,
2000 // process_in->ppid,
2003 // process_in->name,
2004 // process_in->brand,
2007 // &hashed_process_data_in);
2008 // gtk_widget_set_size_request(drawing->drawing_area,
2011 // gtk_widget_queue_draw(drawing->drawing_area);
2013 // processlist_set_name(process_list, process_in->name,
2014 // hashed_process_data_in);
2015 // processlist_set_ppid(process_list, process_in->ppid,
2016 // hashed_process_data_in);
2017 // processlist_set_tgid(process_list, process_in->tgid,
2018 // hashed_process_data_in);
2025 gint
update_time_window_hook(void *hook_data
, void *call_data
)
2027 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2028 Drawing_t
*drawing
= control_flow_data
->drawing
;
2029 ProcessList
*process_list
= control_flow_data
->process_list
;
2031 const TimeWindowNotifyData
*time_window_nofify_data
=
2032 ((const TimeWindowNotifyData
*)call_data
);
2034 TimeWindow
*old_time_window
=
2035 time_window_nofify_data
->old_time_window
;
2036 TimeWindow
*new_time_window
=
2037 time_window_nofify_data
->new_time_window
;
2039 /* Update the ruler */
2040 drawing_update_ruler(control_flow_data
->drawing
,
2044 /* Two cases : zoom in/out or scrolling */
2046 /* In order to make sure we can reuse the old drawing, the scale must
2047 * be the same and the new time interval being partly located in the
2048 * currently shown time interval. (reuse is only for scrolling)
2051 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
2052 old_time_window
->start_time
.tv_sec
,
2053 old_time_window
->start_time
.tv_nsec
,
2054 old_time_window
->time_width
.tv_sec
,
2055 old_time_window
->time_width
.tv_nsec
);
2057 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
2058 new_time_window
->start_time
.tv_sec
,
2059 new_time_window
->start_time
.tv_nsec
,
2060 new_time_window
->time_width
.tv_sec
,
2061 new_time_window
->time_width
.tv_nsec
);
2063 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
2064 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
2066 /* Same scale (scrolling) */
2067 g_info("scrolling");
2068 LttTime
*ns
= &new_time_window
->start_time
;
2069 LttTime
*nw
= &new_time_window
->time_width
;
2070 LttTime
*os
= &old_time_window
->start_time
;
2071 LttTime
*ow
= &old_time_window
->time_width
;
2072 LttTime old_end
= old_time_window
->end_time
;
2073 LttTime new_end
= new_time_window
->end_time
;
2075 //if(ns<os+w && os+w<ns+w)
2076 //if(ns<old_end && os<ns)
2077 if(ltt_time_compare(*ns
, old_end
) == -1
2078 && ltt_time_compare(*os
, *ns
) == -1)
2080 g_info("scrolling near right");
2081 /* Scroll right, keep right part of the screen */
2083 guint width
= control_flow_data
->drawing
->width
;
2084 convert_time_to_pixels(
2090 /* Copy old data to new location */
2091 copy_pixmap_region(process_list
,
2093 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2097 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
2099 if(drawing
->damage_begin
== drawing
->damage_end
)
2100 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
2102 drawing
->damage_begin
= 0;
2104 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2106 /* Clear the data request background, but not SAFETY */
2107 rectangle_pixmap(process_list
,
2108 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2110 drawing
->damage_begin
+SAFETY
, 0,
2111 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2113 gtk_widget_queue_draw(drawing
->drawing_area
);
2114 //gtk_widget_queue_draw_area (drawing->drawing_area,
2116 // control_flow_data->drawing->width,
2117 // control_flow_data->drawing->height);
2119 /* Get new data for the rest. */
2120 drawing_data_request(control_flow_data
->drawing
,
2121 drawing
->damage_begin
, 0,
2122 drawing
->damage_end
- drawing
->damage_begin
,
2123 control_flow_data
->drawing
->height
);
2126 //if(ns<os && os<ns+w)
2127 //if(ns<os && os<new_end)
2128 if(ltt_time_compare(*ns
,*os
) == -1
2129 && ltt_time_compare(*os
,new_end
) == -1)
2131 g_info("scrolling near left");
2132 /* Scroll left, keep left part of the screen */
2134 guint width
= control_flow_data
->drawing
->width
;
2135 convert_time_to_pixels(
2141 /* Copy old data to new location */
2142 copy_pixmap_region (process_list
,
2144 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2150 if(drawing
->damage_begin
== drawing
->damage_end
)
2151 drawing
->damage_end
= x
;
2153 drawing
->damage_end
=
2154 control_flow_data
->drawing
->width
;
2156 drawing
->damage_begin
= 0;
2158 rectangle_pixmap (process_list
,
2159 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2161 drawing
->damage_begin
, 0,
2162 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
2165 gtk_widget_queue_draw(drawing
->drawing_area
);
2166 //gtk_widget_queue_draw_area (drawing->drawing_area,
2168 // control_flow_data->drawing->width,
2169 // control_flow_data->drawing->height);
2172 /* Get new data for the rest. */
2173 drawing_data_request(control_flow_data
->drawing
,
2174 drawing
->damage_begin
, 0,
2175 drawing
->damage_end
- drawing
->damage_begin
,
2176 control_flow_data
->drawing
->height
);
2179 if(ltt_time_compare(*ns
,*os
) == 0)
2181 g_info("not scrolling");
2183 g_info("scrolling far");
2184 /* Cannot reuse any part of the screen : far jump */
2187 rectangle_pixmap (process_list
,
2188 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2191 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2194 //gtk_widget_queue_draw_area (drawing->drawing_area,
2196 // control_flow_data->drawing->width,
2197 // control_flow_data->drawing->height);
2198 gtk_widget_queue_draw(drawing
->drawing_area
);
2200 drawing
->damage_begin
= 0;
2201 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2203 drawing_data_request(control_flow_data
->drawing
,
2205 control_flow_data
->drawing
->width
,
2206 control_flow_data
->drawing
->height
);
2212 /* Different scale (zoom) */
2215 rectangle_pixmap (process_list
,
2216 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
2219 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
2222 //gtk_widget_queue_draw_area (drawing->drawing_area,
2224 // control_flow_data->drawing->width,
2225 // control_flow_data->drawing->height);
2226 gtk_widget_queue_draw(drawing
->drawing_area
);
2228 drawing
->damage_begin
= 0;
2229 drawing
->damage_end
= control_flow_data
->drawing
->width
;
2231 drawing_data_request(control_flow_data
->drawing
,
2233 control_flow_data
->drawing
->width
,
2234 control_flow_data
->drawing
->height
);
2237 /* Update directly when scrolling */
2238 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2244 gint
traceset_notify(void *hook_data
, void *call_data
)
2246 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2247 Drawing_t
*drawing
= control_flow_data
->drawing
;
2249 if(unlikely(drawing
->gc
== NULL
)) {
2252 if(drawing
->dotted_gc
== NULL
) {
2256 drawing_clear(control_flow_data
->drawing
);
2257 processlist_clear(control_flow_data
->process_list
);
2258 gtk_widget_set_size_request(
2259 control_flow_data
->drawing
->drawing_area
,
2260 -1, processlist_get_height(control_flow_data
->process_list
));
2261 redraw_notify(control_flow_data
, NULL
);
2263 request_background_data(control_flow_data
);
2268 gint
redraw_notify(void *hook_data
, void *call_data
)
2270 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2271 Drawing_t
*drawing
= control_flow_data
->drawing
;
2272 GtkWidget
*widget
= drawing
->drawing_area
;
2274 drawing
->damage_begin
= 0;
2275 drawing
->damage_end
= drawing
->width
;
2277 /* fun feature, to be separated someday... */
2278 drawing_clear(control_flow_data
->drawing
);
2279 processlist_clear(control_flow_data
->process_list
);
2280 gtk_widget_set_size_request(
2281 control_flow_data
->drawing
->drawing_area
,
2282 -1, processlist_get_height(control_flow_data
->process_list
));
2284 rectangle_pixmap (control_flow_data
->process_list
,
2285 widget
->style
->black_gc
,
2288 drawing
->alloc_width
,
2291 gtk_widget_queue_draw(drawing
->drawing_area
);
2293 if(drawing
->damage_begin
< drawing
->damage_end
)
2295 drawing_data_request(drawing
,
2296 drawing
->damage_begin
,
2298 drawing
->damage_end
-drawing
->damage_begin
,
2302 //gtk_widget_queue_draw_area(drawing->drawing_area,
2305 // drawing->height);
2311 gint
continue_notify(void *hook_data
, void *call_data
)
2313 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
2314 Drawing_t
*drawing
= control_flow_data
->drawing
;
2316 //g_assert(widget->allocation.width == drawing->damage_end);
2318 if(drawing
->damage_begin
< drawing
->damage_end
)
2320 drawing_data_request(drawing
,
2321 drawing
->damage_begin
,
2323 drawing
->damage_end
-drawing
->damage_begin
,
2331 gint
update_current_time_hook(void *hook_data
, void *call_data
)
2333 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
2334 Drawing_t
*drawing
= control_flow_data
->drawing
;
2336 LttTime current_time
= *((LttTime
*)call_data
);
2338 TimeWindow time_window
=
2339 lttvwindow_get_time_window(control_flow_data
->tab
);
2341 LttTime time_begin
= time_window
.start_time
;
2342 LttTime width
= time_window
.time_width
;
2345 guint64 time_ll
= ltt_time_to_uint64(width
);
2346 time_ll
= time_ll
>> 1; /* divide by two */
2347 half_width
= ltt_time_from_uint64(time_ll
);
2349 LttTime time_end
= ltt_time_add(time_begin
, width
);
2351 LttvTracesetContext
* tsc
=
2352 lttvwindow_get_traceset_context(control_flow_data
->tab
);
2354 LttTime trace_start
= tsc
->time_span
.start_time
;
2355 LttTime trace_end
= tsc
->time_span
.end_time
;
2357 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
2358 current_time
.tv_nsec
);
2362 /* If current time is inside time interval, just move the highlight
2365 /* Else, we have to change the time interval. We have to tell it
2366 * to the main window. */
2367 /* The time interval change will take care of placing the current
2368 * time at the center of the visible area, or nearest possible if we are
2369 * at one end of the trace. */
2372 if(ltt_time_compare(current_time
, time_begin
) < 0)
2374 TimeWindow new_time_window
;
2376 if(ltt_time_compare(current_time
,
2377 ltt_time_add(trace_start
,half_width
)) < 0)
2378 time_begin
= trace_start
;
2380 time_begin
= ltt_time_sub(current_time
,half_width
);
2382 new_time_window
.start_time
= time_begin
;
2383 new_time_window
.time_width
= width
;
2384 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2385 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2387 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2389 else if(ltt_time_compare(current_time
, time_end
) > 0)
2391 TimeWindow new_time_window
;
2393 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
2394 time_begin
= ltt_time_sub(trace_end
,width
);
2396 time_begin
= ltt_time_sub(current_time
,half_width
);
2398 new_time_window
.start_time
= time_begin
;
2399 new_time_window
.time_width
= width
;
2400 new_time_window
.time_width_double
= ltt_time_to_double(width
);
2401 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
2403 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
2406 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2408 /* Update directly when scrolling */
2409 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
2415 typedef struct _ClosureData
{
2416 EventsRequest
*events_request
;
2417 LttvTracesetState
*tss
;
2422 /* Draw line until end of the screen */
2424 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
2426 ResourceInfo
*process_info
= (ResourceInfo
*)key
;
2427 HashedResourceData
*hashed_process_data
= (HashedResourceData
*)value
;
2428 ClosureData
*closure_data
= (ClosureData
*)user_data
;
2430 EventsRequest
*events_request
= closure_data
->events_request
;
2431 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2433 LttvTracesetState
*tss
= closure_data
->tss
;
2434 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)tss
;
2436 LttTime evtime
= closure_data
->end_time
;
2438 gboolean dodraw
= TRUE
;
2441 /* For the process */
2442 /* First, check if the current process is in the state computation
2443 * process list. If it is there, that means we must add it right now and
2444 * draw items from the beginning of the read for it. If it is not
2445 * present, it's a new process and it was not present : it will
2446 * be added after the state update. */
2448 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
2449 #endif //EXTRA_CHECK
2450 LttvTraceContext
*tc
= tsc
->traces
[process_info
->trace_num
];
2451 LttvTraceState
*ts
= (LttvTraceState
*)tc
;
2454 //FIXME : optimize data structures.
2455 LttvTracefileState
*tfs
;
2456 LttvTracefileContext
*tfc
;
2458 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
2459 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
2460 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
2461 && tfs
->cpu
== process_info
->cpu
)
2465 g_assert(i
<tc
->tracefiles
->len
);
2466 tfs
= LTTV_TRACEFILE_STATE(tfc
);
2468 // LttvTracefileState *tfs =
2469 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2470 // tracefiles[process_info->cpu];
2472 // LttvProcessState *process;
2473 // process = lttv_state_find_process(ts, process_info->cpu,
2474 // process_info->pid);
2476 // if(unlikely(process != NULL)) {
2478 // LttvFilter *filter = control_flow_data->filter;
2479 // if(filter != NULL && filter->head != NULL)
2480 // if(!lttv_filter_tree_parse(filter->head,NULL,NULL,
2481 // tc->t,NULL,process,tc))
2484 /* Only draw for processes that are currently in the trace states */
2486 ProcessList
*process_list
= control_flow_data
->process_list
;
2488 /* Should be alike when background info is ready */
2489 if(control_flow_data
->background_info_waiting
==0)
2490 g_assert(ltt_time_compare(process
->creation_time
,
2491 process_info
->birth
) == 0);
2492 #endif //EXTRA_CHECK
2494 /* Now, the process is in the state hash and our own process hash.
2495 * We definitely can draw the items related to the ending state.
2498 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2501 TimeWindow time_window
=
2502 lttvwindow_get_time_window(control_flow_data
->tab
);
2505 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2506 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2508 #endif //EXTRA_CHECK
2509 Drawing_t
*drawing
= control_flow_data
->drawing
;
2510 guint width
= drawing
->width
;
2512 guint x
= closure_data
->x_end
;
2514 DrawContext draw_context
;
2516 /* Now create the drawing context that will be used to draw
2517 * items related to the last state. */
2518 draw_context
.drawable
= hashed_process_data
->pixmap
;
2519 draw_context
.gc
= drawing
->gc
;
2520 draw_context
.pango_layout
= drawing
->pango_layout
;
2521 draw_context
.drawinfo
.end
.x
= x
;
2523 draw_context
.drawinfo
.y
.over
= 1;
2524 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2525 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2527 draw_context
.drawinfo
.start
.offset
.over
= 0;
2528 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2529 draw_context
.drawinfo
.start
.offset
.under
= 0;
2530 draw_context
.drawinfo
.end
.offset
.over
= 0;
2531 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2532 draw_context
.drawinfo
.end
.offset
.under
= 0;
2534 /* Jump over draw if we are at the same x position */
2535 if(x
== hashed_process_data
->x
.over
)
2539 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2541 PropertiesLine prop_line
= prepare_execmode_line(process
);
2542 draw_line((void*)&prop_line
, (void*)&draw_context
);
2544 hashed_process_data
->x
.over
= x
;
2548 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2549 hashed_process_data
->x
.middle_used
)) {
2550 #if 0 /* do not mark closure : not missing information */
2551 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2552 /* Draw collision indicator */
2553 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2554 gdk_draw_point(drawing
->pixmap
,
2558 hashed_process_data
->x
.middle_marked
= TRUE
;
2563 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2566 PropertiesLine prop_line
;
2567 prop_line
.line_width
= STATE_LINE_WIDTH
;
2568 prop_line
.style
= GDK_LINE_SOLID
;
2569 prop_line
.y
= MIDDLE
;
2570 cpu_set_line_color(&prop_line
, ts
->cpu_states
[process_info
->id
].present_state
);
2572 draw_line((void*)&prop_line
, (void*)&draw_context
);
2575 /* become the last x position */
2576 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2577 hashed_process_data
->x
.middle
= x
;
2578 /* but don't use the pixel */
2579 hashed_process_data
->x
.middle_used
= FALSE
;
2581 /* Calculate the next good time */
2582 convert_pixels_to_time(width
, x
+1, time_window
,
2583 &hashed_process_data
->next_good_time
);
2592 int before_chunk(void *hook_data
, void *call_data
)
2594 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2595 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2596 ControlFlowData
*cfd
= (ControlFlowData
*)events_request
->viewer_data
;
2598 /* Desactivate sort */
2599 gtk_tree_sortable_set_sort_column_id(
2600 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2602 GTK_SORT_ASCENDING
);
2604 drawing_chunk_begin(events_request
, tss
);
2609 int before_request(void *hook_data
, void *call_data
)
2611 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2612 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2614 drawing_data_request_begin(events_request
, tss
);
2621 * after request is necessary in addition of after chunk in order to draw
2622 * lines until the end of the screen. after chunk just draws lines until
2629 // TODO pmf: reenable this
2630 int after_request(void *hook_data
, void *call_data
)
2632 // EventsRequest *events_request = (EventsRequest*)hook_data;
2633 // ControlFlowData *control_flow_data = events_request->viewer_data;
2634 // LttvTracesetState *tss = (LttvTracesetState*)call_data;
2636 // ProcessList *process_list = control_flow_data->process_list;
2637 // LttTime end_time = events_request->end_time;
2639 // ClosureData closure_data;
2640 // closure_data.events_request = (EventsRequest*)hook_data;
2641 // closure_data.tss = tss;
2642 // closure_data.end_time = end_time;
2644 // TimeWindow time_window =
2645 // lttvwindow_get_time_window(control_flow_data->tab);
2646 // guint width = control_flow_data->drawing->width;
2647 // convert_time_to_pixels(
2651 // &closure_data.x_end);
2654 // /* Draw last items */
2655 // g_hash_table_foreach(process_list->process_hash, draw_closure,
2656 // (void*)&closure_data);
2659 // /* Request expose */
2660 // drawing_request_expose(events_request, tss, end_time);
2669 int after_chunk(void *hook_data
, void *call_data
)
2671 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2672 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2673 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2674 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)call_data
;
2675 LttvTracefileContext
*tfc
= lttv_traceset_context_get_current_tfc(tsc
);
2678 ProcessList
*process_list
= control_flow_data
->process_list
;
2680 LttvTraceset
*traceset
= tsc
->ts
;
2681 guint nb_trace
= lttv_traceset_number(traceset
);
2683 /* Only execute when called for the first trace's events request */
2684 if(!process_list
->current_hash_data
) return;
2686 for(i
= 0 ; i
< nb_trace
; i
++) {
2687 g_free(process_list
->current_hash_data
[i
]);
2689 g_free(process_list
->current_hash_data
);
2690 process_list
->current_hash_data
= NULL
;
2693 end_time
= LTT_TIME_MIN(tfc
->timestamp
, events_request
->end_time
);
2694 else /* end of traceset, or position now out of request : end */
2695 end_time
= events_request
->end_time
;
2697 ClosureData closure_data
;
2698 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2699 closure_data
.tss
= tss
;
2700 closure_data
.end_time
= end_time
;
2702 TimeWindow time_window
=
2703 lttvwindow_get_time_window(control_flow_data
->tab
);
2704 guint width
= control_flow_data
->drawing
->width
;
2705 convert_time_to_pixels(
2709 &closure_data
.x_end
);
2711 /* Draw last items */
2712 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2713 (void*)&closure_data
);
2715 /* Reactivate sort */
2716 gtk_tree_sortable_set_sort_column_id(
2717 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2718 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2719 GTK_SORT_ASCENDING
);
2721 update_index_to_pixmap(control_flow_data
->process_list
);
2722 /* Request a full expose : drawing scrambled */
2723 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2725 /* Request expose (updates damages zone also) */
2726 drawing_request_expose(events_request
, tss
, end_time
);
2731 /* after_statedump_end
2733 * @param hook_data ControlFlowData structure of the viewer.
2734 * @param call_data Event context.
2736 * This function adds items to be drawn in a queue for each process.
2739 int before_statedump_end(void *hook_data
, void *call_data
)
2741 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2742 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
2743 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2745 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2747 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
2749 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
2751 LttvTracesetState
*tss
= (LttvTracesetState
*)tfc
->t_context
->ts_context
;
2752 ProcessList
*process_list
= control_flow_data
->process_list
;
2755 e
= ltt_tracefile_get_event(tfc
->tf
);
2757 LttvFilter
*filter
= control_flow_data
->filter
;
2758 if(filter
!= NULL
&& filter
->head
!= NULL
)
2759 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2760 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2763 LttTime evtime
= ltt_event_time(e
);
2765 ClosureData closure_data
;
2766 closure_data
.events_request
= events_request
;
2767 closure_data
.tss
= tss
;
2768 closure_data
.end_time
= evtime
;
2770 TimeWindow time_window
=
2771 lttvwindow_get_time_window(control_flow_data
->tab
);
2772 guint width
= control_flow_data
->drawing
->width
;
2773 convert_time_to_pixels(
2777 &closure_data
.x_end
);
2779 /* Draw last items */
2780 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2781 (void*)&closure_data
);
2783 /* Reactivate sort */
2784 gtk_tree_sortable_set_sort_column_id(
2785 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2786 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2787 GTK_SORT_ASCENDING
);
2789 update_index_to_pixmap(control_flow_data
->process_list
);
2790 /* Request a full expose : drawing scrambled */
2791 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2793 /* Request expose (updates damages zone also) */
2794 drawing_request_expose(events_request
, tss
, evtime
);