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