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