move lttv_merge_facility_event_name in tracecontext.h
[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>
9e01e6d4 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
84extern 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
92static 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 */
117static 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 */
186GtkWidget *
58a9b31b 187h_resourceview(LttvPlugin *plugin)
9e01e6d4 188{
189 LttvPluginTab *ptab = LTTV_PLUGIN_TAB(plugin);
190 Tab *tab = ptab->tab;
191 g_info("h_guicontrolflow, %p", tab);
58a9b31b 192 ControlFlowData *control_flow_data = resourceview(ptab);
9e01e6d4 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
220void legend_destructor(GtkWindow *legend)
221{
222 g_legend_list = g_slist_remove(g_legend_list, legend);
223}
224
225/* Create a popup legend */
226GtkWidget *
227h_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
262int 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 */
273static 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;
9e01e6d4 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
d3d99fde 319static void cpu_set_line_color(PropertiesLine *prop_line, LttvCPUState *s)
598026ba 320{
1b171947 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];
d3d99fde 327
201fcc15 328 if(present_state == LTTV_CPU_IDLE) {
598026ba 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 }
d3d99fde 337 else if(present_state == LTTV_CPU_TRAP) {
338 prop_line->color = drawing_colors_cpu[COL_CPU_TRAP];
201fcc15 339 } else {
340 prop_line->color = drawing_colors_cpu[COL_CPU_UNKNOWN];
d3d99fde 341 }
598026ba 342}
9e01e6d4 343
8743690d 344static void irq_set_line_color(PropertiesLine *prop_line, LttvIRQState *s)
345{
1b171947 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];
8743690d 351
1b171947 352 if(present_state == LTTV_IRQ_IDLE) {
8743690d 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 }
1b171947 358 else {
359 prop_line->color = drawing_colors_irq[COL_IRQ_UNKNOWN];
360 }
8743690d 361}
362
20d16f82 363static void bdev_set_line_color(PropertiesLine *prop_line, LttvBdevState *s)
364{
1b171947 365 GQuark present_state;
23e59a12 366 if(s == 0 || s->mode_stack->len == 0)
1b171947 367 present_state = LTTV_BDEV_UNKNOWN;
368 else
369 present_state = ((GQuark*)s->mode_stack->data)[s->mode_stack->len-1];
20d16f82 370
1b171947 371 if(present_state == LTTV_BDEV_IDLE) {
20d16f82 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 }
1b171947 380 else {
381 prop_line->color = drawing_colors_bdev[COL_BDEV_UNKNOWN];
382 }
20d16f82 383}
384
9e01e6d4 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
403int before_schedchange_hook(void *hook_data, void *call_data)
404{
dd455fb8 405 LttvTraceHook *th = (LttvTraceHook*)hook_data;
406 EventsRequest *events_request = (EventsRequest*)th->hook_data;
9e01e6d4 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
58a9b31b 421 GQuark cpuq;
422
9e01e6d4 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;
dd455fb8 430 pid_out = ltt_event_get_long_unsigned(e, th->f1);
431 pid_in = ltt_event_get_long_unsigned(e, th->f2);
44ffb95f 432// if(pid_in != 0 && pid_out != 0) {
433// /* not a transition to/from idle */
434// return 0;
435// }
c4e6f4dc 436
9e01e6d4 437 tfc->target_pid = pid_out;
58a9b31b 438// if(!filter || !filter->head ||
439// lttv_filter_tree_parse(filter->head,e,tfc->tf,
440// tfc->t_context->t,tfc,NULL,NULL)) {
9e01e6d4 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;
44ffb95f 448 {
449 gchar *cpustr;
450 cpustr = g_strdup_printf("CPU%u", cpu);
451 cpuq = g_quark_from_string(cpustr);
452 g_free(cpustr);
453 }
58a9b31b 454
9e01e6d4 455 guint trace_num = ts->parent.index;
58a9b31b 456// LttvProcessState *process = ts->running_process[cpu];
9e01e6d4 457 /* unknown state, bad current pid */
58a9b31b 458// if(process->pid != pid_out)
459// process = lttv_state_find_process(ts,
460// tfs->cpu, pid_out);
9e01e6d4 461
58a9b31b 462// if(process != NULL) {
9e01e6d4 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;
58a9b31b 468 HashedResourceData *hashed_process_data = NULL;
9e01e6d4 469 ProcessList *process_list = control_flow_data->process_list;
58a9b31b 470// LttTime birth = process->creation_time;
9e01e6d4 471
58a9b31b 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);
9e01e6d4 478 if(hashed_process_data == NULL)
479 {
58a9b31b 480// g_assert(pid_out == 0 || pid_out != process->ppid);
9e01e6d4 481 /* Process not present */
58a9b31b 482 ResourceInfo *process_info;
9e01e6d4 483 Drawing_t *drawing = control_flow_data->drawing;
c4e6f4dc 484 resourcelist_add(process_list,
9e01e6d4 485 drawing,
58a9b31b 486 trace_num,
487 cpuq, //process->name,
44ffb95f 488 0, //cpu
489 cpu,
9e01e6d4 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
9e01e6d4 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 */
58a9b31b 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;
d3d99fde 593 cpu_set_line_color(&prop_line, tfs->cpu_state);
9e01e6d4 594 draw_line((void*)&prop_line, (void*)&draw_context);
9e01e6d4 595
58a9b31b 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;
9e01e6d4 601
58a9b31b 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;
9e01e6d4 779
9e01e6d4 780
9e01e6d4 781
9e01e6d4 782
58a9b31b 783 /* Text dump */
784#ifdef DONTSHOW
785 GString *string = g_string_new("");;
786 gboolean field_names = TRUE, state = TRUE;
9e01e6d4 787
58a9b31b 788 lttv_event_to_string(e, tfc->tf, string, TRUE, field_names, tfs);
789 g_string_append_printf(string,"\n");
9e01e6d4 790
58a9b31b 791 if(state) {
792 g_string_append_printf(string, " %s",
793 g_quark_to_string(tfs->process->state->s));
9e01e6d4 794 }
795
58a9b31b 796 g_info("%s",string->str);
9e01e6d4 797
58a9b31b 798 g_string_free(string, TRUE);
799
800 /* End of text dump */
801#endif //DONTSHOW
9e01e6d4 802
803}
804
58a9b31b 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 */
815int after_schedchange_hook(void *hook_data, void *call_data)
9e01e6d4 816{
dd455fb8 817 LttvTraceHook *th = (LttvTraceHook*)hook_data;
818 EventsRequest *events_request = (EventsRequest*)th->hook_data;
44ffb95f 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;
dd455fb8 851 pid_out = ltt_event_get_long_unsigned(e, th->f1);
852 pid_in = ltt_event_get_long_unsigned(e, th->f2);
44ffb95f 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 }
58a9b31b 931 return 0;
932}
9e01e6d4 933
58a9b31b 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 */
9e01e6d4 950
598026ba 951int before_execmode_hook(void *hook_data, void *call_data)
952{
dd455fb8 953 LttvTraceHook *th = (LttvTraceHook*)hook_data;
954 EventsRequest *events_request = (EventsRequest*)th->hook_data;
598026ba 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
8743690d 969 before_execmode_hook_irq(hook_data, call_data);
970
598026ba 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
58a9b31b 988// guint pid = process->pid;
598026ba 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;
d3d99fde 1014 resourcelist_add(process_list,
598026ba 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 }
d3d99fde 1066 }
1067 else {
598026ba 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 */
d3d99fde 1101 }
1102 else {
598026ba 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;
d3d99fde 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);
598026ba 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}
9e01e6d4 1146
8743690d 1147int before_execmode_hook_irq(void *hook_data, void *call_data)
1148{
dd455fb8 1149 LttvTraceHook *th = (LttvTraceHook*)hook_data;
1150 EventsRequest *events_request = (EventsRequest*)th->hook_data;
8743690d 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 GQuark resourceq;
1164
1165 /* we are in a execmode, before the state update. We must draw the
1166 * items corresponding to the state before it changes : now is the right
1167 * time to do it.
1168 */
1169 /* For the pid */
1170
1171 guint64 irq;
1172 guint cpu = tfs->cpu;
1173
1174 LttFacility *ev_facility = ltt_event_facility(e);
1175 if(ltt_facility_name(ev_facility) != LTT_FACILITY_KERNEL)
1176 return 0;
1177 guint8 ev_id_entry = ltt_eventtype_id(ltt_facility_eventtype_get_by_name(ev_facility, LTT_EVENT_IRQ_ENTRY));
1178 guint8 ev_id_exit = ltt_eventtype_id(ltt_facility_eventtype_get_by_name(ev_facility, LTT_EVENT_IRQ_EXIT));
1179 if(ltt_facility_name(ev_facility) == LTT_FACILITY_KERNEL &&
1180 ev_id_entry == ltt_event_eventtype_id(e)) {
dd455fb8 1181 irq = ltt_event_get_long_unsigned(e, th->f1);
8743690d 1182 }
1183 else if(ltt_facility_name(ev_facility) == LTT_FACILITY_KERNEL &&
1184 ev_id_exit == ltt_event_eventtype_id(e)) {
1185 irq = ts->cpu_states[cpu].last_irq;
1186 }
1187 else {
1188 return 0;
1189 }
1190
1191 {
1192 gchar *irqstr;
a53e6234 1193 irqstr = g_strdup_printf("IRQ %llu [%s]", irq, g_quark_to_string(ts->irq_names[irq]));
8743690d 1194 resourceq = g_quark_from_string(irqstr);
1195 g_free(irqstr);
1196 }
1197 guint trace_num = ts->parent.index;
1198
1199// guint pid = process->pid;
1200
1201 /* Well, the process_out existed : we must get it in the process hash
1202 * or add it, and draw its items.
1203 */
1204 /* Add process to process list (if not present) */
1205 guint pl_height = 0;
1206 HashedResourceData *hashed_process_data = NULL;
1207 ProcessList *process_list = control_flow_data->process_list;
1208// LttTime birth = process->creation_time;
1209
1210// if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1211// hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1212// } else {
1213 hashed_process_data = processlist_get_process_data(process_list, resourceq, trace_num);
1214// hashed_process_data = processlist_get_process_data(process_list,
1215// pid,
1216// process->cpu,
1217// &birth,
1218// trace_num);
1219 if(unlikely(hashed_process_data == NULL))
1220 {
1221 //g_assert(pid == 0 || pid != process->ppid);
1222 ResourceInfo *process_info;
1223 /* Process not present */
1224 Drawing_t *drawing = control_flow_data->drawing;
1225 resourcelist_add(process_list,
1226 drawing,
1227 trace_num,
1228 resourceq, //process->name,
1229 1, //irq
1230 irq,
1231 &pl_height,
1232 &process_info,
1233 &hashed_process_data);
1234 gtk_widget_set_size_request(drawing->drawing_area,
1235 -1,
1236 pl_height);
1237 gtk_widget_queue_draw(drawing->drawing_area);
1238 }
1239 /* Set the current process */
1240// process_list->current_hash_data[trace_num][process->cpu] =
1241// hashed_process_data;
1242// }
1243
1244 /* Now, the process is in the state hash and our own process hash.
1245 * We definitely can draw the items related to the ending state.
1246 */
1247
1248 if(likely(ltt_time_compare(hashed_process_data->next_good_time,
1249 evtime) > 0))
1250 {
1251 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1252 TimeWindow time_window =
1253 lttvwindow_get_time_window(control_flow_data->tab);
1254
1255#ifdef EXTRA_CHECK
1256 if(ltt_time_compare(evtime, time_window.start_time) == -1
1257 || ltt_time_compare(evtime, time_window.end_time) == 1)
1258 return;
1259#endif //EXTRA_CHECK
1260 Drawing_t *drawing = control_flow_data->drawing;
1261 guint width = drawing->width;
1262 guint x;
1263 convert_time_to_pixels(
1264 time_window,
1265 evtime,
1266 width,
1267 &x);
1268
1269 /* Draw collision indicator */
1270 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1271 gdk_draw_point(hashed_process_data->pixmap,
1272 drawing->gc,
1273 x,
1274 COLLISION_POSITION(hashed_process_data->height));
1275 hashed_process_data->x.middle_marked = TRUE;
1276 }
1277 }
1278 else {
1279 TimeWindow time_window =
1280 lttvwindow_get_time_window(control_flow_data->tab);
1281
1282#ifdef EXTRA_CHECK
1283 if(ltt_time_compare(evtime, time_window.start_time) == -1
1284 || ltt_time_compare(evtime, time_window.end_time) == 1)
1285 return;
1286#endif //EXTRA_CHECK
1287 Drawing_t *drawing = control_flow_data->drawing;
1288 guint width = drawing->width;
1289 guint x;
1290
1291 convert_time_to_pixels(
1292 time_window,
1293 evtime,
1294 width,
1295 &x);
1296
1297
1298 /* Jump over draw if we are at the same x position */
1299 if(unlikely(x == hashed_process_data->x.middle &&
1300 hashed_process_data->x.middle_used))
1301 {
1302 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1303 /* Draw collision indicator */
1304 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1305 gdk_draw_point(hashed_process_data->pixmap,
1306 drawing->gc,
1307 x,
1308 COLLISION_POSITION(hashed_process_data->height));
1309 hashed_process_data->x.middle_marked = TRUE;
1310 }
1311 /* jump */
1312 }
1313 else {
1314
1315 DrawContext draw_context;
1316 /* Now create the drawing context that will be used to draw
1317 * items related to the last state. */
1318 draw_context.drawable = hashed_process_data->pixmap;
1319 draw_context.gc = drawing->gc;
1320 draw_context.pango_layout = drawing->pango_layout;
1321 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
1322 draw_context.drawinfo.end.x = x;
1323
1324 draw_context.drawinfo.y.over = 1;
1325 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
1326 draw_context.drawinfo.y.under = hashed_process_data->height;
1327
1328 draw_context.drawinfo.start.offset.over = 0;
1329 draw_context.drawinfo.start.offset.middle = 0;
1330 draw_context.drawinfo.start.offset.under = 0;
1331 draw_context.drawinfo.end.offset.over = 0;
1332 draw_context.drawinfo.end.offset.middle = 0;
1333 draw_context.drawinfo.end.offset.under = 0;
1334
1335 {
1336 /* Draw the line */
1337 PropertiesLine prop_line;
1338 prop_line.line_width = STATE_LINE_WIDTH;
1339 prop_line.style = GDK_LINE_SOLID;
1340 prop_line.y = MIDDLE;
1341 irq_set_line_color(&prop_line, &ts->irq_states[irq]);
1342 draw_line((void*)&prop_line, (void*)&draw_context);
1343 }
1344 /* become the last x position */
1345 hashed_process_data->x.middle = x;
1346 hashed_process_data->x.middle_used = TRUE;
1347 hashed_process_data->x.middle_marked = FALSE;
1348
1349 /* Calculate the next good time */
1350 convert_pixels_to_time(width, x+1, time_window,
1351 &hashed_process_data->next_good_time);
1352 }
1353 }
1354
1355 return 0;
1356}
1357
20d16f82 1358int before_bdev_event_hook(void *hook_data, void *call_data)
1359{
dd455fb8 1360 LttvTraceHook *th = (LttvTraceHook*)hook_data;
1361 EventsRequest *events_request = (EventsRequest*)th->hook_data;
20d16f82 1362 ControlFlowData *control_flow_data = events_request->viewer_data;
1363
1364 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1365
1366 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
1367 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
1368
1369 LttEvent *e;
1370 e = ltt_tracefile_get_event(tfc->tf);
1371
1372 LttTime evtime = ltt_event_time(e);
1373
1374 GQuark resourceq;
1375
1376 /* we are in a execmode, before the state update. We must draw the
1377 * items corresponding to the state before it changes : now is the right
1378 * time to do it.
1379 */
1380 /* For the pid */
1381
1382 guint cpu = tfs->cpu;
dd455fb8 1383 guint8 major = ltt_event_get_long_unsigned(e, th->f1);
1384 guint8 minor = ltt_event_get_long_unsigned(e, th->f2);
1385 guint oper = ltt_event_get_long_unsigned(e, th->f3);
20d16f82 1386 gint devcode_gint = MKDEV(major,minor);
1387
1388 {
1389 gchar *resourcestr;
1390 resourcestr = g_strdup_printf("Blockdev (%u,%u)", major, minor);
1391 resourceq = g_quark_from_string(resourcestr);
1392 g_free(resourcestr);
1393 }
1394 guint trace_num = ts->parent.index;
1395
1396 LttvBdevState *bdev = g_hash_table_lookup(ts->bdev_states, &devcode_gint);
23e59a12 1397 /* the result of the lookup might be NULL. that's ok, the rest of the function
1398 should understand it was not found and that its state is unknown */
20d16f82 1399
1400// guint pid = process->pid;
1401
1402 /* Well, the process_out existed : we must get it in the process hash
1403 * or add it, and draw its items.
1404 */
1405 /* Add process to process list (if not present) */
1406 guint pl_height = 0;
1407 HashedResourceData *hashed_process_data = NULL;
1408 ProcessList *process_list = control_flow_data->process_list;
1409// LttTime birth = process->creation_time;
1410
1411// if(likely(process_list->current_hash_data[trace_num][cpu] != NULL)) {
1412// hashed_process_data = process_list->current_hash_data[trace_num][cpu];
1413// } else {
1414 hashed_process_data = processlist_get_process_data(process_list, resourceq, trace_num);
1415// hashed_process_data = processlist_get_process_data(process_list,
1416// pid,
1417// process->cpu,
1418// &birth,
1419// trace_num);
1420 if(unlikely(hashed_process_data == NULL))
1421 {
1422 //g_assert(pid == 0 || pid != process->ppid);
1423 ResourceInfo *process_info;
1424 /* Process not present */
1425 Drawing_t *drawing = control_flow_data->drawing;
1426 resourcelist_add(process_list,
1427 drawing,
1428 trace_num,
1429 resourceq, //process->name,
1430 2, //block dev
1431 devcode_gint, /* MKDEV(major,minor) */
1432 &pl_height,
1433 &process_info,
1434 &hashed_process_data);
1435 gtk_widget_set_size_request(drawing->drawing_area,
1436 -1,
1437 pl_height);
1438 gtk_widget_queue_draw(drawing->drawing_area);
1439 }
1440 /* Set the current process */
1441// process_list->current_hash_data[trace_num][process->cpu] =
1442// hashed_process_data;
1443// }
1444
1445 /* Now, the process is in the state hash and our own process hash.
1446 * We definitely can draw the items related to the ending state.
1447 */
1448
1449 if(likely(ltt_time_compare(hashed_process_data->next_good_time,
1450 evtime) > 0))
1451 {
1452 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1453 TimeWindow time_window =
1454 lttvwindow_get_time_window(control_flow_data->tab);
1455
1456#ifdef EXTRA_CHECK
1457 if(ltt_time_compare(evtime, time_window.start_time) == -1
1458 || ltt_time_compare(evtime, time_window.end_time) == 1)
1459 return;
1460#endif //EXTRA_CHECK
1461 Drawing_t *drawing = control_flow_data->drawing;
1462 guint width = drawing->width;
1463 guint x;
1464 convert_time_to_pixels(
1465 time_window,
1466 evtime,
1467 width,
1468 &x);
1469
1470 /* Draw collision indicator */
1471 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1472 gdk_draw_point(hashed_process_data->pixmap,
1473 drawing->gc,
1474 x,
1475 COLLISION_POSITION(hashed_process_data->height));
1476 hashed_process_data->x.middle_marked = TRUE;
1477 }
1478 }
1479 else {
1480 TimeWindow time_window =
1481 lttvwindow_get_time_window(control_flow_data->tab);
1482
1483#ifdef EXTRA_CHECK
1484 if(ltt_time_compare(evtime, time_window.start_time) == -1
1485 || ltt_time_compare(evtime, time_window.end_time) == 1)
1486 return;
1487#endif //EXTRA_CHECK
1488 Drawing_t *drawing = control_flow_data->drawing;
1489 guint width = drawing->width;
1490 guint x;
1491
1492 convert_time_to_pixels(
1493 time_window,
1494 evtime,
1495 width,
1496 &x);
1497
1498
1499 /* Jump over draw if we are at the same x position */
1500 if(unlikely(x == hashed_process_data->x.middle &&
1501 hashed_process_data->x.middle_used))
1502 {
1503 if(unlikely(hashed_process_data->x.middle_marked == FALSE)) {
1504 /* Draw collision indicator */
1505 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
1506 gdk_draw_point(hashed_process_data->pixmap,
1507 drawing->gc,
1508 x,
1509 COLLISION_POSITION(hashed_process_data->height));
1510 hashed_process_data->x.middle_marked = TRUE;
1511 }
1512 /* jump */
1513 }
1514 else {
1515
1516 DrawContext draw_context;
1517 /* Now create the drawing context that will be used to draw
1518 * items related to the last state. */
1519 draw_context.drawable = hashed_process_data->pixmap;
1520 draw_context.gc = drawing->gc;
1521 draw_context.pango_layout = drawing->pango_layout;
1522 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
1523 draw_context.drawinfo.end.x = x;
1524
1525 draw_context.drawinfo.y.over = 1;
1526 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
1527 draw_context.drawinfo.y.under = hashed_process_data->height;
1528
1529 draw_context.drawinfo.start.offset.over = 0;
1530 draw_context.drawinfo.start.offset.middle = 0;
1531 draw_context.drawinfo.start.offset.under = 0;
1532 draw_context.drawinfo.end.offset.over = 0;
1533 draw_context.drawinfo.end.offset.middle = 0;
1534 draw_context.drawinfo.end.offset.under = 0;
1535
1536 {
1537 /* Draw the line */
1538 PropertiesLine prop_line;
1539 prop_line.line_width = STATE_LINE_WIDTH;
1540 prop_line.style = GDK_LINE_SOLID;
1541 prop_line.y = MIDDLE;
1542 bdev_set_line_color(&prop_line, bdev);
1543 draw_line((void*)&prop_line, (void*)&draw_context);
1544 }
1545 /* become the last x position */
1546 hashed_process_data->x.middle = x;
1547 hashed_process_data->x.middle_used = TRUE;
1548 hashed_process_data->x.middle_marked = FALSE;
1549
1550 /* Calculate the next good time */
1551 convert_pixels_to_time(width, x+1, time_window,
1552 &hashed_process_data->next_good_time);
1553 }
1554 }
1555
1556 return 0;
1557}
1558
9e01e6d4 1559gint update_time_window_hook(void *hook_data, void *call_data)
1560{
1561 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
1562 Drawing_t *drawing = control_flow_data->drawing;
1563 ProcessList *process_list = control_flow_data->process_list;
1564
1565 const TimeWindowNotifyData *time_window_nofify_data =
1566 ((const TimeWindowNotifyData *)call_data);
1567
1568 TimeWindow *old_time_window =
1569 time_window_nofify_data->old_time_window;
1570 TimeWindow *new_time_window =
1571 time_window_nofify_data->new_time_window;
1572
1573 /* Update the ruler */
1574 drawing_update_ruler(control_flow_data->drawing,
1575 new_time_window);
1576
1577
1578 /* Two cases : zoom in/out or scrolling */
1579
1580 /* In order to make sure we can reuse the old drawing, the scale must
1581 * be the same and the new time interval being partly located in the
1582 * currently shown time interval. (reuse is only for scrolling)
1583 */
1584
1585 g_info("Old time window HOOK : %lu, %lu to %lu, %lu",
1586 old_time_window->start_time.tv_sec,
1587 old_time_window->start_time.tv_nsec,
1588 old_time_window->time_width.tv_sec,
1589 old_time_window->time_width.tv_nsec);
1590
1591 g_info("New time window HOOK : %lu, %lu to %lu, %lu",
1592 new_time_window->start_time.tv_sec,
1593 new_time_window->start_time.tv_nsec,
1594 new_time_window->time_width.tv_sec,
1595 new_time_window->time_width.tv_nsec);
1596
1597 if( new_time_window->time_width.tv_sec == old_time_window->time_width.tv_sec
1598 && new_time_window->time_width.tv_nsec == old_time_window->time_width.tv_nsec)
1599 {
1600 /* Same scale (scrolling) */
1601 g_info("scrolling");
1602 LttTime *ns = &new_time_window->start_time;
1603 LttTime *nw = &new_time_window->time_width;
1604 LttTime *os = &old_time_window->start_time;
1605 LttTime *ow = &old_time_window->time_width;
1606 LttTime old_end = old_time_window->end_time;
1607 LttTime new_end = new_time_window->end_time;
1608 //if(ns<os+w<ns+w)
1609 //if(ns<os+w && os+w<ns+w)
1610 //if(ns<old_end && os<ns)
1611 if(ltt_time_compare(*ns, old_end) == -1
1612 && ltt_time_compare(*os, *ns) == -1)
1613 {
1614 g_info("scrolling near right");
1615 /* Scroll right, keep right part of the screen */
1616 guint x = 0;
1617 guint width = control_flow_data->drawing->width;
1618 convert_time_to_pixels(
1619 *old_time_window,
1620 *ns,
1621 width,
1622 &x);
1623
1624 /* Copy old data to new location */
1625 copy_pixmap_region(process_list,
1626 NULL,
1627 control_flow_data->drawing->drawing_area->style->black_gc,
1628 NULL,
1629 x, 0,
1630 0, 0,
1631 control_flow_data->drawing->width-x+SAFETY, -1);
1632
1633 if(drawing->damage_begin == drawing->damage_end)
1634 drawing->damage_begin = control_flow_data->drawing->width-x;
1635 else
1636 drawing->damage_begin = 0;
1637
1638 drawing->damage_end = control_flow_data->drawing->width;
1639
1640 /* Clear the data request background, but not SAFETY */
1641 rectangle_pixmap(process_list,
1642 control_flow_data->drawing->drawing_area->style->black_gc,
1643 TRUE,
1644 drawing->damage_begin+SAFETY, 0,
1645 drawing->damage_end - drawing->damage_begin, // do not overlap
1646 -1);
1647 gtk_widget_queue_draw(drawing->drawing_area);
1648 //gtk_widget_queue_draw_area (drawing->drawing_area,
1649 // 0,0,
1650 // control_flow_data->drawing->width,
1651 // control_flow_data->drawing->height);
1652
1653 /* Get new data for the rest. */
1654 drawing_data_request(control_flow_data->drawing,
1655 drawing->damage_begin, 0,
1656 drawing->damage_end - drawing->damage_begin,
1657 control_flow_data->drawing->height);
1658 } else {
1659 //if(ns<os<ns+w)
1660 //if(ns<os && os<ns+w)
1661 //if(ns<os && os<new_end)
1662 if(ltt_time_compare(*ns,*os) == -1
1663 && ltt_time_compare(*os,new_end) == -1)
1664 {
1665 g_info("scrolling near left");
1666 /* Scroll left, keep left part of the screen */
1667 guint x = 0;
1668 guint width = control_flow_data->drawing->width;
1669 convert_time_to_pixels(
1670 *new_time_window,
1671 *os,
1672 width,
1673 &x);
1674
1675 /* Copy old data to new location */
1676 copy_pixmap_region (process_list,
1677 NULL,
1678 control_flow_data->drawing->drawing_area->style->black_gc,
1679 NULL,
1680 0, 0,
1681 x, 0,
1682 -1, -1);
1683
1684 if(drawing->damage_begin == drawing->damage_end)
1685 drawing->damage_end = x;
1686 else
1687 drawing->damage_end =
1688 control_flow_data->drawing->width;
1689
1690 drawing->damage_begin = 0;
1691
1692 rectangle_pixmap (process_list,
1693 control_flow_data->drawing->drawing_area->style->black_gc,
1694 TRUE,
1695 drawing->damage_begin, 0,
1696 drawing->damage_end - drawing->damage_begin, // do not overlap
1697 -1);
1698
1699 gtk_widget_queue_draw(drawing->drawing_area);
1700 //gtk_widget_queue_draw_area (drawing->drawing_area,
1701 // 0,0,
1702 // control_flow_data->drawing->width,
1703 // control_flow_data->drawing->height);
1704
1705
1706 /* Get new data for the rest. */
1707 drawing_data_request(control_flow_data->drawing,
1708 drawing->damage_begin, 0,
1709 drawing->damage_end - drawing->damage_begin,
1710 control_flow_data->drawing->height);
1711
1712 } else {
1713 if(ltt_time_compare(*ns,*os) == 0)
1714 {
1715 g_info("not scrolling");
1716 } else {
1717 g_info("scrolling far");
1718 /* Cannot reuse any part of the screen : far jump */
1719
1720
1721 rectangle_pixmap (process_list,
1722 control_flow_data->drawing->drawing_area->style->black_gc,
1723 TRUE,
1724 0, 0,
1725 control_flow_data->drawing->width+SAFETY, // do not overlap
1726 -1);
1727
1728 //gtk_widget_queue_draw_area (drawing->drawing_area,
1729 // 0,0,
1730 // control_flow_data->drawing->width,
1731 // control_flow_data->drawing->height);
1732 gtk_widget_queue_draw(drawing->drawing_area);
1733
1734 drawing->damage_begin = 0;
1735 drawing->damage_end = control_flow_data->drawing->width;
1736
1737 drawing_data_request(control_flow_data->drawing,
1738 0, 0,
1739 control_flow_data->drawing->width,
1740 control_flow_data->drawing->height);
1741
1742 }
1743 }
1744 }
1745 } else {
1746 /* Different scale (zoom) */
1747 g_info("zoom");
1748
1749 rectangle_pixmap (process_list,
1750 control_flow_data->drawing->drawing_area->style->black_gc,
1751 TRUE,
1752 0, 0,
1753 control_flow_data->drawing->width+SAFETY, // do not overlap
1754 -1);
1755
1756 //gtk_widget_queue_draw_area (drawing->drawing_area,
1757 // 0,0,
1758 // control_flow_data->drawing->width,
1759 // control_flow_data->drawing->height);
1760 gtk_widget_queue_draw(drawing->drawing_area);
1761
1762 drawing->damage_begin = 0;
1763 drawing->damage_end = control_flow_data->drawing->width;
1764
1765 drawing_data_request(control_flow_data->drawing,
1766 0, 0,
1767 control_flow_data->drawing->width,
1768 control_flow_data->drawing->height);
1769 }
1770
1771 /* Update directly when scrolling */
1772 gdk_window_process_updates(control_flow_data->drawing->drawing_area->window,
1773 TRUE);
1774
1775 return 0;
1776}
1777
1778gint traceset_notify(void *hook_data, void *call_data)
1779{
1780 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
1781 Drawing_t *drawing = control_flow_data->drawing;
1782
1783 if(unlikely(drawing->gc == NULL)) {
1784 return FALSE;
1785 }
1786 if(drawing->dotted_gc == NULL) {
1787 return FALSE;
1788 }
1789
1790 drawing_clear(control_flow_data->drawing);
1791 processlist_clear(control_flow_data->process_list);
1792 gtk_widget_set_size_request(
1793 control_flow_data->drawing->drawing_area,
1794 -1, processlist_get_height(control_flow_data->process_list));
1795 redraw_notify(control_flow_data, NULL);
1796
1797 request_background_data(control_flow_data);
1798
1799 return FALSE;
1800}
1801
1802gint redraw_notify(void *hook_data, void *call_data)
1803{
1804 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
1805 Drawing_t *drawing = control_flow_data->drawing;
1806 GtkWidget *widget = drawing->drawing_area;
1807
1808 drawing->damage_begin = 0;
1809 drawing->damage_end = drawing->width;
1810
1811 /* fun feature, to be separated someday... */
1812 drawing_clear(control_flow_data->drawing);
1813 processlist_clear(control_flow_data->process_list);
1814 gtk_widget_set_size_request(
1815 control_flow_data->drawing->drawing_area,
1816 -1, processlist_get_height(control_flow_data->process_list));
1817 // Clear the images
1818 rectangle_pixmap (control_flow_data->process_list,
1819 widget->style->black_gc,
1820 TRUE,
1821 0, 0,
1822 drawing->alloc_width,
1823 -1);
1824
1825 gtk_widget_queue_draw(drawing->drawing_area);
1826
1827 if(drawing->damage_begin < drawing->damage_end)
1828 {
1829 drawing_data_request(drawing,
1830 drawing->damage_begin,
1831 0,
1832 drawing->damage_end-drawing->damage_begin,
1833 drawing->height);
1834 }
1835
1836 //gtk_widget_queue_draw_area(drawing->drawing_area,
1837 // 0,0,
1838 // drawing->width,
1839 // drawing->height);
1840 return FALSE;
1841
1842}
1843
1844
1845gint continue_notify(void *hook_data, void *call_data)
1846{
1847 ControlFlowData *control_flow_data = (ControlFlowData*) hook_data;
1848 Drawing_t *drawing = control_flow_data->drawing;
1849
1850 //g_assert(widget->allocation.width == drawing->damage_end);
1851
1852 if(drawing->damage_begin < drawing->damage_end)
1853 {
1854 drawing_data_request(drawing,
1855 drawing->damage_begin,
1856 0,
1857 drawing->damage_end-drawing->damage_begin,
1858 drawing->height);
1859 }
1860
1861 return FALSE;
1862}
1863
1864
1865gint update_current_time_hook(void *hook_data, void *call_data)
1866{
1867 ControlFlowData *control_flow_data = (ControlFlowData*)hook_data;
1868 Drawing_t *drawing = control_flow_data->drawing;
1869
1870 LttTime current_time = *((LttTime*)call_data);
1871
1872 TimeWindow time_window =
1873 lttvwindow_get_time_window(control_flow_data->tab);
1874
1875 LttTime time_begin = time_window.start_time;
1876 LttTime width = time_window.time_width;
1877 LttTime half_width;
1878 {
1879 guint64 time_ll = ltt_time_to_uint64(width);
1880 time_ll = time_ll >> 1; /* divide by two */
1881 half_width = ltt_time_from_uint64(time_ll);
1882 }
1883 LttTime time_end = ltt_time_add(time_begin, width);
1884
1885 LttvTracesetContext * tsc =
1886 lttvwindow_get_traceset_context(control_flow_data->tab);
1887
1888 LttTime trace_start = tsc->time_span.start_time;
1889 LttTime trace_end = tsc->time_span.end_time;
1890
1891 g_info("New current time HOOK : %lu, %lu", current_time.tv_sec,
1892 current_time.tv_nsec);
1893
1894
1895
1896 /* If current time is inside time interval, just move the highlight
1897 * bar */
1898
1899 /* Else, we have to change the time interval. We have to tell it
1900 * to the main window. */
1901 /* The time interval change will take care of placing the current
1902 * time at the center of the visible area, or nearest possible if we are
1903 * at one end of the trace. */
1904
1905
1906 if(ltt_time_compare(current_time, time_begin) < 0)
1907 {
1908 TimeWindow new_time_window;
1909
1910 if(ltt_time_compare(current_time,
1911 ltt_time_add(trace_start,half_width)) < 0)
1912 time_begin = trace_start;
1913 else
1914 time_begin = ltt_time_sub(current_time,half_width);
1915
1916 new_time_window.start_time = time_begin;
1917 new_time_window.time_width = width;
1918 new_time_window.time_width_double = ltt_time_to_double(width);
1919 new_time_window.end_time = ltt_time_add(time_begin, width);
1920
1921 lttvwindow_report_time_window(control_flow_data->tab, new_time_window);
1922 }
1923 else if(ltt_time_compare(current_time, time_end) > 0)
1924 {
1925 TimeWindow new_time_window;
1926
1927 if(ltt_time_compare(current_time, ltt_time_sub(trace_end, half_width)) > 0)
1928 time_begin = ltt_time_sub(trace_end,width);
1929 else
1930 time_begin = ltt_time_sub(current_time,half_width);
1931
1932 new_time_window.start_time = time_begin;
1933 new_time_window.time_width = width;
1934 new_time_window.time_width_double = ltt_time_to_double(width);
1935 new_time_window.end_time = ltt_time_add(time_begin, width);
1936
1937 lttvwindow_report_time_window(control_flow_data->tab, new_time_window);
1938
1939 }
1940 gtk_widget_queue_draw(control_flow_data->drawing->drawing_area);
1941
1942 /* Update directly when scrolling */
1943 gdk_window_process_updates(control_flow_data->drawing->drawing_area->window,
1944 TRUE);
1945
1946 return 0;
1947}
1948
1949typedef struct _ClosureData {
1950 EventsRequest *events_request;
1951 LttvTracesetState *tss;
1952 LttTime end_time;
1953 guint x_end;
1954} ClosureData;
1955
58a9b31b 1956/* Draw line until end of the screen */
9e01e6d4 1957
1958void draw_closure(gpointer key, gpointer value, gpointer user_data)
1959{
44ffb95f 1960 ResourceInfo *process_info = (ResourceInfo*)key;
1961 HashedResourceData *hashed_process_data = (HashedResourceData*)value;
1962 ClosureData *closure_data = (ClosureData*)user_data;
1963
1964 EventsRequest *events_request = closure_data->events_request;
1965 ControlFlowData *control_flow_data = events_request->viewer_data;
1966
1967 LttvTracesetState *tss = closure_data->tss;
1968 LttvTracesetContext *tsc = (LttvTracesetContext*)tss;
1969
1970 LttTime evtime = closure_data->end_time;
1971
1972 gboolean dodraw = TRUE;
1973
1974 {
1975 /* For the process */
1976 /* First, check if the current process is in the state computation
1977 * process list. If it is there, that means we must add it right now and
1978 * draw items from the beginning of the read for it. If it is not
1979 * present, it's a new process and it was not present : it will
1980 * be added after the state update. */
1981#ifdef EXTRA_CHECK
1982 g_assert(lttv_traceset_number(tsc->ts) > 0);
1983#endif //EXTRA_CHECK
1984 LttvTraceContext *tc = tsc->traces[process_info->trace_num];
1985 LttvTraceState *ts = (LttvTraceState*)tc;
1986
1987#if 0
1988 //FIXME : optimize data structures.
1989 LttvTracefileState *tfs;
1990 LttvTracefileContext *tfc;
1991 guint i;
1992 for(i=0;i<tc->tracefiles->len;i++) {
1993 tfc = g_array_index(tc->tracefiles, LttvTracefileContext*, i);
1994 if(ltt_tracefile_name(tfc->tf) == LTT_NAME_CPU
1995 && tfs->cpu == process_info->cpu)
1996 break;
1997
1998 }
1999 g_assert(i<tc->tracefiles->len);
2000 tfs = LTTV_TRACEFILE_STATE(tfc);
2001#endif //0
2002 // LttvTracefileState *tfs =
2003 // (LttvTracefileState*)tsc->traces[process_info->trace_num]->
2004 // tracefiles[process_info->cpu];
2005
58a9b31b 2006// LttvProcessState *process;
2007// process = lttv_state_find_process(ts, process_info->cpu,
2008// process_info->pid);
44ffb95f 2009
58a9b31b 2010// if(unlikely(process != NULL)) {
44ffb95f 2011
58a9b31b 2012// LttvFilter *filter = control_flow_data->filter;
2013// if(filter != NULL && filter->head != NULL)
2014// if(!lttv_filter_tree_parse(filter->head,NULL,NULL,
2015// tc->t,NULL,process,tc))
2016// dodraw = FALSE;
44ffb95f 2017
2018 /* Only draw for processes that are currently in the trace states */
2019
2020 ProcessList *process_list = control_flow_data->process_list;
2021#ifdef EXTRA_CHECK
2022 /* Should be alike when background info is ready */
2023 if(control_flow_data->background_info_waiting==0)
2024 g_assert(ltt_time_compare(process->creation_time,
2025 process_info->birth) == 0);
2026#endif //EXTRA_CHECK
2027
2028 /* Now, the process is in the state hash and our own process hash.
2029 * We definitely can draw the items related to the ending state.
2030 */
2031
2032 if(unlikely(ltt_time_compare(hashed_process_data->next_good_time,
2033 evtime) <= 0))
2034 {
2035 TimeWindow time_window =
2036 lttvwindow_get_time_window(control_flow_data->tab);
2037
2038#ifdef EXTRA_CHECK
2039 if(ltt_time_compare(evtime, time_window.start_time) == -1
2040 || ltt_time_compare(evtime, time_window.end_time) == 1)
2041 return;
2042#endif //EXTRA_CHECK
2043 Drawing_t *drawing = control_flow_data->drawing;
2044 guint width = drawing->width;
2045
2046 guint x = closure_data->x_end;
2047
2048 DrawContext draw_context;
2049
2050 /* Now create the drawing context that will be used to draw
2051 * items related to the last state. */
2052 draw_context.drawable = hashed_process_data->pixmap;
2053 draw_context.gc = drawing->gc;
2054 draw_context.pango_layout = drawing->pango_layout;
2055 draw_context.drawinfo.end.x = x;
2056
2057 draw_context.drawinfo.y.over = 1;
2058 draw_context.drawinfo.y.middle = (hashed_process_data->height/2);
2059 draw_context.drawinfo.y.under = hashed_process_data->height;
2060
2061 draw_context.drawinfo.start.offset.over = 0;
2062 draw_context.drawinfo.start.offset.middle = 0;
2063 draw_context.drawinfo.start.offset.under = 0;
2064 draw_context.drawinfo.end.offset.over = 0;
2065 draw_context.drawinfo.end.offset.middle = 0;
2066 draw_context.drawinfo.end.offset.under = 0;
2067#if 0
2068 /* Jump over draw if we are at the same x position */
2069 if(x == hashed_process_data->x.over)
2070 {
2071 /* jump */
2072 } else {
2073 draw_context.drawinfo.start.x = hashed_process_data->x.over;
2074 /* Draw the line */
2075 PropertiesLine prop_line = prepare_execmode_line(process);
2076 draw_line((void*)&prop_line, (void*)&draw_context);
2077
2078 hashed_process_data->x.over = x;
2079 }
2080#endif //0
2081
2082 if(unlikely(x == hashed_process_data->x.middle &&
2083 hashed_process_data->x.middle_used)) {
2084#if 0 /* do not mark closure : not missing information */
2085 if(hashed_process_data->x.middle_marked == FALSE) {
2086 /* Draw collision indicator */
2087 gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]);
2088 gdk_draw_point(drawing->pixmap,
2089 drawing->gc,
2090 x,
2091 y+(height/2)-3);
2092 hashed_process_data->x.middle_marked = TRUE;
2093 }
2094#endif //0
2095 /* Jump */
2096 } else {
2097 draw_context.drawinfo.start.x = hashed_process_data->x.middle;
2098 /* Draw the line */
2099 if(dodraw) {
44ffb95f 2100 PropertiesLine prop_line;
2101 prop_line.line_width = STATE_LINE_WIDTH;
2102 prop_line.style = GDK_LINE_SOLID;
2103 prop_line.y = MIDDLE;
8743690d 2104 if(process_info->type == 0)
2105 cpu_set_line_color(&prop_line, &ts->cpu_states[process_info->id]);
2106 else if(process_info->type == 1)
2107 irq_set_line_color(&prop_line, &ts->irq_states[process_info->id]);
20d16f82 2108 else if(process_info->type == 2) {
2109 gint devcode_gint = process_info->id;
23e59a12 2110 LttvBdevState *bdev = g_hash_table_lookup(ts->bdev_states, &devcode_gint);
2111 // the lookup may return null; bdev_set_line_color must act appropriately
20d16f82 2112 bdev_set_line_color(&prop_line, bdev);
2113 }
44ffb95f 2114
2115 draw_line((void*)&prop_line, (void*)&draw_context);
2116 }
2117
2118 /* become the last x position */
2119 if(likely(x != hashed_process_data->x.middle)) {
2120 hashed_process_data->x.middle = x;
2121 /* but don't use the pixel */
2122 hashed_process_data->x.middle_used = FALSE;
2123
2124 /* Calculate the next good time */
2125 convert_pixels_to_time(width, x+1, time_window,
2126 &hashed_process_data->next_good_time);
2127 }
2128 }
2129 }
58a9b31b 2130// }
44ffb95f 2131 }
9e01e6d4 2132 return;
2133}
2134
2135int before_chunk(void *hook_data, void *call_data)
2136{
2137 EventsRequest *events_request = (EventsRequest*)hook_data;
2138 LttvTracesetState *tss = (LttvTracesetState*)call_data;
2139 ControlFlowData *cfd = (ControlFlowData*)events_request->viewer_data;
2140#if 0
2141 /* Desactivate sort */
2142 gtk_tree_sortable_set_sort_column_id(
2143 GTK_TREE_SORTABLE(cfd->process_list->list_store),
2144 TRACE_COLUMN,
2145 GTK_SORT_ASCENDING);
2146#endif //0
2147 drawing_chunk_begin(events_request, tss);
2148
2149 return 0;
2150}
2151
2152int before_request(void *hook_data, void *call_data)
2153{
2154 EventsRequest *events_request = (EventsRequest*)hook_data;
2155 LttvTracesetState *tss = (LttvTracesetState*)call_data;
2156
2157 drawing_data_request_begin(events_request, tss);
2158
2159 return 0;
2160}
2161
2162
2163/*
2164 * after request is necessary in addition of after chunk in order to draw
2165 * lines until the end of the screen. after chunk just draws lines until
2166 * the last event.
2167 *
2168 * for each process
2169 * draw closing line
2170 * expose
2171 */
58a9b31b 2172// TODO pmf: reenable this
9e01e6d4 2173int after_request(void *hook_data, void *call_data)
2174{
58a9b31b 2175// EventsRequest *events_request = (EventsRequest*)hook_data;
2176// ControlFlowData *control_flow_data = events_request->viewer_data;
2177// LttvTracesetState *tss = (LttvTracesetState*)call_data;
2178//
2179// ProcessList *process_list = control_flow_data->process_list;
2180// LttTime end_time = events_request->end_time;
2181//
2182// ClosureData closure_data;
2183// closure_data.events_request = (EventsRequest*)hook_data;
2184// closure_data.tss = tss;
2185// closure_data.end_time = end_time;
2186//
2187// TimeWindow time_window =
2188// lttvwindow_get_time_window(control_flow_data->tab);
2189// guint width = control_flow_data->drawing->width;
2190// convert_time_to_pixels(
2191// time_window,
2192// end_time,
2193// width,
2194// &closure_data.x_end);
2195//
2196//
2197// /* Draw last items */
2198// g_hash_table_foreach(process_list->process_hash, draw_closure,
2199// (void*)&closure_data);
2200//
2201//
2202// /* Request expose */
2203// drawing_request_expose(events_request, tss, end_time);
9e01e6d4 2204 return 0;
2205}
2206
2207/*
2208 * for each process
2209 * draw closing line
2210 * expose
2211 */
2212int after_chunk(void *hook_data, void *call_data)
2213{
2214 EventsRequest *events_request = (EventsRequest*)hook_data;
2215 ControlFlowData *control_flow_data = events_request->viewer_data;
2216 LttvTracesetState *tss = (LttvTracesetState*)call_data;
2217 LttvTracesetContext *tsc = (LttvTracesetContext*)call_data;
2218 LttvTracefileContext *tfc = lttv_traceset_context_get_current_tfc(tsc);
2219 LttTime end_time;
2220
2221 ProcessList *process_list = control_flow_data->process_list;
2222 guint i;
2223 LttvTraceset *traceset = tsc->ts;
2224 guint nb_trace = lttv_traceset_number(traceset);
2225
2226 /* Only execute when called for the first trace's events request */
2227 if(!process_list->current_hash_data) return;
2228
2229 for(i = 0 ; i < nb_trace ; i++) {
2230 g_free(process_list->current_hash_data[i]);
2231 }
2232 g_free(process_list->current_hash_data);
2233 process_list->current_hash_data = NULL;
2234
2235 if(tfc != NULL)
2236 end_time = LTT_TIME_MIN(tfc->timestamp, events_request->end_time);
2237 else /* end of traceset, or position now out of request : end */
2238 end_time = events_request->end_time;
2239
2240 ClosureData closure_data;
2241 closure_data.events_request = (EventsRequest*)hook_data;
2242 closure_data.tss = tss;
2243 closure_data.end_time = end_time;
2244
2245 TimeWindow time_window =
2246 lttvwindow_get_time_window(control_flow_data->tab);
2247 guint width = control_flow_data->drawing->width;
2248 convert_time_to_pixels(
2249 time_window,
2250 end_time,
2251 width,
2252 &closure_data.x_end);
2253
2254 /* Draw last items */
2255 g_hash_table_foreach(process_list->process_hash, draw_closure,
2256 (void*)&closure_data);
2257#if 0
2258 /* Reactivate sort */
2259 gtk_tree_sortable_set_sort_column_id(
2260 GTK_TREE_SORTABLE(control_flow_data->process_list->list_store),
2261 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
2262 GTK_SORT_ASCENDING);
2263
2264 update_index_to_pixmap(control_flow_data->process_list);
2265 /* Request a full expose : drawing scrambled */
2266 gtk_widget_queue_draw(control_flow_data->drawing->drawing_area);
2267#endif //0
2268 /* Request expose (updates damages zone also) */
2269 drawing_request_expose(events_request, tss, end_time);
2270
2271 return 0;
2272}
2273
2274/* after_statedump_end
2275 *
2276 * @param hook_data ControlFlowData structure of the viewer.
2277 * @param call_data Event context.
2278 *
2279 * This function adds items to be drawn in a queue for each process.
2280 *
2281 */
2282int before_statedump_end(void *hook_data, void *call_data)
2283{
dd455fb8 2284 LttvTraceHook *th = (LttvTraceHook*)hook_data;
2285 EventsRequest *events_request = (EventsRequest*)th->hook_data;
9e01e6d4 2286 ControlFlowData *control_flow_data = events_request->viewer_data;
2287
2288 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
2289
2290 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
2291
2292 LttvTraceState *ts = (LttvTraceState *)tfc->t_context;
2293
2294 LttvTracesetState *tss = (LttvTracesetState*)tfc->t_context->ts_context;
2295 ProcessList *process_list = control_flow_data->process_list;
2296
2297 LttEvent *e;
2298 e = ltt_tracefile_get_event(tfc->tf);
2299
2300 LttvFilter *filter = control_flow_data->filter;
2301 if(filter != NULL && filter->head != NULL)
2302 if(!lttv_filter_tree_parse(filter->head,e,tfc->tf,
2303 tfc->t_context->t,tfc,NULL,NULL))
2304 return FALSE;
2305
2306 LttTime evtime = ltt_event_time(e);
2307
2308 ClosureData closure_data;
2309 closure_data.events_request = events_request;
2310 closure_data.tss = tss;
2311 closure_data.end_time = evtime;
2312
2313 TimeWindow time_window =
2314 lttvwindow_get_time_window(control_flow_data->tab);
2315 guint width = control_flow_data->drawing->width;
2316 convert_time_to_pixels(
2317 time_window,
2318 evtime,
2319 width,
2320 &closure_data.x_end);
2321
2322 /* Draw last items */
2323 g_hash_table_foreach(process_list->process_hash, draw_closure,
2324 (void*)&closure_data);
2325#if 0
2326 /* Reactivate sort */
2327 gtk_tree_sortable_set_sort_column_id(
2328 GTK_TREE_SORTABLE(control_flow_data->process_list->list_store),
2329 GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID,
2330 GTK_SORT_ASCENDING);
2331
2332 update_index_to_pixmap(control_flow_data->process_list);
2333 /* Request a full expose : drawing scrambled */
2334 gtk_widget_queue_draw(control_flow_data->drawing->drawing_area);
2335#endif //0
2336 /* Request expose (updates damages zone also) */
2337 drawing_request_expose(events_request, tss, evtime);
2338
2339 return 0;
2340}
This page took 0.137741 seconds and 4 git commands to generate.