wakeup wait for cpu display
[lttv.git] / lttv / modules / gui / controlflow / eventhooks.c
1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Mathieu Desnoyers
3 *
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;
7 *
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.
12 *
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,
16 * MA 02111-1307, USA.
17 */
18
19
20 /*****************************************************************************
21 * Hooks to be called by the main window *
22 *****************************************************************************/
23
24
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.
27 *
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.
31 *
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.
34 *
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
41 * hook.
42 *
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
45 * line/background.
46 */
47
48 #ifdef HAVE_CONFIG_H
49 #include <config.h>
50 #endif
51
52 //#define PANGO_ENABLE_BACKEND
53 #include <gtk/gtk.h>
54 #include <gdk/gdk.h>
55 #include <glib.h>
56 #include <assert.h>
57 #include <string.h>
58 #include <stdio.h>
59
60 //#include <pango/pango.h>
61
62 #include <ltt/event.h>
63 #include <ltt/time.h>
64 #include <ltt/trace.h>
65
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>
72
73
74 #include "eventhooks.h"
75 #include "cfv.h"
76 #include "processlist.h"
77 #include "drawing.h"
78
79
80 #define MAX_PATH_LEN 256
81 #define STATE_LINE_WIDTH 6
82 #define COLLISION_POSITION(height) (((height - STATE_LINE_WIDTH)/2) -3)
83
84 extern GSList *g_legend_list;
85
86
87 /* Action to do when background computation completed.
88 *
89 * Wait for all the awaited computations to be over.
90 */
91
92 static gint background_ready(void *hook_data, void *call_data)
93 {
94 ControlFlowData *control_flow_data = (ControlFlowData *)hook_data;
95 LttvTrace *trace = (LttvTrace*)call_data;
96
97 control_flow_data->background_info_waiting--;
98
99 if(control_flow_data->background_info_waiting == 0) {
100 g_message("control flow viewer : background computation data ready.");
101
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);
108 }
109
110 return 0;
111 }
112
113
114 /* Request background computation. Verify if it is in progress or ready first.
115 * Only for each trace in the tab's traceset.
116 */
117 static void request_background_data(ControlFlowData *control_flow_data)
118 {
119 LttvTracesetContext * tsc =
120 lttvwindow_get_traceset_context(control_flow_data->tab);
121 gint num_traces = lttv_traceset_number(tsc->ts);
122 gint i;
123 LttvTrace *trace;
124 LttvTraceState *tstate;
125
126 LttvHooks *background_ready_hook =
127 lttv_hooks_new();
128 lttv_hooks_add(background_ready_hook, background_ready, control_flow_data,
129 LTTV_PRIO_DEFAULT);
130 control_flow_data->background_info_waiting = 0;
131
132 for(i=0;i<num_traces;i++) {
133 trace = lttv_traceset_get(tsc->ts, i);
134 tstate = LTTV_TRACE_STATE(tsc->traces[i]);
135
136 if(lttvwindowtraces_get_ready(g_quark_from_string("state"),trace)==FALSE
137 && !tstate->has_precomputed_states) {
138
139 if(lttvwindowtraces_get_in_progress(g_quark_from_string("state"),
140 trace) == FALSE) {
141 /* We first remove requests that could have been done for the same
142 * information. Happens when two viewers ask for it before servicing
143 * starts.
144 */
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,
149 trace,
150 ltt_time_infinite,
151 NULL,
152 background_ready_hook);
153 control_flow_data->background_info_waiting++;
154 } else { /* in progress */
155
156 lttvwindowtraces_background_notify_current(control_flow_data,
157 trace,
158 ltt_time_infinite,
159 NULL,
160 background_ready_hook);
161 control_flow_data->background_info_waiting++;
162 }
163 } else {
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.
167 */
168 }
169
170 }
171
172 lttv_hooks_destroy(background_ready_hook);
173 }
174
175
176
177
178 /**
179 * Event Viewer's constructor hook
180 *
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.
185 */
186 GtkWidget *
187 h_guicontrolflow(LttvPlugin *plugin)
188 {
189 LttvPluginTab *ptab = LTTV_PLUGIN_TAB(plugin);
190 Tab *tab = ptab->tab;
191 g_info("h_guicontrolflow, %p", tab);
192 ControlFlowData *control_flow_data = guicontrolflow(ptab);
193
194 control_flow_data->tab = tab;
195
196 // Unreg done in the GuiControlFlow_Destructor
197 lttvwindow_register_traceset_notify(tab,
198 traceset_notify,
199 control_flow_data);
200
201 lttvwindow_register_time_window_notify(tab,
202 update_time_window_hook,
203 control_flow_data);
204 lttvwindow_register_current_time_notify(tab,
205 update_current_time_hook,
206 control_flow_data);
207 lttvwindow_register_redraw_notify(tab,
208 redraw_notify,
209 control_flow_data);
210 lttvwindow_register_continue_notify(tab,
211 continue_notify,
212 control_flow_data);
213 request_background_data(control_flow_data);
214
215
216 return guicontrolflow_get_widget(control_flow_data) ;
217
218 }
219
220 int event_selected_hook(void *hook_data, void *call_data)
221 {
222 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
223 guint *event_number = (guint*) call_data;
224
225 g_debug("DEBUG : event selected by main window : %u", *event_number);
226
227 return 0;
228 }
229
230 /* Function that selects the color of status&exemode line */
231 static inline PropertiesLine prepare_s_e_line(LttvProcessState *process)
232 {
233 PropertiesLine prop_line;
234 prop_line.line_width = STATE_LINE_WIDTH;
235 prop_line.style = GDK_LINE_SOLID;
236 prop_line.y = MIDDLE;
237 //GdkColormap *colormap = gdk_colormap_get_system();
238
239 if(process->state->s == LTTV_STATE_RUN) {
240 if(process->state->t == LTTV_STATE_USER_MODE)
241 prop_line.color = drawing_colors[COL_RUN_USER_MODE];
242 else if(process->state->t == LTTV_STATE_SYSCALL)
243 prop_line.color = drawing_colors[COL_RUN_SYSCALL];
244 else if(process->state->t == LTTV_STATE_TRAP)
245 prop_line.color = drawing_colors[COL_RUN_TRAP];
246 else if(process->state->t == LTTV_STATE_IRQ)
247 prop_line.color = drawing_colors[COL_RUN_IRQ];
248 else if(process->state->t == LTTV_STATE_SOFT_IRQ)
249 prop_line.color = drawing_colors[COL_RUN_SOFT_IRQ];
250 else if(process->state->t == LTTV_STATE_MODE_UNKNOWN)
251 prop_line.color = drawing_colors[COL_MODE_UNKNOWN];
252 else
253 g_assert(FALSE); /* RUNNING MODE UNKNOWN */
254 } else if(process->state->s == LTTV_STATE_WAIT) {
255 /* We don't show if we wait while in user mode, trap, irq or syscall */
256 prop_line.color = drawing_colors[COL_WAIT];
257 } else if(process->state->s == LTTV_STATE_WAIT_CPU) {
258 /* We don't show if we wait for CPU while in user mode, trap, irq
259 * or syscall */
260 prop_line.color = drawing_colors[COL_WAIT_CPU];
261 } else if(process->state->s == LTTV_STATE_ZOMBIE) {
262 prop_line.color = drawing_colors[COL_ZOMBIE];
263 } else if(process->state->s == LTTV_STATE_WAIT_FORK) {
264 prop_line.color = drawing_colors[COL_WAIT_FORK];
265 } else if(process->state->s == LTTV_STATE_EXIT) {
266 prop_line.color = drawing_colors[COL_EXIT];
267 } else if(process->state->s == LTTV_STATE_UNNAMED) {
268 prop_line.color = drawing_colors[COL_UNNAMED];
269 } else if(process->state->s == LTTV_STATE_DEAD) {
270 prop_line.color = drawing_colors[COL_DEAD];
271 } else {
272 g_critical("unknown state : %s", g_quark_to_string(process->state->s));
273 g_assert(FALSE); /* UNKNOWN STATE */
274 }
275
276 return prop_line;
277
278 }
279
280 /* Before try-wake-up hook. A process is being woken; we need to draw its line up to this point in time
281 in that colour. This is basically like exec-state, but the change applies to a process other than that
282 which is currently running. */
283
284 int before_trywakeup_hook(void *hook_data, void *call_data)
285 {
286 LttvTraceHook *th = (LttvTraceHook*)hook_data;
287 EventsRequest *events_request = (EventsRequest*)th->hook_data;
288 ControlFlowData *control_flow_data = events_request->viewer_data;
289
290 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
291
292 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
293 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
294
295 LttEvent *e = ltt_tracefile_get_event(tfc->tf);
296 gint target_pid_saved = tfc->target_pid;
297
298 LttTime evtime = ltt_event_time(e);
299 LttvFilter *filter = control_flow_data->filter;
300
301 guint woken_pid;
302 gint woken_cpu;
303
304 woken_pid = ltt_event_get_int(e, lttv_trace_get_hook_field(th, 0));
305 woken_cpu = ltt_event_get_unsigned(e, lttv_trace_get_hook_field(th, 1));
306
307 tfc->target_pid = woken_pid;
308 if(!filter || !filter->head ||
309 lttv_filter_tree_parse(filter->head,e,tfc->tf,
310 tfc->t_context->t,tfc,NULL,NULL)) {
311
312 /* First, check if the woken process is in the state computation
313 * process list. If it is there, that means we must add it right now and
314 * draw items from the beginning of the read for it. If it is not
315 * present, it's a new process and it was not present : it will
316 * be added after the state update. TOCHECK: What does that last para mean? */
317 guint cpu = tfs->cpu;
318 guint trace_num = ts->parent.index;
319 LttvProcessState *process = lttv_state_find_process(ts, woken_cpu, woken_pid);
320
321 if(process != NULL) {
322 /* Well, the woken process existed : we must get it in the process hash
323 * or add it, and draw its items.
324 */
325 /* Add process to process list (if not present) */
326 guint pl_height = 0;
327 HashedProcessData *hashed_process_data = NULL;
328 ProcessList *process_list = control_flow_data->process_list;
329 LttTime birth = process->creation_time;
330
331 hashed_process_data = processlist_get_process_data(process_list,
332 woken_pid,
333 process->cpu,
334 &birth,
335 trace_num);
336 if(hashed_process_data == NULL)
337 {
338 g_assert(woken_pid != process->ppid);
339 /* Process not present */
340 ProcessInfo *process_info;
341 Drawing_t *drawing = control_flow_data->drawing;
342 processlist_add(process_list,
343 drawing,
344 woken_pid,
345 process->tgid,
346 process->cpu,
347 process->ppid,
348 &birth,
349 trace_num,
350 process->name,
351 process->brand,
352 &pl_height,
353 &process_info,
354 &hashed_process_data);
355 gtk_widget_set_size_request(drawing->drawing_area,
356 -1,
357 pl_height);
358 gtk_widget_queue_draw(drawing->drawing_area);
359
360 }
361
362 /* Now, the process is in the state hash and our own process hash.
363 * We definitely can draw the items related to the ending state.
364 */
365
366 if(ltt_time_compare(hashed_process_data->next_good_time,
367 evtime) > 0)
368 {
369 if(hashed_process_data->x.middle_marked == FALSE) {
370
371 TimeWindow time_window =
372 lttvwindow_get_time_window(control_flow_data->tab);
373 #ifdef EXTRA_CHECK
374 if(ltt_time_compare(evtime, time_window.start_time) == -1
375 || ltt_time_compare(evtime, time_window.end_time) == 1)
376 return FALSE;
377 #endif //EXTRA_CHECK
378 Drawing_t *drawing = control_flow_data->drawing;
379 guint width = drawing->width;
380 guint x;
381 convert_time_to_pixels(
382 time_window,
383 evtime,
384 width,
385 &x);
386
387 /* Draw collision indicator */
388 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
389 gdk_draw_point(hashed_process_data->pixmap,
390 drawing->gc,
391 x,
392 COLLISION_POSITION(hashed_process_data->height));
393 hashed_process_data->x.middle_marked = TRUE;
394 }
395 } else {
396 TimeWindow time_window =
397 lttvwindow_get_time_window(control_flow_data->tab);
398 #ifdef EXTRA_CHECK
399 if(ltt_time_compare(evtime, time_window.start_time) == -1
400 || ltt_time_compare(evtime, time_window.end_time) == 1)
401 return FALSE;
402 #endif //EXTRA_CHECK
403 Drawing_t *drawing = control_flow_data->drawing;
404 guint width = drawing->width;
405 guint x;
406 convert_time_to_pixels(
407 time_window,
408 evtime,
409 width,
410 &x);
411
412
413 /* Jump over draw if we are at the same x position */
414 if(x == hashed_process_data->x.middle &&
415 hashed_process_data->x.middle_used)
416 {
417 if(hashed_process_data->x.middle_marked == FALSE) {
418 /* Draw collision indicator */
419 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
420 gdk_draw_point(hashed_process_data->pixmap,
421 drawing->gc,
422 x,
423 COLLISION_POSITION(hashed_process_data->height));
424 hashed_process_data->x.middle_marked = TRUE;
425 }
426 /* jump */
427 } else {
428 DrawContext draw_context;
429
430 /* Now create the drawing context that will be used to draw
431 * items related to the last state. */
432 draw_context.drawable = hashed_process_data->pixmap;
433 draw_context.gc = drawing->gc;
434 draw_context.pango_layout = drawing->pango_layout;
435 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
436 draw_context.drawinfo.end.x = x;
437
438 draw_context.drawinfo.y.over = 1;
439 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
440 draw_context.drawinfo.y.under = hashed_process_data->height;
441
442 draw_context.drawinfo.start.offset.over = 0;
443 draw_context.drawinfo.start.offset.middle = 0;
444 draw_context.drawinfo.start.offset.under = 0;
445 draw_context.drawinfo.end.offset.over = 0;
446 draw_context.drawinfo.end.offset.middle = 0;
447 draw_context.drawinfo.end.offset.under = 0;
448
449 {
450 /* Draw the line */
451 PropertiesLine prop_line = prepare_s_e_line(process);
452 draw_line((void*)&prop_line, (void*)&draw_context);
453
454 }
455 /* become the last x position */
456 hashed_process_data->x.middle = x;
457 hashed_process_data->x.middle_used = TRUE;
458 hashed_process_data->x.middle_marked = FALSE;
459
460 /* Calculate the next good time */
461 convert_pixels_to_time(width, x+1, time_window,
462 &hashed_process_data->next_good_time);
463 }
464 }
465 }
466 }
467
468 tfc->target_pid = target_pid_saved;
469
470 return 0;
471
472 }
473
474 /* before_schedchange_hook
475 *
476 * This function basically draw lines and icons. Two types of lines are drawn :
477 * one small (3 pixels?) representing the state of the process and the second
478 * type is thicker (10 pixels?) representing on which CPU a process is running
479 * (and this only in running state).
480 *
481 * Extremums of the lines :
482 * x_min : time of the last event context for this process kept in memory.
483 * x_max : time of the current event.
484 * y : middle of the process in the process list. The process is found in the
485 * list, therefore is it's position in pixels.
486 *
487 * The choice of lines'color is defined by the context of the last event for this
488 * process.
489 */
490
491
492 int before_schedchange_hook(void *hook_data, void *call_data)
493 {
494 LttvTraceHook *th = (LttvTraceHook*)hook_data;
495 EventsRequest *events_request = (EventsRequest*)th->hook_data;
496 ControlFlowData *control_flow_data = events_request->viewer_data;
497
498 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
499
500 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
501 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
502
503 LttEvent *e;
504 e = ltt_tracefile_get_event(tfc->tf);
505 gint target_pid_saved = tfc->target_pid;
506
507 LttTime evtime = ltt_event_time(e);
508 LttvFilter *filter = control_flow_data->filter;
509
510 /* we are in a schedchange, before the state update. We must draw the
511 * items corresponding to the state before it changes : now is the right
512 * time to do it.
513 */
514
515 guint pid_out;
516 guint pid_in;
517 guint state_out;
518 {
519 pid_out = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 0));
520 pid_in = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 1));
521 state_out = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 2));
522 }
523
524 tfc->target_pid = pid_out;
525 if(!filter || !filter->head ||
526 lttv_filter_tree_parse(filter->head,e,tfc->tf,
527 tfc->t_context->t,tfc,NULL,NULL)) {
528 /* For the pid_out */
529 /* First, check if the current process is in the state computation
530 * process list. If it is there, that means we must add it right now and
531 * draw items from the beginning of the read for it. If it is not
532 * present, it's a new process and it was not present : it will
533 * be added after the state update. */
534 guint cpu = tfs->cpu;
535 guint trace_num = ts->parent.index;
536 LttvProcessState *process = ts->running_process[cpu];
537 /* unknown state, bad current pid */
538 if(process->pid != pid_out)
539 process = lttv_state_find_process(ts,
540 tfs->cpu, pid_out);
541
542 if(process != NULL) {
543 /* Well, the process_out existed : we must get it in the process hash
544 * or add it, and draw its items.
545 */
546 /* Add process to process list (if not present) */
547 guint pl_height = 0;
548 HashedProcessData *hashed_process_data = NULL;
549 ProcessList *process_list = control_flow_data->process_list;
550 LttTime birth = process->creation_time;
551
552 hashed_process_data = processlist_get_process_data(process_list,
553 pid_out,
554 process->cpu,
555 &birth,
556 trace_num);
557 if(hashed_process_data == NULL)
558 {
559 g_assert(pid_out == 0 || pid_out != process->ppid);
560 /* Process not present */
561 ProcessInfo *process_info;
562 Drawing_t *drawing = control_flow_data->drawing;
563 processlist_add(process_list,
564 drawing,
565 pid_out,
566 process->tgid,
567 process->cpu,
568 process->ppid,
569 &birth,
570 trace_num,
571 process->name,
572 process->brand,
573 &pl_height,
574 &process_info,
575 &hashed_process_data);
576 gtk_widget_set_size_request(drawing->drawing_area,
577 -1,
578 pl_height);
579 gtk_widget_queue_draw(drawing->drawing_area);
580
581 }
582
583 /* Now, the process is in the state hash and our own process hash.
584 * We definitely can draw the items related to the ending state.
585 */
586
587 if(ltt_time_compare(hashed_process_data->next_good_time,
588 evtime) > 0)
589 {
590 if(hashed_process_data->x.middle_marked == FALSE) {
591
592 TimeWindow time_window =
593 lttvwindow_get_time_window(control_flow_data->tab);
594 #ifdef EXTRA_CHECK
595 if(ltt_time_compare(evtime, time_window.start_time) == -1
596 || ltt_time_compare(evtime, time_window.end_time) == 1)
597 return FALSE;
598 #endif //EXTRA_CHECK
599 Drawing_t *drawing = control_flow_data->drawing;
600 guint width = drawing->width;
601 guint x;
602 convert_time_to_pixels(
603 time_window,
604 evtime,
605 width,
606 &x);
607
608 /* Draw collision indicator */
609 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
610 gdk_draw_point(hashed_process_data->pixmap,
611 drawing->gc,
612 x,
613 COLLISION_POSITION(hashed_process_data->height));
614 hashed_process_data->x.middle_marked = TRUE;
615 }
616 } else {
617 TimeWindow time_window =
618 lttvwindow_get_time_window(control_flow_data->tab);
619 #ifdef EXTRA_CHECK
620 if(ltt_time_compare(evtime, time_window.start_time) == -1
621 || ltt_time_compare(evtime, time_window.end_time) == 1)
622 return FALSE;
623 #endif //EXTRA_CHECK
624 Drawing_t *drawing = control_flow_data->drawing;
625 guint width = drawing->width;
626 guint x;
627 convert_time_to_pixels(
628 time_window,
629 evtime,
630 width,
631 &x);
632
633
634 /* Jump over draw if we are at the same x position */
635 if(x == hashed_process_data->x.middle &&
636 hashed_process_data->x.middle_used)
637 {
638 if(hashed_process_data->x.middle_marked == FALSE) {
639 /* Draw collision indicator */
640 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
641 gdk_draw_point(hashed_process_data->pixmap,
642 drawing->gc,
643 x,
644 COLLISION_POSITION(hashed_process_data->height));
645 hashed_process_data->x.middle_marked = TRUE;
646 }
647 /* jump */
648 } else {
649 DrawContext draw_context;
650
651 /* Now create the drawing context that will be used to draw
652 * items related to the last state. */
653 draw_context.drawable = hashed_process_data->pixmap;
654 draw_context.gc = drawing->gc;
655 draw_context.pango_layout = drawing->pango_layout;
656 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
657 draw_context.drawinfo.end.x = x;
658
659 draw_context.drawinfo.y.over = 1;
660 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
661 draw_context.drawinfo.y.under = hashed_process_data->height;
662
663 draw_context.drawinfo.start.offset.over = 0;
664 draw_context.drawinfo.start.offset.middle = 0;
665 draw_context.drawinfo.start.offset.under = 0;
666 draw_context.drawinfo.end.offset.over = 0;
667 draw_context.drawinfo.end.offset.middle = 0;
668 draw_context.drawinfo.end.offset.under = 0;
669
670 {
671 /* Draw the line */
672 PropertiesLine prop_line = prepare_s_e_line(process);
673 draw_line((void*)&prop_line, (void*)&draw_context);
674
675 }
676 /* become the last x position */
677 hashed_process_data->x.middle = x;
678 hashed_process_data->x.middle_used = TRUE;
679 hashed_process_data->x.middle_marked = FALSE;
680
681 /* Calculate the next good time */
682 convert_pixels_to_time(width, x+1, time_window,
683 &hashed_process_data->next_good_time);
684 }
685 }
686 }
687 }
688
689 tfc->target_pid = pid_in;
690 if(!filter || !filter->head ||
691 lttv_filter_tree_parse(filter->head,e,tfc->tf,
692 tfc->t_context->t,tfc,NULL,NULL)) {
693 /* For the pid_in */
694 /* First, check if the current process is in the state computation
695 * process list. If it is there, that means we must add it right now and
696 * draw items from the beginning of the read for it. If it is not
697 * present, it's a new process and it was not present : it will
698 * be added after the state update. */
699 LttvProcessState *process;
700 process = lttv_state_find_process(ts,
701 tfs->cpu, pid_in);
702 guint trace_num = ts->parent.index;
703
704 if(process != NULL) {
705 /* Well, the process existed : we must get it in the process hash
706 * or add it, and draw its items.
707 */
708 /* Add process to process list (if not present) */
709 guint pl_height = 0;
710 HashedProcessData *hashed_process_data = NULL;
711 ProcessList *process_list = control_flow_data->process_list;
712 LttTime birth = process->creation_time;
713
714 hashed_process_data = processlist_get_process_data(process_list,
715 pid_in,
716 tfs->cpu,
717 &birth,
718 trace_num);
719 if(hashed_process_data == NULL)
720 {
721 g_assert(pid_in == 0 || pid_in != process->ppid);
722 /* Process not present */
723 ProcessInfo *process_info;
724 Drawing_t *drawing = control_flow_data->drawing;
725 processlist_add(process_list,
726 drawing,
727 pid_in,
728 process->tgid,
729 tfs->cpu,
730 process->ppid,
731 &birth,
732 trace_num,
733 process->name,
734 process->brand,
735 &pl_height,
736 &process_info,
737 &hashed_process_data);
738 gtk_widget_set_size_request(drawing->drawing_area,
739 -1,
740 pl_height);
741 gtk_widget_queue_draw(drawing->drawing_area);
742
743 }
744 //We could set the current process and hash here, but will be done
745 //by after schedchange hook
746
747 /* Now, the process is in the state hash and our own process hash.
748 * We definitely can draw the items related to the ending state.
749 */
750
751 if(ltt_time_compare(hashed_process_data->next_good_time,
752 evtime) > 0)
753 {
754 if(hashed_process_data->x.middle_marked == FALSE) {
755
756 TimeWindow time_window =
757 lttvwindow_get_time_window(control_flow_data->tab);
758 #ifdef EXTRA_CHECK
759 if(ltt_time_compare(evtime, time_window.start_time) == -1
760 || ltt_time_compare(evtime, time_window.end_time) == 1)
761 return FALSE;
762 #endif //EXTRA_CHECK
763 Drawing_t *drawing = control_flow_data->drawing;
764 guint width = drawing->width;
765 guint x;
766 convert_time_to_pixels(
767 time_window,
768 evtime,
769 width,
770 &x);
771
772 /* Draw collision indicator */
773 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
774 gdk_draw_point(hashed_process_data->pixmap,
775 drawing->gc,
776 x,
777 COLLISION_POSITION(hashed_process_data->height));
778 hashed_process_data->x.middle_marked = TRUE;
779 }
780 } else {
781 TimeWindow time_window =
782 lttvwindow_get_time_window(control_flow_data->tab);
783 #ifdef EXTRA_CHECK
784 if(ltt_time_compare(evtime, time_window.start_time) == -1
785 || ltt_time_compare(evtime, time_window.end_time) == 1)
786 return FALSE;
787 #endif //EXTRA_CHECK
788 Drawing_t *drawing = control_flow_data->drawing;
789 guint width = drawing->width;
790 guint x;
791
792 convert_time_to_pixels(
793 time_window,
794 evtime,
795 width,
796 &x);
797
798
799 /* Jump over draw if we are at the same x position */
800 if(x == hashed_process_data->x.middle &&
801 hashed_process_data->x.middle_used)
802 {
803 if(hashed_process_data->x.middle_marked == FALSE) {
804 /* Draw collision indicator */
805 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
806 gdk_draw_point(hashed_process_data->pixmap,
807 drawing->gc,
808 x,
809 COLLISION_POSITION(hashed_process_data->height));
810 hashed_process_data->x.middle_marked = TRUE;
811 }
812 /* jump */
813 } else {
814 DrawContext draw_context;
815
816 /* Now create the drawing context that will be used to draw
817 * items related to the last state. */
818 draw_context.drawable = hashed_process_data->pixmap;
819 draw_context.gc = drawing->gc;
820 draw_context.pango_layout = drawing->pango_layout;
821 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
822 draw_context.drawinfo.end.x = x;
823
824 draw_context.drawinfo.y.over = 1;
825 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
826 draw_context.drawinfo.y.under = hashed_process_data->height;
827
828 draw_context.drawinfo.start.offset.over = 0;
829 draw_context.drawinfo.start.offset.middle = 0;
830 draw_context.drawinfo.start.offset.under = 0;
831 draw_context.drawinfo.end.offset.over = 0;
832 draw_context.drawinfo.end.offset.middle = 0;
833 draw_context.drawinfo.end.offset.under = 0;
834
835 {
836 /* Draw the line */
837 PropertiesLine prop_line = prepare_s_e_line(process);
838 draw_line((void*)&prop_line, (void*)&draw_context);
839 }
840
841
842 /* become the last x position */
843 hashed_process_data->x.middle = x;
844 hashed_process_data->x.middle_used = TRUE;
845 hashed_process_data->x.middle_marked = FALSE;
846
847 /* Calculate the next good time */
848 convert_pixels_to_time(width, x+1, time_window,
849 &hashed_process_data->next_good_time);
850 }
851 }
852 } else
853 g_warning("Cannot find pin_in in schedchange %u", pid_in);
854 }
855 tfc->target_pid = target_pid_saved;
856 return 0;
857
858
859
860
861 /* Text dump */
862 #ifdef DONTSHOW
863 GString *string = g_string_new("");;
864 gboolean field_names = TRUE, state = TRUE;
865
866 lttv_event_to_string(e, tfc->tf, string, TRUE, field_names, tfs);
867 g_string_append_printf(string,"\n");
868
869 if(state) {
870 g_string_append_printf(string, " %s",
871 g_quark_to_string(tfs->process->state->s));
872 }
873
874 g_info("%s",string->str);
875
876 g_string_free(string, TRUE);
877
878 /* End of text dump */
879 #endif //DONTSHOW
880
881 }
882
883 /* after_schedchange_hook
884 *
885 * The draw after hook is called by the reading API to have a
886 * particular event drawn on the screen.
887 * @param hook_data ControlFlowData structure of the viewer.
888 * @param call_data Event context.
889 *
890 * This function adds items to be drawn in a queue for each process.
891 *
892 */
893 int after_schedchange_hook(void *hook_data, void *call_data)
894 {
895 LttvTraceHook *th = (LttvTraceHook*)hook_data;
896 EventsRequest *events_request = (EventsRequest*)th->hook_data;
897 ControlFlowData *control_flow_data = events_request->viewer_data;
898
899 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
900
901 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
902
903 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
904
905 LttEvent *e;
906 e = ltt_tracefile_get_event(tfc->tf);
907
908 LttvFilter *filter = control_flow_data->filter;
909 LttTime evtime = ltt_event_time(e);
910
911 /* Add process to process list (if not present) */
912 LttvProcessState *process_in;
913 LttTime birth;
914 guint pl_height = 0;
915 HashedProcessData *hashed_process_data_in = NULL;
916
917 ProcessList *process_list = control_flow_data->process_list;
918
919 guint pid_in;
920 {
921 guint pid_out;
922 pid_out = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 0));
923 pid_in = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 1));
924 }
925
926 tfc->target_pid = pid_in;
927 if(!filter || !filter->head ||
928 lttv_filter_tree_parse(filter->head,e,tfc->tf,
929 tfc->t_context->t,tfc,NULL,NULL)) {
930 /* Find process pid_in in the list... */
931 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
932 //process_in = tfs->process;
933 guint cpu = tfs->cpu;
934 guint trace_num = ts->parent.index;
935 process_in = ts->running_process[cpu];
936 /* It should exist, because we are after the state update. */
937 #ifdef EXTRA_CHECK
938 g_assert(process_in != NULL);
939 #endif //EXTRA_CHECK
940 birth = process_in->creation_time;
941
942 hashed_process_data_in = processlist_get_process_data(process_list,
943 pid_in,
944 process_in->cpu,
945 &birth,
946 trace_num);
947 if(hashed_process_data_in == NULL)
948 {
949 g_assert(pid_in == 0 || pid_in != process_in->ppid);
950 ProcessInfo *process_info;
951 Drawing_t *drawing = control_flow_data->drawing;
952 /* Process not present */
953 processlist_add(process_list,
954 drawing,
955 pid_in,
956 process_in->tgid,
957 process_in->cpu,
958 process_in->ppid,
959 &birth,
960 trace_num,
961 process_in->name,
962 process_in->brand,
963 &pl_height,
964 &process_info,
965 &hashed_process_data_in);
966 gtk_widget_set_size_request(drawing->drawing_area,
967 -1,
968 pl_height);
969 gtk_widget_queue_draw(drawing->drawing_area);
970 }
971 /* Set the current process */
972 process_list->current_hash_data[trace_num][process_in->cpu] =
973 hashed_process_data_in;
974
975 if(ltt_time_compare(hashed_process_data_in->next_good_time,
976 evtime) <= 0)
977 {
978 TimeWindow time_window =
979 lttvwindow_get_time_window(control_flow_data->tab);
980
981 #ifdef EXTRA_CHECK
982 if(ltt_time_compare(evtime, time_window.start_time) == -1
983 || ltt_time_compare(evtime, time_window.end_time) == 1)
984 return FALSE;
985 #endif //EXTRA_CHECK
986 Drawing_t *drawing = control_flow_data->drawing;
987 guint width = drawing->width;
988 guint new_x;
989
990 convert_time_to_pixels(
991 time_window,
992 evtime,
993 width,
994 &new_x);
995
996 if(hashed_process_data_in->x.middle != new_x) {
997 hashed_process_data_in->x.middle = new_x;
998 hashed_process_data_in->x.middle_used = FALSE;
999 hashed_process_data_in->x.middle_marked = FALSE;
1000 }
1001 }
1002 }
1003
1004 return 0;
1005 }
1006
1007
1008
1009
1010 /* before_execmode_hook
1011 *
1012 * This function basically draw lines and icons. Two types of lines are drawn :
1013 * one small (3 pixels?) representing the state of the process and the second
1014 * type is thicker (10 pixels?) representing on which CPU a process is running
1015 * (and this only in running state).
1016 *
1017 * Extremums of the lines :
1018 * x_min : time of the last event context for this process kept in memory.
1019 * x_max : time of the current event.
1020 * y : middle of the process in the process list. The process is found in the
1021 * list, therefore is it's position in pixels.
1022 *
1023 * The choice of lines'color is defined by the context of the last event for this
1024 * process.
1025 */
1026
1027
1028 int before_execmode_hook(void *hook_data, void *call_data)
1029 {
1030 LttvTraceHook *th = (LttvTraceHook*)hook_data;
1031 EventsRequest *events_request = (EventsRequest*)th->hook_data;
1032 ControlFlowData *control_flow_data = events_request->viewer_data;
1033
1034 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1035
1036 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1037
1038 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1039
1040 LttEvent *e;
1041 e = ltt_tracefile_get_event(tfc->tf);
1042
1043 LttvFilter *filter = control_flow_data->filter;
1044 if(filter != NULL && filter->head != NULL)
1045 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1046 tfc->t_context->t,tfc,NULL,NULL))
1047 return FALSE;
1048
1049 LttTime evtime = ltt_event_time(e);
1050
1051 /* we are in a execmode, before the state update. We must draw the
1052 * items corresponding to the state before it changes : now is the right
1053 * time to do it.
1054 */
1055 /* For the pid */
1056 //LttvProcessState *process = tfs->process;
1057 guint cpu = tfs->cpu;
1058 guint trace_num = ts->parent.index;
1059 LttvProcessState *process = ts->running_process[cpu];
1060 g_assert(process != NULL);
1061
1062 guint pid = process->pid;
1063
1064 /* Well, the process_out existed : we must get it in the process hash
1065 * or add it, and draw its items.
1066 */
1067 /* Add process to process list (if not present) */
1068 guint pl_height = 0;
1069 HashedProcessData *hashed_process_data = NULL;
1070 ProcessList *process_list = control_flow_data->process_list;
1071 LttTime birth = process->creation_time;
1072
1073 if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1074 hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1075 } else {
1076 hashed_process_data = processlist_get_process_data(process_list,
1077 pid,
1078 process->cpu,
1079 &birth,
1080 trace_num);
1081 if(unlikely(hashed_process_data == NULL))
1082 {
1083 g_assert(pid == 0 || pid != process->ppid);
1084 ProcessInfo *process_info;
1085 /* Process not present */
1086 Drawing_t *drawing = control_flow_data->drawing;
1087 processlist_add(process_list,
1088 drawing,
1089 pid,
1090 process->tgid,
1091 process->cpu,
1092 process->ppid,
1093 &birth,
1094 trace_num,
1095 process->name,
1096 process->brand,
1097 &pl_height,
1098 &process_info,
1099 &hashed_process_data);
1100 gtk_widget_set_size_request(drawing->drawing_area,
1101 -1,
1102 pl_height);
1103 gtk_widget_queue_draw(drawing->drawing_area);
1104 }
1105 /* Set the current process */
1106 process_list->current_hash_data[trace_num][process->cpu] =
1107 hashed_process_data;
1108 }
1109
1110 /* Now, the process is in the state hash and our own process hash.
1111 * We definitely can draw the items related to the ending state.
1112 */
1113
1114 if(likely(ltt_time_compare(hashed_process_data->next_good_time,
1115 evtime) > 0))
1116 {
1117 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1118 TimeWindow time_window =
1119 lttvwindow_get_time_window(control_flow_data->tab);
1120
1121 #ifdef EXTRA_CHECK
1122 if(ltt_time_compare(evtime, time_window.start_time) == -1
1123 || ltt_time_compare(evtime, time_window.end_time) == 1)
1124 return FALSE;
1125 #endif //EXTRA_CHECK
1126 Drawing_t *drawing = control_flow_data->drawing;
1127 guint width = drawing->width;
1128 guint x;
1129 convert_time_to_pixels(
1130 time_window,
1131 evtime,
1132 width,
1133 &x);
1134
1135 /* Draw collision indicator */
1136 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1137 gdk_draw_point(hashed_process_data->pixmap,
1138 drawing->gc,
1139 x,
1140 COLLISION_POSITION(hashed_process_data->height));
1141 hashed_process_data->x.middle_marked = TRUE;
1142 }
1143 } else {
1144 TimeWindow time_window =
1145 lttvwindow_get_time_window(control_flow_data->tab);
1146
1147 #ifdef EXTRA_CHECK
1148 if(ltt_time_compare(evtime, time_window.start_time) == -1
1149 || ltt_time_compare(evtime, time_window.end_time) == 1)
1150 return FALSE;
1151 #endif //EXTRA_CHECK
1152 Drawing_t *drawing = control_flow_data->drawing;
1153 guint width = drawing->width;
1154 guint x;
1155
1156 convert_time_to_pixels(
1157 time_window,
1158 evtime,
1159 width,
1160 &x);
1161
1162
1163 /* Jump over draw if we are at the same x position */
1164 if(unlikely(x == hashed_process_data->x.middle &&
1165 hashed_process_data->x.middle_used))
1166 {
1167 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1168 /* Draw collision indicator */
1169 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1170 gdk_draw_point(hashed_process_data->pixmap,
1171 drawing->gc,
1172 x,
1173 COLLISION_POSITION(hashed_process_data->height));
1174 hashed_process_data->x.middle_marked = TRUE;
1175 }
1176 /* jump */
1177 } else {
1178
1179 DrawContext draw_context;
1180 /* Now create the drawing context that will be used to draw
1181 * items related to the last state. */
1182 draw_context.drawable = hashed_process_data->pixmap;
1183 draw_context.gc = drawing->gc;
1184 draw_context.pango_layout = drawing->pango_layout;
1185 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
1186 draw_context.drawinfo.end.x = x;
1187
1188 draw_context.drawinfo.y.over = 1;
1189 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
1190 draw_context.drawinfo.y.under = hashed_process_data->height;
1191
1192 draw_context.drawinfo.start.offset.over = 0;
1193 draw_context.drawinfo.start.offset.middle = 0;
1194 draw_context.drawinfo.start.offset.under = 0;
1195 draw_context.drawinfo.end.offset.over = 0;
1196 draw_context.drawinfo.end.offset.middle = 0;
1197 draw_context.drawinfo.end.offset.under = 0;
1198
1199 {
1200 /* Draw the line */
1201 PropertiesLine prop_line = prepare_s_e_line(process);
1202 draw_line((void*)&prop_line, (void*)&draw_context);
1203
1204 }
1205 /* become the last x position */
1206 hashed_process_data->x.middle = x;
1207 hashed_process_data->x.middle_used = TRUE;
1208 hashed_process_data->x.middle_marked = FALSE;
1209
1210 /* Calculate the next good time */
1211 convert_pixels_to_time(width, x+1, time_window,
1212 &hashed_process_data->next_good_time);
1213 }
1214 }
1215
1216 return 0;
1217 }
1218
1219 /* before_process_exit_hook
1220 *
1221 * Draw lines for process event.
1222 *
1223 * @param hook_data ControlFlowData structure of the viewer.
1224 * @param call_data Event context.
1225 *
1226 * This function adds items to be drawn in a queue for each process.
1227 *
1228 */
1229
1230
1231 int before_process_exit_hook(void *hook_data, void *call_data)
1232 {
1233 LttvTraceHook *th = (LttvTraceHook*)hook_data;
1234 EventsRequest *events_request = (EventsRequest*)th->hook_data;
1235
1236 ControlFlowData *control_flow_data = events_request->viewer_data;
1237
1238 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1239
1240 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1241
1242 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1243
1244 LttEvent *e;
1245 e = ltt_tracefile_get_event(tfc->tf);
1246
1247 LttvFilter *filter = control_flow_data->filter;
1248 if(filter != NULL && filter->head != NULL)
1249 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1250 tfc->t_context->t,tfc,NULL,NULL))
1251 return FALSE;
1252
1253 LttTime evtime = ltt_event_time(e);
1254
1255 /* Add process to process list (if not present) */
1256 //LttvProcessState *process = tfs->process;
1257 guint cpu = tfs->cpu;
1258 guint trace_num = ts->parent.index;
1259 LttvProcessState *process = ts->running_process[cpu];
1260 guint pid = process->pid;
1261 LttTime birth;
1262 guint pl_height = 0;
1263 HashedProcessData *hashed_process_data = NULL;
1264
1265 ProcessList *process_list = control_flow_data->process_list;
1266
1267 g_assert(process != NULL);
1268
1269 birth = process->creation_time;
1270
1271 if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1272 hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1273 } else {
1274 hashed_process_data = processlist_get_process_data(process_list,
1275 pid,
1276 process->cpu,
1277 &birth,
1278 trace_num);
1279 if(unlikely(hashed_process_data == NULL))
1280 {
1281 g_assert(pid == 0 || pid != process->ppid);
1282 /* Process not present */
1283 Drawing_t *drawing = control_flow_data->drawing;
1284 ProcessInfo *process_info;
1285 processlist_add(process_list,
1286 drawing,
1287 pid,
1288 process->tgid,
1289 process->cpu,
1290 process->ppid,
1291 &birth,
1292 trace_num,
1293 process->name,
1294 process->brand,
1295 &pl_height,
1296 &process_info,
1297 &hashed_process_data);
1298 gtk_widget_set_size_request(drawing->drawing_area,
1299 -1,
1300 pl_height);
1301 gtk_widget_queue_draw(drawing->drawing_area);
1302 }
1303 }
1304
1305 /* Now, the process is in the state hash and our own process hash.
1306 * We definitely can draw the items related to the ending state.
1307 */
1308
1309 if(likely(ltt_time_compare(hashed_process_data->next_good_time,
1310 evtime) > 0))
1311 {
1312 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1313 TimeWindow time_window =
1314 lttvwindow_get_time_window(control_flow_data->tab);
1315
1316 #ifdef EXTRA_CHECK
1317 if(ltt_time_compare(evtime, time_window.start_time) == -1
1318 || ltt_time_compare(evtime, time_window.end_time) == 1)
1319 return FALSE;
1320 #endif //EXTRA_CHECK
1321 Drawing_t *drawing = control_flow_data->drawing;
1322 guint width = drawing->width;
1323 guint x;
1324 convert_time_to_pixels(
1325 time_window,
1326 evtime,
1327 width,
1328 &x);
1329
1330 /* Draw collision indicator */
1331 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1332 gdk_draw_point(hashed_process_data->pixmap,
1333 drawing->gc,
1334 x,
1335 COLLISION_POSITION(hashed_process_data->height));
1336 hashed_process_data->x.middle_marked = TRUE;
1337 }
1338 } else {
1339 TimeWindow time_window =
1340 lttvwindow_get_time_window(control_flow_data->tab);
1341
1342 #ifdef EXTRA_CHECK
1343 if(ltt_time_compare(evtime, time_window.start_time) == -1
1344 || ltt_time_compare(evtime, time_window.end_time) == 1)
1345 return FALSE;
1346 #endif //EXTRA_CHECK
1347 Drawing_t *drawing = control_flow_data->drawing;
1348 guint width = drawing->width;
1349 guint x;
1350
1351 convert_time_to_pixels(
1352 time_window,
1353 evtime,
1354 width,
1355 &x);
1356
1357
1358 /* Jump over draw if we are at the same x position */
1359 if(unlikely(x == hashed_process_data->x.middle &&
1360 hashed_process_data->x.middle_used))
1361 {
1362 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1363 /* Draw collision indicator */
1364 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1365 gdk_draw_point(hashed_process_data->pixmap,
1366 drawing->gc,
1367 x,
1368 COLLISION_POSITION(hashed_process_data->height));
1369 hashed_process_data->x.middle_marked = TRUE;
1370 }
1371 /* jump */
1372 } else {
1373 DrawContext draw_context;
1374
1375 /* Now create the drawing context that will be used to draw
1376 * items related to the last state. */
1377 draw_context.drawable = hashed_process_data->pixmap;
1378 draw_context.gc = drawing->gc;
1379 draw_context.pango_layout = drawing->pango_layout;
1380 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
1381 draw_context.drawinfo.end.x = x;
1382
1383 draw_context.drawinfo.y.over = 1;
1384 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
1385 draw_context.drawinfo.y.under = hashed_process_data->height;
1386
1387 draw_context.drawinfo.start.offset.over = 0;
1388 draw_context.drawinfo.start.offset.middle = 0;
1389 draw_context.drawinfo.start.offset.under = 0;
1390 draw_context.drawinfo.end.offset.over = 0;
1391 draw_context.drawinfo.end.offset.middle = 0;
1392 draw_context.drawinfo.end.offset.under = 0;
1393
1394 {
1395 /* Draw the line */
1396 PropertiesLine prop_line = prepare_s_e_line(process);
1397 draw_line((void*)&prop_line, (void*)&draw_context);
1398
1399 }
1400 /* become the last x position */
1401 hashed_process_data->x.middle = x;
1402 hashed_process_data->x.middle_used = TRUE;
1403 hashed_process_data->x.middle_marked = FALSE;
1404
1405 /* Calculate the next good time */
1406 convert_pixels_to_time(width, x+1, time_window,
1407 &hashed_process_data->next_good_time);
1408 }
1409 }
1410
1411 return 0;
1412
1413 }
1414
1415
1416
1417 /* before_process_release_hook
1418 *
1419 * Draw lines for process event.
1420 *
1421 * @param hook_data ControlFlowData structure of the viewer.
1422 * @param call_data Event context.
1423 *
1424 * This function adds items to be drawn in a queue for each process.
1425 *
1426 */
1427
1428
1429 int before_process_release_hook(void *hook_data, void *call_data)
1430 {
1431 LttvTraceHook *th = (LttvTraceHook*)hook_data;
1432 EventsRequest *events_request = (EventsRequest*)th->hook_data;
1433
1434 ControlFlowData *control_flow_data = events_request->viewer_data;
1435
1436 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1437
1438 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1439
1440 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1441
1442 LttEvent *e;
1443 e = ltt_tracefile_get_event(tfc->tf);
1444
1445 LttvFilter *filter = control_flow_data->filter;
1446 if(filter != NULL && filter->head != NULL)
1447 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1448 tfc->t_context->t,tfc,NULL,NULL))
1449 return FALSE;
1450
1451 LttTime evtime = ltt_event_time(e);
1452
1453 guint trace_num = ts->parent.index;
1454
1455 guint pid;
1456 {
1457 pid = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 0));
1458 }
1459
1460 /* Add process to process list (if not present) */
1461 /* Don't care about the process if it's not in the state hash already :
1462 * that means a process that has never done anything in the trace and
1463 * unknown suddently gets destroyed : no state meaningful to show. */
1464 LttvProcessState *process = lttv_state_find_process(ts, ANY_CPU, pid);
1465
1466 if(process != NULL) {
1467 LttTime birth;
1468 guint pl_height = 0;
1469 HashedProcessData *hashed_process_data = NULL;
1470
1471 ProcessList *process_list = control_flow_data->process_list;
1472
1473 birth = process->creation_time;
1474
1475 /* Cannot use current process : this event happens on another process,
1476 * action done by the parent. */
1477 hashed_process_data = processlist_get_process_data(process_list,
1478 pid,
1479 process->cpu,
1480 &birth,
1481 trace_num);
1482 if(unlikely(hashed_process_data == NULL))
1483 /*
1484 * Process already been scheduled out EXIT_DEAD, not in the process list
1485 * anymore. Just return.
1486 */
1487 return FALSE;
1488
1489 /* Now, the process is in the state hash and our own process hash.
1490 * We definitely can draw the items related to the ending state.
1491 */
1492
1493 if(likely(ltt_time_compare(hashed_process_data->next_good_time,
1494 evtime) > 0))
1495 {
1496 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1497 TimeWindow time_window =
1498 lttvwindow_get_time_window(control_flow_data->tab);
1499
1500 #ifdef EXTRA_CHECK
1501 if(ltt_time_compare(evtime, time_window.start_time) == -1
1502 || ltt_time_compare(evtime, time_window.end_time) == 1)
1503 return FALSE;
1504 #endif //EXTRA_CHECK
1505 Drawing_t *drawing = control_flow_data->drawing;
1506 guint width = drawing->width;
1507 guint x;
1508 convert_time_to_pixels(
1509 time_window,
1510 evtime,
1511 width,
1512 &x);
1513
1514 /* Draw collision indicator */
1515 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1516 gdk_draw_point(hashed_process_data->pixmap,
1517 drawing->gc,
1518 x,
1519 COLLISION_POSITION(hashed_process_data->height));
1520 hashed_process_data->x.middle_marked = TRUE;
1521 }
1522 } else {
1523 TimeWindow time_window =
1524 lttvwindow_get_time_window(control_flow_data->tab);
1525
1526 #ifdef EXTRA_CHECK
1527 if(ltt_time_compare(evtime, time_window.start_time) == -1
1528 || ltt_time_compare(evtime, time_window.end_time) == 1)
1529 return FALSE;
1530 #endif //EXTRA_CHECK
1531 Drawing_t *drawing = control_flow_data->drawing;
1532 guint width = drawing->width;
1533 guint x;
1534
1535 convert_time_to_pixels(
1536 time_window,
1537 evtime,
1538 width,
1539 &x);
1540
1541
1542 /* Jump over draw if we are at the same x position */
1543 if(unlikely(x == hashed_process_data->x.middle &&
1544 hashed_process_data->x.middle_used))
1545 {
1546 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1547 /* Draw collision indicator */
1548 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1549 gdk_draw_point(hashed_process_data->pixmap,
1550 drawing->gc,
1551 x,
1552 COLLISION_POSITION(hashed_process_data->height));
1553 hashed_process_data->x.middle_marked = TRUE;
1554 }
1555 /* jump */
1556 } else {
1557 DrawContext draw_context;
1558
1559 /* Now create the drawing context that will be used to draw
1560 * items related to the last state. */
1561 draw_context.drawable = hashed_process_data->pixmap;
1562 draw_context.gc = drawing->gc;
1563 draw_context.pango_layout = drawing->pango_layout;
1564 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
1565 draw_context.drawinfo.end.x = x;
1566
1567 draw_context.drawinfo.y.over = 1;
1568 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
1569 draw_context.drawinfo.y.under = hashed_process_data->height;
1570
1571 draw_context.drawinfo.start.offset.over = 0;
1572 draw_context.drawinfo.start.offset.middle = 0;
1573 draw_context.drawinfo.start.offset.under = 0;
1574 draw_context.drawinfo.end.offset.over = 0;
1575 draw_context.drawinfo.end.offset.middle = 0;
1576 draw_context.drawinfo.end.offset.under = 0;
1577
1578 {
1579 /* Draw the line */
1580 PropertiesLine prop_line = prepare_s_e_line(process);
1581 draw_line((void*)&prop_line, (void*)&draw_context);
1582
1583 }
1584 /* become the last x position */
1585 hashed_process_data->x.middle = x;
1586 hashed_process_data->x.middle_used = TRUE;
1587 hashed_process_data->x.middle_marked = FALSE;
1588
1589 /* Calculate the next good time */
1590 convert_pixels_to_time(width, x+1, time_window,
1591 &hashed_process_data->next_good_time);
1592 }
1593 }
1594 }
1595
1596 return 0;
1597 }
1598
1599
1600
1601
1602
1603 /* after_process_fork_hook
1604 *
1605 * Create the processlist entry for the child process. Put the last
1606 * position in x at the current time value.
1607 *
1608 * @param hook_data ControlFlowData structure of the viewer.
1609 * @param call_data Event context.
1610 *
1611 * This function adds items to be drawn in a queue for each process.
1612 *
1613 */
1614 int after_process_fork_hook(void *hook_data, void *call_data)
1615 {
1616 LttvTraceHook *th = (LttvTraceHook*)hook_data;
1617 EventsRequest *events_request = (EventsRequest*)th->hook_data;
1618 ControlFlowData *control_flow_data = events_request->viewer_data;
1619
1620 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1621
1622 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1623
1624 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1625
1626 LttEvent *e;
1627 e = ltt_tracefile_get_event(tfc->tf);
1628
1629 LttvFilter *filter = control_flow_data->filter;
1630 if(filter != NULL && filter->head != NULL)
1631 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1632 tfc->t_context->t,tfc,NULL,NULL))
1633 return FALSE;
1634
1635 LttTime evtime = ltt_event_time(e);
1636
1637 guint child_pid;
1638 {
1639 child_pid = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 1));
1640 }
1641
1642 /* Add process to process list (if not present) */
1643 LttvProcessState *process_child;
1644 LttTime birth;
1645 guint pl_height = 0;
1646 HashedProcessData *hashed_process_data_child = NULL;
1647
1648 ProcessList *process_list = control_flow_data->process_list;
1649
1650 /* Find child in the list... */
1651 process_child = lttv_state_find_process(ts, ANY_CPU, child_pid);
1652 /* It should exist, because we are after the state update. */
1653 g_assert(process_child != NULL);
1654
1655 birth = process_child->creation_time;
1656 guint trace_num = ts->parent.index;
1657
1658 /* Cannot use current process, because this action is done by the parent
1659 * on its child. */
1660 hashed_process_data_child = processlist_get_process_data(process_list,
1661 child_pid,
1662 process_child->cpu,
1663 &birth,
1664 trace_num);
1665 if(likely(hashed_process_data_child == NULL))
1666 {
1667 g_assert(child_pid == 0 || child_pid != process_child->ppid);
1668 /* Process not present */
1669 Drawing_t *drawing = control_flow_data->drawing;
1670 ProcessInfo *process_info;
1671 processlist_add(process_list,
1672 drawing,
1673 child_pid,
1674 process_child->tgid,
1675 process_child->cpu,
1676 process_child->ppid,
1677 &birth,
1678 trace_num,
1679 process_child->name,
1680 process_child->brand,
1681 &pl_height,
1682 &process_info,
1683 &hashed_process_data_child);
1684 gtk_widget_set_size_request(drawing->drawing_area,
1685 -1,
1686 pl_height);
1687 gtk_widget_queue_draw(drawing->drawing_area);
1688 } else {
1689 processlist_set_ppid(process_list, process_child->ppid,
1690 hashed_process_data_child);
1691 processlist_set_tgid(process_list, process_child->tgid,
1692 hashed_process_data_child);
1693 }
1694
1695
1696 if(likely(ltt_time_compare(hashed_process_data_child->next_good_time,
1697 evtime) <= 0))
1698 {
1699 TimeWindow time_window =
1700 lttvwindow_get_time_window(control_flow_data->tab);
1701
1702 #ifdef EXTRA_CHECK
1703 if(ltt_time_compare(evtime, time_window.start_time) == -1
1704 || ltt_time_compare(evtime, time_window.end_time) == 1)
1705 return FALSE;
1706 #endif //EXTRA_CHECK
1707 Drawing_t *drawing = control_flow_data->drawing;
1708 guint width = drawing->width;
1709 guint new_x;
1710 convert_time_to_pixels(
1711 time_window,
1712 evtime,
1713 width,
1714 &new_x);
1715
1716 if(likely(hashed_process_data_child->x.over != new_x)) {
1717 hashed_process_data_child->x.over = new_x;
1718 hashed_process_data_child->x.over_used = FALSE;
1719 hashed_process_data_child->x.over_marked = FALSE;
1720 }
1721 if(likely(hashed_process_data_child->x.middle != new_x)) {
1722 hashed_process_data_child->x.middle = new_x;
1723 hashed_process_data_child->x.middle_used = FALSE;
1724 hashed_process_data_child->x.middle_marked = FALSE;
1725 }
1726 if(likely(hashed_process_data_child->x.under != new_x)) {
1727 hashed_process_data_child->x.under = new_x;
1728 hashed_process_data_child->x.under_used = FALSE;
1729 hashed_process_data_child->x.under_marked = FALSE;
1730 }
1731 }
1732 return FALSE;
1733 }
1734
1735
1736
1737 /* after_process_exit_hook
1738 *
1739 * Create the processlist entry for the child process. Put the last
1740 * position in x at the current time value.
1741 *
1742 * @param hook_data ControlFlowData structure of the viewer.
1743 * @param call_data Event context.
1744 *
1745 * This function adds items to be drawn in a queue for each process.
1746 *
1747 */
1748 int after_process_exit_hook(void *hook_data, void *call_data)
1749 {
1750 LttvTraceHook *th = (LttvTraceHook*)hook_data;
1751 EventsRequest *events_request = (EventsRequest*)th->hook_data;
1752 ControlFlowData *control_flow_data = events_request->viewer_data;
1753
1754 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1755
1756 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1757
1758 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1759
1760 LttEvent *e;
1761 e = ltt_tracefile_get_event(tfc->tf);
1762
1763 LttvFilter *filter = control_flow_data->filter;
1764 if(filter != NULL && filter->head != NULL)
1765 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1766 tfc->t_context->t,tfc,NULL,NULL))
1767 return FALSE;
1768
1769 LttTime evtime = ltt_event_time(e);
1770
1771 /* Add process to process list (if not present) */
1772 //LttvProcessState *process = tfs->process;
1773 guint cpu = tfs->cpu;
1774 guint trace_num = ts->parent.index;
1775 LttvProcessState *process = ts->running_process[cpu];
1776
1777 /* It should exist, because we are after the state update. */
1778 g_assert(process != NULL);
1779
1780 guint pid = process->pid;
1781 LttTime birth;
1782 guint pl_height = 0;
1783 HashedProcessData *hashed_process_data = NULL;
1784
1785 ProcessList *process_list = control_flow_data->process_list;
1786
1787 birth = process->creation_time;
1788
1789 if(likely(process_list->current_hash_data[trace_num][cpu] != NULL) ){
1790 hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1791 } else {
1792 hashed_process_data = processlist_get_process_data(process_list,
1793 pid,
1794 process->cpu,
1795 &birth,
1796 trace_num);
1797 if(unlikely(hashed_process_data == NULL))
1798 {
1799 g_assert(pid == 0 || pid != process->ppid);
1800 /* Process not present */
1801 Drawing_t *drawing = control_flow_data->drawing;
1802 ProcessInfo *process_info;
1803 processlist_add(process_list,
1804 drawing,
1805 pid,
1806 process->tgid,
1807 process->cpu,
1808 process->ppid,
1809 &birth,
1810 trace_num,
1811 process->name,
1812 process->brand,
1813 &pl_height,
1814 &process_info,
1815 &hashed_process_data);
1816 gtk_widget_set_size_request(drawing->drawing_area,
1817 -1,
1818 pl_height);
1819 gtk_widget_queue_draw(drawing->drawing_area);
1820 }
1821
1822 /* Set the current process */
1823 process_list->current_hash_data[trace_num][process->cpu] =
1824 hashed_process_data;
1825 }
1826
1827 if(unlikely(ltt_time_compare(hashed_process_data->next_good_time,
1828 evtime) <= 0))
1829 {
1830 TimeWindow time_window =
1831 lttvwindow_get_time_window(control_flow_data->tab);
1832
1833 #ifdef EXTRA_CHECK
1834 if(ltt_time_compare(evtime, time_window.start_time) == -1
1835 || ltt_time_compare(evtime, time_window.end_time) == 1)
1836 return FALSE;
1837 #endif //EXTRA_CHECK
1838 Drawing_t *drawing = control_flow_data->drawing;
1839 guint width = drawing->width;
1840 guint new_x;
1841 convert_time_to_pixels(
1842 time_window,
1843 evtime,
1844 width,
1845 &new_x);
1846 if(unlikely(hashed_process_data->x.middle != new_x)) {
1847 hashed_process_data->x.middle = new_x;
1848 hashed_process_data->x.middle_used = FALSE;
1849 hashed_process_data->x.middle_marked = FALSE;
1850 }
1851 }
1852
1853 return FALSE;
1854 }
1855
1856
1857 /* Get the filename of the process to print */
1858 int after_fs_exec_hook(void *hook_data, void *call_data)
1859 {
1860 LttvTraceHook *th = (LttvTraceHook*)hook_data;
1861 EventsRequest *events_request = (EventsRequest*)th->hook_data;
1862 ControlFlowData *control_flow_data = events_request->viewer_data;
1863
1864 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1865
1866 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1867
1868 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1869
1870 LttEvent *e;
1871 e = ltt_tracefile_get_event(tfc->tf);
1872
1873 LttvFilter *filter = control_flow_data->filter;
1874 if(filter != NULL && filter->head != NULL)
1875 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1876 tfc->t_context->t,tfc,NULL,NULL))
1877 return FALSE;
1878
1879 guint cpu = tfs->cpu;
1880 guint trace_num = ts->parent.index;
1881 LttvProcessState *process = ts->running_process[cpu];
1882 g_assert(process != NULL);
1883
1884 guint pid = process->pid;
1885
1886 /* Well, the process_out existed : we must get it in the process hash
1887 * or add it, and draw its items.
1888 */
1889 /* Add process to process list (if not present) */
1890 guint pl_height = 0;
1891 HashedProcessData *hashed_process_data = NULL;
1892 ProcessList *process_list = control_flow_data->process_list;
1893 LttTime birth = process->creation_time;
1894
1895 if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1896 hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1897 } else {
1898 hashed_process_data = processlist_get_process_data(process_list,
1899 pid,
1900 process->cpu,
1901 &birth,
1902 trace_num);
1903 if(unlikely(hashed_process_data == NULL))
1904 {
1905 g_assert(pid == 0 || pid != process->ppid);
1906 ProcessInfo *process_info;
1907 /* Process not present */
1908 Drawing_t *drawing = control_flow_data->drawing;
1909 processlist_add(process_list,
1910 drawing,
1911 pid,
1912 process->tgid,
1913 process->cpu,
1914 process->ppid,
1915 &birth,
1916 trace_num,
1917 process->name,
1918 process->brand,
1919 &pl_height,
1920 &process_info,
1921 &hashed_process_data);
1922 gtk_widget_set_size_request(drawing->drawing_area,
1923 -1,
1924 pl_height);
1925 gtk_widget_queue_draw(drawing->drawing_area);
1926 }
1927 /* Set the current process */
1928 process_list->current_hash_data[trace_num][process->cpu] =
1929 hashed_process_data;
1930 }
1931
1932 processlist_set_name(process_list, process->name, hashed_process_data);
1933
1934 return 0;
1935
1936 }
1937
1938 /* Get the filename of the process to print */
1939 int after_user_generic_thread_brand_hook(void *hook_data, void *call_data)
1940 {
1941 LttvTraceHook *th = (LttvTraceHook*)hook_data;
1942 EventsRequest *events_request = (EventsRequest*)th->hook_data;
1943 ControlFlowData *control_flow_data = events_request->viewer_data;
1944
1945 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1946
1947 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1948
1949 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1950
1951 LttEvent *e;
1952 e = ltt_tracefile_get_event(tfc->tf);
1953
1954 LttvFilter *filter = control_flow_data->filter;
1955 if(filter != NULL && filter->head != NULL)
1956 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1957 tfc->t_context->t,tfc,NULL,NULL))
1958 return FALSE;
1959
1960 guint cpu = tfs->cpu;
1961 guint trace_num = ts->parent.index;
1962 LttvProcessState *process = ts->running_process[cpu];
1963 g_assert(process != NULL);
1964
1965 guint pid = process->pid;
1966
1967 /* Well, the process_out existed : we must get it in the process hash
1968 * or add it, and draw its items.
1969 */
1970 /* Add process to process list (if not present) */
1971 guint pl_height = 0;
1972 HashedProcessData *hashed_process_data = NULL;
1973 ProcessList *process_list = control_flow_data->process_list;
1974 LttTime birth = process->creation_time;
1975
1976 if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1977 hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1978 } else {
1979 hashed_process_data = processlist_get_process_data(process_list,
1980 pid,
1981 process->cpu,
1982 &birth,
1983 trace_num);
1984 if(unlikely(hashed_process_data == NULL))
1985 {
1986 g_assert(pid == 0 || pid != process->ppid);
1987 ProcessInfo *process_info;
1988 /* Process not present */
1989 Drawing_t *drawing = control_flow_data->drawing;
1990 processlist_add(process_list,
1991 drawing,
1992 pid,
1993 process->tgid,
1994 process->cpu,
1995 process->ppid,
1996 &birth,
1997 trace_num,
1998 process->name,
1999 process->brand,
2000 &pl_height,
2001 &process_info,
2002 &hashed_process_data);
2003 gtk_widget_set_size_request(drawing->drawing_area,
2004 -1,
2005 pl_height);
2006 gtk_widget_queue_draw(drawing->drawing_area);
2007 }
2008 /* Set the current process */
2009 process_list->current_hash_data[trace_num][process->cpu] =
2010 hashed_process_data;
2011 }
2012
2013 processlist_set_brand(process_list, process->brand, hashed_process_data);
2014
2015 return 0;
2016
2017 }
2018
2019
2020 /* after_event_enum_process_hook
2021 *
2022 * Create the processlist entry for the child process. Put the last
2023 * position in x at the current time value.
2024 *
2025 * @param hook_data ControlFlowData structure of the viewer.
2026 * @param call_data Event context.
2027 *
2028 * This function adds items to be drawn in a queue for each process.
2029 *
2030 */
2031 int after_event_enum_process_hook(void *hook_data, void *call_data)
2032 {
2033 LttvTraceHook *th = (LttvTraceHook*)hook_data;
2034 EventsRequest *events_request = (EventsRequest*)th->hook_data;
2035 ControlFlowData *control_flow_data = events_request->viewer_data;
2036
2037 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
2038
2039 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
2040
2041 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
2042
2043 guint first_cpu, nb_cpus, cpu;
2044
2045 LttEvent *e;
2046 e = ltt_tracefile_get_event(tfc->tf);
2047
2048 LttvFilter *filter = control_flow_data->filter;
2049 if(filter != NULL && filter->head != NULL)
2050 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
2051 tfc->t_context->t,tfc,NULL,NULL))
2052 return FALSE;
2053
2054 LttTime evtime = ltt_event_time(e);
2055
2056 /* Add process to process list (if not present) */
2057 LttvProcessState *process_in;
2058 LttTime birth;
2059 guint pl_height = 0;
2060 HashedProcessData *hashed_process_data_in = NULL;
2061
2062 ProcessList *process_list = control_flow_data->process_list;
2063 guint trace_num = ts->parent.index;
2064
2065 guint pid_in;
2066 {
2067 pid_in = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 0));
2068 }
2069
2070 if(pid_in == 0) {
2071 first_cpu = 0;
2072 nb_cpus = ltt_trace_get_num_cpu(ts->parent.t);
2073 } else {
2074 first_cpu = ANY_CPU;
2075 nb_cpus = ANY_CPU+1;
2076 }
2077
2078 for(cpu = first_cpu; cpu < nb_cpus; cpu++) {
2079 /* Find process pid_in in the list... */
2080 process_in = lttv_state_find_process(ts, cpu, pid_in);
2081 //process_in = tfs->process;
2082 //guint cpu = tfs->cpu;
2083 //guint trace_num = ts->parent.index;
2084 //process_in = ts->running_process[cpu];
2085 /* It should exist, because we are after the state update. */
2086 #ifdef EXTRA_CHECK
2087 //g_assert(process_in != NULL);
2088 #endif //EXTRA_CHECK
2089 birth = process_in->creation_time;
2090
2091 hashed_process_data_in = processlist_get_process_data(process_list,
2092 pid_in,
2093 process_in->cpu,
2094 &birth,
2095 trace_num);
2096 if(hashed_process_data_in == NULL)
2097 {
2098 if(pid_in != 0 && pid_in == process_in->ppid)
2099 g_critical("TEST %u , %u", pid_in, process_in->ppid);
2100 g_assert(pid_in == 0 || pid_in != process_in->ppid);
2101 ProcessInfo *process_info;
2102 Drawing_t *drawing = control_flow_data->drawing;
2103 /* Process not present */
2104 processlist_add(process_list,
2105 drawing,
2106 pid_in,
2107 process_in->tgid,
2108 process_in->cpu,
2109 process_in->ppid,
2110 &birth,
2111 trace_num,
2112 process_in->name,
2113 process_in->brand,
2114 &pl_height,
2115 &process_info,
2116 &hashed_process_data_in);
2117 gtk_widget_set_size_request(drawing->drawing_area,
2118 -1,
2119 pl_height);
2120 gtk_widget_queue_draw(drawing->drawing_area);
2121 } else {
2122 processlist_set_name(process_list, process_in->name,
2123 hashed_process_data_in);
2124 processlist_set_ppid(process_list, process_in->ppid,
2125 hashed_process_data_in);
2126 processlist_set_tgid(process_list, process_in->tgid,
2127 hashed_process_data_in);
2128 }
2129 }
2130 return 0;
2131 }
2132
2133
2134 gint update_time_window_hook(void *hook_data, void *call_data)
2135 {
2136 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
2137 Drawing_t *drawing = control_flow_data->drawing;
2138 ProcessList *process_list = control_flow_data->process_list;
2139
2140 const TimeWindowNotifyData *time_window_nofify_data =
2141 ((const TimeWindowNotifyData *)call_data);
2142
2143 TimeWindow *old_time_window =
2144 time_window_nofify_data->old_time_window;
2145 TimeWindow *new_time_window =
2146 time_window_nofify_data->new_time_window;
2147
2148 /* Update the ruler */
2149 drawing_update_ruler(control_flow_data->drawing,
2150 new_time_window);
2151
2152
2153 /* Two cases : zoom in/out or scrolling */
2154
2155 /* In order to make sure we can reuse the old drawing, the scale must
2156 * be the same and the new time interval being partly located in the
2157 * currently shown time interval. (reuse is only for scrolling)
2158 */
2159
2160 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
2161 old_time_window->start_time.tv_sec,
2162 old_time_window->start_time.tv_nsec,
2163 old_time_window->time_width.tv_sec,
2164 old_time_window->time_width.tv_nsec);
2165
2166 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
2167 new_time_window->start_time.tv_sec,
2168 new_time_window->start_time.tv_nsec,
2169 new_time_window->time_width.tv_sec,
2170 new_time_window->time_width.tv_nsec);
2171
2172 if( new_time_window->time_width.tv_sec == old_time_window->time_width.tv_sec
2173 && new_time_window->time_width.tv_nsec == old_time_window->time_width.tv_nsec)
2174 {
2175 /* Same scale (scrolling) */
2176 g_info("scrolling");
2177 LttTime *ns = &new_time_window->start_time;
2178 LttTime *nw = &new_time_window->time_width;
2179 LttTime *os = &old_time_window->start_time;
2180 LttTime *ow = &old_time_window->time_width;
2181 LttTime old_end = old_time_window->end_time;
2182 LttTime new_end = new_time_window->end_time;
2183 //if(ns<os+w<ns+w)
2184 //if(ns<os+w && os+w<ns+w)
2185 //if(ns<old_end && os<ns)
2186 if(ltt_time_compare(*ns, old_end) == -1
2187 && ltt_time_compare(*os, *ns) == -1)
2188 {
2189 g_info("scrolling near right");
2190 /* Scroll right, keep right part of the screen */
2191 guint x = 0;
2192 guint width = control_flow_data->drawing->width;
2193 convert_time_to_pixels(
2194 *old_time_window,
2195 *ns,
2196 width,
2197 &x);
2198
2199 /* Copy old data to new location */
2200 copy_pixmap_region(process_list,
2201 NULL,
2202 control_flow_data->drawing->drawing_area->style->black_gc,
2203 NULL,
2204 x, 0,
2205 0, 0,
2206 control_flow_data->drawing->width-x+SAFETY, -1);
2207
2208 if(drawing->damage_begin == drawing->damage_end)
2209 drawing->damage_begin = control_flow_data->drawing->width-x;
2210 else
2211 drawing->damage_begin = 0;
2212
2213 drawing->damage_end = control_flow_data->drawing->width;
2214
2215 /* Clear the data request background, but not SAFETY */
2216 rectangle_pixmap(process_list,
2217 control_flow_data->drawing->drawing_area->style->black_gc,
2218 TRUE,
2219 drawing->damage_begin+SAFETY, 0,
2220 drawing->damage_end - drawing->damage_begin, // do not overlap
2221 -1);
2222 gtk_widget_queue_draw(drawing->drawing_area);
2223 //gtk_widget_queue_draw_area (drawing->drawing_area,
2224 // 0,0,
2225 // control_flow_data->drawing->width,
2226 // control_flow_data->drawing->height);
2227
2228 /* Get new data for the rest. */
2229 drawing_data_request(control_flow_data->drawing,
2230 drawing->damage_begin, 0,
2231 drawing->damage_end - drawing->damage_begin,
2232 control_flow_data->drawing->height);
2233 } else {
2234 //if(ns<os<ns+w)
2235 //if(ns<os && os<ns+w)
2236 //if(ns<os && os<new_end)
2237 if(ltt_time_compare(*ns,*os) == -1
2238 && ltt_time_compare(*os,new_end) == -1)
2239 {
2240 g_info("scrolling near left");
2241 /* Scroll left, keep left part of the screen */
2242 guint x = 0;
2243 guint width = control_flow_data->drawing->width;
2244 convert_time_to_pixels(
2245 *new_time_window,
2246 *os,
2247 width,
2248 &x);
2249
2250 /* Copy old data to new location */
2251 copy_pixmap_region (process_list,
2252 NULL,
2253 control_flow_data->drawing->drawing_area->style->black_gc,
2254 NULL,
2255 0, 0,
2256 x, 0,
2257 -1, -1);
2258
2259 if(drawing->damage_begin == drawing->damage_end)
2260 drawing->damage_end = x;
2261 else
2262 drawing->damage_end =
2263 control_flow_data->drawing->width;
2264
2265 drawing->damage_begin = 0;
2266
2267 rectangle_pixmap (process_list,
2268 control_flow_data->drawing->drawing_area->style->black_gc,
2269 TRUE,
2270 drawing->damage_begin, 0,
2271 drawing->damage_end - drawing->damage_begin, // do not overlap
2272 -1);
2273
2274 gtk_widget_queue_draw(drawing->drawing_area);
2275 //gtk_widget_queue_draw_area (drawing->drawing_area,
2276 // 0,0,
2277 // control_flow_data->drawing->width,
2278 // control_flow_data->drawing->height);
2279
2280
2281 /* Get new data for the rest. */
2282 drawing_data_request(control_flow_data->drawing,
2283 drawing->damage_begin, 0,
2284 drawing->damage_end - drawing->damage_begin,
2285 control_flow_data->drawing->height);
2286
2287 } else {
2288 if(ltt_time_compare(*ns,*os) == 0)
2289 {
2290 g_info("not scrolling");
2291 } else {
2292 g_info("scrolling far");
2293 /* Cannot reuse any part of the screen : far jump */
2294
2295
2296 rectangle_pixmap (process_list,
2297 control_flow_data->drawing->drawing_area->style->black_gc,
2298 TRUE,
2299 0, 0,
2300 control_flow_data->drawing->width+SAFETY, // do not overlap
2301 -1);
2302
2303 //gtk_widget_queue_draw_area (drawing->drawing_area,
2304 // 0,0,
2305 // control_flow_data->drawing->width,
2306 // control_flow_data->drawing->height);
2307 gtk_widget_queue_draw(drawing->drawing_area);
2308
2309 drawing->damage_begin = 0;
2310 drawing->damage_end = control_flow_data->drawing->width;
2311
2312 drawing_data_request(control_flow_data->drawing,
2313 0, 0,
2314 control_flow_data->drawing->width,
2315 control_flow_data->drawing->height);
2316
2317 }
2318 }
2319 }
2320 } else {
2321 /* Different scale (zoom) */
2322 g_info("zoom");
2323
2324 rectangle_pixmap (process_list,
2325 control_flow_data->drawing->drawing_area->style->black_gc,
2326 TRUE,
2327 0, 0,
2328 control_flow_data->drawing->width+SAFETY, // do not overlap
2329 -1);
2330
2331 //gtk_widget_queue_draw_area (drawing->drawing_area,
2332 // 0,0,
2333 // control_flow_data->drawing->width,
2334 // control_flow_data->drawing->height);
2335 gtk_widget_queue_draw(drawing->drawing_area);
2336
2337 drawing->damage_begin = 0;
2338 drawing->damage_end = control_flow_data->drawing->width;
2339
2340 drawing_data_request(control_flow_data->drawing,
2341 0, 0,
2342 control_flow_data->drawing->width,
2343 control_flow_data->drawing->height);
2344 }
2345
2346 /* Update directly when scrolling */
2347 gdk_window_process_updates(control_flow_data->drawing->drawing_area->window,
2348 TRUE);
2349
2350 return 0;
2351 }
2352
2353 gint traceset_notify(void *hook_data, void *call_data)
2354 {
2355 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
2356 Drawing_t *drawing = control_flow_data->drawing;
2357
2358 if(unlikely(drawing->gc == NULL)) {
2359 return FALSE;
2360 }
2361 if(drawing->dotted_gc == NULL) {
2362 return FALSE;
2363 }
2364
2365 drawing_clear(control_flow_data->drawing);
2366 processlist_clear(control_flow_data->process_list);
2367 gtk_widget_set_size_request(
2368 control_flow_data->drawing->drawing_area,
2369 -1, processlist_get_height(control_flow_data->process_list));
2370 redraw_notify(control_flow_data, NULL);
2371
2372 request_background_data(control_flow_data);
2373
2374 return FALSE;
2375 }
2376
2377 gint redraw_notify(void *hook_data, void *call_data)
2378 {
2379 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
2380 Drawing_t *drawing = control_flow_data->drawing;
2381 GtkWidget *widget = drawing->drawing_area;
2382
2383 drawing->damage_begin = 0;
2384 drawing->damage_end = drawing->width;
2385
2386 /* fun feature, to be separated someday... */
2387 drawing_clear(control_flow_data->drawing);
2388 processlist_clear(control_flow_data->process_list);
2389 gtk_widget_set_size_request(
2390 control_flow_data->drawing->drawing_area,
2391 -1, processlist_get_height(control_flow_data->process_list));
2392 // Clear the images
2393 rectangle_pixmap (control_flow_data->process_list,
2394 widget->style->black_gc,
2395 TRUE,
2396 0, 0,
2397 drawing->alloc_width,
2398 -1);
2399
2400 gtk_widget_queue_draw(drawing->drawing_area);
2401
2402 if(drawing->damage_begin < drawing->damage_end)
2403 {
2404 drawing_data_request(drawing,
2405 drawing->damage_begin,
2406 0,
2407 drawing->damage_end-drawing->damage_begin,
2408 drawing->height);
2409 }
2410
2411 //gtk_widget_queue_draw_area(drawing->drawing_area,
2412 // 0,0,
2413 // drawing->width,
2414 // drawing->height);
2415 return FALSE;
2416
2417 }
2418
2419
2420 gint continue_notify(void *hook_data, void *call_data)
2421 {
2422 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
2423 Drawing_t *drawing = control_flow_data->drawing;
2424
2425 //g_assert(widget->allocation.width == drawing->damage_end);
2426
2427 if(drawing->damage_begin < drawing->damage_end)
2428 {
2429 drawing_data_request(drawing,
2430 drawing->damage_begin,
2431 0,
2432 drawing->damage_end-drawing->damage_begin,
2433 drawing->height);
2434 }
2435
2436 return FALSE;
2437 }
2438
2439
2440 gint update_current_time_hook(void *hook_data, void *call_data)
2441 {
2442 ControlFlowData *control_flow_data = (ControlFlowData*)hook_data;
2443 Drawing_t *drawing = control_flow_data->drawing;
2444
2445 LttTime current_time = *((LttTime*)call_data);
2446
2447 TimeWindow time_window =
2448 lttvwindow_get_time_window(control_flow_data->tab);
2449
2450 LttTime time_begin = time_window.start_time;
2451 LttTime width = time_window.time_width;
2452 LttTime half_width;
2453 {
2454 guint64 time_ll = ltt_time_to_uint64(width);
2455 time_ll = time_ll >> 1; /* divide by two */
2456 half_width = ltt_time_from_uint64(time_ll);
2457 }
2458 LttTime time_end = ltt_time_add(time_begin, width);
2459
2460 LttvTracesetContext * tsc =
2461 lttvwindow_get_traceset_context(control_flow_data->tab);
2462
2463 LttTime trace_start = tsc->time_span.start_time;
2464 LttTime trace_end = tsc->time_span.end_time;
2465
2466 g_info("New current time HOOK : %lu, %lu", current_time.tv_sec,
2467 current_time.tv_nsec);
2468
2469
2470
2471 /* If current time is inside time interval, just move the highlight
2472 * bar */
2473
2474 /* Else, we have to change the time interval. We have to tell it
2475 * to the main window. */
2476 /* The time interval change will take care of placing the current
2477 * time at the center of the visible area, or nearest possible if we are
2478 * at one end of the trace. */
2479
2480
2481 if(ltt_time_compare(current_time, time_begin) < 0)
2482 {
2483 TimeWindow new_time_window;
2484
2485 if(ltt_time_compare(current_time,
2486 ltt_time_add(trace_start,half_width)) < 0)
2487 time_begin = trace_start;
2488 else
2489 time_begin = ltt_time_sub(current_time,half_width);
2490
2491 new_time_window.start_time = time_begin;
2492 new_time_window.time_width = width;
2493 new_time_window.time_width_double = ltt_time_to_double(width);
2494 new_time_window.end_time = ltt_time_add(time_begin, width);
2495
2496 lttvwindow_report_time_window(control_flow_data->tab, new_time_window);
2497 }
2498 else if(ltt_time_compare(current_time, time_end) > 0)
2499 {
2500 TimeWindow new_time_window;
2501
2502 if(ltt_time_compare(current_time, ltt_time_sub(trace_end, half_width)) > 0)
2503 time_begin = ltt_time_sub(trace_end,width);
2504 else
2505 time_begin = ltt_time_sub(current_time,half_width);
2506
2507 new_time_window.start_time = time_begin;
2508 new_time_window.time_width = width;
2509 new_time_window.time_width_double = ltt_time_to_double(width);
2510 new_time_window.end_time = ltt_time_add(time_begin, width);
2511
2512 lttvwindow_report_time_window(control_flow_data->tab, new_time_window);
2513
2514 }
2515 gtk_widget_queue_draw(control_flow_data->drawing->drawing_area);
2516
2517 /* Update directly when scrolling */
2518 gdk_window_process_updates(control_flow_data->drawing->drawing_area->window,
2519 TRUE);
2520
2521 return 0;
2522 }
2523
2524 typedef struct _ClosureData {
2525 EventsRequest *events_request;
2526 LttvTracesetState *tss;
2527 LttTime end_time;
2528 guint x_end;
2529 } ClosureData;
2530
2531
2532 void draw_closure(gpointer key, gpointer value, gpointer user_data)
2533 {
2534 ProcessInfo *process_info = (ProcessInfo*)key;
2535 HashedProcessData *hashed_process_data = (HashedProcessData*)value;
2536 ClosureData *closure_data = (ClosureData*)user_data;
2537
2538 EventsRequest *events_request = closure_data->events_request;
2539 ControlFlowData *control_flow_data = events_request->viewer_data;
2540
2541 LttvTracesetState *tss = closure_data->tss;
2542 LttvTracesetContext *tsc = (LttvTracesetContext*)tss;
2543
2544 LttTime evtime = closure_data->end_time;
2545
2546 gboolean dodraw = TRUE;
2547
2548 {
2549 /* For the process */
2550 /* First, check if the current process is in the state computation
2551 * process list. If it is there, that means we must add it right now and
2552 * draw items from the beginning of the read for it. If it is not
2553 * present, it's a new process and it was not present : it will
2554 * be added after the state update. */
2555 #ifdef EXTRA_CHECK
2556 g_assert(lttv_traceset_number(tsc->ts) > 0);
2557 #endif //EXTRA_CHECK
2558 LttvTraceContext *tc = tsc->traces[process_info->trace_num];
2559 LttvTraceState *ts = (LttvTraceState*)tc;
2560
2561 #if 0
2562 //FIXME : optimize data structures.
2563 LttvTracefileState *tfs;
2564 LttvTracefileContext *tfc;
2565 guint i;
2566 for(i=0;i<tc->tracefiles->len;i++) {
2567 tfc = g_array_index(tc->tracefiles, LttvTracefileContext*, i);
2568 if(ltt_tracefile_name(tfc->tf) == LTT_NAME_CPU
2569 && tfs->cpu == process_info->cpu)
2570 break;
2571
2572 }
2573 g_assert(i<tc->tracefiles->len);
2574 tfs = LTTV_TRACEFILE_STATE(tfc);
2575 #endif //0
2576 // LttvTracefileState *tfs =
2577 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2578 // tracefiles[process_info->cpu];
2579
2580 LttvProcessState *process;
2581 process = lttv_state_find_process(ts, process_info->cpu,
2582 process_info->pid);
2583
2584 if(unlikely(process != NULL)) {
2585
2586 LttvFilter *filter = control_flow_data->filter;
2587 if(filter != NULL && filter->head != NULL)
2588 if(!lttv_filter_tree_parse(filter->head,NULL,NULL,
2589 tc->t,NULL,process,tc))
2590 dodraw = FALSE;
2591
2592 /* Only draw for processes that are currently in the trace states */
2593
2594 ProcessList *process_list = control_flow_data->process_list;
2595 #ifdef EXTRA_CHECK
2596 /* Should be alike when background info is ready */
2597 if(control_flow_data->background_info_waiting==0)
2598 g_assert(ltt_time_compare(process->creation_time,
2599 process_info->birth) == 0);
2600 #endif //EXTRA_CHECK
2601
2602 /* Now, the process is in the state hash and our own process hash.
2603 * We definitely can draw the items related to the ending state.
2604 */
2605
2606 if(unlikely(ltt_time_compare(hashed_process_data->next_good_time,
2607 evtime) <= 0))
2608 {
2609 TimeWindow time_window =
2610 lttvwindow_get_time_window(control_flow_data->tab);
2611
2612 #ifdef EXTRA_CHECK
2613 if(ltt_time_compare(evtime, time_window.start_time) == -1
2614 || ltt_time_compare(evtime, time_window.end_time) == 1)
2615 return;
2616 #endif //EXTRA_CHECK
2617 Drawing_t *drawing = control_flow_data->drawing;
2618 guint width = drawing->width;
2619
2620 guint x = closure_data->x_end;
2621
2622 DrawContext draw_context;
2623
2624 /* Now create the drawing context that will be used to draw
2625 * items related to the last state. */
2626 draw_context.drawable = hashed_process_data->pixmap;
2627 draw_context.gc = drawing->gc;
2628 draw_context.pango_layout = drawing->pango_layout;
2629 draw_context.drawinfo.end.x = x;
2630
2631 draw_context.drawinfo.y.over = 1;
2632 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
2633 draw_context.drawinfo.y.under = hashed_process_data->height;
2634
2635 draw_context.drawinfo.start.offset.over = 0;
2636 draw_context.drawinfo.start.offset.middle = 0;
2637 draw_context.drawinfo.start.offset.under = 0;
2638 draw_context.drawinfo.end.offset.over = 0;
2639 draw_context.drawinfo.end.offset.middle = 0;
2640 draw_context.drawinfo.end.offset.under = 0;
2641 #if 0
2642 /* Jump over draw if we are at the same x position */
2643 if(x == hashed_process_data->x.over)
2644 {
2645 /* jump */
2646 } else {
2647 draw_context.drawinfo.start.x = hashed_process_data->x.over;
2648 /* Draw the line */
2649 PropertiesLine prop_line = prepare_execmode_line(process);
2650 draw_line((void*)&prop_line, (void*)&draw_context);
2651
2652 hashed_process_data->x.over = x;
2653 }
2654 #endif //0
2655
2656 if(unlikely(x == hashed_process_data->x.middle &&
2657 hashed_process_data->x.middle_used)) {
2658 #if 0 /* do not mark closure : not missing information */
2659 if(hashed_process_data->x.middle_marked == FALSE) {
2660 /* Draw collision indicator */
2661 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
2662 gdk_draw_point(drawing->pixmap,
2663 drawing->gc,
2664 x,
2665 y+(height/2)-3);
2666 hashed_process_data->x.middle_marked = TRUE;
2667 }
2668 #endif //0
2669 /* Jump */
2670 } else {
2671 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
2672 /* Draw the line */
2673 if(dodraw) {
2674 PropertiesLine prop_line = prepare_s_e_line(process);
2675 draw_line((void*)&prop_line, (void*)&draw_context);
2676 }
2677
2678 /* become the last x position */
2679 if(likely(x != hashed_process_data->x.middle)) {
2680 hashed_process_data->x.middle = x;
2681 /* but don't use the pixel */
2682 hashed_process_data->x.middle_used = FALSE;
2683
2684 /* Calculate the next good time */
2685 convert_pixels_to_time(width, x+1, time_window,
2686 &hashed_process_data->next_good_time);
2687 }
2688 }
2689 }
2690 }
2691 }
2692 return;
2693 }
2694
2695 int before_chunk(void *hook_data, void *call_data)
2696 {
2697 EventsRequest *events_request = (EventsRequest*)hook_data;
2698 LttvTracesetState *tss = (LttvTracesetState*)call_data;
2699 ControlFlowData *cfd = (ControlFlowData*)events_request->viewer_data;
2700 #if 0
2701 /* Desactivate sort */
2702 gtk_tree_sortable_set_sort_column_id(
2703 GTK_TREE_SORTABLE(cfd->process_list->list_store),
2704 TRACE_COLUMN,
2705 GTK_SORT_ASCENDING);
2706 #endif //0
2707 drawing_chunk_begin(events_request, tss);
2708
2709 return 0;
2710 }
2711
2712 int before_request(void *hook_data, void *call_data)
2713 {
2714 EventsRequest *events_request = (EventsRequest*)hook_data;
2715 LttvTracesetState *tss = (LttvTracesetState*)call_data;
2716
2717 drawing_data_request_begin(events_request, tss);
2718
2719 return 0;
2720 }
2721
2722
2723 /*
2724 * after request is necessary in addition of after chunk in order to draw
2725 * lines until the end of the screen. after chunk just draws lines until
2726 * the last event.
2727 *
2728 * for each process
2729 * draw closing line
2730 * expose
2731 */
2732 int after_request(void *hook_data, void *call_data)
2733 {
2734 EventsRequest *events_request = (EventsRequest*)hook_data;
2735 ControlFlowData *control_flow_data = events_request->viewer_data;
2736 LttvTracesetState *tss = (LttvTracesetState*)call_data;
2737
2738 ProcessList *process_list = control_flow_data->process_list;
2739 LttTime end_time = events_request->end_time;
2740
2741 ClosureData closure_data;
2742 closure_data.events_request = (EventsRequest*)hook_data;
2743 closure_data.tss = tss;
2744 closure_data.end_time = end_time;
2745
2746 TimeWindow time_window =
2747 lttvwindow_get_time_window(control_flow_data->tab);
2748 guint width = control_flow_data->drawing->width;
2749 convert_time_to_pixels(
2750 time_window,
2751 end_time,
2752 width,
2753 &closure_data.x_end);
2754
2755
2756 /* Draw last items */
2757 g_hash_table_foreach(process_list->process_hash, draw_closure,
2758 (void*)&closure_data);
2759
2760
2761 /* Request expose */
2762 drawing_request_expose(events_request, tss, end_time);
2763 return 0;
2764 }
2765
2766 /*
2767 * for each process
2768 * draw closing line
2769 * expose
2770 */
2771 int after_chunk(void *hook_data, void *call_data)
2772 {
2773 EventsRequest *events_request = (EventsRequest*)hook_data;
2774 ControlFlowData *control_flow_data = events_request->viewer_data;
2775 LttvTracesetState *tss = (LttvTracesetState*)call_data;
2776 LttvTracesetContext *tsc = (LttvTracesetContext*)call_data;
2777 LttvTracefileContext *tfc = lttv_traceset_context_get_current_tfc(tsc);
2778 LttTime end_time;
2779
2780 ProcessList *process_list = control_flow_data->process_list;
2781 guint i;
2782 LttvTraceset *traceset = tsc->ts;
2783 guint nb_trace = lttv_traceset_number(traceset);
2784
2785 /* Only execute when called for the first trace's events request */
2786 if(!process_list->current_hash_data)
2787 return 0;
2788
2789 for(i = 0 ; i < nb_trace ; i++) {
2790 g_free(process_list->current_hash_data[i]);
2791 }
2792 g_free(process_list->current_hash_data);
2793 process_list->current_hash_data = NULL;
2794
2795 if(tfc != NULL)
2796 end_time = LTT_TIME_MIN(tfc->timestamp, events_request->end_time);
2797 else /* end of traceset, or position now out of request : end */
2798 end_time = events_request->end_time;
2799
2800 ClosureData closure_data;
2801 closure_data.events_request = (EventsRequest*)hook_data;
2802 closure_data.tss = tss;
2803 closure_data.end_time = end_time;
2804
2805 TimeWindow time_window =
2806 lttvwindow_get_time_window(control_flow_data->tab);
2807 guint width = control_flow_data->drawing->width;
2808 convert_time_to_pixels(
2809 time_window,
2810 end_time,
2811 width,
2812 &closure_data.x_end);
2813
2814 /* Draw last items */
2815 g_hash_table_foreach(process_list->process_hash, draw_closure,
2816 (void*)&closure_data);
2817 #if 0
2818 /* Reactivate sort */
2819 gtk_tree_sortable_set_sort_column_id(
2820 GTK_TREE_SORTABLE(control_flow_data->process_list->list_store),
2821 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
2822 GTK_SORT_ASCENDING);
2823
2824 update_index_to_pixmap(control_flow_data->process_list);
2825 /* Request a full expose : drawing scrambled */
2826 gtk_widget_queue_draw(control_flow_data->drawing->drawing_area);
2827 #endif //0
2828 /* Request expose (updates damages zone also) */
2829 drawing_request_expose(events_request, tss, end_time);
2830
2831 return 0;
2832 }
2833
2834 /* after_statedump_end
2835 *
2836 * @param hook_data ControlFlowData structure of the viewer.
2837 * @param call_data Event context.
2838 *
2839 * This function adds items to be drawn in a queue for each process.
2840 *
2841 */
2842 int before_statedump_end(void *hook_data, void *call_data)
2843 {
2844 LttvTraceHook *th = (LttvTraceHook*)hook_data;
2845 EventsRequest *events_request = (EventsRequest*)th->hook_data;
2846 ControlFlowData *control_flow_data = events_request->viewer_data;
2847
2848 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
2849
2850 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
2851
2852 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
2853
2854 LttvTracesetState *tss = (LttvTracesetState*)tfc->t_context->ts_context;
2855 ProcessList *process_list = control_flow_data->process_list;
2856
2857 LttEvent *e;
2858 e = ltt_tracefile_get_event(tfc->tf);
2859
2860 LttvFilter *filter = control_flow_data->filter;
2861 if(filter != NULL && filter->head != NULL)
2862 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
2863 tfc->t_context->t,tfc,NULL,NULL))
2864 return FALSE;
2865
2866 LttTime evtime = ltt_event_time(e);
2867
2868 ClosureData closure_data;
2869 closure_data.events_request = events_request;
2870 closure_data.tss = tss;
2871 closure_data.end_time = evtime;
2872
2873 TimeWindow time_window =
2874 lttvwindow_get_time_window(control_flow_data->tab);
2875 guint width = control_flow_data->drawing->width;
2876 convert_time_to_pixels(
2877 time_window,
2878 evtime,
2879 width,
2880 &closure_data.x_end);
2881
2882 /* Draw last items */
2883 g_hash_table_foreach(process_list->process_hash, draw_closure,
2884 (void*)&closure_data);
2885 #if 0
2886 /* Reactivate sort */
2887 gtk_tree_sortable_set_sort_column_id(
2888 GTK_TREE_SORTABLE(control_flow_data->process_list->list_store),
2889 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
2890 GTK_SORT_ASCENDING);
2891
2892 update_index_to_pixmap(control_flow_data->process_list);
2893 /* Request a full expose : drawing scrambled */
2894 gtk_widget_queue_draw(control_flow_data->drawing->drawing_area);
2895 #endif //0
2896 /* Request expose (updates damages zone also) */
2897 drawing_request_expose(events_request, tss, evtime);
2898
2899 return 0;
2900 }
This page took 0.117564 seconds and 5 git commands to generate.