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
;
324 if(s
->mode_stack
->len
== 0)
325 present_state
= LTTV_CPU_UNKNOWN
;
327 present_state
= ((GQuark
*)s
->mode_stack
->data
)[s
->mode_stack
->len
-1];
329 if(present_state
== LTTV_CPU_IDLE
) {
330 prop_line
->color
= drawing_colors_cpu
[COL_CPU_IDLE
];
332 else if(present_state
== LTTV_CPU_BUSY
) {
333 prop_line
->color
= drawing_colors_cpu
[COL_CPU_BUSY
];
335 else if(present_state
== LTTV_CPU_IRQ
) {
336 prop_line
->color
= drawing_colors_cpu
[COL_CPU_IRQ
];
338 else if(present_state
== LTTV_CPU_TRAP
) {
339 prop_line
->color
= drawing_colors_cpu
[COL_CPU_TRAP
];
341 prop_line
->color
= drawing_colors_cpu
[COL_CPU_UNKNOWN
];
345 static void irq_set_line_color(PropertiesLine
*prop_line
, LttvIRQState
*s
)
347 GQuark present_state
;
348 if(s
->mode_stack
->len
== 0)
349 present_state
= LTTV_IRQ_UNKNOWN
;
351 present_state
= ((GQuark
*)s
->mode_stack
->data
)[s
->mode_stack
->len
-1];
353 if(present_state
== LTTV_IRQ_IDLE
) {
354 prop_line
->color
= drawing_colors_irq
[COL_IRQ_IDLE
];
356 else if(present_state
== LTTV_IRQ_BUSY
) {
357 prop_line
->color
= drawing_colors_irq
[COL_IRQ_BUSY
];
360 prop_line
->color
= drawing_colors_irq
[COL_IRQ_UNKNOWN
];
364 static void bdev_set_line_color(PropertiesLine
*prop_line
, LttvBdevState
*s
)
366 GQuark present_state
;
367 if(s
->mode_stack
->len
== 0)
368 present_state
= LTTV_BDEV_UNKNOWN
;
370 present_state
= ((GQuark
*)s
->mode_stack
->data
)[s
->mode_stack
->len
-1];
372 if(present_state
== LTTV_BDEV_IDLE
) {
373 prop_line
->color
= drawing_colors_bdev
[COL_BDEV_IDLE
];
375 else if(present_state
== LTTV_BDEV_BUSY_READING
) {
376 prop_line
->color
= drawing_colors_bdev
[COL_BDEV_BUSY_READING
];
378 else if(present_state
== LTTV_BDEV_BUSY_WRITING
) {
379 prop_line
->color
= drawing_colors_bdev
[COL_BDEV_BUSY_WRITING
];
382 prop_line
->color
= drawing_colors_bdev
[COL_BDEV_UNKNOWN
];
386 /* before_schedchange_hook
388 * This function basically draw lines and icons. Two types of lines are drawn :
389 * one small (3 pixels?) representing the state of the process and the second
390 * type is thicker (10 pixels?) representing on which CPU a process is running
391 * (and this only in running state).
393 * Extremums of the lines :
394 * x_min : time of the last event context for this process kept in memory.
395 * x_max : time of the current event.
396 * y : middle of the process in the process list. The process is found in the
397 * list, therefore is it's position in pixels.
399 * The choice of lines'color is defined by the context of the last event for this
404 int before_schedchange_hook(void *hook_data
, void *call_data
)
406 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
407 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
408 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
410 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
412 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
413 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
416 e
= ltt_tracefile_get_event(tfc
->tf
);
417 gint target_pid_saved
= tfc
->target_pid
;
419 LttTime evtime
= ltt_event_time(e
);
420 LttvFilter
*filter
= control_flow_data
->filter
;
424 /* we are in a schedchange, before the state update. We must draw the
425 * items corresponding to the state before it changes : now is the right
431 pid_out
= ltt_event_get_long_unsigned(e
, thf
->f1
);
432 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f2
);
433 // if(pid_in != 0 && pid_out != 0) {
434 // /* not a transition to/from idle */
438 tfc
->target_pid
= pid_out
;
439 // if(!filter || !filter->head ||
440 // lttv_filter_tree_parse(filter->head,e,tfc->tf,
441 // tfc->t_context->t,tfc,NULL,NULL)) {
442 /* For the pid_out */
443 /* First, check if the current process is in the state computation
444 * process list. If it is there, that means we must add it right now and
445 * draw items from the beginning of the read for it. If it is not
446 * present, it's a new process and it was not present : it will
447 * be added after the state update. */
448 guint cpu
= tfs
->cpu
;
451 cpustr
= g_strdup_printf("CPU%u", cpu
);
452 cpuq
= g_quark_from_string(cpustr
);
456 guint trace_num
= ts
->parent
.index
;
457 // LttvProcessState *process = ts->running_process[cpu];
458 /* unknown state, bad current pid */
459 // if(process->pid != pid_out)
460 // process = lttv_state_find_process(ts,
461 // tfs->cpu, pid_out);
463 // if(process != NULL) {
464 /* Well, the process_out existed : we must get it in the process hash
465 * or add it, and draw its items.
467 /* Add process to process list (if not present) */
469 HashedResourceData
*hashed_process_data
= NULL
;
470 ProcessList
*process_list
= control_flow_data
->process_list
;
471 // LttTime birth = process->creation_time;
473 hashed_process_data
= processlist_get_process_data(process_list
, cpuq
, trace_num
);
474 // hashed_process_data = processlist_get_process_data(process_list,
479 if(hashed_process_data
== NULL
)
481 // g_assert(pid_out == 0 || pid_out != process->ppid);
482 /* Process not present */
483 ResourceInfo
*process_info
;
484 Drawing_t
*drawing
= control_flow_data
->drawing
;
485 resourcelist_add(process_list
,
488 cpuq
, //process->name,
493 &hashed_process_data
);
494 gtk_widget_set_size_request(drawing
->drawing_area
,
497 gtk_widget_queue_draw(drawing
->drawing_area
);
501 /* Now, the process is in the state hash and our own process hash.
502 * We definitely can draw the items related to the ending state.
505 if(ltt_time_compare(hashed_process_data
->next_good_time
,
508 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
510 TimeWindow time_window
=
511 lttvwindow_get_time_window(control_flow_data
->tab
);
513 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
514 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
517 Drawing_t
*drawing
= control_flow_data
->drawing
;
518 guint width
= drawing
->width
;
520 convert_time_to_pixels(
526 /* Draw collision indicator */
527 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
528 gdk_draw_point(hashed_process_data
->pixmap
,
531 COLLISION_POSITION(hashed_process_data
->height
));
532 hashed_process_data
->x
.middle_marked
= TRUE
;
535 TimeWindow time_window
=
536 lttvwindow_get_time_window(control_flow_data
->tab
);
538 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
539 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
542 Drawing_t
*drawing
= control_flow_data
->drawing
;
543 guint width
= drawing
->width
;
545 convert_time_to_pixels(
552 /* Jump over draw if we are at the same x position */
553 if(x
== hashed_process_data
->x
.middle
&&
554 hashed_process_data
->x
.middle_used
)
556 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
557 /* Draw collision indicator */
558 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
559 gdk_draw_point(hashed_process_data
->pixmap
,
562 COLLISION_POSITION(hashed_process_data
->height
));
563 hashed_process_data
->x
.middle_marked
= TRUE
;
567 DrawContext draw_context
;
569 /* Now create the drawing context that will be used to draw
570 * items related to the last state. */
571 draw_context
.drawable
= hashed_process_data
->pixmap
;
572 draw_context
.gc
= drawing
->gc
;
573 draw_context
.pango_layout
= drawing
->pango_layout
;
574 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
575 draw_context
.drawinfo
.end
.x
= x
;
577 draw_context
.drawinfo
.y
.over
= 1;
578 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
579 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
581 draw_context
.drawinfo
.start
.offset
.over
= 0;
582 draw_context
.drawinfo
.start
.offset
.middle
= 0;
583 draw_context
.drawinfo
.start
.offset
.under
= 0;
584 draw_context
.drawinfo
.end
.offset
.over
= 0;
585 draw_context
.drawinfo
.end
.offset
.middle
= 0;
586 draw_context
.drawinfo
.end
.offset
.under
= 0;
590 //PropertiesLine prop_line = prepare_s_e_line(process);
591 PropertiesLine prop_line
;
592 prop_line
.line_width
= STATE_LINE_WIDTH
;
593 prop_line
.style
= GDK_LINE_SOLID
;
594 prop_line
.y
= MIDDLE
;
595 cpu_set_line_color(&prop_line
, tfs
->cpu_state
);
596 draw_line((void*)&prop_line
, (void*)&draw_context
);
599 /* become the last x position */
600 hashed_process_data
->x
.middle
= x
;
601 hashed_process_data
->x
.middle_used
= TRUE
;
602 hashed_process_data
->x
.middle_marked
= FALSE
;
604 /* Calculate the next good time */
605 convert_pixels_to_time(width
, x
+1, time_window
,
606 &hashed_process_data
->next_good_time
);
612 // tfc->target_pid = pid_in;
613 // if(!filter || !filter->head ||
614 // lttv_filter_tree_parse(filter->head,e,tfc->tf,
615 // tfc->t_context->t,tfc,NULL,NULL)) {
616 // /* For the pid_in */
617 // /* First, check if the current process is in the state computation
618 // * process list. If it is there, that means we must add it right now and
619 // * draw items from the beginning of the read for it. If it is not
620 // * present, it's a new process and it was not present : it will
621 // * be added after the state update. */
622 // LttvProcessState *process;
623 // process = lttv_state_find_process(ts,
624 // tfs->cpu, pid_in);
625 // guint trace_num = ts->parent.index;
627 // if(process != NULL) {
628 // /* Well, the process existed : we must get it in the process hash
629 // * or add it, and draw its items.
631 // /* Add process to process list (if not present) */
632 // guint pl_height = 0;
633 // HashedResourceData *hashed_process_data = NULL;
634 // ProcessList *process_list = control_flow_data->process_list;
635 // LttTime birth = process->creation_time;
637 // hashed_process_data = processlist_get_process_data(process_list, cpuq);
638 //// hashed_process_data = processlist_get_process_data(process_list,
643 // if(hashed_process_data == NULL)
645 // g_assert(pid_in == 0 || pid_in != process->ppid);
646 // /* Process not present */
647 // ResourceInfo *process_info;
648 // Drawing_t *drawing = control_flow_data->drawing;
649 // resourcelist_add(process_list,
661 // &hashed_process_data);
662 // gtk_widget_set_size_request(drawing->drawing_area,
665 // gtk_widget_queue_draw(drawing->drawing_area);
668 // //We could set the current process and hash here, but will be done
669 // //by after schedchange hook
671 // /* Now, the process is in the state hash and our own process hash.
672 // * We definitely can draw the items related to the ending state.
675 // if(ltt_time_compare(hashed_process_data->next_good_time,
678 // if(hashed_process_data->x.middle_marked == FALSE) {
680 // TimeWindow time_window =
681 // lttvwindow_get_time_window(control_flow_data->tab);
683 // if(ltt_time_compare(evtime, time_window.start_time) == -1
684 // || ltt_time_compare(evtime, time_window.end_time) == 1)
686 //#endif //EXTRA_CHECK
687 // Drawing_t *drawing = control_flow_data->drawing;
688 // guint width = drawing->width;
690 // convert_time_to_pixels(
696 // /* Draw collision indicator */
697 // gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
698 // gdk_draw_point(hashed_process_data->pixmap,
701 // COLLISION_POSITION(hashed_process_data->height));
702 // hashed_process_data->x.middle_marked = TRUE;
705 // TimeWindow time_window =
706 // lttvwindow_get_time_window(control_flow_data->tab);
708 // if(ltt_time_compare(evtime, time_window.start_time) == -1
709 // || ltt_time_compare(evtime, time_window.end_time) == 1)
711 //#endif //EXTRA_CHECK
712 // Drawing_t *drawing = control_flow_data->drawing;
713 // guint width = drawing->width;
716 // convert_time_to_pixels(
723 // /* Jump over draw if we are at the same x position */
724 // if(x == hashed_process_data->x.middle &&
725 // hashed_process_data->x.middle_used)
727 // if(hashed_process_data->x.middle_marked == FALSE) {
728 // /* Draw collision indicator */
729 // gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
730 // gdk_draw_point(hashed_process_data->pixmap,
733 // COLLISION_POSITION(hashed_process_data->height));
734 // hashed_process_data->x.middle_marked = TRUE;
738 // DrawContext draw_context;
740 // /* Now create the drawing context that will be used to draw
741 // * items related to the last state. */
742 // draw_context.drawable = hashed_process_data->pixmap;
743 // draw_context.gc = drawing->gc;
744 // draw_context.pango_layout = drawing->pango_layout;
745 // draw_context.drawinfo.start.x = hashed_process_data->x.middle;
746 // draw_context.drawinfo.end.x = x;
748 // draw_context.drawinfo.y.over = 1;
749 // draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
750 // draw_context.drawinfo.y.under = hashed_process_data->height;
752 // draw_context.drawinfo.start.offset.over = 0;
753 // draw_context.drawinfo.start.offset.middle = 0;
754 // draw_context.drawinfo.start.offset.under = 0;
755 // draw_context.drawinfo.end.offset.over = 0;
756 // draw_context.drawinfo.end.offset.middle = 0;
757 // draw_context.drawinfo.end.offset.under = 0;
760 // /* Draw the line */
761 // PropertiesLine prop_line = prepare_s_e_line(process);
762 // draw_line((void*)&prop_line, (void*)&draw_context);
766 // /* become the last x position */
767 // hashed_process_data->x.middle = x;
768 // hashed_process_data->x.middle_used = TRUE;
769 // hashed_process_data->x.middle_marked = FALSE;
771 // /* Calculate the next good time */
772 // convert_pixels_to_time(width, x+1, time_window,
773 // &hashed_process_data->next_good_time);
777 // g_warning("Cannot find pin_in in schedchange %u", pid_in);
779 // tfc->target_pid = target_pid_saved;
787 GString
*string
= g_string_new("");;
788 gboolean field_names
= TRUE
, state
= TRUE
;
790 lttv_event_to_string(e
, tfc
->tf
, string
, TRUE
, field_names
, tfs
);
791 g_string_append_printf(string
,"\n");
794 g_string_append_printf(string
, " %s",
795 g_quark_to_string(tfs
->process
->state
->s
));
798 g_info("%s",string
->str
);
800 g_string_free(string
, TRUE
);
802 /* End of text dump */
807 /* after_schedchange_hook
809 * The draw after hook is called by the reading API to have a
810 * particular event drawn on the screen.
811 * @param hook_data ControlFlowData structure of the viewer.
812 * @param call_data Event context.
814 * This function adds items to be drawn in a queue for each process.
817 int after_schedchange_hook(void *hook_data
, void *call_data
)
819 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
820 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
821 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
823 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
825 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
827 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
830 e
= ltt_tracefile_get_event(tfc
->tf
);
832 LttvFilter
*filter
= control_flow_data
->filter
;
833 if(filter
!= NULL
&& filter
->head
!= NULL
)
834 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
835 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
838 LttTime evtime
= ltt_event_time(e
);
842 /* Add process to process list (if not present) */
843 LttvProcessState
*process_in
;
846 HashedResourceData
*hashed_process_data_in
= NULL
;
848 ProcessList
*process_list
= control_flow_data
->process_list
;
853 pid_out
= ltt_event_get_long_unsigned(e
, thf
->f1
);
854 pid_in
= ltt_event_get_long_unsigned(e
, thf
->f2
);
858 /* Find process pid_in in the list... */
859 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
860 //process_in = tfs->process;
861 guint cpu
= tfs
->cpu
;
864 cpustr
= g_strdup_printf("CPU%u", cpu
);
865 cpuq
= g_quark_from_string(cpustr
);
868 guint trace_num
= ts
->parent
.index
;
869 process_in
= ts
->running_process
[cpu
];
870 /* It should exist, because we are after the state update. */
872 g_assert(process_in
!= NULL
);
874 birth
= process_in
->creation_time
;
876 hashed_process_data_in
= processlist_get_process_data(process_list
, cpuq
, trace_num
);
877 // hashed_process_data_in = processlist_get_process_data(process_list,
882 if(hashed_process_data_in
== NULL
)
884 g_assert(pid_in
== 0 || pid_in
!= process_in
->ppid
);
885 ResourceInfo
*process_info
;
886 Drawing_t
*drawing
= control_flow_data
->drawing
;
887 /* Process not present */
888 resourcelist_add(process_list
,
896 &hashed_process_data_in
);
897 gtk_widget_set_size_request(drawing
->drawing_area
,
900 gtk_widget_queue_draw(drawing
->drawing_area
);
902 /* Set the current process */
903 process_list
->current_hash_data
[trace_num
][process_in
->cpu
] =
904 hashed_process_data_in
;
906 if(ltt_time_compare(hashed_process_data_in
->next_good_time
,
909 TimeWindow time_window
=
910 lttvwindow_get_time_window(control_flow_data
->tab
);
913 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
914 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
917 Drawing_t
*drawing
= control_flow_data
->drawing
;
918 guint width
= drawing
->width
;
921 convert_time_to_pixels(
927 if(hashed_process_data_in
->x
.middle
!= new_x
) {
928 hashed_process_data_in
->x
.middle
= new_x
;
929 hashed_process_data_in
->x
.middle_used
= FALSE
;
930 hashed_process_data_in
->x
.middle_marked
= FALSE
;
936 /* before_execmode_hook
938 * This function basically draw lines and icons. Two types of lines are drawn :
939 * one small (3 pixels?) representing the state of the process and the second
940 * type is thicker (10 pixels?) representing on which CPU a process is running
941 * (and this only in running state).
943 * Extremums of the lines :
944 * x_min : time of the last event context for this process kept in memory.
945 * x_max : time of the current event.
946 * y : middle of the process in the process list. The process is found in the
947 * list, therefore is it's position in pixels.
949 * The choice of lines'color is defined by the context of the last event for this
953 int before_execmode_hook(void *hook_data
, void *call_data
)
955 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
956 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
957 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
959 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
961 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
962 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
965 e
= ltt_tracefile_get_event(tfc
->tf
);
967 LttTime evtime
= ltt_event_time(e
);
971 before_execmode_hook_irq(hook_data
, call_data
);
973 /* we are in a execmode, before the state update. We must draw the
974 * items corresponding to the state before it changes : now is the right
978 //LttvProcessState *process = tfs->process;
979 guint cpu
= tfs
->cpu
;
982 cpustr
= g_strdup_printf("CPU%u", cpu
);
983 cpuq
= g_quark_from_string(cpustr
);
986 guint trace_num
= ts
->parent
.index
;
987 LttvProcessState
*process
= ts
->running_process
[cpu
];
988 g_assert(process
!= NULL
);
990 // guint pid = process->pid;
992 /* Well, the process_out existed : we must get it in the process hash
993 * or add it, and draw its items.
995 /* Add process to process list (if not present) */
997 HashedResourceData
*hashed_process_data
= NULL
;
998 ProcessList
*process_list
= control_flow_data
->process_list
;
999 LttTime birth
= process
->creation_time
;
1001 if(likely(process_list
->current_hash_data
[trace_num
][cpu
] != NULL
)) {
1002 hashed_process_data
= process_list
->current_hash_data
[trace_num
][cpu
];
1004 hashed_process_data
= processlist_get_process_data(process_list
, cpuq
, trace_num
);
1005 // hashed_process_data = processlist_get_process_data(process_list,
1010 if(unlikely(hashed_process_data
== NULL
))
1012 //g_assert(pid == 0 || pid != process->ppid);
1013 ResourceInfo
*process_info
;
1014 /* Process not present */
1015 Drawing_t
*drawing
= control_flow_data
->drawing
;
1016 resourcelist_add(process_list
,
1019 cpuq
, //process->name,
1024 &hashed_process_data
);
1025 gtk_widget_set_size_request(drawing
->drawing_area
,
1028 gtk_widget_queue_draw(drawing
->drawing_area
);
1030 /* Set the current process */
1031 process_list
->current_hash_data
[trace_num
][process
->cpu
] =
1032 hashed_process_data
;
1035 /* Now, the process is in the state hash and our own process hash.
1036 * We definitely can draw the items related to the ending state.
1039 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1042 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1043 TimeWindow time_window
=
1044 lttvwindow_get_time_window(control_flow_data
->tab
);
1047 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1048 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1050 #endif //EXTRA_CHECK
1051 Drawing_t
*drawing
= control_flow_data
->drawing
;
1052 guint width
= drawing
->width
;
1054 convert_time_to_pixels(
1060 /* Draw collision indicator */
1061 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1062 gdk_draw_point(hashed_process_data
->pixmap
,
1065 COLLISION_POSITION(hashed_process_data
->height
));
1066 hashed_process_data
->x
.middle_marked
= TRUE
;
1070 TimeWindow time_window
=
1071 lttvwindow_get_time_window(control_flow_data
->tab
);
1074 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1075 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1077 #endif //EXTRA_CHECK
1078 Drawing_t
*drawing
= control_flow_data
->drawing
;
1079 guint width
= drawing
->width
;
1082 convert_time_to_pixels(
1089 /* Jump over draw if we are at the same x position */
1090 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1091 hashed_process_data
->x
.middle_used
))
1093 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1094 /* Draw collision indicator */
1095 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1096 gdk_draw_point(hashed_process_data
->pixmap
,
1099 COLLISION_POSITION(hashed_process_data
->height
));
1100 hashed_process_data
->x
.middle_marked
= TRUE
;
1106 DrawContext draw_context
;
1107 /* Now create the drawing context that will be used to draw
1108 * items related to the last state. */
1109 draw_context
.drawable
= hashed_process_data
->pixmap
;
1110 draw_context
.gc
= drawing
->gc
;
1111 draw_context
.pango_layout
= drawing
->pango_layout
;
1112 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1113 draw_context
.drawinfo
.end
.x
= x
;
1115 draw_context
.drawinfo
.y
.over
= 1;
1116 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1117 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1119 draw_context
.drawinfo
.start
.offset
.over
= 0;
1120 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1121 draw_context
.drawinfo
.start
.offset
.under
= 0;
1122 draw_context
.drawinfo
.end
.offset
.over
= 0;
1123 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1124 draw_context
.drawinfo
.end
.offset
.under
= 0;
1128 PropertiesLine prop_line
;
1129 prop_line
.line_width
= STATE_LINE_WIDTH
;
1130 prop_line
.style
= GDK_LINE_SOLID
;
1131 prop_line
.y
= MIDDLE
;
1132 cpu_set_line_color(&prop_line
, tfs
->cpu_state
);
1133 draw_line((void*)&prop_line
, (void*)&draw_context
);
1135 /* become the last x position */
1136 hashed_process_data
->x
.middle
= x
;
1137 hashed_process_data
->x
.middle_used
= TRUE
;
1138 hashed_process_data
->x
.middle_marked
= FALSE
;
1140 /* Calculate the next good time */
1141 convert_pixels_to_time(width
, x
+1, time_window
,
1142 &hashed_process_data
->next_good_time
);
1149 int before_execmode_hook_irq(void *hook_data
, void *call_data
)
1151 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1152 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1153 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1155 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1157 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1158 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1161 e
= ltt_tracefile_get_event(tfc
->tf
);
1163 LttTime evtime
= ltt_event_time(e
);
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 LttFacility
*ev_facility
= ltt_event_facility(e
);
1177 if(ltt_facility_name(ev_facility
) != LTT_FACILITY_KERNEL
)
1179 guint8 ev_id_entry
= ltt_eventtype_id(ltt_facility_eventtype_get_by_name(ev_facility
, LTT_EVENT_IRQ_ENTRY
));
1180 guint8 ev_id_exit
= ltt_eventtype_id(ltt_facility_eventtype_get_by_name(ev_facility
, LTT_EVENT_IRQ_EXIT
));
1181 if(ltt_facility_name(ev_facility
) == LTT_FACILITY_KERNEL
&&
1182 ev_id_entry
== ltt_event_eventtype_id(e
)) {
1183 irq
= ltt_event_get_long_unsigned(e
, thf
->f1
);
1185 else if(ltt_facility_name(ev_facility
) == LTT_FACILITY_KERNEL
&&
1186 ev_id_exit
== ltt_event_eventtype_id(e
)) {
1187 irq
= ts
->cpu_states
[cpu
].last_irq
;
1195 irqstr
= g_strdup_printf("IRQ %u", irq
);
1196 resourceq
= g_quark_from_string(irqstr
);
1199 guint trace_num
= ts
->parent
.index
;
1201 // guint pid = process->pid;
1203 /* Well, the process_out existed : we must get it in the process hash
1204 * or add it, and draw its items.
1206 /* Add process to process list (if not present) */
1207 guint pl_height
= 0;
1208 HashedResourceData
*hashed_process_data
= NULL
;
1209 ProcessList
*process_list
= control_flow_data
->process_list
;
1210 // LttTime birth = process->creation_time;
1212 // if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1213 // hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1215 hashed_process_data
= processlist_get_process_data(process_list
, resourceq
, trace_num
);
1216 // hashed_process_data = processlist_get_process_data(process_list,
1221 if(unlikely(hashed_process_data
== NULL
))
1223 //g_assert(pid == 0 || pid != process->ppid);
1224 ResourceInfo
*process_info
;
1225 /* Process not present */
1226 Drawing_t
*drawing
= control_flow_data
->drawing
;
1227 resourcelist_add(process_list
,
1230 resourceq
, //process->name,
1235 &hashed_process_data
);
1236 gtk_widget_set_size_request(drawing
->drawing_area
,
1239 gtk_widget_queue_draw(drawing
->drawing_area
);
1241 /* Set the current process */
1242 // process_list->current_hash_data[trace_num][process->cpu] =
1243 // hashed_process_data;
1246 /* Now, the process is in the state hash and our own process hash.
1247 * We definitely can draw the items related to the ending state.
1250 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1253 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1254 TimeWindow time_window
=
1255 lttvwindow_get_time_window(control_flow_data
->tab
);
1258 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1259 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1261 #endif //EXTRA_CHECK
1262 Drawing_t
*drawing
= control_flow_data
->drawing
;
1263 guint width
= drawing
->width
;
1265 convert_time_to_pixels(
1271 /* Draw collision indicator */
1272 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1273 gdk_draw_point(hashed_process_data
->pixmap
,
1276 COLLISION_POSITION(hashed_process_data
->height
));
1277 hashed_process_data
->x
.middle_marked
= TRUE
;
1281 TimeWindow time_window
=
1282 lttvwindow_get_time_window(control_flow_data
->tab
);
1285 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1286 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1288 #endif //EXTRA_CHECK
1289 Drawing_t
*drawing
= control_flow_data
->drawing
;
1290 guint width
= drawing
->width
;
1293 convert_time_to_pixels(
1300 /* Jump over draw if we are at the same x position */
1301 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1302 hashed_process_data
->x
.middle_used
))
1304 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1305 /* Draw collision indicator */
1306 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1307 gdk_draw_point(hashed_process_data
->pixmap
,
1310 COLLISION_POSITION(hashed_process_data
->height
));
1311 hashed_process_data
->x
.middle_marked
= TRUE
;
1317 DrawContext draw_context
;
1318 /* Now create the drawing context that will be used to draw
1319 * items related to the last state. */
1320 draw_context
.drawable
= hashed_process_data
->pixmap
;
1321 draw_context
.gc
= drawing
->gc
;
1322 draw_context
.pango_layout
= drawing
->pango_layout
;
1323 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1324 draw_context
.drawinfo
.end
.x
= x
;
1326 draw_context
.drawinfo
.y
.over
= 1;
1327 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1328 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1330 draw_context
.drawinfo
.start
.offset
.over
= 0;
1331 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1332 draw_context
.drawinfo
.start
.offset
.under
= 0;
1333 draw_context
.drawinfo
.end
.offset
.over
= 0;
1334 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1335 draw_context
.drawinfo
.end
.offset
.under
= 0;
1339 PropertiesLine prop_line
;
1340 prop_line
.line_width
= STATE_LINE_WIDTH
;
1341 prop_line
.style
= GDK_LINE_SOLID
;
1342 prop_line
.y
= MIDDLE
;
1343 irq_set_line_color(&prop_line
, &ts
->irq_states
[irq
]);
1344 draw_line((void*)&prop_line
, (void*)&draw_context
);
1346 /* become the last x position */
1347 hashed_process_data
->x
.middle
= x
;
1348 hashed_process_data
->x
.middle_used
= TRUE
;
1349 hashed_process_data
->x
.middle_marked
= FALSE
;
1351 /* Calculate the next good time */
1352 convert_pixels_to_time(width
, x
+1, time_window
,
1353 &hashed_process_data
->next_good_time
);
1360 int before_bdev_event_hook(void *hook_data
, void *call_data
)
1362 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
1363 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
1364 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1366 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1368 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
1369 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
1372 e
= ltt_tracefile_get_event(tfc
->tf
);
1374 LttTime evtime
= ltt_event_time(e
);
1378 /* we are in a execmode, before the state update. We must draw the
1379 * items corresponding to the state before it changes : now is the right
1384 guint cpu
= tfs
->cpu
;
1385 guint8 major
= ltt_event_get_long_unsigned(e
, thf
->f1
);
1386 guint8 minor
= ltt_event_get_long_unsigned(e
, thf
->f2
);
1387 guint oper
= ltt_event_get_long_unsigned(e
, thf
->f3
);
1388 gint devcode_gint
= MKDEV(major
,minor
);
1392 resourcestr
= g_strdup_printf("Blockdev (%u,%u)", major
, minor
);
1393 resourceq
= g_quark_from_string(resourcestr
);
1394 g_free(resourcestr
);
1396 guint trace_num
= ts
->parent
.index
;
1398 LttvBdevState
*bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
1399 g_assert(bdev
!= NULL
);
1401 // guint pid = process->pid;
1403 /* Well, the process_out existed : we must get it in the process hash
1404 * or add it, and draw its items.
1406 /* Add process to process list (if not present) */
1407 guint pl_height
= 0;
1408 HashedResourceData
*hashed_process_data
= NULL
;
1409 ProcessList
*process_list
= control_flow_data
->process_list
;
1410 // LttTime birth = process->creation_time;
1412 // if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1413 // hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1415 hashed_process_data
= processlist_get_process_data(process_list
, resourceq
, trace_num
);
1416 // hashed_process_data = processlist_get_process_data(process_list,
1421 if(unlikely(hashed_process_data
== NULL
))
1423 //g_assert(pid == 0 || pid != process->ppid);
1424 ResourceInfo
*process_info
;
1425 /* Process not present */
1426 Drawing_t
*drawing
= control_flow_data
->drawing
;
1427 resourcelist_add(process_list
,
1430 resourceq
, //process->name,
1432 devcode_gint
, /* MKDEV(major,minor) */
1435 &hashed_process_data
);
1436 gtk_widget_set_size_request(drawing
->drawing_area
,
1439 gtk_widget_queue_draw(drawing
->drawing_area
);
1441 /* Set the current process */
1442 // process_list->current_hash_data[trace_num][process->cpu] =
1443 // hashed_process_data;
1446 /* Now, the process is in the state hash and our own process hash.
1447 * We definitely can draw the items related to the ending state.
1450 if(likely(ltt_time_compare(hashed_process_data
->next_good_time
,
1453 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1454 TimeWindow time_window
=
1455 lttvwindow_get_time_window(control_flow_data
->tab
);
1458 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1459 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1461 #endif //EXTRA_CHECK
1462 Drawing_t
*drawing
= control_flow_data
->drawing
;
1463 guint width
= drawing
->width
;
1465 convert_time_to_pixels(
1471 /* Draw collision indicator */
1472 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1473 gdk_draw_point(hashed_process_data
->pixmap
,
1476 COLLISION_POSITION(hashed_process_data
->height
));
1477 hashed_process_data
->x
.middle_marked
= TRUE
;
1481 TimeWindow time_window
=
1482 lttvwindow_get_time_window(control_flow_data
->tab
);
1485 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
1486 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
1488 #endif //EXTRA_CHECK
1489 Drawing_t
*drawing
= control_flow_data
->drawing
;
1490 guint width
= drawing
->width
;
1493 convert_time_to_pixels(
1500 /* Jump over draw if we are at the same x position */
1501 if(unlikely(x
== hashed_process_data
->x
.middle
&&
1502 hashed_process_data
->x
.middle_used
))
1504 if(unlikely(hashed_process_data
->x
.middle_marked
== FALSE
)) {
1505 /* Draw collision indicator */
1506 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
1507 gdk_draw_point(hashed_process_data
->pixmap
,
1510 COLLISION_POSITION(hashed_process_data
->height
));
1511 hashed_process_data
->x
.middle_marked
= TRUE
;
1517 DrawContext draw_context
;
1518 /* Now create the drawing context that will be used to draw
1519 * items related to the last state. */
1520 draw_context
.drawable
= hashed_process_data
->pixmap
;
1521 draw_context
.gc
= drawing
->gc
;
1522 draw_context
.pango_layout
= drawing
->pango_layout
;
1523 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
1524 draw_context
.drawinfo
.end
.x
= x
;
1526 draw_context
.drawinfo
.y
.over
= 1;
1527 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
1528 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
1530 draw_context
.drawinfo
.start
.offset
.over
= 0;
1531 draw_context
.drawinfo
.start
.offset
.middle
= 0;
1532 draw_context
.drawinfo
.start
.offset
.under
= 0;
1533 draw_context
.drawinfo
.end
.offset
.over
= 0;
1534 draw_context
.drawinfo
.end
.offset
.middle
= 0;
1535 draw_context
.drawinfo
.end
.offset
.under
= 0;
1539 PropertiesLine prop_line
;
1540 prop_line
.line_width
= STATE_LINE_WIDTH
;
1541 prop_line
.style
= GDK_LINE_SOLID
;
1542 prop_line
.y
= MIDDLE
;
1543 bdev_set_line_color(&prop_line
, bdev
);
1544 draw_line((void*)&prop_line
, (void*)&draw_context
);
1546 /* become the last x position */
1547 hashed_process_data
->x
.middle
= x
;
1548 hashed_process_data
->x
.middle_used
= TRUE
;
1549 hashed_process_data
->x
.middle_marked
= FALSE
;
1551 /* Calculate the next good time */
1552 convert_pixels_to_time(width
, x
+1, time_window
,
1553 &hashed_process_data
->next_good_time
);
1560 gint
update_time_window_hook(void *hook_data
, void *call_data
)
1562 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1563 Drawing_t
*drawing
= control_flow_data
->drawing
;
1564 ProcessList
*process_list
= control_flow_data
->process_list
;
1566 const TimeWindowNotifyData
*time_window_nofify_data
=
1567 ((const TimeWindowNotifyData
*)call_data
);
1569 TimeWindow
*old_time_window
=
1570 time_window_nofify_data
->old_time_window
;
1571 TimeWindow
*new_time_window
=
1572 time_window_nofify_data
->new_time_window
;
1574 /* Update the ruler */
1575 drawing_update_ruler(control_flow_data
->drawing
,
1579 /* Two cases : zoom in/out or scrolling */
1581 /* In order to make sure we can reuse the old drawing, the scale must
1582 * be the same and the new time interval being partly located in the
1583 * currently shown time interval. (reuse is only for scrolling)
1586 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
1587 old_time_window
->start_time
.tv_sec
,
1588 old_time_window
->start_time
.tv_nsec
,
1589 old_time_window
->time_width
.tv_sec
,
1590 old_time_window
->time_width
.tv_nsec
);
1592 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
1593 new_time_window
->start_time
.tv_sec
,
1594 new_time_window
->start_time
.tv_nsec
,
1595 new_time_window
->time_width
.tv_sec
,
1596 new_time_window
->time_width
.tv_nsec
);
1598 if( new_time_window
->time_width
.tv_sec
== old_time_window
->time_width
.tv_sec
1599 && new_time_window
->time_width
.tv_nsec
== old_time_window
->time_width
.tv_nsec
)
1601 /* Same scale (scrolling) */
1602 g_info("scrolling");
1603 LttTime
*ns
= &new_time_window
->start_time
;
1604 LttTime
*nw
= &new_time_window
->time_width
;
1605 LttTime
*os
= &old_time_window
->start_time
;
1606 LttTime
*ow
= &old_time_window
->time_width
;
1607 LttTime old_end
= old_time_window
->end_time
;
1608 LttTime new_end
= new_time_window
->end_time
;
1610 //if(ns<os+w && os+w<ns+w)
1611 //if(ns<old_end && os<ns)
1612 if(ltt_time_compare(*ns
, old_end
) == -1
1613 && ltt_time_compare(*os
, *ns
) == -1)
1615 g_info("scrolling near right");
1616 /* Scroll right, keep right part of the screen */
1618 guint width
= control_flow_data
->drawing
->width
;
1619 convert_time_to_pixels(
1625 /* Copy old data to new location */
1626 copy_pixmap_region(process_list
,
1628 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1632 control_flow_data
->drawing
->width
-x
+SAFETY
, -1);
1634 if(drawing
->damage_begin
== drawing
->damage_end
)
1635 drawing
->damage_begin
= control_flow_data
->drawing
->width
-x
;
1637 drawing
->damage_begin
= 0;
1639 drawing
->damage_end
= control_flow_data
->drawing
->width
;
1641 /* Clear the data request background, but not SAFETY */
1642 rectangle_pixmap(process_list
,
1643 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1645 drawing
->damage_begin
+SAFETY
, 0,
1646 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
1648 gtk_widget_queue_draw(drawing
->drawing_area
);
1649 //gtk_widget_queue_draw_area (drawing->drawing_area,
1651 // control_flow_data->drawing->width,
1652 // control_flow_data->drawing->height);
1654 /* Get new data for the rest. */
1655 drawing_data_request(control_flow_data
->drawing
,
1656 drawing
->damage_begin
, 0,
1657 drawing
->damage_end
- drawing
->damage_begin
,
1658 control_flow_data
->drawing
->height
);
1661 //if(ns<os && os<ns+w)
1662 //if(ns<os && os<new_end)
1663 if(ltt_time_compare(*ns
,*os
) == -1
1664 && ltt_time_compare(*os
,new_end
) == -1)
1666 g_info("scrolling near left");
1667 /* Scroll left, keep left part of the screen */
1669 guint width
= control_flow_data
->drawing
->width
;
1670 convert_time_to_pixels(
1676 /* Copy old data to new location */
1677 copy_pixmap_region (process_list
,
1679 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1685 if(drawing
->damage_begin
== drawing
->damage_end
)
1686 drawing
->damage_end
= x
;
1688 drawing
->damage_end
=
1689 control_flow_data
->drawing
->width
;
1691 drawing
->damage_begin
= 0;
1693 rectangle_pixmap (process_list
,
1694 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1696 drawing
->damage_begin
, 0,
1697 drawing
->damage_end
- drawing
->damage_begin
, // do not overlap
1700 gtk_widget_queue_draw(drawing
->drawing_area
);
1701 //gtk_widget_queue_draw_area (drawing->drawing_area,
1703 // control_flow_data->drawing->width,
1704 // control_flow_data->drawing->height);
1707 /* Get new data for the rest. */
1708 drawing_data_request(control_flow_data
->drawing
,
1709 drawing
->damage_begin
, 0,
1710 drawing
->damage_end
- drawing
->damage_begin
,
1711 control_flow_data
->drawing
->height
);
1714 if(ltt_time_compare(*ns
,*os
) == 0)
1716 g_info("not scrolling");
1718 g_info("scrolling far");
1719 /* Cannot reuse any part of the screen : far jump */
1722 rectangle_pixmap (process_list
,
1723 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1726 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
1729 //gtk_widget_queue_draw_area (drawing->drawing_area,
1731 // control_flow_data->drawing->width,
1732 // control_flow_data->drawing->height);
1733 gtk_widget_queue_draw(drawing
->drawing_area
);
1735 drawing
->damage_begin
= 0;
1736 drawing
->damage_end
= control_flow_data
->drawing
->width
;
1738 drawing_data_request(control_flow_data
->drawing
,
1740 control_flow_data
->drawing
->width
,
1741 control_flow_data
->drawing
->height
);
1747 /* Different scale (zoom) */
1750 rectangle_pixmap (process_list
,
1751 control_flow_data
->drawing
->drawing_area
->style
->black_gc
,
1754 control_flow_data
->drawing
->width
+SAFETY
, // do not overlap
1757 //gtk_widget_queue_draw_area (drawing->drawing_area,
1759 // control_flow_data->drawing->width,
1760 // control_flow_data->drawing->height);
1761 gtk_widget_queue_draw(drawing
->drawing_area
);
1763 drawing
->damage_begin
= 0;
1764 drawing
->damage_end
= control_flow_data
->drawing
->width
;
1766 drawing_data_request(control_flow_data
->drawing
,
1768 control_flow_data
->drawing
->width
,
1769 control_flow_data
->drawing
->height
);
1772 /* Update directly when scrolling */
1773 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
1779 gint
traceset_notify(void *hook_data
, void *call_data
)
1781 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1782 Drawing_t
*drawing
= control_flow_data
->drawing
;
1784 if(unlikely(drawing
->gc
== NULL
)) {
1787 if(drawing
->dotted_gc
== NULL
) {
1791 drawing_clear(control_flow_data
->drawing
);
1792 processlist_clear(control_flow_data
->process_list
);
1793 gtk_widget_set_size_request(
1794 control_flow_data
->drawing
->drawing_area
,
1795 -1, processlist_get_height(control_flow_data
->process_list
));
1796 redraw_notify(control_flow_data
, NULL
);
1798 request_background_data(control_flow_data
);
1803 gint
redraw_notify(void *hook_data
, void *call_data
)
1805 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1806 Drawing_t
*drawing
= control_flow_data
->drawing
;
1807 GtkWidget
*widget
= drawing
->drawing_area
;
1809 drawing
->damage_begin
= 0;
1810 drawing
->damage_end
= drawing
->width
;
1812 /* fun feature, to be separated someday... */
1813 drawing_clear(control_flow_data
->drawing
);
1814 processlist_clear(control_flow_data
->process_list
);
1815 gtk_widget_set_size_request(
1816 control_flow_data
->drawing
->drawing_area
,
1817 -1, processlist_get_height(control_flow_data
->process_list
));
1819 rectangle_pixmap (control_flow_data
->process_list
,
1820 widget
->style
->black_gc
,
1823 drawing
->alloc_width
,
1826 gtk_widget_queue_draw(drawing
->drawing_area
);
1828 if(drawing
->damage_begin
< drawing
->damage_end
)
1830 drawing_data_request(drawing
,
1831 drawing
->damage_begin
,
1833 drawing
->damage_end
-drawing
->damage_begin
,
1837 //gtk_widget_queue_draw_area(drawing->drawing_area,
1840 // drawing->height);
1846 gint
continue_notify(void *hook_data
, void *call_data
)
1848 ControlFlowData
*control_flow_data
= (ControlFlowData
*) hook_data
;
1849 Drawing_t
*drawing
= control_flow_data
->drawing
;
1851 //g_assert(widget->allocation.width == drawing->damage_end);
1853 if(drawing
->damage_begin
< drawing
->damage_end
)
1855 drawing_data_request(drawing
,
1856 drawing
->damage_begin
,
1858 drawing
->damage_end
-drawing
->damage_begin
,
1866 gint
update_current_time_hook(void *hook_data
, void *call_data
)
1868 ControlFlowData
*control_flow_data
= (ControlFlowData
*)hook_data
;
1869 Drawing_t
*drawing
= control_flow_data
->drawing
;
1871 LttTime current_time
= *((LttTime
*)call_data
);
1873 TimeWindow time_window
=
1874 lttvwindow_get_time_window(control_flow_data
->tab
);
1876 LttTime time_begin
= time_window
.start_time
;
1877 LttTime width
= time_window
.time_width
;
1880 guint64 time_ll
= ltt_time_to_uint64(width
);
1881 time_ll
= time_ll
>> 1; /* divide by two */
1882 half_width
= ltt_time_from_uint64(time_ll
);
1884 LttTime time_end
= ltt_time_add(time_begin
, width
);
1886 LttvTracesetContext
* tsc
=
1887 lttvwindow_get_traceset_context(control_flow_data
->tab
);
1889 LttTime trace_start
= tsc
->time_span
.start_time
;
1890 LttTime trace_end
= tsc
->time_span
.end_time
;
1892 g_info("New current time HOOK : %lu, %lu", current_time
.tv_sec
,
1893 current_time
.tv_nsec
);
1897 /* If current time is inside time interval, just move the highlight
1900 /* Else, we have to change the time interval. We have to tell it
1901 * to the main window. */
1902 /* The time interval change will take care of placing the current
1903 * time at the center of the visible area, or nearest possible if we are
1904 * at one end of the trace. */
1907 if(ltt_time_compare(current_time
, time_begin
) < 0)
1909 TimeWindow new_time_window
;
1911 if(ltt_time_compare(current_time
,
1912 ltt_time_add(trace_start
,half_width
)) < 0)
1913 time_begin
= trace_start
;
1915 time_begin
= ltt_time_sub(current_time
,half_width
);
1917 new_time_window
.start_time
= time_begin
;
1918 new_time_window
.time_width
= width
;
1919 new_time_window
.time_width_double
= ltt_time_to_double(width
);
1920 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
1922 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
1924 else if(ltt_time_compare(current_time
, time_end
) > 0)
1926 TimeWindow new_time_window
;
1928 if(ltt_time_compare(current_time
, ltt_time_sub(trace_end
, half_width
)) > 0)
1929 time_begin
= ltt_time_sub(trace_end
,width
);
1931 time_begin
= ltt_time_sub(current_time
,half_width
);
1933 new_time_window
.start_time
= time_begin
;
1934 new_time_window
.time_width
= width
;
1935 new_time_window
.time_width_double
= ltt_time_to_double(width
);
1936 new_time_window
.end_time
= ltt_time_add(time_begin
, width
);
1938 lttvwindow_report_time_window(control_flow_data
->tab
, new_time_window
);
1941 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
1943 /* Update directly when scrolling */
1944 gdk_window_process_updates(control_flow_data
->drawing
->drawing_area
->window
,
1950 typedef struct _ClosureData
{
1951 EventsRequest
*events_request
;
1952 LttvTracesetState
*tss
;
1957 /* Draw line until end of the screen */
1959 void draw_closure(gpointer key
, gpointer value
, gpointer user_data
)
1961 ResourceInfo
*process_info
= (ResourceInfo
*)key
;
1962 HashedResourceData
*hashed_process_data
= (HashedResourceData
*)value
;
1963 ClosureData
*closure_data
= (ClosureData
*)user_data
;
1965 EventsRequest
*events_request
= closure_data
->events_request
;
1966 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
1968 LttvTracesetState
*tss
= closure_data
->tss
;
1969 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)tss
;
1971 LttTime evtime
= closure_data
->end_time
;
1973 gboolean dodraw
= TRUE
;
1976 /* For the process */
1977 /* First, check if the current process is in the state computation
1978 * process list. If it is there, that means we must add it right now and
1979 * draw items from the beginning of the read for it. If it is not
1980 * present, it's a new process and it was not present : it will
1981 * be added after the state update. */
1983 g_assert(lttv_traceset_number(tsc
->ts
) > 0);
1984 #endif //EXTRA_CHECK
1985 LttvTraceContext
*tc
= tsc
->traces
[process_info
->trace_num
];
1986 LttvTraceState
*ts
= (LttvTraceState
*)tc
;
1989 //FIXME : optimize data structures.
1990 LttvTracefileState
*tfs
;
1991 LttvTracefileContext
*tfc
;
1993 for(i
=0;i
<tc
->tracefiles
->len
;i
++) {
1994 tfc
= g_array_index(tc
->tracefiles
, LttvTracefileContext
*, i
);
1995 if(ltt_tracefile_name(tfc
->tf
) == LTT_NAME_CPU
1996 && tfs
->cpu
== process_info
->cpu
)
2000 g_assert(i
<tc
->tracefiles
->len
);
2001 tfs
= LTTV_TRACEFILE_STATE(tfc
);
2003 // LttvTracefileState *tfs =
2004 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2005 // tracefiles[process_info->cpu];
2007 // LttvProcessState *process;
2008 // process = lttv_state_find_process(ts, process_info->cpu,
2009 // process_info->pid);
2011 // if(unlikely(process != NULL)) {
2013 // LttvFilter *filter = control_flow_data->filter;
2014 // if(filter != NULL && filter->head != NULL)
2015 // if(!lttv_filter_tree_parse(filter->head,NULL,NULL,
2016 // tc->t,NULL,process,tc))
2019 /* Only draw for processes that are currently in the trace states */
2021 ProcessList
*process_list
= control_flow_data
->process_list
;
2023 /* Should be alike when background info is ready */
2024 if(control_flow_data
->background_info_waiting
==0)
2025 g_assert(ltt_time_compare(process
->creation_time
,
2026 process_info
->birth
) == 0);
2027 #endif //EXTRA_CHECK
2029 /* Now, the process is in the state hash and our own process hash.
2030 * We definitely can draw the items related to the ending state.
2033 if(unlikely(ltt_time_compare(hashed_process_data
->next_good_time
,
2036 TimeWindow time_window
=
2037 lttvwindow_get_time_window(control_flow_data
->tab
);
2040 if(ltt_time_compare(evtime
, time_window
.start_time
) == -1
2041 || ltt_time_compare(evtime
, time_window
.end_time
) == 1)
2043 #endif //EXTRA_CHECK
2044 Drawing_t
*drawing
= control_flow_data
->drawing
;
2045 guint width
= drawing
->width
;
2047 guint x
= closure_data
->x_end
;
2049 DrawContext draw_context
;
2051 /* Now create the drawing context that will be used to draw
2052 * items related to the last state. */
2053 draw_context
.drawable
= hashed_process_data
->pixmap
;
2054 draw_context
.gc
= drawing
->gc
;
2055 draw_context
.pango_layout
= drawing
->pango_layout
;
2056 draw_context
.drawinfo
.end
.x
= x
;
2058 draw_context
.drawinfo
.y
.over
= 1;
2059 draw_context
.drawinfo
.y
.middle
= (hashed_process_data
->height
/2);
2060 draw_context
.drawinfo
.y
.under
= hashed_process_data
->height
;
2062 draw_context
.drawinfo
.start
.offset
.over
= 0;
2063 draw_context
.drawinfo
.start
.offset
.middle
= 0;
2064 draw_context
.drawinfo
.start
.offset
.under
= 0;
2065 draw_context
.drawinfo
.end
.offset
.over
= 0;
2066 draw_context
.drawinfo
.end
.offset
.middle
= 0;
2067 draw_context
.drawinfo
.end
.offset
.under
= 0;
2069 /* Jump over draw if we are at the same x position */
2070 if(x
== hashed_process_data
->x
.over
)
2074 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.over
;
2076 PropertiesLine prop_line
= prepare_execmode_line(process
);
2077 draw_line((void*)&prop_line
, (void*)&draw_context
);
2079 hashed_process_data
->x
.over
= x
;
2083 if(unlikely(x
== hashed_process_data
->x
.middle
&&
2084 hashed_process_data
->x
.middle_used
)) {
2085 #if 0 /* do not mark closure : not missing information */
2086 if(hashed_process_data
->x
.middle_marked
== FALSE
) {
2087 /* Draw collision indicator */
2088 gdk_gc_set_foreground(drawing
->gc
, &drawing_colors
[COL_WHITE
]);
2089 gdk_draw_point(drawing
->pixmap
,
2093 hashed_process_data
->x
.middle_marked
= TRUE
;
2098 draw_context
.drawinfo
.start
.x
= hashed_process_data
->x
.middle
;
2101 PropertiesLine prop_line
;
2102 prop_line
.line_width
= STATE_LINE_WIDTH
;
2103 prop_line
.style
= GDK_LINE_SOLID
;
2104 prop_line
.y
= MIDDLE
;
2105 if(process_info
->type
== 0)
2106 cpu_set_line_color(&prop_line
, &ts
->cpu_states
[process_info
->id
]);
2107 else if(process_info
->type
== 1)
2108 irq_set_line_color(&prop_line
, &ts
->irq_states
[process_info
->id
]);
2109 else if(process_info
->type
== 2) {
2110 gint devcode_gint
= process_info
->id
;
2111 LttvBdevState
*bdev
= g_hash_table_lookup(ts
->bdev_states
, &devcode_gint
);
2112 bdev_set_line_color(&prop_line
, bdev
);
2115 draw_line((void*)&prop_line
, (void*)&draw_context
);
2118 /* become the last x position */
2119 if(likely(x
!= hashed_process_data
->x
.middle
)) {
2120 hashed_process_data
->x
.middle
= x
;
2121 /* but don't use the pixel */
2122 hashed_process_data
->x
.middle_used
= FALSE
;
2124 /* Calculate the next good time */
2125 convert_pixels_to_time(width
, x
+1, time_window
,
2126 &hashed_process_data
->next_good_time
);
2135 int before_chunk(void *hook_data
, void *call_data
)
2137 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2138 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2139 ControlFlowData
*cfd
= (ControlFlowData
*)events_request
->viewer_data
;
2141 /* Desactivate sort */
2142 gtk_tree_sortable_set_sort_column_id(
2143 GTK_TREE_SORTABLE(cfd
->process_list
->list_store
),
2145 GTK_SORT_ASCENDING
);
2147 drawing_chunk_begin(events_request
, tss
);
2152 int before_request(void *hook_data
, void *call_data
)
2154 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2155 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2157 drawing_data_request_begin(events_request
, tss
);
2164 * after request is necessary in addition of after chunk in order to draw
2165 * lines until the end of the screen. after chunk just draws lines until
2172 // TODO pmf: reenable this
2173 int after_request(void *hook_data
, void *call_data
)
2175 // EventsRequest *events_request = (EventsRequest*)hook_data;
2176 // ControlFlowData *control_flow_data = events_request->viewer_data;
2177 // LttvTracesetState *tss = (LttvTracesetState*)call_data;
2179 // ProcessList *process_list = control_flow_data->process_list;
2180 // LttTime end_time = events_request->end_time;
2182 // ClosureData closure_data;
2183 // closure_data.events_request = (EventsRequest*)hook_data;
2184 // closure_data.tss = tss;
2185 // closure_data.end_time = end_time;
2187 // TimeWindow time_window =
2188 // lttvwindow_get_time_window(control_flow_data->tab);
2189 // guint width = control_flow_data->drawing->width;
2190 // convert_time_to_pixels(
2194 // &closure_data.x_end);
2197 // /* Draw last items */
2198 // g_hash_table_foreach(process_list->process_hash, draw_closure,
2199 // (void*)&closure_data);
2202 // /* Request expose */
2203 // drawing_request_expose(events_request, tss, end_time);
2212 int after_chunk(void *hook_data
, void *call_data
)
2214 EventsRequest
*events_request
= (EventsRequest
*)hook_data
;
2215 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2216 LttvTracesetState
*tss
= (LttvTracesetState
*)call_data
;
2217 LttvTracesetContext
*tsc
= (LttvTracesetContext
*)call_data
;
2218 LttvTracefileContext
*tfc
= lttv_traceset_context_get_current_tfc(tsc
);
2221 ProcessList
*process_list
= control_flow_data
->process_list
;
2223 LttvTraceset
*traceset
= tsc
->ts
;
2224 guint nb_trace
= lttv_traceset_number(traceset
);
2226 /* Only execute when called for the first trace's events request */
2227 if(!process_list
->current_hash_data
) return;
2229 for(i
= 0 ; i
< nb_trace
; i
++) {
2230 g_free(process_list
->current_hash_data
[i
]);
2232 g_free(process_list
->current_hash_data
);
2233 process_list
->current_hash_data
= NULL
;
2236 end_time
= LTT_TIME_MIN(tfc
->timestamp
, events_request
->end_time
);
2237 else /* end of traceset, or position now out of request : end */
2238 end_time
= events_request
->end_time
;
2240 ClosureData closure_data
;
2241 closure_data
.events_request
= (EventsRequest
*)hook_data
;
2242 closure_data
.tss
= tss
;
2243 closure_data
.end_time
= end_time
;
2245 TimeWindow time_window
=
2246 lttvwindow_get_time_window(control_flow_data
->tab
);
2247 guint width
= control_flow_data
->drawing
->width
;
2248 convert_time_to_pixels(
2252 &closure_data
.x_end
);
2254 /* Draw last items */
2255 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2256 (void*)&closure_data
);
2258 /* Reactivate sort */
2259 gtk_tree_sortable_set_sort_column_id(
2260 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2261 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2262 GTK_SORT_ASCENDING
);
2264 update_index_to_pixmap(control_flow_data
->process_list
);
2265 /* Request a full expose : drawing scrambled */
2266 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2268 /* Request expose (updates damages zone also) */
2269 drawing_request_expose(events_request
, tss
, end_time
);
2274 /* after_statedump_end
2276 * @param hook_data ControlFlowData structure of the viewer.
2277 * @param call_data Event context.
2279 * This function adds items to be drawn in a queue for each process.
2282 int before_statedump_end(void *hook_data
, void *call_data
)
2284 LttvTraceHookByFacility
*thf
= (LttvTraceHookByFacility
*)hook_data
;
2285 EventsRequest
*events_request
= (EventsRequest
*)thf
->hook_data
;
2286 ControlFlowData
*control_flow_data
= events_request
->viewer_data
;
2288 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
2290 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
2292 LttvTraceState
*ts
= (LttvTraceState
*)tfc
->t_context
;
2294 LttvTracesetState
*tss
= (LttvTracesetState
*)tfc
->t_context
->ts_context
;
2295 ProcessList
*process_list
= control_flow_data
->process_list
;
2298 e
= ltt_tracefile_get_event(tfc
->tf
);
2300 LttvFilter
*filter
= control_flow_data
->filter
;
2301 if(filter
!= NULL
&& filter
->head
!= NULL
)
2302 if(!lttv_filter_tree_parse(filter
->head
,e
,tfc
->tf
,
2303 tfc
->t_context
->t
,tfc
,NULL
,NULL
))
2306 LttTime evtime
= ltt_event_time(e
);
2308 ClosureData closure_data
;
2309 closure_data
.events_request
= events_request
;
2310 closure_data
.tss
= tss
;
2311 closure_data
.end_time
= evtime
;
2313 TimeWindow time_window
=
2314 lttvwindow_get_time_window(control_flow_data
->tab
);
2315 guint width
= control_flow_data
->drawing
->width
;
2316 convert_time_to_pixels(
2320 &closure_data
.x_end
);
2322 /* Draw last items */
2323 g_hash_table_foreach(process_list
->process_hash
, draw_closure
,
2324 (void*)&closure_data
);
2326 /* Reactivate sort */
2327 gtk_tree_sortable_set_sort_column_id(
2328 GTK_TREE_SORTABLE(control_flow_data
->process_list
->list_store
),
2329 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID
,
2330 GTK_SORT_ASCENDING
);
2332 update_index_to_pixmap(control_flow_data
->process_list
);
2333 /* Request a full expose : drawing scrambled */
2334 gtk_widget_queue_draw(control_flow_data
->drawing
->drawing_area
);
2336 /* Request expose (updates damages zone also) */
2337 drawing_request_expose(events_request
, tss
, evtime
);