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>
77 #include <ltt/trace.h>
78 #include <ltt/facility.h>
79 #include <lttv/module.h>
80 #include <lttv/hook.h>
81 #include <lttv/tracecontext.h>
82 #include <lttv/state.h>
83 #include <lttv/filter.h>
84 #include <lttvwindow/lttvwindow.h>
87 #include "hInterruptsInsert.xpm"
89 #define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
90 #define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format)
103 guint TotalNumberOfInterrupts
;
104 LttTime total_duration
;
105 guint average_duration
;
106 IrqDuration max_irq_handler
;
107 IrqDuration min_irq_handler
;
120 guint TotalNumberOfInterrupts
;//frequency;//
121 guint64 sumOfDurations
; // to store the Sum ((xi -Xa)^2) of the duration Standard deviation
122 guint64 sumOfPeriods
; // to store the Sum ((xi -Xa)^2) of the period Standard deviation
123 guint64 sumOfFrequencies
;// to store the Sum ((xi -Xa)^2) of the frequency Standard deviation
132 /** Array containing instanced objects. Used when module is unloaded */
133 static GSList
*interrupt_data_list
= NULL
;
136 #define TRACE_NUMBER 0
138 typedef struct _InterruptEventData
{
140 /*Graphical Widgets */
141 GtkWidget
* ScrollWindow
;
142 GtkListStore
*ListStore
;
145 GtkTreeSelection
*SelectionTree
;
147 Tab
* tab
; /* tab that contains this plug-in*/
148 LttvHooks
* event_hooks
;
149 LttvHooks
* hooks_trace_after
;
150 LttvHooks
* hooks_trace_before
;
151 TimeWindow time_window
;
152 LttvHooksById
* event_by_id_hooks
;
153 GArray
*FirstRequestIrqExit
;
154 GArray
*FirstRequestIrqEntry
;
155 GArray
*SecondRequestIrqEntry
;
156 GArray
*SecondRequestIrqExit
;
159 } InterruptEventData
;
162 /* Function prototypes */
164 static gboolean
interrupt_update_time_window(void * hook_data
, void * call_data
);
165 static GtkWidget
*interrupts(Tab
*tab
);
166 static InterruptEventData
*system_info(Tab
*tab
);
167 void interrupt_destructor(InterruptEventData
*event_viewer_data
);
168 static void FirstRequest(InterruptEventData
*event_data
);
169 static guint64
get_interrupt_id(LttEvent
*e
);
170 static gboolean
trace_header(void *hook_data
, void *call_data
);
171 static gboolean
DisplayViewer (void *hook_data
, void *call_data
);
172 static void CalculateData(LttTime time_exit
, guint cpu_id
, InterruptEventData
*event_data
);
173 static void CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(irq_entry
*e
, LttTime time_exit
, GArray
*FirstRequestIrqExit
);
174 static gboolean
FirstRequestIrqEntryCallback(void *hook_data
, void *call_data
);
175 static gboolean
FirstRequestIrqExitCallback(void *hook_data
, void *call_data
);
176 static gboolean
SecondRequest(void *hook_data
, void *call_data
);
177 static void CalculateAverageDurationForEachIrqId(InterruptEventData
*event_data
);
178 static gboolean
SecondRequestIrqEntryCallback(void *hook_data
, void *call_data
);
179 static gboolean
SecondRequestIrqExitCallback(void *hook_data
, void *call_data
);
180 static void CalculateXi(LttEvent
*event
, InterruptEventData
*event_data
);
181 static void SumItems(gint irq_id
, LttTime Xi
, InterruptEventData
*event_data
);
182 static int CalculateDurationStandardDeviation(gint id
, InterruptEventData
*event_data
);
183 static int CalculatePeriodStandardDeviation(gint id
, InterruptEventData
*event_data
);
184 static int FrequencyInHZ(gint NumberOfInterruptions
, TimeWindow time_window
);
185 static guint64
CalculatePeriodInnerPart(guint Xi
, guint FrequencyHZ
);
186 static guint64
CalculateFrequencyInnerPart(guint Xi_in_ns
, guint FrequencyHZ
);
187 static void InterruptFree(InterruptEventData
*event_viewer_data
);
188 static int CalculateFrequencyStandardDeviation(gint id
, InterruptEventData
*event_data
);
190 /* Enumeration of the columns */
196 DURATION_STANDARD_DEV_COLUMN
,
197 MAX_IRQ_HANDLER_COLUMN
,
198 MIN_IRQ_HANDLER_COLUMN
,
200 PERIOD_STANDARD_DEV_COLUMN
,
201 FREQUENCY_STANDARD_DEV_COLUMN
,
211 * This is the entry point of the viewer.
215 g_info("interrupts: init()");
216 lttvwindow_register_constructor("interrupts",
218 "Insert Interrupts View",
219 hInterruptsInsert_xpm
,
220 "Insert Interrupts View",
230 static GtkWidget
*interrupts(Tab
* tab
)
233 InterruptEventData
* event_data
= system_info(tab
) ;
235 return event_data
->Hbox
;
241 * This function initializes the Event Viewer functionnality through the
244 InterruptEventData
*system_info(Tab
*tab
)
248 GtkTreeViewColumn
*column
;
249 GtkCellRenderer
*renderer
;
250 InterruptEventData
* event_viewer_data
= g_new(InterruptEventData
,1) ;
252 event_viewer_data
->tab
= tab
;
254 /*Get the current time frame from the main window */
255 event_viewer_data
->time_window
= lttvwindow_get_time_window(tab
);
257 event_viewer_data
->FirstRequestIrqExit
= g_array_new(FALSE
, FALSE
, sizeof(Irq
));
258 event_viewer_data
->FirstRequestIrqEntry
= g_array_new(FALSE
, FALSE
, sizeof(irq_entry
));
260 event_viewer_data
->SecondRequestIrqEntry
= g_array_new(FALSE
, FALSE
, sizeof(irq_entry
));
261 event_viewer_data
->SecondRequestIrqExit
= g_array_new(FALSE
, FALSE
, sizeof(Irq
));
263 event_viewer_data
->SumArray
= g_array_new(FALSE
, FALSE
, sizeof(SumId
));
266 /*Create tha main window for the viewer */
267 event_viewer_data
->ScrollWindow
= gtk_scrolled_window_new (NULL
, NULL
);
268 gtk_widget_show (event_viewer_data
->ScrollWindow
);
269 gtk_scrolled_window_set_policy(
270 GTK_SCROLLED_WINDOW(event_viewer_data
->ScrollWindow
),
271 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
/*GTK_POLICY_NEVER*/);
273 /* Create a model for storing the data list */
274 event_viewer_data
->ListStore
= gtk_list_store_new (
275 N_COLUMNS
, /* Total number of columns */
276 G_TYPE_INT
, /* CPUID */
277 G_TYPE_INT
, /* IRQ_ID */
278 G_TYPE_INT
, /* Frequency */
279 G_TYPE_UINT64
, /* Duration */
280 G_TYPE_INT
, /* standard deviation */
281 G_TYPE_STRING
, /* Max IRQ handler */
282 G_TYPE_STRING
, /* Min IRQ handler */
283 G_TYPE_INT
, /* Average period */
284 G_TYPE_INT
, /* period standard deviation */
285 G_TYPE_INT
/* frequency standard deviation */
289 event_viewer_data
->TreeView
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (event_viewer_data
->ListStore
));
291 g_object_unref (G_OBJECT (event_viewer_data
->ListStore
));
293 renderer
= gtk_cell_renderer_text_new ();
294 column
= gtk_tree_view_column_new_with_attributes ("CPU ID",
296 "text", CPUID_COLUMN
,
298 gtk_tree_view_column_set_alignment (column
, 0.0);
299 gtk_tree_view_column_set_fixed_width (column
, 45);
300 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
303 renderer
= gtk_cell_renderer_text_new ();
304 column
= gtk_tree_view_column_new_with_attributes ("IRQ ID",
306 "text", IRQ_ID_COLUMN
,
308 gtk_tree_view_column_set_alignment (column
, 0.0);
309 gtk_tree_view_column_set_fixed_width (column
, 220);
310 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
312 renderer
= gtk_cell_renderer_text_new ();
313 column
= gtk_tree_view_column_new_with_attributes ("Frequency (Hz)",
315 "text", FREQUENCY_COLUMN
,
317 gtk_tree_view_column_set_alignment (column
, 1.0);
318 gtk_tree_view_column_set_fixed_width (column
, 220);
319 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
321 renderer
= gtk_cell_renderer_text_new ();
322 column
= gtk_tree_view_column_new_with_attributes ("Total Duration (nsec)",
324 "text", DURATION_COLUMN
,
326 gtk_tree_view_column_set_alignment (column
, 0.0);
327 gtk_tree_view_column_set_fixed_width (column
, 145);
328 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
331 renderer
= gtk_cell_renderer_text_new ();
332 column
= gtk_tree_view_column_new_with_attributes ("Duration standard deviation (nsec)",
334 "text", DURATION_STANDARD_DEV_COLUMN
,
336 gtk_tree_view_column_set_alignment (column
, 0.0);
337 gtk_tree_view_column_set_fixed_width (column
, 200);
338 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
340 renderer
= gtk_cell_renderer_text_new ();
341 column
= gtk_tree_view_column_new_with_attributes ("Max IRQ handler duration (nsec) [time interval]",
343 "text", MAX_IRQ_HANDLER_COLUMN
,
345 gtk_tree_view_column_set_alignment (column
, 0.0);
346 gtk_tree_view_column_set_fixed_width (column
, 250);
347 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
349 renderer
= gtk_cell_renderer_text_new ();
350 column
= gtk_tree_view_column_new_with_attributes ("Min IRQ handler duration (nsec) [time interval]",
352 "text", MIN_IRQ_HANDLER_COLUMN
,
354 gtk_tree_view_column_set_alignment (column
, 0.0);
355 gtk_tree_view_column_set_fixed_width (column
, 250);
356 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
358 renderer
= gtk_cell_renderer_text_new ();
359 column
= gtk_tree_view_column_new_with_attributes (" Average period (nsec)",
361 "text", AVERAGE_PERIOD
,
363 gtk_tree_view_column_set_alignment (column
, 0.0);
364 gtk_tree_view_column_set_fixed_width (column
, 200);
365 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
367 renderer
= gtk_cell_renderer_text_new ();
368 column
= gtk_tree_view_column_new_with_attributes ("Period standard deviation (nsec)",
370 "text", PERIOD_STANDARD_DEV_COLUMN
,
372 gtk_tree_view_column_set_alignment (column
, 0.0);
373 gtk_tree_view_column_set_fixed_width (column
, 200);
374 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
376 renderer
= gtk_cell_renderer_text_new ();
377 column
= gtk_tree_view_column_new_with_attributes ("Frequency standard deviation (Hz)",
379 "text", FREQUENCY_STANDARD_DEV_COLUMN
,
381 gtk_tree_view_column_set_alignment (column
, 0.0);
382 gtk_tree_view_column_set_fixed_width (column
, 200);
383 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
386 event_viewer_data
->SelectionTree
= gtk_tree_view_get_selection (GTK_TREE_VIEW (event_viewer_data
->TreeView
));
387 gtk_tree_selection_set_mode (event_viewer_data
->SelectionTree
, GTK_SELECTION_SINGLE
);
389 gtk_container_add (GTK_CONTAINER (event_viewer_data
->ScrollWindow
), event_viewer_data
->TreeView
);
391 event_viewer_data
->Hbox
= gtk_hbox_new(0, 0);
392 gtk_box_pack_start(GTK_BOX(event_viewer_data
->Hbox
), event_viewer_data
->ScrollWindow
, TRUE
, TRUE
, 0);
394 gtk_widget_show(event_viewer_data
->Hbox
);
395 gtk_widget_show(event_viewer_data
->TreeView
);
397 interrupt_data_list
= g_slist_append(interrupt_data_list
, event_viewer_data
);
398 /* Registration for time notification */
399 lttvwindow_register_time_window_notify(tab
,
400 interrupt_update_time_window
,
403 g_object_set_data_full(G_OBJECT(event_viewer_data
->Hbox
),
406 (GDestroyNotify
) InterruptFree
);
408 FirstRequest(event_viewer_data
);
409 return event_viewer_data
;
415 * For each trace in the traceset, this function:
416 * - registers a callback function to each hook
417 * - calls lttv_trace_find_hook() registers a hook function to event_by_id_hooks
418 * - calls lttvwindow_events_request() to request data in a specific
419 * time interval to the main window
422 static void FirstRequest(InterruptEventData
*event_data
)
424 guint i
, k
, l
, nb_trace
;
434 EventsRequest
*events_request
;
436 LttvTraceHookByFacility
*thf
;
438 LttvTracesetContext
*tsc
= lttvwindow_get_traceset_context(event_data
->tab
);
441 /* Get the traceset */
442 LttvTraceset
*traceset
= tsc
->ts
;
444 nb_trace
= lttv_traceset_number(traceset
);
446 /* There are many traces in a traceset. Iteration for each trace. */
447 for(i
= 0; i
<MIN(TRACE_NUMBER
+1, nb_trace
);i
++)
449 events_request
= g_new(EventsRequest
, 1);
451 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
453 hooks
= g_array_set_size(hooks
, 2);
455 event_data
->hooks_trace_before
= lttv_hooks_new();
457 /* Registers a hook function */
458 lttv_hooks_add(event_data
->hooks_trace_before
, trace_header
, event_data
, LTTV_PRIO_DEFAULT
);
460 event_data
->hooks_trace_after
= lttv_hooks_new();
462 /* Registers a hook function */
463 lttv_hooks_add(event_data
->hooks_trace_after
, SecondRequest
, event_data
, LTTV_PRIO_DEFAULT
);
464 /* Get a trace state */
465 ts
= (LttvTraceState
*)tsc
->traces
[i
];
466 /* Create event_by_Id hooks */
467 event_data
->event_by_id_hooks
= lttv_hooks_by_id_new();
469 /*Register event_by_id_hooks with a callback function*/
470 ret
= lttv_trace_find_hook(ts
->parent
.t
,
471 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
472 LTT_FIELD_IRQ_ID
, 0, 0,
473 FirstRequestIrqEntryCallback
,
475 &g_array_index(hooks
, LttvTraceHook
, 0));
477 ret
= lttv_trace_find_hook(ts
->parent
.t
,
478 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
479 LTT_FIELD_IRQ_ID
, 0, 0,
480 FirstRequestIrqExitCallback
,
482 &g_array_index(hooks
, LttvTraceHook
, 1));
485 /*iterate through the facility list*/
486 for(k
= 0 ; k
< hooks
->len
; k
++)
488 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
489 for(l
=0; l
<hook
->fac_list
->len
; l
++)
491 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
492 lttv_hooks_add(lttv_hooks_by_id_find(event_data
->event_by_id_hooks
, thf
->id
),
499 /* Initalize the EventsRequest structure */
500 events_request
->owner
= event_data
;
501 events_request
->viewer_data
= event_data
;
502 events_request
->servicing
= FALSE
;
503 events_request
->start_time
= event_data
->time_window
.start_time
;
504 events_request
->start_position
= NULL
;
505 events_request
->stop_flag
= FALSE
;
506 events_request
->end_time
= event_data
->time_window
.end_time
;
507 events_request
->num_events
= G_MAXUINT
;
508 events_request
->end_position
= NULL
;
509 events_request
->trace
= i
;
511 events_request
->hooks
= hooks
;
513 events_request
->before_chunk_traceset
= NULL
;
514 events_request
->before_chunk_trace
= event_data
->hooks_trace_before
;
515 events_request
->before_chunk_tracefile
= NULL
;
516 events_request
->event
= NULL
;
517 events_request
->event_by_id
= event_data
->event_by_id_hooks
;
518 events_request
->after_chunk_tracefile
= NULL
;
519 events_request
->after_chunk_trace
= NULL
;
520 events_request
->after_chunk_traceset
= NULL
;
521 events_request
->before_request
= NULL
;
522 events_request
->after_request
= event_data
->hooks_trace_after
;
524 lttvwindow_events_request(event_data
->tab
, events_request
);
530 * This function is called whenever an irq_entry event occurs.
533 static gboolean
FirstRequestIrqEntryCallback(void *hook_data
, void *call_data
)
539 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
540 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
541 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
542 GArray
* FirstRequestIrqEntry
= event_data
->FirstRequestIrqEntry
;
543 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
544 event_time
= ltt_event_time(e
);
545 cpu_id
= ltt_event_cpu_id(e
);
548 entry
.id
=get_interrupt_id(e
);
549 entry
.cpu_id
= cpu_id
;
550 entry
.event_time
= event_time
;
551 g_array_append_val (FirstRequestIrqEntry
, entry
);
557 * This function gets the id of the interrupt. The id is stored in a dynamic structure.
558 * Refer to the print.c file for how to extract data from a dynamic structure.
560 static guint64
get_interrupt_id(LttEvent
*e
)
563 LttEventType
*event_type
;
567 event_type
= ltt_event_eventtype(e
);
568 num_fields
= ltt_eventtype_num_fields(event_type
);
569 for(i
= 0 ; i
< num_fields
-1 ; i
++)
571 field
= ltt_eventtype_field(event_type
, i
);
572 irq_id
= ltt_event_get_long_unsigned(e
,field
);
578 * This function is called whenever an irq_exit event occurs.
581 gboolean
FirstRequestIrqExitCallback(void *hook_data
, void *call_data
)
585 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
586 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
587 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
588 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
589 LttEventType
*type
= ltt_event_eventtype(e
);
590 event_time
= ltt_event_time(e
);
591 cpu_id
= ltt_event_cpu_id(e
);
593 CalculateData( event_time
, cpu_id
, event_data
);
599 * This function calculates the duration of an interrupt.
602 static void CalculateData(LttTime time_exit
, guint cpu_id
,InterruptEventData
*event_data
)
608 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
609 GArray
*FirstRequestIrqEntry
= event_data
->FirstRequestIrqEntry
;
610 for(i
= 0; i
< FirstRequestIrqEntry
->len
; i
++)
612 element
= &g_array_index(FirstRequestIrqEntry
,irq_entry
,i
);
613 if(element
->cpu_id
== cpu_id
)
615 CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(element
,time_exit
, FirstRequestIrqExit
);
616 g_array_remove_index(FirstRequestIrqEntry
, i
);
624 * This function calculates the total duration of an interrupt and the longest & shortest Irq handlers.
627 static void CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(irq_entry
*e
, LttTime time_exit
, GArray
*FirstRequestIrqExit
)
633 gboolean notFound
= FALSE
;
634 memset ((void*)&irq
, 0,sizeof(Irq
));
637 if(FirstRequestIrqExit
->len
== NO_ITEMS
)
639 irq
.cpu_id
= e
->cpu_id
;
641 irq
.TotalNumberOfInterrupts
++;
642 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
644 irq
.max_irq_handler
.start_time
= e
->event_time
;
645 irq
.max_irq_handler
.end_time
= time_exit
;
646 irq
.max_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
648 irq
.min_irq_handler
.start_time
= e
->event_time
;
649 irq
.min_irq_handler
.end_time
= time_exit
;
650 irq
.min_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
652 g_array_append_val (FirstRequestIrqExit
, irq
);
656 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
658 element
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
659 if(element
->id
== e
->id
)
662 duration
= ltt_time_sub(time_exit
, e
->event_time
);
663 element
->total_duration
= ltt_time_add(element
->total_duration
, duration
);
664 element
->TotalNumberOfInterrupts
++;
666 if(ltt_time_compare(duration
,element
->max_irq_handler
.duration
) > 0)
668 element
->max_irq_handler
.duration
= duration
;
669 element
->max_irq_handler
.start_time
= e
->event_time
;
670 element
->max_irq_handler
.end_time
= time_exit
;
673 if(ltt_time_compare(duration
,element
->min_irq_handler
.duration
) < 0)
675 element
->min_irq_handler
.duration
= duration
;
676 element
->min_irq_handler
.start_time
= e
->event_time
;
677 element
->min_irq_handler
.end_time
= time_exit
;
683 irq
.cpu_id
= e
->cpu_id
;
685 irq
.TotalNumberOfInterrupts
++;
686 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
688 irq
.max_irq_handler
.start_time
= e
->event_time
;
689 irq
.max_irq_handler
.end_time
= time_exit
;
690 irq
.max_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
692 irq
.min_irq_handler
.start_time
= e
->event_time
;
693 irq
.min_irq_handler
.end_time
= time_exit
;
694 irq
.min_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
696 g_array_append_val (FirstRequestIrqExit
, irq
);
702 * This function passes the second EventsRequest to LTTV
705 static gboolean
SecondRequest(void *hook_data
, void *call_data
)
708 guint i
, k
, l
, nb_trace
;
718 EventsRequest
*events_request
;
720 LttvTraceHookByFacility
*thf
;
722 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
724 LttvTracesetContext
*tsc
= lttvwindow_get_traceset_context(event_data
->tab
);
726 CalculateAverageDurationForEachIrqId(event_data
);
728 /* Get the traceset */
729 LttvTraceset
*traceset
= tsc
->ts
;
731 nb_trace
= lttv_traceset_number(traceset
);
733 /* There are many traces in a traceset. Iteration for each trace. */
734 for(i
= 0; i
<MIN(TRACE_NUMBER
+1, nb_trace
);i
++)
736 events_request
= g_new(EventsRequest
, 1);
738 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
740 hooks
= g_array_set_size(hooks
, 2);
742 event_data
->hooks_trace_after
= lttv_hooks_new();
744 /* Registers a hook function */
745 lttv_hooks_add(event_data
->hooks_trace_after
, DisplayViewer
, event_data
, LTTV_PRIO_DEFAULT
);
747 /* Get a trace state */
748 ts
= (LttvTraceState
*)tsc
->traces
[i
];
749 /* Create event_by_Id hooks */
750 event_data
->event_by_id_hooks
= lttv_hooks_by_id_new();
752 /*Register event_by_id_hooks with a callback function*/
753 ret
= lttv_trace_find_hook(ts
->parent
.t
,
754 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
755 LTT_FIELD_IRQ_ID
, 0, 0,
756 SecondRequestIrqEntryCallback
,
758 &g_array_index(hooks
, LttvTraceHook
, 0));
760 ret
= lttv_trace_find_hook(ts
->parent
.t
,
761 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
762 LTT_FIELD_IRQ_ID
, 0, 0,
763 SecondRequestIrqExitCallback
,
765 &g_array_index(hooks
, LttvTraceHook
, 1));
769 /* iterate through the facility list */
770 for(k
= 0 ; k
< hooks
->len
; k
++)
772 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
773 for(l
=0; l
<hook
->fac_list
->len
; l
++)
775 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
776 lttv_hooks_add(lttv_hooks_by_id_find(event_data
->event_by_id_hooks
, thf
->id
),
783 /* Initalize the EventsRequest structure */
784 events_request
->owner
= event_data
;
785 events_request
->viewer_data
= event_data
;
786 events_request
->servicing
= FALSE
;
787 events_request
->start_time
= event_data
->time_window
.start_time
;
788 events_request
->start_position
= NULL
;
789 events_request
->stop_flag
= FALSE
;
790 events_request
->end_time
= event_data
->time_window
.end_time
;
791 events_request
->num_events
= G_MAXUINT
;
792 events_request
->end_position
= NULL
;
793 events_request
->trace
= i
;
795 events_request
->hooks
= hooks
;
797 events_request
->before_chunk_traceset
= NULL
;
798 events_request
->before_chunk_trace
= NULL
;
799 events_request
->before_chunk_tracefile
= NULL
;
800 events_request
->event
= NULL
;
801 events_request
->event_by_id
= event_data
->event_by_id_hooks
;
802 events_request
->after_chunk_tracefile
= NULL
;
803 events_request
->after_chunk_trace
= NULL
;
804 events_request
->after_chunk_traceset
= NULL
;
805 events_request
->before_request
= NULL
;
806 events_request
->after_request
= event_data
->hooks_trace_after
;
808 lttvwindow_events_request(event_data
->tab
, events_request
);
814 * This function calculates the average duration for each Irq Id
817 static void CalculateAverageDurationForEachIrqId(InterruptEventData
*event_data
)
822 GArray
* FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
823 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
825 element
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
826 real_data
= element
->total_duration
.tv_sec
;
827 real_data
*= NANOSECONDS_PER_SECOND
;
828 real_data
+= element
->total_duration
.tv_nsec
;
829 if(element
->TotalNumberOfInterrupts
!= 0)
830 element
->average_duration
= real_data
/ element
->TotalNumberOfInterrupts
;
832 element
->average_duration
= 0;
838 * This function is called whenever an irq_entry event occurs. Use in the second request
841 static gboolean
SecondRequestIrqEntryCallback(void *hook_data
, void *call_data
)
847 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
848 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
849 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
850 GArray
* SecondRequestIrqEntry
= event_data
->SecondRequestIrqEntry
;
851 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
852 event_time
= ltt_event_time(e
);
853 cpu_id
= ltt_event_cpu_id(e
);
856 entry
.id
=get_interrupt_id(e
);
857 entry
.cpu_id
= cpu_id
;
858 entry
.event_time
= event_time
;
859 g_array_append_val (SecondRequestIrqEntry
, entry
);
865 * This function is called whenever an irq_exit event occurs in the second request.
868 static gboolean
SecondRequestIrqExitCallback(void *hook_data
, void *call_data
)
871 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
872 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
873 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
874 LttEvent
*event
= ltt_tracefile_get_event(tfc
->tf
);
876 CalculateXi(event
, event_data
);
882 * This function is called whenever an irq_exit event occurs in the second request.
885 static void CalculateXi(LttEvent
*event_irq_exit
, InterruptEventData
*event_data
)
893 GArray
*SecondRequestIrqExit
= event_data
->SecondRequestIrqExit
;
894 GArray
*SecondRequestIrqEntry
= event_data
->SecondRequestIrqEntry
;
895 cpu_id
= ltt_event_cpu_id(event_irq_exit
);
896 for(i
= 0; i
< SecondRequestIrqEntry
->len
; i
++)
898 element
= &g_array_index(SecondRequestIrqEntry
,irq_entry
,i
);
899 if(element
->cpu_id
== cpu_id
)
902 /* time calculation */
903 exit_time
= ltt_event_time(event_irq_exit
);
904 Xi
= ltt_time_sub(exit_time
, element
->event_time
);
905 irq_id
= element
->id
;
907 SumItems(irq_id
, Xi
,event_data
);
908 g_array_remove_index(SecondRequestIrqEntry
, i
);
916 * This function computes the Sum ((xi -Xa)^2) and store the result in SumArray
919 static void SumItems(gint irq_id
, LttTime Xi
, InterruptEventData
*event_data
)
924 gint duration_inner_part
;
925 guint64 period_inner_part
;
926 guint64 frequency_inner_part
;
932 gboolean notFound
= FALSE
;
933 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
934 GArray
*SumArray
= event_data
->SumArray
;
935 Xi_in_ns
= Xi
.tv_sec
;
936 Xi_in_ns
*= NANOSECONDS_PER_SECOND
;
937 Xi_in_ns
+= Xi
.tv_nsec
;
939 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
941 average
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
942 if(irq_id
== average
->id
)
944 duration_inner_part
= Xi_in_ns
- average
->average_duration
;
945 FrequencyHZ
= FrequencyInHZ(average
->TotalNumberOfInterrupts
, event_data
->time_window
);
947 // compute (xi -Xa)^2 of the duration Standard deviation
948 sum
.TotalNumberOfInterrupts
= average
->TotalNumberOfInterrupts
;
949 sum
.sumOfDurations
= pow (duration_inner_part
, 2);
951 // compute (xi -Xa)^2 of the period Standard deviation
952 period_inner_part
= CalculatePeriodInnerPart(Xi_in_ns
, FrequencyHZ
);
954 // compute (xi -Xa)^2 of the frequency Standard deviation
955 frequency_inner_part
= CalculateFrequencyInnerPart(Xi_in_ns
, FrequencyHZ
);
957 sum
.sumOfPeriods
= period_inner_part
;
959 sum
.sumOfFrequencies
= frequency_inner_part
;
961 if(event_data
->SumArray
->len
== NO_ITEMS
)
963 g_array_append_val (SumArray
, sum
);
967 for(i
= 0; i
< SumArray
->len
; i
++)
969 sumItem
= &g_array_index(SumArray
, SumId
, i
);
970 if(sumItem
->irqId
== irq_id
)
973 sumItem
->sumOfDurations
+= sum
.sumOfDurations
;
974 sumItem
->sumOfPeriods
+= sum
.sumOfPeriods
;
975 sumItem
->sumOfFrequencies
+= sum
.sumOfFrequencies
;
980 g_array_append_val (SumArray
, sum
);
990 * This function computes the inner part of the period standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
991 * The inner part is: (xi -Xa)^2
993 static guint64
CalculatePeriodInnerPart(guint Xi
, guint FrequencyHZ
)
996 double periodInSec
; /*period in sec*/
1000 periodInSec
= (double)1/FrequencyHZ
;
1001 periodInSec
*= NANOSECONDS_PER_SECOND
;
1002 periodInNSec
= (int)periodInSec
;
1004 difference
= Xi
- periodInNSec
;
1005 result
= pow (difference
, 2);
1010 * This function computes the inner part of the frequency standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1011 * The inner part is: (xi -Xa)^2
1013 static guint64
CalculateFrequencyInnerPart(guint Xi_in_ns
, guint FrequencyHZ
)
1018 difference
= Xi_in_ns
- FrequencyHZ
;
1019 result
= pow (difference
, 2);
1023 * This function displays the result on the viewer
1026 static gboolean
DisplayViewer(void *hook_data
, void *call_data
)
1032 LttTime average_duration
;
1035 guint maxIRQduration
;
1036 guint minIRQduration
;
1039 char maxIrqHandler
[80];
1040 char minIrqHandler
[80];
1041 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
1042 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
1043 int FrequencyHZ
= 0;
1045 gtk_list_store_clear(event_data
->ListStore
);
1046 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
1048 element
= g_array_index(FirstRequestIrqExit
,Irq
,i
);
1049 real_data
= element
.total_duration
.tv_sec
;
1050 real_data
*= NANOSECONDS_PER_SECOND
;
1051 real_data
+= element
.total_duration
.tv_nsec
;
1054 maxIRQduration
= element
.max_irq_handler
.duration
.tv_sec
;
1055 maxIRQduration
*= NANOSECONDS_PER_SECOND
;
1056 maxIRQduration
+= element
.max_irq_handler
.duration
.tv_nsec
;
1058 sprintf(maxIrqHandler
, "%d [%d.%d - %d.%d]",maxIRQduration
, element
.max_irq_handler
.start_time
.tv_sec
, \
1059 element
.max_irq_handler
.start_time
.tv_nsec
, element
.max_irq_handler
.end_time
.tv_sec
, \
1060 element
.max_irq_handler
.end_time
.tv_nsec
) ;
1062 minIRQduration
= element
.min_irq_handler
.duration
.tv_sec
;
1063 minIRQduration
*= NANOSECONDS_PER_SECOND
;
1064 minIRQduration
+= element
.min_irq_handler
.duration
.tv_nsec
;
1065 sprintf(minIrqHandler
, "%d [%d.%d - %d.%d]",minIRQduration
, element
.min_irq_handler
.start_time
.tv_sec
, \
1066 element
.min_irq_handler
.start_time
.tv_nsec
, element
.min_irq_handler
.end_time
.tv_sec
, \
1067 element
.min_irq_handler
.end_time
.tv_nsec
) ;
1070 FrequencyHZ
= FrequencyInHZ(element
.TotalNumberOfInterrupts
,event_data
->time_window
);
1072 if(FrequencyHZ
!= 0)
1074 periodInSec
= (double)1/FrequencyHZ
;
1075 periodInSec
*= NANOSECONDS_PER_SECOND
;
1076 periodInNsec
= (int)periodInSec
;
1080 gtk_list_store_append (event_data
->ListStore
, &iter
);
1081 gtk_list_store_set (event_data
->ListStore
, &iter
,
1082 CPUID_COLUMN
, element
.cpu_id
,
1083 IRQ_ID_COLUMN
, element
.id
,
1084 FREQUENCY_COLUMN
, FrequencyHZ
,
1085 DURATION_COLUMN
, real_data
,
1086 DURATION_STANDARD_DEV_COLUMN
, CalculateDurationStandardDeviation(element
.id
, event_data
),
1087 MAX_IRQ_HANDLER_COLUMN
, maxIrqHandler
,
1088 MIN_IRQ_HANDLER_COLUMN
, minIrqHandler
,
1089 AVERAGE_PERIOD
, periodInNsec
,
1090 PERIOD_STANDARD_DEV_COLUMN
, CalculatePeriodStandardDeviation(element
.id
, event_data
),
1091 FREQUENCY_STANDARD_DEV_COLUMN
, CalculateFrequencyStandardDeviation(element
.id
, event_data
),
1096 if(event_data
->FirstRequestIrqExit
->len
)
1098 g_array_remove_range (event_data
->FirstRequestIrqExit
,0,event_data
->FirstRequestIrqExit
->len
);
1101 if(event_data
->FirstRequestIrqEntry
->len
)
1103 g_array_remove_range (event_data
->FirstRequestIrqEntry
,0,event_data
->FirstRequestIrqEntry
->len
);
1106 if(event_data
->SecondRequestIrqEntry
->len
)
1108 g_array_remove_range (event_data
->SecondRequestIrqEntry
,0,event_data
->SecondRequestIrqEntry
->len
);
1111 if(event_data
->SecondRequestIrqExit
->len
)
1113 g_array_remove_range (event_data
->SecondRequestIrqExit
,0, event_data
->SecondRequestIrqExit
->len
);
1116 if(event_data
->SumArray
->len
)
1118 g_array_remove_range (event_data
->SumArray
,0, event_data
->SumArray
->len
);
1126 * This function converts the number of interrupts over a time window to
1129 static int FrequencyInHZ(gint NumerofInterruptions
, TimeWindow time_window
)
1131 guint64 frequencyHz
= 0;
1132 double timeSec
; // time in second
1134 result
= ltt_time_to_double(time_window
.time_width
);
1135 timeSec
= (result
/NANOSECONDS_PER_SECOND
); //time in second
1136 frequencyHz
= NumerofInterruptions
/ timeSec
;
1141 * This function calculates the duration standard deviation
1142 * Duration standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1144 * sumId.sumOfDurations -> Sum ((xi -Xa)^2)
1145 * inner_component -> 1/N Sum ((xi -Xa)^2)
1146 * deviation-> sqrt(1/N Sum ((xi -Xa)^2))
1148 static int CalculateDurationStandardDeviation(gint id
, InterruptEventData
*event_data
)
1152 double inner_component
;
1154 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
1156 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
1157 if(id
== sumId
.irqId
)
1159 if(sumId
.TotalNumberOfInterrupts
!= 0)
1160 inner_component
= sumId
.sumOfDurations
/ sumId
.TotalNumberOfInterrupts
;
1162 inner_component
= 0.0;
1163 deviation
= sqrt(inner_component
);
1172 * This function calculates the period standard deviation
1173 * Period standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1175 * sumId.sumOfPeriods -> Sum ((xi -Xa)^2)
1176 * inner_component -> 1/N Sum ((xi -Xa)^2)
1177 * period_standard_deviation-> sqrt(1/N Sum ((xi -Xa)^2))
1181 static int CalculatePeriodStandardDeviation(gint id
, InterruptEventData
*event_data
)
1185 guint64 inner_component
;
1186 guint64 period_standard_deviation
= 0;
1188 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
1190 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
1191 if(id
== sumId
.irqId
)
1193 if(sumId
.TotalNumberOfInterrupts
!= 0)
1194 inner_component
= sumId
.sumOfPeriods
/ sumId
.TotalNumberOfInterrupts
;
1196 inner_component
= 0;
1198 period_standard_deviation
= sqrt(inner_component
);
1202 return period_standard_deviation
;
1206 * This function calculates the frequency standard deviation
1207 * Frequency standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1209 * sumId.sumOfFrequencies -> Sum ((xi -Xa)^2)
1210 * inner_component -> 1/N Sum ((xi -Xa)^2)
1211 * frequency_standard_deviation-> sqrt(1/N Sum ((xi -Xa)^2))
1214 static int CalculateFrequencyStandardDeviation(gint id
, InterruptEventData
*event_data
)
1218 guint64 inner_component
;
1219 guint64 frequency_standard_deviation
= 0;
1220 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
1222 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
1223 if(id
== sumId
.irqId
)
1225 if(sumId
.TotalNumberOfInterrupts
!= 0)
1226 inner_component
= sumId
.sumOfFrequencies
/ sumId
.TotalNumberOfInterrupts
;
1228 inner_component
= 0;
1230 frequency_standard_deviation
= sqrt(inner_component
);
1233 return frequency_standard_deviation
;
1237 * This function is called by the main window
1238 * when the time interval needs to be updated.
1240 gboolean
interrupt_update_time_window(void * hook_data
, void * call_data
)
1242 InterruptEventData
*event_data
= (InterruptEventData
*) hook_data
;
1243 const TimeWindowNotifyData
*time_window_nofify_data
= ((const TimeWindowNotifyData
*)call_data
);
1244 event_data
->time_window
= *time_window_nofify_data
->new_time_window
;
1245 g_info("interrupts: interrupt_update_time_window()\n");
1246 Tab
*tab
= event_data
->tab
;
1247 lttvwindow_events_request_remove_all(tab
, event_data
);
1248 FirstRequest(event_data
);
1253 gboolean
trace_header(void *hook_data
, void *call_data
)
1256 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
1257 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1263 void interrupt_destroy_walk(gpointer data
, gpointer user_data
)
1265 g_info("interrupt_destroy_walk");
1266 InterruptEventData
*event_data
= (InterruptEventData
*) data
;
1267 interrupt_destructor((InterruptEventData
*)data
);
1271 void interrupt_destructor(InterruptEventData
*event_viewer_data
)
1273 /* May already been done by GTK window closing */
1274 g_info("enter interrupt_destructor \n");
1275 if(GTK_IS_WIDGET(event_viewer_data
->Hbox
))
1277 gtk_widget_destroy(event_viewer_data
->Hbox
);
1282 This function is called when the viewer is destroyed to free hooks and memory
1284 static void InterruptFree(InterruptEventData
*event_viewer_data
)
1286 Tab
*tab
= event_viewer_data
->tab
;
1290 g_array_free(event_viewer_data
->FirstRequestIrqExit
, TRUE
);
1291 g_array_free(event_viewer_data
->FirstRequestIrqEntry
, TRUE
);
1292 g_array_free(event_viewer_data
->SecondRequestIrqEntry
, TRUE
);
1293 g_array_free(event_viewer_data
->SecondRequestIrqExit
, TRUE
);
1294 g_array_free(event_viewer_data
->SumArray
, TRUE
);
1296 lttvwindow_unregister_time_window_notify(tab
, interrupt_update_time_window
, event_viewer_data
);
1298 lttvwindow_events_request_remove_all(event_viewer_data
->tab
,
1301 interrupt_data_list
= g_slist_remove(interrupt_data_list
, event_viewer_data
);
1308 * plugin's destroy function
1310 * This function releases the memory reserved by the module and unregisters
1311 * everything that has been registered in the gtkTraceSet API.
1313 static void destroy()
1316 g_info("Destroy interrupts");
1317 g_slist_foreach(interrupt_data_list
, interrupt_destroy_walk
, NULL
);
1318 g_slist_free(interrupt_data_list
);
1319 lttvwindow_unregister_constructor(interrupts
);
1323 LTTV_MODULE("interrupts", "interrupts info view", \
1324 "Graphical module to display interrupts performance", \
1325 init
, destroy
, "lttvwindow")