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