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