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