update compat
[lttv.git] / ltt / branches / poly / lttv / modules / gui / interrupts / interrupts.c
1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2005 Peter Ho
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 CPUID | IRQID | Frequency |
21
22 The standard deviation (sigma) is based on:
23 http://en.wikipedia.org/wiki/Standard_deviation
24
25 sigma = sqrt(1/N Sum ((xi -Xa)^2))
26
27 To compute the standard deviation, we pass two EventRequests to LTTV. In
28 the first EventRequest, we compute the average duration (Xa) of and the
29 frequency (N) each IrqID. We store the information in an array called
30 FirstRequestIrqExit.
31
32 In the second EventRequest, we compute the Sum ((xi -Xa)^2)
33
34
35
36
37
38 *******************************************************************/
39
40
41
42 #include <math.h>
43 #include <glib.h>
44 #include <gtk/gtk.h>
45 #include <gdk/gdk.h>
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <math.h>
49 #include <string.h>
50 #include <ltt/ltt.h>
51 #include <ltt/event.h>
52 #include <ltt/type.h>
53 #include <ltt/trace.h>
54 #include <ltt/facility.h>
55 #include <lttv/module.h>
56 #include <lttv/hook.h>
57 #include <lttv/tracecontext.h>
58 #include <lttv/state.h>
59 #include <lttv/filter.h>
60 #include <lttvwindow/lttvwindow.h>
61 #include <ltt/time.h>
62
63 #include "hInterruptsInsert.xpm"
64
65 #define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
66 #define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format)
67 #define NO_ITEMS 0
68
69 typedef struct {
70 guint cpu_id;
71 guint id;
72 guint frequency;
73 LttTime total_duration;
74 guint average_duration;
75
76 }Irq;
77
78 typedef struct {
79 guint id;
80 guint cpu_id;
81 LttTime event_time;
82 }irq_entry;
83
84
85 typedef struct
86 {
87 guint irqId;
88 guint frequency;
89 guint64 sumOfDurations;
90
91 }SumId;
92
93 enum type_t {
94 IRQ_ENTRY,
95 IRQ_EXIT
96 };
97
98 /** Array containing instanced objects. Used when module is unloaded */
99 static GSList *interrupt_data_list = NULL ;
100
101
102 #define TRACE_NUMBER 0
103
104 typedef struct _InterruptEventData {
105
106 /*Graphical Widgets */
107 GtkWidget * ScrollWindow;
108 GtkListStore *ListStore;
109 GtkWidget *Hbox;
110 GtkWidget *TreeView;
111 GtkTreeSelection *SelectionTree;
112
113 Tab * tab; /* tab that contains this plug-in*/
114 LttvHooks * event_hooks;
115 LttvHooks * hooks_trace_after;
116 LttvHooks * hooks_trace_before;
117 TimeWindow time_window;
118 LttvHooksById * event_by_id_hooks;
119 GArray *FirstRequestIrqExit;
120 GArray *FirstRequestIrqEntry;
121 GArray *SecondRequestIrqEntry;
122 GArray *SecondRequestIrqExit;
123 GArray *SumArray;
124
125 } InterruptEventData ;
126
127
128 /* Function prototypes */
129
130 static gboolean interrupt_update_time_window(void * hook_data, void * call_data);
131 static GtkWidget *interrupts(Tab *tab);
132 static InterruptEventData *system_info(Tab *tab);
133 void interrupt_destructor(InterruptEventData *event_viewer_data);
134 static void FirstRequest(InterruptEventData *event_data );
135 static guint64 get_interrupt_id(LttEvent *e);
136 static gboolean trace_header(void *hook_data, void *call_data);
137 static gboolean DisplayViewer (void *hook_data, void *call_data);
138 static void calcul_duration(LttTime time_exit, guint cpu_id, InterruptEventData *event_data);
139 static void sum_interrupt_data(irq_entry *e, LttTime time_exit, GArray *FirstRequestIrqExit);
140 static gboolean FirstRequestIrqEntryCallback(void *hook_data, void *call_data);
141 static gboolean FirstRequestIrqExitCallback(void *hook_data, void *call_data);
142 static gboolean SecondRequest(void *hook_data, void *call_data);
143 static void CalculateAverageDurationForEachIrqId(InterruptEventData *event_data);
144 static gboolean SecondRequestIrqEntryCallback(void *hook_data, void *call_data);
145 static gboolean SecondRequestIrqExitCallback(void *hook_data, void *call_data);
146 static void CalculateXi(LttEvent *event, InterruptEventData *event_data);
147 static void SumItems(gint irq_id, LttTime Xi, InterruptEventData *event_data);
148 static int CalculateStandardDeviation(gint id, InterruptEventData *event_data);
149 static void CalculateMaxIRQHandler();
150 /* Enumeration of the columns */
151 enum{
152 CPUID_COLUMN,
153 IRQ_ID_COLUMN,
154 FREQUENCY_COLUMN,
155 DURATION_COLUMN,
156 DURATION_STANDARD_DEV_COLUMN,
157 N_COLUMNS
158 };
159
160
161
162 /**
163 * init function
164 *
165 *
166 * This is the entry point of the viewer.
167 *
168 */
169 static void init() {
170 g_info("interrupts: init()");
171 lttvwindow_register_constructor("interrupts",
172 "/",
173 "Insert Interrupts View",
174 hInterruptsInsert_xpm,
175 "Insert Interrupts View",
176 interrupts);
177
178 }
179
180
181 /**
182 * Constructor hook
183 *
184 */
185 static GtkWidget *interrupts(Tab * tab)
186 {
187
188 InterruptEventData* event_data = system_info(tab) ;
189 if(event_data)
190 return event_data->Hbox;
191 else
192 return NULL;
193 }
194
195 /**
196 * This function initializes the Event Viewer functionnality through the
197 * GTK API.
198 */
199 InterruptEventData *system_info(Tab *tab)
200 {
201
202 LttTime end;
203 GtkTreeViewColumn *column;
204 GtkCellRenderer *renderer;
205 InterruptEventData* event_viewer_data = g_new(InterruptEventData,1) ;
206
207 event_viewer_data->tab = tab;
208
209 /*Get the current time frame from the main window */
210 event_viewer_data->time_window = lttvwindow_get_time_window(tab);
211
212 event_viewer_data->FirstRequestIrqExit = g_array_new(FALSE, FALSE, sizeof(Irq));
213 event_viewer_data->FirstRequestIrqEntry = g_array_new(FALSE, FALSE, sizeof(irq_entry));
214
215 event_viewer_data->SecondRequestIrqEntry = g_array_new(FALSE, FALSE, sizeof(irq_entry));
216 event_viewer_data->SecondRequestIrqExit = g_array_new(FALSE, FALSE, sizeof(Irq));
217
218 event_viewer_data->SumArray = g_array_new(FALSE, FALSE, sizeof(SumId));
219
220
221 /*Create tha main window for the viewer */
222 event_viewer_data->ScrollWindow = gtk_scrolled_window_new (NULL, NULL);
223 gtk_widget_show (event_viewer_data->ScrollWindow);
224 gtk_scrolled_window_set_policy(
225 GTK_SCROLLED_WINDOW(event_viewer_data->ScrollWindow),
226 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC/*GTK_POLICY_NEVER*/);
227
228 /* Create a model for storing the data list */
229 event_viewer_data->ListStore = gtk_list_store_new (
230 N_COLUMNS, /* Total number of columns */
231 G_TYPE_INT, /* CPUID */
232 G_TYPE_INT, /* IRQ_ID */
233 G_TYPE_INT, /* Frequency */
234 G_TYPE_UINT64, /* Duration */
235 G_TYPE_INT /* standard deviation */
236 );
237
238 event_viewer_data->TreeView = gtk_tree_view_new_with_model (GTK_TREE_MODEL (event_viewer_data->ListStore));
239
240 g_object_unref (G_OBJECT (event_viewer_data->ListStore));
241
242 renderer = gtk_cell_renderer_text_new ();
243 column = gtk_tree_view_column_new_with_attributes ("CPUID",
244 renderer,
245 "text", CPUID_COLUMN,
246 NULL);
247 gtk_tree_view_column_set_alignment (column, 0.0);
248 gtk_tree_view_column_set_fixed_width (column, 45);
249 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
250
251
252 renderer = gtk_cell_renderer_text_new ();
253 column = gtk_tree_view_column_new_with_attributes ("IrqId",
254 renderer,
255 "text", IRQ_ID_COLUMN,
256 NULL);
257 gtk_tree_view_column_set_alignment (column, 0.0);
258 gtk_tree_view_column_set_fixed_width (column, 220);
259 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
260
261 renderer = gtk_cell_renderer_text_new ();
262 column = gtk_tree_view_column_new_with_attributes ("Frequency",
263 renderer,
264 "text", FREQUENCY_COLUMN,
265 NULL);
266 gtk_tree_view_column_set_alignment (column, 1.0);
267 gtk_tree_view_column_set_fixed_width (column, 220);
268 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
269
270 renderer = gtk_cell_renderer_text_new ();
271 column = gtk_tree_view_column_new_with_attributes ("Duration (nsec)",
272 renderer,
273 "text", DURATION_COLUMN,
274 NULL);
275 gtk_tree_view_column_set_alignment (column, 0.0);
276 gtk_tree_view_column_set_fixed_width (column, 145);
277 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
278
279
280 renderer = gtk_cell_renderer_text_new ();
281 column = gtk_tree_view_column_new_with_attributes ("Duration standard deviation (nsec)",
282 renderer,
283 "text", DURATION_STANDARD_DEV_COLUMN,
284 NULL);
285 gtk_tree_view_column_set_alignment (column, 0.0);
286 gtk_tree_view_column_set_fixed_width (column, 250);
287 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
288
289
290
291 event_viewer_data->SelectionTree = gtk_tree_view_get_selection (GTK_TREE_VIEW (event_viewer_data->TreeView));
292 gtk_tree_selection_set_mode (event_viewer_data->SelectionTree, GTK_SELECTION_SINGLE);
293
294 gtk_container_add (GTK_CONTAINER (event_viewer_data->ScrollWindow), event_viewer_data->TreeView);
295
296 event_viewer_data->Hbox = gtk_hbox_new(0, 0);
297 gtk_box_pack_start(GTK_BOX(event_viewer_data->Hbox), event_viewer_data->ScrollWindow, TRUE, TRUE, 0);
298
299 gtk_widget_show(event_viewer_data->Hbox);
300 gtk_widget_show(event_viewer_data->TreeView);
301
302 interrupt_data_list = g_slist_append(interrupt_data_list, event_viewer_data);
303 /* Registration for time notification */
304 lttvwindow_register_time_window_notify(tab,
305 interrupt_update_time_window,
306 event_viewer_data);
307
308
309 FirstRequest(event_viewer_data );
310 return event_viewer_data;
311 }
312
313 /**
314 *
315 * For each trace in the traceset, this function:
316 * - registers a callback function to each hook
317 * - calls lttv_trace_find_hook() registers a hook function to event_by_id_hooks
318 * - calls lttvwindow_events_request() to request data in a specific
319 * time interval to the main window
320 *
321 */
322 static void FirstRequest(InterruptEventData *event_data )
323 {
324 guint i, k, l, nb_trace;
325
326 LttvTraceHook *hook;
327
328 guint ret;
329
330 LttvTraceState *ts;
331
332 GArray *hooks;
333
334 EventsRequest *events_request;
335
336 LttvTraceHookByFacility *thf;
337
338 LttvTracesetContext *tsc = lttvwindow_get_traceset_context(event_data->tab);
339
340
341 /* Get the traceset */
342 LttvTraceset *traceset = tsc->ts;
343
344 nb_trace = lttv_traceset_number(traceset);
345
346 /* There are many traces in a traceset. Iteration for each trace. */
347 for(i = 0; i<MIN(TRACE_NUMBER+1, nb_trace);i++)
348 {
349 events_request = g_new(EventsRequest, 1);
350
351 hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook));
352
353 hooks = g_array_set_size(hooks, 2);
354
355 event_data->hooks_trace_before = lttv_hooks_new();
356
357 /* Registers a hook function */
358 lttv_hooks_add(event_data->hooks_trace_before, trace_header, event_data, LTTV_PRIO_DEFAULT);
359
360 event_data->hooks_trace_after = lttv_hooks_new();
361
362 /* Registers a hook function */
363 lttv_hooks_add(event_data->hooks_trace_after, SecondRequest, event_data, LTTV_PRIO_DEFAULT);
364 /* Get a trace state */
365 ts = (LttvTraceState *)tsc->traces[i];
366 /* Create event_by_Id hooks */
367 event_data->event_by_id_hooks = lttv_hooks_by_id_new();
368
369 /*Register event_by_id_hooks with a callback function*/
370 ret = lttv_trace_find_hook(ts->parent.t,
371 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
372 LTT_FIELD_IRQ_ID, 0, 0,
373 FirstRequestIrqEntryCallback,
374 events_request,
375 &g_array_index(hooks, LttvTraceHook, 0));
376
377 ret = lttv_trace_find_hook(ts->parent.t,
378 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
379 LTT_FIELD_IRQ_ID, 0, 0,
380 FirstRequestIrqExitCallback,
381 events_request,
382 &g_array_index(hooks, LttvTraceHook, 1));
383
384 g_assert(!ret);
385 /*iterate through the facility list*/
386 for(k = 0 ; k < hooks->len; k++)
387 {
388 hook = &g_array_index(hooks, LttvTraceHook, k);
389 for(l=0; l<hook->fac_list->len; l++)
390 {
391 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
392 lttv_hooks_add(lttv_hooks_by_id_find(event_data->event_by_id_hooks, thf->id),
393 thf->h,
394 event_data,
395 LTTV_PRIO_DEFAULT);
396
397 }
398 }
399 /* Initalize the EventsRequest structure */
400 events_request->owner = event_data;
401 events_request->viewer_data = event_data;
402 events_request->servicing = FALSE;
403 events_request->start_time = event_data->time_window.start_time;
404 events_request->start_position = NULL;
405 events_request->stop_flag = FALSE;
406 events_request->end_time = event_data->time_window.end_time;
407 events_request->num_events = G_MAXUINT;
408 events_request->end_position = NULL;
409 events_request->trace = i;
410
411 events_request->hooks = hooks;
412
413 events_request->before_chunk_traceset = NULL;
414 events_request->before_chunk_trace = event_data->hooks_trace_before;
415 events_request->before_chunk_tracefile= NULL;
416 events_request->event = NULL;
417 events_request->event_by_id = event_data->event_by_id_hooks;
418 events_request->after_chunk_tracefile = NULL;
419 events_request->after_chunk_trace = NULL;
420 events_request->after_chunk_traceset = NULL;
421 events_request->before_request = NULL;
422 events_request->after_request = event_data->hooks_trace_after;
423
424 lttvwindow_events_request(event_data->tab, events_request);
425 }
426
427 }
428
429 /**
430 * This function is called whenever an irq_entry event occurs.
431 *
432 */
433 static gboolean FirstRequestIrqEntryCallback(void *hook_data, void *call_data)
434 {
435
436 LttTime event_time;
437 unsigned cpu_id;
438 irq_entry entry;
439 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
440 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
441 InterruptEventData *event_data = (InterruptEventData *)hook_data;
442 GArray* FirstRequestIrqEntry = event_data->FirstRequestIrqEntry;
443 LttEvent *e = ltt_tracefile_get_event(tfc->tf);
444 event_time = ltt_event_time(e);
445 cpu_id = ltt_event_cpu_id(e);
446
447
448 entry.id =get_interrupt_id(e);
449 entry.cpu_id = cpu_id;
450 entry.event_time = event_time;
451 g_array_append_val (FirstRequestIrqEntry, entry);
452
453 return FALSE;
454 }
455
456 /**
457 * This function gets the id of the interrupt. The id is stored in a dynamic structure.
458 * Refer to the print.c file for howto extract data from a dynamic structure.
459 */
460 static guint64 get_interrupt_id(LttEvent *e)
461 {
462 guint i, num_fields;
463 LttEventType *event_type;
464 LttField *element;
465 LttField *field;
466 guint64 irq_id;
467 event_type = ltt_event_eventtype(e);
468 num_fields = ltt_eventtype_num_fields(event_type);
469 for(i = 0 ; i < num_fields-1 ; i++)
470 {
471 field = ltt_eventtype_field(event_type, i);
472 irq_id = ltt_event_get_long_unsigned(e,field);
473 }
474 return irq_id;
475
476 }
477 /**
478 * This function is called whenever an irq_exit event occurs.
479 *
480 */
481 gboolean FirstRequestIrqExitCallback(void *hook_data, void *call_data)
482 {
483 LttTime event_time;
484 unsigned cpu_id;
485 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
486 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
487 InterruptEventData *event_data = (InterruptEventData *)hook_data;
488 LttEvent *e = ltt_tracefile_get_event(tfc->tf);
489 LttEventType *type = ltt_event_eventtype(e);
490 event_time = ltt_event_time(e);
491 cpu_id = ltt_event_cpu_id(e);
492
493 calcul_duration( event_time, cpu_id, event_data);
494 CalculateMaxIRQHandler();
495 return FALSE;
496 }
497
498 /**
499 * This function calculates the duration of an interrupt.
500 *
501 */
502 static void calcul_duration(LttTime time_exit, guint cpu_id,InterruptEventData *event_data)
503 {
504
505 gint i, irq_id;
506 irq_entry *element;
507 LttTime duration;
508 GArray *FirstRequestIrqExit = event_data->FirstRequestIrqExit;
509 GArray *FirstRequestIrqEntry = event_data->FirstRequestIrqEntry;
510 for(i = 0; i < FirstRequestIrqEntry->len; i++)
511 {
512 element = &g_array_index(FirstRequestIrqEntry,irq_entry,i);
513 if(element->cpu_id == cpu_id)
514 {
515 sum_interrupt_data(element,time_exit, FirstRequestIrqExit);
516 g_array_remove_index(FirstRequestIrqEntry, i);
517 break;
518 }
519 }
520 }
521
522 static void CalculateMaxIRQHandler()
523 {
524
525 }
526
527 /**
528 * This function calculates the total duration of an interrupt.
529 *
530 */
531 static void sum_interrupt_data(irq_entry *e, LttTime time_exit, GArray *FirstRequestIrqExit){
532 Irq irq;
533 Irq *element;
534 guint i;
535 LttTime duration;
536 gboolean notFound = FALSE;
537 memset ((void*)&irq, 0,sizeof(Irq));
538
539 /*first time*/
540 if(FirstRequestIrqExit->len == NO_ITEMS)
541 {
542 irq.cpu_id = e->cpu_id;
543 irq.id = e->id;
544 irq.frequency++;
545 irq.total_duration = ltt_time_sub(time_exit, e->event_time);
546 g_array_append_val (FirstRequestIrqExit, irq);
547 }
548 else
549 {
550 for(i = 0; i < FirstRequestIrqExit->len; i++)
551 {
552 element = &g_array_index(FirstRequestIrqExit,Irq,i);
553 if(element->id == e->id)
554 {
555 notFound = TRUE;
556 duration = ltt_time_sub(time_exit, e->event_time);
557 element->total_duration = ltt_time_add(element->total_duration, duration);
558 element->frequency++;
559 }
560 }
561 if(!notFound)
562 {
563 irq.cpu_id = e->cpu_id;
564 irq.id = e->id;
565 irq.frequency++;
566 irq.total_duration = ltt_time_sub(time_exit, e->event_time);
567 g_array_append_val (FirstRequestIrqExit, irq);
568 }
569 }
570 }
571
572 static gboolean SecondRequest(void *hook_data, void *call_data)
573 {
574
575 guint i, k, l, nb_trace;
576
577 LttvTraceHook *hook;
578
579 guint ret;
580
581 LttvTraceState *ts;
582
583 GArray *hooks;
584
585 EventsRequest *events_request;
586
587 LttvTraceHookByFacility *thf;
588
589 InterruptEventData *event_data = (InterruptEventData *)hook_data;
590
591 LttvTracesetContext *tsc = lttvwindow_get_traceset_context(event_data->tab);
592
593 CalculateAverageDurationForEachIrqId(event_data);
594
595 /* Get the traceset */
596 LttvTraceset *traceset = tsc->ts;
597
598 nb_trace = lttv_traceset_number(traceset);
599
600 /* There are many traces in a traceset. Iteration for each trace. */
601 for(i = 0; i<MIN(TRACE_NUMBER+1, nb_trace);i++)
602 {
603 events_request = g_new(EventsRequest, 1);
604
605 hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook));
606
607 hooks = g_array_set_size(hooks, 2);
608
609 event_data->hooks_trace_after = lttv_hooks_new();
610
611 /* Registers a hook function */
612 lttv_hooks_add(event_data->hooks_trace_after, DisplayViewer, event_data, LTTV_PRIO_DEFAULT);
613
614 /* Get a trace state */
615 ts = (LttvTraceState *)tsc->traces[i];
616 /* Create event_by_Id hooks */
617 event_data->event_by_id_hooks = lttv_hooks_by_id_new();
618
619 /*Register event_by_id_hooks with a callback function*/
620 ret = lttv_trace_find_hook(ts->parent.t,
621 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
622 LTT_FIELD_IRQ_ID, 0, 0,
623 SecondRequestIrqEntryCallback,
624 events_request,
625 &g_array_index(hooks, LttvTraceHook, 0));
626
627 ret = lttv_trace_find_hook(ts->parent.t,
628 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
629 LTT_FIELD_IRQ_ID, 0, 0,
630 SecondRequestIrqExitCallback,
631 events_request,
632 &g_array_index(hooks, LttvTraceHook, 1));
633
634 g_assert(!ret);
635 /*iterate through the facility list*/
636 for(k = 0 ; k < hooks->len; k++)
637 {
638 hook = &g_array_index(hooks, LttvTraceHook, k);
639 for(l=0; l<hook->fac_list->len; l++)
640 {
641 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
642 lttv_hooks_add(lttv_hooks_by_id_find(event_data->event_by_id_hooks, thf->id),
643 thf->h,
644 event_data,
645 LTTV_PRIO_DEFAULT);
646
647 }
648 }
649 /* Initalize the EventsRequest structure */
650 events_request->owner = event_data;
651 events_request->viewer_data = event_data;
652 events_request->servicing = FALSE;
653 events_request->start_time = event_data->time_window.start_time;
654 events_request->start_position = NULL;
655 events_request->stop_flag = FALSE;
656 events_request->end_time = event_data->time_window.end_time;
657 events_request->num_events = G_MAXUINT;
658 events_request->end_position = NULL;
659 events_request->trace = i;
660
661 events_request->hooks = hooks;
662
663 events_request->before_chunk_traceset = NULL;
664 events_request->before_chunk_trace = NULL;
665 events_request->before_chunk_tracefile= NULL;
666 events_request->event = NULL;
667 events_request->event_by_id = event_data->event_by_id_hooks;
668 events_request->after_chunk_tracefile = NULL;
669 events_request->after_chunk_trace = NULL;
670 events_request->after_chunk_traceset = NULL;
671 events_request->before_request = NULL;
672 events_request->after_request = event_data->hooks_trace_after;
673
674 lttvwindow_events_request(event_data->tab, events_request);
675 }
676
677
678 return FALSE;
679 }
680
681 static void CalculateAverageDurationForEachIrqId(InterruptEventData *event_data)
682 {
683 guint64 real_data;
684 Irq *element;
685 gint i;
686 GArray* FirstRequestIrqExit = event_data->FirstRequestIrqExit;
687 for(i = 0; i < FirstRequestIrqExit->len; i++)
688 {
689 element = &g_array_index(FirstRequestIrqExit,Irq,i);
690 real_data = element->total_duration.tv_sec;
691 real_data *= NANOSECONDS_PER_SECOND;
692 real_data += element->total_duration.tv_nsec;
693 element->average_duration = real_data / element->frequency;
694 printf("average duration: %d\n", element->average_duration);
695 }
696
697 }
698
699 static gboolean SecondRequestIrqEntryCallback(void *hook_data, void *call_data)
700 {
701
702 LttTime event_time;
703 unsigned cpu_id;
704 irq_entry entry;
705 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
706 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
707 InterruptEventData *event_data = (InterruptEventData *)hook_data;
708 GArray* SecondRequestIrqEntry = event_data->SecondRequestIrqEntry;
709 LttEvent *e = ltt_tracefile_get_event(tfc->tf);
710 event_time = ltt_event_time(e);
711 cpu_id = ltt_event_cpu_id(e);
712
713
714 entry.id =get_interrupt_id(e);
715 entry.cpu_id = cpu_id;
716 entry.event_time = event_time;
717 g_array_append_val (SecondRequestIrqEntry, entry);
718
719 return FALSE;
720 }
721
722 static gboolean SecondRequestIrqExitCallback(void *hook_data, void *call_data)
723 {
724
725 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
726 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
727 InterruptEventData *event_data = (InterruptEventData *)hook_data;
728 LttEvent *event = ltt_tracefile_get_event(tfc->tf);
729
730 CalculateXi(event, event_data);
731 return FALSE;
732 }
733
734 static void CalculateXi(LttEvent *event_irq_exit, InterruptEventData *event_data)
735 {
736 gint i, irq_id;
737 irq_entry *element;
738 LttTime Xi;
739 LttTime exit_time;
740 unsigned cpu_id;
741
742 GArray *SecondRequestIrqExit = event_data->SecondRequestIrqExit;
743 GArray *SecondRequestIrqEntry = event_data->SecondRequestIrqEntry;
744 cpu_id = ltt_event_cpu_id(event_irq_exit);
745 for(i = 0; i < SecondRequestIrqEntry->len; i++)
746 {
747 element = &g_array_index(SecondRequestIrqEntry,irq_entry,i);
748 if(element->cpu_id == cpu_id)
749 {
750
751 /* time calculation */
752 exit_time = ltt_event_time(event_irq_exit);
753 Xi = ltt_time_sub(exit_time, element->event_time);
754 irq_id = element->id;
755
756 SumItems(irq_id, Xi,event_data);
757 g_array_remove_index(SecondRequestIrqEntry, i);
758 break;
759 }
760 }
761 }
762
763 static void SumItems(gint irq_id, LttTime Xi, InterruptEventData *event_data)
764 {
765 gint i;
766 guint time_in_ns;
767
768 gint temp;
769 Irq *average;
770 SumId *sumItem;
771 SumId sum;
772 gboolean notFound = FALSE;
773 GArray *FirstRequestIrqExit = event_data->FirstRequestIrqExit;
774 GArray *SumArray = event_data->SumArray;
775 time_in_ns = Xi.tv_sec;
776 time_in_ns *= NANOSECONDS_PER_SECOND;
777 time_in_ns += Xi.tv_nsec;
778
779 for(i = 0; i < FirstRequestIrqExit->len; i++)
780 {
781 average = &g_array_index(FirstRequestIrqExit,Irq,i);
782 if(irq_id == average->id)
783 {
784 temp = time_in_ns - average->average_duration;
785 sum.sumOfDurations = pow (temp , 2);
786 //printf("one : %d\n", sum.sumOfDurations);
787 sum.irqId = irq_id;
788 sum.frequency = average->frequency;
789 if(event_data->SumArray->len == NO_ITEMS)
790 {
791 g_array_append_val (SumArray, sum);
792 }
793 else
794 {
795
796 for(i = 0; i < SumArray->len; i++)
797 {
798 sumItem = &g_array_index(SumArray, SumId, i);
799 if(sumItem->irqId == irq_id)
800 {
801 notFound = TRUE;
802 sumItem->sumOfDurations += sum.sumOfDurations;
803
804 }
805 }
806 if(!notFound)
807 {
808 g_array_append_val (SumArray, sum);
809 }
810
811
812 }
813
814 }
815 }
816 }
817
818 /**
819 * This function displays the result on the viewer
820 *
821 */
822 static gboolean DisplayViewer(void *hook_data, void *call_data)
823 {
824
825 guint average;
826 gint i;
827 Irq element;
828 LttTime average_duration;
829 GtkTreeIter iter;
830 guint64 real_data;
831 InterruptEventData *event_data = (InterruptEventData *)hook_data;
832 GArray *FirstRequestIrqExit = event_data->FirstRequestIrqExit;
833 gtk_list_store_clear(event_data->ListStore);
834 for(i = 0; i < FirstRequestIrqExit->len; i++)
835 {
836 element = g_array_index(FirstRequestIrqExit,Irq,i);
837 real_data = element.total_duration.tv_sec;
838 real_data *= NANOSECONDS_PER_SECOND;
839 real_data += element.total_duration.tv_nsec;
840 gtk_list_store_append (event_data->ListStore, &iter);
841 gtk_list_store_set (event_data->ListStore, &iter,
842 CPUID_COLUMN, element.cpu_id,
843 IRQ_ID_COLUMN, element.id,
844 FREQUENCY_COLUMN, element.frequency,
845 DURATION_COLUMN, real_data,
846 DURATION_STANDARD_DEV_COLUMN, CalculateStandardDeviation(element.id, event_data),
847 -1);
848
849 }
850
851
852
853 if(event_data->FirstRequestIrqExit->len)
854 {
855 g_array_remove_range (event_data->FirstRequestIrqExit,0,event_data->FirstRequestIrqExit->len);
856 }
857
858 if(event_data->FirstRequestIrqEntry->len)
859 {
860 g_array_remove_range (event_data->FirstRequestIrqEntry,0,event_data->FirstRequestIrqEntry->len);
861 }
862
863 if(event_data->SecondRequestIrqEntry->len)
864 {
865 g_array_remove_range (event_data->SecondRequestIrqEntry,0,event_data->SecondRequestIrqEntry->len);
866 }
867
868 if(event_data->SecondRequestIrqExit->len)
869 {
870 g_array_remove_range (event_data->SecondRequestIrqExit,0, event_data->SecondRequestIrqExit->len);
871 }
872
873 if(event_data->SumArray->len)
874 {
875 g_array_remove_range (event_data->SumArray,0, event_data->SumArray->len);
876 }
877
878 return FALSE;
879 }
880
881 static int CalculateStandardDeviation(gint id, InterruptEventData *event_data)
882 {
883 int i;
884 SumId sumId;
885 double inner_component;
886 int deviation = 0;
887 for(i = 0; i < event_data->SumArray->len; i++)
888 {
889 sumId = g_array_index(event_data->SumArray, SumId, i);
890 if(id == sumId.irqId)
891 {
892 printf("id: %d\n", sumId.irqId);
893 inner_component = sumId.sumOfDurations/ sumId.frequency;
894 deviation = sqrt(inner_component);
895 printf("deviation: %d\n", deviation);
896 return deviation;
897
898 }
899 }
900 return deviation;
901 }
902 /*
903 * This function is called by the main window
904 * when the time interval needs to be updated.
905 **/
906 gboolean interrupt_update_time_window(void * hook_data, void * call_data)
907 {
908 InterruptEventData *event_data = (InterruptEventData *) hook_data;
909 const TimeWindowNotifyData *time_window_nofify_data = ((const TimeWindowNotifyData *)call_data);
910 event_data->time_window = *time_window_nofify_data->new_time_window;
911 g_info("interrupts: interrupt_update_time_window()\n");
912 Tab *tab = event_data->tab;
913 lttvwindow_events_request_remove_all(tab, event_data);
914 FirstRequest(event_data );
915 return FALSE;
916 }
917
918
919 gboolean trace_header(void *hook_data, void *call_data)
920 {
921
922 InterruptEventData *event_data = (InterruptEventData *)hook_data;
923 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
924 LttEvent *e;
925 LttTime event_time;
926 return FALSE;
927 }
928
929 void interrupt_destroy_walk(gpointer data, gpointer user_data)
930 {
931 g_info("interrupt_destroy_walk");
932 interrupt_destructor((InterruptEventData*)data);
933
934 }
935
936 void interrupt_destructor(InterruptEventData *event_viewer_data)
937 {
938 /* May already been done by GTK window closing */
939 g_info("enter interrupt_destructor \n");
940 if(GTK_IS_WIDGET(event_viewer_data->Hbox))
941 {
942 gtk_widget_destroy(event_viewer_data->Hbox);
943 }
944 }
945
946 /**
947 * plugin's destroy function
948 *
949 * This function releases the memory reserved by the module and unregisters
950 * everything that has been registered in the gtkTraceSet API.
951 */
952 static void destroy()
953 {
954
955 g_info("Destroy interrupts");
956 g_slist_foreach(interrupt_data_list, interrupt_destroy_walk, NULL );
957 g_slist_free(interrupt_data_list);
958 lttvwindow_unregister_constructor(interrupts);
959
960 }
961
962 LTTV_MODULE("interrupts", "interrupts info view", \
963 "Graphical module to display interrupts performance", \
964 init, destroy, "lttvwindow")
This page took 0.049173 seconds and 5 git commands to generate.