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