1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2005 Peter Ho
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;
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.
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,
19 /******************************************************************
21 Each field of the interrupt viewer is summarized as follows:
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.
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
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.
45 - Max IRQ handler duration (nsec) [time interval]: the longest IRQ handler duration in nsec.
47 - Min IRQ handler duration (nsec) [time interval]: the shortest IRQ handler duration in nsec.
49 - Average period (nsec): 1/Frequency(in HZ). The frequency is computed above.
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)
56 -Frequency Standard_deviation = sqrt(1/N Sum ((xi -Xa)^2))
57 N: number of interrupts
58 xi: duration of an interrupt
62 *******************************************************************/
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>
86 #include "hInterruptsInsert.xpm"
88 #define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
89 #define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format)
102 guint TotalNumberOfInterrupts;
103 LttTime total_duration;
104 guint average_duration;
105 IrqDuration max_irq_handler;
106 IrqDuration min_irq_handler;
119 guint TotalNumberOfInterrupts;//frequency;//
120 guint64 sumOfDurations; // to store the Sum ((xi -Xa)^2) of the duration Standard deviation
121 guint64 sumOfPeriods; // to store the Sum ((xi -Xa)^2) of the period Standard deviation
122 guint64 sumOfFrequencies;// to store the Sum ((xi -Xa)^2) of the frequency Standard deviation
131 /** Array containing instanced objects. Used when module is unloaded */
132 static GSList *interrupt_data_list = NULL ;
135 //fixed #define TRACE_NUMBER 0
137 typedef struct _InterruptEventData {
139 /*Graphical Widgets */
140 GtkWidget * ScrollWindow;
141 GtkListStore *ListStore;
144 GtkTreeSelection *SelectionTree;
146 Tab * tab; /* tab that contains this plug-in*/
148 LttvHooks * event_hooks;
149 LttvHooks * hooks_trace_after;
150 LttvHooks * hooks_trace_before;
151 TimeWindow time_window;
152 LttvHooksById * event_by_id_hooks;
153 GArray *FirstRequestIrqExit;
154 GArray *FirstRequestIrqEntry;
155 GArray *SecondRequestIrqEntry;
156 GArray *SecondRequestIrqExit;
159 } InterruptEventData ;
162 /* Function prototypes */
164 static gboolean interrupt_update_time_window(void * hook_data, void * call_data);
165 static GtkWidget *interrupts(LttvPlugin *plugin);
166 static InterruptEventData *system_info(LttvPluginTab *ptab);
167 void interrupt_destructor(InterruptEventData *event_viewer_data);
168 static void FirstRequest(InterruptEventData *event_data );
169 static guint64 get_interrupt_id(LttEvent *e);
170 static gboolean trace_header(void *hook_data, void *call_data);
171 static gboolean DisplayViewer (void *hook_data, void *call_data);
172 static void CalculateData(LttTime time_exit, guint cpu_id, InterruptEventData *event_data);
173 static void CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(irq_entry *e, LttTime time_exit, GArray *FirstRequestIrqExit);
174 static gboolean FirstRequestIrqEntryCallback(void *hook_data, void *call_data);
175 static gboolean FirstRequestIrqExitCallback(void *hook_data, void *call_data);
176 static gboolean SecondRequest(void *hook_data, void *call_data);
177 static void CalculateAverageDurationForEachIrqId(InterruptEventData *event_data);
178 static gboolean SecondRequestIrqEntryCallback(void *hook_data, void *call_data);
179 static gboolean SecondRequestIrqExitCallback(void *hook_data, void *call_data);
180 static void CalculateXi(LttEvent *event, InterruptEventData *event_data);
181 static void SumItems(gint irq_id, LttTime Xi, InterruptEventData *event_data);
182 static int CalculateDurationStandardDeviation(gint id, InterruptEventData *event_data);
183 static int CalculatePeriodStandardDeviation(gint id, InterruptEventData *event_data);
184 static int FrequencyInHZ(gint NumberOfInterruptions, TimeWindow time_window);
185 static guint64 CalculatePeriodInnerPart(guint Xi, guint FrequencyHZ);
186 static guint64 CalculateFrequencyInnerPart(guint Xi_in_ns, guint FrequencyHZ);
187 static void InterruptFree(InterruptEventData *event_viewer_data);
188 static int CalculateFrequencyStandardDeviation(gint id, InterruptEventData *event_data);
190 /* Enumeration of the columns */
196 DURATION_STANDARD_DEV_COLUMN,
197 MAX_IRQ_HANDLER_COLUMN,
198 MIN_IRQ_HANDLER_COLUMN,
200 PERIOD_STANDARD_DEV_COLUMN,
201 FREQUENCY_STANDARD_DEV_COLUMN,
211 * This is the entry point of the viewer.
215 g_info("interrupts: init()");
216 lttvwindow_register_constructor("interrupts",
218 "Insert Interrupts View",
219 hInterruptsInsert_xpm,
220 "Insert Interrupts View",
230 static GtkWidget *interrupts(LttvPlugin *plugin)
232 LttvPluginTab *ptab = LTTV_PLUGIN_TAB(plugin);
233 InterruptEventData* event_data = system_info(ptab) ;
235 return event_data->Hbox;
241 * This function initializes the Event Viewer functionnality through the
244 InterruptEventData *system_info(LttvPluginTab *ptab)
248 GtkTreeViewColumn *column;
249 GtkCellRenderer *renderer;
250 InterruptEventData* event_viewer_data = g_new(InterruptEventData,1) ;
251 Tab *tab = ptab->tab;
252 event_viewer_data->ptab = ptab;
253 event_viewer_data->tab = tab;
255 /*Get the current time frame from the main window */
256 event_viewer_data->time_window = lttvwindow_get_time_window(tab);
258 event_viewer_data->FirstRequestIrqExit = g_array_new(FALSE, FALSE, sizeof(Irq));
259 event_viewer_data->FirstRequestIrqEntry = g_array_new(FALSE, FALSE, sizeof(irq_entry));
261 event_viewer_data->SecondRequestIrqEntry = g_array_new(FALSE, FALSE, sizeof(irq_entry));
262 event_viewer_data->SecondRequestIrqExit = g_array_new(FALSE, FALSE, sizeof(Irq));
264 event_viewer_data->SumArray = g_array_new(FALSE, FALSE, sizeof(SumId));
267 /*Create tha main window for the viewer */
268 event_viewer_data->ScrollWindow = gtk_scrolled_window_new (NULL, NULL);
269 gtk_widget_show (event_viewer_data->ScrollWindow);
270 gtk_scrolled_window_set_policy(
271 GTK_SCROLLED_WINDOW(event_viewer_data->ScrollWindow),
272 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC/*GTK_POLICY_NEVER*/);
274 /* Create a model for storing the data list */
275 event_viewer_data->ListStore = gtk_list_store_new (
276 N_COLUMNS, /* Total number of columns */
277 G_TYPE_INT, /* CPUID */
278 G_TYPE_INT, /* IRQ_ID */
279 G_TYPE_INT, /* Frequency */
280 G_TYPE_UINT64, /* Duration */
281 G_TYPE_INT, /* standard deviation */
282 G_TYPE_STRING, /* Max IRQ handler */
283 G_TYPE_STRING, /* Min IRQ handler */
284 G_TYPE_INT, /* Average period */
285 G_TYPE_INT, /* period standard deviation */
286 G_TYPE_INT /* frequency standard deviation */
290 event_viewer_data->TreeView = gtk_tree_view_new_with_model (GTK_TREE_MODEL (event_viewer_data->ListStore));
292 g_object_unref (G_OBJECT (event_viewer_data->ListStore));
294 renderer = gtk_cell_renderer_text_new ();
295 column = gtk_tree_view_column_new_with_attributes ("CPU ID",
297 "text", CPUID_COLUMN,
299 gtk_tree_view_column_set_alignment (column, 0.0);
300 gtk_tree_view_column_set_fixed_width (column, 45);
301 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
304 renderer = gtk_cell_renderer_text_new ();
305 column = gtk_tree_view_column_new_with_attributes ("IRQ ID",
307 "text", IRQ_ID_COLUMN,
309 gtk_tree_view_column_set_alignment (column, 0.0);
310 gtk_tree_view_column_set_fixed_width (column, 220);
311 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
313 renderer = gtk_cell_renderer_text_new ();
314 column = gtk_tree_view_column_new_with_attributes ("Frequency (Hz)",
316 "text", FREQUENCY_COLUMN,
318 gtk_tree_view_column_set_alignment (column, 1.0);
319 gtk_tree_view_column_set_fixed_width (column, 220);
320 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
322 renderer = gtk_cell_renderer_text_new ();
323 column = gtk_tree_view_column_new_with_attributes ("Total Duration (nsec)",
325 "text", DURATION_COLUMN,
327 gtk_tree_view_column_set_alignment (column, 0.0);
328 gtk_tree_view_column_set_fixed_width (column, 145);
329 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
332 renderer = gtk_cell_renderer_text_new ();
333 column = gtk_tree_view_column_new_with_attributes ("Duration standard deviation (nsec)",
335 "text", DURATION_STANDARD_DEV_COLUMN,
337 gtk_tree_view_column_set_alignment (column, 0.0);
338 gtk_tree_view_column_set_fixed_width (column, 200);
339 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
341 renderer = gtk_cell_renderer_text_new ();
342 column = gtk_tree_view_column_new_with_attributes ("Max IRQ handler duration (nsec) [time interval]",
344 "text", MAX_IRQ_HANDLER_COLUMN,
346 gtk_tree_view_column_set_alignment (column, 0.0);
347 gtk_tree_view_column_set_fixed_width (column, 250);
348 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
350 renderer = gtk_cell_renderer_text_new ();
351 column = gtk_tree_view_column_new_with_attributes ("Min IRQ handler duration (nsec) [time interval]",
353 "text", MIN_IRQ_HANDLER_COLUMN,
355 gtk_tree_view_column_set_alignment (column, 0.0);
356 gtk_tree_view_column_set_fixed_width (column, 250);
357 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
359 renderer = gtk_cell_renderer_text_new ();
360 column = gtk_tree_view_column_new_with_attributes (" Average period (nsec)",
362 "text", AVERAGE_PERIOD,
364 gtk_tree_view_column_set_alignment (column, 0.0);
365 gtk_tree_view_column_set_fixed_width (column, 200);
366 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
368 renderer = gtk_cell_renderer_text_new ();
369 column = gtk_tree_view_column_new_with_attributes ("Period standard deviation (nsec)",
371 "text", PERIOD_STANDARD_DEV_COLUMN,
373 gtk_tree_view_column_set_alignment (column, 0.0);
374 gtk_tree_view_column_set_fixed_width (column, 200);
375 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
377 renderer = gtk_cell_renderer_text_new ();
378 column = gtk_tree_view_column_new_with_attributes ("Frequency standard deviation (Hz)",
380 "text", FREQUENCY_STANDARD_DEV_COLUMN,
382 gtk_tree_view_column_set_alignment (column, 0.0);
383 gtk_tree_view_column_set_fixed_width (column, 200);
384 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
387 event_viewer_data->SelectionTree = gtk_tree_view_get_selection (GTK_TREE_VIEW (event_viewer_data->TreeView));
388 gtk_tree_selection_set_mode (event_viewer_data->SelectionTree, GTK_SELECTION_SINGLE);
390 gtk_container_add (GTK_CONTAINER (event_viewer_data->ScrollWindow), event_viewer_data->TreeView);
392 event_viewer_data->Hbox = gtk_hbox_new(0, 0);
393 gtk_box_pack_start(GTK_BOX(event_viewer_data->Hbox), event_viewer_data->ScrollWindow, TRUE, TRUE, 0);
395 gtk_widget_show(event_viewer_data->Hbox);
396 gtk_widget_show(event_viewer_data->TreeView);
398 interrupt_data_list = g_slist_append(interrupt_data_list, event_viewer_data);
399 /* Registration for time notification */
400 lttvwindow_register_time_window_notify(tab,
401 interrupt_update_time_window,
404 g_object_set_data_full(G_OBJECT(event_viewer_data->Hbox),
407 (GDestroyNotify) InterruptFree);
409 FirstRequest(event_viewer_data );
410 return event_viewer_data;
416 * For each trace in the traceset, this function:
417 * - registers a callback function to each hook
418 * - calls lttv_trace_find_hook() registers a hook function to event_by_id_hooks
419 * - calls lttvwindow_events_request() to request data in a specific
420 * time interval to the main window
423 static void FirstRequest(InterruptEventData *event_data )
425 guint i, k, l, nb_trace;
435 EventsRequest *events_request;
437 LttvTraceHookByFacility *thf;
439 LttvTracesetContext *tsc = lttvwindow_get_traceset_context(event_data->tab);
442 /* Get the traceset */
443 LttvTraceset *traceset = tsc->ts;
445 nb_trace = lttv_traceset_number(traceset);
447 /* There are many traces in a traceset. Iteration for each trace. */
448 //for(i = 0; i<MIN(TRACE_NUMBER+1, nb_trace);i++) {
449 for(i = 0 ; i < nb_trace ; i++) {
450 events_request = g_new(EventsRequest, 1);
452 hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook));
454 hooks = g_array_set_size(hooks, 2);
456 event_data->hooks_trace_before = lttv_hooks_new();
458 /* Registers a hook function */
459 lttv_hooks_add(event_data->hooks_trace_before, trace_header, event_data, LTTV_PRIO_DEFAULT);
461 event_data->hooks_trace_after = lttv_hooks_new();
463 /* Registers a hook function */
464 lttv_hooks_add(event_data->hooks_trace_after, SecondRequest, event_data, LTTV_PRIO_DEFAULT);
465 /* Get a trace state */
466 ts = (LttvTraceState *)tsc->traces[i];
467 /* Create event_by_Id hooks */
468 event_data->event_by_id_hooks = lttv_hooks_by_id_new();
470 /*Register event_by_id_hooks with a callback function*/
471 ret = lttv_trace_find_hook(ts->parent.t,
472 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
473 LTT_FIELD_IRQ_ID, 0, 0,
474 FirstRequestIrqEntryCallback,
476 &g_array_index(hooks, LttvTraceHook, 0));
478 ret = lttv_trace_find_hook(ts->parent.t,
479 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
480 LTT_FIELD_IRQ_ID, 0, 0,
481 FirstRequestIrqExitCallback,
483 &g_array_index(hooks, LttvTraceHook, 1));
486 /*iterate through the facility list*/
487 for(k = 0 ; k < hooks->len; k++)
489 hook = &g_array_index(hooks, LttvTraceHook, k);
490 for(l=0; l<hook->fac_list->len; l++)
492 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
493 lttv_hooks_add(lttv_hooks_by_id_find(event_data->event_by_id_hooks, thf->id),
500 /* Initalize the EventsRequest structure */
501 events_request->owner = event_data;
502 events_request->viewer_data = event_data;
503 events_request->servicing = FALSE;
504 events_request->start_time = event_data->time_window.start_time;
505 events_request->start_position = NULL;
506 events_request->stop_flag = FALSE;
507 events_request->end_time = event_data->time_window.end_time;
508 events_request->num_events = G_MAXUINT;
509 events_request->end_position = NULL;
510 events_request->trace = i;
512 events_request->hooks = hooks;
514 events_request->before_chunk_traceset = NULL;
515 events_request->before_chunk_trace = event_data->hooks_trace_before;
516 events_request->before_chunk_tracefile= NULL;
517 events_request->event = NULL;
518 events_request->event_by_id = event_data->event_by_id_hooks;
519 events_request->after_chunk_tracefile = NULL;
520 events_request->after_chunk_trace = NULL;
521 events_request->after_chunk_traceset = NULL;
522 events_request->before_request = NULL;
523 events_request->after_request = event_data->hooks_trace_after;
525 lttvwindow_events_request(event_data->tab, events_request);
531 * This function is called whenever an irq_entry event occurs.
534 static gboolean FirstRequestIrqEntryCallback(void *hook_data, void *call_data)
540 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
541 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
542 InterruptEventData *event_data = (InterruptEventData *)hook_data;
543 GArray* FirstRequestIrqEntry = event_data->FirstRequestIrqEntry;
544 LttEvent *e = ltt_tracefile_get_event(tfc->tf);
545 event_time = ltt_event_time(e);
546 cpu_id = ltt_event_cpu_id(e);
549 entry.id =get_interrupt_id(e);
550 entry.cpu_id = cpu_id;
551 entry.event_time = event_time;
552 g_array_append_val (FirstRequestIrqEntry, entry);
558 * This function gets the id of the interrupt. The id is stored in a dynamic structure.
559 * Refer to the print.c file for how to extract data from a dynamic structure.
561 static guint64 get_interrupt_id(LttEvent *e)
564 LttEventType *event_type;
568 event_type = ltt_event_eventtype(e);
569 num_fields = ltt_eventtype_num_fields(event_type);
570 for(i = 0 ; i < num_fields-1 ; i++)
572 field = ltt_eventtype_field(event_type, i);
573 irq_id = ltt_event_get_long_unsigned(e,field);
579 * This function is called whenever an irq_exit event occurs.
582 gboolean FirstRequestIrqExitCallback(void *hook_data, void *call_data)
586 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
587 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
588 InterruptEventData *event_data = (InterruptEventData *)hook_data;
589 LttEvent *e = ltt_tracefile_get_event(tfc->tf);
590 LttEventType *type = ltt_event_eventtype(e);
591 event_time = ltt_event_time(e);
592 cpu_id = ltt_event_cpu_id(e);
594 CalculateData( event_time, cpu_id, event_data);
600 * This function calculates the duration of an interrupt.
603 static void CalculateData(LttTime time_exit, guint cpu_id,InterruptEventData *event_data)
609 GArray *FirstRequestIrqExit = event_data->FirstRequestIrqExit;
610 GArray *FirstRequestIrqEntry = event_data->FirstRequestIrqEntry;
611 for(i = 0; i < FirstRequestIrqEntry->len; i++)
613 element = &g_array_index(FirstRequestIrqEntry,irq_entry,i);
614 if(element->cpu_id == cpu_id)
616 CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(element,time_exit, FirstRequestIrqExit);
617 g_array_remove_index(FirstRequestIrqEntry, i);
625 * This function calculates the total duration of an interrupt and the longest & shortest Irq handlers.
628 static void CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(irq_entry *e, LttTime time_exit, GArray *FirstRequestIrqExit)
634 gboolean notFound = FALSE;
635 memset ((void*)&irq, 0,sizeof(Irq));
638 if(FirstRequestIrqExit->len == NO_ITEMS)
640 irq.cpu_id = e->cpu_id;
642 irq.TotalNumberOfInterrupts++;
643 irq.total_duration = ltt_time_sub(time_exit, e->event_time);
645 irq.max_irq_handler.start_time = e->event_time;
646 irq.max_irq_handler.end_time = time_exit;
647 irq.max_irq_handler.duration = ltt_time_sub(time_exit, e->event_time);
649 irq.min_irq_handler.start_time = e->event_time;
650 irq.min_irq_handler.end_time = time_exit;
651 irq.min_irq_handler.duration = ltt_time_sub(time_exit, e->event_time);
653 g_array_append_val (FirstRequestIrqExit, irq);
657 for(i = 0; i < FirstRequestIrqExit->len; i++)
659 element = &g_array_index(FirstRequestIrqExit,Irq,i);
660 if(element->id == e->id)
663 duration = ltt_time_sub(time_exit, e->event_time);
664 element->total_duration = ltt_time_add(element->total_duration, duration);
665 element->TotalNumberOfInterrupts++;
667 if(ltt_time_compare(duration,element->max_irq_handler.duration) > 0)
669 element->max_irq_handler.duration = duration;
670 element->max_irq_handler.start_time = e->event_time;
671 element->max_irq_handler.end_time = time_exit;
674 if(ltt_time_compare(duration,element->min_irq_handler.duration) < 0)
676 element->min_irq_handler.duration = duration;
677 element->min_irq_handler.start_time = e->event_time;
678 element->min_irq_handler.end_time = time_exit;
684 irq.cpu_id = e->cpu_id;
686 irq.TotalNumberOfInterrupts++;
687 irq.total_duration = ltt_time_sub(time_exit, e->event_time);
689 irq.max_irq_handler.start_time = e->event_time;
690 irq.max_irq_handler.end_time = time_exit;
691 irq.max_irq_handler.duration = ltt_time_sub(time_exit, e->event_time);
693 irq.min_irq_handler.start_time = e->event_time;
694 irq.min_irq_handler.end_time = time_exit;
695 irq.min_irq_handler.duration = ltt_time_sub(time_exit, e->event_time);
697 g_array_append_val (FirstRequestIrqExit, irq);
703 * This function passes the second EventsRequest to LTTV
706 static gboolean SecondRequest(void *hook_data, void *call_data)
709 guint i, k, l, nb_trace;
719 EventsRequest *events_request;
721 LttvTraceHookByFacility *thf;
723 InterruptEventData *event_data = (InterruptEventData *)hook_data;
725 LttvTracesetContext *tsc = lttvwindow_get_traceset_context(event_data->tab);
727 CalculateAverageDurationForEachIrqId(event_data);
729 /* Get the traceset */
730 LttvTraceset *traceset = tsc->ts;
732 nb_trace = lttv_traceset_number(traceset);
734 /* There are many traces in a traceset. Iteration for each trace. */
735 for(i = 0 ; i < nb_trace ; i++) {
736 // fixed for(i = 0; i<MIN(TRACE_NUMBER+1, nb_trace);i++) {
737 events_request = g_new(EventsRequest, 1);
739 hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook));
741 hooks = g_array_set_size(hooks, 2);
743 event_data->hooks_trace_after = lttv_hooks_new();
745 /* Registers a hook function */
746 lttv_hooks_add(event_data->hooks_trace_after, DisplayViewer, event_data, LTTV_PRIO_DEFAULT);
748 /* Get a trace state */
749 ts = (LttvTraceState *)tsc->traces[i];
750 /* Create event_by_Id hooks */
751 event_data->event_by_id_hooks = lttv_hooks_by_id_new();
753 /*Register event_by_id_hooks with a callback function*/
754 ret = lttv_trace_find_hook(ts->parent.t,
755 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
756 LTT_FIELD_IRQ_ID, 0, 0,
757 SecondRequestIrqEntryCallback,
759 &g_array_index(hooks, LttvTraceHook, 0));
761 ret = lttv_trace_find_hook(ts->parent.t,
762 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
763 LTT_FIELD_IRQ_ID, 0, 0,
764 SecondRequestIrqExitCallback,
766 &g_array_index(hooks, LttvTraceHook, 1));
770 /* iterate through the facility list */
771 for(k = 0 ; k < hooks->len; k++)
773 hook = &g_array_index(hooks, LttvTraceHook, k);
774 for(l=0; l<hook->fac_list->len; l++)
776 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
777 lttv_hooks_add(lttv_hooks_by_id_find(event_data->event_by_id_hooks, thf->id),
784 /* Initalize the EventsRequest structure */
785 events_request->owner = event_data;
786 events_request->viewer_data = event_data;
787 events_request->servicing = FALSE;
788 events_request->start_time = event_data->time_window.start_time;
789 events_request->start_position = NULL;
790 events_request->stop_flag = FALSE;
791 events_request->end_time = event_data->time_window.end_time;
792 events_request->num_events = G_MAXUINT;
793 events_request->end_position = NULL;
794 events_request->trace = i;
796 events_request->hooks = hooks;
798 events_request->before_chunk_traceset = NULL;
799 events_request->before_chunk_trace = NULL;
800 events_request->before_chunk_tracefile= NULL;
801 events_request->event = NULL;
802 events_request->event_by_id = event_data->event_by_id_hooks;
803 events_request->after_chunk_tracefile = NULL;
804 events_request->after_chunk_trace = NULL;
805 events_request->after_chunk_traceset = NULL;
806 events_request->before_request = NULL;
807 events_request->after_request = event_data->hooks_trace_after;
809 lttvwindow_events_request(event_data->tab, events_request);
815 * This function calculates the average duration for each Irq Id
818 static void CalculateAverageDurationForEachIrqId(InterruptEventData *event_data)
823 GArray* FirstRequestIrqExit = event_data->FirstRequestIrqExit;
824 for(i = 0; i < FirstRequestIrqExit->len; i++)
826 element = &g_array_index(FirstRequestIrqExit,Irq,i);
827 real_data = element->total_duration.tv_sec;
828 real_data *= NANOSECONDS_PER_SECOND;
829 real_data += element->total_duration.tv_nsec;
830 if(element->TotalNumberOfInterrupts != 0)
831 element->average_duration = real_data / element->TotalNumberOfInterrupts;
833 element->average_duration = 0;
839 * This function is called whenever an irq_entry event occurs. Use in the second request
842 static gboolean SecondRequestIrqEntryCallback(void *hook_data, void *call_data)
848 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
849 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
850 InterruptEventData *event_data = (InterruptEventData *)hook_data;
851 GArray* SecondRequestIrqEntry = event_data->SecondRequestIrqEntry;
852 LttEvent *e = ltt_tracefile_get_event(tfc->tf);
853 event_time = ltt_event_time(e);
854 cpu_id = ltt_event_cpu_id(e);
857 entry.id =get_interrupt_id(e);
858 entry.cpu_id = cpu_id;
859 entry.event_time = event_time;
860 g_array_append_val (SecondRequestIrqEntry, entry);
866 * This function is called whenever an irq_exit event occurs in the second request.
869 static gboolean SecondRequestIrqExitCallback(void *hook_data, void *call_data)
872 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
873 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
874 InterruptEventData *event_data = (InterruptEventData *)hook_data;
875 LttEvent *event = ltt_tracefile_get_event(tfc->tf);
877 CalculateXi(event, event_data);
883 * This function is called whenever an irq_exit event occurs in the second request.
886 static void CalculateXi(LttEvent *event_irq_exit, InterruptEventData *event_data)
894 GArray *SecondRequestIrqExit = event_data->SecondRequestIrqExit;
895 GArray *SecondRequestIrqEntry = event_data->SecondRequestIrqEntry;
896 cpu_id = ltt_event_cpu_id(event_irq_exit);
897 for(i = 0; i < SecondRequestIrqEntry->len; i++)
899 element = &g_array_index(SecondRequestIrqEntry,irq_entry,i);
900 if(element->cpu_id == cpu_id)
903 /* time calculation */
904 exit_time = ltt_event_time(event_irq_exit);
905 Xi = ltt_time_sub(exit_time, element->event_time);
906 irq_id = element->id;
908 SumItems(irq_id, Xi,event_data);
909 g_array_remove_index(SecondRequestIrqEntry, i);
917 * This function computes the Sum ((xi -Xa)^2) and store the result in SumArray
920 static void SumItems(gint irq_id, LttTime Xi, InterruptEventData *event_data)
925 gint duration_inner_part;
926 guint64 period_inner_part;
927 guint64 frequency_inner_part;
933 gboolean notFound = FALSE;
934 GArray *FirstRequestIrqExit = event_data->FirstRequestIrqExit;
935 GArray *SumArray = event_data->SumArray;
936 Xi_in_ns = Xi.tv_sec;
937 Xi_in_ns *= NANOSECONDS_PER_SECOND;
938 Xi_in_ns += Xi.tv_nsec;
940 for(i = 0; i < FirstRequestIrqExit->len; i++)
942 average = &g_array_index(FirstRequestIrqExit,Irq,i);
943 if(irq_id == average->id)
945 duration_inner_part = Xi_in_ns - average->average_duration;
946 FrequencyHZ = FrequencyInHZ(average->TotalNumberOfInterrupts, event_data->time_window);
948 // compute (xi -Xa)^2 of the duration Standard deviation
949 sum.TotalNumberOfInterrupts = average->TotalNumberOfInterrupts;
950 sum.sumOfDurations = pow (duration_inner_part , 2);
952 // compute (xi -Xa)^2 of the period Standard deviation
953 period_inner_part = CalculatePeriodInnerPart(Xi_in_ns, FrequencyHZ);
955 // compute (xi -Xa)^2 of the frequency Standard deviation
956 frequency_inner_part = CalculateFrequencyInnerPart(Xi_in_ns, FrequencyHZ);
958 sum.sumOfPeriods = period_inner_part;
960 sum.sumOfFrequencies = frequency_inner_part;
962 if(event_data->SumArray->len == NO_ITEMS)
964 g_array_append_val (SumArray, sum);
968 for(i = 0; i < SumArray->len; i++)
970 sumItem = &g_array_index(SumArray, SumId, i);
971 if(sumItem->irqId == irq_id)
974 sumItem->sumOfDurations += sum.sumOfDurations;
975 sumItem->sumOfPeriods += sum.sumOfPeriods;
976 sumItem->sumOfFrequencies += sum.sumOfFrequencies;
981 g_array_append_val (SumArray, sum);
991 * This function computes the inner part of the period standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
992 * The inner part is: (xi -Xa)^2
994 static guint64 CalculatePeriodInnerPart(guint Xi, guint FrequencyHZ)
997 double periodInSec; /*period in sec*/
1001 periodInSec = (double)1/FrequencyHZ;
1002 periodInSec *= NANOSECONDS_PER_SECOND;
1003 periodInNSec = (int)periodInSec;
1005 difference = Xi - periodInNSec;
1006 result = pow (difference , 2);
1011 * This function computes the inner part of the frequency standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1012 * The inner part is: (xi -Xa)^2
1014 static guint64 CalculateFrequencyInnerPart(guint Xi_in_ns, guint FrequencyHZ)
1019 difference = Xi_in_ns - FrequencyHZ;
1020 result = pow (difference , 2);
1024 * This function displays the result on the viewer
1027 static gboolean DisplayViewer(void *hook_data, void *call_data)
1033 LttTime average_duration;
1036 guint maxIRQduration;
1037 guint minIRQduration;
1040 char maxIrqHandler[80];
1041 char minIrqHandler[80];
1042 InterruptEventData *event_data = (InterruptEventData *)hook_data;
1043 GArray *FirstRequestIrqExit = event_data->FirstRequestIrqExit;
1044 int FrequencyHZ = 0;
1046 gtk_list_store_clear(event_data->ListStore);
1047 for(i = 0; i < FirstRequestIrqExit->len; i++)
1049 element = g_array_index(FirstRequestIrqExit,Irq,i);
1050 real_data = element.total_duration.tv_sec;
1051 real_data *= NANOSECONDS_PER_SECOND;
1052 real_data += element.total_duration.tv_nsec;
1055 maxIRQduration = element.max_irq_handler.duration.tv_sec;
1056 maxIRQduration *= NANOSECONDS_PER_SECOND;
1057 maxIRQduration += element.max_irq_handler.duration.tv_nsec;
1059 sprintf(maxIrqHandler, "%d [%d.%d - %d.%d]",maxIRQduration, element.max_irq_handler.start_time.tv_sec, \
1060 element.max_irq_handler.start_time.tv_nsec, element.max_irq_handler.end_time.tv_sec, \
1061 element.max_irq_handler.end_time.tv_nsec) ;
1063 minIRQduration = element.min_irq_handler.duration.tv_sec;
1064 minIRQduration *= NANOSECONDS_PER_SECOND;
1065 minIRQduration += element.min_irq_handler.duration.tv_nsec;
1066 sprintf(minIrqHandler, "%d [%d.%d - %d.%d]",minIRQduration, element.min_irq_handler.start_time.tv_sec, \
1067 element.min_irq_handler.start_time.tv_nsec, element.min_irq_handler.end_time.tv_sec, \
1068 element.min_irq_handler.end_time.tv_nsec) ;
1071 FrequencyHZ = FrequencyInHZ(element.TotalNumberOfInterrupts,event_data->time_window);
1073 if(FrequencyHZ != 0)
1075 periodInSec = (double)1/FrequencyHZ;
1076 periodInSec *= NANOSECONDS_PER_SECOND;
1077 periodInNsec = (int)periodInSec;
1081 gtk_list_store_append (event_data->ListStore, &iter);
1082 gtk_list_store_set (event_data->ListStore, &iter,
1083 CPUID_COLUMN, element.cpu_id,
1084 IRQ_ID_COLUMN, element.id,
1085 FREQUENCY_COLUMN, FrequencyHZ,
1086 DURATION_COLUMN, real_data,
1087 DURATION_STANDARD_DEV_COLUMN, CalculateDurationStandardDeviation(element.id, event_data),
1088 MAX_IRQ_HANDLER_COLUMN, maxIrqHandler,
1089 MIN_IRQ_HANDLER_COLUMN, minIrqHandler,
1090 AVERAGE_PERIOD , periodInNsec,
1091 PERIOD_STANDARD_DEV_COLUMN, CalculatePeriodStandardDeviation(element.id, event_data),
1092 FREQUENCY_STANDARD_DEV_COLUMN, CalculateFrequencyStandardDeviation(element.id, event_data),
1097 if(event_data->FirstRequestIrqExit->len)
1099 g_array_remove_range (event_data->FirstRequestIrqExit,0,event_data->FirstRequestIrqExit->len);
1102 if(event_data->FirstRequestIrqEntry->len)
1104 g_array_remove_range (event_data->FirstRequestIrqEntry,0,event_data->FirstRequestIrqEntry->len);
1107 if(event_data->SecondRequestIrqEntry->len)
1109 g_array_remove_range (event_data->SecondRequestIrqEntry,0,event_data->SecondRequestIrqEntry->len);
1112 if(event_data->SecondRequestIrqExit->len)
1114 g_array_remove_range (event_data->SecondRequestIrqExit,0, event_data->SecondRequestIrqExit->len);
1117 if(event_data->SumArray->len)
1119 g_array_remove_range (event_data->SumArray,0, event_data->SumArray->len);
1127 * This function converts the number of interrupts over a time window to
1130 static int FrequencyInHZ(gint NumerofInterruptions, TimeWindow time_window)
1132 guint64 frequencyHz = 0;
1133 double timeSec; // time in second
1135 result = ltt_time_to_double(time_window.time_width);
1136 timeSec = (result/NANOSECONDS_PER_SECOND); //time in second
1137 frequencyHz = NumerofInterruptions / timeSec;
1142 * This function calculates the duration standard deviation
1143 * Duration standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1145 * sumId.sumOfDurations -> Sum ((xi -Xa)^2)
1146 * inner_component -> 1/N Sum ((xi -Xa)^2)
1147 * deviation-> sqrt(1/N Sum ((xi -Xa)^2))
1149 static int CalculateDurationStandardDeviation(gint id, InterruptEventData *event_data)
1153 double inner_component;
1155 for(i = 0; i < event_data->SumArray->len; i++)
1157 sumId = g_array_index(event_data->SumArray, SumId, i);
1158 if(id == sumId.irqId)
1160 if(sumId.TotalNumberOfInterrupts != 0)
1161 inner_component = sumId.sumOfDurations/ sumId.TotalNumberOfInterrupts;
1163 inner_component = 0.0;
1164 deviation = sqrt(inner_component);
1173 * This function calculates the period standard deviation
1174 * Period standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1176 * sumId.sumOfPeriods -> Sum ((xi -Xa)^2)
1177 * inner_component -> 1/N Sum ((xi -Xa)^2)
1178 * period_standard_deviation-> sqrt(1/N Sum ((xi -Xa)^2))
1182 static int CalculatePeriodStandardDeviation(gint id, InterruptEventData *event_data)
1186 guint64 inner_component;
1187 guint64 period_standard_deviation = 0;
1189 for(i = 0; i < event_data->SumArray->len; i++)
1191 sumId = g_array_index(event_data->SumArray, SumId, i);
1192 if(id == sumId.irqId)
1194 if(sumId.TotalNumberOfInterrupts != 0)
1195 inner_component = sumId.sumOfPeriods / sumId.TotalNumberOfInterrupts;
1197 inner_component = 0;
1199 period_standard_deviation = sqrt(inner_component);
1203 return period_standard_deviation;
1207 * This function calculates the frequency standard deviation
1208 * Frequency standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1210 * sumId.sumOfFrequencies -> Sum ((xi -Xa)^2)
1211 * inner_component -> 1/N Sum ((xi -Xa)^2)
1212 * frequency_standard_deviation-> sqrt(1/N Sum ((xi -Xa)^2))
1215 static int CalculateFrequencyStandardDeviation(gint id, InterruptEventData *event_data)
1219 guint64 inner_component;
1220 guint64 frequency_standard_deviation = 0;
1221 for(i = 0; i < event_data->SumArray->len; i++)
1223 sumId = g_array_index(event_data->SumArray, SumId, i);
1224 if(id == sumId.irqId)
1226 if(sumId.TotalNumberOfInterrupts != 0)
1227 inner_component = sumId.sumOfFrequencies / sumId.TotalNumberOfInterrupts;
1229 inner_component = 0;
1231 frequency_standard_deviation = sqrt(inner_component);
1234 return frequency_standard_deviation;
1238 * This function is called by the main window
1239 * when the time interval needs to be updated.
1241 gboolean interrupt_update_time_window(void * hook_data, void * call_data)
1243 InterruptEventData *event_data = (InterruptEventData *) hook_data;
1244 const TimeWindowNotifyData *time_window_nofify_data = ((const TimeWindowNotifyData *)call_data);
1245 event_data->time_window = *time_window_nofify_data->new_time_window;
1246 g_info("interrupts: interrupt_update_time_window()\n");
1247 Tab *tab = event_data->tab;
1248 lttvwindow_events_request_remove_all(tab, event_data);
1249 FirstRequest(event_data );
1254 gboolean trace_header(void *hook_data, void *call_data)
1257 InterruptEventData *event_data = (InterruptEventData *)hook_data;
1258 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
1264 void interrupt_destroy_walk(gpointer data, gpointer user_data)
1266 g_info("interrupt_destroy_walk");
1267 InterruptEventData *event_data = (InterruptEventData*) data;
1268 interrupt_destructor((InterruptEventData*)data);
1272 void interrupt_destructor(InterruptEventData *event_viewer_data)
1274 /* May already been done by GTK window closing */
1275 g_info("enter interrupt_destructor \n");
1276 if(GTK_IS_WIDGET(event_viewer_data->Hbox))
1278 gtk_widget_destroy(event_viewer_data->Hbox);
1283 This function is called when the viewer is destroyed to free hooks and memory
1285 static void InterruptFree(InterruptEventData *event_viewer_data)
1287 Tab *tab = event_viewer_data->tab;
1291 g_array_free(event_viewer_data->FirstRequestIrqExit, TRUE);
1292 g_array_free(event_viewer_data->FirstRequestIrqEntry, TRUE);
1293 g_array_free(event_viewer_data->SecondRequestIrqEntry, TRUE);
1294 g_array_free(event_viewer_data->SecondRequestIrqExit, TRUE);
1295 g_array_free(event_viewer_data->SumArray, TRUE);
1297 lttvwindow_unregister_time_window_notify(tab, interrupt_update_time_window, event_viewer_data);
1299 lttvwindow_events_request_remove_all(event_viewer_data->tab,
1302 interrupt_data_list = g_slist_remove(interrupt_data_list, event_viewer_data);
1309 * plugin's destroy function
1311 * This function releases the memory reserved by the module and unregisters
1312 * everything that has been registered in the gtkTraceSet API.
1314 static void destroy()
1317 g_info("Destroy interrupts");
1318 g_slist_foreach(interrupt_data_list, interrupt_destroy_walk, NULL );
1319 g_slist_free(interrupt_data_list);
1320 lttvwindow_unregister_constructor(interrupts);
1324 LTTV_MODULE("interrupts", "interrupts info view", \
1325 "Graphical module to display interrupts performance", \
1326 init, destroy, "lttvwindow")