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
)
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_channel_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_channel_find(
488 event_data
->event_by_id_hooks
,
489 th
->channel
, th
->id
),
495 /* Initalize the EventsRequest structure */
496 events_request
->owner
= event_data
;
497 events_request
->viewer_data
= event_data
;
498 events_request
->servicing
= FALSE
;
499 events_request
->start_time
= event_data
->time_window
.start_time
;
500 events_request
->start_position
= NULL
;
501 events_request
->stop_flag
= FALSE
;
502 events_request
->end_time
= event_data
->time_window
.end_time
;
503 events_request
->num_events
= G_MAXUINT
;
504 events_request
->end_position
= NULL
;
505 events_request
->trace
= i
;
507 events_request
->hooks
= hooks
;
509 events_request
->before_chunk_traceset
= NULL
;
510 events_request
->before_chunk_trace
= event_data
->hooks_trace_before
;
511 events_request
->before_chunk_tracefile
= NULL
;
512 events_request
->event
= NULL
;
513 events_request
->event_by_id_channel
= event_data
->event_by_id_hooks
;
514 events_request
->after_chunk_tracefile
= NULL
;
515 events_request
->after_chunk_trace
= NULL
;
516 events_request
->after_chunk_traceset
= NULL
;
517 events_request
->before_request
= NULL
;
518 events_request
->after_request
= event_data
->hooks_trace_after
;
520 lttvwindow_events_request(event_data
->tab
, events_request
);
526 * This function is called whenever an irq_entry event occurs.
529 static gboolean
FirstRequestIrqEntryCallback(void *hook_data
, void *call_data
)
535 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
536 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
537 LttvTraceHook
*th
= (LttvTraceHook
*) hook_data
;
538 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
539 InterruptEventData
*event_data
= events_request
->viewer_data
;
540 GArray
* FirstRequestIrqEntry
= event_data
->FirstRequestIrqEntry
;
541 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
542 event_time
= ltt_event_time(e
);
546 entry
.id
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
547 entry
.cpu_id
= cpu_id
;
548 entry
.event_time
= event_time
;
549 g_array_append_val (FirstRequestIrqEntry
, entry
);
555 * This function is called whenever an irq_exit event occurs.
558 gboolean
FirstRequestIrqExitCallback(void *hook_data
, void *call_data
)
562 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
563 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
564 LttvTraceHook
*th
= (LttvTraceHook
*) hook_data
;
565 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
566 InterruptEventData
*event_data
= events_request
->viewer_data
;
567 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
568 event_time
= ltt_event_time(e
);
571 CalculateData( event_time
, cpu_id
, event_data
);
577 * This function calculates the duration of an interrupt.
580 static void CalculateData(LttTime time_exit
, guint cpu_id
,InterruptEventData
*event_data
)
586 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
587 GArray
*FirstRequestIrqEntry
= event_data
->FirstRequestIrqEntry
;
588 for(i
= FirstRequestIrqEntry
->len
-1; i
>=0; i
--)
590 element
= &g_array_index(FirstRequestIrqEntry
,irq_entry
,i
);
591 if(element
->cpu_id
== cpu_id
)
593 CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(element
,time_exit
, FirstRequestIrqExit
);
594 g_array_remove_index(FirstRequestIrqEntry
, i
);
602 * This function calculates the total duration of an interrupt and the longest & shortest Irq handlers.
605 static void CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(irq_entry
*e
, LttTime time_exit
, GArray
*FirstRequestIrqExit
)
611 gboolean notFound
= FALSE
;
612 memset ((void*)&irq
, 0,sizeof(Irq
));
615 if(FirstRequestIrqExit
->len
== NO_ITEMS
)
617 irq
.cpu_id
= e
->cpu_id
;
619 irq
.TotalNumberOfInterrupts
++;
620 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
622 irq
.max_irq_handler
.start_time
= e
->event_time
;
623 irq
.max_irq_handler
.end_time
= time_exit
;
624 irq
.max_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
626 irq
.min_irq_handler
.start_time
= e
->event_time
;
627 irq
.min_irq_handler
.end_time
= time_exit
;
628 irq
.min_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
630 g_array_append_val (FirstRequestIrqExit
, irq
);
634 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
636 element
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
637 if(element
->id
== e
->id
)
640 duration
= ltt_time_sub(time_exit
, e
->event_time
);
641 element
->total_duration
= ltt_time_add(element
->total_duration
, duration
);
642 element
->TotalNumberOfInterrupts
++;
644 if(ltt_time_compare(duration
,element
->max_irq_handler
.duration
) > 0)
646 element
->max_irq_handler
.duration
= duration
;
647 element
->max_irq_handler
.start_time
= e
->event_time
;
648 element
->max_irq_handler
.end_time
= time_exit
;
651 if(ltt_time_compare(duration
,element
->min_irq_handler
.duration
) < 0)
653 element
->min_irq_handler
.duration
= duration
;
654 element
->min_irq_handler
.start_time
= e
->event_time
;
655 element
->min_irq_handler
.end_time
= time_exit
;
661 irq
.cpu_id
= e
->cpu_id
;
663 irq
.TotalNumberOfInterrupts
++;
664 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
666 irq
.max_irq_handler
.start_time
= e
->event_time
;
667 irq
.max_irq_handler
.end_time
= time_exit
;
668 irq
.max_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
670 irq
.min_irq_handler
.start_time
= e
->event_time
;
671 irq
.min_irq_handler
.end_time
= time_exit
;
672 irq
.min_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
674 g_array_append_val (FirstRequestIrqExit
, irq
);
680 * This function passes the second EventsRequest to LTTV
683 static gboolean
SecondRequest(void *hook_data
, void *call_data
)
686 guint i
, k
, l
, nb_trace
;
696 EventsRequest
*events_request
;
700 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
702 LttvTracesetContext
*tsc
= lttvwindow_get_traceset_context(event_data
->tab
);
704 CalculateAverageDurationForEachIrqId(event_data
);
706 /* Get the traceset */
707 LttvTraceset
*traceset
= tsc
->ts
;
709 nb_trace
= lttv_traceset_number(traceset
);
711 /* There are many traces in a traceset. Iteration for each trace. */
712 for(i
= 0 ; i
< nb_trace
; i
++) {
713 // fixed for(i = 0; i<MIN(TRACE_NUMBER+1, nb_trace);i++) {
714 events_request
= g_new(EventsRequest
, 1);
716 hooks
= g_array_sized_new(FALSE
, FALSE
, sizeof(LttvTraceHook
), 2);
718 event_data
->hooks_trace_after
= lttv_hooks_new();
720 /* Registers a hook function */
721 lttv_hooks_add(event_data
->hooks_trace_after
, DisplayViewer
, event_data
, LTTV_PRIO_DEFAULT
);
723 /* Get a trace state */
724 ts
= (LttvTraceState
*)tsc
->traces
[i
];
725 /* Create event_by_Id hooks */
726 event_data
->event_by_id_hooks
= lttv_hooks_by_id_channel_new();
728 /*Register event_by_id_hooks with a callback function*/
729 ret
= lttv_trace_find_hook(ts
->parent
.t
,
732 FIELD_ARRAY(LTT_FIELD_IRQ_ID
),
733 SecondRequestIrqEntryCallback
,
737 ret
= lttv_trace_find_hook(ts
->parent
.t
,
741 SecondRequestIrqExitCallback
,
747 /* iterate through the facility list */
748 for(k
= 0 ; k
< hooks
->len
; k
++)
750 th
= &g_array_index(hooks
, LttvTraceHook
, k
);
751 lttv_hooks_add(lttv_hooks_by_id_channel_find(
752 event_data
->event_by_id_hooks
,
753 th
->channel
, th
->id
),
759 /* Initalize the EventsRequest structure */
760 events_request
->owner
= event_data
;
761 events_request
->viewer_data
= event_data
;
762 events_request
->servicing
= FALSE
;
763 events_request
->start_time
= event_data
->time_window
.start_time
;
764 events_request
->start_position
= NULL
;
765 events_request
->stop_flag
= FALSE
;
766 events_request
->end_time
= event_data
->time_window
.end_time
;
767 events_request
->num_events
= G_MAXUINT
;
768 events_request
->end_position
= NULL
;
769 events_request
->trace
= i
;
771 events_request
->hooks
= hooks
;
773 events_request
->before_chunk_traceset
= NULL
;
774 events_request
->before_chunk_trace
= NULL
;
775 events_request
->before_chunk_tracefile
= NULL
;
776 events_request
->event
= NULL
;
777 events_request
->event_by_id_channel
= event_data
->event_by_id_hooks
;
778 events_request
->after_chunk_tracefile
= NULL
;
779 events_request
->after_chunk_trace
= NULL
;
780 events_request
->after_chunk_traceset
= NULL
;
781 events_request
->before_request
= NULL
;
782 events_request
->after_request
= event_data
->hooks_trace_after
;
784 lttvwindow_events_request(event_data
->tab
, events_request
);
790 * This function calculates the average duration for each Irq Id
793 static void CalculateAverageDurationForEachIrqId(InterruptEventData
*event_data
)
798 GArray
* FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
799 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
801 element
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
802 real_data
= element
->total_duration
.tv_sec
;
803 real_data
*= NANOSECONDS_PER_SECOND
;
804 real_data
+= element
->total_duration
.tv_nsec
;
805 if(element
->TotalNumberOfInterrupts
!= 0)
806 element
->average_duration
= real_data
/ element
->TotalNumberOfInterrupts
;
808 element
->average_duration
= 0;
814 * This function is called whenever an irq_entry event occurs. Use in the second request
817 static gboolean
SecondRequestIrqEntryCallback(void *hook_data
, void *call_data
)
823 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
824 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
825 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
826 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
827 InterruptEventData
*event_data
= events_request
->viewer_data
;
828 GArray
* SecondRequestIrqEntry
= event_data
->SecondRequestIrqEntry
;
829 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
830 event_time
= ltt_event_time(e
);
834 entry
.id
= ltt_event_get_long_unsigned(e
, lttv_trace_get_hook_field(th
, 0));
835 entry
.cpu_id
= cpu_id
;
836 entry
.event_time
= event_time
;
837 g_array_append_val (SecondRequestIrqEntry
, entry
);
843 * This function is called whenever an irq_exit event occurs in the second request.
846 static gboolean
SecondRequestIrqExitCallback(void *hook_data
, void *call_data
)
849 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
850 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
851 LttvTraceHook
*th
= (LttvTraceHook
*)hook_data
;
852 EventsRequest
*events_request
= (EventsRequest
*)th
->hook_data
;
853 InterruptEventData
*event_data
= events_request
->viewer_data
;
855 LttEvent
*event
= ltt_tracefile_get_event(tfc
->tf
);
857 CalculateXi(event
, event_data
, tfs
->cpu
);
863 * This function is called whenever an irq_exit event occurs in the second request.
866 static void CalculateXi(LttEvent
*event_irq_exit
, InterruptEventData
*event_data
, guint cpu_id
)
873 GArray
*SecondRequestIrqExit
= event_data
->SecondRequestIrqExit
;
874 GArray
*SecondRequestIrqEntry
= event_data
->SecondRequestIrqEntry
;
875 for(i
= 0; i
< SecondRequestIrqEntry
->len
; i
++)
877 element
= &g_array_index(SecondRequestIrqEntry
,irq_entry
,i
);
878 if(element
->cpu_id
== cpu_id
)
881 /* time calculation */
882 exit_time
= ltt_event_time(event_irq_exit
);
883 Xi
= ltt_time_sub(exit_time
, element
->event_time
);
884 irq_id
= element
->id
;
886 SumItems(irq_id
, Xi
,event_data
);
887 g_array_remove_index(SecondRequestIrqEntry
, i
);
895 * This function computes the Sum ((xi -Xa)^2) and store the result in SumArray
898 static void SumItems(gint irq_id
, LttTime Xi
, InterruptEventData
*event_data
)
903 gint duration_inner_part
;
904 guint64 period_inner_part
;
905 guint64 frequency_inner_part
;
911 gboolean notFound
= FALSE
;
912 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
913 GArray
*SumArray
= event_data
->SumArray
;
914 Xi_in_ns
= Xi
.tv_sec
;
915 Xi_in_ns
*= NANOSECONDS_PER_SECOND
;
916 Xi_in_ns
+= Xi
.tv_nsec
;
918 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
920 average
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
921 if(irq_id
== average
->id
)
923 duration_inner_part
= Xi_in_ns
- average
->average_duration
;
924 FrequencyHZ
= FrequencyInHZ(average
->TotalNumberOfInterrupts
, event_data
->time_window
);
926 // compute (xi -Xa)^2 of the duration Standard deviation
927 sum
.TotalNumberOfInterrupts
= average
->TotalNumberOfInterrupts
;
928 sum
.sumOfDurations
= pow (duration_inner_part
, 2);
930 // compute (xi -Xa)^2 of the period Standard deviation
931 period_inner_part
= CalculatePeriodInnerPart(Xi_in_ns
, FrequencyHZ
);
933 // compute (xi -Xa)^2 of the frequency Standard deviation
934 frequency_inner_part
= CalculateFrequencyInnerPart(Xi_in_ns
, FrequencyHZ
);
936 sum
.sumOfPeriods
= period_inner_part
;
938 sum
.sumOfFrequencies
= frequency_inner_part
;
940 if(event_data
->SumArray
->len
== NO_ITEMS
)
942 g_array_append_val (SumArray
, sum
);
946 for(i
= 0; i
< SumArray
->len
; i
++)
948 sumItem
= &g_array_index(SumArray
, SumId
, i
);
949 if(sumItem
->irqId
== irq_id
)
952 sumItem
->sumOfDurations
+= sum
.sumOfDurations
;
953 sumItem
->sumOfPeriods
+= sum
.sumOfPeriods
;
954 sumItem
->sumOfFrequencies
+= sum
.sumOfFrequencies
;
959 g_array_append_val (SumArray
, sum
);
969 * This function computes the inner part of the period standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
970 * The inner part is: (xi -Xa)^2
972 static guint64
CalculatePeriodInnerPart(guint Xi
, guint FrequencyHZ
)
975 double periodInSec
; /*period in sec*/
979 periodInSec
= (double)1/FrequencyHZ
;
980 periodInSec
*= NANOSECONDS_PER_SECOND
;
981 periodInNSec
= (int)periodInSec
;
983 difference
= Xi
- periodInNSec
;
984 result
= pow (difference
, 2);
989 * This function computes the inner part of the frequency standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
990 * The inner part is: (xi -Xa)^2
992 static guint64
CalculateFrequencyInnerPart(guint Xi_in_ns
, guint FrequencyHZ
)
997 difference
= Xi_in_ns
- FrequencyHZ
;
998 result
= pow (difference
, 2);
1002 * This function displays the result on the viewer
1005 static gboolean
DisplayViewer(void *hook_data
, void *call_data
)
1011 LttTime average_duration
;
1014 guint maxIRQduration
;
1015 guint minIRQduration
;
1017 int periodInNsec
= 0;
1018 char maxIrqHandler
[80];
1019 char minIrqHandler
[80];
1020 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
1021 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
1022 int FrequencyHZ
= 0;
1024 gtk_list_store_clear(event_data
->ListStore
);
1025 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
1027 element
= g_array_index(FirstRequestIrqExit
,Irq
,i
);
1028 real_data
= element
.total_duration
.tv_sec
;
1029 real_data
*= NANOSECONDS_PER_SECOND
;
1030 real_data
+= element
.total_duration
.tv_nsec
;
1033 maxIRQduration
= element
.max_irq_handler
.duration
.tv_sec
;
1034 maxIRQduration
*= NANOSECONDS_PER_SECOND
;
1035 maxIRQduration
+= element
.max_irq_handler
.duration
.tv_nsec
;
1037 sprintf(maxIrqHandler
, "%d [%lu.%lu - %lu.%lu]",maxIRQduration
, element
.max_irq_handler
.start_time
.tv_sec
, \
1038 element
.max_irq_handler
.start_time
.tv_nsec
, element
.max_irq_handler
.end_time
.tv_sec
, \
1039 element
.max_irq_handler
.end_time
.tv_nsec
) ;
1041 minIRQduration
= element
.min_irq_handler
.duration
.tv_sec
;
1042 minIRQduration
*= NANOSECONDS_PER_SECOND
;
1043 minIRQduration
+= element
.min_irq_handler
.duration
.tv_nsec
;
1044 sprintf(minIrqHandler
, "%d [%lu.%lu - %lu.%lu]",minIRQduration
, element
.min_irq_handler
.start_time
.tv_sec
, \
1045 element
.min_irq_handler
.start_time
.tv_nsec
, element
.min_irq_handler
.end_time
.tv_sec
, \
1046 element
.min_irq_handler
.end_time
.tv_nsec
) ;
1049 FrequencyHZ
= FrequencyInHZ(element
.TotalNumberOfInterrupts
,event_data
->time_window
);
1051 if(FrequencyHZ
!= 0)
1053 periodInSec
= (double)1/FrequencyHZ
;
1054 periodInSec
*= NANOSECONDS_PER_SECOND
;
1055 periodInNsec
= (int)periodInSec
;
1059 gtk_list_store_append (event_data
->ListStore
, &iter
);
1060 gtk_list_store_set (event_data
->ListStore
, &iter
,
1061 CPUID_COLUMN
, element
.cpu_id
,
1062 IRQ_ID_COLUMN
, element
.id
,
1063 FREQUENCY_COLUMN
, FrequencyHZ
,
1064 DURATION_COLUMN
, real_data
,
1065 DURATION_STANDARD_DEV_COLUMN
, CalculateDurationStandardDeviation(element
.id
, event_data
),
1066 MAX_IRQ_HANDLER_COLUMN
, maxIrqHandler
,
1067 MIN_IRQ_HANDLER_COLUMN
, minIrqHandler
,
1068 AVERAGE_PERIOD
, periodInNsec
,
1069 PERIOD_STANDARD_DEV_COLUMN
, CalculatePeriodStandardDeviation(element
.id
, event_data
),
1070 FREQUENCY_STANDARD_DEV_COLUMN
, CalculateFrequencyStandardDeviation(element
.id
, event_data
),
1075 if(event_data
->FirstRequestIrqExit
->len
)
1077 g_array_remove_range (event_data
->FirstRequestIrqExit
,0,event_data
->FirstRequestIrqExit
->len
);
1080 if(event_data
->FirstRequestIrqEntry
->len
)
1082 g_array_remove_range (event_data
->FirstRequestIrqEntry
,0,event_data
->FirstRequestIrqEntry
->len
);
1085 if(event_data
->SecondRequestIrqEntry
->len
)
1087 g_array_remove_range (event_data
->SecondRequestIrqEntry
,0,event_data
->SecondRequestIrqEntry
->len
);
1090 if(event_data
->SecondRequestIrqExit
->len
)
1092 g_array_remove_range (event_data
->SecondRequestIrqExit
,0, event_data
->SecondRequestIrqExit
->len
);
1095 if(event_data
->SumArray
->len
)
1097 g_array_remove_range (event_data
->SumArray
,0, event_data
->SumArray
->len
);
1105 * This function converts the number of interrupts over a time window to
1108 static int FrequencyInHZ(gint NumerofInterruptions
, TimeWindow time_window
)
1110 guint64 frequencyHz
= 0;
1111 double timeSec
; // time in second
1113 result
= ltt_time_to_double(time_window
.time_width
);
1114 timeSec
= (result
/NANOSECONDS_PER_SECOND
); //time in second
1115 frequencyHz
= NumerofInterruptions
/ timeSec
;
1120 * This function calculates the duration standard deviation
1121 * Duration standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1123 * sumId.sumOfDurations -> Sum ((xi -Xa)^2)
1124 * inner_component -> 1/N Sum ((xi -Xa)^2)
1125 * deviation-> sqrt(1/N Sum ((xi -Xa)^2))
1127 static int CalculateDurationStandardDeviation(gint id
, InterruptEventData
*event_data
)
1131 double inner_component
;
1133 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
1135 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
1136 if(id
== sumId
.irqId
)
1138 if(sumId
.TotalNumberOfInterrupts
!= 0)
1139 inner_component
= sumId
.sumOfDurations
/ sumId
.TotalNumberOfInterrupts
;
1141 inner_component
= 0.0;
1142 deviation
= sqrt(inner_component
);
1151 * This function calculates the period standard deviation
1152 * Period standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1154 * sumId.sumOfPeriods -> Sum ((xi -Xa)^2)
1155 * inner_component -> 1/N Sum ((xi -Xa)^2)
1156 * period_standard_deviation-> sqrt(1/N Sum ((xi -Xa)^2))
1160 static int CalculatePeriodStandardDeviation(gint id
, InterruptEventData
*event_data
)
1164 guint64 inner_component
;
1165 guint64 period_standard_deviation
= 0;
1167 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
1169 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
1170 if(id
== sumId
.irqId
)
1172 if(sumId
.TotalNumberOfInterrupts
!= 0)
1173 inner_component
= sumId
.sumOfPeriods
/ sumId
.TotalNumberOfInterrupts
;
1175 inner_component
= 0;
1177 period_standard_deviation
= sqrt(inner_component
);
1181 return period_standard_deviation
;
1185 * This function calculates the frequency standard deviation
1186 * Frequency standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1188 * sumId.sumOfFrequencies -> Sum ((xi -Xa)^2)
1189 * inner_component -> 1/N Sum ((xi -Xa)^2)
1190 * frequency_standard_deviation-> sqrt(1/N Sum ((xi -Xa)^2))
1193 static int CalculateFrequencyStandardDeviation(gint id
, InterruptEventData
*event_data
)
1197 guint64 inner_component
;
1198 guint64 frequency_standard_deviation
= 0;
1199 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
1201 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
1202 if(id
== sumId
.irqId
)
1204 if(sumId
.TotalNumberOfInterrupts
!= 0)
1205 inner_component
= sumId
.sumOfFrequencies
/ sumId
.TotalNumberOfInterrupts
;
1207 inner_component
= 0;
1209 frequency_standard_deviation
= sqrt(inner_component
);
1212 return frequency_standard_deviation
;
1216 * This function is called by the main window
1217 * when the time interval needs to be updated.
1219 gboolean
interrupt_update_time_window(void * hook_data
, void * call_data
)
1221 InterruptEventData
*event_data
= (InterruptEventData
*) hook_data
;
1222 const TimeWindowNotifyData
*time_window_nofify_data
= ((const TimeWindowNotifyData
*)call_data
);
1223 event_data
->time_window
= *time_window_nofify_data
->new_time_window
;
1224 g_info("interrupts: interrupt_update_time_window()\n");
1225 Tab
*tab
= event_data
->tab
;
1226 lttvwindow_events_request_remove_all(tab
, event_data
);
1227 FirstRequest(event_data
);
1232 gboolean
trace_header(void *hook_data
, void *call_data
)
1235 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
1236 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1242 void interrupt_destroy_walk(gpointer data
, gpointer user_data
)
1244 g_info("interrupt_destroy_walk");
1245 InterruptEventData
*event_data
= (InterruptEventData
*) data
;
1246 interrupt_destructor((InterruptEventData
*)data
);
1250 void interrupt_destructor(InterruptEventData
*event_viewer_data
)
1252 /* May already been done by GTK window closing */
1253 g_info("enter interrupt_destructor \n");
1254 if(GTK_IS_WIDGET(event_viewer_data
->Hbox
))
1256 gtk_widget_destroy(event_viewer_data
->Hbox
);
1261 This function is called when the viewer is destroyed to free hooks and memory
1263 static void InterruptFree(InterruptEventData
*event_viewer_data
)
1265 Tab
*tab
= event_viewer_data
->tab
;
1269 g_array_free(event_viewer_data
->FirstRequestIrqExit
, TRUE
);
1270 g_array_free(event_viewer_data
->FirstRequestIrqEntry
, TRUE
);
1271 g_array_free(event_viewer_data
->SecondRequestIrqEntry
, TRUE
);
1272 g_array_free(event_viewer_data
->SecondRequestIrqExit
, TRUE
);
1273 g_array_free(event_viewer_data
->SumArray
, TRUE
);
1275 lttvwindow_unregister_time_window_notify(tab
, interrupt_update_time_window
, event_viewer_data
);
1277 lttvwindow_events_request_remove_all(event_viewer_data
->tab
,
1280 interrupt_data_list
= g_slist_remove(interrupt_data_list
, event_viewer_data
);
1287 * plugin's destroy function
1289 * This function releases the memory reserved by the module and unregisters
1290 * everything that has been registered in the gtkTraceSet API.
1292 static void destroy()
1295 g_info("Destroy interrupts");
1296 g_slist_foreach(interrupt_data_list
, interrupt_destroy_walk
, NULL
);
1297 g_slist_free(interrupt_data_list
);
1298 lttvwindow_unregister_constructor(interrupts
);
1302 LTTV_MODULE("interrupts", "interrupts info view", \
1303 "Graphical module to display interrupts performance", \
1304 init
, destroy
, "lttvwindow")