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