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)
101 guint TotalNumberOfInterrupts
;
102 LttTime total_duration
;
103 guint average_duration
;
104 IrqDuration max_irq_handler
;
105 IrqDuration min_irq_handler
;
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
130 /** Array containing instanced objects. Used when module is unloaded */
131 static GSList
*interrupt_data_list
= NULL
;
134 //fixed #define TRACE_NUMBER 0
136 typedef struct _InterruptEventData
{
138 /*Graphical Widgets */
139 GtkWidget
* ScrollWindow
;
140 GtkListStore
*ListStore
;
143 GtkTreeSelection
*SelectionTree
;
145 Tab
* tab
; /* tab that contains this plug-in*/
147 LttvHooks
* event_hooks
;
148 LttvHooks
* hooks_trace_after
;
149 LttvHooks
* hooks_trace_before
;
150 TimeWindow time_window
;
151 LttvHooksById
* event_by_id_hooks
;
152 GArray
*FirstRequestIrqExit
;
153 GArray
*FirstRequestIrqEntry
;
154 GArray
*SecondRequestIrqEntry
;
155 GArray
*SecondRequestIrqExit
;
158 } InterruptEventData
;
161 /* Function prototypes */
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
);
188 /* Enumeration of the columns */
194 DURATION_STANDARD_DEV_COLUMN
,
195 MAX_IRQ_HANDLER_COLUMN
,
196 MIN_IRQ_HANDLER_COLUMN
,
198 PERIOD_STANDARD_DEV_COLUMN
,
199 FREQUENCY_STANDARD_DEV_COLUMN
,
209 * This is the entry point of the viewer.
213 g_info("interrupts: init()");
214 lttvwindow_register_constructor("interrupts",
216 "Insert Interrupts View",
217 hInterruptsInsert_xpm
,
218 "Insert Interrupts View",
228 static GtkWidget
*interrupts(LttvPlugin
*plugin
)
230 LttvPluginTab
*ptab
= LTTV_PLUGIN_TAB(plugin
);
231 InterruptEventData
* event_data
= system_info(ptab
) ;
233 return event_data
->Hbox
;
239 * This function initializes the Event Viewer functionnality through the
242 InterruptEventData
*system_info(LttvPluginTab
*ptab
)
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
;
253 /*Get the current time frame from the main window */
254 event_viewer_data
->time_window
= lttvwindow_get_time_window(tab
);
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
));
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
));
262 event_viewer_data
->SumArray
= g_array_new(FALSE
, FALSE
, sizeof(SumId
));
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*/);
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 */
288 event_viewer_data
->TreeView
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (event_viewer_data
->ListStore
));
290 g_object_unref (G_OBJECT (event_viewer_data
->ListStore
));
292 renderer
= gtk_cell_renderer_text_new ();
293 column
= gtk_tree_view_column_new_with_attributes ("CPU ID",
295 "text", CPUID_COLUMN
,
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
);
302 renderer
= gtk_cell_renderer_text_new ();
303 column
= gtk_tree_view_column_new_with_attributes ("IRQ ID",
305 "text", IRQ_ID_COLUMN
,
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
);
311 renderer
= gtk_cell_renderer_text_new ();
312 column
= gtk_tree_view_column_new_with_attributes ("Frequency (Hz)",
314 "text", FREQUENCY_COLUMN
,
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
);
320 renderer
= gtk_cell_renderer_text_new ();
321 column
= gtk_tree_view_column_new_with_attributes ("Total Duration (nsec)",
323 "text", DURATION_COLUMN
,
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
);
330 renderer
= gtk_cell_renderer_text_new ();
331 column
= gtk_tree_view_column_new_with_attributes ("Duration standard deviation (nsec)",
333 "text", DURATION_STANDARD_DEV_COLUMN
,
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
);
339 renderer
= gtk_cell_renderer_text_new ();
340 column
= gtk_tree_view_column_new_with_attributes ("Max IRQ handler duration (nsec) [time interval]",
342 "text", MAX_IRQ_HANDLER_COLUMN
,
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
);
348 renderer
= gtk_cell_renderer_text_new ();
349 column
= gtk_tree_view_column_new_with_attributes ("Min IRQ handler duration (nsec) [time interval]",
351 "text", MIN_IRQ_HANDLER_COLUMN
,
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
);
357 renderer
= gtk_cell_renderer_text_new ();
358 column
= gtk_tree_view_column_new_with_attributes (" Average period (nsec)",
360 "text", AVERAGE_PERIOD
,
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
);
366 renderer
= gtk_cell_renderer_text_new ();
367 column
= gtk_tree_view_column_new_with_attributes ("Period standard deviation (nsec)",
369 "text", PERIOD_STANDARD_DEV_COLUMN
,
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
);
375 renderer
= gtk_cell_renderer_text_new ();
376 column
= gtk_tree_view_column_new_with_attributes ("Frequency standard deviation (Hz)",
378 "text", FREQUENCY_STANDARD_DEV_COLUMN
,
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
);
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
);
388 gtk_container_add (GTK_CONTAINER (event_viewer_data
->ScrollWindow
), event_viewer_data
->TreeView
);
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);
393 gtk_widget_show(event_viewer_data
->Hbox
);
394 gtk_widget_show(event_viewer_data
->TreeView
);
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
,
402 g_object_set_data_full(G_OBJECT(event_viewer_data
->Hbox
),
405 (GDestroyNotify
) InterruptFree
);
407 FirstRequest(event_viewer_data
);
408 return event_viewer_data
;
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
421 static void FirstRequest(InterruptEventData
*event_data
)
423 guint i
, k
, l
, nb_trace
;
433 EventsRequest
*events_request
;
437 LttvTracesetContext
*tsc
= lttvwindow_get_traceset_context(event_data
->tab
);
440 /* Get the traceset */
441 LttvTraceset
*traceset
= tsc
->ts
;
443 nb_trace
= lttv_traceset_number(traceset
);
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);
450 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 2);
452 event_data
->hooks_trace_before
= lttv_hooks_new();
454 /* Registers a hook function */
455 lttv_hooks_add(event_data
->hooks_trace_before
, trace_header
, event_data
, LTTV_PRIO_DEFAULT
);
457 event_data
->hooks_trace_after
= lttv_hooks_new();
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_new();
466 /*Register event_by_id_hooks with a callback function*/
467 lttv_trace_find_hook(ts
->parent
.t
,
470 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
471 FirstRequestIrqEntryCallback
,
475 lttv_trace_find_hook(ts
->parent
.t
,
479 FirstRequestIrqExitCallback
,
483 /*iterate through the facility list*/
484 for(k
= 0 ; k
< hooks
->len
; k
++)
486 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
487 lttv_hooks_add(lttv_hooks_by_id_find(event_data
->event_by_id_hooks
, th
->id
),
493 /* Initalize the EventsRequest structure */
494 events_request
->owner
= event_data
;
495 events_request
->viewer_data
= event_data
;
496 events_request
->servicing
= FALSE
;
497 events_request
->start_time
= event_data
->time_window
.start_time
;
498 events_request
->start_position
= NULL
;
499 events_request
->stop_flag
= FALSE
;
500 events_request
->end_time
= event_data
->time_window
.end_time
;
501 events_request
->num_events
= G_MAXUINT
;
502 events_request
->end_position
= NULL
;
503 events_request
->trace
= i
;
505 events_request
->hooks
= hooks
;
507 events_request
->before_chunk_traceset
= NULL
;
508 events_request
->before_chunk_trace
= event_data
->hooks_trace_before
;
509 events_request
->before_chunk_tracefile
= NULL
;
510 events_request
->event
= NULL
;
511 events_request
->event_by_id
= event_data
->event_by_id_hooks
;
512 events_request
->after_chunk_tracefile
= NULL
;
513 events_request
->after_chunk_trace
= NULL
;
514 events_request
->after_chunk_traceset
= NULL
;
515 events_request
->before_request
= NULL
;
516 events_request
->after_request
= event_data
->hooks_trace_after
;
518 lttvwindow_events_request(event_data
->tab
, events_request
);
524 * This function is called whenever an irq_entry event occurs.
527 static gboolean
FirstRequestIrqEntryCallback(void *hook_data
, void *call_data
)
533 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
534 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
535 LttvTraceHook
*th
= (LttvTraceHook
*) hook_data
;
536 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
537 InterruptEventData
*event_data
= events_request
->viewer_data
;
538 GArray
* FirstRequestIrqEntry
= event_data
->FirstRequestIrqEntry
;
539 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
540 event_time
= ltt_event_time(e
);
544 entry
.id
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
545 entry
.cpu_id
= cpu_id
;
546 entry
.event_time
= event_time
;
547 g_array_append_val (FirstRequestIrqEntry
, entry
);
553 * This function is called whenever an irq_exit event occurs.
556 gboolean
FirstRequestIrqExitCallback(void *hook_data
, void *call_data
)
560 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
561 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
562 LttvTraceHook
*th
= (LttvTraceHook
*) hook_data
;
563 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
564 InterruptEventData
*event_data
= events_request
->viewer_data
;
565 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
566 event_time
= ltt_event_time(e
);
569 CalculateData( event_time
, cpu_id
, event_data
);
575 * This function calculates the duration of an interrupt.
578 static void CalculateData(LttTime time_exit
, guint cpu_id
,InterruptEventData
*event_data
)
584 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
585 GArray
*FirstRequestIrqEntry
= event_data
->FirstRequestIrqEntry
;
586 for(i
= 0; i
< FirstRequestIrqEntry
->len
; i
++)
588 element
= &g_array_index(FirstRequestIrqEntry
,irq_entry
,i
);
589 if(element
->cpu_id
== cpu_id
)
591 CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(element
,time_exit
, FirstRequestIrqExit
);
592 g_array_remove_index(FirstRequestIrqEntry
, i
);
600 * This function calculates the total duration of an interrupt and the longest & shortest Irq handlers.
603 static void CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(irq_entry
*e
, LttTime time_exit
, GArray
*FirstRequestIrqExit
)
609 gboolean notFound
= FALSE
;
610 memset ((void*)&irq
, 0,sizeof(Irq
));
613 if(FirstRequestIrqExit
->len
== NO_ITEMS
)
615 irq
.cpu_id
= e
->cpu_id
;
617 irq
.TotalNumberOfInterrupts
++;
618 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
620 irq
.max_irq_handler
.start_time
= e
->event_time
;
621 irq
.max_irq_handler
.end_time
= time_exit
;
622 irq
.max_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
624 irq
.min_irq_handler
.start_time
= e
->event_time
;
625 irq
.min_irq_handler
.end_time
= time_exit
;
626 irq
.min_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
628 g_array_append_val (FirstRequestIrqExit
, irq
);
632 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
634 element
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
635 if(element
->id
== e
->id
)
638 duration
= ltt_time_sub(time_exit
, e
->event_time
);
639 element
->total_duration
= ltt_time_add(element
->total_duration
, duration
);
640 element
->TotalNumberOfInterrupts
++;
642 if(ltt_time_compare(duration
,element
->max_irq_handler
.duration
) > 0)
644 element
->max_irq_handler
.duration
= duration
;
645 element
->max_irq_handler
.start_time
= e
->event_time
;
646 element
->max_irq_handler
.end_time
= time_exit
;
649 if(ltt_time_compare(duration
,element
->min_irq_handler
.duration
) < 0)
651 element
->min_irq_handler
.duration
= duration
;
652 element
->min_irq_handler
.start_time
= e
->event_time
;
653 element
->min_irq_handler
.end_time
= time_exit
;
659 irq
.cpu_id
= e
->cpu_id
;
661 irq
.TotalNumberOfInterrupts
++;
662 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
664 irq
.max_irq_handler
.start_time
= e
->event_time
;
665 irq
.max_irq_handler
.end_time
= time_exit
;
666 irq
.max_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
668 irq
.min_irq_handler
.start_time
= e
->event_time
;
669 irq
.min_irq_handler
.end_time
= time_exit
;
670 irq
.min_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
672 g_array_append_val (FirstRequestIrqExit
, irq
);
678 * This function passes the second EventsRequest to LTTV
681 static gboolean
SecondRequest(void *hook_data
, void *call_data
)
684 guint i
, k
, l
, nb_trace
;
694 EventsRequest
*events_request
;
698 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
700 LttvTracesetContext
*tsc
= lttvwindow_get_traceset_context(event_data
->tab
);
702 CalculateAverageDurationForEachIrqId(event_data
);
704 /* Get the traceset */
705 LttvTraceset
*traceset
= tsc
->ts
;
707 nb_trace
= lttv_traceset_number(traceset
);
709 /* There are many traces in a traceset. Iteration for each trace. */
710 for(i
= 0 ; i
< nb_trace
; i
++) {
711 // fixed for(i = 0; i<MIN(TRACE_NUMBER+1, nb_trace);i++) {
712 events_request
= g_new(EventsRequest
, 1);
714 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 2);
716 event_data
->hooks_trace_after
= lttv_hooks_new();
718 /* Registers a hook function */
719 lttv_hooks_add(event_data
->hooks_trace_after
, DisplayViewer
, event_data
, LTTV_PRIO_DEFAULT
);
721 /* Get a trace state */
722 ts
= (LttvTraceState
*)tsc
->traces
[i
];
723 /* Create event_by_Id hooks */
724 event_data
->event_by_id_hooks
= lttv_hooks_by_id_new();
726 /*Register event_by_id_hooks with a callback function*/
727 ret
= lttv_trace_find_hook(ts
->parent
.t
,
730 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
731 SecondRequestIrqEntryCallback
,
735 ret
= lttv_trace_find_hook(ts
->parent
.t
,
739 SecondRequestIrqExitCallback
,
745 /* iterate through the facility list */
746 for(k
= 0 ; k
< hooks
->len
; k
++)
748 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
749 lttv_hooks_add(lttv_hooks_by_id_find(event_data
->event_by_id_hooks
, th
->id
),
755 /* Initalize the EventsRequest structure */
756 events_request
->owner
= event_data
;
757 events_request
->viewer_data
= event_data
;
758 events_request
->servicing
= FALSE
;
759 events_request
->start_time
= event_data
->time_window
.start_time
;
760 events_request
->start_position
= NULL
;
761 events_request
->stop_flag
= FALSE
;
762 events_request
->end_time
= event_data
->time_window
.end_time
;
763 events_request
->num_events
= G_MAXUINT
;
764 events_request
->end_position
= NULL
;
765 events_request
->trace
= i
;
767 events_request
->hooks
= hooks
;
769 events_request
->before_chunk_traceset
= NULL
;
770 events_request
->before_chunk_trace
= NULL
;
771 events_request
->before_chunk_tracefile
= NULL
;
772 events_request
->event
= NULL
;
773 events_request
->event_by_id
= event_data
->event_by_id_hooks
;
774 events_request
->after_chunk_tracefile
= NULL
;
775 events_request
->after_chunk_trace
= NULL
;
776 events_request
->after_chunk_traceset
= NULL
;
777 events_request
->before_request
= NULL
;
778 events_request
->after_request
= event_data
->hooks_trace_after
;
780 lttvwindow_events_request(event_data
->tab
, events_request
);
786 * This function calculates the average duration for each Irq Id
789 static void CalculateAverageDurationForEachIrqId(InterruptEventData
*event_data
)
794 GArray
* FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
795 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
797 element
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
798 real_data
= element
->total_duration
.tv_sec
;
799 real_data
*= NANOSECONDS_PER_SECOND
;
800 real_data
+= element
->total_duration
.tv_nsec
;
801 if(element
->TotalNumberOfInterrupts
!= 0)
802 element
->average_duration
= real_data
/ element
->TotalNumberOfInterrupts
;
804 element
->average_duration
= 0;
810 * This function is called whenever an irq_entry event occurs. Use in the second request
813 static gboolean
SecondRequestIrqEntryCallback(void *hook_data
, void *call_data
)
819 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
820 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
821 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
822 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
823 InterruptEventData
*event_data
= events_request
->viewer_data
;
824 GArray
* SecondRequestIrqEntry
= event_data
->SecondRequestIrqEntry
;
825 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
826 event_time
= ltt_event_time(e
);
830 entry
.id
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
831 entry
.cpu_id
= cpu_id
;
832 entry
.event_time
= event_time
;
833 g_array_append_val (SecondRequestIrqEntry
, entry
);
839 * This function is called whenever an irq_exit event occurs in the second request.
842 static gboolean
SecondRequestIrqExitCallback(void *hook_data
, void *call_data
)
845 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
846 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
847 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
848 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
849 InterruptEventData
*event_data
= events_request
->viewer_data
;
851 LttEvent
*event
= ltt_tracefile_get_event(tfc
->tf
);
853 CalculateXi(event
, event_data
, tfs
->cpu
);
859 * This function is called whenever an irq_exit event occurs in the second request.
862 static void CalculateXi(LttEvent
*event_irq_exit
, InterruptEventData
*event_data
, guint cpu_id
)
869 GArray
*SecondRequestIrqExit
= event_data
->SecondRequestIrqExit
;
870 GArray
*SecondRequestIrqEntry
= event_data
->SecondRequestIrqEntry
;
871 for(i
= 0; i
< SecondRequestIrqEntry
->len
; i
++)
873 element
= &g_array_index(SecondRequestIrqEntry
,irq_entry
,i
);
874 if(element
->cpu_id
== cpu_id
)
877 /* time calculation */
878 exit_time
= ltt_event_time(event_irq_exit
);
879 Xi
= ltt_time_sub(exit_time
, element
->event_time
);
880 irq_id
= element
->id
;
882 SumItems(irq_id
, Xi
,event_data
);
883 g_array_remove_index(SecondRequestIrqEntry
, i
);
891 * This function computes the Sum ((xi -Xa)^2) and store the result in SumArray
894 static void SumItems(gint irq_id
, LttTime Xi
, InterruptEventData
*event_data
)
899 gint duration_inner_part
;
900 guint64 period_inner_part
;
901 guint64 frequency_inner_part
;
907 gboolean notFound
= FALSE
;
908 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
909 GArray
*SumArray
= event_data
->SumArray
;
910 Xi_in_ns
= Xi
.tv_sec
;
911 Xi_in_ns
*= NANOSECONDS_PER_SECOND
;
912 Xi_in_ns
+= Xi
.tv_nsec
;
914 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
916 average
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
917 if(irq_id
== average
->id
)
919 duration_inner_part
= Xi_in_ns
- average
->average_duration
;
920 FrequencyHZ
= FrequencyInHZ(average
->TotalNumberOfInterrupts
, event_data
->time_window
);
922 // compute (xi -Xa)^2 of the duration Standard deviation
923 sum
.TotalNumberOfInterrupts
= average
->TotalNumberOfInterrupts
;
924 sum
.sumOfDurations
= pow (duration_inner_part
, 2);
926 // compute (xi -Xa)^2 of the period Standard deviation
927 period_inner_part
= CalculatePeriodInnerPart(Xi_in_ns
, FrequencyHZ
);
929 // compute (xi -Xa)^2 of the frequency Standard deviation
930 frequency_inner_part
= CalculateFrequencyInnerPart(Xi_in_ns
, FrequencyHZ
);
932 sum
.sumOfPeriods
= period_inner_part
;
934 sum
.sumOfFrequencies
= frequency_inner_part
;
936 if(event_data
->SumArray
->len
== NO_ITEMS
)
938 g_array_append_val (SumArray
, sum
);
942 for(i
= 0; i
< SumArray
->len
; i
++)
944 sumItem
= &g_array_index(SumArray
, SumId
, i
);
945 if(sumItem
->irqId
== irq_id
)
948 sumItem
->sumOfDurations
+= sum
.sumOfDurations
;
949 sumItem
->sumOfPeriods
+= sum
.sumOfPeriods
;
950 sumItem
->sumOfFrequencies
+= sum
.sumOfFrequencies
;
955 g_array_append_val (SumArray
, sum
);
965 * This function computes the inner part of the period standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
966 * The inner part is: (xi -Xa)^2
968 static guint64
CalculatePeriodInnerPart(guint Xi
, guint FrequencyHZ
)
971 double periodInSec
; /*period in sec*/
975 periodInSec
= (double)1/FrequencyHZ
;
976 periodInSec
*= NANOSECONDS_PER_SECOND
;
977 periodInNSec
= (int)periodInSec
;
979 difference
= Xi
- periodInNSec
;
980 result
= pow (difference
, 2);
985 * This function computes the inner part of the frequency standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
986 * The inner part is: (xi -Xa)^2
988 static guint64
CalculateFrequencyInnerPart(guint Xi_in_ns
, guint FrequencyHZ
)
993 difference
= Xi_in_ns
- FrequencyHZ
;
994 result
= pow (difference
, 2);
998 * This function displays the result on the viewer
1001 static gboolean
DisplayViewer(void *hook_data
, void *call_data
)
1007 LttTime average_duration
;
1010 guint maxIRQduration
;
1011 guint minIRQduration
;
1014 char maxIrqHandler
[80];
1015 char minIrqHandler
[80];
1016 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
1017 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
1018 int FrequencyHZ
= 0;
1020 gtk_list_store_clear(event_data
->ListStore
);
1021 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
1023 element
= g_array_index(FirstRequestIrqExit
,Irq
,i
);
1024 real_data
= element
.total_duration
.tv_sec
;
1025 real_data
*= NANOSECONDS_PER_SECOND
;
1026 real_data
+= element
.total_duration
.tv_nsec
;
1029 maxIRQduration
= element
.max_irq_handler
.duration
.tv_sec
;
1030 maxIRQduration
*= NANOSECONDS_PER_SECOND
;
1031 maxIRQduration
+= element
.max_irq_handler
.duration
.tv_nsec
;
1033 sprintf(maxIrqHandler
, "%d [%d.%d - %d.%d]",maxIRQduration
, element
.max_irq_handler
.start_time
.tv_sec
, \
1034 element
.max_irq_handler
.start_time
.tv_nsec
, element
.max_irq_handler
.end_time
.tv_sec
, \
1035 element
.max_irq_handler
.end_time
.tv_nsec
) ;
1037 minIRQduration
= element
.min_irq_handler
.duration
.tv_sec
;
1038 minIRQduration
*= NANOSECONDS_PER_SECOND
;
1039 minIRQduration
+= element
.min_irq_handler
.duration
.tv_nsec
;
1040 sprintf(minIrqHandler
, "%d [%d.%d - %d.%d]",minIRQduration
, element
.min_irq_handler
.start_time
.tv_sec
, \
1041 element
.min_irq_handler
.start_time
.tv_nsec
, element
.min_irq_handler
.end_time
.tv_sec
, \
1042 element
.min_irq_handler
.end_time
.tv_nsec
) ;
1045 FrequencyHZ
= FrequencyInHZ(element
.TotalNumberOfInterrupts
,event_data
->time_window
);
1047 if(FrequencyHZ
!= 0)
1049 periodInSec
= (double)1/FrequencyHZ
;
1050 periodInSec
*= NANOSECONDS_PER_SECOND
;
1051 periodInNsec
= (int)periodInSec
;
1055 gtk_list_store_append (event_data
->ListStore
, &iter
);
1056 gtk_list_store_set (event_data
->ListStore
, &iter
,
1057 CPUID_COLUMN
, element
.cpu_id
,
1058 IRQ_ID_COLUMN
, element
.id
,
1059 FREQUENCY_COLUMN
, FrequencyHZ
,
1060 DURATION_COLUMN
, real_data
,
1061 DURATION_STANDARD_DEV_COLUMN
, CalculateDurationStandardDeviation(element
.id
, event_data
),
1062 MAX_IRQ_HANDLER_COLUMN
, maxIrqHandler
,
1063 MIN_IRQ_HANDLER_COLUMN
, minIrqHandler
,
1064 AVERAGE_PERIOD
, periodInNsec
,
1065 PERIOD_STANDARD_DEV_COLUMN
, CalculatePeriodStandardDeviation(element
.id
, event_data
),
1066 FREQUENCY_STANDARD_DEV_COLUMN
, CalculateFrequencyStandardDeviation(element
.id
, event_data
),
1071 if(event_data
->FirstRequestIrqExit
->len
)
1073 g_array_remove_range (event_data
->FirstRequestIrqExit
,0,event_data
->FirstRequestIrqExit
->len
);
1076 if(event_data
->FirstRequestIrqEntry
->len
)
1078 g_array_remove_range (event_data
->FirstRequestIrqEntry
,0,event_data
->FirstRequestIrqEntry
->len
);
1081 if(event_data
->SecondRequestIrqEntry
->len
)
1083 g_array_remove_range (event_data
->SecondRequestIrqEntry
,0,event_data
->SecondRequestIrqEntry
->len
);
1086 if(event_data
->SecondRequestIrqExit
->len
)
1088 g_array_remove_range (event_data
->SecondRequestIrqExit
,0, event_data
->SecondRequestIrqExit
->len
);
1091 if(event_data
->SumArray
->len
)
1093 g_array_remove_range (event_data
->SumArray
,0, event_data
->SumArray
->len
);
1101 * This function converts the number of interrupts over a time window to
1104 static int FrequencyInHZ(gint NumerofInterruptions
, TimeWindow time_window
)
1106 guint64 frequencyHz
= 0;
1107 double timeSec
; // time in second
1109 result
= ltt_time_to_double(time_window
.time_width
);
1110 timeSec
= (result
/NANOSECONDS_PER_SECOND
); //time in second
1111 frequencyHz
= NumerofInterruptions
/ timeSec
;
1116 * This function calculates the duration standard deviation
1117 * Duration standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1119 * sumId.sumOfDurations -> Sum ((xi -Xa)^2)
1120 * inner_component -> 1/N Sum ((xi -Xa)^2)
1121 * deviation-> sqrt(1/N Sum ((xi -Xa)^2))
1123 static int CalculateDurationStandardDeviation(gint id
, InterruptEventData
*event_data
)
1127 double inner_component
;
1129 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
1131 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
1132 if(id
== sumId
.irqId
)
1134 if(sumId
.TotalNumberOfInterrupts
!= 0)
1135 inner_component
= sumId
.sumOfDurations
/ sumId
.TotalNumberOfInterrupts
;
1137 inner_component
= 0.0;
1138 deviation
= sqrt(inner_component
);
1147 * This function calculates the period standard deviation
1148 * Period standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1150 * sumId.sumOfPeriods -> Sum ((xi -Xa)^2)
1151 * inner_component -> 1/N Sum ((xi -Xa)^2)
1152 * period_standard_deviation-> sqrt(1/N Sum ((xi -Xa)^2))
1156 static int CalculatePeriodStandardDeviation(gint id
, InterruptEventData
*event_data
)
1160 guint64 inner_component
;
1161 guint64 period_standard_deviation
= 0;
1163 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
1165 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
1166 if(id
== sumId
.irqId
)
1168 if(sumId
.TotalNumberOfInterrupts
!= 0)
1169 inner_component
= sumId
.sumOfPeriods
/ sumId
.TotalNumberOfInterrupts
;
1171 inner_component
= 0;
1173 period_standard_deviation
= sqrt(inner_component
);
1177 return period_standard_deviation
;
1181 * This function calculates the frequency standard deviation
1182 * Frequency standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1184 * sumId.sumOfFrequencies -> Sum ((xi -Xa)^2)
1185 * inner_component -> 1/N Sum ((xi -Xa)^2)
1186 * frequency_standard_deviation-> sqrt(1/N Sum ((xi -Xa)^2))
1189 static int CalculateFrequencyStandardDeviation(gint id
, InterruptEventData
*event_data
)
1193 guint64 inner_component
;
1194 guint64 frequency_standard_deviation
= 0;
1195 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
1197 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
1198 if(id
== sumId
.irqId
)
1200 if(sumId
.TotalNumberOfInterrupts
!= 0)
1201 inner_component
= sumId
.sumOfFrequencies
/ sumId
.TotalNumberOfInterrupts
;
1203 inner_component
= 0;
1205 frequency_standard_deviation
= sqrt(inner_component
);
1208 return frequency_standard_deviation
;
1212 * This function is called by the main window
1213 * when the time interval needs to be updated.
1215 gboolean
interrupt_update_time_window(void * hook_data
, void * call_data
)
1217 InterruptEventData
*event_data
= (InterruptEventData
*) hook_data
;
1218 const TimeWindowNotifyData
*time_window_nofify_data
= ((const TimeWindowNotifyData
*)call_data
);
1219 event_data
->time_window
= *time_window_nofify_data
->new_time_window
;
1220 g_info("interrupts: interrupt_update_time_window()\n");
1221 Tab
*tab
= event_data
->tab
;
1222 lttvwindow_events_request_remove_all(tab
, event_data
);
1223 FirstRequest(event_data
);
1228 gboolean
trace_header(void *hook_data
, void *call_data
)
1231 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
1232 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1238 void interrupt_destroy_walk(gpointer data
, gpointer user_data
)
1240 g_info("interrupt_destroy_walk");
1241 InterruptEventData
*event_data
= (InterruptEventData
*) data
;
1242 interrupt_destructor((InterruptEventData
*)data
);
1246 void interrupt_destructor(InterruptEventData
*event_viewer_data
)
1248 /* May already been done by GTK window closing */
1249 g_info("enter interrupt_destructor \n");
1250 if(GTK_IS_WIDGET(event_viewer_data
->Hbox
))
1252 gtk_widget_destroy(event_viewer_data
->Hbox
);
1257 This function is called when the viewer is destroyed to free hooks and memory
1259 static void InterruptFree(InterruptEventData
*event_viewer_data
)
1261 Tab
*tab
= event_viewer_data
->tab
;
1265 g_array_free(event_viewer_data
->FirstRequestIrqExit
, TRUE
);
1266 g_array_free(event_viewer_data
->FirstRequestIrqEntry
, TRUE
);
1267 g_array_free(event_viewer_data
->SecondRequestIrqEntry
, TRUE
);
1268 g_array_free(event_viewer_data
->SecondRequestIrqExit
, TRUE
);
1269 g_array_free(event_viewer_data
->SumArray
, TRUE
);
1271 lttvwindow_unregister_time_window_notify(tab
, interrupt_update_time_window
, event_viewer_data
);
1273 lttvwindow_events_request_remove_all(event_viewer_data
->tab
,
1276 interrupt_data_list
= g_slist_remove(interrupt_data_list
, event_viewer_data
);
1283 * plugin's destroy function
1285 * This function releases the memory reserved by the module and unregisters
1286 * everything that has been registered in the gtkTraceSet API.
1288 static void destroy()
1291 g_info("Destroy interrupts");
1292 g_slist_foreach(interrupt_data_list
, interrupt_destroy_walk
, NULL
);
1293 g_slist_free(interrupt_data_list
);
1294 lttvwindow_unregister_constructor(interrupts
);
1298 LTTV_MODULE("interrupts", "interrupts info view", \
1299 "Graphical module to display interrupts performance", \
1300 init
, destroy
, "lttvwindow")