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 LttvHooksByIdChannelArray
* 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
)
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
;
251 /*Get the current time frame from the main window */
252 event_viewer_data
->time_window
= lttvwindow_get_time_window(tab
);
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
));
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
));
260 event_viewer_data
->SumArray
= g_array_new(FALSE
, FALSE
, sizeof(SumId
));
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*/);
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 */
286 event_viewer_data
->TreeView
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (event_viewer_data
->ListStore
));
288 g_object_unref (G_OBJECT (event_viewer_data
->ListStore
));
290 renderer
= gtk_cell_renderer_text_new ();
291 column
= gtk_tree_view_column_new_with_attributes ("CPU ID",
293 "text", CPUID_COLUMN
,
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
);
300 renderer
= gtk_cell_renderer_text_new ();
301 column
= gtk_tree_view_column_new_with_attributes ("IRQ ID",
303 "text", IRQ_ID_COLUMN
,
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
);
309 renderer
= gtk_cell_renderer_text_new ();
310 column
= gtk_tree_view_column_new_with_attributes ("Frequency (Hz)",
312 "text", FREQUENCY_COLUMN
,
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
);
318 renderer
= gtk_cell_renderer_text_new ();
319 column
= gtk_tree_view_column_new_with_attributes ("Total Duration (nsec)",
321 "text", DURATION_COLUMN
,
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
);
328 renderer
= gtk_cell_renderer_text_new ();
329 column
= gtk_tree_view_column_new_with_attributes ("Duration standard deviation (nsec)",
331 "text", DURATION_STANDARD_DEV_COLUMN
,
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
);
337 renderer
= gtk_cell_renderer_text_new ();
338 column
= gtk_tree_view_column_new_with_attributes ("Max IRQ handler duration (nsec) [time interval]",
340 "text", MAX_IRQ_HANDLER_COLUMN
,
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
);
346 renderer
= gtk_cell_renderer_text_new ();
347 column
= gtk_tree_view_column_new_with_attributes ("Min IRQ handler duration (nsec) [time interval]",
349 "text", MIN_IRQ_HANDLER_COLUMN
,
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
);
355 renderer
= gtk_cell_renderer_text_new ();
356 column
= gtk_tree_view_column_new_with_attributes (" Average period (nsec)",
358 "text", AVERAGE_PERIOD
,
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
);
364 renderer
= gtk_cell_renderer_text_new ();
365 column
= gtk_tree_view_column_new_with_attributes ("Period standard deviation (nsec)",
367 "text", PERIOD_STANDARD_DEV_COLUMN
,
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
);
373 renderer
= gtk_cell_renderer_text_new ();
374 column
= gtk_tree_view_column_new_with_attributes ("Frequency standard deviation (Hz)",
376 "text", FREQUENCY_STANDARD_DEV_COLUMN
,
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
);
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
);
386 gtk_container_add (GTK_CONTAINER (event_viewer_data
->ScrollWindow
), event_viewer_data
->TreeView
);
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);
391 gtk_widget_show(event_viewer_data
->Hbox
);
392 gtk_widget_show(event_viewer_data
->TreeView
);
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
,
400 g_object_set_data_full(G_OBJECT(event_viewer_data
->Hbox
),
403 (GDestroyNotify
) InterruptFree
);
405 FirstRequest(event_viewer_data
);
406 return event_viewer_data
;
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
419 static void FirstRequest(InterruptEventData
*event_data
)
421 guint i
, k
, nb_trace
;
424 EventsRequest
*events_request
;
426 LttvTracesetContext
*tsc
= lttvwindow_get_traceset_context(event_data
->tab
);
428 /* Get the traceset */
429 LttvTraceset
*traceset
= tsc
->ts
;
431 nb_trace
= lttv_traceset_number(traceset
);
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);
438 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 2);
440 event_data
->hooks_trace_before
= lttv_hooks_new();
442 /* Registers a hook function */
443 lttv_hooks_add(event_data
->hooks_trace_before
, trace_header
, event_data
, LTTV_PRIO_DEFAULT
);
445 event_data
->hooks_trace_after
= lttv_hooks_new();
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();
454 /*Register event_by_id_hooks with a callback function*/
455 lttv_trace_find_hook(ts
->parent
.t
,
458 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
459 FirstRequestIrqEntryCallback
,
463 lttv_trace_find_hook(ts
->parent
.t
,
467 FirstRequestIrqExitCallback
,
471 /*iterate through the facility list*/
472 for(k
= 0 ; k
< hooks
->len
; k
++)
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
),
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
;
495 events_request
->hooks
= hooks
;
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
;
508 lttvwindow_events_request(event_data
->tab
, events_request
);
514 * This function is called whenever an irq_entry event occurs.
517 static gboolean
FirstRequestIrqEntryCallback(void *hook_data
, void *call_data
)
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
);
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
);
543 * This function is called whenever an irq_exit event occurs.
546 gboolean
FirstRequestIrqExitCallback(void *hook_data
, void *call_data
)
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
);
559 CalculateData( event_time
, cpu_id
, event_data
);
565 * This function calculates the duration of an interrupt.
568 static void CalculateData(LttTime time_exit
, guint cpu_id
,InterruptEventData
*event_data
)
573 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
574 GArray
*FirstRequestIrqEntry
= event_data
->FirstRequestIrqEntry
;
575 for(i
= FirstRequestIrqEntry
->len
-1; i
>=0; i
--)
577 element
= &g_array_index(FirstRequestIrqEntry
,irq_entry
,i
);
578 if(element
->cpu_id
== cpu_id
)
580 CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(element
,time_exit
, FirstRequestIrqExit
);
581 g_array_remove_index(FirstRequestIrqEntry
, i
);
589 * This function calculates the total duration of an interrupt and the longest & shortest Irq handlers.
592 static void CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(irq_entry
*e
, LttTime time_exit
, GArray
*FirstRequestIrqExit
)
598 gboolean notFound
= FALSE
;
599 memset ((void*)&irq
, 0,sizeof(Irq
));
602 if(FirstRequestIrqExit
->len
== NO_ITEMS
)
604 irq
.cpu_id
= e
->cpu_id
;
606 irq
.TotalNumberOfInterrupts
++;
607 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
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
);
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
);
617 g_array_append_val (FirstRequestIrqExit
, irq
);
621 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
623 element
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
624 if(element
->id
== e
->id
)
627 duration
= ltt_time_sub(time_exit
, e
->event_time
);
628 element
->total_duration
= ltt_time_add(element
->total_duration
, duration
);
629 element
->TotalNumberOfInterrupts
++;
631 if(ltt_time_compare(duration
,element
->max_irq_handler
.duration
) > 0)
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
;
638 if(ltt_time_compare(duration
,element
->min_irq_handler
.duration
) < 0)
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
;
648 irq
.cpu_id
= e
->cpu_id
;
650 irq
.TotalNumberOfInterrupts
++;
651 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
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
);
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
);
661 g_array_append_val (FirstRequestIrqExit
, irq
);
667 * This function passes the second EventsRequest to LTTV
670 static gboolean
SecondRequest(void *hook_data
, void *call_data
)
672 guint i
, k
, nb_trace
;
676 EventsRequest
*events_request
;
678 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
679 LttvTracesetContext
*tsc
= lttvwindow_get_traceset_context(event_data
->tab
);
680 CalculateAverageDurationForEachIrqId(event_data
);
682 /* Get the traceset */
683 LttvTraceset
*traceset
= tsc
->ts
;
685 nb_trace
= lttv_traceset_number(traceset
);
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);
692 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 2);
694 event_data
->hooks_trace_after
= lttv_hooks_new();
696 /* Registers a hook function */
697 lttv_hooks_add(event_data
->hooks_trace_after
, DisplayViewer
, event_data
, LTTV_PRIO_DEFAULT
);
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();
704 /*Register event_by_id_hooks with a callback function*/
705 ret
= lttv_trace_find_hook(ts
->parent
.t
,
708 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
709 SecondRequestIrqEntryCallback
,
713 ret
= lttv_trace_find_hook(ts
->parent
.t
,
717 SecondRequestIrqExitCallback
,
723 /* iterate through the facility list */
724 for(k
= 0 ; k
< hooks
->len
; k
++)
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
),
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
;
747 events_request
->hooks
= hooks
;
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
;
760 lttvwindow_events_request(event_data
->tab
, events_request
);
766 * This function calculates the average duration for each Irq Id
769 static void CalculateAverageDurationForEachIrqId(InterruptEventData
*event_data
)
774 GArray
* FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
775 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
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
;
784 element
->average_duration
= 0;
790 * This function is called whenever an irq_entry event occurs. Use in the second request
793 static gboolean
SecondRequestIrqEntryCallback(void *hook_data
, void *call_data
)
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
);
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
);
819 * This function is called whenever an irq_exit event occurs in the second request.
822 static gboolean
SecondRequestIrqExitCallback(void *hook_data
, void *call_data
)
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
;
831 LttEvent
*event
= ltt_tracefile_get_event(tfc
->tf
);
833 CalculateXi(event
, event_data
, tfs
->cpu
);
839 * This function is called whenever an irq_exit event occurs in the second request.
842 static void CalculateXi(LttEvent
*event_irq_exit
, InterruptEventData
*event_data
, guint cpu_id
)
849 GArray
*SecondRequestIrqEntry
= event_data
->SecondRequestIrqEntry
;
850 for(i
= 0; i
< SecondRequestIrqEntry
->len
; i
++)
852 element
= &g_array_index(SecondRequestIrqEntry
,irq_entry
,i
);
853 if(element
->cpu_id
== cpu_id
)
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
;
861 SumItems(irq_id
, Xi
,event_data
);
862 g_array_remove_index(SecondRequestIrqEntry
, i
);
870 * This function computes the Sum ((xi -Xa)^2) and store the result in SumArray
873 static void SumItems(gint irq_id
, LttTime Xi
, InterruptEventData
*event_data
)
878 gint duration_inner_part
;
879 guint64 period_inner_part
;
880 guint64 frequency_inner_part
;
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
;
893 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
895 average
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
896 if(irq_id
== average
->id
)
898 duration_inner_part
= Xi_in_ns
- average
->average_duration
;
899 FrequencyHZ
= FrequencyInHZ(average
->TotalNumberOfInterrupts
, event_data
->time_window
);
901 // compute (xi -Xa)^2 of the duration Standard deviation
902 sum
.TotalNumberOfInterrupts
= average
->TotalNumberOfInterrupts
;
903 sum
.sumOfDurations
= pow (duration_inner_part
, 2);
905 // compute (xi -Xa)^2 of the period Standard deviation
906 period_inner_part
= CalculatePeriodInnerPart(Xi_in_ns
, FrequencyHZ
);
908 // compute (xi -Xa)^2 of the frequency Standard deviation
909 frequency_inner_part
= CalculateFrequencyInnerPart(Xi_in_ns
, FrequencyHZ
);
911 sum
.sumOfPeriods
= period_inner_part
;
913 sum
.sumOfFrequencies
= frequency_inner_part
;
915 if(event_data
->SumArray
->len
== NO_ITEMS
)
917 g_array_append_val (SumArray
, sum
);
921 for(i
= 0; i
< SumArray
->len
; i
++)
923 sumItem
= &g_array_index(SumArray
, SumId
, i
);
924 if(sumItem
->irqId
== irq_id
)
927 sumItem
->sumOfDurations
+= sum
.sumOfDurations
;
928 sumItem
->sumOfPeriods
+= sum
.sumOfPeriods
;
929 sumItem
->sumOfFrequencies
+= sum
.sumOfFrequencies
;
934 g_array_append_val (SumArray
, sum
);
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
947 static guint64
CalculatePeriodInnerPart(guint Xi
, guint FrequencyHZ
)
950 double periodInSec
; /*period in sec*/
954 periodInSec
= (double)1/FrequencyHZ
;
955 periodInSec
*= NANOSECONDS_PER_SECOND
;
956 periodInNSec
= (int)periodInSec
;
958 difference
= Xi
- periodInNSec
;
959 result
= pow (difference
, 2);
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
967 static guint64
CalculateFrequencyInnerPart(guint Xi_in_ns
, guint FrequencyHZ
)
972 difference
= Xi_in_ns
- FrequencyHZ
;
973 result
= pow (difference
, 2);
977 * This function displays the result on the viewer
980 static gboolean
DisplayViewer(void *hook_data
, void *call_data
)
986 guint maxIRQduration
;
987 guint minIRQduration
;
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
;
996 gtk_list_store_clear(event_data
->ListStore
);
997 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
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
;
1005 maxIRQduration
= element
.max_irq_handler
.duration
.tv_sec
;
1006 maxIRQduration
*= NANOSECONDS_PER_SECOND
;
1007 maxIRQduration
+= element
.max_irq_handler
.duration
.tv_nsec
;
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
) ;
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
) ;
1021 FrequencyHZ
= FrequencyInHZ(element
.TotalNumberOfInterrupts
,event_data
->time_window
);
1023 if(FrequencyHZ
!= 0)
1025 periodInSec
= (double)1/FrequencyHZ
;
1026 periodInSec
*= NANOSECONDS_PER_SECOND
;
1027 periodInNsec
= (int)periodInSec
;
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
),
1047 if(event_data
->FirstRequestIrqExit
->len
)
1049 g_array_remove_range (event_data
->FirstRequestIrqExit
,0,event_data
->FirstRequestIrqExit
->len
);
1052 if(event_data
->FirstRequestIrqEntry
->len
)
1054 g_array_remove_range (event_data
->FirstRequestIrqEntry
,0,event_data
->FirstRequestIrqEntry
->len
);
1057 if(event_data
->SecondRequestIrqEntry
->len
)
1059 g_array_remove_range (event_data
->SecondRequestIrqEntry
,0,event_data
->SecondRequestIrqEntry
->len
);
1062 if(event_data
->SecondRequestIrqExit
->len
)
1064 g_array_remove_range (event_data
->SecondRequestIrqExit
,0, event_data
->SecondRequestIrqExit
->len
);
1067 if(event_data
->SumArray
->len
)
1069 g_array_remove_range (event_data
->SumArray
,0, event_data
->SumArray
->len
);
1077 * This function converts the number of interrupts over a time window to
1080 static int FrequencyInHZ(gint NumerofInterruptions
, TimeWindow time_window
)
1082 guint64 frequencyHz
= 0;
1083 double timeSec
; // time in second
1085 result
= ltt_time_to_double(time_window
.time_width
);
1086 timeSec
= (result
/NANOSECONDS_PER_SECOND
); //time in second
1087 frequencyHz
= NumerofInterruptions
/ timeSec
;
1092 * This function calculates the duration standard deviation
1093 * Duration standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
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))
1099 static int CalculateDurationStandardDeviation(gint id
, InterruptEventData
*event_data
)
1103 double inner_component
;
1105 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
1107 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
1108 if(id
== sumId
.irqId
)
1110 if(sumId
.TotalNumberOfInterrupts
!= 0)
1111 inner_component
= sumId
.sumOfDurations
/ sumId
.TotalNumberOfInterrupts
;
1113 inner_component
= 0.0;
1114 deviation
= sqrt(inner_component
);
1123 * This function calculates the period standard deviation
1124 * Period standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
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))
1132 static int CalculatePeriodStandardDeviation(gint id
, InterruptEventData
*event_data
)
1136 guint64 inner_component
;
1137 guint64 period_standard_deviation
= 0;
1139 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
1141 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
1142 if(id
== sumId
.irqId
)
1144 if(sumId
.TotalNumberOfInterrupts
!= 0)
1145 inner_component
= sumId
.sumOfPeriods
/ sumId
.TotalNumberOfInterrupts
;
1147 inner_component
= 0;
1149 period_standard_deviation
= sqrt(inner_component
);
1153 return period_standard_deviation
;
1157 * This function calculates the frequency standard deviation
1158 * Frequency standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
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))
1165 static int CalculateFrequencyStandardDeviation(gint id
, InterruptEventData
*event_data
)
1169 guint64 inner_component
;
1170 guint64 frequency_standard_deviation
= 0;
1171 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
1173 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
1174 if(id
== sumId
.irqId
)
1176 if(sumId
.TotalNumberOfInterrupts
!= 0)
1177 inner_component
= sumId
.sumOfFrequencies
/ sumId
.TotalNumberOfInterrupts
;
1179 inner_component
= 0;
1181 frequency_standard_deviation
= sqrt(inner_component
);
1184 return frequency_standard_deviation
;
1188 * This function is called by the main window
1189 * when the time interval needs to be updated.
1191 gboolean
interrupt_update_time_window(void * hook_data
, void * call_data
)
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
);
1204 gboolean
trace_header(void *hook_data
, void *call_data
)
1209 void interrupt_destroy_walk(gpointer data
, gpointer user_data
)
1211 g_info("interrupt_destroy_walk");
1212 interrupt_destructor((InterruptEventData
*)data
);
1216 void interrupt_destructor(InterruptEventData
*event_viewer_data
)
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
))
1222 gtk_widget_destroy(event_viewer_data
->Hbox
);
1227 This function is called when the viewer is destroyed to free hooks and memory
1229 static void InterruptFree(InterruptEventData
*event_viewer_data
)
1231 Tab
*tab
= event_viewer_data
->tab
;
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
);
1241 lttvwindow_unregister_time_window_notify(tab
, interrupt_update_time_window
, event_viewer_data
);
1243 lttvwindow_events_request_remove_all(event_viewer_data
->tab
,
1246 interrupt_data_list
= g_slist_remove(interrupt_data_list
, event_viewer_data
);
1253 * plugin's destroy function
1255 * This function releases the memory reserved by the module and unregisters
1256 * everything that has been registered in the gtkTraceSet API.
1258 static void destroy()
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
);
1268 LTTV_MODULE("interrupts", "interrupts info view", \
1269 "Graphical module to display interrupts performance", \
1270 init
, destroy
, "lttvwindow")