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