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