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>
64 #include <ltt/trace.h>
66 #include <lttv/lttv.h>
67 #include <lttv/hook.h>
68 #include <lttv/state.h>
69 #include <lttvwindow/lttvwindow.h>
70 #include <lttvwindow/lttvwindowtraces.h>
71 #include <lttvwindow/support.h>
74 #include "eventhooks.h"
76 #include "processlist.h"
80 #define MAX_PATH_LEN 256
81 #define STATE_LINE_WIDTH 4
82 #define COLLISION_POSITION(height) (((height - STATE_LINE_WIDTH)/2) -3)
84 extern GSList
*g_legend_list
;
87 /* Action to do when background computation completed.
89 * Wait for all the awaited computations to be over.
92 static gint
background_ready(void *hook_data
, void *call_data
)
94 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
95 LttvTrace
*trace
= (LttvTrace
*)call_data
;
97 control_flow_data
->background_info_waiting
--;
99 if(control_flow_data
->background_info_waiting
== 0) {
100 g_message("control flow viewer : background computation data ready.");
102 drawing_clear(control_flow_data
->drawing
);
103 processlist_clear(control_flow_data
->process_list
);
104 gtk_widget_set_size_request(
105 control_flow_data
->drawing
->drawing_area
,
106 -1, processlist_get_height(control_flow_data
->process_list
));
107 redraw_notify(control_flow_data
, NULL
);
114 /* Request background computation. Verify if it is in progress or ready first.
115 * Only for each trace in the tab's traceset.
117 static void request_background_data(ControlFlowData
*control_flow_data
)
119 LttvTracesetContext
* tsc
=
120 lttvwindow_get_traceset_context(control_flow_data
->tab
);
121 gint num_traces
= lttv_traceset_number(tsc
->ts
);
124 LttvTraceState
*tstate
;
126 LttvHooks
*background_ready_hook
=
128 lttv_hooks_add(background_ready_hook
, background_ready
, control_flow_data
,
130 control_flow_data
->background_info_waiting
= 0;
132 for(i
=0;i
<num_traces
;i
++) {
133 trace
= lttv_traceset_get(tsc
->ts
, i
);
134 tstate
= LTTV_TRACE_STATE(tsc
->traces
[i
]);
136 if(lttvwindowtraces_get_ready(g_quark_from_string("state"),trace
)==FALSE
137 && !tstate
->has_precomputed_states
) {
139 if(lttvwindowtraces_get_in_progress(g_quark_from_string("state"),
141 /* We first remove requests that could have been done for the same
142 * information. Happens when two viewers ask for it before servicing
145 if(!lttvwindowtraces_background_request_find(trace
, "state"))
146 lttvwindowtraces_background_request_queue(
147 main_window_get_widget(control_flow_data
->tab
), trace
, "state");
148 lttvwindowtraces_background_notify_queue(control_flow_data
,
152 background_ready_hook
);
153 control_flow_data
->background_info_waiting
++;
154 } else { /* in progress */
156 lttvwindowtraces_background_notify_current(control_flow_data
,
160 background_ready_hook
);
161 control_flow_data
->background_info_waiting
++;
164 /* Data ready. By its nature, this viewer doesn't need to have
165 * its data ready hook called there, because a background
166 * request is always linked with a redraw.
172 lttv_hooks_destroy(background_ready_hook
);
179 * Event Viewer's constructor hook
181 * This constructor is given as a parameter to the menuitem and toolbar button
182 * registration. It creates the list.
183 * @param tab A pointer to the parent tab.
184 * @return The widget created.
187 h_resourceview(LttvPlugin
*plugin
)
189 LttvPluginTab
*ptab
= LTTV_PLUGIN_TAB(plugin
);
190 Tab
*tab
= ptab
->tab
;
191 g_info("h_guicontrolflow, %p", tab
);
192 ControlFlowData
*control_flow_data
= resourceview(ptab
);
194 control_flow_data
->tab
= tab
;
196 // Unreg done in the GuiControlFlow_Destructor
197 lttvwindow_register_traceset_notify(tab
,
201 lttvwindow_register_time_window_notify(tab
,
202 update_time_window_hook
,
204 lttvwindow_register_current_time_notify(tab
,
205 update_current_time_hook
,
207 lttvwindow_register_redraw_notify(tab
,
210 lttvwindow_register_continue_notify(tab
,
213 request_background_data(control_flow_data
);
216 return guicontrolflow_get_widget(control_flow_data
) ;
220 void legend_destructor(GtkWindow
*legend
)
222 g_legend_list
= g_slist_remove(g_legend_list
, legend
);
225 /* Create a popup legend */
227 h_legend(LttvPlugin
*plugin
)
229 LttvPluginTab
*ptab
= LTTV_PLUGIN_TAB(plugin
);
230 Tab
*tab
= ptab
->tab
;
231 g_info("h_legend, %p", tab
);
233 GtkWindow
*legend
= GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL
));
235 g_legend_list
= g_slist_append(
239 g_object_set_data_full(
243 (GDestroyNotify
)legend_destructor
);
245 gtk_window_set_title(legend
, "Control Flow View Legend");
247 GtkWidget
*pixmap
= create_pixmap(GTK_WIDGET(legend
), "lttv-color-list.png");
249 // GtkImage *image = GTK_IMAGE(gtk_image_new_from_pixmap(
250 // GDK_PIXMAP(pixmap), NULL));
252 gtk_container_add(GTK_CONTAINER(legend
), GTK_WIDGET(pixmap
));
254 gtk_widget_show(GTK_WIDGET(pixmap
));
255 gtk_widget_show(GTK_WIDGET(legend
));
258 return NULL
; /* This is a popup window */
262 int event_selected_hook(void *hook_data
, void *call_data
)
264 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
265 guint
*event_number
= (guint
*) call_data
;
267 g_debug("DEBUG : event selected by main window : %u", *event_number
);
272 /* Function that selects the color of status&exemode line */
273 static inline PropertiesLine
prepare_s_e_line(LttvProcessState
*process
)
275 PropertiesLine prop_line
;
276 prop_line
.line_width
= STATE_LINE_WIDTH
;
277 prop_line
.style
= GDK_LINE_SOLID
;
278 prop_line
.y
= MIDDLE
;
280 if(process
->state
->s
== LTTV_STATE_RUN
) {
281 if(process
->state
->t
== LTTV_STATE_USER_MODE
)
282 prop_line
.color
= drawing_colors
[COL_RUN_USER_MODE
];
283 else if(process
->state
->t
== LTTV_STATE_SYSCALL
)
284 prop_line
.color
= drawing_colors
[COL_RUN_SYSCALL
];
285 else if(process
->state
->t
== LTTV_STATE_TRAP
)
286 prop_line
.color
= drawing_colors
[COL_RUN_TRAP
];
287 else if(process
->state
->t
== LTTV_STATE_IRQ
)
288 prop_line
.color
= drawing_colors
[COL_RUN_IRQ
];
289 else if(process
->state
->t
== LTTV_STATE_SOFT_IRQ
)
290 prop_line
.color
= drawing_colors
[COL_RUN_SOFT_IRQ
];
291 else if(process
->state
->t
== LTTV_STATE_MODE_UNKNOWN
)
292 prop_line
.color
= drawing_colors
[COL_MODE_UNKNOWN
];
294 g_assert(FALSE
); /* RUNNING MODE UNKNOWN */
295 } else if(process
->state
->s
== LTTV_STATE_WAIT
) {
296 /* We don't show if we wait while in user mode, trap, irq or syscall */
297 prop_line
.color
= drawing_colors
[COL_WAIT
];
298 } else if(process
->state
->s
== LTTV_STATE_WAIT_CPU
) {
299 /* We don't show if we wait for CPU while in user mode, trap, irq
301 prop_line
.color
= drawing_colors
[COL_WAIT_CPU
];
302 } else if(process
->state
->s
== LTTV_STATE_ZOMBIE
) {
303 prop_line
.color
= drawing_colors
[COL_ZOMBIE
];
304 } else if(process
->state
->s
== LTTV_STATE_WAIT_FORK
) {
305 prop_line
.color
= drawing_colors
[COL_WAIT_FORK
];
306 } else if(process
->state
->s
== LTTV_STATE_EXIT
) {
307 prop_line
.color
= drawing_colors
[COL_EXIT
];
308 } else if(process
->state
->s
== LTTV_STATE_UNNAMED
) {
309 prop_line
.color
= drawing_colors
[COL_UNNAMED
];
311 g_critical("unknown state : %s", g_quark_to_string(process
->state
->s
));
312 g_assert(FALSE
); /* UNKNOWN STATE */
319 static void cpu_set_line_color(PropertiesLine
*prop_line
, LttvCPUState
*s
)
321 GQuark present_state
;
323 if(s
->mode_stack
->len
== 0)
324 present_state
= LTTV_CPU_UNKNOWN
;
326 present_state
= ((GQuark
*)s
->mode_stack
->data
)[s
->mode_stack
->len
-1];
328 if(present_state
== LTTV_CPU_IDLE
) {
329 prop_line
->color
= drawing_colors_cpu
[COL_CPU_IDLE
];
331 else if(present_state
== LTTV_CPU_BUSY
) {
332 prop_line
->color
= drawing_colors_cpu
[COL_CPU_BUSY
];
334 else if(present_state
== LTTV_CPU_IRQ
) {
335 prop_line
->color
= drawing_colors_cpu
[COL_CPU_IRQ
];
337 else if(present_state
== LTTV_CPU_TRAP
) {
338 prop_line
->color
= drawing_colors_cpu
[COL_CPU_TRAP
];
340 prop_line
->color
= drawing_colors_cpu
[COL_CPU_UNKNOWN
];
344 static void irq_set_line_color(PropertiesLine
*prop_line
, LttvIRQState
*s
)
346 GQuark present_state
;
347 if(s
->mode_stack
->len
== 0)
348 present_state
= LTTV_IRQ_UNKNOWN
;
350 present_state
= ((GQuark
*)s
->mode_stack
->data
)[s
->mode_stack
->len
-1];
352 if(present_state
== LTTV_IRQ_IDLE
) {
353 prop_line
->color
= drawing_colors_irq
[COL_IRQ_IDLE
];
355 else if(present_state
== LTTV_IRQ_BUSY
) {
356 prop_line
->color
= drawing_colors_irq
[COL_IRQ_BUSY
];
359 prop_line
->color
= drawing_colors_irq
[COL_IRQ_UNKNOWN
];
363 static void bdev_set_line_color(PropertiesLine
*prop_line
, LttvBdevState
*s
)
365 GQuark present_state
;
366 if(s
== 0 || s
->mode_stack
->len
== 0)
367 present_state
= LTTV_BDEV_UNKNOWN
;
369 present_state
= ((GQuark
*)s
->mode_stack
->data
)[s
->mode_stack
->len
-1];
371 if(present_state
== LTTV_BDEV_IDLE
) {
372 prop_line
->color
= drawing_colors_bdev
[COL_BDEV_IDLE
];
374 else if(present_state
== LTTV_BDEV_BUSY_READING
) {
375 prop_line
->color
= drawing_colors_bdev
[COL_BDEV_BUSY_READING
];
377 else if(present_state
== LTTV_BDEV_BUSY_WRITING
) {
378 prop_line
->color
= drawing_colors_bdev
[COL_BDEV_BUSY_WRITING
];
381 prop_line
->color
= drawing_colors_bdev
[COL_BDEV_UNKNOWN
];
385 /* before_schedchange_hook
387 * This function basically draw lines and icons. Two types of lines are drawn :
388 * one small (3 pixels?) representing the state of the process and the second
389 * type is thicker (10 pixels?) representing on which CPU a process is running
390 * (and this only in running state).
392 * Extremums of the lines :
393 * x_min : time of the last event context for this process kept in memory.
394 * x_max : time of the current event.
395 * y : middle of the process in the process list. The process is found in the
396 * list, therefore is it's position in pixels.
398 * The choice of lines'color is defined by the context of the last event for this
403 int before_schedchange_hook(void *hook_data
, void *call_data
)
405 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
406 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
407 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
409 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
411 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
412 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
415 e
= ltt_tracefile_get_event(tfc
->tf
);
416 gint target_pid_saved
= tfc
->target_pid
;
418 LttTime evtime
= ltt_event_time(e
);
419 LttvFilter
*filter
= control_flow_data
->filter
;
423 /* we are in a schedchange, before the state update. We must draw the
424 * items corresponding to the state before it changes : now is the right
430 pid_out
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
431 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
432 // if(pid_in != 0 && pid_out != 0) {
433 // /* not a transition to/from idle */
437 tfc
->target_pid
= pid_out
;
438 // if(!filter || !filter->head ||
439 // lttv_filter_tree_parse(filter->head,e,tfc->tf,
440 // tfc->t_context->t,tfc,NULL,NULL)) {
441 /* For the pid_out */
442 /* First, check if the current process is in the state computation
443 * process list. If it is there, that means we must add it right now and
444 * draw items from the beginning of the read for it. If it is not
445 * present, it's a new process and it was not present : it will
446 * be added after the state update. */
447 guint cpu
= tfs
->cpu
;
450 cpustr
= g_strdup_printf("CPU%u", cpu
);
451 cpuq
= g_quark_from_string(cpustr
);
455 guint trace_num
= ts
->parent
.index
;
456 // LttvProcessState *process = ts->running_process[cpu];
457 /* unknown state, bad current pid */
458 // if(process->pid != pid_out)
459 // process = lttv_state_find_process(ts,
460 // tfs->cpu, pid_out);
462 // if(process != NULL) {
463 /* Well, the process_out existed : we must get it in the process hash
464 * or add it, and draw its items.
466 /* Add process to process list (if not present) */
468 HashedResourceData
*hashed_process_data
= NULL
;
469 ProcessList
*process_list
= control_flow_data
->process_list
;
470 // LttTime birth = process->creation_time;
472 hashed_process_data
= processlist_get_process_data(process_list
, cpuq
, trace_num
);
473 // hashed_process_data = processlist_get_process_data(process_list,
478 if(hashed_process_data
== NULL
)
480 // g_assert(pid_out == 0 || pid_out != process->ppid);
481 /* Process not present */
482 ResourceInfo
*process_info
;
483 Drawing_t
*drawing
= control_flow_data
->drawing
;
484 resourcelist_add(process_list
,
487 cpuq
, //process->name,
492 &hashed_process_data
);
493 gtk_widget_set_size_request(drawing
->drawing_area
,
496 gtk_widget_queue_draw(drawing
->drawing_area
);
500 /* Now, the process is in the state hash and our own process hash.
501 * We definitely can draw the items related to the ending state.
504 if(ltt_time_compare(hashed_process_data
->next_good_time
,
507 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
509 TimeWindow time_window
=
510 lttvwindow_get_time_window(control_flow_data
->tab
);
512 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
513 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
516 Drawing_t
*drawing
= control_flow_data
->drawing
;
517 guint width
= drawing
->width
;
519 convert_time_to_pixels(
525 /* Draw collision indicator */
526 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
527 gdk_draw_point(hashed_process_data
->pixmap
,
530 COLLISION_POSITION(hashed_process_data
->height
));
531 hashed_process_data
->x
.middle_marked
= TRUE
;
534 TimeWindow time_window
=
535 lttvwindow_get_time_window(control_flow_data
->tab
);
537 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
538 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
541 Drawing_t
*drawing
= control_flow_data
->drawing
;
542 guint width
= drawing
->width
;
544 convert_time_to_pixels(
550 /* Jump over draw if we are at the same x position */
551 if(x
== hashed_process_data
->x
.middle
&&
552 hashed_process_data
->x
.middle_used
)
554 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
555 /* Draw collision indicator */
556 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
557 gdk_draw_point(hashed_process_data
->pixmap
,
560 COLLISION_POSITION(hashed_process_data
->height
));
561 hashed_process_data
->x
.middle_marked
= TRUE
;
565 DrawContext draw_context
;
567 /* Now create the drawing context that will be used to draw
568 * items related to the last state. */
569 draw_context
.drawable
= hashed_process_data
->pixmap
;
570 draw_context
.gc
= drawing
->gc
;
571 draw_context
.pango_layout
= drawing
->pango_layout
;
572 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
573 draw_context
.drawinfo
.end
.x
= x
;
575 draw_context
.drawinfo
.y
.over
= 1;
576 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
577 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
579 draw_context
.drawinfo
.start
.offset
.over
= 0;
580 draw_context
.drawinfo
.start
.offset
.middle
= 0;
581 draw_context
.drawinfo
.start
.offset
.under
= 0;
582 draw_context
.drawinfo
.end
.offset
.over
= 0;
583 draw_context
.drawinfo
.end
.offset
.middle
= 0;
584 draw_context
.drawinfo
.end
.offset
.under
= 0;
588 //PropertiesLine prop_line = prepare_s_e_line(process);
589 PropertiesLine prop_line
;
590 prop_line
.line_width
= STATE_LINE_WIDTH
;
591 prop_line
.style
= GDK_LINE_SOLID
;
592 prop_line
.y
= MIDDLE
;
593 cpu_set_line_color(&prop_line
, tfs
->cpu_state
);
594 draw_line((void*)&prop_line
, (void*)&draw_context
);
597 /* become the last x position */
598 hashed_process_data
->x
.middle
= x
;
599 hashed_process_data
->x
.middle_used
= TRUE
;
600 hashed_process_data
->x
.middle_marked
= FALSE
;
602 /* Calculate the next good time */
603 convert_pixels_to_time(width
, x
+1, time_window
,
604 &hashed_process_data
->next_good_time
);
610 // tfc->target_pid = pid_in;
611 // if(!filter || !filter->head ||
612 // lttv_filter_tree_parse(filter->head,e,tfc->tf,
613 // tfc->t_context->t,tfc,NULL,NULL)) {
614 // /* For the pid_in */
615 // /* First, check if the current process is in the state computation
616 // * process list. If it is there, that means we must add it right now and
617 // * draw items from the beginning of the read for it. If it is not
618 // * present, it's a new process and it was not present : it will
619 // * be added after the state update. */
620 // LttvProcessState *process;
621 // process = lttv_state_find_process(ts,
622 // tfs->cpu, pid_in);
623 // guint trace_num = ts->parent.index;
625 // if(process != NULL) {
626 // /* Well, the process existed : we must get it in the process hash
627 // * or add it, and draw its items.
629 // /* Add process to process list (if not present) */
630 // guint pl_height = 0;
631 // HashedResourceData *hashed_process_data = NULL;
632 // ProcessList *process_list = control_flow_data->process_list;
633 // LttTime birth = process->creation_time;
635 // hashed_process_data = processlist_get_process_data(process_list, cpuq);
636 //// hashed_process_data = processlist_get_process_data(process_list,
641 // if(hashed_process_data == NULL)
643 // g_assert(pid_in == 0 || pid_in != process->ppid);
644 // /* Process not present */
645 // ResourceInfo *process_info;
646 // Drawing_t *drawing = control_flow_data->drawing;
647 // resourcelist_add(process_list,
659 // &hashed_process_data);
660 // gtk_widget_set_size_request(drawing->drawing_area,
663 // gtk_widget_queue_draw(drawing->drawing_area);
666 // //We could set the current process and hash here, but will be done
667 // //by after schedchange hook
669 // /* Now, the process is in the state hash and our own process hash.
670 // * We definitely can draw the items related to the ending state.
673 // if(ltt_time_compare(hashed_process_data->next_good_time,
676 // if(hashed_process_data->x.middle_marked == FALSE) {
678 // TimeWindow time_window =
679 // lttvwindow_get_time_window(control_flow_data->tab);
681 // if(ltt_time_compare(evtime, time_window.start_time) == -1
682 // || ltt_time_compare(evtime, time_window.end_time) == 1)
684 //#endif //EXTRA_CHECK
685 // Drawing_t *drawing = control_flow_data->drawing;
686 // guint width = drawing->width;
688 // convert_time_to_pixels(
694 // /* Draw collision indicator */
695 // gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
696 // gdk_draw_point(hashed_process_data->pixmap,
699 // COLLISION_POSITION(hashed_process_data->height));
700 // hashed_process_data->x.middle_marked = TRUE;
703 // TimeWindow time_window =
704 // lttvwindow_get_time_window(control_flow_data->tab);
706 // if(ltt_time_compare(evtime, time_window.start_time) == -1
707 // || ltt_time_compare(evtime, time_window.end_time) == 1)
709 //#endif //EXTRA_CHECK
710 // Drawing_t *drawing = control_flow_data->drawing;
711 // guint width = drawing->width;
714 // convert_time_to_pixels(
721 // /* Jump over draw if we are at the same x position */
722 // if(x == hashed_process_data->x.middle &&
723 // hashed_process_data->x.middle_used)
725 // if(hashed_process_data->x.middle_marked == FALSE) {
726 // /* Draw collision indicator */
727 // gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
728 // gdk_draw_point(hashed_process_data->pixmap,
731 // COLLISION_POSITION(hashed_process_data->height));
732 // hashed_process_data->x.middle_marked = TRUE;
736 // DrawContext draw_context;
738 // /* Now create the drawing context that will be used to draw
739 // * items related to the last state. */
740 // draw_context.drawable = hashed_process_data->pixmap;
741 // draw_context.gc = drawing->gc;
742 // draw_context.pango_layout = drawing->pango_layout;
743 // draw_context.drawinfo.start.x = hashed_process_data->x.middle;
744 // draw_context.drawinfo.end.x = x;
746 // draw_context.drawinfo.y.over = 1;
747 // draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
748 // draw_context.drawinfo.y.under = hashed_process_data->height;
750 // draw_context.drawinfo.start.offset.over = 0;
751 // draw_context.drawinfo.start.offset.middle = 0;
752 // draw_context.drawinfo.start.offset.under = 0;
753 // draw_context.drawinfo.end.offset.over = 0;
754 // draw_context.drawinfo.end.offset.middle = 0;
755 // draw_context.drawinfo.end.offset.under = 0;
758 // /* Draw the line */
759 // PropertiesLine prop_line = prepare_s_e_line(process);
760 // draw_line((void*)&prop_line, (void*)&draw_context);
764 // /* become the last x position */
765 // hashed_process_data->x.middle = x;
766 // hashed_process_data->x.middle_used = TRUE;
767 // hashed_process_data->x.middle_marked = FALSE;
769 // /* Calculate the next good time */
770 // convert_pixels_to_time(width, x+1, time_window,
771 // &hashed_process_data->next_good_time);
775 // g_warning("Cannot find pin_in in schedchange %u", pid_in);
777 // tfc->target_pid = target_pid_saved;
785 GString
*string
= g_string_new("");;
786 gboolean field_names
= TRUE
, state
= TRUE
;
788 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
789 g_string_append_printf(string
,"\n");
792 g_string_append_printf(string
, " %s",
793 g_quark_to_string(tfs
->process
->state
->s
));
796 g_info("%s",string
->str
);
798 g_string_free(string
, TRUE
);
800 /* End of text dump */
805 /* after_schedchange_hook
807 * The draw after hook is called by the reading API to have a
808 * particular event drawn on the screen.
809 * @param hook_data ControlFlowData structure of the viewer.
810 * @param call_data Event context.
812 * This function adds items to be drawn in a queue for each process.
815 int after_schedchange_hook(void *hook_data
, void *call_data
)
817 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
818 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
819 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
821 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
823 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
825 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
828 e
= ltt_tracefile_get_event(tfc
->tf
);
830 LttvFilter
*filter
= control_flow_data
->filter
;
831 if(filter
!= NULL
&& filter
->head
!= NULL
)
832 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
833 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
836 LttTime evtime
= ltt_event_time(e
);
840 /* Add process to process list (if not present) */
841 LttvProcessState
*process_in
;
844 HashedResourceData
*hashed_process_data_in
= NULL
;
846 ProcessList
*process_list
= control_flow_data
->process_list
;
851 pid_out
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
852 pid_in
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
856 /* Find process pid_in in the list... */
857 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
858 //process_in = tfs->process;
859 guint cpu
= tfs
->cpu
;
862 cpustr
= g_strdup_printf("CPU%u", cpu
);
863 cpuq
= g_quark_from_string(cpustr
);
866 guint trace_num
= ts
->parent
.index
;
867 process_in
= ts
->running_process
[cpu
];
868 /* It should exist, because we are after the state update. */
870 g_assert(process_in
!= NULL
);
872 birth
= process_in
->creation_time
;
874 hashed_process_data_in
= processlist_get_process_data(process_list
, cpuq
, trace_num
);
875 // hashed_process_data_in = processlist_get_process_data(process_list,
880 if(hashed_process_data_in
== NULL
)
882 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
883 ResourceInfo
*process_info
;
884 Drawing_t
*drawing
= control_flow_data
->drawing
;
885 /* Process not present */
886 resourcelist_add(process_list
,
894 &hashed_process_data_in
);
895 gtk_widget_set_size_request(drawing
->drawing_area
,
898 gtk_widget_queue_draw(drawing
->drawing_area
);
900 /* Set the current process */
901 process_list
->current_hash_data
[trace_num
][process_in
->cpu
] =
902 hashed_process_data_in
;
904 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
907 TimeWindow time_window
=
908 lttvwindow_get_time_window(control_flow_data
->tab
);
911 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
912 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
915 Drawing_t
*drawing
= control_flow_data
->drawing
;
916 guint width
= drawing
->width
;
919 convert_time_to_pixels(
925 if(hashed_process_data_in
->x
.middle
!= new_x
) {
926 hashed_process_data_in
->x
.middle
= new_x
;
927 hashed_process_data_in
->x
.middle_used
= FALSE
;
928 hashed_process_data_in
->x
.middle_marked
= FALSE
;
934 /* before_execmode_hook
936 * This function basically draw lines and icons. Two types of lines are drawn :
937 * one small (3 pixels?) representing the state of the process and the second
938 * type is thicker (10 pixels?) representing on which CPU a process is running
939 * (and this only in running state).
941 * Extremums of the lines :
942 * x_min : time of the last event context for this process kept in memory.
943 * x_max : time of the current event.
944 * y : middle of the process in the process list. The process is found in the
945 * list, therefore is it's position in pixels.
947 * The choice of lines'color is defined by the context of the last event for this
951 int before_execmode_hook(void *hook_data
, void *call_data
)
953 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
954 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
955 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
957 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
959 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
960 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
963 e
= ltt_tracefile_get_event(tfc
->tf
);
965 LttTime evtime
= ltt_event_time(e
);
969 before_execmode_hook_irq(hook_data
, call_data
);
971 /* we are in a execmode, before the state update. We must draw the
972 * items corresponding to the state before it changes : now is the right
976 //LttvProcessState *process = tfs->process;
977 guint cpu
= tfs
->cpu
;
980 cpustr
= g_strdup_printf("CPU%u", cpu
);
981 cpuq
= g_quark_from_string(cpustr
);
984 guint trace_num
= ts
->parent
.index
;
985 LttvProcessState
*process
= ts
->running_process
[cpu
];
986 g_assert(process
!= NULL
);
988 // guint pid = process->pid;
990 /* Well, the process_out existed : we must get it in the process hash
991 * or add it, and draw its items.
993 /* Add process to process list (if not present) */
995 HashedResourceData
*hashed_process_data
= NULL
;
996 ProcessList
*process_list
= control_flow_data
->process_list
;
997 LttTime birth
= process
->creation_time
;
999 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1000 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1002 hashed_process_data
= processlist_get_process_data(process_list
, cpuq
, trace_num
);
1003 // hashed_process_data = processlist_get_process_data(process_list,
1008 if(unlikely(hashed_process_data
== NULL
))
1010 //g_assert(pid == 0 || pid != process->ppid);
1011 ResourceInfo
*process_info
;
1012 /* Process not present */
1013 Drawing_t
*drawing
= control_flow_data
->drawing
;
1014 resourcelist_add(process_list
,
1017 cpuq
, //process->name,
1022 &hashed_process_data
);
1023 gtk_widget_set_size_request(drawing
->drawing_area
,
1026 gtk_widget_queue_draw(drawing
->drawing_area
);
1028 /* Set the current process */
1029 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1030 hashed_process_data
;
1033 /* Now, the process is in the state hash and our own process hash.
1034 * We definitely can draw the items related to the ending state.
1037 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1040 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1041 TimeWindow time_window
=
1042 lttvwindow_get_time_window(control_flow_data
->tab
);
1045 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1046 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1048 #endif //EXTRA_CHECK
1049 Drawing_t
*drawing
= control_flow_data
->drawing
;
1050 guint width
= drawing
->width
;
1052 convert_time_to_pixels(
1058 /* Draw collision indicator */
1059 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1060 gdk_draw_point(hashed_process_data
->pixmap
,
1063 COLLISION_POSITION(hashed_process_data
->height
));
1064 hashed_process_data
->x
.middle_marked
= TRUE
;
1068 TimeWindow time_window
=
1069 lttvwindow_get_time_window(control_flow_data
->tab
);
1072 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1073 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1075 #endif //EXTRA_CHECK
1076 Drawing_t
*drawing
= control_flow_data
->drawing
;
1077 guint width
= drawing
->width
;
1080 convert_time_to_pixels(
1087 /* Jump over draw if we are at the same x position */
1088 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1089 hashed_process_data
->x
.middle_used
))
1091 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1092 /* Draw collision indicator */
1093 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1094 gdk_draw_point(hashed_process_data
->pixmap
,
1097 COLLISION_POSITION(hashed_process_data
->height
));
1098 hashed_process_data
->x
.middle_marked
= TRUE
;
1104 DrawContext draw_context
;
1105 /* Now create the drawing context that will be used to draw
1106 * items related to the last state. */
1107 draw_context
.drawable
= hashed_process_data
->pixmap
;
1108 draw_context
.gc
= drawing
->gc
;
1109 draw_context
.pango_layout
= drawing
->pango_layout
;
1110 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1111 draw_context
.drawinfo
.end
.x
= x
;
1113 draw_context
.drawinfo
.y
.over
= 1;
1114 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1115 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1117 draw_context
.drawinfo
.start
.offset
.over
= 0;
1118 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1119 draw_context
.drawinfo
.start
.offset
.under
= 0;
1120 draw_context
.drawinfo
.end
.offset
.over
= 0;
1121 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1122 draw_context
.drawinfo
.end
.offset
.under
= 0;
1126 PropertiesLine prop_line
;
1127 prop_line
.line_width
= STATE_LINE_WIDTH
;
1128 prop_line
.style
= GDK_LINE_SOLID
;
1129 prop_line
.y
= MIDDLE
;
1130 cpu_set_line_color(&prop_line
, tfs
->cpu_state
);
1131 draw_line((void*)&prop_line
, (void*)&draw_context
);
1133 /* become the last x position */
1134 hashed_process_data
->x
.middle
= x
;
1135 hashed_process_data
->x
.middle_used
= TRUE
;
1136 hashed_process_data
->x
.middle_marked
= FALSE
;
1138 /* Calculate the next good time */
1139 convert_pixels_to_time(width
, x
+1, time_window
,
1140 &hashed_process_data
->next_good_time
);
1147 int before_execmode_hook_irq(void *hook_data
, void *call_data
)
1149 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1150 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1151 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1153 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1155 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1156 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1159 e
= ltt_tracefile_get_event(tfc
->tf
);
1161 LttTime evtime
= ltt_event_time(e
);
1163 LttTrace
*trace
= tfc
->t_context
->t
;
1167 /* we are in a execmode, before the state update. We must draw the
1168 * items corresponding to the state before it changes : now is the right
1174 guint cpu
= tfs
->cpu
;
1176 guint16 ev_id_entry
= marker_get_id_from_info(trace
, marker_get_info_from_name(trace
, lttv_merge_facility_event_name(LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
)));
1177 guint16 ev_id_exit
= marker_get_id_from_info(trace
, marker_get_info_from_name(trace
, lttv_merge_facility_event_name(LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
)));
1178 if(ev_id_entry
== e
->event_id
) {
1179 irq
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
1181 else if(ev_id_exit
== e
->event_id
) {
1182 irq
= ts
->cpu_states
[cpu
].last_irq
;
1190 irqstr
= g_strdup_printf("IRQ %llu [%s]", irq
, g_quark_to_string(ts
->irq_names
[irq
]));
1191 resourceq
= g_quark_from_string(irqstr
);
1194 guint trace_num
= ts
->parent
.index
;
1196 // guint pid = process->pid;
1198 /* Well, the process_out existed : we must get it in the process hash
1199 * or add it, and draw its items.
1201 /* Add process to process list (if not present) */
1202 guint pl_height
= 0;
1203 HashedResourceData
*hashed_process_data
= NULL
;
1204 ProcessList
*process_list
= control_flow_data
->process_list
;
1205 // LttTime birth = process->creation_time;
1207 // if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1208 // hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1210 hashed_process_data
= processlist_get_process_data(process_list
, resourceq
, trace_num
);
1211 // hashed_process_data = processlist_get_process_data(process_list,
1216 if(unlikely(hashed_process_data
== NULL
))
1218 //g_assert(pid == 0 || pid != process->ppid);
1219 ResourceInfo
*process_info
;
1220 /* Process not present */
1221 Drawing_t
*drawing
= control_flow_data
->drawing
;
1222 resourcelist_add(process_list
,
1225 resourceq
, //process->name,
1230 &hashed_process_data
);
1231 gtk_widget_set_size_request(drawing
->drawing_area
,
1234 gtk_widget_queue_draw(drawing
->drawing_area
);
1236 /* Set the current process */
1237 // process_list->current_hash_data[trace_num][process->cpu] =
1238 // hashed_process_data;
1241 /* Now, the process is in the state hash and our own process hash.
1242 * We definitely can draw the items related to the ending state.
1245 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1248 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1249 TimeWindow time_window
=
1250 lttvwindow_get_time_window(control_flow_data
->tab
);
1253 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1254 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1256 #endif //EXTRA_CHECK
1257 Drawing_t
*drawing
= control_flow_data
->drawing
;
1258 guint width
= drawing
->width
;
1260 convert_time_to_pixels(
1266 /* Draw collision indicator */
1267 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1268 gdk_draw_point(hashed_process_data
->pixmap
,
1271 COLLISION_POSITION(hashed_process_data
->height
));
1272 hashed_process_data
->x
.middle_marked
= TRUE
;
1276 TimeWindow time_window
=
1277 lttvwindow_get_time_window(control_flow_data
->tab
);
1280 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1281 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1283 #endif //EXTRA_CHECK
1284 Drawing_t
*drawing
= control_flow_data
->drawing
;
1285 guint width
= drawing
->width
;
1288 convert_time_to_pixels(
1295 /* Jump over draw if we are at the same x position */
1296 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1297 hashed_process_data
->x
.middle_used
))
1299 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1300 /* Draw collision indicator */
1301 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1302 gdk_draw_point(hashed_process_data
->pixmap
,
1305 COLLISION_POSITION(hashed_process_data
->height
));
1306 hashed_process_data
->x
.middle_marked
= TRUE
;
1312 DrawContext draw_context
;
1313 /* Now create the drawing context that will be used to draw
1314 * items related to the last state. */
1315 draw_context
.drawable
= hashed_process_data
->pixmap
;
1316 draw_context
.gc
= drawing
->gc
;
1317 draw_context
.pango_layout
= drawing
->pango_layout
;
1318 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1319 draw_context
.drawinfo
.end
.x
= x
;
1321 draw_context
.drawinfo
.y
.over
= 1;
1322 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1323 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1325 draw_context
.drawinfo
.start
.offset
.over
= 0;
1326 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1327 draw_context
.drawinfo
.start
.offset
.under
= 0;
1328 draw_context
.drawinfo
.end
.offset
.over
= 0;
1329 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1330 draw_context
.drawinfo
.end
.offset
.under
= 0;
1334 PropertiesLine prop_line
;
1335 prop_line
.line_width
= STATE_LINE_WIDTH
;
1336 prop_line
.style
= GDK_LINE_SOLID
;
1337 prop_line
.y
= MIDDLE
;
1338 irq_set_line_color(&prop_line
, &ts
->irq_states
[irq
]);
1339 draw_line((void*)&prop_line
, (void*)&draw_context
);
1341 /* become the last x position */
1342 hashed_process_data
->x
.middle
= x
;
1343 hashed_process_data
->x
.middle_used
= TRUE
;
1344 hashed_process_data
->x
.middle_marked
= FALSE
;
1346 /* Calculate the next good time */
1347 convert_pixels_to_time(width
, x
+1, time_window
,
1348 &hashed_process_data
->next_good_time
);
1355 int before_bdev_event_hook(void *hook_data
, void *call_data
)
1357 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
1358 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
1359 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1361 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1363 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1364 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1367 e
= ltt_tracefile_get_event(tfc
->tf
);
1369 LttTime evtime
= ltt_event_time(e
);
1373 /* we are in a execmode, before the state update. We must draw the
1374 * items corresponding to the state before it changes : now is the right
1379 guint cpu
= tfs
->cpu
;
1380 guint8 major
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
1381 guint8 minor
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 1));
1382 guint oper
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 2));
1383 gint devcode_gint
= MKDEV(major
,minor
);
1387 resourcestr
= g_strdup_printf("Blockdev (%u,%u)", major
, minor
);
1388 resourceq
= g_quark_from_string(resourcestr
);
1389 g_free(resourcestr
);
1391 guint trace_num
= ts
->parent
.index
;
1393 LttvBdevState
*bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1394 /* the result of the lookup might be NULL. that's ok, the rest of the function
1395 should understand it was not found and that its state is unknown */
1397 // guint pid = process->pid;
1399 /* Well, the process_out existed : we must get it in the process hash
1400 * or add it, and draw its items.
1402 /* Add process to process list (if not present) */
1403 guint pl_height
= 0;
1404 HashedResourceData
*hashed_process_data
= NULL
;
1405 ProcessList
*process_list
= control_flow_data
->process_list
;
1406 // LttTime birth = process->creation_time;
1408 // if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1409 // hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1411 hashed_process_data
= processlist_get_process_data(process_list
, resourceq
, trace_num
);
1412 // hashed_process_data = processlist_get_process_data(process_list,
1417 if(unlikely(hashed_process_data
== NULL
))
1419 //g_assert(pid == 0 || pid != process->ppid);
1420 ResourceInfo
*process_info
;
1421 /* Process not present */
1422 Drawing_t
*drawing
= control_flow_data
->drawing
;
1423 resourcelist_add(process_list
,
1426 resourceq
, //process->name,
1428 devcode_gint
, /* MKDEV(major,minor) */
1431 &hashed_process_data
);
1432 gtk_widget_set_size_request(drawing
->drawing_area
,
1435 gtk_widget_queue_draw(drawing
->drawing_area
);
1437 /* Set the current process */
1438 // process_list->current_hash_data[trace_num][process->cpu] =
1439 // hashed_process_data;
1442 /* Now, the process is in the state hash and our own process hash.
1443 * We definitely can draw the items related to the ending state.
1446 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1449 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1450 TimeWindow time_window
=
1451 lttvwindow_get_time_window(control_flow_data
->tab
);
1454 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1455 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1457 #endif //EXTRA_CHECK
1458 Drawing_t
*drawing
= control_flow_data
->drawing
;
1459 guint width
= drawing
->width
;
1461 convert_time_to_pixels(
1467 /* Draw collision indicator */
1468 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1469 gdk_draw_point(hashed_process_data
->pixmap
,
1472 COLLISION_POSITION(hashed_process_data
->height
));
1473 hashed_process_data
->x
.middle_marked
= TRUE
;
1477 TimeWindow time_window
=
1478 lttvwindow_get_time_window(control_flow_data
->tab
);
1481 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1482 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1484 #endif //EXTRA_CHECK
1485 Drawing_t
*drawing
= control_flow_data
->drawing
;
1486 guint width
= drawing
->width
;
1489 convert_time_to_pixels(
1496 /* Jump over draw if we are at the same x position */
1497 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1498 hashed_process_data
->x
.middle_used
))
1500 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1501 /* Draw collision indicator */
1502 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1503 gdk_draw_point(hashed_process_data
->pixmap
,
1506 COLLISION_POSITION(hashed_process_data
->height
));
1507 hashed_process_data
->x
.middle_marked
= TRUE
;
1513 DrawContext draw_context
;
1514 /* Now create the drawing context that will be used to draw
1515 * items related to the last state. */
1516 draw_context
.drawable
= hashed_process_data
->pixmap
;
1517 draw_context
.gc
= drawing
->gc
;
1518 draw_context
.pango_layout
= drawing
->pango_layout
;
1519 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1520 draw_context
.drawinfo
.end
.x
= x
;
1522 draw_context
.drawinfo
.y
.over
= 1;
1523 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1524 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1526 draw_context
.drawinfo
.start
.offset
.over
= 0;
1527 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1528 draw_context
.drawinfo
.start
.offset
.under
= 0;
1529 draw_context
.drawinfo
.end
.offset
.over
= 0;
1530 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1531 draw_context
.drawinfo
.end
.offset
.under
= 0;
1535 PropertiesLine prop_line
;
1536 prop_line
.line_width
= STATE_LINE_WIDTH
;
1537 prop_line
.style
= GDK_LINE_SOLID
;
1538 prop_line
.y
= MIDDLE
;
1539 bdev_set_line_color(&prop_line
, bdev
);
1540 draw_line((void*)&prop_line
, (void*)&draw_context
);
1542 /* become the last x position */
1543 hashed_process_data
->x
.middle
= x
;
1544 hashed_process_data
->x
.middle_used
= TRUE
;
1545 hashed_process_data
->x
.middle_marked
= FALSE
;
1547 /* Calculate the next good time */
1548 convert_pixels_to_time(width
, x
+1, time_window
,
1549 &hashed_process_data
->next_good_time
);
1556 gint
update_time_window_hook(void *hook_data
, void *call_data
)
1558 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1559 Drawing_t
*drawing
= control_flow_data
->drawing
;
1560 ProcessList
*process_list
= control_flow_data
->process_list
;
1562 const TimeWindowNotifyData
*time_window_nofify_data
=
1563 ((const TimeWindowNotifyData
*)call_data
);
1565 TimeWindow
*old_time_window
=
1566 time_window_nofify_data
->old_time_window
;
1567 TimeWindow
*new_time_window
=
1568 time_window_nofify_data
->new_time_window
;
1570 /* Update the ruler */
1571 drawing_update_ruler(control_flow_data
->drawing
,
1575 /* Two cases : zoom in/out or scrolling */
1577 /* In order to make sure we can reuse the old drawing, the scale must
1578 * be the same and the new time interval being partly located in the
1579 * currently shown time interval. (reuse is only for scrolling)
1582 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
1583 old_time_window
->start_time
.tv_sec
,
1584 old_time_window
->start_time
.tv_nsec
,
1585 old_time_window
->time_width
.tv_sec
,
1586 old_time_window
->time_width
.tv_nsec
);
1588 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
1589 new_time_window
->start_time
.tv_sec
,
1590 new_time_window
->start_time
.tv_nsec
,
1591 new_time_window
->time_width
.tv_sec
,
1592 new_time_window
->time_width
.tv_nsec
);
1594 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
1595 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
1597 /* Same scale (scrolling) */
1598 g_info("scrolling");
1599 LttTime
*ns
= &new_time_window
->start_time
;
1600 LttTime
*nw
= &new_time_window
->time_width
;
1601 LttTime
*os
= &old_time_window
->start_time
;
1602 LttTime
*ow
= &old_time_window
->time_width
;
1603 LttTime old_end
= old_time_window
->end_time
;
1604 LttTime new_end
= new_time_window
->end_time
;
1606 //if(ns<os+w && os+w<ns+w)
1607 //if(ns<old_end && os<ns)
1608 if(ltt_time_compare(*ns
, old_end
) == -1
1609 && ltt_time_compare(*os
, *ns
) == -1)
1611 g_info("scrolling near right");
1612 /* Scroll right, keep right part of the screen */
1614 guint width
= control_flow_data
->drawing
->width
;
1615 convert_time_to_pixels(
1621 /* Copy old data to new location */
1622 copy_pixmap_region(process_list
,
1624 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1628 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
1630 if(drawing
->damage_begin
== drawing
->damage_end
)
1631 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
1633 drawing
->damage_begin
= 0;
1635 drawing
->damage_end
= control_flow_data
->drawing
->width
;
1637 /* Clear the data request background, but not SAFETY */
1638 rectangle_pixmap(process_list
,
1639 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1641 drawing
->damage_begin
+SAFETY
, 0,
1642 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
1644 gtk_widget_queue_draw(drawing
->drawing_area
);
1645 //gtk_widget_queue_draw_area (drawing->drawing_area,
1647 // control_flow_data->drawing->width,
1648 // control_flow_data->drawing->height);
1650 /* Get new data for the rest. */
1651 drawing_data_request(control_flow_data
->drawing
,
1652 drawing
->damage_begin
, 0,
1653 drawing
->damage_end
- drawing
->damage_begin
,
1654 control_flow_data
->drawing
->height
);
1657 //if(ns<os && os<ns+w)
1658 //if(ns<os && os<new_end)
1659 if(ltt_time_compare(*ns
,*os
) == -1
1660 && ltt_time_compare(*os
,new_end
) == -1)
1662 g_info("scrolling near left");
1663 /* Scroll left, keep left part of the screen */
1665 guint width
= control_flow_data
->drawing
->width
;
1666 convert_time_to_pixels(
1672 /* Copy old data to new location */
1673 copy_pixmap_region (process_list
,
1675 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1681 if(drawing
->damage_begin
== drawing
->damage_end
)
1682 drawing
->damage_end
= x
;
1684 drawing
->damage_end
=
1685 control_flow_data
->drawing
->width
;
1687 drawing
->damage_begin
= 0;
1689 rectangle_pixmap (process_list
,
1690 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1692 drawing
->damage_begin
, 0,
1693 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
1696 gtk_widget_queue_draw(drawing
->drawing_area
);
1697 //gtk_widget_queue_draw_area (drawing->drawing_area,
1699 // control_flow_data->drawing->width,
1700 // control_flow_data->drawing->height);
1703 /* Get new data for the rest. */
1704 drawing_data_request(control_flow_data
->drawing
,
1705 drawing
->damage_begin
, 0,
1706 drawing
->damage_end
- drawing
->damage_begin
,
1707 control_flow_data
->drawing
->height
);
1710 if(ltt_time_compare(*ns
,*os
) == 0)
1712 g_info("not scrolling");
1714 g_info("scrolling far");
1715 /* Cannot reuse any part of the screen : far jump */
1718 rectangle_pixmap (process_list
,
1719 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1722 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
1725 //gtk_widget_queue_draw_area (drawing->drawing_area,
1727 // control_flow_data->drawing->width,
1728 // control_flow_data->drawing->height);
1729 gtk_widget_queue_draw(drawing
->drawing_area
);
1731 drawing
->damage_begin
= 0;
1732 drawing
->damage_end
= control_flow_data
->drawing
->width
;
1734 drawing_data_request(control_flow_data
->drawing
,
1736 control_flow_data
->drawing
->width
,
1737 control_flow_data
->drawing
->height
);
1743 /* Different scale (zoom) */
1746 rectangle_pixmap (process_list
,
1747 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1750 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
1753 //gtk_widget_queue_draw_area (drawing->drawing_area,
1755 // control_flow_data->drawing->width,
1756 // control_flow_data->drawing->height);
1757 gtk_widget_queue_draw(drawing
->drawing_area
);
1759 drawing
->damage_begin
= 0;
1760 drawing
->damage_end
= control_flow_data
->drawing
->width
;
1762 drawing_data_request(control_flow_data
->drawing
,
1764 control_flow_data
->drawing
->width
,
1765 control_flow_data
->drawing
->height
);
1768 /* Update directly when scrolling */
1769 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
1775 gint
traceset_notify(void *hook_data
, void *call_data
)
1777 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1778 Drawing_t
*drawing
= control_flow_data
->drawing
;
1780 if(unlikely(drawing
->gc
== NULL
)) {
1783 if(drawing
->dotted_gc
== NULL
) {
1787 drawing_clear(control_flow_data
->drawing
);
1788 processlist_clear(control_flow_data
->process_list
);
1789 gtk_widget_set_size_request(
1790 control_flow_data
->drawing
->drawing_area
,
1791 -1, processlist_get_height(control_flow_data
->process_list
));
1792 redraw_notify(control_flow_data
, NULL
);
1794 request_background_data(control_flow_data
);
1799 gint
redraw_notify(void *hook_data
, void *call_data
)
1801 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1802 Drawing_t
*drawing
= control_flow_data
->drawing
;
1803 GtkWidget
*widget
= drawing
->drawing_area
;
1805 drawing
->damage_begin
= 0;
1806 drawing
->damage_end
= drawing
->width
;
1808 /* fun feature, to be separated someday... */
1809 drawing_clear(control_flow_data
->drawing
);
1810 processlist_clear(control_flow_data
->process_list
);
1811 gtk_widget_set_size_request(
1812 control_flow_data
->drawing
->drawing_area
,
1813 -1, processlist_get_height(control_flow_data
->process_list
));
1815 rectangle_pixmap (control_flow_data
->process_list
,
1816 widget
->style
->black_gc
,
1819 drawing
->alloc_width
,
1822 gtk_widget_queue_draw(drawing
->drawing_area
);
1824 if(drawing
->damage_begin
< drawing
->damage_end
)
1826 drawing_data_request(drawing
,
1827 drawing
->damage_begin
,
1829 drawing
->damage_end
-drawing
->damage_begin
,
1833 //gtk_widget_queue_draw_area(drawing->drawing_area,
1836 // drawing->height);
1842 gint
continue_notify(void *hook_data
, void *call_data
)
1844 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1845 Drawing_t
*drawing
= control_flow_data
->drawing
;
1847 //g_assert(widget->allocation.width == drawing->damage_end);
1849 if(drawing
->damage_begin
< drawing
->damage_end
)
1851 drawing_data_request(drawing
,
1852 drawing
->damage_begin
,
1854 drawing
->damage_end
-drawing
->damage_begin
,
1862 gint
update_current_time_hook(void *hook_data
, void *call_data
)
1864 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
1865 Drawing_t
*drawing
= control_flow_data
->drawing
;
1867 LttTime current_time
= *((LttTime
*)call_data
);
1869 TimeWindow time_window
=
1870 lttvwindow_get_time_window(control_flow_data
->tab
);
1872 LttTime time_begin
= time_window
.start_time
;
1873 LttTime width
= time_window
.time_width
;
1876 guint64 time_ll
= ltt_time_to_uint64(width
);
1877 time_ll
= time_ll
>> 1; /* divide by two */
1878 half_width
= ltt_time_from_uint64(time_ll
);
1880 LttTime time_end
= ltt_time_add(time_begin
, width
);
1882 LttvTracesetContext
* tsc
=
1883 lttvwindow_get_traceset_context(control_flow_data
->tab
);
1885 LttTime trace_start
= tsc
->time_span
.start_time
;
1886 LttTime trace_end
= tsc
->time_span
.end_time
;
1888 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
1889 current_time
.tv_nsec
);
1893 /* If current time is inside time interval, just move the highlight
1896 /* Else, we have to change the time interval. We have to tell it
1897 * to the main window. */
1898 /* The time interval change will take care of placing the current
1899 * time at the center of the visible area, or nearest possible if we are
1900 * at one end of the trace. */
1903 if(ltt_time_compare(current_time
, time_begin
) < 0)
1905 TimeWindow new_time_window
;
1907 if(ltt_time_compare(current_time
,
1908 ltt_time_add(trace_start
,half_width
)) < 0)
1909 time_begin
= trace_start
;
1911 time_begin
= ltt_time_sub(current_time
,half_width
);
1913 new_time_window
.start_time
= time_begin
;
1914 new_time_window
.time_width
= width
;
1915 new_time_window
.time_width_double
= ltt_time_to_double(width
);
1916 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
1918 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
1920 else if(ltt_time_compare(current_time
, time_end
) > 0)
1922 TimeWindow new_time_window
;
1924 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
1925 time_begin
= ltt_time_sub(trace_end
,width
);
1927 time_begin
= ltt_time_sub(current_time
,half_width
);
1929 new_time_window
.start_time
= time_begin
;
1930 new_time_window
.time_width
= width
;
1931 new_time_window
.time_width_double
= ltt_time_to_double(width
);
1932 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
1934 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
1937 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
1939 /* Update directly when scrolling */
1940 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
1946 typedef struct _ClosureData
{
1947 EventsRequest
*events_request
;
1948 LttvTracesetState
*tss
;
1953 /* Draw line until end of the screen */
1955 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
1957 ResourceInfo
*process_info
= (ResourceInfo
*)key
;
1958 HashedResourceData
*hashed_process_data
= (HashedResourceData
*)value
;
1959 ClosureData
*closure_data
= (ClosureData
*)user_data
;
1961 EventsRequest
*events_request
= closure_data
->events_request
;
1962 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1964 LttvTracesetState
*tss
= closure_data
->tss
;
1965 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)tss
;
1967 LttTime evtime
= closure_data
->end_time
;
1969 gboolean dodraw
= TRUE
;
1972 /* For the process */
1973 /* First, check if the current process is in the state computation
1974 * process list. If it is there, that means we must add it right now and
1975 * draw items from the beginning of the read for it. If it is not
1976 * present, it's a new process and it was not present : it will
1977 * be added after the state update. */
1979 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
1980 #endif //EXTRA_CHECK
1981 LttvTraceContext
*tc
= tsc
->traces
[process_info
->trace_num
];
1982 LttvTraceState
*ts
= (LttvTraceState
*)tc
;
1985 //FIXME : optimize data structures.
1986 LttvTracefileState
*tfs
;
1987 LttvTracefileContext
*tfc
;
1989 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
1990 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
1991 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
1992 && tfs
->cpu
== process_info
->cpu
)
1996 g_assert(i
<tc
->tracefiles
->len
);
1997 tfs
= LTTV_TRACEFILE_STATE(tfc
);
1999 // LttvTracefileState *tfs =
2000 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2001 // tracefiles[process_info->cpu];
2003 // LttvProcessState *process;
2004 // process = lttv_state_find_process(ts, process_info->cpu,
2005 // process_info->pid);
2007 // if(unlikely(process != NULL)) {
2009 // LttvFilter *filter = control_flow_data->filter;
2010 // if(filter != NULL && filter->head != NULL)
2011 // if(!lttv_filter_tree_parse(filter->head,NULL,NULL,
2012 // tc->t,NULL,process,tc))
2015 /* Only draw for processes that are currently in the trace states */
2017 ProcessList
*process_list
= control_flow_data
->process_list
;
2019 /* Should be alike when background info is ready */
2020 if(control_flow_data
->background_info_waiting
==0)
2021 g_assert(ltt_time_compare(process
->creation_time
,
2022 process_info
->birth
) == 0);
2023 #endif //EXTRA_CHECK
2025 /* Now, the process is in the state hash and our own process hash.
2026 * We definitely can draw the items related to the ending state.
2029 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2032 TimeWindow time_window
=
2033 lttvwindow_get_time_window(control_flow_data
->tab
);
2036 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2037 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2039 #endif //EXTRA_CHECK
2040 Drawing_t
*drawing
= control_flow_data
->drawing
;
2041 guint width
= drawing
->width
;
2043 guint x
= closure_data
->x_end
;
2045 DrawContext draw_context
;
2047 /* Now create the drawing context that will be used to draw
2048 * items related to the last state. */
2049 draw_context
.drawable
= hashed_process_data
->pixmap
;
2050 draw_context
.gc
= drawing
->gc
;
2051 draw_context
.pango_layout
= drawing
->pango_layout
;
2052 draw_context
.drawinfo
.end
.x
= x
;
2054 draw_context
.drawinfo
.y
.over
= 1;
2055 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2056 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2058 draw_context
.drawinfo
.start
.offset
.over
= 0;
2059 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2060 draw_context
.drawinfo
.start
.offset
.under
= 0;
2061 draw_context
.drawinfo
.end
.offset
.over
= 0;
2062 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2063 draw_context
.drawinfo
.end
.offset
.under
= 0;
2065 /* Jump over draw if we are at the same x position */
2066 if(x
== hashed_process_data
->x
.over
)
2070 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2072 PropertiesLine prop_line
= prepare_execmode_line(process
);
2073 draw_line((void*)&prop_line
, (void*)&draw_context
);
2075 hashed_process_data
->x
.over
= x
;
2079 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2080 hashed_process_data
->x
.middle_used
)) {
2081 #if 0 /* do not mark closure : not missing information */
2082 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2083 /* Draw collision indicator */
2084 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2085 gdk_draw_point(drawing
->pixmap
,
2089 hashed_process_data
->x
.middle_marked
= TRUE
;
2094 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2097 PropertiesLine prop_line
;
2098 prop_line
.line_width
= STATE_LINE_WIDTH
;
2099 prop_line
.style
= GDK_LINE_SOLID
;
2100 prop_line
.y
= MIDDLE
;
2101 if(process_info
->type
== 0)
2102 cpu_set_line_color(&prop_line
, &ts
->cpu_states
[process_info
->id
]);
2103 else if(process_info
->type
== 1)
2104 irq_set_line_color(&prop_line
, &ts
->irq_states
[process_info
->id
]);
2105 else if(process_info
->type
== 2) {
2106 gint devcode_gint
= process_info
->id
;
2107 LttvBdevState
*bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
2108 // the lookup may return null; bdev_set_line_color must act appropriately
2109 bdev_set_line_color(&prop_line
, bdev
);
2112 draw_line((void*)&prop_line
, (void*)&draw_context
);
2115 /* become the last x position */
2116 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2117 hashed_process_data
->x
.middle
= x
;
2118 /* but don't use the pixel */
2119 hashed_process_data
->x
.middle_used
= FALSE
;
2121 /* Calculate the next good time */
2122 convert_pixels_to_time(width
, x
+1, time_window
,
2123 &hashed_process_data
->next_good_time
);
2132 int before_chunk(void *hook_data
, void *call_data
)
2134 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2135 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2136 ControlFlowData
*cfd
= (ControlFlowData
*)events_request
->viewer_data
;
2138 /* Desactivate sort */
2139 gtk_tree_sortable_set_sort_column_id(
2140 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2142 GTK_SORT_ASCENDING
);
2144 drawing_chunk_begin(events_request
, tss
);
2149 int before_request(void *hook_data
, void *call_data
)
2151 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2152 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2154 drawing_data_request_begin(events_request
, tss
);
2161 * after request is necessary in addition of after chunk in order to draw
2162 * lines until the end of the screen. after chunk just draws lines until
2169 // TODO pmf: reenable this
2170 int after_request(void *hook_data
, void *call_data
)
2172 // EventsRequest *events_request = (EventsRequest*)hook_data;
2173 // ControlFlowData *control_flow_data = events_request->viewer_data;
2174 // LttvTracesetState *tss = (LttvTracesetState*)call_data;
2176 // ProcessList *process_list = control_flow_data->process_list;
2177 // LttTime end_time = events_request->end_time;
2179 // ClosureData closure_data;
2180 // closure_data.events_request = (EventsRequest*)hook_data;
2181 // closure_data.tss = tss;
2182 // closure_data.end_time = end_time;
2184 // TimeWindow time_window =
2185 // lttvwindow_get_time_window(control_flow_data->tab);
2186 // guint width = control_flow_data->drawing->width;
2187 // convert_time_to_pixels(
2191 // &closure_data.x_end);
2194 // /* Draw last items */
2195 // g_hash_table_foreach(process_list->process_hash, draw_closure,
2196 // (void*)&closure_data);
2199 // /* Request expose */
2200 // drawing_request_expose(events_request, tss, end_time);
2209 int after_chunk(void *hook_data
, void *call_data
)
2211 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2212 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2213 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2214 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)call_data
;
2215 LttvTracefileContext
*tfc
= lttv_traceset_context_get_current_tfc(tsc
);
2218 ProcessList
*process_list
= control_flow_data
->process_list
;
2220 LttvTraceset
*traceset
= tsc
->ts
;
2221 guint nb_trace
= lttv_traceset_number(traceset
);
2223 /* Only execute when called for the first trace's events request */
2224 if(!process_list
->current_hash_data
) return;
2226 for(i
= 0 ; i
< nb_trace
; i
++) {
2227 g_free(process_list
->current_hash_data
[i
]);
2229 g_free(process_list
->current_hash_data
);
2230 process_list
->current_hash_data
= NULL
;
2233 end_time
= LTT_TIME_MIN(tfc
->timestamp
, events_request
->end_time
);
2234 else /* end of traceset, or position now out of request : end */
2235 end_time
= events_request
->end_time
;
2237 ClosureData closure_data
;
2238 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2239 closure_data
.tss
= tss
;
2240 closure_data
.end_time
= end_time
;
2242 TimeWindow time_window
=
2243 lttvwindow_get_time_window(control_flow_data
->tab
);
2244 guint width
= control_flow_data
->drawing
->width
;
2245 convert_time_to_pixels(
2249 &closure_data
.x_end
);
2251 /* Draw last items */
2252 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2253 (void*)&closure_data
);
2255 /* Reactivate sort */
2256 gtk_tree_sortable_set_sort_column_id(
2257 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2258 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2259 GTK_SORT_ASCENDING
);
2261 update_index_to_pixmap(control_flow_data
->process_list
);
2262 /* Request a full expose : drawing scrambled */
2263 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2265 /* Request expose (updates damages zone also) */
2266 drawing_request_expose(events_request
, tss
, end_time
);
2271 /* after_statedump_end
2273 * @param hook_data ControlFlowData structure of the viewer.
2274 * @param call_data Event context.
2276 * This function adds items to be drawn in a queue for each process.
2279 int before_statedump_end(void *hook_data
, void *call_data
)
2281 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
2282 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
2283 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2285 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2287 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
2289 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
2291 LttvTracesetState
*tss
= (LttvTracesetState
*)tfc
->t_context
->ts_context
;
2292 ProcessList
*process_list
= control_flow_data
->process_list
;
2295 e
= ltt_tracefile_get_event(tfc
->tf
);
2297 LttvFilter
*filter
= control_flow_data
->filter
;
2298 if(filter
!= NULL
&& filter
->head
!= NULL
)
2299 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2300 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2303 LttTime evtime
= ltt_event_time(e
);
2305 ClosureData closure_data
;
2306 closure_data
.events_request
= events_request
;
2307 closure_data
.tss
= tss
;
2308 closure_data
.end_time
= evtime
;
2310 TimeWindow time_window
=
2311 lttvwindow_get_time_window(control_flow_data
->tab
);
2312 guint width
= control_flow_data
->drawing
->width
;
2313 convert_time_to_pixels(
2317 &closure_data
.x_end
);
2319 /* Draw last items */
2320 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2321 (void*)&closure_data
);
2323 /* Reactivate sort */
2324 gtk_tree_sortable_set_sort_column_id(
2325 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2326 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2327 GTK_SORT_ASCENDING
);
2329 update_index_to_pixmap(control_flow_data
->process_list
);
2330 /* Request a full expose : drawing scrambled */
2331 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2333 /* Request expose (updates damages zone also) */
2334 drawing_request_expose(events_request
, tss
, evtime
);