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