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