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