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