03d7fdf3 |
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 | *JO |
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 | #include <lttv/stats.h> |
74 | #include <lttv/xenoltt_sim.h> |
75 | |
76 | #include <lttv/filter.h> |
77 | |
78 | #include "xenoltt_eventhooks.h" |
79 | #include "xfv.h" |
80 | #include "xenoltt_threadlist.h" |
81 | #include "xenoltt_drawing.h" |
82 | |
83 | #include "TraceControlStart.xpm" |
84 | |
85 | #define MAX_PATH_LEN 256 |
86 | #define STATE_LINE_WIDTH 2 |
87 | #define COLLISION_POSITION(height) (((height - STATE_LINE_WIDTH)/2) -3) |
88 | |
89 | extern GSList *g_legend_list; |
90 | |
91 | |
92 | |
93 | |
94 | /* Action to do when background computation completed. |
95 | * |
96 | * Wait for all the awaited computations to be over. |
97 | */ |
98 | |
99 | static gint background_ready(void *hook_data, void *call_data) { |
100 | XenoLTTData *xenoltt_data = (XenoLTTData *)hook_data; |
101 | LttvTrace *trace = (LttvTrace*)call_data; |
102 | |
103 | xenoltt_data->background_info_waiting--; |
104 | |
105 | if(xenoltt_data->background_info_waiting == 0) { |
106 | g_message("xenoltt viewer : background computation data ready."); |
107 | |
108 | drawing_clear(xenoltt_data->drawing); |
109 | threadlist_clear(xenoltt_data->thread_list); |
110 | gtk_widget_set_size_request(xenoltt_data->drawing->drawing_area,-1, threadlist_get_height(xenoltt_data->thread_list)); |
111 | |
112 | redraw_notify(xenoltt_data, NULL); |
113 | |
114 | } |
115 | |
116 | return 0; |
117 | } |
118 | |
119 | |
120 | /* Request background computation. Verify if it is in progress or ready first. |
121 | * Only for each trace in the tab's traceset. |
122 | */ |
123 | static void request_background_data(XenoLTTData *xenoltt_data) { |
124 | LttvTracesetContext * tsc = lttvwindow_get_traceset_context(xenoltt_data->tab); |
125 | gint num_traces = lttv_traceset_number(tsc->ts); |
126 | gint i; |
127 | LttvTrace *trace; |
128 | LttvTraceState *tstate; |
129 | |
130 | LttvHooks *background_ready_hook = lttv_hooks_new(); |
131 | lttv_hooks_add(background_ready_hook, background_ready, xenoltt_data,LTTV_PRIO_DEFAULT); |
132 | xenoltt_data->background_info_waiting = 0; |
133 | |
134 | for(i=0;i<num_traces;i++) { |
135 | trace = lttv_traceset_get(tsc->ts, i); |
136 | tstate = LTTV_TRACE_STATE(tsc->traces[i]); |
137 | |
138 | if(lttvwindowtraces_get_ready(g_quark_from_string("state"), trace)==FALSE |
139 | && !tstate->has_precomputed_states) { |
140 | |
141 | if(lttvwindowtraces_get_in_progress(g_quark_from_string("state"), |
142 | trace) == FALSE) { |
143 | /* We first remove requests that could have been done for the same |
144 | * information. Happens when two viewers ask for it before servicing |
145 | * starts. |
146 | */ |
147 | if(!lttvwindowtraces_background_request_find(trace, "state")) |
148 | lttvwindowtraces_background_request_queue( |
149 | main_window_get_widget(xenoltt_data->tab), trace, "state"); |
150 | lttvwindowtraces_background_notify_queue(xenoltt_data, |
151 | trace, |
152 | ltt_time_infinite, |
153 | NULL, |
154 | background_ready_hook); |
155 | xenoltt_data->background_info_waiting++; |
156 | } else { /* in progress */ |
157 | lttvwindowtraces_background_notify_current(xenoltt_data, |
158 | trace, |
159 | ltt_time_infinite, |
160 | NULL, |
161 | background_ready_hook); |
162 | xenoltt_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 | lttv_hooks_destroy(background_ready_hook); |
173 | } |
174 | |
175 | |
176 | /***********************************************************************************************************************************/ |
177 | /***********************************************************************************************************************************/ |
178 | |
179 | |
180 | /** |
181 | * Event Viewer's constructor hook |
182 | * |
183 | * This constructor is given as a parameter to the menuitem and toolbar button |
184 | * registration. It creates the list. |
185 | * @param tab A pointer to the parent tab. |
186 | * @return The widget created. |
187 | */ |
188 | GtkWidget *h_guixenoltt(LttvPlugin *plugin) { |
189 | LttvPluginTab *ptab = LTTV_PLUGIN_TAB(plugin); |
190 | Tab *tab = ptab->tab; |
191 | g_info("h_guixenoltt, %p", tab); |
192 | XenoLTTData *xenoltt_data = guixenoltt(ptab); |
193 | |
194 | xenoltt_data->tab = tab; |
195 | |
196 | // Unreg done in the guixenoltt_Destructor |
197 | lttvwindow_register_traceset_notify(tab,traceset_notify,xenoltt_data); |
198 | |
199 | lttvwindow_register_time_window_notify(tab,update_time_window_hook,xenoltt_data); |
200 | lttvwindow_register_current_time_notify(tab,update_current_time_hook,xenoltt_data); |
201 | lttvwindow_register_redraw_notify(tab,redraw_notify,xenoltt_data); |
202 | lttvwindow_register_continue_notify(tab,continue_notify,xenoltt_data); |
203 | request_background_data(xenoltt_data); |
204 | |
205 | return guixenoltt_get_widget(xenoltt_data); |
206 | |
207 | } |
208 | |
209 | void xenolttlegend_destructor(GtkWindow *legend) { |
210 | g_legend_list = g_slist_remove(g_legend_list, legend); |
211 | } |
212 | /***********************************************************************************************************************************/ |
213 | void start_clicked (GtkButton *button, gpointer user_data); |
214 | |
215 | typedef struct _ControlData ControlData; |
216 | struct _ControlData { |
217 | Tab *tab; //< current tab of module |
218 | |
219 | GtkWidget *window; //< window |
220 | |
221 | GtkWidget *main_box; //< main container |
222 | GtkWidget *start_button; |
223 | GtkWidget *task_selection_combo; |
224 | GtkWidget *period_entry; |
225 | GtkWidget *sim_file_label; |
226 | GtkWidget *file_entry; |
227 | GtkWidget *title; |
228 | GtkWidget *period_settings; |
229 | GtkWidget *task_label; |
230 | GtkWidget *period_label; |
231 | }; |
232 | |
233 | void prepare_sim_data(ControlData *tcd); |
234 | |
235 | /* Create a simulation settings window */ |
236 | |
237 | GtkWidget *h_xenolttsimulation(LttvPlugin *plugin) { |
238 | LttvPluginTab *ptab = LTTV_PLUGIN_TAB(plugin); |
239 | Tab *tab = ptab->tab; |
240 | g_info("h_Simulation, %p", tab); |
241 | |
242 | ControlData* tcd = g_new(ControlData,1); |
243 | |
244 | tcd->window = gtk_window_new(GTK_WINDOW_TOPLEVEL); |
245 | gtk_window_set_title(GTK_WINDOW(tcd->window), "XenoLTT Simulation"); |
246 | |
247 | g_legend_list = g_slist_append(g_legend_list,GTK_WINDOW(tcd->window)); |
248 | |
249 | g_object_set_data_full(G_OBJECT(tcd->window),"Simulation",GTK_WINDOW(tcd->window), |
250 | (GDestroyNotify)xenolttlegend_destructor); |
251 | |
252 | |
253 | tcd->tab = tab; |
254 | tcd->main_box = gtk_table_new(3,7,FALSE); |
255 | gtk_table_set_row_spacings(GTK_TABLE(tcd->main_box),5); |
256 | gtk_table_set_col_spacings(GTK_TABLE(tcd->main_box),5); |
257 | |
258 | gtk_container_add(GTK_CONTAINER(tcd->window), GTK_WIDGET(tcd->main_box)); |
259 | |
260 | prepare_sim_data(tcd); |
261 | |
262 | return NULL; |
263 | |
264 | } |
265 | |
266 | /***********************************************************************************************************************************/ |
267 | |
268 | static gint data_ready(void *hook_data, void *call_data){ |
269 | ControlData *tcd = (ControlData*)hook_data; |
270 | ThreadEventData *temp_thread; |
271 | GArray *list = get_thread_list(); |
272 | |
273 | tcd->sim_file_label = gtk_label_new("Simulation directory:"); |
274 | gtk_widget_show (tcd->sim_file_label); |
275 | tcd->file_entry = gtk_entry_new(); |
276 | gtk_entry_set_text(GTK_ENTRY(tcd->file_entry),"/tmp/trace1.xml"); |
277 | gtk_widget_show (tcd->file_entry); |
278 | gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->sim_file_label,0,2,0,1,GTK_FILL,GTK_FILL,2,2); |
279 | gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->file_entry,2,6,0,1,GTK_FILL,GTK_FILL,0,0); |
280 | |
281 | |
282 | //Insert Task selection |
283 | tcd->task_label = gtk_label_new("Task:"); |
284 | gtk_widget_show (tcd->task_label); |
285 | |
286 | tcd->task_selection_combo = gtk_combo_box_new_text(); |
287 | // iterate on all task to get the name and default period |
288 | int i; |
289 | |
290 | gtk_combo_box_append_text(GTK_COMBO_BOX(tcd->task_selection_combo), " - Choose a task - "); |
291 | for(i=0;i<list->len;i++){ |
292 | temp_thread = g_array_index(list, ThreadEventData*, i); |
293 | gchar text[MAX_PATH_LEN] = ""; |
294 | sprintf(text,"%s (%u)",g_quark_to_string(temp_thread->name),temp_thread->period); |
295 | gtk_combo_box_append_text(GTK_COMBO_BOX(tcd->task_selection_combo), text); |
296 | } |
297 | gtk_combo_box_set_active(GTK_COMBO_BOX(tcd->task_selection_combo), 0); |
298 | gtk_widget_show (tcd->task_selection_combo); |
299 | |
300 | // Period Entry |
301 | tcd->period_label = gtk_label_new("New period:"); |
302 | gtk_widget_show (tcd->period_label); |
303 | tcd->period_entry = gtk_entry_new(); |
304 | gtk_entry_set_text(GTK_ENTRY(tcd->period_entry),""); |
305 | gtk_widget_show (tcd->period_entry); |
306 | gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->task_label,0,2,1,2,GTK_FILL,GTK_FILL,0,0); |
307 | gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->task_selection_combo,2,6,1,2,GTK_FILL,GTK_FILL,2,2); |
308 | gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->period_label,0,2,2,3,GTK_FILL,GTK_FILL,0,0); |
309 | gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->period_entry,2,6,2,3,GTK_FILL,GTK_FILL,0,0); |
310 | |
311 | //Insert Start button |
312 | GdkPixbuf *pixbuf; |
313 | GtkWidget *image; |
314 | pixbuf = gdk_pixbuf_new_from_xpm_data((const char **)TraceControlStart_xpm); |
315 | image = gtk_image_new_from_pixbuf(pixbuf); |
316 | tcd->start_button = gtk_button_new_with_label("Start"); |
317 | g_object_set(G_OBJECT(tcd->start_button), "image", image, NULL); |
318 | gtk_button_set_alignment(GTK_BUTTON(tcd->start_button), 0.0, 0.0); |
319 | gtk_widget_show (tcd->start_button); |
320 | gtk_table_attach( GTK_TABLE(tcd->main_box),tcd->start_button,6,7,2,3,GTK_FILL,GTK_FILL,5,2); |
321 | |
322 | |
323 | // User interface guide |
324 | GList *focus_chain = NULL; |
325 | |
326 | focus_chain = g_list_append (focus_chain, tcd->file_entry); |
327 | focus_chain = g_list_append (focus_chain, tcd->task_selection_combo); |
328 | focus_chain = g_list_append (focus_chain, tcd->period_entry); |
329 | focus_chain = g_list_append (focus_chain, tcd->start_button); |
330 | |
331 | gtk_container_set_focus_chain(GTK_CONTAINER(tcd->main_box), focus_chain); |
332 | |
333 | g_list_free(focus_chain); |
334 | |
335 | g_signal_connect(G_OBJECT(tcd->start_button), "clicked",(GCallback)start_clicked, tcd); |
336 | |
337 | gtk_widget_show(tcd->main_box); |
338 | gtk_widget_show(tcd->window); |
339 | |
340 | |
341 | return 0; |
342 | } |
343 | |
344 | // When Start button is clicked, we need to perform some checks |
345 | // First, check if simulation is needed (period not the same) |
346 | // Then try to create the file |
347 | // Then compute simulation |
348 | void start_clicked (GtkButton *button, gpointer user_data){ |
349 | ControlData *tcd = (ControlData*)user_data; |
350 | FILE *a_file; |
351 | GArray *list = get_thread_list(); |
352 | ThreadEventData *temp_thread; |
353 | gchar msg[256]; |
354 | |
355 | const gchar *name; |
356 | GtkTreeIter iter; |
357 | |
358 | gtk_combo_box_get_active_iter(GTK_COMBO_BOX(tcd->task_selection_combo), &iter); |
359 | gtk_tree_model_get( |
360 | gtk_combo_box_get_model(GTK_COMBO_BOX(tcd->task_selection_combo)), |
361 | &iter, 0, &name, -1); |
362 | if(strcmp(name, " - Choose a task - ") == 0){ |
363 | strcpy(msg, "Please choose a task in the list"); |
364 | GtkWidget *dialogue = |
365 | gtk_message_dialog_new( |
366 | GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))), |
367 | GTK_DIALOG_MODAL, |
368 | GTK_MESSAGE_ERROR, |
369 | GTK_BUTTONS_OK, |
370 | msg); |
371 | gtk_dialog_run(GTK_DIALOG(dialogue)); |
372 | gtk_widget_destroy(dialogue); |
373 | return; |
374 | } |
375 | |
376 | // test period value |
377 | int i = gtk_combo_box_get_active(GTK_COMBO_BOX(tcd->task_selection_combo)) - 1; |
378 | |
379 | temp_thread = g_array_index(list, ThreadEventData*, i); |
380 | |
381 | |
382 | const gchar *period = gtk_entry_get_text(GTK_ENTRY(tcd->period_entry)); |
383 | int period_value = atoi(period); |
384 | |
385 | if(period_value <= 0){ |
386 | strcpy(msg, "Please enter a valid period value"); |
387 | GtkWidget *dialogue = |
388 | gtk_message_dialog_new( |
389 | GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))), |
390 | GTK_DIALOG_MODAL, |
391 | GTK_MESSAGE_ERROR, |
392 | GTK_BUTTONS_OK, |
393 | msg); |
394 | gtk_dialog_run(GTK_DIALOG(dialogue)); |
395 | gtk_widget_destroy(dialogue); |
396 | return; |
397 | } |
398 | |
399 | // Checkif same period |
400 | else if (period_value == temp_thread->period){ |
401 | strcpy(msg, "Please enter a different period value"); |
402 | GtkWidget *dialogue = |
403 | gtk_message_dialog_new( |
404 | GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))), |
405 | GTK_DIALOG_MODAL, |
406 | GTK_MESSAGE_ERROR, |
407 | GTK_BUTTONS_OK, |
408 | msg); |
409 | gtk_dialog_run(GTK_DIALOG(dialogue)); |
410 | gtk_widget_destroy(dialogue); |
411 | return; |
412 | } |
413 | |
414 | // Everything is ok |
415 | |
416 | // test existence of files in the directory |
417 | const gchar *file_name = gtk_entry_get_text(GTK_ENTRY(tcd->file_entry)); |
418 | printf("%s\n",file_name); |
419 | |
420 | // Try to open file in read mode to check if it exist |
421 | a_file = fopen(file_name, "r"); |
422 | if(a_file != NULL){ |
423 | |
424 | strcpy(msg, "Wrong file name, file already exist"); |
425 | GtkWidget *dialogue = |
426 | gtk_message_dialog_new( |
427 | GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))), |
428 | GTK_DIALOG_MODAL, |
429 | GTK_MESSAGE_ERROR, |
430 | GTK_BUTTONS_OK, |
431 | msg); |
432 | gtk_dialog_run(GTK_DIALOG(dialogue)); |
433 | gtk_widget_destroy(dialogue); |
434 | fclose(a_file); |
435 | return; |
436 | } |
437 | else{ |
438 | // Create the file |
439 | a_file = fopen(file_name, "w"); |
440 | if(a_file == NULL){ |
441 | sprintf(msg,"Unable to create file: %s",file_name); |
442 | GtkWidget *dialogue = |
443 | gtk_message_dialog_new( |
444 | GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))), |
445 | GTK_DIALOG_MODAL, |
446 | GTK_MESSAGE_ERROR, |
447 | GTK_BUTTONS_OK, |
448 | msg); |
449 | gtk_dialog_run(GTK_DIALOG(dialogue)); |
450 | gtk_widget_destroy(dialogue); |
451 | return; |
452 | } |
453 | |
454 | fprintf(a_file,"<TRACE SIMULATION>\n"); |
455 | compute_simulation(i,period_value,a_file); |
456 | fprintf(a_file,"</TRACE SIMULATION>\n"); |
457 | fclose(a_file); |
458 | sprintf(msg,"Simulation finished\n\nSimulation file: %s",file_name); |
459 | GtkWidget *dialogue = |
460 | gtk_message_dialog_new( |
461 | GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(button))), |
462 | GTK_DIALOG_MODAL, |
463 | GTK_MESSAGE_INFO, |
464 | GTK_BUTTONS_OK, |
465 | msg); |
466 | gtk_dialog_run(GTK_DIALOG(dialogue)); |
467 | gtk_widget_destroy(dialogue); |
468 | |
469 | } |
470 | } |
471 | |
472 | void prepare_sim_data(ControlData *tcd){ |
473 | // ControlData *tcd = (ControlData*)user_data; |
474 | LttvTracesetContext * tsc = lttvwindow_get_traceset_context(tcd->tab); |
475 | gint num_traces = lttv_traceset_number(tsc->ts); |
476 | gint i; |
477 | LttvTrace *trace; |
478 | LttvTraceState *tstate; |
479 | |
480 | /* Register simulation calculator */ |
481 | LttvHooks *hook_adder = lttv_hooks_new(); |
482 | lttv_hooks_add(hook_adder, lttv_xenoltt_sim_hook_add_event_hooks, NULL,LTTV_PRIO_DEFAULT); |
483 | lttv_hooks_add(hook_adder, lttv_state_hook_add_event_hooks, NULL,LTTV_PRIO_DEFAULT); |
484 | |
485 | LttvHooks *hook_remover = lttv_hooks_new(); |
486 | lttv_hooks_add(hook_remover, lttv_xenoltt_sim_hook_remove_event_hooks,NULL, LTTV_PRIO_DEFAULT); |
487 | lttv_hooks_add(hook_remover, lttv_state_hook_remove_event_hooks,NULL, LTTV_PRIO_DEFAULT); |
488 | |
489 | /* Add simulation hook adder to attributes */ |
490 | lttvwindowtraces_register_computation_hooks(g_quark_from_string("xenoltt_sim"), |
491 | NULL, NULL, NULL, NULL, NULL, NULL, NULL, |
492 | NULL, NULL, NULL, |
493 | hook_adder, hook_remover); |
494 | |
495 | LttvHooks *background_ready_hook = lttv_hooks_new(); |
496 | lttv_hooks_add(background_ready_hook, data_ready, tcd, LTTV_PRIO_DEFAULT); |
497 | |
498 | for(i=0;i<num_traces;i++) { |
499 | trace = lttvwindowtraces_get_trace(i); |
500 | |
501 | if(lttvwindowtraces_get_ready(g_quark_from_string("xenoltt_sim"),trace)==FALSE) { |
502 | |
503 | if(lttvwindowtraces_get_in_progress(g_quark_from_string("xenoltt_sim"),trace) == FALSE) { |
504 | if(!lttvwindowtraces_background_request_find(trace, "xenoltt_sim")) |
505 | lttvwindowtraces_background_request_queue(main_window_get_widget(tcd->tab), trace, "xenoltt_sim"); |
506 | lttvwindowtraces_background_notify_queue(tcd,trace,ltt_time_infinite,NULL,background_ready_hook); |
507 | } else { /* in progress */ |
508 | lttvwindowtraces_background_notify_current(tcd,trace,ltt_time_infinite,NULL,background_ready_hook); |
509 | |
510 | } |
511 | } else {} |
512 | } |
513 | lttv_hooks_destroy(background_ready_hook); |
514 | } |
515 | |
516 | /***********************************************************************************************************************************/ |
517 | |
518 | /* Create a popup legend */ |
519 | GtkWidget *h_xenolttlegend(LttvPlugin *plugin) |
520 | { |
521 | LttvPluginTab *ptab = LTTV_PLUGIN_TAB(plugin); |
522 | Tab *tab = ptab->tab; |
523 | g_info("h_legend, %p", tab); |
524 | |
525 | GtkWindow *xenoltt_settings = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); |
526 | |
527 | g_legend_list = g_slist_append(g_legend_list,xenoltt_settings); |
528 | |
529 | g_object_set_data_full(G_OBJECT(xenoltt_settings),"settings",xenoltt_settings,(GDestroyNotify)xenolttlegend_destructor); |
530 | |
531 | gtk_window_set_title(xenoltt_settings, "XenoLTT Settings"); |
532 | |
533 | GtkWidget *pixmap = create_pixmap(GTK_WIDGET(xenoltt_settings), "xenoltt-color-list.png"); |
534 | |
535 | |
536 | gtk_container_add(GTK_CONTAINER(xenoltt_settings), GTK_WIDGET(pixmap)); |
537 | |
538 | gtk_widget_show(GTK_WIDGET(pixmap)); |
539 | gtk_widget_show(GTK_WIDGET(xenoltt_settings)); |
540 | |
541 | |
542 | return NULL; /* This is a popup window */ |
543 | } |
544 | |
545 | /***********************************************************************************************************************************/ |
546 | |
547 | int event_selected_hook(void *hook_data, void *call_data) { |
548 | XenoLTTData *xenoltt_data = (XenoLTTData*) hook_data; |
549 | guint *event_number = (guint*) call_data; |
550 | |
551 | g_debug("DEBUG : event selected by main window : %u", *event_number); |
552 | |
553 | return 0; |
554 | } |
555 | |
556 | /* Function that selects the color of status&exemode line */ |
557 | static inline void prepare_s_e_line(LttvXenoThreadState *thread, DrawContext draw_context,LttvTraceState *ts) { |
558 | |
559 | PropertiesLine prop_line; |
560 | prop_line.style = GDK_LINE_SOLID; |
561 | prop_line.y = MIDDLE; |
562 | |
563 | //If thread is in ovverun state, we want to display a diffent background color |
564 | if(thread->state->mode == LTTV_XENO_MODE_OVERRUN){ |
565 | prop_line.line_width = 6; |
566 | prop_line.color = drawing_colors[COL_RUN_IRQ]; |
567 | draw_line((void*)&prop_line, (void*)&draw_context); |
568 | } |
569 | |
570 | // We want to draw a line if thread is the owner of at least one synch |
571 | if (lttv_xeno_thread_synch_owner(ts,thread)){ |
572 | prop_line.line_width = 1; |
573 | prop_line.color = drawing_colors[COL_RUN_USER_MODE]; |
574 | draw_context.drawinfo.y.middle = (draw_context.drawinfo.y.middle/4); |
575 | draw_line((void*)&prop_line, (void*)&draw_context); |
576 | draw_context.drawinfo.y.middle = (draw_context.drawinfo.y.under/2); |
577 | } |
578 | |
579 | if (lttv_xeno_thread_synch_waiting(ts,thread)){ |
580 | prop_line.line_width = 1; |
581 | prop_line.color = drawing_colors[COL_RUN_SOFT_IRQ]; |
582 | draw_context.drawinfo.y.middle = (draw_context.drawinfo.y.middle/2); |
583 | draw_line((void*)&prop_line, (void*)&draw_context); |
584 | draw_context.drawinfo.y.middle = (draw_context.drawinfo.y.under/2); |
585 | } |
586 | |
587 | prop_line.line_width = STATE_LINE_WIDTH; |
588 | |
589 | if(thread->state->status == LTTV_XENO_STATE_INIT) { |
590 | prop_line.color = drawing_colors[COL_EXIT]; // Created = MAGENTA |
591 | |
592 | } else if(thread->state->status == LTTV_XENO_STATE_START) { |
593 | prop_line.color = drawing_colors[COL_RUN_SOFT_IRQ]; // Started = RED |
594 | |
595 | } else if(thread->state->status == LTTV_XENO_STATE_RUN) { |
596 | prop_line.color = drawing_colors[COL_RUN_USER_MODE]; // Running = GREEN |
597 | |
598 | } else if(thread->state->status == LTTV_XENO_STATE_READY) { |
599 | prop_line.color = drawing_colors[COL_WHITE]; // READY = WHITE |
600 | |
601 | } else if(thread->state->status == LTTV_XENO_STATE_WAIT_PERIOD) { |
602 | prop_line.color = drawing_colors[COL_WAIT]; // WAIT PERIOD = DARK RED |
603 | |
604 | } else if(thread->state->status == LTTV_XENO_STATE_SUSPEND) { |
605 | prop_line.color = drawing_colors[COL_RUN_SYSCALL]; // SUSPEND = BLUE |
606 | |
607 | } else if(thread->state->status == LTTV_XENO_STATE_DEAD) { |
608 | prop_line.color = drawing_colors[COL_BLACK]; // DEAD = BLACK |
609 | |
610 | } else if(thread->state->status == LTTV_XENO_STATE_UNNAMED) { |
611 | prop_line.color = drawing_colors[COL_WHITE]; |
612 | |
613 | } else { |
614 | g_critical("unknown status : %s", g_quark_to_string(thread->state->status)); |
615 | g_assert(FALSE); /* UNKNOWN STATUS */ |
616 | } |
617 | |
618 | draw_line((void*)&prop_line, (void*)&draw_context); |
619 | } |
620 | |
621 | |
622 | |
623 | gint update_time_window_hook(void *hook_data, void *call_data) { |
624 | XenoLTTData *xenoltt_data = (XenoLTTData*) hook_data; |
625 | XenoLtt_Drawing_t *drawing = xenoltt_data->drawing; |
626 | ThreadList *thread_list = xenoltt_data->thread_list; |
627 | |
628 | const TimeWindowNotifyData *time_window_nofify_data = |
629 | ((const TimeWindowNotifyData *)call_data); |
630 | |
631 | TimeWindow *old_time_window = time_window_nofify_data->old_time_window; |
632 | TimeWindow *new_time_window = time_window_nofify_data->new_time_window; |
633 | |
634 | /* Update the ruler */ |
635 | drawing_update_ruler(xenoltt_data->drawing,new_time_window); |
636 | |
637 | |
638 | /* Two cases : zoom in/out or scrolling */ |
639 | |
640 | /* In order to make sure we can reuse the old drawing, the scale must |
641 | * be the same and the new time interval being partly located in the |
642 | * currently shown time interval. (reuse is only for scrolling) |
643 | */ |
644 | |
645 | g_info("Old time window HOOK : %lu, %lu to %lu, %lu", |
646 | old_time_window->start_time.tv_sec, |
647 | old_time_window->start_time.tv_nsec, |
648 | old_time_window->time_width.tv_sec, |
649 | old_time_window->time_width.tv_nsec); |
650 | |
651 | g_info("New time window HOOK : %lu, %lu to %lu, %lu", |
652 | new_time_window->start_time.tv_sec, |
653 | new_time_window->start_time.tv_nsec, |
654 | new_time_window->time_width.tv_sec, |
655 | new_time_window->time_width.tv_nsec); |
656 | |
657 | if( new_time_window->time_width.tv_sec == old_time_window->time_width.tv_sec |
658 | && new_time_window->time_width.tv_nsec == old_time_window->time_width.tv_nsec) { |
659 | /* Same scale (scrolling) */ |
660 | g_info("scrolling"); |
661 | LttTime *ns = &new_time_window->start_time; |
662 | LttTime *nw = &new_time_window->time_width; |
663 | LttTime *os = &old_time_window->start_time; |
664 | LttTime *ow = &old_time_window->time_width; |
665 | LttTime old_end = old_time_window->end_time; |
666 | LttTime new_end = new_time_window->end_time; |
667 | if(ltt_time_compare(*ns, old_end) == -1 |
668 | && ltt_time_compare(*os, *ns) == -1) { |
669 | g_info("scrolling near right"); |
670 | /* Scroll right, keep right part of the screen */ |
671 | guint x = 0; |
672 | guint width = xenoltt_data->drawing->width; |
673 | convert_time_to_pixels( |
674 | *old_time_window, |
675 | *ns, |
676 | width, |
677 | &x); |
678 | |
679 | /* Copy old data to new location */ |
680 | copy_pixmap_region(thread_list, |
681 | NULL, |
682 | xenoltt_data->drawing->drawing_area->style->black_gc, |
683 | NULL, |
684 | x, 0, |
685 | 0, 0, |
686 | xenoltt_data->drawing->width-x+SAFETY, -1); |
687 | |
688 | if(drawing->damage_begin == drawing->damage_end) |
689 | drawing->damage_begin = xenoltt_data->drawing->width-x; |
690 | else |
691 | drawing->damage_begin = 0; |
692 | |
693 | drawing->damage_end = xenoltt_data->drawing->width; |
694 | |
695 | /* Clear the data request background, but not SAFETY */ |
696 | rectangle_pixmap(thread_list, |
697 | xenoltt_data->drawing->drawing_area->style->black_gc, |
698 | TRUE, |
699 | drawing->damage_begin+SAFETY, 0, |
700 | drawing->damage_end - drawing->damage_begin, // do not overlap |
701 | -1); |
702 | gtk_widget_queue_draw(drawing->drawing_area); |
703 | |
704 | /* Get new data for the rest. */ |
705 | drawing_data_request(xenoltt_data->drawing, |
706 | drawing->damage_begin, 0, |
707 | drawing->damage_end - drawing->damage_begin, |
708 | xenoltt_data->drawing->height); |
709 | } else { |
710 | if(ltt_time_compare(*ns, *os) == -1 |
711 | && ltt_time_compare(*os, new_end) == -1) { |
712 | g_info("scrolling near left"); |
713 | /* Scroll left, keep left part of the screen */ |
714 | guint x = 0; |
715 | guint width = xenoltt_data->drawing->width; |
716 | convert_time_to_pixels( |
717 | *new_time_window, |
718 | *os, |
719 | width, |
720 | &x); |
721 | |
722 | /* Copy old data to new location */ |
723 | copy_pixmap_region (thread_list, |
724 | NULL, |
725 | xenoltt_data->drawing->drawing_area->style->black_gc, |
726 | NULL, |
727 | 0, 0, |
728 | x, 0, |
729 | -1, -1); |
730 | |
731 | if(drawing->damage_begin == drawing->damage_end) |
732 | drawing->damage_end = x; |
733 | else |
734 | drawing->damage_end = |
735 | xenoltt_data->drawing->width; |
736 | |
737 | drawing->damage_begin = 0; |
738 | |
739 | rectangle_pixmap(thread_list, |
740 | xenoltt_data->drawing->drawing_area->style->black_gc, |
741 | TRUE, |
742 | drawing->damage_begin, 0, |
743 | drawing->damage_end - drawing->damage_begin, // do not overlap |
744 | -1); |
745 | |
746 | gtk_widget_queue_draw(drawing->drawing_area); |
747 | |
748 | |
749 | /* Get new data for the rest. */ |
750 | drawing_data_request(xenoltt_data->drawing, |
751 | drawing->damage_begin, 0, |
752 | drawing->damage_end - drawing->damage_begin, |
753 | xenoltt_data->drawing->height); |
754 | |
755 | } else { |
756 | if(ltt_time_compare(*ns, *os) == 0) { |
757 | g_info("not scrolling"); |
758 | } else { |
759 | g_info("scrolling far"); |
760 | /* Cannot reuse any part of the screen : far jump */ |
761 | |
762 | |
763 | rectangle_pixmap(thread_list, |
764 | xenoltt_data->drawing->drawing_area->style->black_gc, |
765 | TRUE, |
766 | 0, 0, |
767 | xenoltt_data->drawing->width+SAFETY, // do not overlap |
768 | -1); |
769 | |
770 | gtk_widget_queue_draw(drawing->drawing_area); |
771 | |
772 | drawing->damage_begin = 0; |
773 | drawing->damage_end = xenoltt_data->drawing->width; |
774 | |
775 | drawing_data_request(xenoltt_data->drawing, |
776 | 0, 0, |
777 | xenoltt_data->drawing->width, |
778 | xenoltt_data->drawing->height); |
779 | |
780 | } |
781 | } |
782 | } |
783 | } else { |
784 | /* Different scale (zoom) */ |
785 | g_info("zoom"); |
786 | |
787 | rectangle_pixmap(thread_list, |
788 | xenoltt_data->drawing->drawing_area->style->black_gc, |
789 | TRUE, |
790 | 0, 0, |
791 | xenoltt_data->drawing->width+SAFETY, // do not overlap |
792 | -1); |
793 | |
794 | gtk_widget_queue_draw(drawing->drawing_area); |
795 | |
796 | drawing->damage_begin = 0; |
797 | drawing->damage_end = xenoltt_data->drawing->width; |
798 | |
799 | drawing_data_request(xenoltt_data->drawing, |
800 | 0, 0, |
801 | xenoltt_data->drawing->width, |
802 | xenoltt_data->drawing->height); |
803 | } |
804 | |
805 | /* Update directly when scrolling */ |
806 | gdk_window_process_updates(xenoltt_data->drawing->drawing_area->window, |
807 | TRUE); |
808 | |
809 | return 0; |
810 | } |
811 | |
812 | gint traceset_notify(void *hook_data, void *call_data) { |
813 | XenoLTTData *xenoltt_data = (XenoLTTData*) hook_data; |
814 | XenoLtt_Drawing_t *drawing = xenoltt_data->drawing; |
815 | |
816 | if(unlikely(drawing->gc == NULL)) { |
817 | return FALSE; |
818 | } |
819 | if(drawing->dotted_gc == NULL) { |
820 | return FALSE; |
821 | } |
822 | |
823 | drawing_clear(xenoltt_data->drawing); |
824 | threadlist_clear(xenoltt_data->thread_list); |
825 | gtk_widget_set_size_request( |
826 | xenoltt_data->drawing->drawing_area, |
827 | -1, threadlist_get_height(xenoltt_data->thread_list)); |
828 | redraw_notify(xenoltt_data, NULL); |
829 | |
830 | request_background_data(xenoltt_data); |
831 | |
832 | return FALSE; |
833 | } |
834 | |
835 | gint redraw_notify(void *hook_data, void *call_data) { |
836 | XenoLTTData *xenoltt_data = (XenoLTTData*) hook_data; |
837 | XenoLtt_Drawing_t *drawing = xenoltt_data->drawing; |
838 | GtkWidget *widget = drawing->drawing_area; |
839 | |
840 | drawing->damage_begin = 0; |
841 | drawing->damage_end = drawing->width; |
842 | |
843 | /* fun feature, to be separated someday... */ |
844 | drawing_clear(xenoltt_data->drawing); |
845 | threadlist_clear(xenoltt_data->thread_list); |
846 | gtk_widget_set_size_request( |
847 | xenoltt_data->drawing->drawing_area, |
848 | -1, threadlist_get_height(xenoltt_data->thread_list)); |
849 | // Clear the images |
850 | rectangle_pixmap(xenoltt_data->thread_list, |
851 | widget->style->black_gc, |
852 | TRUE, |
853 | 0, 0, |
854 | drawing->alloc_width, |
855 | -1); |
856 | |
857 | gtk_widget_queue_draw(drawing->drawing_area); |
858 | |
859 | if(drawing->damage_begin < drawing->damage_end) { |
860 | drawing_data_request(drawing, |
861 | drawing->damage_begin, |
862 | 0, |
863 | drawing->damage_end-drawing->damage_begin, |
864 | drawing->height); |
865 | } |
866 | |
867 | return FALSE; |
868 | |
869 | } |
870 | |
871 | |
872 | gint continue_notify(void *hook_data, void *call_data) { |
873 | XenoLTTData *xenoltt_data = (XenoLTTData*) hook_data; |
874 | XenoLtt_Drawing_t *drawing = xenoltt_data->drawing; |
875 | |
876 | |
877 | if(drawing->damage_begin < drawing->damage_end) { |
878 | drawing_data_request(drawing, |
879 | drawing->damage_begin, |
880 | 0, |
881 | drawing->damage_end-drawing->damage_begin, |
882 | drawing->height); |
883 | } |
884 | |
885 | return FALSE; |
886 | } |
887 | |
888 | |
889 | gint update_current_time_hook(void *hook_data, void *call_data) { |
890 | XenoLTTData *xenoltt_data = (XenoLTTData*)hook_data; |
891 | XenoLtt_Drawing_t *drawing = xenoltt_data->drawing; |
892 | |
893 | LttTime current_time = *((LttTime*)call_data); |
894 | |
895 | TimeWindow time_window = lttvwindow_get_time_window(xenoltt_data->tab); |
896 | |
897 | LttTime time_begin = time_window.start_time; |
898 | LttTime width = time_window.time_width; |
899 | LttTime half_width; { |
900 | guint64 time_ll = ltt_time_to_uint64(width); |
901 | time_ll = time_ll >> 1; /* divide by two */ |
902 | half_width = ltt_time_from_uint64(time_ll); |
903 | } |
904 | LttTime time_end = ltt_time_add(time_begin, width); |
905 | |
906 | LttvTracesetContext * tsc = |
907 | lttvwindow_get_traceset_context(xenoltt_data->tab); |
908 | |
909 | LttTime trace_start = tsc->time_span.start_time; |
910 | LttTime trace_end = tsc->time_span.end_time; |
911 | |
912 | g_info("New current time HOOK : %lu, %lu", current_time.tv_sec, |
913 | current_time.tv_nsec); |
914 | |
915 | |
916 | |
917 | /* If current time is inside time interval, just move the highlight |
918 | * bar */ |
919 | |
920 | /* Else, we have to change the time interval. We have to tell it |
921 | * to the main window. */ |
922 | /* The time interval change will take care of placing the current |
923 | * time at the center of the visible area, or nearest possible if we are |
924 | * at one end of the trace. */ |
925 | |
926 | |
927 | if(ltt_time_compare(current_time, time_begin) < 0) { |
928 | TimeWindow new_time_window; |
929 | |
930 | if(ltt_time_compare(current_time, |
931 | ltt_time_add(trace_start, half_width)) < 0) |
932 | time_begin = trace_start; |
933 | else |
934 | time_begin = ltt_time_sub(current_time, half_width); |
935 | |
936 | new_time_window.start_time = time_begin; |
937 | new_time_window.time_width = width; |
938 | new_time_window.time_width_double = ltt_time_to_double(width); |
939 | new_time_window.end_time = ltt_time_add(time_begin, width); |
940 | |
941 | lttvwindow_report_time_window(xenoltt_data->tab, new_time_window); |
942 | } |
943 | else if(ltt_time_compare(current_time, time_end) > 0) { |
944 | TimeWindow new_time_window; |
945 | |
946 | if(ltt_time_compare(current_time, ltt_time_sub(trace_end, half_width)) > 0) |
947 | time_begin = ltt_time_sub(trace_end, width); |
948 | else |
949 | time_begin = ltt_time_sub(current_time, half_width); |
950 | |
951 | new_time_window.start_time = time_begin; |
952 | new_time_window.time_width = width; |
953 | new_time_window.time_width_double = ltt_time_to_double(width); |
954 | new_time_window.end_time = ltt_time_add(time_begin, width); |
955 | |
956 | lttvwindow_report_time_window(xenoltt_data->tab, new_time_window); |
957 | |
958 | } |
959 | gtk_widget_queue_draw(xenoltt_data->drawing->drawing_area); |
960 | |
961 | /* Update directly when scrolling */ |
962 | gdk_window_process_updates(xenoltt_data->drawing->drawing_area->window, |
963 | TRUE); |
964 | |
965 | return 0; |
966 | } |
967 | |
968 | typedef struct _ClosureData { |
969 | EventsRequest *events_request; |
970 | LttvTracesetState *tss; |
971 | LttTime end_time; |
972 | guint x_end; |
973 | } ClosureData; |
974 | |
975 | |
976 | void draw_closure(gpointer key, gpointer value, gpointer user_data) { |
977 | XenoThreadInfo *thread_Info = (XenoThreadInfo*)key; |
978 | HashedThreadData *hashed_thread_data = (HashedThreadData*)value; |
979 | ClosureData *closure_data = (ClosureData*)user_data; |
980 | |
981 | EventsRequest *events_request = closure_data->events_request; |
982 | XenoLTTData *xenoltt_data = events_request->viewer_data; |
983 | |
984 | LttvTracesetState *tss = closure_data->tss; |
985 | LttvTracesetContext *tsc = (LttvTracesetContext*)tss; |
986 | |
987 | LttTime evtime = closure_data->end_time; |
988 | |
989 | { |
990 | /* For the thread */ |
991 | /* First, check if the current thread is in the state computation |
992 | * thread list. If it is there, that means we must add it right now and |
993 | * draw items from the beginning of the read for it. If it is not |
994 | * present, it's a new process and it was not present : it will |
995 | * be added after the state update. */ |
996 | #ifdef EXTRA_CHECK |
997 | g_assert(lttv_traceset_number(tsc->ts) > 0); |
998 | #endif //EXTRA_CHECK |
999 | LttvTraceContext *tc = tsc->traces[thread_Info->trace_num]; |
1000 | LttvTraceState *ts = (LttvTraceState*)tc; |
1001 | |
1002 | LttvXenoThreadState *thread; |
1003 | thread = lttv_xeno_state_find_thread(ts, thread_Info->cpu,thread_Info->address); |
1004 | |
1005 | if(unlikely(thread != NULL)) { |
1006 | ThreadList *thread_list = xenoltt_data->thread_list; |
1007 | #ifdef EXTRA_CHECK |
1008 | /* Should be alike when background info is ready */ |
1009 | if(xenoltt_data->background_info_waiting==0) |
1010 | #endif //EXTRA_CHECK |
1011 | |
1012 | /* Now, the process is in the state hash and our own process hash. |
1013 | * We definitely can draw the items related to the ending state. |
1014 | */ |
1015 | |
1016 | if(unlikely(ltt_time_compare(hashed_thread_data->next_good_time,evtime) <= 0)) { |
1017 | TimeWindow time_window = lttvwindow_get_time_window(xenoltt_data->tab); |
1018 | |
1019 | #ifdef EXTRA_CHECK |
1020 | if(ltt_time_compare(evtime, time_window.start_time) == -1 |
1021 | || ltt_time_compare(evtime, time_window.end_time) == 1) |
1022 | return; |
1023 | #endif //EXTRA_CHECK |
1024 | XenoLtt_Drawing_t *drawing = xenoltt_data->drawing; |
1025 | guint width = drawing->width; |
1026 | |
1027 | guint x = closure_data->x_end; |
1028 | |
1029 | DrawContext draw_context; |
1030 | |
1031 | /* Now create the drawing context that will be used to draw |
1032 | * items related to the last state. */ |
1033 | draw_context.drawable = hashed_thread_data->pixmap; |
1034 | draw_context.gc = drawing->gc; |
1035 | draw_context.pango_layout = drawing->pango_layout; |
1036 | draw_context.drawinfo.end.x = x; |
1037 | |
1038 | draw_context.drawinfo.y.over = 1; |
1039 | draw_context.drawinfo.y.middle = (hashed_thread_data->height/2); |
1040 | draw_context.drawinfo.y.under = hashed_thread_data->height; |
1041 | |
1042 | draw_context.drawinfo.start.offset.over = 0; |
1043 | draw_context.drawinfo.start.offset.middle = 0; |
1044 | draw_context.drawinfo.start.offset.under = 0; |
1045 | draw_context.drawinfo.end.offset.over = 0; |
1046 | draw_context.drawinfo.end.offset.middle = 0; |
1047 | draw_context.drawinfo.end.offset.under = 0; |
1048 | |
1049 | if(unlikely(x == hashed_thread_data->x.middle && |
1050 | hashed_thread_data->x.middle_used)) { |
1051 | /* Jump */ |
1052 | } else { |
1053 | draw_context.drawinfo.start.x = hashed_thread_data->x.middle; |
1054 | /* Draw the line */ |
1055 | // PropertiesLine prop_line = |
1056 | prepare_s_e_line(thread,draw_context,ts); |
1057 | // draw_line((void*)&prop_line, (void*)&draw_context); |
1058 | |
1059 | /* become the last x position */ |
1060 | if(likely(x != hashed_thread_data->x.middle)) { |
1061 | hashed_thread_data->x.middle = x; |
1062 | /* but don't use the pixel */ |
1063 | hashed_thread_data->x.middle_used = FALSE; |
1064 | |
1065 | /* Calculate the next good time */ |
1066 | convert_pixels_to_time(width, x+1, time_window, |
1067 | &hashed_thread_data->next_good_time); |
1068 | } |
1069 | } |
1070 | } |
1071 | } |
1072 | } |
1073 | return; |
1074 | } |
1075 | |
1076 | |
1077 | int xenoltt_before_chunk(void *hook_data, void *call_data) { |
1078 | EventsRequest *events_request = (EventsRequest*)hook_data; |
1079 | LttvTracesetState *tss = (LttvTracesetState*)call_data; |
1080 | |
1081 | drawing_chunk_begin(events_request, tss); |
1082 | |
1083 | return 0; |
1084 | } |
1085 | |
1086 | int xenoltt_before_request(void *hook_data, void *call_data) { |
1087 | EventsRequest *events_request = (EventsRequest*)hook_data; |
1088 | LttvTracesetState *tss = (LttvTracesetState*)call_data; |
1089 | |
1090 | drawing_data_request_begin(events_request, tss); |
1091 | |
1092 | return 0; |
1093 | } |
1094 | |
1095 | |
1096 | /* |
1097 | * after request is necessary in addition of after chunk in order to draw |
1098 | * lines until the end of the screen. after chunk just draws lines until |
1099 | * the last event. |
1100 | * |
1101 | * for each process |
1102 | * draw closing line |
1103 | * expose |
1104 | */ |
1105 | int xenoltt_after_request(void *hook_data, void *call_data) { |
1106 | EventsRequest *events_request = (EventsRequest*)hook_data; |
1107 | XenoLTTData *xenoltt_data = events_request->viewer_data; |
1108 | LttvTracesetState *tss = (LttvTracesetState*)call_data; |
1109 | |
1110 | ThreadList *thread_list = xenoltt_data->thread_list; |
1111 | LttTime end_time = events_request->end_time; |
1112 | |
1113 | ClosureData closure_data; |
1114 | closure_data.events_request = (EventsRequest*)hook_data; |
1115 | closure_data.tss = tss; |
1116 | closure_data.end_time = end_time; |
1117 | |
1118 | TimeWindow time_window = |
1119 | lttvwindow_get_time_window(xenoltt_data->tab); |
1120 | guint width = xenoltt_data->drawing->width; |
1121 | convert_time_to_pixels( |
1122 | time_window, |
1123 | end_time, |
1124 | width, |
1125 | &closure_data.x_end); |
1126 | |
1127 | |
1128 | /* Draw last items */ |
1129 | g_hash_table_foreach(thread_list->thread_hash, draw_closure, |
1130 | (void*)&closure_data); |
1131 | |
1132 | |
1133 | /* Request expose */ |
1134 | drawing_request_expose(events_request, tss, end_time); |
1135 | return 0; |
1136 | } |
1137 | |
1138 | /* |
1139 | * for each process |
1140 | * draw closing line |
1141 | * expose |
1142 | */ |
1143 | int xenoltt_after_chunk(void *hook_data, void *call_data) { |
1144 | EventsRequest *events_request = (EventsRequest*)hook_data; |
1145 | XenoLTTData *xenoltt_data = events_request->viewer_data; |
1146 | LttvTracesetState *tss = (LttvTracesetState*)call_data; |
1147 | LttvTracesetContext *tsc = (LttvTracesetContext*)call_data; |
1148 | LttvTracefileContext *tfc = lttv_traceset_context_get_current_tfc(tsc); |
1149 | LttTime end_time; |
1150 | |
1151 | ThreadList *thread_list = xenoltt_data->thread_list; |
1152 | guint i; |
1153 | LttvTraceset *traceset = tsc->ts; |
1154 | guint nb_trace = lttv_traceset_number(traceset); |
1155 | |
1156 | /* Only execute when called for the first trace's events request */ |
1157 | if(!thread_list->current_hash_data) return; |
1158 | |
1159 | for(i = 0 ; i < nb_trace ; i++) { |
1160 | g_free(thread_list->current_hash_data[i]); |
1161 | } |
1162 | g_free(thread_list->current_hash_data); |
1163 | thread_list->current_hash_data = NULL; |
1164 | |
1165 | if(tfc != NULL) |
1166 | end_time = LTT_TIME_MIN(tfc->timestamp, events_request->end_time); |
1167 | else /* end of traceset, or position now out of request : end */ |
1168 | end_time = events_request->end_time; |
1169 | |
1170 | ClosureData closure_data; |
1171 | closure_data.events_request = (EventsRequest*)hook_data; |
1172 | closure_data.tss = tss; |
1173 | closure_data.end_time = end_time; |
1174 | |
1175 | TimeWindow time_window = |
1176 | lttvwindow_get_time_window(xenoltt_data->tab); |
1177 | guint width = xenoltt_data->drawing->width; |
1178 | convert_time_to_pixels( |
1179 | time_window, |
1180 | end_time, |
1181 | width, |
1182 | &closure_data.x_end); |
1183 | |
1184 | /* Draw last items */ |
1185 | g_hash_table_foreach(thread_list->thread_hash, draw_closure, |
1186 | (void*)&closure_data); |
1187 | |
1188 | /* Request expose (updates damages zone also) */ |
1189 | drawing_request_expose(events_request, tss, end_time); |
1190 | |
1191 | return 0; |
1192 | } |
1193 | |
1194 | /****************************************************************************** |
1195 | * Xenoami Thread Initialization hook |
1196 | ******************************************************************************/ |
1197 | int xenoltt_thread_init(void *hook_data, void *call_data){ |
1198 | LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data; |
1199 | EventsRequest *events_request = (EventsRequest*)thf->hook_data; |
1200 | |
1201 | XenoLTTData *xenoltt_data = events_request->viewer_data; |
1202 | |
1203 | LttvTracefileContext *tfc = (LttvTracefileContext *)call_data; |
1204 | |
1205 | LttvTracefileState *tfs = (LttvTracefileState *)call_data; |
1206 | LttvTraceState *ts = (LttvTraceState *)tfc->t_context; |
1207 | |
1208 | LttEvent *e = ltt_tracefile_get_event(tfc->tf); |
1209 | |
1210 | LttTime evtime = ltt_event_time(e); |
1211 | |
1212 | GQuark name = g_quark_from_string(ltt_event_get_string(e, thf->f1)); |
1213 | gulong address = ltt_event_get_long_unsigned(e, thf->f2); |
1214 | guint prio = ltt_event_get_unsigned(e, thf->f3); |
1215 | |
1216 | guint trace_num = ts->parent.index; |
1217 | |
1218 | |
1219 | LttvXenoThreadState *thread; |
1220 | LttTime birth; |
1221 | guint pl_height = 0; |
1222 | /* Find thread in the list... */ |
1223 | thread = lttv_xeno_state_find_thread(ts, ANY_CPU, address); |
1224 | |
1225 | if (thread != NULL){ |
1226 | birth = thread->creation_time; |
1227 | /* Add thread to thread list (if not present) */ |
1228 | HashedThreadData *hashed_thread_data = NULL; |
1229 | ThreadList *thread_list = xenoltt_data->thread_list; |
1230 | |
1231 | hashed_thread_data = threadlist_get_thread_data(thread_list,thread->address,tfs->cpu, &birth, trace_num); |
1232 | XenoLtt_Drawing_t *drawing = xenoltt_data->drawing; |
1233 | |
1234 | if(hashed_thread_data == NULL){ |
1235 | /* Xenomai Thread not present */ |
1236 | XenoThreadInfo *thread_Info; |
1237 | threadlist_add(thread_list, |
1238 | drawing, |
1239 | address, |
1240 | thread->prio, |
1241 | tfs->cpu, |
1242 | thread->period, |
1243 | &birth, |
1244 | trace_num, |
1245 | thread->name, |
1246 | &pl_height, |
1247 | &thread_Info, |
1248 | &hashed_thread_data); |
1249 | gtk_widget_set_size_request(drawing->drawing_area, -1, pl_height); |
1250 | gtk_widget_queue_draw(drawing->drawing_area); |
1251 | } |
1252 | } |
1253 | /* |
1254 | else{ |
1255 | g_warning("Cannot find thread initialization %s - %u", g_quark_to_string(name), address); |
1256 | } |
1257 | */ |
1258 | return 0; |
1259 | } |
1260 | |
1261 | /****************************************************************************** |
1262 | * Xenoami Thread Set Period hook |
1263 | ******************************************************************************/ |
1264 | int xenoltt_thread_set_period(void *hook_data, void *call_data){ |
1265 | |
1266 | LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data; |
1267 | EventsRequest *events_request = (EventsRequest*)thf->hook_data; |
1268 | |
1269 | XenoLTTData *xenoltt_data = events_request->viewer_data; |
1270 | |
1271 | LttvTracefileContext *tfc = (LttvTracefileContext *)call_data; |
1272 | |
1273 | LttvTracefileState *tfs = (LttvTracefileState *)call_data; |
1274 | LttvTraceState *ts = (LttvTraceState *)tfc->t_context; |
1275 | |
1276 | LttEvent *e = ltt_tracefile_get_event(tfc->tf); |
1277 | |
1278 | GQuark name = g_quark_from_string(ltt_event_get_string(e, thf->f1)); |
1279 | gulong address = ltt_event_get_long_unsigned(e, thf->f2); |
1280 | guint period = ltt_event_get_unsigned(e, thf->f3); |
1281 | gulong timer_address = ltt_event_get_long_unsigned(e,ltt_eventtype_field_by_name(ltt_event_eventtype(e),g_quark_from_string("timer_address"))); |
1282 | LttTime evtime = ltt_event_time(e); |
1283 | |
1284 | guint trace_num = ts->parent.index; |
1285 | |
1286 | LttvXenoThreadState *thread; |
1287 | LttTime birth; |
1288 | guint pl_height = 0; |
1289 | /* Find thread in the list... */ |
1290 | thread = lttv_xeno_state_find_thread(ts, ANY_CPU, address); |
1291 | |
1292 | if (thread != NULL){ // Thread present in table |
1293 | birth = thread->creation_time; |
1294 | // Add thread to thread list (if not present) |
1295 | HashedThreadData *hashed_thread_data = NULL; |
1296 | ThreadList *thread_list = xenoltt_data->thread_list; |
1297 | |
1298 | hashed_thread_data = threadlist_get_thread_data(thread_list,thread->address,tfs->cpu, &birth, trace_num); |
1299 | if(hashed_thread_data != NULL){ |
1300 | |
1301 | threadlist_set_period(thread_list, period, hashed_thread_data); |
1302 | |
1303 | //Save the timer address |
1304 | hashed_thread_data->timer_address = timer_address; |
1305 | |
1306 | XenoLtt_Drawing_t *drawing = xenoltt_data->drawing; |
1307 | gtk_widget_set_size_request(drawing->drawing_area, -1, pl_height); |
1308 | gtk_widget_queue_draw(drawing->drawing_area); |
1309 | } |
1310 | else{ |
1311 | // Xenomai Thread not present |
1312 | XenoThreadInfo *thread_Info; |
1313 | XenoLtt_Drawing_t *drawing = xenoltt_data->drawing; |
1314 | threadlist_add(thread_list, |
1315 | drawing, |
1316 | address, |
1317 | thread->prio, // Priority |
1318 | tfs->cpu, |
1319 | thread->period, //Period |
1320 | &birth, |
1321 | trace_num, |
1322 | thread->name, |
1323 | &pl_height, |
1324 | &thread_Info, |
1325 | &hashed_thread_data); |
1326 | gtk_widget_set_size_request(drawing->drawing_area, -1, pl_height); |
1327 | gtk_widget_queue_draw(drawing->drawing_area); |
1328 | } |
1329 | } |
1330 | /* |
1331 | else{ |
1332 | g_warning("Cannot find thread in set_period %s - %u", g_quark_to_string(name), address); |
1333 | } |
1334 | */ |
1335 | return 0; |
1336 | } |
1337 | |
1338 | |
1339 | |
1340 | /******************************************************************************/ |
1341 | |
1342 | int xenoltt_before_thread_hook(void *hook_data, void *call_data){ |
1343 | |
1344 | LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data; |
1345 | EventsRequest *events_request = (EventsRequest*)thf->hook_data; |
1346 | |
1347 | XenoLTTData *xenoltt_data = events_request->viewer_data; |
1348 | |
1349 | LttvTracefileContext *tfc = (LttvTracefileContext *)call_data; |
1350 | |
1351 | LttvTracefileState *tfs = (LttvTracefileState *)call_data; |
1352 | LttvTraceState *ts = (LttvTraceState *)tfc->t_context; |
1353 | |
1354 | LttEvent *e = ltt_tracefile_get_event(tfc->tf); |
1355 | |
1356 | GQuark event_name = ltt_eventtype_name(ltt_event_eventtype(e)); |
1357 | |
1358 | gulong address = ltt_event_get_long_unsigned(e, thf->f1); |
1359 | |
1360 | guint trace_num = ts->parent.index; |
1361 | |
1362 | LttTime evtime = ltt_event_time(e); |
1363 | LttvXenoThreadState *thread; |
1364 | LttTime birth; |
1365 | guint pl_height = 0; |
1366 | /* Find thread in the list... */ |
1367 | |
1368 | if (event_name == LTT_EVENT_XENOLTT_TIMER_TICK) |
1369 | thread = lttv_xeno_state_find_thread_from_timer(ts, ANY_CPU, address); |
1370 | else |
1371 | thread = lttv_xeno_state_find_thread(ts, ANY_CPU, address); |
1372 | |
1373 | if (thread != NULL){ // Thread present in table |
1374 | birth = thread->creation_time; |
1375 | HashedThreadData *hashed_thread_data = NULL; |
1376 | ThreadList *thread_list = xenoltt_data->thread_list; |
1377 | hashed_thread_data = threadlist_get_thread_data(thread_list,thread->address,tfs->cpu, &birth, trace_num); |
1378 | |
1379 | if(hashed_thread_data == NULL){ // Xenomai Thread not present |
1380 | XenoThreadInfo *thread_Info; |
1381 | XenoLtt_Drawing_t *drawing = xenoltt_data->drawing; |
1382 | threadlist_add(thread_list,drawing,thread->address,thread->prio,tfs->cpu, |
1383 | thread->period, &birth, trace_num, thread->name, &pl_height, |
1384 | &thread_Info, &hashed_thread_data); |
1385 | |
1386 | gtk_widget_set_size_request(drawing->drawing_area, -1, pl_height); |
1387 | gtk_widget_queue_draw(drawing->drawing_area); |
1388 | } |
1389 | else{ |
1390 | |
1391 | /* Now, the process is in the state hash and our own process hash. |
1392 | * We definitely can draw the items related to the ending state. |
1393 | */ |
1394 | |
1395 | if(ltt_time_compare(hashed_thread_data->next_good_time,evtime) > 0) { |
1396 | if(hashed_thread_data->x.middle_marked == FALSE) { |
1397 | |
1398 | TimeWindow time_window = lttvwindow_get_time_window(xenoltt_data->tab); |
1399 | #ifdef EXTRA_CHECK |
1400 | if(ltt_time_compare(evtime, time_window.start_time) == -1 || ltt_time_compare(evtime, time_window.end_time) == 1) |
1401 | return; |
1402 | #endif //EXTRA_CHECK |
1403 | XenoLtt_Drawing_t *drawing = xenoltt_data->drawing; |
1404 | guint width = drawing->width; |
1405 | guint x; |
1406 | convert_time_to_pixels(time_window,evtime,width,&x); |
1407 | |
1408 | // Draw collision indicator |
1409 | gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]); |
1410 | gdk_draw_point(hashed_thread_data->pixmap,drawing->gc,x, |
1411 | COLLISION_POSITION(hashed_thread_data->height)); |
1412 | hashed_thread_data->x.middle_marked = TRUE; |
1413 | } |
1414 | } else { |
1415 | TimeWindow time_window = lttvwindow_get_time_window(xenoltt_data->tab); |
1416 | #ifdef EXTRA_CHECK |
1417 | if(ltt_time_compare(evtime, time_window.start_time) == -1 || ltt_time_compare(evtime, time_window.end_time) == 1) |
1418 | return; |
1419 | #endif //EXTRA_CHECK |
1420 | XenoLtt_Drawing_t *drawing = xenoltt_data->drawing; |
1421 | guint width = drawing->width; |
1422 | guint x; |
1423 | convert_time_to_pixels(time_window,evtime,width,&x); |
1424 | |
1425 | /* Jump over draw if we are at the same x position */ |
1426 | if(x == hashed_thread_data->x.middle && hashed_thread_data->x.middle_used) { |
1427 | if(hashed_thread_data->x.middle_marked == FALSE) { |
1428 | // Draw collision indicator |
1429 | gdk_gc_set_foreground(drawing->gc, &drawing_colors[COL_WHITE]); |
1430 | gdk_draw_point(hashed_thread_data->pixmap,drawing->gc,x, |
1431 | COLLISION_POSITION(hashed_thread_data->height)); |
1432 | hashed_thread_data->x.middle_marked = TRUE; |
1433 | } |
1434 | } else { |
1435 | DrawContext draw_context; |
1436 | |
1437 | |
1438 | /* Now create the drawing context that will be used to draw |
1439 | * items related to the last state. */ |
1440 | draw_context.drawable = hashed_thread_data->pixmap; |
1441 | draw_context.gc = drawing->gc; |
1442 | draw_context.pango_layout = drawing->pango_layout; |
1443 | draw_context.drawinfo.start.x = hashed_thread_data->x.middle; |
1444 | draw_context.drawinfo.end.x = x; |
1445 | |
1446 | draw_context.drawinfo.y.over = 1; |
1447 | draw_context.drawinfo.y.middle = (hashed_thread_data->height/2); |
1448 | draw_context.drawinfo.y.under = hashed_thread_data->height; |
1449 | |
1450 | draw_context.drawinfo.start.offset.over = 0; |
1451 | draw_context.drawinfo.start.offset.middle = 0; |
1452 | draw_context.drawinfo.start.offset.under = 0; |
1453 | draw_context.drawinfo.end.offset.over = 0; |
1454 | draw_context.drawinfo.end.offset.middle = 0; |
1455 | draw_context.drawinfo.end.offset.under = 0; |
1456 | |
1457 | prepare_s_e_line(thread,draw_context,ts); // Draw the line |
1458 | |
1459 | /* become the last x position */ |
1460 | hashed_thread_data->x.middle = x; |
1461 | hashed_thread_data->x.middle_used = TRUE; |
1462 | hashed_thread_data->x.middle_marked = FALSE; |
1463 | |
1464 | /* Calculate the next good time */ |
1465 | convert_pixels_to_time(width, x+1, time_window, |
1466 | &hashed_thread_data->next_good_time); |
1467 | } |
1468 | } |
1469 | } |
1470 | } |
1471 | /* |
1472 | else{ |
1473 | g_warning("Cannot find thread in before hook - %u", g_quark_to_string(address)); |
1474 | } |
1475 | */ |
1476 | return 0; |
1477 | } |
1478 | |
1479 | // When the thread switch is read, we need to change the state of the thread_out also |
1480 | int xenoltt_before_thread_switch_hook(void *hook_data, void *call_data){ |
1481 | |
1482 | LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data; |
1483 | EventsRequest *events_request = (EventsRequest*)thf->hook_data; |
1484 | XenoLTTData *xenoltt_data = events_request->viewer_data; |
1485 | LttvTracefileContext *tfc = (LttvTracefileContext *)call_data; |
1486 | LttvTracefileState *tfs = (LttvTracefileState *)call_data; |
1487 | LttvTraceState *ts = (LttvTraceState *)tfc->t_context; |
1488 | LttEvent *e = ltt_tracefile_get_event(tfc->tf); |
1489 | gulong address = ltt_event_get_long_unsigned(e, thf->f2); |
1490 | |
1491 | guint trace_num = ts->parent.index; |
1492 | |
1493 | LttTime evtime = ltt_event_time(e); |
1494 | LttvXenoThreadState *thread; |
1495 | LttTime birth; |
1496 | guint pl_height = 0; |
1497 | /* Find thread in the list... */ |
1498 | |
1499 | thread = lttv_xeno_state_find_thread(ts, ANY_CPU, address); |
1500 | |
1501 | if (thread != NULL){ // Thread present in table |
1502 | birth = thread->creation_time; |
1503 | HashedThreadData *hashed_thread_data = NULL; |
1504 | ThreadList *thread_list = xenoltt_data->thread_list; |
1505 | hashed_thread_data = threadlist_get_thread_data(thread_list,thread->address,tfs->cpu, &birth, trace_num); |
1506 | |
1507 | if(hashed_thread_data == NULL){ // Xenomai Thread not present |
1508 | XenoThreadInfo *thread_Info; |
1509 | XenoLtt_Drawing_t *drawing = xenoltt_data->drawing; |
1510 | threadlist_add(thread_list,drawing,thread->address,thread->prio, tfs->cpu, |
1511 | thread->period, &birth,trace_num, thread->name, &pl_height, |
1512 | &thread_Info,&hashed_thread_data); |
1513 | gtk_widget_set_size_request(drawing->drawing_area, -1, pl_height); |
1514 | gtk_widget_queue_draw(drawing->drawing_area); |
1515 | } |
1516 | else{ |
1517 | TimeWindow time_window = lttvwindow_get_time_window(xenoltt_data->tab); |
1518 | |
1519 | XenoLtt_Drawing_t *drawing = xenoltt_data->drawing; |
1520 | guint width = drawing->width; |
1521 | guint x; |
1522 | convert_time_to_pixels(time_window,evtime,width,&x); |
1523 | |
1524 | DrawContext draw_context; |
1525 | |
1526 | |
1527 | /* Now create the drawing context that will be used to draw |
1528 | * items related to the last state. */ |
1529 | draw_context.drawable = hashed_thread_data->pixmap; |
1530 | draw_context.gc = drawing->gc; |
1531 | draw_context.pango_layout = drawing->pango_layout; |
1532 | draw_context.drawinfo.start.x = hashed_thread_data->x.middle; |
1533 | draw_context.drawinfo.end.x = x; |
1534 | |
1535 | draw_context.drawinfo.y.over = 1; |
1536 | draw_context.drawinfo.y.middle = (hashed_thread_data->height/2); |
1537 | draw_context.drawinfo.y.under = hashed_thread_data->height; |
1538 | |
1539 | draw_context.drawinfo.start.offset.over = 0; |
1540 | draw_context.drawinfo.start.offset.middle = 0; |
1541 | draw_context.drawinfo.start.offset.under = 0; |
1542 | draw_context.drawinfo.end.offset.over = 0; |
1543 | draw_context.drawinfo.end.offset.middle = 0; |
1544 | draw_context.drawinfo.end.offset.under = 0; |
1545 | |
1546 | |
1547 | prepare_s_e_line(thread,draw_context,ts); // Draw the line |
1548 | |
1549 | /* become the last x position */ |
1550 | hashed_thread_data->x.middle = x; |
1551 | hashed_thread_data->x.middle_used = TRUE; |
1552 | hashed_thread_data->x.middle_marked = FALSE; |
1553 | |
1554 | /* Calculate the next good time */ |
1555 | convert_pixels_to_time(width, x+1, time_window, |
1556 | &hashed_thread_data->next_good_time); |
1557 | } |
1558 | } |
1559 | /* |
1560 | else{ |
1561 | g_warning("Cannot find thread in before hook - %u", g_quark_to_string(address)); |
1562 | } |
1563 | */ |
1564 | return 0; |
1565 | } |
1566 | |
1567 | /******************************************************************************/ |
1568 | /* xenoltt_after_thread_hook */ |
1569 | |
1570 | int xenoltt_after_thread_hook(void *hook_data, void *call_data){ |
1571 | LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data; |
1572 | EventsRequest *events_request = (EventsRequest*)thf->hook_data; |
1573 | |
1574 | XenoLTTData *xenoltt_data = events_request->viewer_data; |
1575 | |
1576 | LttvTracefileContext *tfc = (LttvTracefileContext *)call_data; |
1577 | |
1578 | LttvTracefileState *tfs = (LttvTracefileState *)call_data; |
1579 | LttvTraceState *ts = (LttvTraceState *)tfc->t_context; |
1580 | |
1581 | LttEvent *e = ltt_tracefile_get_event(tfc->tf); |
1582 | |
1583 | GQuark event_name = ltt_eventtype_name(ltt_event_eventtype(e)); |
1584 | |
1585 | gulong address = ltt_event_get_long_unsigned(e, thf->f1); |
1586 | |
1587 | guint trace_num = ts->parent.index; |
1588 | LttTime evtime = ltt_event_time(e); |
1589 | LttvXenoThreadState *thread; |
1590 | LttTime birth; |
1591 | guint pl_height = 0; |
1592 | /* Find thread in the list... */ |
1593 | |
1594 | if (event_name == LTT_EVENT_XENOLTT_TIMER_TICK){ |
1595 | thread = lttv_xeno_state_find_thread_from_timer(ts, ANY_CPU,address); |
1596 | } |
1597 | else thread = lttv_xeno_state_find_thread(ts, ANY_CPU, address); |
1598 | |
1599 | if (thread != NULL){ // Thread present in table |
1600 | birth = thread->creation_time; |
1601 | // Add thread to thread list (if not present) |
1602 | HashedThreadData *hashed_thread_data = NULL; |
1603 | ThreadList *thread_list = xenoltt_data->thread_list; |
1604 | guint pl_height = 0; |
1605 | |
1606 | hashed_thread_data = threadlist_get_thread_data(thread_list, thread->address,tfs->cpu, &birth, trace_num); |
1607 | |
1608 | if(hashed_thread_data == NULL){ |
1609 | // Xenomai Thread not present |
1610 | XenoThreadInfo *thread_Info; |
1611 | XenoLtt_Drawing_t *drawing = xenoltt_data->drawing; |
1612 | threadlist_add(thread_list, |
1613 | drawing, |
1614 | thread->address, |
1615 | thread->prio, // Priority |
1616 | tfs->cpu, |
1617 | thread->period, //Period |
1618 | &birth, |
1619 | trace_num, |
1620 | thread->name, |
1621 | &pl_height, |
1622 | &thread_Info, |
1623 | &hashed_thread_data); |
1624 | gtk_widget_set_size_request(drawing->drawing_area, -1, pl_height); |
1625 | gtk_widget_queue_draw(drawing->drawing_area); |
1626 | } |
1627 | |
1628 | /* Set the current Xenomai thread */ |
1629 | thread_list->current_hash_data[trace_num][tfs->cpu] = hashed_thread_data; |
1630 | |
1631 | if(ltt_time_compare(hashed_thread_data->next_good_time, evtime) <= 0){ |
1632 | TimeWindow time_window = lttvwindow_get_time_window(xenoltt_data->tab); |
1633 | |
1634 | #ifdef EXTRA_CHECK |
1635 | if(ltt_time_compare(evtime, time_window.start_time) == -1 |
1636 | || ltt_time_compare(evtime, time_window.end_time) == 1) |
1637 | return; |
1638 | #endif //EXTRA_CHECK |
1639 | XenoLtt_Drawing_t *drawing = xenoltt_data->drawing; |
1640 | guint width = drawing->width; |
1641 | guint new_x; |
1642 | |
1643 | convert_time_to_pixels(time_window,evtime,width,&new_x); |
1644 | |
1645 | if(hashed_thread_data->x.middle != new_x) { |
1646 | hashed_thread_data->x.middle = new_x; |
1647 | hashed_thread_data->x.middle_used = FALSE; |
1648 | hashed_thread_data->x.middle_marked = FALSE; |
1649 | } |
1650 | } |
1651 | } |
1652 | /* |
1653 | else{ |
1654 | g_warning("Cannot find thread in after hook %u", g_quark_to_string(address)); |
1655 | } |
1656 | */ |
1657 | return 0; |
1658 | } |
1659 | |
1660 | |
1661 | int xenoltt_draw_icons(void *hook_data, void *call_data){ |
1662 | |
1663 | LttvTraceHookByFacility *thf = (LttvTraceHookByFacility*)hook_data; |
1664 | EventsRequest *events_request = (EventsRequest*)thf->hook_data; |
1665 | |
1666 | XenoLTTData *xenoltt_data = events_request->viewer_data; |
1667 | |
1668 | LttvTracefileContext *tfc = (LttvTracefileContext *)call_data; |
1669 | |
1670 | LttvTracefileState *tfs = (LttvTracefileState *)call_data; |
1671 | LttvTraceState *ts = (LttvTraceState *)tfc->t_context; |
1672 | |
1673 | LttEvent *e = ltt_tracefile_get_event(tfc->tf); |
1674 | |
1675 | // We must update the state of the current Xenomai Thread |
1676 | GQuark event_name = ltt_eventtype_name(ltt_event_eventtype(e)); |
1677 | |
1678 | guint trace_num = ts->parent.index; |
1679 | LttTime evtime = ltt_event_time(e); |
1680 | |
1681 | gulong address = ltt_event_get_long_unsigned(e, thf->f2); |
1682 | |
1683 | LttvXenoThreadState *thread; |
1684 | LttTime birth; |
1685 | guint pl_height = 0; |
1686 | /* Find thread in the list... */ |
1687 | |
1688 | HashedThreadData *hashed_thread_data = NULL; |
1689 | ThreadList *thread_list = xenoltt_data->thread_list; |
1690 | |
1691 | XenoLtt_Drawing_t *drawing = xenoltt_data->drawing; |
1692 | |
1693 | if (event_name == LTT_EVENT_XENOLTT_TIMER_TICK){ |
1694 | thread = lttv_xeno_state_find_thread_from_timer(ts, ANY_CPU,address); |
1695 | } |
1696 | else thread = lttv_xeno_state_find_thread(ts, ANY_CPU, address); |
1697 | |
1698 | if (thread != NULL){ // Thread present in table |
1699 | birth = thread->creation_time; |
1700 | // Add thread to thread list (if not present) |
1701 | HashedThreadData *hashed_thread_data = NULL; |
1702 | ThreadList *thread_list = xenoltt_data->thread_list; |
1703 | guint pl_height = 0; |
1704 | |
1705 | hashed_thread_data = threadlist_get_thread_data(thread_list, thread->address,tfs->cpu, &birth, trace_num); |
1706 | |
1707 | if(hashed_thread_data != NULL){ |
1708 | TimeWindow time_window = lttvwindow_get_time_window(xenoltt_data->tab); |
1709 | guint width = drawing->width; |
1710 | guint new_x; |
1711 | |
1712 | |
1713 | convert_time_to_pixels(time_window,evtime,width,&new_x); |
1714 | |
1715 | DrawContext draw_context; |
1716 | |
1717 | /* Now create the drawing context that will be used to draw |
1718 | * items related to the event. */ |
1719 | draw_context.drawable = hashed_thread_data->pixmap; |
1720 | draw_context.gc = drawing->gc; |
1721 | draw_context.pango_layout = drawing->pango_layout; |
1722 | |
1723 | draw_context.drawinfo.y.over = -1; |
1724 | draw_context.drawinfo.y.middle = (hashed_thread_data->height/2); |
1725 | draw_context.drawinfo.y.under = hashed_thread_data->height; |
1726 | |
1727 | draw_context.drawinfo.start.x = new_x; |
1728 | draw_context.drawinfo.start.offset.over = 0; |
1729 | draw_context.drawinfo.start.offset.middle = 0; |
1730 | draw_context.drawinfo.start.offset.under = 0; |
1731 | |
1732 | draw_context.drawinfo.end.x = new_x + 2; |
1733 | draw_context.drawinfo.end.offset.over = 0; |
1734 | draw_context.drawinfo.end.offset.middle = 0; |
1735 | draw_context.drawinfo.end.offset.under = 0; |
1736 | |
1737 | if(event_name == LTT_EVENT_XENOLTT_THREAD_INIT) { |
1738 | // When a thread is initialized, we place a small green flag |
1739 | PropertiesIcon prop_icon; |
1740 | prop_icon.icon_name = "/usr/local/share/LinuxTraceToolkitViewer/pixmaps/FlagThreadInit.xpm"; |
1741 | prop_icon.width = 6; |
1742 | prop_icon.height = 13; |
1743 | prop_icon.position.x = POS_START; |
1744 | prop_icon.position.y = OVER; |
1745 | |
1746 | draw_context.drawinfo.end.x = new_x + 6; |
1747 | draw_icon((void*)&prop_icon, (void*)&draw_context); |
1748 | |
1749 | PropertiesText prop_text; |
1750 | prop_text.foreground = &drawing_colors[COL_RUN_USER_MODE]; |
1751 | prop_text.background = &drawing_colors[COL_BLACK]; |
1752 | prop_text.size = 8; |
1753 | prop_text.text = ltt_event_get_string(e, thf->f1); |
1754 | prop_text.position.x = POS_START; |
1755 | prop_text.position.y = OVER; |
1756 | |
1757 | draw_context.drawinfo.end.x = new_x + 1000; |
1758 | draw_text((void*)&prop_text, (void*)&draw_context); |
1759 | |
1760 | |
1761 | } else if(event_name == LTT_EVENT_XENOLTT_THREAD_SET_PERIOD) { |
1762 | PropertiesArc prop_arc; |
1763 | prop_arc.color = &drawing_colors[COL_RUN_TRAP]; |
1764 | prop_arc.size = 6; |
1765 | prop_arc.filled = 1; |
1766 | prop_arc.position.x = POS_START; |
1767 | prop_arc.position.y = MIDDLE; |
1768 | |
1769 | draw_context.drawinfo.end.x = new_x + 6; |
1770 | draw_arc((void*)&prop_arc, (void*)&draw_context); |
1771 | |
1772 | guint period = ltt_event_get_unsigned(e, thf->f3); |
1773 | gchar text[MAX_PATH_LEN] = "Period :"; |
1774 | sprintf(text,"%s %u",text,period); |
1775 | //We must update the thread priority in the list |
1776 | threadlist_set_period(thread_list, period, hashed_thread_data); |
1777 | |
1778 | PropertiesText prop_text; |
1779 | prop_text.foreground = &drawing_colors[COL_RUN_TRAP]; //Yellow |
1780 | prop_text.background = &drawing_colors[COL_BLACK]; |
1781 | prop_text.size = 8; |
1782 | prop_text.text = text; |
1783 | prop_text.position.x = POS_START; |
1784 | prop_text.position.y = MIDDLE; |
1785 | |
1786 | draw_context.drawinfo.end.x = new_x + 1000; |
1787 | draw_text((void*)&prop_text, (void*)&draw_context); |
1788 | |
1789 | } else if(event_name == LTT_EVENT_XENOLTT_THREAD_RENICE) { |
1790 | PropertiesArc prop_arc; |
1791 | prop_arc.color = &drawing_colors[COL_WHITE]; |
1792 | prop_arc.size = 6; |
1793 | prop_arc.filled = 1; |
1794 | prop_arc.position.x = POS_START; |
1795 | prop_arc.position.y = MIDDLE; |
1796 | |
1797 | draw_context.drawinfo.end.x = new_x + 6; |
1798 | draw_arc((void*)&prop_arc, (void*)&draw_context); |
1799 | |
1800 | guint prio = ltt_event_get_unsigned(e, thf->f3); |
1801 | gchar text[MAX_PATH_LEN] = "Priority :"; |
1802 | sprintf(text,"%s %u",text,prio); |
1803 | //We must update the thread priority in the list |
1804 | threadlist_set_prio(thread_list,prio,hashed_thread_data); |
1805 | |
1806 | PropertiesText prop_text; |
1807 | prop_text.foreground = &drawing_colors[COL_WHITE]; |
1808 | prop_text.background = &drawing_colors[COL_BLACK]; |
1809 | prop_text.size = 8; |
1810 | prop_text.text = text; |
1811 | prop_text.position.x = POS_START; |
1812 | prop_text.position.y = MIDDLE; |
1813 | |
1814 | draw_context.drawinfo.end.x = new_x + 500; |
1815 | draw_text((void*)&prop_text, (void*)&draw_context); |
1816 | |
1817 | } else if(event_name == LTT_EVENT_XENOLTT_TIMER_TICK) { |
1818 | PropertiesLine prop_line; |
1819 | prop_line.line_width = 20; |
1820 | prop_line.style = GDK_LINE_SOLID; |
1821 | prop_line.y = MIDDLE; |
1822 | prop_line.color = drawing_colors[COL_WHITE]; // WHITE |
1823 | |
1824 | draw_context.drawinfo.start.x = new_x; |
1825 | draw_context.drawinfo.end.x = new_x + 2; |
1826 | draw_line((void*)&prop_line, (void*)&draw_context); |
1827 | |
1828 | } else if(event_name == LTT_EVENT_XENOLTT_THREAD_DELETE) { |
1829 | // When a thread is deleted, we place a small red flag |
1830 | PropertiesIcon prop_icon; |
1831 | prop_icon.icon_name = "/usr/local/share/LinuxTraceToolkitViewer/pixmaps/FlagThreadDelete.xpm"; |
1832 | prop_icon.width = 6; |
1833 | prop_icon.height = 13; |
1834 | prop_icon.position.x = POS_START; |
1835 | prop_icon.position.y = OVER; |
1836 | |
1837 | draw_context.drawinfo.end.x = new_x + 10; |
1838 | draw_icon((void*)&prop_icon, (void*)&draw_context); |
1839 | |
1840 | } else if(event_name == LTT_EVENT_XENOLTT_THREAD_MISSED_PERIOD) { |
1841 | PropertiesArc prop_arc; |
1842 | prop_arc.color = &drawing_colors[COL_WHITE]; |
1843 | prop_arc.size = 6; |
1844 | prop_arc.filled = 1; |
1845 | prop_arc.position.x = POS_START; |
1846 | prop_arc.position.y = MIDDLE; |
1847 | |
1848 | draw_context.drawinfo.end.x = new_x + 6; |
1849 | draw_arc((void*)&prop_arc, (void*)&draw_context); |
1850 | |
1851 | guint overruns = ltt_event_get_unsigned(e, thf->f3); |
1852 | gchar text[MAX_PATH_LEN] = "Overruns :"; |
1853 | sprintf(text,"%s %u",text,overruns); |
1854 | |
1855 | PropertiesText prop_text; |
1856 | prop_text.foreground = &drawing_colors[COL_WHITE]; |
1857 | prop_text.background = &drawing_colors[COL_BLACK]; |
1858 | prop_text.size = 8; |
1859 | prop_text.text = text; |
1860 | prop_text.position.x = POS_START; |
1861 | prop_text.position.y = MIDDLE; |
1862 | |
1863 | draw_context.drawinfo.end.x = new_x + 1000; |
1864 | draw_text((void*)&prop_text, (void*)&draw_context); |
1865 | |
1866 | } else if(event_name == LTT_EVENT_XENOLTT_SYNCH_SET_OWNER || |
1867 | event_name == LTT_EVENT_XENOLTT_SYNCH_WAKEUP1 || |
1868 | event_name == LTT_EVENT_XENOLTT_SYNCH_WAKEUPX) { |
1869 | |
1870 | gulong synch_address = ltt_event_get_long_unsigned(e, thf->f3); |
1871 | |
1872 | LttvXenoSynchState *synch = lttv_xeno_state_find_synch(ts,synch_address); |
1873 | |
1874 | if (synch != NULL){ |
1875 | // When a thread has a synch, we place a small blue flag |
1876 | PropertiesIcon prop_icon; |
1877 | prop_icon.icon_name = "/usr/local/share/LinuxTraceToolkitViewer/pixmaps/FlagSynchOwner.xpm"; |
1878 | prop_icon.width = 6; |
1879 | prop_icon.height = 13; |
1880 | prop_icon.position.x = POS_START; |
1881 | prop_icon.position.y = OVER; |
1882 | |
1883 | int i; |
1884 | LttvXenoThreadState *temp_thread; |
1885 | |
1886 | // If the thread has a lower priority than another we need to inform |
1887 | // about priority inversion |
1888 | for(i=0;i<synch->state->waiting_threads->len;i++){ |
1889 | temp_thread = g_array_index(synch->state->waiting_threads, LttvXenoThreadState*, i); |
1890 | if (temp_thread->address != thread->address){ |
1891 | if (thread->prio < temp_thread->prio){ |
1892 | prop_icon.width = 13; |
1893 | prop_icon.icon_name = "/usr/local/share/LinuxTraceToolkitViewer/pixmaps/FlagPriority.xpm"; |
1894 | } |
1895 | } |
1896 | } |
1897 | |
1898 | draw_context.drawinfo.end.x = new_x + 10; |
1899 | draw_icon((void*)&prop_icon, (void*)&draw_context); |
1900 | } |
1901 | } else if(event_name == LTT_EVENT_XENOLTT_SYNCH_SLEEP_ON) { |
1902 | |
1903 | gulong synch_address = ltt_event_get_long_unsigned(e, thf->f3); |
1904 | |
1905 | LttvXenoSynchState *synch = lttv_xeno_state_find_synch(ts,synch_address); |
1906 | |
1907 | if (synch != NULL){ |
1908 | // When a thread has a synch, we place a small blue flag |
1909 | PropertiesIcon prop_icon; |
1910 | prop_icon.icon_name = "/usr/local/share/LinuxTraceToolkitViewer/pixmaps/FlagSynchSleep.xpm"; |
1911 | prop_icon.width = 6; |
1912 | prop_icon.height = 13; |
1913 | prop_icon.position.x = POS_START; |
1914 | prop_icon.position.y = OVER; |
1915 | |
1916 | draw_context.drawinfo.end.x = new_x + 10; |
1917 | draw_icon((void*)&prop_icon, (void*)&draw_context); |
1918 | } |
1919 | } else if(event_name == LTT_EVENT_XENOLTT_SYNCH_UNLOCK) { |
1920 | |
1921 | gulong synch_address = ltt_event_get_long_unsigned(e, thf->f3); |
1922 | |
1923 | LttvXenoSynchState *synch = lttv_xeno_state_find_synch(ts,synch_address); |
1924 | |
1925 | if (synch != NULL){ |
1926 | // When a thread has a synch, we place a small blue flag |
1927 | PropertiesIcon prop_icon; |
1928 | prop_icon.icon_name = "/usr/local/share/LinuxTraceToolkitViewer/pixmaps/FlagSynchUnlock.xpm"; |
1929 | prop_icon.width = 6; |
1930 | prop_icon.height = 13; |
1931 | prop_icon.position.x = POS_START; |
1932 | prop_icon.position.y = OVER; |
1933 | |
1934 | draw_context.drawinfo.end.x = new_x + 10; |
1935 | draw_icon((void*)&prop_icon, (void*)&draw_context); |
1936 | } |
1937 | } |
1938 | } |
1939 | } |
1940 | return 0; |
1941 | } |