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_IDLE
) {
325 prop_line
->color
= drawing_colors_cpu
[COL_CPU_IDLE
];
327 else if(present_state
== LTTV_CPU_BUSY
) {
328 prop_line
->color
= drawing_colors_cpu
[COL_CPU_BUSY
];
330 else if(present_state
== LTTV_CPU_IRQ
) {
331 prop_line
->color
= drawing_colors_cpu
[COL_CPU_IRQ
];
333 else if(present_state
== LTTV_CPU_TRAP
) {
334 prop_line
->color
= drawing_colors_cpu
[COL_CPU_TRAP
];
336 prop_line
->color
= drawing_colors_cpu
[COL_CPU_UNKNOWN
];
340 static void irq_set_line_color(PropertiesLine
*prop_line
, LttvIRQState
*s
)
342 GQuark present_state
= ((GQuark
*)s
->mode_stack
->data
)[s
->mode_stack
->len
-1];
344 if(present_state
== LTTV_IRQ_UNKNOWN
) {
345 prop_line
->color
= drawing_colors_irq
[COL_IRQ_UNKNOWN
];
347 else if(present_state
== LTTV_IRQ_IDLE
) {
348 prop_line
->color
= drawing_colors_irq
[COL_IRQ_IDLE
];
350 else if(present_state
== LTTV_IRQ_BUSY
) {
351 prop_line
->color
= drawing_colors_irq
[COL_IRQ_BUSY
];
355 static void bdev_set_line_color(PropertiesLine
*prop_line
, LttvBdevState
*s
)
357 GQuark present_state
= ((GQuark
*)s
->mode_stack
->data
)[s
->mode_stack
->len
-1];
359 if(present_state
== LTTV_BDEV_UNKNOWN
) {
360 prop_line
->color
= drawing_colors_bdev
[COL_BDEV_UNKNOWN
];
362 else if(present_state
== LTTV_BDEV_IDLE
) {
363 prop_line
->color
= drawing_colors_bdev
[COL_BDEV_IDLE
];
365 else if(present_state
== LTTV_BDEV_BUSY_READING
) {
366 prop_line
->color
= drawing_colors_bdev
[COL_BDEV_BUSY_READING
];
368 else if(present_state
== LTTV_BDEV_BUSY_WRITING
) {
369 prop_line
->color
= drawing_colors_bdev
[COL_BDEV_BUSY_WRITING
];
373 /* before_schedchange_hook
375 * This function basically draw lines and icons. Two types of lines are drawn :
376 * one small (3 pixels?) representing the state of the process and the second
377 * type is thicker (10 pixels?) representing on which CPU a process is running
378 * (and this only in running state).
380 * Extremums of the lines :
381 * x_min : time of the last event context for this process kept in memory.
382 * x_max : time of the current event.
383 * y : middle of the process in the process list. The process is found in the
384 * list, therefore is it's position in pixels.
386 * The choice of lines'color is defined by the context of the last event for this
391 int before_schedchange_hook(void *hook_data
, void *call_data
)
393 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
394 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
395 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
397 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
399 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
400 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
403 e
= ltt_tracefile_get_event(tfc
->tf
);
404 gint target_pid_saved
= tfc
->target_pid
;
406 LttTime evtime
= ltt_event_time(e
);
407 LttvFilter
*filter
= control_flow_data
->filter
;
411 /* we are in a schedchange, before the state update. We must draw the
412 * items corresponding to the state before it changes : now is the right
418 pid_out
= ltt_event_get_long_unsigned(e
, thf
->f1
);
419 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f2
);
420 // if(pid_in != 0 && pid_out != 0) {
421 // /* not a transition to/from idle */
425 tfc
->target_pid
= pid_out
;
426 // if(!filter || !filter->head ||
427 // lttv_filter_tree_parse(filter->head,e,tfc->tf,
428 // tfc->t_context->t,tfc,NULL,NULL)) {
429 /* For the pid_out */
430 /* First, check if the current process is in the state computation
431 * process list. If it is there, that means we must add it right now and
432 * draw items from the beginning of the read for it. If it is not
433 * present, it's a new process and it was not present : it will
434 * be added after the state update. */
435 guint cpu
= tfs
->cpu
;
438 cpustr
= g_strdup_printf("CPU%u", cpu
);
439 cpuq
= g_quark_from_string(cpustr
);
443 guint trace_num
= ts
->parent
.index
;
444 // LttvProcessState *process = ts->running_process[cpu];
445 /* unknown state, bad current pid */
446 // if(process->pid != pid_out)
447 // process = lttv_state_find_process(ts,
448 // tfs->cpu, pid_out);
450 // if(process != NULL) {
451 /* Well, the process_out existed : we must get it in the process hash
452 * or add it, and draw its items.
454 /* Add process to process list (if not present) */
456 HashedResourceData
*hashed_process_data
= NULL
;
457 ProcessList
*process_list
= control_flow_data
->process_list
;
458 // LttTime birth = process->creation_time;
460 hashed_process_data
= processlist_get_process_data(process_list
, cpuq
, trace_num
);
461 // hashed_process_data = processlist_get_process_data(process_list,
466 if(hashed_process_data
== NULL
)
468 // g_assert(pid_out == 0 || pid_out != process->ppid);
469 /* Process not present */
470 ResourceInfo
*process_info
;
471 Drawing_t
*drawing
= control_flow_data
->drawing
;
472 resourcelist_add(process_list
,
475 cpuq
, //process->name,
480 &hashed_process_data
);
481 gtk_widget_set_size_request(drawing
->drawing_area
,
484 gtk_widget_queue_draw(drawing
->drawing_area
);
488 /* Now, the process is in the state hash and our own process hash.
489 * We definitely can draw the items related to the ending state.
492 if(ltt_time_compare(hashed_process_data
->next_good_time
,
495 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
497 TimeWindow time_window
=
498 lttvwindow_get_time_window(control_flow_data
->tab
);
500 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
501 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
504 Drawing_t
*drawing
= control_flow_data
->drawing
;
505 guint width
= drawing
->width
;
507 convert_time_to_pixels(
513 /* Draw collision indicator */
514 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
515 gdk_draw_point(hashed_process_data
->pixmap
,
518 COLLISION_POSITION(hashed_process_data
->height
));
519 hashed_process_data
->x
.middle_marked
= TRUE
;
522 TimeWindow time_window
=
523 lttvwindow_get_time_window(control_flow_data
->tab
);
525 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
526 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
529 Drawing_t
*drawing
= control_flow_data
->drawing
;
530 guint width
= drawing
->width
;
532 convert_time_to_pixels(
539 /* Jump over draw if we are at the same x position */
540 if(x
== hashed_process_data
->x
.middle
&&
541 hashed_process_data
->x
.middle_used
)
543 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
544 /* Draw collision indicator */
545 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
546 gdk_draw_point(hashed_process_data
->pixmap
,
549 COLLISION_POSITION(hashed_process_data
->height
));
550 hashed_process_data
->x
.middle_marked
= TRUE
;
554 DrawContext draw_context
;
556 /* Now create the drawing context that will be used to draw
557 * items related to the last state. */
558 draw_context
.drawable
= hashed_process_data
->pixmap
;
559 draw_context
.gc
= drawing
->gc
;
560 draw_context
.pango_layout
= drawing
->pango_layout
;
561 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
562 draw_context
.drawinfo
.end
.x
= x
;
564 draw_context
.drawinfo
.y
.over
= 1;
565 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
566 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
568 draw_context
.drawinfo
.start
.offset
.over
= 0;
569 draw_context
.drawinfo
.start
.offset
.middle
= 0;
570 draw_context
.drawinfo
.start
.offset
.under
= 0;
571 draw_context
.drawinfo
.end
.offset
.over
= 0;
572 draw_context
.drawinfo
.end
.offset
.middle
= 0;
573 draw_context
.drawinfo
.end
.offset
.under
= 0;
577 //PropertiesLine prop_line = prepare_s_e_line(process);
578 PropertiesLine prop_line
;
579 prop_line
.line_width
= STATE_LINE_WIDTH
;
580 prop_line
.style
= GDK_LINE_SOLID
;
581 prop_line
.y
= MIDDLE
;
582 cpu_set_line_color(&prop_line
, tfs
->cpu_state
);
583 draw_line((void*)&prop_line
, (void*)&draw_context
);
586 /* become the last x position */
587 hashed_process_data
->x
.middle
= x
;
588 hashed_process_data
->x
.middle_used
= TRUE
;
589 hashed_process_data
->x
.middle_marked
= FALSE
;
591 /* Calculate the next good time */
592 convert_pixels_to_time(width
, x
+1, time_window
,
593 &hashed_process_data
->next_good_time
);
599 // tfc->target_pid = pid_in;
600 // if(!filter || !filter->head ||
601 // lttv_filter_tree_parse(filter->head,e,tfc->tf,
602 // tfc->t_context->t,tfc,NULL,NULL)) {
603 // /* For the pid_in */
604 // /* First, check if the current process is in the state computation
605 // * process list. If it is there, that means we must add it right now and
606 // * draw items from the beginning of the read for it. If it is not
607 // * present, it's a new process and it was not present : it will
608 // * be added after the state update. */
609 // LttvProcessState *process;
610 // process = lttv_state_find_process(ts,
611 // tfs->cpu, pid_in);
612 // guint trace_num = ts->parent.index;
614 // if(process != NULL) {
615 // /* Well, the process existed : we must get it in the process hash
616 // * or add it, and draw its items.
618 // /* Add process to process list (if not present) */
619 // guint pl_height = 0;
620 // HashedResourceData *hashed_process_data = NULL;
621 // ProcessList *process_list = control_flow_data->process_list;
622 // LttTime birth = process->creation_time;
624 // hashed_process_data = processlist_get_process_data(process_list, cpuq);
625 //// hashed_process_data = processlist_get_process_data(process_list,
630 // if(hashed_process_data == NULL)
632 // g_assert(pid_in == 0 || pid_in != process->ppid);
633 // /* Process not present */
634 // ResourceInfo *process_info;
635 // Drawing_t *drawing = control_flow_data->drawing;
636 // resourcelist_add(process_list,
648 // &hashed_process_data);
649 // gtk_widget_set_size_request(drawing->drawing_area,
652 // gtk_widget_queue_draw(drawing->drawing_area);
655 // //We could set the current process and hash here, but will be done
656 // //by after schedchange hook
658 // /* Now, the process is in the state hash and our own process hash.
659 // * We definitely can draw the items related to the ending state.
662 // if(ltt_time_compare(hashed_process_data->next_good_time,
665 // if(hashed_process_data->x.middle_marked == FALSE) {
667 // TimeWindow time_window =
668 // lttvwindow_get_time_window(control_flow_data->tab);
670 // if(ltt_time_compare(evtime, time_window.start_time) == -1
671 // || ltt_time_compare(evtime, time_window.end_time) == 1)
673 //#endif //EXTRA_CHECK
674 // Drawing_t *drawing = control_flow_data->drawing;
675 // guint width = drawing->width;
677 // convert_time_to_pixels(
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;
692 // TimeWindow time_window =
693 // lttvwindow_get_time_window(control_flow_data->tab);
695 // if(ltt_time_compare(evtime, time_window.start_time) == -1
696 // || ltt_time_compare(evtime, time_window.end_time) == 1)
698 //#endif //EXTRA_CHECK
699 // Drawing_t *drawing = control_flow_data->drawing;
700 // guint width = drawing->width;
703 // convert_time_to_pixels(
710 // /* Jump over draw if we are at the same x position */
711 // if(x == hashed_process_data->x.middle &&
712 // hashed_process_data->x.middle_used)
714 // if(hashed_process_data->x.middle_marked == FALSE) {
715 // /* Draw collision indicator */
716 // gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
717 // gdk_draw_point(hashed_process_data->pixmap,
720 // COLLISION_POSITION(hashed_process_data->height));
721 // hashed_process_data->x.middle_marked = TRUE;
725 // DrawContext draw_context;
727 // /* Now create the drawing context that will be used to draw
728 // * items related to the last state. */
729 // draw_context.drawable = hashed_process_data->pixmap;
730 // draw_context.gc = drawing->gc;
731 // draw_context.pango_layout = drawing->pango_layout;
732 // draw_context.drawinfo.start.x = hashed_process_data->x.middle;
733 // draw_context.drawinfo.end.x = x;
735 // draw_context.drawinfo.y.over = 1;
736 // draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
737 // draw_context.drawinfo.y.under = hashed_process_data->height;
739 // draw_context.drawinfo.start.offset.over = 0;
740 // draw_context.drawinfo.start.offset.middle = 0;
741 // draw_context.drawinfo.start.offset.under = 0;
742 // draw_context.drawinfo.end.offset.over = 0;
743 // draw_context.drawinfo.end.offset.middle = 0;
744 // draw_context.drawinfo.end.offset.under = 0;
747 // /* Draw the line */
748 // PropertiesLine prop_line = prepare_s_e_line(process);
749 // draw_line((void*)&prop_line, (void*)&draw_context);
753 // /* become the last x position */
754 // hashed_process_data->x.middle = x;
755 // hashed_process_data->x.middle_used = TRUE;
756 // hashed_process_data->x.middle_marked = FALSE;
758 // /* Calculate the next good time */
759 // convert_pixels_to_time(width, x+1, time_window,
760 // &hashed_process_data->next_good_time);
764 // g_warning("Cannot find pin_in in schedchange %u", pid_in);
766 // tfc->target_pid = target_pid_saved;
774 GString
*string
= g_string_new("");;
775 gboolean field_names
= TRUE
, state
= TRUE
;
777 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
778 g_string_append_printf(string
,"\n");
781 g_string_append_printf(string
, " %s",
782 g_quark_to_string(tfs
->process
->state
->s
));
785 g_info("%s",string
->str
);
787 g_string_free(string
, TRUE
);
789 /* End of text dump */
794 /* after_schedchange_hook
796 * The draw after hook is called by the reading API to have a
797 * particular event drawn on the screen.
798 * @param hook_data ControlFlowData structure of the viewer.
799 * @param call_data Event context.
801 * This function adds items to be drawn in a queue for each process.
804 int after_schedchange_hook(void *hook_data
, void *call_data
)
806 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
807 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
808 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
810 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
812 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
814 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
817 e
= ltt_tracefile_get_event(tfc
->tf
);
819 LttvFilter
*filter
= control_flow_data
->filter
;
820 if(filter
!= NULL
&& filter
->head
!= NULL
)
821 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
822 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
825 LttTime evtime
= ltt_event_time(e
);
829 /* Add process to process list (if not present) */
830 LttvProcessState
*process_in
;
833 HashedResourceData
*hashed_process_data_in
= NULL
;
835 ProcessList
*process_list
= control_flow_data
->process_list
;
840 pid_out
= ltt_event_get_long_unsigned(e
, thf
->f1
);
841 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f2
);
845 /* Find process pid_in in the list... */
846 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
847 //process_in = tfs->process;
848 guint cpu
= tfs
->cpu
;
851 cpustr
= g_strdup_printf("CPU%u", cpu
);
852 cpuq
= g_quark_from_string(cpustr
);
855 guint trace_num
= ts
->parent
.index
;
856 process_in
= ts
->running_process
[cpu
];
857 /* It should exist, because we are after the state update. */
859 g_assert(process_in
!= NULL
);
861 birth
= process_in
->creation_time
;
863 hashed_process_data_in
= processlist_get_process_data(process_list
, cpuq
, trace_num
);
864 // hashed_process_data_in = processlist_get_process_data(process_list,
869 if(hashed_process_data_in
== NULL
)
871 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
872 ResourceInfo
*process_info
;
873 Drawing_t
*drawing
= control_flow_data
->drawing
;
874 /* Process not present */
875 resourcelist_add(process_list
,
883 &hashed_process_data_in
);
884 gtk_widget_set_size_request(drawing
->drawing_area
,
887 gtk_widget_queue_draw(drawing
->drawing_area
);
889 /* Set the current process */
890 process_list
->current_hash_data
[trace_num
][process_in
->cpu
] =
891 hashed_process_data_in
;
893 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
896 TimeWindow time_window
=
897 lttvwindow_get_time_window(control_flow_data
->tab
);
900 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
901 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
904 Drawing_t
*drawing
= control_flow_data
->drawing
;
905 guint width
= drawing
->width
;
908 convert_time_to_pixels(
914 if(hashed_process_data_in
->x
.middle
!= new_x
) {
915 hashed_process_data_in
->x
.middle
= new_x
;
916 hashed_process_data_in
->x
.middle_used
= FALSE
;
917 hashed_process_data_in
->x
.middle_marked
= FALSE
;
923 /* before_execmode_hook
925 * This function basically draw lines and icons. Two types of lines are drawn :
926 * one small (3 pixels?) representing the state of the process and the second
927 * type is thicker (10 pixels?) representing on which CPU a process is running
928 * (and this only in running state).
930 * Extremums of the lines :
931 * x_min : time of the last event context for this process kept in memory.
932 * x_max : time of the current event.
933 * y : middle of the process in the process list. The process is found in the
934 * list, therefore is it's position in pixels.
936 * The choice of lines'color is defined by the context of the last event for this
940 int before_execmode_hook(void *hook_data
, void *call_data
)
942 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
943 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
944 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
946 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
948 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
949 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
952 e
= ltt_tracefile_get_event(tfc
->tf
);
954 LttTime evtime
= ltt_event_time(e
);
958 before_execmode_hook_irq(hook_data
, call_data
);
960 /* we are in a execmode, before the state update. We must draw the
961 * items corresponding to the state before it changes : now is the right
965 //LttvProcessState *process = tfs->process;
966 guint cpu
= tfs
->cpu
;
969 cpustr
= g_strdup_printf("CPU%u", cpu
);
970 cpuq
= g_quark_from_string(cpustr
);
973 guint trace_num
= ts
->parent
.index
;
974 LttvProcessState
*process
= ts
->running_process
[cpu
];
975 g_assert(process
!= NULL
);
977 // guint pid = process->pid;
979 /* Well, the process_out existed : we must get it in the process hash
980 * or add it, and draw its items.
982 /* Add process to process list (if not present) */
984 HashedResourceData
*hashed_process_data
= NULL
;
985 ProcessList
*process_list
= control_flow_data
->process_list
;
986 LttTime birth
= process
->creation_time
;
988 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
989 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
991 hashed_process_data
= processlist_get_process_data(process_list
, cpuq
, trace_num
);
992 // hashed_process_data = processlist_get_process_data(process_list,
997 if(unlikely(hashed_process_data
== NULL
))
999 //g_assert(pid == 0 || pid != process->ppid);
1000 ResourceInfo
*process_info
;
1001 /* Process not present */
1002 Drawing_t
*drawing
= control_flow_data
->drawing
;
1003 resourcelist_add(process_list
,
1006 cpuq
, //process->name,
1011 &hashed_process_data
);
1012 gtk_widget_set_size_request(drawing
->drawing_area
,
1015 gtk_widget_queue_draw(drawing
->drawing_area
);
1017 /* Set the current process */
1018 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1019 hashed_process_data
;
1022 /* Now, the process is in the state hash and our own process hash.
1023 * We definitely can draw the items related to the ending state.
1026 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1029 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1030 TimeWindow time_window
=
1031 lttvwindow_get_time_window(control_flow_data
->tab
);
1034 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1035 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1037 #endif //EXTRA_CHECK
1038 Drawing_t
*drawing
= control_flow_data
->drawing
;
1039 guint width
= drawing
->width
;
1041 convert_time_to_pixels(
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
;
1057 TimeWindow time_window
=
1058 lttvwindow_get_time_window(control_flow_data
->tab
);
1061 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1062 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1064 #endif //EXTRA_CHECK
1065 Drawing_t
*drawing
= control_flow_data
->drawing
;
1066 guint width
= drawing
->width
;
1069 convert_time_to_pixels(
1076 /* Jump over draw if we are at the same x position */
1077 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1078 hashed_process_data
->x
.middle_used
))
1080 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1081 /* Draw collision indicator */
1082 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1083 gdk_draw_point(hashed_process_data
->pixmap
,
1086 COLLISION_POSITION(hashed_process_data
->height
));
1087 hashed_process_data
->x
.middle_marked
= TRUE
;
1093 DrawContext draw_context
;
1094 /* Now create the drawing context that will be used to draw
1095 * items related to the last state. */
1096 draw_context
.drawable
= hashed_process_data
->pixmap
;
1097 draw_context
.gc
= drawing
->gc
;
1098 draw_context
.pango_layout
= drawing
->pango_layout
;
1099 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1100 draw_context
.drawinfo
.end
.x
= x
;
1102 draw_context
.drawinfo
.y
.over
= 1;
1103 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1104 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1106 draw_context
.drawinfo
.start
.offset
.over
= 0;
1107 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1108 draw_context
.drawinfo
.start
.offset
.under
= 0;
1109 draw_context
.drawinfo
.end
.offset
.over
= 0;
1110 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1111 draw_context
.drawinfo
.end
.offset
.under
= 0;
1115 PropertiesLine prop_line
;
1116 prop_line
.line_width
= STATE_LINE_WIDTH
;
1117 prop_line
.style
= GDK_LINE_SOLID
;
1118 prop_line
.y
= MIDDLE
;
1119 cpu_set_line_color(&prop_line
, tfs
->cpu_state
);
1120 draw_line((void*)&prop_line
, (void*)&draw_context
);
1122 /* become the last x position */
1123 hashed_process_data
->x
.middle
= x
;
1124 hashed_process_data
->x
.middle_used
= TRUE
;
1125 hashed_process_data
->x
.middle_marked
= FALSE
;
1127 /* Calculate the next good time */
1128 convert_pixels_to_time(width
, x
+1, time_window
,
1129 &hashed_process_data
->next_good_time
);
1136 int before_execmode_hook_irq(void *hook_data
, void *call_data
)
1138 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1139 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1140 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1142 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1144 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1145 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1148 e
= ltt_tracefile_get_event(tfc
->tf
);
1150 LttTime evtime
= ltt_event_time(e
);
1154 /* we are in a execmode, before the state update. We must draw the
1155 * items corresponding to the state before it changes : now is the right
1161 guint cpu
= tfs
->cpu
;
1163 LttFacility
*ev_facility
= ltt_event_facility(e
);
1164 if(ltt_facility_name(ev_facility
) != LTT_FACILITY_KERNEL
)
1166 guint8 ev_id_entry
= ltt_eventtype_id(ltt_facility_eventtype_get_by_name(ev_facility
, LTT_EVENT_IRQ_ENTRY
));
1167 guint8 ev_id_exit
= ltt_eventtype_id(ltt_facility_eventtype_get_by_name(ev_facility
, LTT_EVENT_IRQ_EXIT
));
1168 if(ltt_facility_name(ev_facility
) == LTT_FACILITY_KERNEL
&&
1169 ev_id_entry
== ltt_event_eventtype_id(e
)) {
1170 irq
= ltt_event_get_long_unsigned(e
, thf
->f1
);
1172 else if(ltt_facility_name(ev_facility
) == LTT_FACILITY_KERNEL
&&
1173 ev_id_exit
== ltt_event_eventtype_id(e
)) {
1174 irq
= ts
->cpu_states
[cpu
].last_irq
;
1182 irqstr
= g_strdup_printf("IRQ %u", irq
);
1183 resourceq
= g_quark_from_string(irqstr
);
1186 guint trace_num
= ts
->parent
.index
;
1188 // guint pid = process->pid;
1190 /* Well, the process_out existed : we must get it in the process hash
1191 * or add it, and draw its items.
1193 /* Add process to process list (if not present) */
1194 guint pl_height
= 0;
1195 HashedResourceData
*hashed_process_data
= NULL
;
1196 ProcessList
*process_list
= control_flow_data
->process_list
;
1197 // LttTime birth = process->creation_time;
1199 // if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1200 // hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1202 hashed_process_data
= processlist_get_process_data(process_list
, resourceq
, trace_num
);
1203 // hashed_process_data = processlist_get_process_data(process_list,
1208 if(unlikely(hashed_process_data
== NULL
))
1210 //g_assert(pid == 0 || pid != process->ppid);
1211 ResourceInfo
*process_info
;
1212 /* Process not present */
1213 Drawing_t
*drawing
= control_flow_data
->drawing
;
1214 resourcelist_add(process_list
,
1217 resourceq
, //process->name,
1222 &hashed_process_data
);
1223 gtk_widget_set_size_request(drawing
->drawing_area
,
1226 gtk_widget_queue_draw(drawing
->drawing_area
);
1228 /* Set the current process */
1229 // process_list->current_hash_data[trace_num][process->cpu] =
1230 // hashed_process_data;
1233 /* Now, the process is in the state hash and our own process hash.
1234 * We definitely can draw the items related to the ending state.
1237 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1240 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1241 TimeWindow time_window
=
1242 lttvwindow_get_time_window(control_flow_data
->tab
);
1245 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1246 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1248 #endif //EXTRA_CHECK
1249 Drawing_t
*drawing
= control_flow_data
->drawing
;
1250 guint width
= drawing
->width
;
1252 convert_time_to_pixels(
1258 /* Draw collision indicator */
1259 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1260 gdk_draw_point(hashed_process_data
->pixmap
,
1263 COLLISION_POSITION(hashed_process_data
->height
));
1264 hashed_process_data
->x
.middle_marked
= TRUE
;
1268 TimeWindow time_window
=
1269 lttvwindow_get_time_window(control_flow_data
->tab
);
1272 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1273 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1275 #endif //EXTRA_CHECK
1276 Drawing_t
*drawing
= control_flow_data
->drawing
;
1277 guint width
= drawing
->width
;
1280 convert_time_to_pixels(
1287 /* Jump over draw if we are at the same x position */
1288 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1289 hashed_process_data
->x
.middle_used
))
1291 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1292 /* Draw collision indicator */
1293 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1294 gdk_draw_point(hashed_process_data
->pixmap
,
1297 COLLISION_POSITION(hashed_process_data
->height
));
1298 hashed_process_data
->x
.middle_marked
= TRUE
;
1304 DrawContext draw_context
;
1305 /* Now create the drawing context that will be used to draw
1306 * items related to the last state. */
1307 draw_context
.drawable
= hashed_process_data
->pixmap
;
1308 draw_context
.gc
= drawing
->gc
;
1309 draw_context
.pango_layout
= drawing
->pango_layout
;
1310 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1311 draw_context
.drawinfo
.end
.x
= x
;
1313 draw_context
.drawinfo
.y
.over
= 1;
1314 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1315 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1317 draw_context
.drawinfo
.start
.offset
.over
= 0;
1318 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1319 draw_context
.drawinfo
.start
.offset
.under
= 0;
1320 draw_context
.drawinfo
.end
.offset
.over
= 0;
1321 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1322 draw_context
.drawinfo
.end
.offset
.under
= 0;
1326 PropertiesLine prop_line
;
1327 prop_line
.line_width
= STATE_LINE_WIDTH
;
1328 prop_line
.style
= GDK_LINE_SOLID
;
1329 prop_line
.y
= MIDDLE
;
1330 irq_set_line_color(&prop_line
, &ts
->irq_states
[irq
]);
1331 draw_line((void*)&prop_line
, (void*)&draw_context
);
1333 /* become the last x position */
1334 hashed_process_data
->x
.middle
= x
;
1335 hashed_process_data
->x
.middle_used
= TRUE
;
1336 hashed_process_data
->x
.middle_marked
= FALSE
;
1338 /* Calculate the next good time */
1339 convert_pixels_to_time(width
, x
+1, time_window
,
1340 &hashed_process_data
->next_good_time
);
1347 int before_bdev_event_hook(void *hook_data
, void *call_data
)
1349 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1350 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1351 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1353 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1355 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1356 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1359 e
= ltt_tracefile_get_event(tfc
->tf
);
1361 LttTime evtime
= ltt_event_time(e
);
1365 /* we are in a execmode, before the state update. We must draw the
1366 * items corresponding to the state before it changes : now is the right
1371 guint cpu
= tfs
->cpu
;
1372 guint8 major
= ltt_event_get_long_unsigned(e
, thf
->f1
);
1373 guint8 minor
= ltt_event_get_long_unsigned(e
, thf
->f2
);
1374 guint oper
= ltt_event_get_long_unsigned(e
, thf
->f3
);
1375 gint devcode_gint
= MKDEV(major
,minor
);
1379 resourcestr
= g_strdup_printf("Blockdev (%u,%u)", major
, minor
);
1380 resourceq
= g_quark_from_string(resourcestr
);
1381 g_free(resourcestr
);
1383 guint trace_num
= ts
->parent
.index
;
1385 LttvBdevState
*bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1386 g_assert(bdev
!= NULL
);
1388 // guint pid = process->pid;
1390 /* Well, the process_out existed : we must get it in the process hash
1391 * or add it, and draw its items.
1393 /* Add process to process list (if not present) */
1394 guint pl_height
= 0;
1395 HashedResourceData
*hashed_process_data
= NULL
;
1396 ProcessList
*process_list
= control_flow_data
->process_list
;
1397 // LttTime birth = process->creation_time;
1399 // if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1400 // hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1402 hashed_process_data
= processlist_get_process_data(process_list
, resourceq
, trace_num
);
1403 // hashed_process_data = processlist_get_process_data(process_list,
1408 if(unlikely(hashed_process_data
== NULL
))
1410 //g_assert(pid == 0 || pid != process->ppid);
1411 ResourceInfo
*process_info
;
1412 /* Process not present */
1413 Drawing_t
*drawing
= control_flow_data
->drawing
;
1414 resourcelist_add(process_list
,
1417 resourceq
, //process->name,
1419 devcode_gint
, /* MKDEV(major,minor) */
1422 &hashed_process_data
);
1423 gtk_widget_set_size_request(drawing
->drawing_area
,
1426 gtk_widget_queue_draw(drawing
->drawing_area
);
1428 /* Set the current process */
1429 // process_list->current_hash_data[trace_num][process->cpu] =
1430 // hashed_process_data;
1433 /* Now, the process is in the state hash and our own process hash.
1434 * We definitely can draw the items related to the ending state.
1437 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1440 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1441 TimeWindow time_window
=
1442 lttvwindow_get_time_window(control_flow_data
->tab
);
1445 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1446 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1448 #endif //EXTRA_CHECK
1449 Drawing_t
*drawing
= control_flow_data
->drawing
;
1450 guint width
= drawing
->width
;
1452 convert_time_to_pixels(
1458 /* Draw collision indicator */
1459 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1460 gdk_draw_point(hashed_process_data
->pixmap
,
1463 COLLISION_POSITION(hashed_process_data
->height
));
1464 hashed_process_data
->x
.middle_marked
= TRUE
;
1468 TimeWindow time_window
=
1469 lttvwindow_get_time_window(control_flow_data
->tab
);
1472 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1473 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1475 #endif //EXTRA_CHECK
1476 Drawing_t
*drawing
= control_flow_data
->drawing
;
1477 guint width
= drawing
->width
;
1480 convert_time_to_pixels(
1487 /* Jump over draw if we are at the same x position */
1488 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1489 hashed_process_data
->x
.middle_used
))
1491 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1492 /* Draw collision indicator */
1493 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1494 gdk_draw_point(hashed_process_data
->pixmap
,
1497 COLLISION_POSITION(hashed_process_data
->height
));
1498 hashed_process_data
->x
.middle_marked
= TRUE
;
1504 DrawContext draw_context
;
1505 /* Now create the drawing context that will be used to draw
1506 * items related to the last state. */
1507 draw_context
.drawable
= hashed_process_data
->pixmap
;
1508 draw_context
.gc
= drawing
->gc
;
1509 draw_context
.pango_layout
= drawing
->pango_layout
;
1510 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1511 draw_context
.drawinfo
.end
.x
= x
;
1513 draw_context
.drawinfo
.y
.over
= 1;
1514 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1515 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1517 draw_context
.drawinfo
.start
.offset
.over
= 0;
1518 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1519 draw_context
.drawinfo
.start
.offset
.under
= 0;
1520 draw_context
.drawinfo
.end
.offset
.over
= 0;
1521 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1522 draw_context
.drawinfo
.end
.offset
.under
= 0;
1526 PropertiesLine prop_line
;
1527 prop_line
.line_width
= STATE_LINE_WIDTH
;
1528 prop_line
.style
= GDK_LINE_SOLID
;
1529 prop_line
.y
= MIDDLE
;
1530 bdev_set_line_color(&prop_line
, bdev
);
1531 draw_line((void*)&prop_line
, (void*)&draw_context
);
1533 /* become the last x position */
1534 hashed_process_data
->x
.middle
= x
;
1535 hashed_process_data
->x
.middle_used
= TRUE
;
1536 hashed_process_data
->x
.middle_marked
= FALSE
;
1538 /* Calculate the next good time */
1539 convert_pixels_to_time(width
, x
+1, time_window
,
1540 &hashed_process_data
->next_good_time
);
1547 gint
update_time_window_hook(void *hook_data
, void *call_data
)
1549 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1550 Drawing_t
*drawing
= control_flow_data
->drawing
;
1551 ProcessList
*process_list
= control_flow_data
->process_list
;
1553 const TimeWindowNotifyData
*time_window_nofify_data
=
1554 ((const TimeWindowNotifyData
*)call_data
);
1556 TimeWindow
*old_time_window
=
1557 time_window_nofify_data
->old_time_window
;
1558 TimeWindow
*new_time_window
=
1559 time_window_nofify_data
->new_time_window
;
1561 /* Update the ruler */
1562 drawing_update_ruler(control_flow_data
->drawing
,
1566 /* Two cases : zoom in/out or scrolling */
1568 /* In order to make sure we can reuse the old drawing, the scale must
1569 * be the same and the new time interval being partly located in the
1570 * currently shown time interval. (reuse is only for scrolling)
1573 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
1574 old_time_window
->start_time
.tv_sec
,
1575 old_time_window
->start_time
.tv_nsec
,
1576 old_time_window
->time_width
.tv_sec
,
1577 old_time_window
->time_width
.tv_nsec
);
1579 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
1580 new_time_window
->start_time
.tv_sec
,
1581 new_time_window
->start_time
.tv_nsec
,
1582 new_time_window
->time_width
.tv_sec
,
1583 new_time_window
->time_width
.tv_nsec
);
1585 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
1586 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
1588 /* Same scale (scrolling) */
1589 g_info("scrolling");
1590 LttTime
*ns
= &new_time_window
->start_time
;
1591 LttTime
*nw
= &new_time_window
->time_width
;
1592 LttTime
*os
= &old_time_window
->start_time
;
1593 LttTime
*ow
= &old_time_window
->time_width
;
1594 LttTime old_end
= old_time_window
->end_time
;
1595 LttTime new_end
= new_time_window
->end_time
;
1597 //if(ns<os+w && os+w<ns+w)
1598 //if(ns<old_end && os<ns)
1599 if(ltt_time_compare(*ns
, old_end
) == -1
1600 && ltt_time_compare(*os
, *ns
) == -1)
1602 g_info("scrolling near right");
1603 /* Scroll right, keep right part of the screen */
1605 guint width
= control_flow_data
->drawing
->width
;
1606 convert_time_to_pixels(
1612 /* Copy old data to new location */
1613 copy_pixmap_region(process_list
,
1615 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1619 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
1621 if(drawing
->damage_begin
== drawing
->damage_end
)
1622 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
1624 drawing
->damage_begin
= 0;
1626 drawing
->damage_end
= control_flow_data
->drawing
->width
;
1628 /* Clear the data request background, but not SAFETY */
1629 rectangle_pixmap(process_list
,
1630 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1632 drawing
->damage_begin
+SAFETY
, 0,
1633 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
1635 gtk_widget_queue_draw(drawing
->drawing_area
);
1636 //gtk_widget_queue_draw_area (drawing->drawing_area,
1638 // control_flow_data->drawing->width,
1639 // control_flow_data->drawing->height);
1641 /* Get new data for the rest. */
1642 drawing_data_request(control_flow_data
->drawing
,
1643 drawing
->damage_begin
, 0,
1644 drawing
->damage_end
- drawing
->damage_begin
,
1645 control_flow_data
->drawing
->height
);
1648 //if(ns<os && os<ns+w)
1649 //if(ns<os && os<new_end)
1650 if(ltt_time_compare(*ns
,*os
) == -1
1651 && ltt_time_compare(*os
,new_end
) == -1)
1653 g_info("scrolling near left");
1654 /* Scroll left, keep left part of the screen */
1656 guint width
= control_flow_data
->drawing
->width
;
1657 convert_time_to_pixels(
1663 /* Copy old data to new location */
1664 copy_pixmap_region (process_list
,
1666 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1672 if(drawing
->damage_begin
== drawing
->damage_end
)
1673 drawing
->damage_end
= x
;
1675 drawing
->damage_end
=
1676 control_flow_data
->drawing
->width
;
1678 drawing
->damage_begin
= 0;
1680 rectangle_pixmap (process_list
,
1681 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1683 drawing
->damage_begin
, 0,
1684 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
1687 gtk_widget_queue_draw(drawing
->drawing_area
);
1688 //gtk_widget_queue_draw_area (drawing->drawing_area,
1690 // control_flow_data->drawing->width,
1691 // control_flow_data->drawing->height);
1694 /* Get new data for the rest. */
1695 drawing_data_request(control_flow_data
->drawing
,
1696 drawing
->damage_begin
, 0,
1697 drawing
->damage_end
- drawing
->damage_begin
,
1698 control_flow_data
->drawing
->height
);
1701 if(ltt_time_compare(*ns
,*os
) == 0)
1703 g_info("not scrolling");
1705 g_info("scrolling far");
1706 /* Cannot reuse any part of the screen : far jump */
1709 rectangle_pixmap (process_list
,
1710 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1713 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
1716 //gtk_widget_queue_draw_area (drawing->drawing_area,
1718 // control_flow_data->drawing->width,
1719 // control_flow_data->drawing->height);
1720 gtk_widget_queue_draw(drawing
->drawing_area
);
1722 drawing
->damage_begin
= 0;
1723 drawing
->damage_end
= control_flow_data
->drawing
->width
;
1725 drawing_data_request(control_flow_data
->drawing
,
1727 control_flow_data
->drawing
->width
,
1728 control_flow_data
->drawing
->height
);
1734 /* Different scale (zoom) */
1737 rectangle_pixmap (process_list
,
1738 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1741 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
1744 //gtk_widget_queue_draw_area (drawing->drawing_area,
1746 // control_flow_data->drawing->width,
1747 // control_flow_data->drawing->height);
1748 gtk_widget_queue_draw(drawing
->drawing_area
);
1750 drawing
->damage_begin
= 0;
1751 drawing
->damage_end
= control_flow_data
->drawing
->width
;
1753 drawing_data_request(control_flow_data
->drawing
,
1755 control_flow_data
->drawing
->width
,
1756 control_flow_data
->drawing
->height
);
1759 /* Update directly when scrolling */
1760 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
1766 gint
traceset_notify(void *hook_data
, void *call_data
)
1768 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1769 Drawing_t
*drawing
= control_flow_data
->drawing
;
1771 if(unlikely(drawing
->gc
== NULL
)) {
1774 if(drawing
->dotted_gc
== NULL
) {
1778 drawing_clear(control_flow_data
->drawing
);
1779 processlist_clear(control_flow_data
->process_list
);
1780 gtk_widget_set_size_request(
1781 control_flow_data
->drawing
->drawing_area
,
1782 -1, processlist_get_height(control_flow_data
->process_list
));
1783 redraw_notify(control_flow_data
, NULL
);
1785 request_background_data(control_flow_data
);
1790 gint
redraw_notify(void *hook_data
, void *call_data
)
1792 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1793 Drawing_t
*drawing
= control_flow_data
->drawing
;
1794 GtkWidget
*widget
= drawing
->drawing_area
;
1796 drawing
->damage_begin
= 0;
1797 drawing
->damage_end
= drawing
->width
;
1799 /* fun feature, to be separated someday... */
1800 drawing_clear(control_flow_data
->drawing
);
1801 processlist_clear(control_flow_data
->process_list
);
1802 gtk_widget_set_size_request(
1803 control_flow_data
->drawing
->drawing_area
,
1804 -1, processlist_get_height(control_flow_data
->process_list
));
1806 rectangle_pixmap (control_flow_data
->process_list
,
1807 widget
->style
->black_gc
,
1810 drawing
->alloc_width
,
1813 gtk_widget_queue_draw(drawing
->drawing_area
);
1815 if(drawing
->damage_begin
< drawing
->damage_end
)
1817 drawing_data_request(drawing
,
1818 drawing
->damage_begin
,
1820 drawing
->damage_end
-drawing
->damage_begin
,
1824 //gtk_widget_queue_draw_area(drawing->drawing_area,
1827 // drawing->height);
1833 gint
continue_notify(void *hook_data
, void *call_data
)
1835 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1836 Drawing_t
*drawing
= control_flow_data
->drawing
;
1838 //g_assert(widget->allocation.width == drawing->damage_end);
1840 if(drawing
->damage_begin
< drawing
->damage_end
)
1842 drawing_data_request(drawing
,
1843 drawing
->damage_begin
,
1845 drawing
->damage_end
-drawing
->damage_begin
,
1853 gint
update_current_time_hook(void *hook_data
, void *call_data
)
1855 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
1856 Drawing_t
*drawing
= control_flow_data
->drawing
;
1858 LttTime current_time
= *((LttTime
*)call_data
);
1860 TimeWindow time_window
=
1861 lttvwindow_get_time_window(control_flow_data
->tab
);
1863 LttTime time_begin
= time_window
.start_time
;
1864 LttTime width
= time_window
.time_width
;
1867 guint64 time_ll
= ltt_time_to_uint64(width
);
1868 time_ll
= time_ll
>> 1; /* divide by two */
1869 half_width
= ltt_time_from_uint64(time_ll
);
1871 LttTime time_end
= ltt_time_add(time_begin
, width
);
1873 LttvTracesetContext
* tsc
=
1874 lttvwindow_get_traceset_context(control_flow_data
->tab
);
1876 LttTime trace_start
= tsc
->time_span
.start_time
;
1877 LttTime trace_end
= tsc
->time_span
.end_time
;
1879 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
1880 current_time
.tv_nsec
);
1884 /* If current time is inside time interval, just move the highlight
1887 /* Else, we have to change the time interval. We have to tell it
1888 * to the main window. */
1889 /* The time interval change will take care of placing the current
1890 * time at the center of the visible area, or nearest possible if we are
1891 * at one end of the trace. */
1894 if(ltt_time_compare(current_time
, time_begin
) < 0)
1896 TimeWindow new_time_window
;
1898 if(ltt_time_compare(current_time
,
1899 ltt_time_add(trace_start
,half_width
)) < 0)
1900 time_begin
= trace_start
;
1902 time_begin
= ltt_time_sub(current_time
,half_width
);
1904 new_time_window
.start_time
= time_begin
;
1905 new_time_window
.time_width
= width
;
1906 new_time_window
.time_width_double
= ltt_time_to_double(width
);
1907 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
1909 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
1911 else if(ltt_time_compare(current_time
, time_end
) > 0)
1913 TimeWindow new_time_window
;
1915 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
1916 time_begin
= ltt_time_sub(trace_end
,width
);
1918 time_begin
= ltt_time_sub(current_time
,half_width
);
1920 new_time_window
.start_time
= time_begin
;
1921 new_time_window
.time_width
= width
;
1922 new_time_window
.time_width_double
= ltt_time_to_double(width
);
1923 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
1925 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
1928 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
1930 /* Update directly when scrolling */
1931 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
1937 typedef struct _ClosureData
{
1938 EventsRequest
*events_request
;
1939 LttvTracesetState
*tss
;
1944 /* Draw line until end of the screen */
1946 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
1948 ResourceInfo
*process_info
= (ResourceInfo
*)key
;
1949 HashedResourceData
*hashed_process_data
= (HashedResourceData
*)value
;
1950 ClosureData
*closure_data
= (ClosureData
*)user_data
;
1952 EventsRequest
*events_request
= closure_data
->events_request
;
1953 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1955 LttvTracesetState
*tss
= closure_data
->tss
;
1956 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)tss
;
1958 LttTime evtime
= closure_data
->end_time
;
1960 gboolean dodraw
= TRUE
;
1963 /* For the process */
1964 /* First, check if the current process is in the state computation
1965 * process list. If it is there, that means we must add it right now and
1966 * draw items from the beginning of the read for it. If it is not
1967 * present, it's a new process and it was not present : it will
1968 * be added after the state update. */
1970 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
1971 #endif //EXTRA_CHECK
1972 LttvTraceContext
*tc
= tsc
->traces
[process_info
->trace_num
];
1973 LttvTraceState
*ts
= (LttvTraceState
*)tc
;
1976 //FIXME : optimize data structures.
1977 LttvTracefileState
*tfs
;
1978 LttvTracefileContext
*tfc
;
1980 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
1981 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
1982 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
1983 && tfs
->cpu
== process_info
->cpu
)
1987 g_assert(i
<tc
->tracefiles
->len
);
1988 tfs
= LTTV_TRACEFILE_STATE(tfc
);
1990 // LttvTracefileState *tfs =
1991 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
1992 // tracefiles[process_info->cpu];
1994 // LttvProcessState *process;
1995 // process = lttv_state_find_process(ts, process_info->cpu,
1996 // process_info->pid);
1998 // if(unlikely(process != NULL)) {
2000 // LttvFilter *filter = control_flow_data->filter;
2001 // if(filter != NULL && filter->head != NULL)
2002 // if(!lttv_filter_tree_parse(filter->head,NULL,NULL,
2003 // tc->t,NULL,process,tc))
2006 /* Only draw for processes that are currently in the trace states */
2008 ProcessList
*process_list
= control_flow_data
->process_list
;
2010 /* Should be alike when background info is ready */
2011 if(control_flow_data
->background_info_waiting
==0)
2012 g_assert(ltt_time_compare(process
->creation_time
,
2013 process_info
->birth
) == 0);
2014 #endif //EXTRA_CHECK
2016 /* Now, the process is in the state hash and our own process hash.
2017 * We definitely can draw the items related to the ending state.
2020 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2023 TimeWindow time_window
=
2024 lttvwindow_get_time_window(control_flow_data
->tab
);
2027 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2028 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2030 #endif //EXTRA_CHECK
2031 Drawing_t
*drawing
= control_flow_data
->drawing
;
2032 guint width
= drawing
->width
;
2034 guint x
= closure_data
->x_end
;
2036 DrawContext draw_context
;
2038 /* Now create the drawing context that will be used to draw
2039 * items related to the last state. */
2040 draw_context
.drawable
= hashed_process_data
->pixmap
;
2041 draw_context
.gc
= drawing
->gc
;
2042 draw_context
.pango_layout
= drawing
->pango_layout
;
2043 draw_context
.drawinfo
.end
.x
= x
;
2045 draw_context
.drawinfo
.y
.over
= 1;
2046 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2047 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2049 draw_context
.drawinfo
.start
.offset
.over
= 0;
2050 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2051 draw_context
.drawinfo
.start
.offset
.under
= 0;
2052 draw_context
.drawinfo
.end
.offset
.over
= 0;
2053 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2054 draw_context
.drawinfo
.end
.offset
.under
= 0;
2056 /* Jump over draw if we are at the same x position */
2057 if(x
== hashed_process_data
->x
.over
)
2061 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2063 PropertiesLine prop_line
= prepare_execmode_line(process
);
2064 draw_line((void*)&prop_line
, (void*)&draw_context
);
2066 hashed_process_data
->x
.over
= x
;
2070 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2071 hashed_process_data
->x
.middle_used
)) {
2072 #if 0 /* do not mark closure : not missing information */
2073 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2074 /* Draw collision indicator */
2075 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2076 gdk_draw_point(drawing
->pixmap
,
2080 hashed_process_data
->x
.middle_marked
= TRUE
;
2085 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2088 PropertiesLine prop_line
;
2089 prop_line
.line_width
= STATE_LINE_WIDTH
;
2090 prop_line
.style
= GDK_LINE_SOLID
;
2091 prop_line
.y
= MIDDLE
;
2092 if(process_info
->type
== 0)
2093 cpu_set_line_color(&prop_line
, &ts
->cpu_states
[process_info
->id
]);
2094 else if(process_info
->type
== 1)
2095 irq_set_line_color(&prop_line
, &ts
->irq_states
[process_info
->id
]);
2096 else if(process_info
->type
== 2) {
2097 gint devcode_gint
= process_info
->id
;
2098 LttvBdevState
*bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
2099 bdev_set_line_color(&prop_line
, bdev
);
2102 draw_line((void*)&prop_line
, (void*)&draw_context
);
2105 /* become the last x position */
2106 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2107 hashed_process_data
->x
.middle
= x
;
2108 /* but don't use the pixel */
2109 hashed_process_data
->x
.middle_used
= FALSE
;
2111 /* Calculate the next good time */
2112 convert_pixels_to_time(width
, x
+1, time_window
,
2113 &hashed_process_data
->next_good_time
);
2122 int before_chunk(void *hook_data
, void *call_data
)
2124 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2125 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2126 ControlFlowData
*cfd
= (ControlFlowData
*)events_request
->viewer_data
;
2128 /* Desactivate sort */
2129 gtk_tree_sortable_set_sort_column_id(
2130 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2132 GTK_SORT_ASCENDING
);
2134 drawing_chunk_begin(events_request
, tss
);
2139 int before_request(void *hook_data
, void *call_data
)
2141 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2142 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2144 drawing_data_request_begin(events_request
, tss
);
2151 * after request is necessary in addition of after chunk in order to draw
2152 * lines until the end of the screen. after chunk just draws lines until
2159 // TODO pmf: reenable this
2160 int after_request(void *hook_data
, void *call_data
)
2162 // EventsRequest *events_request = (EventsRequest*)hook_data;
2163 // ControlFlowData *control_flow_data = events_request->viewer_data;
2164 // LttvTracesetState *tss = (LttvTracesetState*)call_data;
2166 // ProcessList *process_list = control_flow_data->process_list;
2167 // LttTime end_time = events_request->end_time;
2169 // ClosureData closure_data;
2170 // closure_data.events_request = (EventsRequest*)hook_data;
2171 // closure_data.tss = tss;
2172 // closure_data.end_time = end_time;
2174 // TimeWindow time_window =
2175 // lttvwindow_get_time_window(control_flow_data->tab);
2176 // guint width = control_flow_data->drawing->width;
2177 // convert_time_to_pixels(
2181 // &closure_data.x_end);
2184 // /* Draw last items */
2185 // g_hash_table_foreach(process_list->process_hash, draw_closure,
2186 // (void*)&closure_data);
2189 // /* Request expose */
2190 // drawing_request_expose(events_request, tss, end_time);
2199 int after_chunk(void *hook_data
, void *call_data
)
2201 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2202 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2203 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2204 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)call_data
;
2205 LttvTracefileContext
*tfc
= lttv_traceset_context_get_current_tfc(tsc
);
2208 ProcessList
*process_list
= control_flow_data
->process_list
;
2210 LttvTraceset
*traceset
= tsc
->ts
;
2211 guint nb_trace
= lttv_traceset_number(traceset
);
2213 /* Only execute when called for the first trace's events request */
2214 if(!process_list
->current_hash_data
) return;
2216 for(i
= 0 ; i
< nb_trace
; i
++) {
2217 g_free(process_list
->current_hash_data
[i
]);
2219 g_free(process_list
->current_hash_data
);
2220 process_list
->current_hash_data
= NULL
;
2223 end_time
= LTT_TIME_MIN(tfc
->timestamp
, events_request
->end_time
);
2224 else /* end of traceset, or position now out of request : end */
2225 end_time
= events_request
->end_time
;
2227 ClosureData closure_data
;
2228 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2229 closure_data
.tss
= tss
;
2230 closure_data
.end_time
= end_time
;
2232 TimeWindow time_window
=
2233 lttvwindow_get_time_window(control_flow_data
->tab
);
2234 guint width
= control_flow_data
->drawing
->width
;
2235 convert_time_to_pixels(
2239 &closure_data
.x_end
);
2241 /* Draw last items */
2242 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2243 (void*)&closure_data
);
2245 /* Reactivate sort */
2246 gtk_tree_sortable_set_sort_column_id(
2247 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2248 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2249 GTK_SORT_ASCENDING
);
2251 update_index_to_pixmap(control_flow_data
->process_list
);
2252 /* Request a full expose : drawing scrambled */
2253 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2255 /* Request expose (updates damages zone also) */
2256 drawing_request_expose(events_request
, tss
, end_time
);
2261 /* after_statedump_end
2263 * @param hook_data ControlFlowData structure of the viewer.
2264 * @param call_data Event context.
2266 * This function adds items to be drawn in a queue for each process.
2269 int before_statedump_end(void *hook_data
, void *call_data
)
2271 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2272 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
2273 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2275 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2277 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
2279 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
2281 LttvTracesetState
*tss
= (LttvTracesetState
*)tfc
->t_context
->ts_context
;
2282 ProcessList
*process_list
= control_flow_data
->process_list
;
2285 e
= ltt_tracefile_get_event(tfc
->tf
);
2287 LttvFilter
*filter
= control_flow_data
->filter
;
2288 if(filter
!= NULL
&& filter
->head
!= NULL
)
2289 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2290 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2293 LttTime evtime
= ltt_event_time(e
);
2295 ClosureData closure_data
;
2296 closure_data
.events_request
= events_request
;
2297 closure_data
.tss
= tss
;
2298 closure_data
.end_time
= evtime
;
2300 TimeWindow time_window
=
2301 lttvwindow_get_time_window(control_flow_data
->tab
);
2302 guint width
= control_flow_data
->drawing
->width
;
2303 convert_time_to_pixels(
2307 &closure_data
.x_end
);
2309 /* Draw last items */
2310 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2311 (void*)&closure_data
);
2313 /* Reactivate sort */
2314 gtk_tree_sortable_set_sort_column_id(
2315 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2316 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2317 GTK_SORT_ASCENDING
);
2319 update_index_to_pixmap(control_flow_data
->process_list
);
2320 /* Request a full expose : drawing scrambled */
2321 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2323 /* Request expose (updates damages zone also) */
2324 drawing_request_expose(events_request
, tss
, evtime
);