bea4a10214089869cf35bff73a5d21f4a5cae284
[lttv.git] / lttv / 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
21 Each field of the interrupt viewer is summarized as follows:
22
23 - CPUID: processor ID
24
25 - IrqId: IRQ ID
26
27 - Frequency (Hz): the number of interrupts per second (Hz).
28 We compute the total number of interrupts. Then
29 we divide it by the time interval.
30
31 - Total Duration (nsec): the sum of each interrupt duration in nsec.
32 For a given Irq ID, we sum the duration of each interrupt
33 to give us the total duration
34
35 - Duration Standard_deviation = sqrt(1/N Sum ((xi -Xa)^2)) where
36 N: number of interrupts
37 xi: duration of an interrupt (nsec)
38 Xa: average duration (nsec)
39 The formula is taken from wikipedia: http://en.wikipedia.org/wiki/Standard_deviation.
40 To calculate the duration standard deviation, we make two EventsRequest passes to the main window.
41 In the first EventsRequest pass, we calculate the total number of interrupts to compute for
42 the average Xa. In the second EventsRequest pass, calculate the standard deviation.
43
44
45 - Max IRQ handler duration (nsec) [time interval]: the longest IRQ handler duration in nsec.
46
47 - Min IRQ handler duration (nsec) [time interval]: the shortest IRQ handler duration in nsec.
48
49 - Average period (nsec): 1/Frequency(in HZ). The frequency is computed above.
50
51 -Period Standard_deviation = sqrt(1/N Sum ((xi -Xa)^2)) where
52 N: number of interrupts
53 xi: duration of an interrupt
54 Xa: Period = 1/Frequency (in Hz)
55
56 -Frequency Standard_deviation = sqrt(1/N Sum ((xi -Xa)^2))
57 N: number of interrupts
58 xi: duration of an interrupt
59 Xa: Frequency (Hz)
60
61
62 *******************************************************************/
63
64
65
66 #include <math.h>
67 #include <glib.h>
68 #include <gtk/gtk.h>
69 #include <gdk/gdk.h>
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <math.h>
73 #include <string.h>
74 #include <ltt/ltt.h>
75 #include <ltt/event.h>
76 #include <ltt/trace.h>
77 #include <lttv/module.h>
78 #include <lttv/hook.h>
79 #include <lttv/tracecontext.h>
80 #include <lttv/state.h>
81 #include <lttv/filter.h>
82 #include <lttvwindow/lttvwindow.h>
83 #include <lttvwindow/lttv_plugin_tab.h>
84 #include <ltt/time.h>
85
86 #include "hInterruptsInsert.xpm"
87
88 #define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
89 #define NO_ITEMS 0
90
91 typedef struct
92 {
93 LttTime duration;
94 LttTime start_time;
95 LttTime end_time;
96 }IrqDuration;
97
98 typedef struct {
99 guint cpu_id;
100 guint id;
101 guint TotalNumberOfInterrupts;
102 LttTime total_duration;
103 guint average_duration;
104 IrqDuration max_irq_handler;
105 IrqDuration min_irq_handler;
106 }Irq;
107
108 typedef struct {
109 guint id;
110 guint cpu_id;
111 LttTime event_time;
112 }irq_entry;
113
114
115 typedef struct
116 {
117 guint irqId;
118 guint TotalNumberOfInterrupts;//frequency;//
119 guint64 sumOfDurations; // to store the Sum ((xi -Xa)^2) of the duration Standard deviation
120 guint64 sumOfPeriods; // to store the Sum ((xi -Xa)^2) of the period Standard deviation
121 guint64 sumOfFrequencies;// to store the Sum ((xi -Xa)^2) of the frequency Standard deviation
122
123 }SumId;
124
125 enum type_t {
126 IRQ_ENTRY,
127 IRQ_EXIT
128 };
129
130 /** Array containing instanced objects. Used when module is unloaded */
131 static GSList *interrupt_data_list = NULL ;
132
133
134 //fixed #define TRACE_NUMBER 0
135
136 typedef struct _InterruptEventData {
137
138 /*Graphical Widgets */
139 GtkWidget * ScrollWindow;
140 GtkListStore *ListStore;
141 GtkWidget *Hbox;
142 GtkWidget *TreeView;
143 GtkTreeSelection *SelectionTree;
144
145 Tab * tab; /* tab that contains this plug-in*/
146 LttvPluginTab *ptab;
147 LttvHooks * event_hooks;
148 LttvHooks * hooks_trace_after;
149 LttvHooks * hooks_trace_before;
150 TimeWindow time_window;
151 LttvHooksByIdChannelArray * event_by_id_hooks;
152 GArray *FirstRequestIrqExit;
153 GArray *FirstRequestIrqEntry;
154 GArray *SecondRequestIrqEntry;
155 GArray *SecondRequestIrqExit;
156 GArray *SumArray;
157
158 } InterruptEventData ;
159
160
161 /* Function prototypes */
162
163 static gboolean interrupt_update_time_window(void * hook_data, void * call_data);
164 static GtkWidget *interrupts(LttvPlugin *plugin);
165 static InterruptEventData *system_info(LttvPluginTab *ptab);
166 void interrupt_destructor(InterruptEventData *event_viewer_data);
167 static void FirstRequest(InterruptEventData *event_data );
168 static gboolean trace_header(void *hook_data, void *call_data);
169 static gboolean DisplayViewer (void *hook_data, void *call_data);
170 static void CalculateData(LttTime time_exit, guint cpu_id, InterruptEventData *event_data);
171 static void CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(irq_entry *e, LttTime time_exit, GArray *FirstRequestIrqExit);
172 static gboolean FirstRequestIrqEntryCallback(void *hook_data, void *call_data);
173 static gboolean FirstRequestIrqExitCallback(void *hook_data, void *call_data);
174 static gboolean SecondRequest(void *hook_data, void *call_data);
175 static void CalculateAverageDurationForEachIrqId(InterruptEventData *event_data);
176 static gboolean SecondRequestIrqEntryCallback(void *hook_data, void *call_data);
177 static gboolean SecondRequestIrqExitCallback(void *hook_data, void *call_data);
178 static void CalculateXi(LttEvent *event, InterruptEventData *event_data, guint cpu_id);
179 static void SumItems(gint irq_id, LttTime Xi, InterruptEventData *event_data);
180 static int CalculateDurationStandardDeviation(gint id, InterruptEventData *event_data);
181 static int CalculatePeriodStandardDeviation(gint id, InterruptEventData *event_data);
182 static int FrequencyInHZ(gint NumberOfInterruptions, TimeWindow time_window);
183 static guint64 CalculatePeriodInnerPart(guint Xi, guint FrequencyHZ);
184 static guint64 CalculateFrequencyInnerPart(guint Xi_in_ns, guint FrequencyHZ);
185 static void InterruptFree(InterruptEventData *event_viewer_data);
186 static int CalculateFrequencyStandardDeviation(gint id, InterruptEventData *event_data);
187
188 /* Enumeration of the columns */
189 enum{
190 CPUID_COLUMN,
191 IRQ_ID_COLUMN,
192 FREQUENCY_COLUMN,
193 DURATION_COLUMN,
194 DURATION_STANDARD_DEV_COLUMN,
195 MAX_IRQ_HANDLER_COLUMN,
196 MIN_IRQ_HANDLER_COLUMN,
197 AVERAGE_PERIOD,
198 PERIOD_STANDARD_DEV_COLUMN,
199 FREQUENCY_STANDARD_DEV_COLUMN,
200 N_COLUMNS
201 };
202
203
204
205 /**
206 * init function
207 *
208 *
209 * This is the entry point of the viewer.
210 *
211 */
212 static void init() {
213 g_info("interrupts: init()");
214 lttvwindow_register_constructor("interrupts",
215 "/",
216 "Insert Interrupts View",
217 hInterruptsInsert_xpm,
218 "Insert Interrupts View",
219 interrupts);
220
221 }
222
223
224 /**
225 * Constructor hook
226 *
227 */
228 static GtkWidget *interrupts(LttvPlugin *plugin)
229 {
230 LttvPluginTab *ptab = LTTV_PLUGIN_TAB(plugin);
231 InterruptEventData* event_data = system_info(ptab) ;
232 if(event_data)
233 return event_data->Hbox;
234 else
235 return NULL;
236 }
237
238 /**
239 * This function initializes the Event Viewer functionnality through the
240 * GTK API.
241 */
242 InterruptEventData *system_info(LttvPluginTab *ptab)
243 {
244
245 LttTime end;
246 GtkTreeViewColumn *column;
247 GtkCellRenderer *renderer;
248 InterruptEventData* event_viewer_data = g_new(InterruptEventData,1) ;
249 Tab *tab = ptab->tab;
250 event_viewer_data->ptab = ptab;
251 event_viewer_data->tab = tab;
252
253 /*Get the current time frame from the main window */
254 event_viewer_data->time_window = lttvwindow_get_time_window(tab);
255
256 event_viewer_data->FirstRequestIrqExit = g_array_new(FALSE, FALSE, sizeof(Irq));
257 event_viewer_data->FirstRequestIrqEntry = g_array_new(FALSE, FALSE, sizeof(irq_entry));
258
259 event_viewer_data->SecondRequestIrqEntry = g_array_new(FALSE, FALSE, sizeof(irq_entry));
260 event_viewer_data->SecondRequestIrqExit = g_array_new(FALSE, FALSE, sizeof(Irq));
261
262 event_viewer_data->SumArray = g_array_new(FALSE, FALSE, sizeof(SumId));
263
264
265 /*Create tha main window for the viewer */
266 event_viewer_data->ScrollWindow = gtk_scrolled_window_new (NULL, NULL);
267 gtk_widget_show (event_viewer_data->ScrollWindow);
268 gtk_scrolled_window_set_policy(
269 GTK_SCROLLED_WINDOW(event_viewer_data->ScrollWindow),
270 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC/*GTK_POLICY_NEVER*/);
271
272 /* Create a model for storing the data list */
273 event_viewer_data->ListStore = gtk_list_store_new (
274 N_COLUMNS, /* Total number of columns */
275 G_TYPE_INT, /* CPUID */
276 G_TYPE_INT, /* IRQ_ID */
277 G_TYPE_INT, /* Frequency */
278 G_TYPE_UINT64, /* Duration */
279 G_TYPE_INT, /* standard deviation */
280 G_TYPE_STRING, /* Max IRQ handler */
281 G_TYPE_STRING, /* Min IRQ handler */
282 G_TYPE_INT, /* Average period */
283 G_TYPE_INT, /* period standard deviation */
284 G_TYPE_INT /* frequency standard deviation */
285
286 );
287
288 event_viewer_data->TreeView = gtk_tree_view_new_with_model (GTK_TREE_MODEL (event_viewer_data->ListStore));
289
290 g_object_unref (G_OBJECT (event_viewer_data->ListStore));
291
292 renderer = gtk_cell_renderer_text_new ();
293 column = gtk_tree_view_column_new_with_attributes ("CPU ID",
294 renderer,
295 "text", CPUID_COLUMN,
296 NULL);
297 gtk_tree_view_column_set_alignment (column, 0.0);
298 gtk_tree_view_column_set_fixed_width (column, 45);
299 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
300
301
302 renderer = gtk_cell_renderer_text_new ();
303 column = gtk_tree_view_column_new_with_attributes ("IRQ ID",
304 renderer,
305 "text", IRQ_ID_COLUMN,
306 NULL);
307 gtk_tree_view_column_set_alignment (column, 0.0);
308 gtk_tree_view_column_set_fixed_width (column, 220);
309 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
310
311 renderer = gtk_cell_renderer_text_new ();
312 column = gtk_tree_view_column_new_with_attributes ("Frequency (Hz)",
313 renderer,
314 "text", FREQUENCY_COLUMN,
315 NULL);
316 gtk_tree_view_column_set_alignment (column, 1.0);
317 gtk_tree_view_column_set_fixed_width (column, 220);
318 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
319
320 renderer = gtk_cell_renderer_text_new ();
321 column = gtk_tree_view_column_new_with_attributes ("Total Duration (nsec)",
322 renderer,
323 "text", DURATION_COLUMN,
324 NULL);
325 gtk_tree_view_column_set_alignment (column, 0.0);
326 gtk_tree_view_column_set_fixed_width (column, 145);
327 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
328
329
330 renderer = gtk_cell_renderer_text_new ();
331 column = gtk_tree_view_column_new_with_attributes ("Duration standard deviation (nsec)",
332 renderer,
333 "text", DURATION_STANDARD_DEV_COLUMN,
334 NULL);
335 gtk_tree_view_column_set_alignment (column, 0.0);
336 gtk_tree_view_column_set_fixed_width (column, 200);
337 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
338
339 renderer = gtk_cell_renderer_text_new ();
340 column = gtk_tree_view_column_new_with_attributes ("Max IRQ handler duration (nsec) [time interval]",
341 renderer,
342 "text", MAX_IRQ_HANDLER_COLUMN,
343 NULL);
344 gtk_tree_view_column_set_alignment (column, 0.0);
345 gtk_tree_view_column_set_fixed_width (column, 250);
346 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
347
348 renderer = gtk_cell_renderer_text_new ();
349 column = gtk_tree_view_column_new_with_attributes ("Min IRQ handler duration (nsec) [time interval]",
350 renderer,
351 "text", MIN_IRQ_HANDLER_COLUMN,
352 NULL);
353 gtk_tree_view_column_set_alignment (column, 0.0);
354 gtk_tree_view_column_set_fixed_width (column, 250);
355 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
356
357 renderer = gtk_cell_renderer_text_new ();
358 column = gtk_tree_view_column_new_with_attributes (" Average period (nsec)",
359 renderer,
360 "text", AVERAGE_PERIOD,
361 NULL);
362 gtk_tree_view_column_set_alignment (column, 0.0);
363 gtk_tree_view_column_set_fixed_width (column, 200);
364 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
365
366 renderer = gtk_cell_renderer_text_new ();
367 column = gtk_tree_view_column_new_with_attributes ("Period standard deviation (nsec)",
368 renderer,
369 "text", PERIOD_STANDARD_DEV_COLUMN,
370 NULL);
371 gtk_tree_view_column_set_alignment (column, 0.0);
372 gtk_tree_view_column_set_fixed_width (column, 200);
373 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
374
375 renderer = gtk_cell_renderer_text_new ();
376 column = gtk_tree_view_column_new_with_attributes ("Frequency standard deviation (Hz)",
377 renderer,
378 "text", FREQUENCY_STANDARD_DEV_COLUMN,
379 NULL);
380 gtk_tree_view_column_set_alignment (column, 0.0);
381 gtk_tree_view_column_set_fixed_width (column, 200);
382 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
383
384
385 event_viewer_data->SelectionTree = gtk_tree_view_get_selection (GTK_TREE_VIEW (event_viewer_data->TreeView));
386 gtk_tree_selection_set_mode (event_viewer_data->SelectionTree, GTK_SELECTION_SINGLE);
387
388 gtk_container_add (GTK_CONTAINER (event_viewer_data->ScrollWindow), event_viewer_data->TreeView);
389
390 event_viewer_data->Hbox = gtk_hbox_new(0, 0);
391 gtk_box_pack_start(GTK_BOX(event_viewer_data->Hbox), event_viewer_data->ScrollWindow, TRUE, TRUE, 0);
392
393 gtk_widget_show(event_viewer_data->Hbox);
394 gtk_widget_show(event_viewer_data->TreeView);
395
396 interrupt_data_list = g_slist_append(interrupt_data_list, event_viewer_data);
397 /* Registration for time notification */
398 lttvwindow_register_time_window_notify(tab,
399 interrupt_update_time_window,
400 event_viewer_data);
401
402 g_object_set_data_full(G_OBJECT(event_viewer_data->Hbox),
403 "event_data",
404 event_viewer_data,
405 (GDestroyNotify) InterruptFree);
406
407 FirstRequest(event_viewer_data );
408 return event_viewer_data;
409 }
410
411
412 /**
413 *
414 * For each trace in the traceset, this function:
415 * - registers a callback function to each hook
416 * - calls lttv_trace_find_hook() registers a hook function to event_by_id_hooks
417 * - calls lttvwindow_events_request() to request data in a specific
418 * time interval to the main window
419 *
420 */
421 static void FirstRequest(InterruptEventData *event_data )
422 {
423 guint i, k, l, nb_trace;
424
425 LttvTraceHook *hook;
426
427 guint ret;
428
429 LttvTraceState *ts;
430
431 GArray *hooks;
432
433 EventsRequest *events_request;
434
435 LttvTraceHook *th;
436
437 LttvTracesetContext *tsc = lttvwindow_get_traceset_context(event_data->tab);
438
439
440 /* Get the traceset */
441 LttvTraceset *traceset = tsc->ts;
442
443 nb_trace = lttv_traceset_number(traceset);
444
445 /* There are many traces in a traceset. Iteration for each trace. */
446 //for(i = 0; i<MIN(TRACE_NUMBER+1, nb_trace);i++) {
447 for(i = 0 ; i < nb_trace ; i++) {
448 events_request = g_new(EventsRequest, 1);
449
450 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 2);
451
452 event_data->hooks_trace_before = lttv_hooks_new();
453
454 /* Registers a hook function */
455 lttv_hooks_add(event_data->hooks_trace_before, trace_header, event_data, LTTV_PRIO_DEFAULT);
456
457 event_data->hooks_trace_after = lttv_hooks_new();
458
459 /* Registers a hook function */
460 lttv_hooks_add(event_data->hooks_trace_after, SecondRequest, event_data, LTTV_PRIO_DEFAULT);
461 /* Get a trace state */
462 ts = (LttvTraceState *)tsc->traces[i];
463 /* Create event_by_Id hooks */
464 event_data->event_by_id_hooks = lttv_hooks_by_id_channel_new();
465
466 /*Register event_by_id_hooks with a callback function*/
467 lttv_trace_find_hook(ts->parent.t,
468 LTT_CHANNEL_KERNEL,
469 LTT_EVENT_IRQ_ENTRY,
470 FIELD_ARRAY(LTT_FIELD_IRQ_ID),
471 FirstRequestIrqEntryCallback,
472 events_request,
473 &hooks);
474
475 lttv_trace_find_hook(ts->parent.t,
476 LTT_CHANNEL_KERNEL,
477 LTT_EVENT_IRQ_EXIT,
478 NULL,
479 FirstRequestIrqExitCallback,
480 events_request,
481 &hooks);
482
483 /*iterate through the facility list*/
484 for(k = 0 ; k < hooks->len; k++)
485 {
486 th = &g_array_index(hooks, LttvTraceHook, k);
487 lttv_hooks_add(lttv_hooks_by_id_channel_find(
488 event_data->event_by_id_hooks,
489 th->channel, th->id),
490 th->h,
491 th,
492 LTTV_PRIO_DEFAULT);
493
494 }
495 /* Initalize the EventsRequest structure */
496 events_request->owner = event_data;
497 events_request->viewer_data = event_data;
498 events_request->servicing = FALSE;
499 events_request->start_time = event_data->time_window.start_time;
500 events_request->start_position = NULL;
501 events_request->stop_flag = FALSE;
502 events_request->end_time = event_data->time_window.end_time;
503 events_request->num_events = G_MAXUINT;
504 events_request->end_position = NULL;
505 events_request->trace = i;
506
507 events_request->hooks = hooks;
508
509 events_request->before_chunk_traceset = NULL;
510 events_request->before_chunk_trace = event_data->hooks_trace_before;
511 events_request->before_chunk_tracefile= NULL;
512 events_request->event = NULL;
513 events_request->event_by_id_channel = event_data->event_by_id_hooks;
514 events_request->after_chunk_tracefile = NULL;
515 events_request->after_chunk_trace = NULL;
516 events_request->after_chunk_traceset = NULL;
517 events_request->before_request = NULL;
518 events_request->after_request = event_data->hooks_trace_after;
519
520 lttvwindow_events_request(event_data->tab, events_request);
521 }
522
523 }
524
525 /**
526 * This function is called whenever an irq_entry event occurs.
527 *
528 */
529 static gboolean FirstRequestIrqEntryCallback(void *hook_data, void *call_data)
530 {
531
532 LttTime event_time;
533 unsigned cpu_id;
534 irq_entry entry;
535 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
536 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
537 LttvTraceHook *th = (LttvTraceHook*) hook_data;
538 EventsRequest *events_request = (EventsRequest*)th->hook_data;
539 InterruptEventData *event_data = events_request->viewer_data;
540 GArray* FirstRequestIrqEntry = event_data->FirstRequestIrqEntry;
541 LttEvent *e = ltt_tracefile_get_event(tfc->tf);
542 event_time = ltt_event_time(e);
543 cpu_id = tfs->cpu;
544
545
546 entry.id = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 0));
547 entry.cpu_id = cpu_id;
548 entry.event_time = event_time;
549 g_array_append_val (FirstRequestIrqEntry, entry);
550
551 return FALSE;
552 }
553
554 /**
555 * This function is called whenever an irq_exit event occurs.
556 *
557 */
558 gboolean FirstRequestIrqExitCallback(void *hook_data, void *call_data)
559 {
560 LttTime event_time;
561 unsigned cpu_id;
562 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
563 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
564 LttvTraceHook *th = (LttvTraceHook*) hook_data;
565 EventsRequest *events_request = (EventsRequest*)th->hook_data;
566 InterruptEventData *event_data = events_request->viewer_data;
567 LttEvent *e = ltt_tracefile_get_event(tfc->tf);
568 event_time = ltt_event_time(e);
569 cpu_id = tfs->cpu;
570
571 CalculateData( event_time, cpu_id, event_data);
572
573 return FALSE;
574 }
575
576 /**
577 * This function calculates the duration of an interrupt.
578 *
579 */
580 static void CalculateData(LttTime time_exit, guint cpu_id,InterruptEventData *event_data)
581 {
582
583 gint i, irq_id;
584 irq_entry *element;
585 LttTime duration;
586 GArray *FirstRequestIrqExit = event_data->FirstRequestIrqExit;
587 GArray *FirstRequestIrqEntry = event_data->FirstRequestIrqEntry;
588 for(i = FirstRequestIrqEntry->len-1; i >=0; i--)
589 {
590 element = &g_array_index(FirstRequestIrqEntry,irq_entry,i);
591 if(element->cpu_id == cpu_id)
592 {
593 CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(element,time_exit, FirstRequestIrqExit);
594 g_array_remove_index(FirstRequestIrqEntry, i);
595 break;
596 }
597 }
598 }
599
600
601 /**
602 * This function calculates the total duration of an interrupt and the longest & shortest Irq handlers.
603 *
604 */
605 static void CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(irq_entry *e, LttTime time_exit, GArray *FirstRequestIrqExit)
606 {
607 Irq irq;
608 Irq *element;
609 guint i;
610 LttTime duration;
611 gboolean notFound = FALSE;
612 memset ((void*)&irq, 0,sizeof(Irq));
613
614 /*first time*/
615 if(FirstRequestIrqExit->len == NO_ITEMS)
616 {
617 irq.cpu_id = e->cpu_id;
618 irq.id = e->id;
619 irq.TotalNumberOfInterrupts++;
620 irq.total_duration = ltt_time_sub(time_exit, e->event_time);
621
622 irq.max_irq_handler.start_time = e->event_time;
623 irq.max_irq_handler.end_time = time_exit;
624 irq.max_irq_handler.duration = ltt_time_sub(time_exit, e->event_time);
625
626 irq.min_irq_handler.start_time = e->event_time;
627 irq.min_irq_handler.end_time = time_exit;
628 irq.min_irq_handler.duration = ltt_time_sub(time_exit, e->event_time);
629
630 g_array_append_val (FirstRequestIrqExit, irq);
631 }
632 else
633 {
634 for(i = 0; i < FirstRequestIrqExit->len; i++)
635 {
636 element = &g_array_index(FirstRequestIrqExit,Irq,i);
637 if(element->id == e->id)
638 {
639 notFound = TRUE;
640 duration = ltt_time_sub(time_exit, e->event_time);
641 element->total_duration = ltt_time_add(element->total_duration, duration);
642 element->TotalNumberOfInterrupts++;
643 // Max irq handler
644 if(ltt_time_compare(duration,element->max_irq_handler.duration) > 0)
645 {
646 element->max_irq_handler.duration = duration;
647 element->max_irq_handler.start_time = e->event_time;
648 element->max_irq_handler.end_time = time_exit;
649 }
650 // Min irq handler
651 if(ltt_time_compare(duration,element->min_irq_handler.duration) < 0)
652 {
653 element->min_irq_handler.duration = duration;
654 element->min_irq_handler.start_time = e->event_time;
655 element->min_irq_handler.end_time = time_exit;
656 }
657 }
658 }
659 if(!notFound)
660 {
661 irq.cpu_id = e->cpu_id;
662 irq.id = e->id;
663 irq.TotalNumberOfInterrupts++;
664 irq.total_duration = ltt_time_sub(time_exit, e->event_time);
665 // Max irq handler
666 irq.max_irq_handler.start_time = e->event_time;
667 irq.max_irq_handler.end_time = time_exit;
668 irq.max_irq_handler.duration = ltt_time_sub(time_exit, e->event_time);
669 // Min irq handler
670 irq.min_irq_handler.start_time = e->event_time;
671 irq.min_irq_handler.end_time = time_exit;
672 irq.min_irq_handler.duration = ltt_time_sub(time_exit, e->event_time);
673
674 g_array_append_val (FirstRequestIrqExit, irq);
675 }
676 }
677 }
678
679 /**
680 * This function passes the second EventsRequest to LTTV
681 *
682 */
683 static gboolean SecondRequest(void *hook_data, void *call_data)
684 {
685
686 guint i, k, l, nb_trace;
687
688 LttvTraceHook *hook;
689
690 guint ret;
691
692 LttvTraceState *ts;
693
694 GArray *hooks;
695
696 EventsRequest *events_request;
697
698 LttvTraceHook *th;
699
700 InterruptEventData *event_data = (InterruptEventData *)hook_data;
701
702 LttvTracesetContext *tsc = lttvwindow_get_traceset_context(event_data->tab);
703
704 CalculateAverageDurationForEachIrqId(event_data);
705
706 /* Get the traceset */
707 LttvTraceset *traceset = tsc->ts;
708
709 nb_trace = lttv_traceset_number(traceset);
710
711 /* There are many traces in a traceset. Iteration for each trace. */
712 for(i = 0 ; i < nb_trace ; i++) {
713 // fixed for(i = 0; i<MIN(TRACE_NUMBER+1, nb_trace);i++) {
714 events_request = g_new(EventsRequest, 1);
715
716 hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 2);
717
718 event_data->hooks_trace_after = lttv_hooks_new();
719
720 /* Registers a hook function */
721 lttv_hooks_add(event_data->hooks_trace_after, DisplayViewer, event_data, LTTV_PRIO_DEFAULT);
722
723 /* Get a trace state */
724 ts = (LttvTraceState *)tsc->traces[i];
725 /* Create event_by_Id hooks */
726 event_data->event_by_id_hooks = lttv_hooks_by_id_channel_new();
727
728 /*Register event_by_id_hooks with a callback function*/
729 ret = lttv_trace_find_hook(ts->parent.t,
730 LTT_CHANNEL_KERNEL,
731 LTT_EVENT_IRQ_ENTRY,
732 FIELD_ARRAY(LTT_FIELD_IRQ_ID),
733 SecondRequestIrqEntryCallback,
734 events_request,
735 &hooks);
736
737 ret = lttv_trace_find_hook(ts->parent.t,
738 LTT_CHANNEL_KERNEL,
739 LTT_EVENT_IRQ_EXIT,
740 NULL,
741 SecondRequestIrqExitCallback,
742 events_request,
743 &hooks);
744
745 g_assert(!ret);
746
747 /* iterate through the facility list */
748 for(k = 0 ; k < hooks->len; k++)
749 {
750 th = &g_array_index(hooks, LttvTraceHook, k);
751 lttv_hooks_add(lttv_hooks_by_id_channel_find(
752 event_data->event_by_id_hooks,
753 th->channel, th->id),
754 th->h,
755 th,
756 LTTV_PRIO_DEFAULT);
757
758 }
759 /* Initalize the EventsRequest structure */
760 events_request->owner = event_data;
761 events_request->viewer_data = event_data;
762 events_request->servicing = FALSE;
763 events_request->start_time = event_data->time_window.start_time;
764 events_request->start_position = NULL;
765 events_request->stop_flag = FALSE;
766 events_request->end_time = event_data->time_window.end_time;
767 events_request->num_events = G_MAXUINT;
768 events_request->end_position = NULL;
769 events_request->trace = i;
770
771 events_request->hooks = hooks;
772
773 events_request->before_chunk_traceset = NULL;
774 events_request->before_chunk_trace = NULL;
775 events_request->before_chunk_tracefile= NULL;
776 events_request->event = NULL;
777 events_request->event_by_id_channel = event_data->event_by_id_hooks;
778 events_request->after_chunk_tracefile = NULL;
779 events_request->after_chunk_trace = NULL;
780 events_request->after_chunk_traceset = NULL;
781 events_request->before_request = NULL;
782 events_request->after_request = event_data->hooks_trace_after;
783
784 lttvwindow_events_request(event_data->tab, events_request);
785 }
786 return FALSE;
787 }
788
789 /**
790 * This function calculates the average duration for each Irq Id
791 *
792 */
793 static void CalculateAverageDurationForEachIrqId(InterruptEventData *event_data)
794 {
795 guint64 real_data;
796 Irq *element;
797 gint i;
798 GArray* FirstRequestIrqExit = event_data->FirstRequestIrqExit;
799 for(i = 0; i < FirstRequestIrqExit->len; i++)
800 {
801 element = &g_array_index(FirstRequestIrqExit,Irq,i);
802 real_data = element->total_duration.tv_sec;
803 real_data *= NANOSECONDS_PER_SECOND;
804 real_data += element->total_duration.tv_nsec;
805 if(element->TotalNumberOfInterrupts != 0)
806 element->average_duration = real_data / element->TotalNumberOfInterrupts;
807 else
808 element->average_duration = 0;
809 }
810
811 }
812
813 /**
814 * This function is called whenever an irq_entry event occurs. Use in the second request
815 *
816 */
817 static gboolean SecondRequestIrqEntryCallback(void *hook_data, void *call_data)
818 {
819
820 LttTime event_time;
821 unsigned cpu_id;
822 irq_entry entry;
823 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
824 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
825 LttvTraceHook *th = (LttvTraceHook *)hook_data;
826 EventsRequest *events_request = (EventsRequest*)th->hook_data;
827 InterruptEventData *event_data = events_request->viewer_data;
828 GArray* SecondRequestIrqEntry = event_data->SecondRequestIrqEntry;
829 LttEvent *e = ltt_tracefile_get_event(tfc->tf);
830 event_time = ltt_event_time(e);
831 cpu_id = tfs->cpu;
832
833
834 entry.id = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 0));
835 entry.cpu_id = cpu_id;
836 entry.event_time = event_time;
837 g_array_append_val (SecondRequestIrqEntry, entry);
838
839 return FALSE;
840 }
841
842 /**
843 * This function is called whenever an irq_exit event occurs in the second request.
844 *
845 */
846 static gboolean SecondRequestIrqExitCallback(void *hook_data, void *call_data)
847 {
848
849 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
850 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
851 LttvTraceHook *th = (LttvTraceHook *)hook_data;
852 EventsRequest *events_request = (EventsRequest*)th->hook_data;
853 InterruptEventData *event_data = events_request->viewer_data;
854
855 LttEvent *event = ltt_tracefile_get_event(tfc->tf);
856
857 CalculateXi(event, event_data, tfs->cpu);
858 return FALSE;
859 }
860
861
862 /**
863 * This function is called whenever an irq_exit event occurs in the second request.
864 *
865 */
866 static void CalculateXi(LttEvent *event_irq_exit, InterruptEventData *event_data, guint cpu_id)
867 {
868 gint i, irq_id;
869 irq_entry *element;
870 LttTime Xi;
871 LttTime exit_time;
872
873 GArray *SecondRequestIrqExit = event_data->SecondRequestIrqExit;
874 GArray *SecondRequestIrqEntry = event_data->SecondRequestIrqEntry;
875 for(i = 0; i < SecondRequestIrqEntry->len; i++)
876 {
877 element = &g_array_index(SecondRequestIrqEntry,irq_entry,i);
878 if(element->cpu_id == cpu_id)
879 {
880
881 /* time calculation */
882 exit_time = ltt_event_time(event_irq_exit);
883 Xi = ltt_time_sub(exit_time, element->event_time);
884 irq_id = element->id;
885
886 SumItems(irq_id, Xi,event_data);
887 g_array_remove_index(SecondRequestIrqEntry, i);
888 break;
889 }
890 }
891 }
892
893
894 /**
895 * This function computes the Sum ((xi -Xa)^2) and store the result in SumArray
896 *
897 */
898 static void SumItems(gint irq_id, LttTime Xi, InterruptEventData *event_data)
899 {
900 gint i;
901 guint Xi_in_ns;
902
903 gint duration_inner_part;
904 guint64 period_inner_part;
905 guint64 frequency_inner_part;
906
907 Irq *average;
908 SumId *sumItem;
909 SumId sum;
910 int FrequencyHZ = 0;
911 gboolean notFound = FALSE;
912 GArray *FirstRequestIrqExit = event_data->FirstRequestIrqExit;
913 GArray *SumArray = event_data->SumArray;
914 Xi_in_ns = Xi.tv_sec;
915 Xi_in_ns *= NANOSECONDS_PER_SECOND;
916 Xi_in_ns += Xi.tv_nsec;
917
918 for(i = 0; i < FirstRequestIrqExit->len; i++)
919 {
920 average = &g_array_index(FirstRequestIrqExit,Irq,i);
921 if(irq_id == average->id)
922 {
923 duration_inner_part = Xi_in_ns - average->average_duration;
924 FrequencyHZ = FrequencyInHZ(average->TotalNumberOfInterrupts, event_data->time_window);
925 sum.irqId = irq_id;
926 // compute (xi -Xa)^2 of the duration Standard deviation
927 sum.TotalNumberOfInterrupts = average->TotalNumberOfInterrupts;
928 sum.sumOfDurations = pow (duration_inner_part , 2);
929
930 // compute (xi -Xa)^2 of the period Standard deviation
931 period_inner_part = CalculatePeriodInnerPart(Xi_in_ns, FrequencyHZ);
932
933 // compute (xi -Xa)^2 of the frequency Standard deviation
934 frequency_inner_part = CalculateFrequencyInnerPart(Xi_in_ns, FrequencyHZ);
935
936 sum.sumOfPeriods = period_inner_part;
937
938 sum.sumOfFrequencies = frequency_inner_part;
939
940 if(event_data->SumArray->len == NO_ITEMS)
941 {
942 g_array_append_val (SumArray, sum);
943 }
944 else
945 {
946 for(i = 0; i < SumArray->len; i++)
947 {
948 sumItem = &g_array_index(SumArray, SumId, i);
949 if(sumItem->irqId == irq_id)
950 {
951 notFound = TRUE;
952 sumItem->sumOfDurations += sum.sumOfDurations;
953 sumItem->sumOfPeriods += sum.sumOfPeriods;
954 sumItem->sumOfFrequencies += sum.sumOfFrequencies;
955 }
956 }
957 if(!notFound)
958 {
959 g_array_append_val (SumArray, sum);
960 }
961
962 }
963
964 }
965 }
966 }
967
968 /**
969 * This function computes the inner part of the period standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
970 * The inner part is: (xi -Xa)^2
971 */
972 static guint64 CalculatePeriodInnerPart(guint Xi, guint FrequencyHZ)
973 {
974
975 double periodInSec; /*period in sec*/
976 int periodInNSec;
977 gint difference;
978 guint64 result;
979 periodInSec = (double)1/FrequencyHZ;
980 periodInSec *= NANOSECONDS_PER_SECOND;
981 periodInNSec = (int)periodInSec;
982
983 difference = Xi - periodInNSec;
984 result = pow (difference , 2);
985 return result;
986 }
987
988 /**
989 * This function computes the inner part of the frequency standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
990 * The inner part is: (xi -Xa)^2
991 */
992 static guint64 CalculateFrequencyInnerPart(guint Xi_in_ns, guint FrequencyHZ)
993 {
994 guint64 result;
995 gint difference;
996
997 difference = Xi_in_ns - FrequencyHZ;
998 result = pow (difference , 2);
999 return result;
1000 }
1001 /**
1002 * This function displays the result on the viewer
1003 *
1004 */
1005 static gboolean DisplayViewer(void *hook_data, void *call_data)
1006 {
1007
1008 guint average;
1009 gint i;
1010 Irq element;
1011 LttTime average_duration;
1012 GtkTreeIter iter;
1013 guint64 real_data;
1014 guint maxIRQduration;
1015 guint minIRQduration;
1016 double periodInSec;
1017 int periodInNsec = 0;
1018 char maxIrqHandler[80];
1019 char minIrqHandler[80];
1020 InterruptEventData *event_data = (InterruptEventData *)hook_data;
1021 GArray *FirstRequestIrqExit = event_data->FirstRequestIrqExit;
1022 int FrequencyHZ = 0;
1023 periodInSec = 0;
1024 gtk_list_store_clear(event_data->ListStore);
1025 for(i = 0; i < FirstRequestIrqExit->len; i++)
1026 {
1027 element = g_array_index(FirstRequestIrqExit,Irq,i);
1028 real_data = element.total_duration.tv_sec;
1029 real_data *= NANOSECONDS_PER_SECOND;
1030 real_data += element.total_duration.tv_nsec;
1031
1032
1033 maxIRQduration = element.max_irq_handler.duration.tv_sec;
1034 maxIRQduration *= NANOSECONDS_PER_SECOND;
1035 maxIRQduration += element.max_irq_handler.duration.tv_nsec;
1036
1037 sprintf(maxIrqHandler, "%d [%lu.%lu - %lu.%lu]",maxIRQduration, element.max_irq_handler.start_time.tv_sec, \
1038 element.max_irq_handler.start_time.tv_nsec, element.max_irq_handler.end_time.tv_sec, \
1039 element.max_irq_handler.end_time.tv_nsec) ;
1040
1041 minIRQduration = element.min_irq_handler.duration.tv_sec;
1042 minIRQduration *= NANOSECONDS_PER_SECOND;
1043 minIRQduration += element.min_irq_handler.duration.tv_nsec;
1044 sprintf(minIrqHandler, "%d [%lu.%lu - %lu.%lu]",minIRQduration, element.min_irq_handler.start_time.tv_sec, \
1045 element.min_irq_handler.start_time.tv_nsec, element.min_irq_handler.end_time.tv_sec, \
1046 element.min_irq_handler.end_time.tv_nsec) ;
1047
1048
1049 FrequencyHZ = FrequencyInHZ(element.TotalNumberOfInterrupts,event_data->time_window);
1050
1051 if(FrequencyHZ != 0)
1052 {
1053 periodInSec = (double)1/FrequencyHZ;
1054 periodInSec *= NANOSECONDS_PER_SECOND;
1055 periodInNsec = (int)periodInSec;
1056
1057 }
1058
1059 gtk_list_store_append (event_data->ListStore, &iter);
1060 gtk_list_store_set (event_data->ListStore, &iter,
1061 CPUID_COLUMN, element.cpu_id,
1062 IRQ_ID_COLUMN, element.id,
1063 FREQUENCY_COLUMN, FrequencyHZ,
1064 DURATION_COLUMN, real_data,
1065 DURATION_STANDARD_DEV_COLUMN, CalculateDurationStandardDeviation(element.id, event_data),
1066 MAX_IRQ_HANDLER_COLUMN, maxIrqHandler,
1067 MIN_IRQ_HANDLER_COLUMN, minIrqHandler,
1068 AVERAGE_PERIOD , periodInNsec,
1069 PERIOD_STANDARD_DEV_COLUMN, CalculatePeriodStandardDeviation(element.id, event_data),
1070 FREQUENCY_STANDARD_DEV_COLUMN, CalculateFrequencyStandardDeviation(element.id, event_data),
1071 -1);
1072 }
1073
1074
1075 if(event_data->FirstRequestIrqExit->len)
1076 {
1077 g_array_remove_range (event_data->FirstRequestIrqExit,0,event_data->FirstRequestIrqExit->len);
1078 }
1079
1080 if(event_data->FirstRequestIrqEntry->len)
1081 {
1082 g_array_remove_range (event_data->FirstRequestIrqEntry,0,event_data->FirstRequestIrqEntry->len);
1083 }
1084
1085 if(event_data->SecondRequestIrqEntry->len)
1086 {
1087 g_array_remove_range (event_data->SecondRequestIrqEntry,0,event_data->SecondRequestIrqEntry->len);
1088 }
1089
1090 if(event_data->SecondRequestIrqExit->len)
1091 {
1092 g_array_remove_range (event_data->SecondRequestIrqExit,0, event_data->SecondRequestIrqExit->len);
1093 }
1094
1095 if(event_data->SumArray->len)
1096 {
1097 g_array_remove_range (event_data->SumArray,0, event_data->SumArray->len);
1098 }
1099
1100 return FALSE;
1101 }
1102
1103
1104 /**
1105 * This function converts the number of interrupts over a time window to
1106 * frequency in HZ
1107 */
1108 static int FrequencyInHZ(gint NumerofInterruptions, TimeWindow time_window)
1109 {
1110 guint64 frequencyHz = 0;
1111 double timeSec; // time in second
1112 double result;
1113 result = ltt_time_to_double(time_window.time_width);
1114 timeSec = (result/NANOSECONDS_PER_SECOND); //time in second
1115 frequencyHz = NumerofInterruptions / timeSec;
1116 return frequencyHz;
1117 }
1118
1119 /**
1120 * This function calculates the duration standard deviation
1121 * Duration standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1122 * Where:
1123 * sumId.sumOfDurations -> Sum ((xi -Xa)^2)
1124 * inner_component -> 1/N Sum ((xi -Xa)^2)
1125 * deviation-> sqrt(1/N Sum ((xi -Xa)^2))
1126 */
1127 static int CalculateDurationStandardDeviation(gint id, InterruptEventData *event_data)
1128 {
1129 int i;
1130 SumId sumId;
1131 double inner_component;
1132 int deviation = 0;
1133 for(i = 0; i < event_data->SumArray->len; i++)
1134 {
1135 sumId = g_array_index(event_data->SumArray, SumId, i);
1136 if(id == sumId.irqId)
1137 {
1138 if(sumId.TotalNumberOfInterrupts != 0)
1139 inner_component = sumId.sumOfDurations/ sumId.TotalNumberOfInterrupts;
1140 else
1141 inner_component = 0.0;
1142 deviation = sqrt(inner_component);
1143 return deviation;
1144 }
1145 }
1146 return deviation;
1147 }
1148
1149
1150 /**
1151 * This function calculates the period standard deviation
1152 * Period standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1153 * Where:
1154 * sumId.sumOfPeriods -> Sum ((xi -Xa)^2)
1155 * inner_component -> 1/N Sum ((xi -Xa)^2)
1156 * period_standard_deviation-> sqrt(1/N Sum ((xi -Xa)^2))
1157
1158 *
1159 */
1160 static int CalculatePeriodStandardDeviation(gint id, InterruptEventData *event_data)
1161 {
1162 int i;
1163 SumId sumId;
1164 guint64 inner_component;
1165 guint64 period_standard_deviation = 0;
1166
1167 for(i = 0; i < event_data->SumArray->len; i++)
1168 {
1169 sumId = g_array_index(event_data->SumArray, SumId, i);
1170 if(id == sumId.irqId)
1171 {
1172 if(sumId.TotalNumberOfInterrupts != 0)
1173 inner_component = sumId.sumOfPeriods / sumId.TotalNumberOfInterrupts;
1174 else
1175 inner_component = 0;
1176
1177 period_standard_deviation = sqrt(inner_component);
1178 }
1179 }
1180
1181 return period_standard_deviation;
1182 }
1183
1184 /**
1185 * This function calculates the frequency standard deviation
1186 * Frequency standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1187 * Where:
1188 * sumId.sumOfFrequencies -> Sum ((xi -Xa)^2)
1189 * inner_component -> 1/N Sum ((xi -Xa)^2)
1190 * frequency_standard_deviation-> sqrt(1/N Sum ((xi -Xa)^2))
1191 *
1192 */
1193 static int CalculateFrequencyStandardDeviation(gint id, InterruptEventData *event_data)
1194 {
1195 int i;
1196 SumId sumId;
1197 guint64 inner_component;
1198 guint64 frequency_standard_deviation = 0;
1199 for(i = 0; i < event_data->SumArray->len; i++)
1200 {
1201 sumId = g_array_index(event_data->SumArray, SumId, i);
1202 if(id == sumId.irqId)
1203 {
1204 if(sumId.TotalNumberOfInterrupts != 0)
1205 inner_component = sumId.sumOfFrequencies / sumId.TotalNumberOfInterrupts;
1206 else
1207 inner_component = 0;
1208
1209 frequency_standard_deviation = sqrt(inner_component);
1210 }
1211 }
1212 return frequency_standard_deviation;
1213 }
1214
1215 /*
1216 * This function is called by the main window
1217 * when the time interval needs to be updated.
1218 **/
1219 gboolean interrupt_update_time_window(void * hook_data, void * call_data)
1220 {
1221 InterruptEventData *event_data = (InterruptEventData *) hook_data;
1222 const TimeWindowNotifyData *time_window_nofify_data = ((const TimeWindowNotifyData *)call_data);
1223 event_data->time_window = *time_window_nofify_data->new_time_window;
1224 g_info("interrupts: interrupt_update_time_window()\n");
1225 Tab *tab = event_data->tab;
1226 lttvwindow_events_request_remove_all(tab, event_data);
1227 FirstRequest(event_data );
1228 return FALSE;
1229 }
1230
1231
1232 gboolean trace_header(void *hook_data, void *call_data)
1233 {
1234
1235 InterruptEventData *event_data = (InterruptEventData *)hook_data;
1236 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1237 LttEvent *e;
1238 LttTime event_time;
1239 return FALSE;
1240 }
1241
1242 void interrupt_destroy_walk(gpointer data, gpointer user_data)
1243 {
1244 g_info("interrupt_destroy_walk");
1245 InterruptEventData *event_data = (InterruptEventData*) data;
1246 interrupt_destructor((InterruptEventData*)data);
1247 }
1248
1249
1250 void interrupt_destructor(InterruptEventData *event_viewer_data)
1251 {
1252 /* May already been done by GTK window closing */
1253 g_info("enter interrupt_destructor \n");
1254 if(GTK_IS_WIDGET(event_viewer_data->Hbox))
1255 {
1256 gtk_widget_destroy(event_viewer_data->Hbox);
1257 }
1258 }
1259
1260 /**
1261 This function is called when the viewer is destroyed to free hooks and memory
1262 */
1263 static void InterruptFree(InterruptEventData *event_viewer_data)
1264 {
1265 Tab *tab = event_viewer_data->tab;
1266 if(tab != NULL)
1267 {
1268
1269 g_array_free(event_viewer_data->FirstRequestIrqExit, TRUE);
1270 g_array_free(event_viewer_data->FirstRequestIrqEntry, TRUE);
1271 g_array_free(event_viewer_data->SecondRequestIrqEntry, TRUE);
1272 g_array_free(event_viewer_data->SecondRequestIrqExit, TRUE);
1273 g_array_free(event_viewer_data->SumArray, TRUE);
1274
1275 lttvwindow_unregister_time_window_notify(tab, interrupt_update_time_window, event_viewer_data);
1276
1277 lttvwindow_events_request_remove_all(event_viewer_data->tab,
1278 event_viewer_data);
1279
1280 interrupt_data_list = g_slist_remove(interrupt_data_list, event_viewer_data);
1281
1282 }
1283
1284 }
1285
1286 /**
1287 * plugin's destroy function
1288 *
1289 * This function releases the memory reserved by the module and unregisters
1290 * everything that has been registered in the gtkTraceSet API.
1291 */
1292 static void destroy()
1293 {
1294
1295 g_info("Destroy interrupts");
1296 g_slist_foreach(interrupt_data_list, interrupt_destroy_walk, NULL );
1297 g_slist_free(interrupt_data_list);
1298 lttvwindow_unregister_constructor(interrupts);
1299
1300 }
1301
1302 LTTV_MODULE("interrupts", "interrupts info view", \
1303 "Graphical module to display interrupts performance", \
1304 init, destroy, "lttvwindow")
This page took 0.066292 seconds and 3 git commands to generate.