Fix tar.gz build by removing legacy include to ltt directory
[lttv.git] / lttv / modules / gui / controlflow / eventhooks.c
1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2003-2004 Mathieu Desnoyers
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16 * MA 02111-1307, USA.
17 */
18
19
20 /*****************************************************************************
21 * Hooks to be called by the main window *
22 *****************************************************************************/
23
24
25 /* Event hooks are the drawing hooks called during traceset read. They draw the
26 * icons, text, lines and background color corresponding to the events read.
27 *
28 * Two hooks are used for drawing : before_schedchange and after_schedchange hooks. The
29 * before_schedchange is called before the state update that occurs with an event and
30 * the after_schedchange hook is called after this state update.
31 *
32 * The before_schedchange hooks fulfill the task of drawing the visible objects that
33 * corresponds to the data accumulated by the after_schedchange hook.
34 *
35 * The after_schedchange hook accumulates the data that need to be shown on the screen
36 * (items) into a queue. Then, the next before_schedchange hook will draw what that
37 * queue contains. That's the Right Way (TM) of drawing items on the screen,
38 * because we need to draw the background first (and then add icons, text, ...
39 * over it), but we only know the length of a background region once the state
40 * corresponding to it is over, which happens to be at the next before_schedchange
41 * hook.
42 *
43 * We also have a hook called at the end of a chunk to draw the information left
44 * undrawn in each process queue. We use the current time as end of
45 * line/background.
46 */
47
48 #ifdef HAVE_CONFIG_H
49 #include <config.h>
50 #endif
51
52 //#define PANGO_ENABLE_BACKEND
53 #include <gtk/gtk.h>
54 #include <gdk/gdk.h>
55 #include <glib.h>
56 #include <assert.h>
57 #include <string.h>
58 #include <stdio.h>
59
60 //#include <pango/pango.h>
61
62 #include <lttv/lttv.h>
63 #include <lttv/hook.h>
64 #include <lttv/state.h>
65 #include <lttvwindow/lttvwindow.h>
66 #include <lttvwindow/lttvwindowtraces.h>
67 #include <lttvwindow/support.h>
68
69
70 #include "eventhooks.h"
71 #include "cfv.h"
72 #include "processlist.h"
73 #include "drawing.h"
74
75
76 #define MAX_PATH_LEN 256
77 #define STATE_LINE_WIDTH 8
78 #define COLLISION_POSITION(height) (((height - STATE_LINE_WIDTH)/2) -3)
79
80 extern GSList *g_legend_list;
81
82
83 /* Action to do when background computation completed.
84 *
85 * Wait for all the awaited computations to be over.
86 */
87
88 static gint background_ready(void *hook_data, void *call_data)
89 {
90 ControlFlowData *control_flow_data = (ControlFlowData *)hook_data;
91
92 control_flow_data->background_info_waiting--;
93
94 if(control_flow_data->background_info_waiting == 0) {
95 g_message("control flow viewer : background computation data ready.");
96
97 drawing_clear(control_flow_data->drawing);
98 processlist_clear(control_flow_data->process_list);
99 gtk_widget_set_size_request(
100 control_flow_data->drawing->drawing_area,
101 -1, processlist_get_height(control_flow_data->process_list));
102 redraw_notify(control_flow_data, NULL);
103 }
104
105 return 0;
106 }
107
108
109 /* Request background computation. Verify if it is in progress or ready first.
110 * Only for each trace in the tab's traceset.
111 */
112
113 static void request_background_data(ControlFlowData *control_flow_data)
114 {
115
116 LttvTraceset *ts = lttvwindow_get_traceset(control_flow_data->tab);
117 gint num_traces = lttv_traceset_number(ts);
118 gint i;
119 LttvTrace *trace;
120 LttvTraceState *tstate;
121
122 LttvHooks *background_ready_hook = lttv_hooks_new();
123 lttv_hooks_add(background_ready_hook, background_ready, control_flow_data,
124 LTTV_PRIO_DEFAULT);
125 control_flow_data->background_info_waiting = 0;
126
127 for(i=0;i<num_traces;i++) {
128 trace = lttv_traceset_get(ts, i);
129
130 if(lttvwindowtraces_get_ready(g_quark_from_string("state"),trace)==FALSE
131 && !ts->has_precomputed_states) {
132
133 if(lttvwindowtraces_get_in_progress(g_quark_from_string("state"),
134 trace) == FALSE) {
135 /* We first remove requests that could have been done for the same
136 * information. Happens when two viewers ask for it before servicing
137 * starts.
138 */
139 if(!lttvwindowtraces_background_request_find(trace, "state"))
140 lttvwindowtraces_background_request_queue(
141 main_window_get_widget(control_flow_data->tab), trace, "state");
142 lttvwindowtraces_background_notify_queue(control_flow_data,
143 trace,
144 ltt_time_infinite,
145 NULL,
146 background_ready_hook);
147 control_flow_data->background_info_waiting++;
148 } else { /* in progress */
149
150 lttvwindowtraces_background_notify_current(control_flow_data,
151 trace,
152 ltt_time_infinite,
153 NULL,
154 background_ready_hook);
155 control_flow_data->background_info_waiting++;
156 }
157 } else {
158 /* Data ready. By its nature, this viewer doesn't need to have
159 * its data ready hook called there, because a background
160 * request is always linked with a redraw.
161 */
162 }
163
164 }
165
166 lttv_hooks_destroy(background_ready_hook);
167 }
168
169
170
171
172 /**
173 * Event Viewer's constructor hook
174 *
175 * This constructor is given as a parameter to the menuitem and toolbar button
176 * registration. It creates the list.
177 * @param tab A pointer to the parent tab.
178 * @return The widget created.
179 */
180 GtkWidget *
181 h_guicontrolflow(LttvPlugin *plugin)
182 {
183 LttvPluginTab *ptab = LTTV_PLUGIN_TAB(plugin);
184 Tab *tab = ptab->tab;
185 g_info("h_guicontrolflow, %p", tab);
186 ControlFlowData *control_flow_data = guicontrolflow(ptab);
187
188 control_flow_data->tab = tab;
189
190 // Unreg done in the GuiControlFlow_Destructor
191 lttvwindow_register_traceset_notify(tab,
192 traceset_notify,
193 control_flow_data);
194
195 lttvwindow_register_time_window_notify(tab,
196 update_time_window_hook,
197 control_flow_data);
198 lttvwindow_register_current_time_notify(tab,
199 update_current_time_hook,
200 control_flow_data);
201 lttvwindow_register_redraw_notify(tab,
202 redraw_notify,
203 control_flow_data);
204 lttvwindow_register_continue_notify(tab,
205 continue_notify,
206 control_flow_data);
207 request_background_data(control_flow_data);
208
209
210 return guicontrolflow_get_widget(control_flow_data) ;
211
212 }
213
214 int event_selected_hook(void *hook_data, void *call_data)
215 {
216 guint *event_number = (guint*) call_data;
217
218 g_debug("DEBUG : event selected by main window : %u", *event_number);
219
220 return 0;
221 }
222
223 /* Function that selects the color of status&exemode line */
224 static inline PropertiesLine prepare_s_e_line(LttvProcessState *process)
225 {
226 PropertiesLine prop_line;
227 prop_line.line_width = STATE_LINE_WIDTH;
228 prop_line.style = GDK_LINE_SOLID;
229 prop_line.y = MIDDLE;
230 //GdkColormap *colormap = gdk_colormap_get_system();
231
232 if(process->state->s == LTTV_STATE_RUN) {
233 if(process->state->t == LTTV_STATE_USER_MODE)
234 prop_line.color = drawing_colors[COL_RUN_USER_MODE];
235 else if(process->state->t == LTTV_STATE_SYSCALL)
236 prop_line.color = drawing_colors[COL_RUN_SYSCALL];
237 else if(process->state->t == LTTV_STATE_TRAP)
238 prop_line.color = drawing_colors[COL_RUN_TRAP];
239 else if(process->state->t == LTTV_STATE_IRQ)
240 prop_line.color = drawing_colors[COL_RUN_IRQ];
241 else if(process->state->t == LTTV_STATE_SOFT_IRQ)
242 prop_line.color = drawing_colors[COL_RUN_SOFT_IRQ];
243 else if(process->state->t == LTTV_STATE_MAYBE_SYSCALL)
244 prop_line.color = drawing_colors[COL_MODE_UNKNOWN];
245 else if(process->state->t == LTTV_STATE_MAYBE_USER_MODE)
246 prop_line.color = drawing_colors[COL_MODE_UNKNOWN];
247 else if(process->state->t == LTTV_STATE_MAYBE_TRAP)
248 prop_line.color = drawing_colors[COL_MODE_UNKNOWN];
249 else if(process->state->t == LTTV_STATE_MODE_UNKNOWN)
250 prop_line.color = drawing_colors[COL_MODE_UNKNOWN];
251 else
252 g_assert(FALSE); /* RUNNING MODE UNKNOWN */
253 } else if(process->state->s == LTTV_STATE_WAIT) {
254 /* We don't show if we wait while in user mode, trap, irq or syscall */
255 prop_line.color = drawing_colors[COL_WAIT];
256 } else if(process->state->s == LTTV_STATE_WAIT_CPU) {
257 /* We don't show if we wait for CPU while in user mode, trap, irq
258 * or syscall */
259 prop_line.color = drawing_colors[COL_WAIT_CPU];
260 } else if(process->state->s == LTTV_STATE_ZOMBIE) {
261 prop_line.color = drawing_colors[COL_ZOMBIE];
262 } else if(process->state->s == LTTV_STATE_WAIT_FORK) {
263 prop_line.color = drawing_colors[COL_WAIT_FORK];
264 } else if(process->state->s == LTTV_STATE_EXIT) {
265 prop_line.color = drawing_colors[COL_EXIT];
266 } else if(process->state->s == LTTV_STATE_UNNAMED) {
267 prop_line.color = drawing_colors[COL_UNNAMED];
268 } else if(process->state->s == LTTV_STATE_DEAD) {
269 prop_line.color = drawing_colors[COL_DEAD];
270 } else {
271 g_critical("unknown state : %s", g_quark_to_string(process->state->s));
272 g_assert(FALSE); /* UNKNOWN STATE */
273 }
274
275 return prop_line;
276
277 }
278
279 HashedProcessData *get_hashed_process_data(ControlFlowData *control_flow_data,
280 LttvProcessState *process,
281 guint pid,
282 guint trace_num)
283 {
284 HashedProcessData *hashed_process_data = NULL;
285 ProcessList *process_list = control_flow_data->process_list;
286 LttTime birth = process->creation_time;
287 guint pl_height = 0;
288
289 hashed_process_data = processlist_get_process_data(process_list,
290 pid,
291 process->cpu,
292 &birth,
293 trace_num);
294 if(hashed_process_data == NULL)
295 {
296 g_assert(pid == 0 || pid != process->ppid);
297 ProcessInfo *process_info;
298 Drawing_t *drawing = control_flow_data->drawing;
299 /* Process not present */
300 processlist_add(process_list,
301 drawing,
302 pid,
303 process->tgid,
304 process->cpu,
305 process->ppid,
306 &birth,
307 trace_num,
308 process->name,
309 process->brand,
310 &pl_height,
311 &process_info,
312 &hashed_process_data);
313 gtk_widget_set_size_request(drawing->drawing_area,
314 -1,
315 pl_height);
316 gtk_widget_queue_draw(drawing->drawing_area);
317 }
318 return hashed_process_data;
319 }
320
321 void init_drawing_context(DrawContext *draw_context,
322 HashedProcessData *hashed_process_data,
323 Drawing_t *drawing,
324 guint x
325 )
326 {
327 draw_context->drawable = hashed_process_data->pixmap;
328 draw_context->gc = drawing->gc;
329 draw_context->pango_layout = drawing->pango_layout;
330 draw_context->drawinfo.start.x = hashed_process_data->x.middle;
331 draw_context->drawinfo.end.x = x;
332
333 draw_context->drawinfo.y.over = 1;
334 draw_context->drawinfo.y.middle = (hashed_process_data->height/2);
335 draw_context->drawinfo.y.under = hashed_process_data->height;
336
337 draw_context->drawinfo.start.offset.over = 0;
338 draw_context->drawinfo.start.offset.middle = 0;
339 draw_context->drawinfo.start.offset.under = 0;
340 draw_context->drawinfo.end.offset.over = 0;
341 draw_context->drawinfo.end.offset.middle = 0;
342 draw_context->drawinfo.end.offset.under = 0;
343
344 }
345
346 void draw_state_line(HashedProcessData *hashed_process_data,
347 LttvProcessState *process,
348 Drawing_t *drawing,
349 guint x,
350 TimeWindow time_window)
351 {
352 DrawContext draw_context;
353 guint width = drawing->width;
354
355 init_drawing_context(&draw_context,
356 hashed_process_data,
357 drawing,
358 x);
359
360
361 /* Draw the line */
362 PropertiesLine prop_line = prepare_s_e_line(process);
363 draw_line((void*)&prop_line, (void*)&draw_context);
364
365 /* become the last x position */
366 hashed_process_data->x.middle = x;
367 hashed_process_data->x.middle_used = TRUE;
368 hashed_process_data->x.middle_marked = FALSE;
369
370 /* Calculate the next good time */
371 convert_pixels_to_time(width, x+1, time_window,
372 &hashed_process_data->next_good_time);
373 }
374
375
376 void draw_state_items(ControlFlowData *control_flow_data,
377 HashedProcessData *hashed_process_data,
378 LttvProcessState *process,
379 LttTime evtime )
380 {
381
382
383 if(likely(ltt_time_compare(hashed_process_data->next_good_time,
384 evtime) > 0))
385 {
386 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
387 TimeWindow time_window =
388 lttvwindow_get_time_window(control_flow_data->tab);
389
390 #ifdef EXTRA_CHECK
391 if(ltt_time_compare(evtime, time_window.start_time) == -1
392 || ltt_time_compare(evtime, time_window.end_time) == 1)
393 return FALSE;
394 #endif //EXTRA_CHECK
395 Drawing_t *drawing = control_flow_data->drawing;
396 guint width = drawing->width;
397 guint x;
398 convert_time_to_pixels(
399 time_window,
400 evtime,
401 width,
402 &x);
403
404 /* Draw collision indicator */
405 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
406 gdk_draw_point(hashed_process_data->pixmap,
407 drawing->gc,
408 x,
409 COLLISION_POSITION(hashed_process_data->height));
410 hashed_process_data->x.middle_marked = TRUE;
411 }
412 } else {
413 TimeWindow time_window =
414 lttvwindow_get_time_window(control_flow_data->tab);
415
416 #ifdef EXTRA_CHECK
417 if(ltt_time_compare(evtime, time_window.start_time) == -1
418 || ltt_time_compare(evtime, time_window.end_time) == 1)
419 return FALSE;
420 #endif //EXTRA_CHECK
421 Drawing_t *drawing = control_flow_data->drawing;
422 guint width = drawing->width;
423 guint x;
424
425 convert_time_to_pixels(
426 time_window,
427 evtime,
428 width,
429 &x);
430
431
432 /* Jump over draw if we are at the same x position */
433 if(unlikely(x == hashed_process_data->x.middle &&
434 hashed_process_data->x.middle_used))
435 {
436 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
437 /* Draw collision indicator */
438 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
439 gdk_draw_point(hashed_process_data->pixmap,
440 drawing->gc,
441 x,
442 COLLISION_POSITION(hashed_process_data->height));
443 hashed_process_data->x.middle_marked = TRUE;
444 }
445 /* jump */
446 } else {
447
448 draw_state_line(hashed_process_data,
449 process,
450 drawing,
451 x,
452 time_window);
453 }
454 }
455 }
456
457
458 /* Before try-wake-up hook. A process is being woken; we need to draw its line up to this point in time
459 in that colour. This is basically like exec-state, but the change applies to a process other than that
460 which is currently running. */
461
462 int before_trywakeup_hook(void *hook_data, void *call_data)
463 {
464
465 LttvEvent *event;
466
467 event = (LttvEvent *) call_data;
468 if (strcmp(lttv_traceset_get_name_from_event(event),"sched_wakeup") != 0)
469 return FALSE;
470
471 ControlFlowData *control_flow_data = (ControlFlowData*)hook_data;
472
473 LttvTraceState *ts = event->state;;
474
475
476 LttTime evtime = lttv_event_get_timestamp(event);
477 #ifdef BABEL_CLEANUP
478 LttvFilter *filter = control_flow_data->filter;
479 #endif
480
481 guint woken_pid;
482 gint woken_cpu;
483
484 woken_pid = lttv_event_get_long(event, "tid");
485 woken_cpu = lttv_event_get_long(event, "target_cpu");
486
487 #ifdef BABEL_CLEANUP
488 if(!filter || !filter->head ||
489 lttv_filter_tree_parse(filter->head,e,tfc->tf,
490 tfc->t_context->t,tfc,NULL,NULL)) {
491 #else
492 {
493 #endif
494 /* First, check if the woken process is in the state computation
495 * process list. If it is there, that means we must add it right now and
496 * draw items from the beginning of the read for it. If it is not
497 * present, it's a new process and it was not present : it will
498 * be added after the state update. TOCHECK: What does that last para mean? */
499 guint trace_num = lttv_traceset_get_trace_index_from_event(event);
500 LttvProcessState *process = lttv_state_find_process(ts, woken_cpu, woken_pid);
501
502 if(process != NULL) {
503 /* Well, the woken process existed : we must get it in the process hash
504 * or add it, and draw its items.
505 */
506 /* Add process to process list (if not present) */
507
508 HashedProcessData *hashed_process_data = get_hashed_process_data(control_flow_data, process, woken_pid, trace_num);
509
510 /* Now, the process is in the state hash and our own process hash.
511 * We definitely can draw the items related to the ending state.
512 */
513
514 draw_state_items(control_flow_data,
515 hashed_process_data,
516 process,
517 evtime );
518
519 }
520 }
521
522
523
524
525 return 0;
526
527 }
528
529 /* before_schedchange_hook
530 *
531 * This function basically draw lines and icons. Two types of lines are drawn :
532 * one small (3 pixels?) representing the state of the process and the second
533 * type is thicker (10 pixels?) representing on which CPU a process is running
534 * (and this only in running state).
535 *
536 * Extremums of the lines :
537 * x_min : time of the last event context for this process kept in memory.
538 * x_max : time of the current event.
539 * y : middle of the process in the process list. The process is found in the
540 * list, therefore is it's position in pixels.
541 *
542 * The choice of lines'color is defined by the context of the last event for this
543 * process.
544 */
545
546
547 int before_schedchange_hook(void *hook_data, void *call_data)
548 {
549 LttvEvent *event;
550 guint cpu;
551 LttvTraceState *ts;
552 LttvProcessState *process;
553
554 //LttvProcessState *old_process = ts->running_process[cpu];
555
556 guint pid_in, pid_out;
557 gint64 state_out;
558 LttTime evtime;
559 event = (LttvEvent *) call_data;
560 if (strcmp(lttv_traceset_get_name_from_event(event),"sched_switch") != 0)
561 return FALSE;
562
563 ControlFlowData *control_flow_data = (ControlFlowData*)hook_data;
564
565
566 /* we are in a schedchange, before the state update. We must draw the
567 * items corresponding to the state before it changes : now is the right
568 * time to do it.
569 */
570 cpu = lttv_traceset_get_cpuid_from_event(event);
571 ts = event->state;
572
573 pid_out = lttv_event_get_long(event, "prev_tid");
574 pid_in = lttv_event_get_long(event, "next_tid");
575 state_out = lttv_event_get_long(event, "prev_state");
576 guint trace_number = lttv_traceset_get_trace_index_from_event(event);
577
578 process = lttv_state_find_process(ts,cpu,pid_out);
579 evtime = lttv_event_get_timestamp(event);
580 /* For the pid_out */
581 /* First, check if the current process is in the state computation
582 * process list. If it is there, that means we must add it right now and
583 * draw items from the beginning of the read for it. If it is not
584 * present, it's a new process and it was not present : it will
585 * be added after the state update. */
586
587 /* unknown state, bad current pid */
588
589 if(process != NULL) {
590 /* Well, the process_out existed : we must get it in the process hash
591 * or add it, and draw its items.
592 */
593 /* Add process to process list (if not present) */
594
595 HashedProcessData *hashed_process_data = get_hashed_process_data(control_flow_data, process, pid_out, trace_number);
596
597 /* Now, the process is in the state hash and our own process hash.
598 * We definitely can draw the items related to the ending state.
599 */
600
601 draw_state_items(control_flow_data,
602 hashed_process_data,
603 process,
604 evtime );
605 }
606
607 /* For the pid_in */
608 /* First, check if the current process is in the state computation
609 * process list. If it is there, that means we must add it right now and
610 * draw items from the beginning of the read for it. If it is not
611 * present, it's a new process and it was not present : it will
612 * be added after the state update. */
613 process = lttv_state_find_process(ts,cpu,pid_in);
614
615 if(process != NULL) {
616 /* Well, the process existed : we must get it in the process hash
617 * or add it, and draw its items.
618 */
619 /* Add process to process list (if not present) */
620
621 HashedProcessData *hashed_process_data = get_hashed_process_data(control_flow_data, process, pid_in, trace_number);
622
623 //We could set the current process and hash here, but will be done
624 //by after schedchange hook
625
626 /* Now, the process is in the state hash and our own process hash.
627 * We definitely can draw the items related to the ending state.
628 */
629 draw_state_items(control_flow_data,
630 hashed_process_data,
631 process,
632 evtime );
633
634 } else
635 g_warning("Cannot find pid_in in schedchange %u at %u.%u", pid_in, evtime.tv_sec, evtime.tv_nsec);
636 #ifdef BABEL_CLEANUP
637 tfc->target_pid = target_pid_saved;
638 #endif //babel_cleanup
639 return 0;
640
641
642
643
644 /* Text dump */
645 #ifdef DONTSHOW
646 GString *string = g_string_new("");;
647 gboolean field_names = TRUE, state = TRUE;
648
649 lttv_event_to_string(e, tfc->tf, string, TRUE, field_names, tfs);
650 g_string_append_printf(string,"\n");
651
652 if(state) {
653 g_string_append_printf(string, " %s",
654 g_quark_to_string(tfs->process->state->s));
655 }
656
657 g_info("%s",string->str);
658
659 g_string_free(string, TRUE);
660
661 /* End of text dump */
662 #endif //DONTSHOW
663
664 }
665
666 /* after_schedchange_hook
667 *
668 * The draw after hook is called by the reading API to have a
669 * particular event drawn on the screen.
670 * @param hook_data ControlFlowData structure of the viewer.
671 * @param call_data Event context.
672 *
673 * This function adds items to be drawn in a queue for each process.
674 *
675 */
676 int after_schedchange_hook(void *hook_data, void *call_data)
677 {
678 LttvEvent *event;
679
680 event = (LttvEvent *) call_data;
681
682 if (strcmp(lttv_traceset_get_name_from_event(event),"sched_switch") != 0)
683 return FALSE;
684
685 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
686
687
688 LttvTraceState *ts = event->state;
689
690 #ifdef BABEL_CLEANUP
691 LttvFilter *filter = control_flow_data->filter;
692 #endif
693 LttTime evtime = lttv_event_get_timestamp(event);
694
695 /* Add process to process list (if not present) */
696 LttvProcessState *process_in;
697 HashedProcessData *hashed_process_data_in = NULL;
698
699 ProcessList *process_list = control_flow_data->process_list;
700
701 guint pid_in;
702 {
703 pid_in = lttv_event_get_long(event, "next_tid");
704 }
705
706 #ifdef BABEL_CLEANUP
707 if(!filter || !filter->head ||
708 lttv_filter_tree_parse(filter->head,e,tfc->tf,
709 tfc->t_context->t,tfc,NULL,NULL)) {
710 #else
711 {
712 #endif
713 /* Find process pid_in in the list... */
714 //process_in = lttv_state_find_process(ts, ANY_CPU, pid_in);
715 //process_in = tfs->process;
716 guint cpu = lttv_traceset_get_cpuid_from_event(event);
717 guint trace_num = lttv_traceset_get_trace_index_from_event(event);
718 process_in = ts->running_process[cpu];
719 /* It should exist, because we are after the state update. */
720 #ifdef EXTRA_CHECK
721 g_assert(process_in != NULL);
722 #endif //EXTRA_CHECK
723 hashed_process_data_in = get_hashed_process_data(control_flow_data, process_in, pid_in, trace_num);
724
725 /* Set the current process */
726 process_list->current_hash_data[trace_num][process_in->cpu] =
727 hashed_process_data_in;
728
729 if(ltt_time_compare(hashed_process_data_in->next_good_time,
730 evtime) <= 0)
731 {
732 TimeWindow time_window =
733 lttvwindow_get_time_window(control_flow_data->tab);
734
735 #ifdef EXTRA_CHECK
736 if(ltt_time_compare(evtime, time_window.start_time) == -1
737 || ltt_time_compare(evtime, time_window.end_time) == 1)
738 return FALSE;
739 #endif //EXTRA_CHECK
740 Drawing_t *drawing = control_flow_data->drawing;
741 guint width = drawing->width;
742 guint new_x;
743
744 convert_time_to_pixels(
745 time_window,
746 evtime,
747 width,
748 &new_x);
749
750 if(hashed_process_data_in->x.middle != new_x) {
751 hashed_process_data_in->x.middle = new_x;
752 hashed_process_data_in->x.middle_used = FALSE;
753 hashed_process_data_in->x.middle_marked = FALSE;
754 }
755 }
756 }
757
758 return 0;
759 }
760
761
762
763
764 /* before_execmode_hook
765 *
766 * This function basically draw lines and icons. Two types of lines are drawn :
767 * one small (3 pixels?) representing the state of the process and the second
768 * type is thicker (10 pixels?) representing on which CPU a process is running
769 * (and this only in running state).
770 *
771 * Extremums of the lines :
772 * x_min : time of the last event context for this process kept in memory.
773 * x_max : time of the current event.
774 * y : middle of the process in the process list. The process is found in the
775 * list, therefore is it's position in pixels.
776 *
777 * The choice of lines'color is defined by the context of the last event for this
778 * process.
779 */
780
781
782 int before_execmode_hook(void *hook_data, void *call_data)
783 {
784 LttvEvent *event;
785 guint cpu;
786 guint pid = 0;
787 LttvTraceState *ts;
788 LttvProcessState *process;
789
790 /* we are in a execmode, before the state update. We must draw the
791 * items corresponding to the state before it changes : now is the right
792 * time to do it.
793 */
794
795 event = (LttvEvent *) call_data;
796 if ((strncmp(lttv_traceset_get_name_from_event(event),"sys_", sizeof("sys_") - 1) == 0)
797 ||(strcmp(lttv_traceset_get_name_from_event(event),"exit_syscall") == 0)
798 ||(strncmp(lttv_traceset_get_name_from_event(event),"irq_handler_",sizeof("irq_handler_") -1) == 0)
799 ||(strncmp(lttv_traceset_get_name_from_event(event),"softirq_", sizeof("softirq_") - 1) == 0)) {
800
801 LttTime evtime = lttv_event_get_timestamp(event);
802 ControlFlowData *control_flow_data = (ControlFlowData*)hook_data;
803 /* For the pid */
804 LttvTraceset *traceSet = lttvwindow_get_traceset(control_flow_data->tab);
805
806 cpu = lttv_traceset_get_cpuid_from_event(event);
807 ts = event->state;
808
809 guint trace_number = lttv_traceset_get_trace_index_from_event(event);
810
811 //TODO ybrosseau 2013-04-09 validate that using the running process is the right choice
812 //process = lttv_state_find_process(ts ,cpu ,pid);
813 process = ts->running_process[cpu];
814
815 g_assert(process != NULL);
816
817 guint pid = process->pid;
818
819 /* Well, the process_out existed : we must get it in the process hash
820 * or add it, and draw its items.
821 */
822 /* Add process to process list (if not present) */
823 HashedProcessData *hashed_process_data = NULL;
824 ProcessList *process_list = control_flow_data->process_list;
825 if(process_list->current_hash_data == NULL){//TODO fdeslauriers 2012-07-17 : should not be necessary
826 return 0;
827 }
828
829 if(likely(process_list->current_hash_data[trace_number][cpu] != NULL)) {
830 hashed_process_data = process_list->current_hash_data[trace_number][cpu];
831 } else {
832 hashed_process_data = get_hashed_process_data(control_flow_data,
833 process, pid, trace_number);
834
835 /* Set the current process */
836 process_list->current_hash_data[trace_number][process->cpu] =
837 hashed_process_data;
838 }
839
840 /* Now, the process is in the state hash and our own process hash.
841 * We definitely can draw the items related to the ending state.
842 */
843
844 draw_state_items(control_flow_data,
845 hashed_process_data,
846 process,
847 evtime );
848 }
849
850 return 0;
851
852 }
853
854 /* before_process_exit_hook
855 *
856 * Draw lines for process event.
857 *
858 * @param hook_data ControlFlowData structure of the viewer.
859 * @param call_data Event context.
860 *
861 * This function adds items to be drawn in a queue for each process.
862 *
863 */
864
865
866 int before_process_exit_hook(void *hook_data, void *call_data)
867 {
868
869 LttvEvent *event;
870
871 event = (LttvEvent *) call_data;
872 if (strcmp(lttv_traceset_get_name_from_event(event),
873 "sched_process_exit") != 0)
874 return FALSE;
875
876
877 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
878 LttvTraceState *ts = event->state;
879
880 #ifdef BABEL_CLEANUP
881 LttvFilter *filter = control_flow_data->filter;
882 if(filter != NULL && filter->head != NULL)
883 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
884 tfc->t_context->t,tfc,NULL,NULL))
885 return FALSE;
886 #endif
887
888 LttTime evtime = lttv_event_get_timestamp(event);
889
890 /* Add process to process list (if not present) */
891 //LttvProcessState *process = tfs->process;
892 guint cpu = lttv_traceset_get_cpuid_from_event(event);
893 guint trace_num = lttv_traceset_get_trace_index_from_event(event);
894
895 LttvProcessState *process = ts->running_process[cpu];
896 guint pid = process->pid;
897 HashedProcessData *hashed_process_data = NULL;
898
899 ProcessList *process_list = control_flow_data->process_list;
900
901 g_assert(process != NULL);
902
903 if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
904 hashed_process_data = process_list->current_hash_data[trace_num][cpu];
905 } else {
906 hashed_process_data = get_hashed_process_data(control_flow_data,
907 process, pid, trace_num);
908 }
909
910 /* Now, the process is in the state hash and our own process hash.
911 * We definitely can draw the items related to the ending state.
912 */
913
914 draw_state_items(control_flow_data,
915 hashed_process_data,
916 process,
917 evtime);
918
919 return 0;
920
921 }
922
923
924
925 /* before_process_release_hook
926 *
927 * Draw lines for process event.
928 *
929 * @param hook_data ControlFlowData structure of the viewer.
930 * @param call_data Event context.
931 *
932 * This function adds items to be drawn in a queue for each process.
933 *
934 */
935
936
937 int before_process_release_hook(void *hook_data, void *call_data)
938 {
939
940 LttvEvent *event;
941
942 event = (LttvEvent *) call_data;
943
944 if (strcmp(lttv_traceset_get_name_from_event(event),"sched_process_free") != 0)
945 return FALSE;
946
947 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
948
949
950 LttvTraceState *ts = event->state;
951
952 #ifdef BABEL_CLEANUP
953 LttvFilter *filter = control_flow_data->filter;
954 if(filter != NULL && filter->head != NULL)
955 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
956 tfc->t_context->t,tfc,NULL,NULL))
957 return FALSE;
958 #endif
959 LttTime evtime = lttv_event_get_timestamp(event);
960
961
962 guint trace_num = lttv_traceset_get_trace_index_from_event(event);
963
964 guint pid;
965 {
966 pid = lttv_event_get_long(event, "tid");
967 }
968
969 /* Add process to process list (if not present) */
970 /* Don't care about the process if it's not in the state hash already :
971 * that means a process that has never done anything in the trace and
972 * unknown suddently gets destroyed : no state meaningful to show. */
973 LttvProcessState *process = lttv_state_find_process(ts, ANY_CPU, pid);
974
975 if(process != NULL) {
976 LttTime birth;
977 HashedProcessData *hashed_process_data = NULL;
978
979 ProcessList *process_list = control_flow_data->process_list;
980
981 birth = process->creation_time;
982
983 /* Cannot use current process : this event happens on another process,
984 * action done by the parent. */
985 hashed_process_data = processlist_get_process_data(process_list,
986 pid,
987 process->cpu,
988 &birth,
989 trace_num);
990 if(unlikely(hashed_process_data == NULL))
991 /*
992 * Process already been scheduled out EXIT_DEAD, not in the process list
993 * anymore. Just return.
994 */
995 return FALSE;
996
997 /* Now, the process is in the state hash and our own process hash.
998 * We definitely can draw the items related to the ending state.
999 */
1000
1001 draw_state_items(control_flow_data,
1002 hashed_process_data,
1003 process,
1004 evtime);
1005 }
1006 return 0;
1007 }
1008
1009
1010
1011
1012
1013 /* after_process_fork_hook
1014 *
1015 * Create the processlist entry for the child process. Put the last
1016 * position in x at the current time value.
1017 *
1018 * @param hook_data ControlFlowData structure of the viewer.
1019 * @param call_data Event context.
1020 *
1021 * This function adds items to be drawn in a queue for each process.
1022 *
1023 */
1024 int after_process_fork_hook(void *hook_data, void *call_data)
1025 {
1026 LttvEvent *event;
1027
1028 event = (LttvEvent *) call_data;
1029
1030 if (strcmp(lttv_traceset_get_name_from_event(event),"sched_process_fork") != 0)
1031 return FALSE;
1032
1033 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
1034
1035
1036 LttvTraceState *ts = event->state;
1037
1038 #ifdef BABEL_CLEANUP
1039 LttvFilter *filter = control_flow_data->filter;
1040 if(filter != NULL && filter->head != NULL)
1041 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1042 tfc->t_context->t,tfc,NULL,NULL))
1043 return FALSE;
1044 #endif
1045
1046 LttTime evtime = lttv_event_get_timestamp(event);
1047
1048 guint child_pid;
1049 {
1050 child_pid = lttv_event_get_long(event, "child_tid");
1051 }
1052
1053 /* Add process to process list (if not present) */
1054 LttvProcessState *process_child;
1055 HashedProcessData *hashed_process_data_child = NULL;
1056
1057 ProcessList *process_list = control_flow_data->process_list;
1058
1059 /* Find child in the list... */
1060 process_child = lttv_state_find_process(ts, ANY_CPU, child_pid);
1061 /* It should exist, because we are after the state update. */
1062 g_assert(process_child != NULL);
1063
1064 guint trace_num = lttv_traceset_get_trace_index_from_event(event);
1065
1066 /* Cannot use current process, because this action is done by the parent
1067 * on its child. */
1068 hashed_process_data_child = get_hashed_process_data(control_flow_data,
1069 process_child, child_pid, trace_num);
1070
1071
1072 processlist_set_ppid(process_list, process_child->ppid,
1073 hashed_process_data_child);
1074 processlist_set_tgid(process_list, process_child->tgid,
1075 hashed_process_data_child);
1076
1077
1078
1079 if(likely(ltt_time_compare(hashed_process_data_child->next_good_time,
1080 evtime) <= 0))
1081 {
1082 TimeWindow time_window =
1083 lttvwindow_get_time_window(control_flow_data->tab);
1084
1085 #ifdef EXTRA_CHECK
1086 if(ltt_time_compare(evtime, time_window.start_time) == -1
1087 || ltt_time_compare(evtime, time_window.end_time) == 1)
1088 return FALSE;
1089 #endif //EXTRA_CHECK
1090 Drawing_t *drawing = control_flow_data->drawing;
1091 guint width = drawing->width;
1092 guint new_x;
1093 convert_time_to_pixels(
1094 time_window,
1095 evtime,
1096 width,
1097 &new_x);
1098
1099 if(likely(hashed_process_data_child->x.over != new_x)) {
1100 hashed_process_data_child->x.over = new_x;
1101 hashed_process_data_child->x.over_used = FALSE;
1102 hashed_process_data_child->x.over_marked = FALSE;
1103 }
1104 if(likely(hashed_process_data_child->x.middle != new_x)) {
1105 hashed_process_data_child->x.middle = new_x;
1106 hashed_process_data_child->x.middle_used = FALSE;
1107 hashed_process_data_child->x.middle_marked = FALSE;
1108 }
1109 if(likely(hashed_process_data_child->x.under != new_x)) {
1110 hashed_process_data_child->x.under = new_x;
1111 hashed_process_data_child->x.under_used = FALSE;
1112 hashed_process_data_child->x.under_marked = FALSE;
1113 }
1114 }
1115 return FALSE;
1116 }
1117
1118
1119
1120 /* after_process_exit_hook
1121 *
1122 * Create the processlist entry for the child process. Put the last
1123 * position in x at the current time value.
1124 *
1125 * @param hook_data ControlFlowData structure of the viewer.
1126 * @param call_data Event context.
1127 *
1128 * This function adds items to be drawn in a queue for each process.
1129 *
1130 */
1131 int after_process_exit_hook(void *hook_data, void *call_data)
1132 {
1133
1134 LttvEvent *event;
1135
1136 event = (LttvEvent *) call_data;
1137
1138 if (strcmp(lttv_traceset_get_name_from_event(event),"sched_process_exit") != 0)
1139 return FALSE;
1140
1141 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
1142
1143 LttvTraceState *ts = event->state;
1144
1145 #ifdef BABEL_CLEANUP
1146 LttvFilter *filter = control_flow_data->filter;
1147 if(filter != NULL && filter->head != NULL)
1148 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1149 tfc->t_context->t,tfc,NULL,NULL))
1150 return FALSE;
1151 #endif
1152
1153 LttTime evtime = lttv_event_get_timestamp(event);
1154
1155 /* Add process to process list (if not present) */
1156 //LttvProcessState *process = tfs->process;
1157 guint cpu = lttv_traceset_get_cpuid_from_event(event);
1158 guint trace_num = lttv_traceset_get_trace_index_from_event(event);
1159 LttvProcessState *process = ts->running_process[cpu];
1160
1161 /* It should exist, because we are after the state update. */
1162 g_assert(process != NULL);
1163
1164 guint pid = process->pid;
1165 //LttTime birth;
1166 //guint pl_height = 0;
1167 HashedProcessData *hashed_process_data = NULL;
1168
1169 ProcessList *process_list = control_flow_data->process_list;
1170
1171 //birth = process->creation_time;
1172
1173 if(likely(process_list->current_hash_data[trace_num][cpu] != NULL) ){
1174 hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1175 } else {
1176 hashed_process_data = get_hashed_process_data(control_flow_data,
1177 process, pid, trace_num);
1178
1179
1180 /* Set the current process */
1181 process_list->current_hash_data[trace_num][process->cpu] =
1182 hashed_process_data;
1183 }
1184
1185 if(unlikely(ltt_time_compare(hashed_process_data->next_good_time,
1186 evtime) <= 0))
1187 {
1188 TimeWindow time_window =
1189 lttvwindow_get_time_window(control_flow_data->tab);
1190
1191 #ifdef EXTRA_CHECK
1192 if(ltt_time_compare(evtime, time_window.start_time) == -1
1193 || ltt_time_compare(evtime, time_window.end_time) == 1)
1194 return FALSE;
1195 #endif //EXTRA_CHECK
1196 Drawing_t *drawing = control_flow_data->drawing;
1197 guint width = drawing->width;
1198 guint new_x;
1199 convert_time_to_pixels(
1200 time_window,
1201 evtime,
1202 width,
1203 &new_x);
1204 if(unlikely(hashed_process_data->x.middle != new_x)) {
1205 hashed_process_data->x.middle = new_x;
1206 hashed_process_data->x.middle_used = FALSE;
1207 hashed_process_data->x.middle_marked = FALSE;
1208 }
1209 }
1210
1211 return FALSE;
1212 }
1213
1214
1215 /* Get the filename of the process to print */
1216 int after_fs_exec_hook(void *hook_data, void *call_data)
1217 {
1218 #ifdef BABEL_CLEANUP
1219 LttvTraceHook *th = (LttvTraceHook*)hook_data;
1220 EventsRequest *events_request = (EventsRequest*)th->hook_data;
1221 ControlFlowData *control_flow_data = events_request->viewer_data;
1222
1223 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1224
1225 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1226
1227 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1228
1229 LttEvent *e;
1230 e = ltt_tracefile_get_event(tfc->tf);
1231
1232 LttvFilter *filter = control_flow_data->filter;
1233 if(filter != NULL && filter->head != NULL)
1234 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1235 tfc->t_context->t,tfc,NULL,NULL))
1236 return FALSE;
1237
1238 guint cpu = tfs->cpu;
1239 guint trace_num = ts->parent.index;
1240 LttvProcessState *process = ts->running_process[cpu];
1241 g_assert(process != NULL);
1242
1243 guint pid = process->pid;
1244
1245 /* Well, the process_out existed : we must get it in the process hash
1246 * or add it, and draw its items.
1247 */
1248 /* Add process to process list (if not present) */
1249 guint pl_height = 0;
1250 HashedProcessData *hashed_process_data = NULL;
1251 ProcessList *process_list = control_flow_data->process_list;
1252 LttTime birth = process->creation_time;
1253
1254 if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1255 hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1256 } else {
1257 hashed_process_data = get_hashed_process_data(control_flow_data,
1258 process, pid, trace_num);
1259 /* Set the current process */
1260 process_list->current_hash_data[trace_num][process->cpu] =
1261 hashed_process_data;
1262 }
1263
1264 processlist_set_name(process_list, process->name, hashed_process_data);
1265
1266 #endif //babel_cleanup
1267 return 0;
1268
1269 }
1270
1271 /* after_event_enum_process_hook
1272 *
1273 * Create the processlist entry for the child process. Put the last
1274 * position in x at the current time value.
1275 *
1276 * @param hook_data ControlFlowData structure of the viewer.
1277 * @param call_data Event context.
1278 *
1279 * This function adds items to be drawn in a queue for each process.
1280 *
1281 */
1282 int after_event_enum_process_hook(void *hook_data, void *call_data)
1283 {
1284 LttvEvent *event;
1285
1286 event = (LttvEvent *) call_data;
1287
1288 if (strcmp(lttv_traceset_get_name_from_event(event),"lttng_statedump_process_state") != 0)
1289 return FALSE;
1290
1291 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
1292
1293
1294 LttvTraceState *ts = event->state;
1295
1296 guint first_cpu, nb_cpus, cpu;
1297
1298 #ifdef BABEL_CLEANUP
1299 LttvFilter *filter = control_flow_data->filter;
1300 if(filter != NULL && filter->head != NULL)
1301 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
1302 tfc->t_context->t,tfc,NULL,NULL))
1303 return FALSE;
1304 #endif
1305 /* Add process to process list (if not present) */
1306 LttvProcessState *process_in;
1307 HashedProcessData *hashed_process_data_in = NULL;
1308
1309 ProcessList *process_list = control_flow_data->process_list;
1310 guint trace_num = lttv_traceset_get_trace_index_from_event(event);
1311
1312 guint pid_in;
1313 {
1314 pid_in = lttv_event_get_long(event, "tid");
1315 }
1316
1317 if(pid_in == 0) {
1318 first_cpu = 0;
1319 nb_cpus = lttv_trace_get_num_cpu(ts->trace);
1320 } else {
1321 first_cpu = ANY_CPU;
1322 nb_cpus = ANY_CPU+1;
1323 }
1324
1325 for(cpu = first_cpu; cpu < nb_cpus; cpu++) {
1326 /* Find process pid_in in the list... */
1327 process_in = lttv_state_find_process(ts, cpu, pid_in);
1328 //process_in = tfs->process;
1329 //guint cpu = tfs->cpu;
1330 //guint trace_num = ts->parent.index;
1331 //process_in = ts->running_process[cpu];
1332 /* It should exist, because we are after the state update. */
1333 #ifdef EXTRA_CHECK
1334 //g_assert(process_in != NULL);
1335 #endif //EXTRA_CHECK
1336
1337 hashed_process_data_in = get_hashed_process_data(control_flow_data,
1338 process_in, pid_in, trace_num);
1339
1340 processlist_set_name(process_list, process_in->name,
1341 hashed_process_data_in);
1342 processlist_set_ppid(process_list, process_in->ppid,
1343 hashed_process_data_in);
1344 processlist_set_tgid(process_list, process_in->tgid,
1345 hashed_process_data_in);
1346
1347 }
1348 return 0;
1349 }
1350
1351
1352 gint update_time_window_hook(void *hook_data, void *call_data)
1353 {
1354 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
1355
1356 Drawing_t *drawing = control_flow_data->drawing;
1357 ProcessList *process_list = control_flow_data->process_list;
1358
1359 const TimeWindowNotifyData *time_window_nofify_data =
1360 ((const TimeWindowNotifyData *)call_data);
1361
1362 TimeWindow *old_time_window =
1363 time_window_nofify_data->old_time_window;
1364 TimeWindow *new_time_window =
1365 time_window_nofify_data->new_time_window;
1366
1367 /* Update the ruler */
1368 drawing_update_ruler(control_flow_data->drawing,
1369 new_time_window);
1370
1371
1372 /* Two cases : zoom in/out or scrolling */
1373
1374 /* In order to make sure we can reuse the old drawing, the scale must
1375 * be the same and the new time interval being partly located in the
1376 * currently shown time interval. (reuse is only for scrolling)
1377 */
1378
1379 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
1380 old_time_window->start_time.tv_sec,
1381 old_time_window->start_time.tv_nsec,
1382 old_time_window->time_width.tv_sec,
1383 old_time_window->time_width.tv_nsec);
1384
1385 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
1386 new_time_window->start_time.tv_sec,
1387 new_time_window->start_time.tv_nsec,
1388 new_time_window->time_width.tv_sec,
1389 new_time_window->time_width.tv_nsec);
1390
1391 if( new_time_window->time_width.tv_sec == old_time_window->time_width.tv_sec
1392 && new_time_window->time_width.tv_nsec == old_time_window->time_width.tv_nsec)
1393 {
1394 /* Same scale (scrolling) */
1395 g_info("scrolling");
1396 LttTime *ns = &new_time_window->start_time;
1397 LttTime *os = &old_time_window->start_time;
1398 LttTime old_end = old_time_window->end_time;
1399 LttTime new_end = new_time_window->end_time;
1400 //if(ns<os+w<ns+w)
1401 //if(ns<os+w && os+w<ns+w)
1402 //if(ns<old_end && os<ns)
1403 if(ltt_time_compare(*ns, old_end) == -1
1404 && ltt_time_compare(*os, *ns) == -1)
1405 {
1406 g_info("scrolling near right");
1407 /* Scroll right, keep right part of the screen */
1408 guint x = 0;
1409 guint width = control_flow_data->drawing->width;
1410 convert_time_to_pixels(
1411 *old_time_window,
1412 *ns,
1413 width,
1414 &x);
1415
1416 /* Copy old data to new location */
1417 copy_pixmap_region(process_list,
1418 NULL,
1419 control_flow_data->drawing->drawing_area->style->black_gc,
1420 NULL,
1421 x, 0,
1422 0, 0,
1423 control_flow_data->drawing->width-x+SAFETY, -1);
1424
1425 if(drawing->damage_begin == drawing->damage_end)
1426 drawing->damage_begin = control_flow_data->drawing->width-x;
1427 else
1428 drawing->damage_begin = 0;
1429
1430 drawing->damage_end = control_flow_data->drawing->width;
1431
1432 /* Clear the data request background, but not SAFETY */
1433 rectangle_pixmap(process_list,
1434 control_flow_data->drawing->drawing_area->style->black_gc,
1435 TRUE,
1436 drawing->damage_begin+SAFETY, 0,
1437 drawing->damage_end - drawing->damage_begin, // do not overlap
1438 -1);
1439 gtk_widget_queue_draw(drawing->drawing_area);
1440 //gtk_widget_queue_draw_area (drawing->drawing_area,
1441 // 0,0,
1442 // control_flow_data->drawing->width,
1443 // control_flow_data->drawing->height);
1444
1445 /* Get new data for the rest. */
1446 drawing_data_request(control_flow_data->drawing,
1447 drawing->damage_begin, 0,
1448 drawing->damage_end - drawing->damage_begin,
1449 control_flow_data->drawing->height);
1450 } else {
1451 //if(ns<os<ns+w)
1452 //if(ns<os && os<ns+w)
1453 //if(ns<os && os<new_end)
1454 if(ltt_time_compare(*ns,*os) == -1
1455 && ltt_time_compare(*os,new_end) == -1)
1456 {
1457 g_info("scrolling near left");
1458 /* Scroll left, keep left part of the screen */
1459 guint x = 0;
1460 guint width = control_flow_data->drawing->width;
1461 convert_time_to_pixels(
1462 *new_time_window,
1463 *os,
1464 width,
1465 &x);
1466
1467 /* Copy old data to new location */
1468 copy_pixmap_region (process_list,
1469 NULL,
1470 control_flow_data->drawing->drawing_area->style->black_gc,
1471 NULL,
1472 0, 0,
1473 x, 0,
1474 -1, -1);
1475
1476 if(drawing->damage_begin == drawing->damage_end)
1477 drawing->damage_end = x;
1478 else
1479 drawing->damage_end =
1480 control_flow_data->drawing->width;
1481
1482 drawing->damage_begin = 0;
1483
1484 rectangle_pixmap (process_list,
1485 control_flow_data->drawing->drawing_area->style->black_gc,
1486 TRUE,
1487 drawing->damage_begin, 0,
1488 drawing->damage_end - drawing->damage_begin, // do not overlap
1489 -1);
1490
1491 gtk_widget_queue_draw(drawing->drawing_area);
1492 //gtk_widget_queue_draw_area (drawing->drawing_area,
1493 // 0,0,
1494 // control_flow_data->drawing->width,
1495 // control_flow_data->drawing->height);
1496
1497
1498 /* Get new data for the rest. */
1499 drawing_data_request(control_flow_data->drawing,
1500 drawing->damage_begin, 0,
1501 drawing->damage_end - drawing->damage_begin,
1502 control_flow_data->drawing->height);
1503
1504 } else {
1505 if(ltt_time_compare(*ns,*os) == 0)
1506 {
1507 g_info("not scrolling");
1508 } else {
1509 g_info("scrolling far");
1510 /* Cannot reuse any part of the screen : far jump */
1511
1512
1513 rectangle_pixmap (process_list,
1514 control_flow_data->drawing->drawing_area->style->black_gc,
1515 TRUE,
1516 0, 0,
1517 control_flow_data->drawing->width+SAFETY, // do not overlap
1518 -1);
1519
1520 //gtk_widget_queue_draw_area (drawing->drawing_area,
1521 // 0,0,
1522 // control_flow_data->drawing->width,
1523 // control_flow_data->drawing->height);
1524 gtk_widget_queue_draw(drawing->drawing_area);
1525
1526 drawing->damage_begin = 0;
1527 drawing->damage_end = control_flow_data->drawing->width;
1528
1529 drawing_data_request(control_flow_data->drawing,
1530 0, 0,
1531 control_flow_data->drawing->width,
1532 control_flow_data->drawing->height);
1533
1534 }
1535 }
1536 }
1537 } else {
1538 /* Different scale (zoom) */
1539 g_info("zoom");
1540
1541 rectangle_pixmap (process_list,
1542 control_flow_data->drawing->drawing_area->style->black_gc,
1543 TRUE,
1544 0, 0,
1545 control_flow_data->drawing->width+SAFETY, // do not overlap
1546 -1);
1547
1548 //gtk_widget_queue_draw_area (drawing->drawing_area,
1549 // 0,0,
1550 // control_flow_data->drawing->width,
1551 // control_flow_data->drawing->height);
1552 gtk_widget_queue_draw(drawing->drawing_area);
1553
1554 drawing->damage_begin = 0;
1555 drawing->damage_end = control_flow_data->drawing->width;
1556
1557 drawing_data_request(control_flow_data->drawing,
1558 0, 0,
1559 control_flow_data->drawing->width,
1560 control_flow_data->drawing->height);
1561 }
1562
1563 /* Update directly when scrolling */
1564 gdk_window_process_updates(control_flow_data->drawing->drawing_area->window,
1565 TRUE);
1566
1567 return 0;
1568 }
1569
1570 gint traceset_notify(void *hook_data, void *call_data)
1571 {
1572 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
1573 Drawing_t *drawing = control_flow_data->drawing;
1574
1575 if(unlikely(drawing->gc == NULL)) {
1576 return FALSE;
1577 }
1578 if(drawing->dotted_gc == NULL) {
1579 return FALSE;
1580 }
1581
1582 drawing_clear(control_flow_data->drawing);
1583 processlist_clear(control_flow_data->process_list);
1584 gtk_widget_set_size_request(
1585 control_flow_data->drawing->drawing_area,
1586 -1, processlist_get_height(control_flow_data->process_list));
1587 redraw_notify(control_flow_data, NULL);
1588
1589 request_background_data(control_flow_data);
1590
1591 return FALSE;
1592 }
1593
1594 gint redraw_notify(void *hook_data, void *call_data)
1595 {
1596 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
1597 Drawing_t *drawing = control_flow_data->drawing;
1598 GtkWidget *widget = drawing->drawing_area;
1599
1600 drawing->damage_begin = 0;
1601 drawing->damage_end = drawing->width;
1602
1603 /* fun feature, to be separated someday... */
1604 drawing_clear(control_flow_data->drawing);
1605 processlist_clear(control_flow_data->process_list);
1606 gtk_widget_set_size_request(
1607 control_flow_data->drawing->drawing_area,
1608 -1, processlist_get_height(control_flow_data->process_list));
1609 // Clear the images
1610 rectangle_pixmap (control_flow_data->process_list,
1611 widget->style->black_gc,
1612 TRUE,
1613 0, 0,
1614 drawing->alloc_width,
1615 -1);
1616
1617 gtk_widget_queue_draw(drawing->drawing_area);
1618
1619 if(drawing->damage_begin < drawing->damage_end)
1620 {
1621 drawing_data_request(drawing,
1622 drawing->damage_begin,
1623 0,
1624 drawing->damage_end-drawing->damage_begin,
1625 drawing->height);
1626 }
1627
1628 //gtk_widget_queue_draw_area(drawing->drawing_area,
1629 // 0,0,
1630 // drawing->width,
1631 // drawing->height);
1632 return FALSE;
1633
1634 }
1635
1636
1637 gint continue_notify(void *hook_data, void *call_data)
1638 {
1639 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
1640 Drawing_t *drawing = control_flow_data->drawing;
1641
1642 //g_assert(widget->allocation.width == drawing->damage_end);
1643
1644 if(drawing->damage_begin < drawing->damage_end)
1645 {
1646 drawing_data_request(drawing,
1647 drawing->damage_begin,
1648 0,
1649 drawing->damage_end-drawing->damage_begin,
1650 drawing->height);
1651 }
1652
1653 return FALSE;
1654 }
1655
1656
1657 gint update_current_time_hook(void *hook_data, void *call_data)
1658 {
1659
1660 ControlFlowData *control_flow_data = (ControlFlowData*)hook_data;
1661
1662 LttTime current_time = *((LttTime*)call_data);
1663
1664 TimeWindow time_window =
1665 lttvwindow_get_time_window(control_flow_data->tab);
1666
1667 LttTime time_begin = time_window.start_time;
1668 LttTime width = time_window.time_width;
1669 LttTime half_width;
1670 {
1671 guint64 time_ll = ltt_time_to_uint64(width);
1672 time_ll = time_ll >> 1; /* divide by two */
1673 half_width = ltt_time_from_uint64(time_ll);
1674 }
1675 LttTime time_end = ltt_time_add(time_begin, width);
1676
1677 LttvTraceset * ts = lttvwindow_get_traceset(control_flow_data->tab);
1678
1679 TimeInterval time_span = lttv_traceset_get_time_span_real(ts);
1680 LttTime trace_start = time_span.start_time;
1681 LttTime trace_end = time_span.end_time;
1682
1683 g_info("New current time HOOK : %lu, %lu", current_time.tv_sec,
1684 current_time.tv_nsec);
1685
1686
1687
1688 /* If current time is inside time interval, just move the highlight
1689 * bar */
1690
1691 /* Else, we have to change the time interval. We have to tell it
1692 * to the main window. */
1693 /* The time interval change will take care of placing the current
1694 * time at the center of the visible area, or nearest possible if we are
1695 * at one end of the trace. */
1696
1697
1698 if(ltt_time_compare(current_time, time_begin) < 0)
1699 {
1700 TimeWindow new_time_window;
1701
1702 if(ltt_time_compare(current_time,
1703 ltt_time_add(trace_start,half_width)) < 0)
1704 time_begin = trace_start;
1705 else
1706 time_begin = ltt_time_sub(current_time,half_width);
1707
1708 new_time_window.start_time = time_begin;
1709 new_time_window.time_width = width;
1710 new_time_window.time_width_double = ltt_time_to_double(width);
1711 new_time_window.end_time = ltt_time_add(time_begin, width);
1712
1713 lttvwindow_report_time_window(control_flow_data->tab, new_time_window);
1714 }
1715 else if(ltt_time_compare(current_time, time_end) > 0)
1716 {
1717 TimeWindow new_time_window;
1718
1719 if(ltt_time_compare(current_time, ltt_time_sub(trace_end, half_width)) > 0)
1720 time_begin = ltt_time_sub(trace_end,width);
1721 else
1722 time_begin = ltt_time_sub(current_time,half_width);
1723
1724 new_time_window.start_time = time_begin;
1725 new_time_window.time_width = width;
1726 new_time_window.time_width_double = ltt_time_to_double(width);
1727 new_time_window.end_time = ltt_time_add(time_begin, width);
1728
1729 lttvwindow_report_time_window(control_flow_data->tab, new_time_window);
1730
1731 }
1732 gtk_widget_queue_draw(control_flow_data->drawing->drawing_area);
1733
1734 /* Update directly when scrolling */
1735 gdk_window_process_updates(control_flow_data->drawing->drawing_area->window,
1736 TRUE);
1737
1738 return 0;
1739
1740 }
1741
1742 typedef struct _ClosureData {
1743 EventsRequest *events_request;
1744 LttTime end_time;
1745 guint x_end;
1746 } ClosureData;
1747
1748
1749 void draw_closure(gpointer key, gpointer value, gpointer user_data)
1750 {
1751
1752 ProcessInfo *process_info = (ProcessInfo*)key;
1753 HashedProcessData *hashed_process_data = (HashedProcessData*)value;
1754 ClosureData *closure_data = (ClosureData*)user_data;
1755
1756 EventsRequest *events_request = closure_data->events_request;
1757 ControlFlowData *control_flow_data = events_request->viewer_data;
1758 LttvTraceset *ts = lttvwindow_get_traceset(control_flow_data->tab);
1759
1760
1761 LttTime evtime = closure_data->end_time;
1762
1763 gboolean dodraw = TRUE;
1764
1765 {
1766 /* For the process */
1767 /* First, check if the current process is in the state computation
1768 * process list. If it is there, that means we must add it right now and
1769 * draw items from the beginning of the read for it. If it is not
1770 * present, it's a new process and it was not present : it will
1771 * be added after the state update. */
1772 #ifdef EXTRA_CHECK
1773 g_assert(lttv_traceset_number(tsc->ts) > 0);
1774 #endif //EXTRA_CHECK
1775
1776 LttvTrace *trace = lttv_traceset_get(ts, process_info->trace_num);
1777 LttvTraceState *trace_state = trace->state;
1778
1779 #if 0
1780 //FIXME : optimize data structures.
1781 LttvTracefileState *tfs;
1782 LttvTracefileContext *tfc;
1783 guint i;
1784 for(i=0;i<tc->tracefiles->len;i++) {
1785 tfc = g_array_index(tc->tracefiles, LttvTracefileContext*, i);
1786 if(ltt_tracefile_name(tfc->tf) == LTT_NAME_CPU
1787 && tfs->cpu == process_info->cpu)
1788 break;
1789
1790 }
1791 g_assert(i<tc->tracefiles->len);
1792 tfs = LTTV_TRACEFILE_STATE(tfc);
1793 #endif //0
1794 // LttvTracefileState *tfs =ts
1795 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
1796 // tracefiles[process_info->cpu];
1797
1798 LttvProcessState *process;
1799 process = lttv_state_find_process(trace_state, process_info->cpu,
1800 process_info->pid);
1801
1802 if(unlikely(process != NULL)) {
1803 #ifdef BABEL_CLEANUP
1804 LttvFilter *filter = control_flow_data->filter;
1805 if(filter != NULL && filter->head != NULL)
1806 if(!lttv_filter_tree_parse(filter->head,NULL,NULL,
1807 tc->t,NULL,process,tc))
1808 dodraw = FALSE;
1809 #endif //babel_cleanup
1810 /* Only draw for processes that are currently in the trace states */
1811
1812 #ifdef EXTRA_CHECK
1813 /* Should be alike when background info is ready */
1814 if(control_flow_data->background_info_waiting==0)
1815 g_assert(ltt_time_compare(process->creation_time,
1816 process_info->birth) == 0);
1817 #endif //EXTRA_CHECK
1818
1819 /* Now, the process is in the state hash and our own process hash.
1820 * We definitely can draw the items related to the ending state.
1821 */
1822
1823 if(unlikely(ltt_time_compare(hashed_process_data->next_good_time,
1824 evtime) <= 0))
1825 {
1826 TimeWindow time_window =
1827 lttvwindow_get_time_window(control_flow_data->tab);
1828
1829 #ifdef EXTRA_CHECK
1830 if(ltt_time_compare(evtime, time_window.start_time) == -1
1831 || ltt_time_compare(evtime, time_window.end_time) == 1)
1832 return;
1833 #endif //EXTRA_CHECK
1834 Drawing_t *drawing = control_flow_data->drawing;
1835 guint width = drawing->width;
1836
1837 guint x = closure_data->x_end;
1838
1839 DrawContext draw_context;
1840
1841 init_drawing_context(&draw_context,
1842 hashed_process_data,
1843 drawing,
1844 x);
1845
1846 #if 0
1847 /* Jump over draw if we are at the same x position */
1848 if(x == hashed_process_data->x.over)
1849 {
1850 /* jump */
1851 } else {
1852 draw_context.drawinfo.start.x = hashed_process_data->x.over;
1853 /* Draw the line */
1854 PropertiesLine prop_line = prepare_execmode_line(process);
1855 draw_line((void*)&prop_line, (void*)&draw_context);
1856
1857 hashed_process_data->x.over = x;
1858 }
1859 #endif //0
1860
1861 if(unlikely(x == hashed_process_data->x.middle &&
1862 hashed_process_data->x.middle_used)) {
1863 #if 0 /* do not mark closure : not missing information */
1864 if(hashed_process_data->x.middle_marked == FALSE) {
1865 /* Draw collision indicator */
1866 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1867 gdk_draw_point(drawing->pixmap,
1868 drawing->gc,
1869 x,
1870 y+(height/2)-3);
1871 hashed_process_data->x.middle_marked = TRUE;
1872 }
1873 #endif //0
1874 /* Jump */
1875 } else {
1876 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
1877 /* Draw the line */
1878 if(dodraw) {
1879 PropertiesLine prop_line = prepare_s_e_line(process);
1880 draw_line((void*)&prop_line, (void*)&draw_context);
1881 }
1882
1883 /* become the last x position */
1884 if(likely(x != hashed_process_data->x.middle)) {
1885 hashed_process_data->x.middle = x;
1886 /* but don't use the pixel */
1887 hashed_process_data->x.middle_used = FALSE;
1888
1889 /* Calculate the next good time */
1890 convert_pixels_to_time(width, x+1, time_window,
1891 &hashed_process_data->next_good_time);
1892 }
1893 }
1894 }
1895 }
1896 }
1897 return;
1898 }
1899
1900 int before_chunk(void *hook_data, void *call_data)
1901 {
1902
1903 EventsRequest *events_request = (EventsRequest*)hook_data;
1904 LttvTraceset *ts = (LttvTraceset*)call_data;
1905 #if 0
1906 /* Desactivate sort */
1907 gtk_tree_sortable_set_sort_column_id(
1908 GTK_TREE_SORTABLE(cfd->process_list->list_store),
1909 TRACE_COLUMN,
1910 GTK_SORT_ASCENDING);
1911 #endif //0
1912 drawing_chunk_begin(events_request, ts);
1913
1914 return 0;
1915 }
1916
1917 int before_request(void *hook_data, void *call_data)
1918 {
1919
1920 EventsRequest *events_request = (EventsRequest*)hook_data;
1921
1922 drawing_data_request_begin(events_request);
1923
1924 return 0;
1925
1926 }
1927
1928
1929 void draw_closing_lines(ControlFlowData *control_flow_data,
1930 EventsRequest* events_request)
1931 {
1932 ProcessList *process_list = control_flow_data->process_list;
1933
1934
1935 ClosureData closure_data;
1936 closure_data.events_request = events_request;
1937 closure_data.end_time = events_request->end_time;
1938
1939 TimeWindow time_window =
1940 lttvwindow_get_time_window(control_flow_data->tab);
1941 guint width = control_flow_data->drawing->width;
1942 convert_time_to_pixels(
1943 time_window,
1944 events_request->end_time,
1945 width,
1946 &closure_data.x_end);
1947
1948
1949 /* Draw last items */
1950 g_hash_table_foreach(process_list->process_hash, draw_closure,
1951 (void*)&closure_data);
1952
1953
1954 /* Request expose */
1955 drawing_request_expose(events_request, events_request->end_time);
1956 }
1957
1958 /*
1959 * after request is necessary in addition of after chunk in order to draw
1960 * lines until the end of the screen. after chunk just draws lines until
1961 * the last event.
1962 *
1963 * for each process
1964 * draw closing line
1965 * expose
1966 */
1967 int after_request(void *hook_data, void *call_data)
1968 {
1969
1970 EventsRequest *events_request = (EventsRequest*)hook_data;
1971 ControlFlowData *control_flow_data = events_request->viewer_data;
1972
1973 draw_closing_lines(control_flow_data, events_request);
1974
1975 return 0;
1976 }
1977
1978 /*
1979 * for each process
1980 * draw closing line
1981 * expose
1982 */
1983 int after_chunk(void *hook_data, void *call_data)
1984 {
1985
1986 EventsRequest *events_request = (EventsRequest*)hook_data;
1987 ControlFlowData *control_flow_data = events_request->viewer_data;
1988 LttvTraceset *ts = (LttvTraceset*)call_data;
1989
1990
1991 ProcessList *process_list = control_flow_data->process_list;
1992 guint i;
1993 guint nb_trace = lttv_traceset_number(ts);
1994
1995 /* Only execute when called for the first trace's events request */
1996 if(!process_list->current_hash_data)
1997 return 0;
1998
1999 for(i = 0 ; i < nb_trace ; i++) {
2000 g_free(process_list->current_hash_data[i]);
2001 }
2002 g_free(process_list->current_hash_data);
2003 process_list->current_hash_data = NULL;
2004
2005 draw_closing_lines(control_flow_data, events_request);
2006
2007 return 0;
2008 }
2009
2010 /* after_statedump_end
2011 *
2012 * @param hook_data ControlFlowData structure of the viewer.
2013 * @param call_data Event context.
2014 *
2015 * This function adds items to be drawn in a queue for each process.
2016 *
2017 */
2018 int before_statedump_end(void *hook_data, void *call_data)
2019 {
2020 LttvEvent *event;
2021
2022 event = (LttvEvent *) call_data;
2023
2024 if (strcmp(lttv_traceset_get_name_from_event(event),"lttng_statedump_end") != 0)
2025 return FALSE;
2026
2027 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
2028
2029
2030 LttvTraceState *ts = event->state;
2031
2032
2033 ProcessList *process_list = control_flow_data->process_list;
2034
2035 #ifdef BABEL_CLEANUP
2036 LttvFilter *filter = control_flow_data->filter;
2037 if(filter != NULL && filter->head != NULL)
2038 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
2039 tfc->t_context->t,tfc,NULL,NULL))
2040 return FALSE;
2041 #endif
2042
2043 LttTime evtime = lttv_event_get_timestamp(event);
2044
2045 ClosureData closure_data;
2046 //TODO ybrosseau 2013-03-27: Fake and event_request.
2047 // We need to change the API of drawing_request_expose to ask
2048 // For and control flow data only.
2049 EventsRequest events_request;
2050 events_request.viewer_data = control_flow_data;
2051 closure_data.events_request = &events_request;
2052 closure_data.end_time = evtime;
2053
2054 TimeWindow time_window =
2055 lttvwindow_get_time_window(control_flow_data->tab);
2056 guint width = control_flow_data->drawing->width;
2057 convert_time_to_pixels(
2058 time_window,
2059 evtime,
2060 width,
2061 &closure_data.x_end);
2062
2063 /* Draw last items */
2064 g_hash_table_foreach(process_list->process_hash, draw_closure,
2065 (void*)&closure_data);
2066
2067 #if 0
2068 /* Reactivate sort */
2069 gtk_tree_sortable_set_sort_column_id(
2070 GTK_TREE_SORTABLE(control_flow_data->process_list->list_store),
2071 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
2072 GTK_SORT_ASCENDING);
2073
2074 update_index_to_pixmap(control_flow_data->process_list);
2075 /* Request a full expose : drawing scrambled */
2076 gtk_widget_queue_draw(control_flow_data->drawing->drawing_area);
2077 #endif //0
2078 /* Request expose (updates damages zone also) */
2079 drawing_request_expose(&events_request, evtime);
2080
2081 return 0;
2082 }
This page took 0.108531 seconds and 4 git commands to generate.