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>
85 #include <lttvwindow/lttv_plugin_tab.h>
88 #include "hInterruptsInsert.xpm"
90 #define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
91 #define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format)
104 guint TotalNumberOfInterrupts
;
105 LttTime total_duration
;
106 guint average_duration
;
107 IrqDuration max_irq_handler
;
108 IrqDuration min_irq_handler
;
121 guint TotalNumberOfInterrupts
;//frequency;//
122 guint64 sumOfDurations
; // to store the Sum ((xi -Xa)^2) of the duration Standard deviation
123 guint64 sumOfPeriods
; // to store the Sum ((xi -Xa)^2) of the period Standard deviation
124 guint64 sumOfFrequencies
;// to store the Sum ((xi -Xa)^2) of the frequency Standard deviation
133 /** Array containing instanced objects. Used when module is unloaded */
134 static GSList
*interrupt_data_list
= NULL
;
137 //fixed #define TRACE_NUMBER 0
139 typedef struct _InterruptEventData
{
141 /*Graphical Widgets */
142 GtkWidget
* ScrollWindow
;
143 GtkListStore
*ListStore
;
146 GtkTreeSelection
*SelectionTree
;
148 Tab
* tab
; /* tab that contains this plug-in*/
150 LttvHooks
* event_hooks
;
151 LttvHooks
* hooks_trace_after
;
152 LttvHooks
* hooks_trace_before
;
153 TimeWindow time_window
;
154 LttvHooksById
* event_by_id_hooks
;
155 GArray
*FirstRequestIrqExit
;
156 GArray
*FirstRequestIrqEntry
;
157 GArray
*SecondRequestIrqEntry
;
158 GArray
*SecondRequestIrqExit
;
161 } InterruptEventData
;
164 /* Function prototypes */
166 static gboolean
interrupt_update_time_window(void * hook_data
, void * call_data
);
167 static GtkWidget
*interrupts(LttvPlugin
*plugin
);
168 static InterruptEventData
*system_info(LttvPluginTab
*ptab
);
169 void interrupt_destructor(InterruptEventData
*event_viewer_data
);
170 static void FirstRequest(InterruptEventData
*event_data
);
171 static guint64
get_interrupt_id(LttEvent
*e
);
172 static gboolean
trace_header(void *hook_data
, void *call_data
);
173 static gboolean
DisplayViewer (void *hook_data
, void *call_data
);
174 static void CalculateData(LttTime time_exit
, guint cpu_id
, InterruptEventData
*event_data
);
175 static void CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(irq_entry
*e
, LttTime time_exit
, GArray
*FirstRequestIrqExit
);
176 static gboolean
FirstRequestIrqEntryCallback(void *hook_data
, void *call_data
);
177 static gboolean
FirstRequestIrqExitCallback(void *hook_data
, void *call_data
);
178 static gboolean
SecondRequest(void *hook_data
, void *call_data
);
179 static void CalculateAverageDurationForEachIrqId(InterruptEventData
*event_data
);
180 static gboolean
SecondRequestIrqEntryCallback(void *hook_data
, void *call_data
);
181 static gboolean
SecondRequestIrqExitCallback(void *hook_data
, void *call_data
);
182 static void CalculateXi(LttEvent
*event
, InterruptEventData
*event_data
);
183 static void SumItems(gint irq_id
, LttTime Xi
, InterruptEventData
*event_data
);
184 static int CalculateDurationStandardDeviation(gint id
, InterruptEventData
*event_data
);
185 static int CalculatePeriodStandardDeviation(gint id
, InterruptEventData
*event_data
);
186 static int FrequencyInHZ(gint NumberOfInterruptions
, TimeWindow time_window
);
187 static guint64
CalculatePeriodInnerPart(guint Xi
, guint FrequencyHZ
);
188 static guint64
CalculateFrequencyInnerPart(guint Xi_in_ns
, guint FrequencyHZ
);
189 static void InterruptFree(InterruptEventData
*event_viewer_data
);
190 static int CalculateFrequencyStandardDeviation(gint id
, InterruptEventData
*event_data
);
192 /* Enumeration of the columns */
198 DURATION_STANDARD_DEV_COLUMN
,
199 MAX_IRQ_HANDLER_COLUMN
,
200 MIN_IRQ_HANDLER_COLUMN
,
202 PERIOD_STANDARD_DEV_COLUMN
,
203 FREQUENCY_STANDARD_DEV_COLUMN
,
213 * This is the entry point of the viewer.
217 g_info("interrupts: init()");
218 lttvwindow_register_constructor("interrupts",
220 "Insert Interrupts View",
221 hInterruptsInsert_xpm
,
222 "Insert Interrupts View",
232 static GtkWidget
*interrupts(LttvPlugin
*plugin
)
234 LttvPluginTab
*ptab
= LTTV_PLUGIN_TAB(plugin
);
235 InterruptEventData
* event_data
= system_info(ptab
) ;
237 return event_data
->Hbox
;
243 * This function initializes the Event Viewer functionnality through the
246 InterruptEventData
*system_info(LttvPluginTab
*ptab
)
250 GtkTreeViewColumn
*column
;
251 GtkCellRenderer
*renderer
;
252 InterruptEventData
* event_viewer_data
= g_new(InterruptEventData
,1) ;
253 Tab
*tab
= ptab
->tab
;
254 event_viewer_data
->ptab
= ptab
;
255 event_viewer_data
->tab
= tab
;
257 /*Get the current time frame from the main window */
258 event_viewer_data
->time_window
= lttvwindow_get_time_window(tab
);
260 event_viewer_data
->FirstRequestIrqExit
= g_array_new(FALSE
, FALSE
, sizeof(Irq
));
261 event_viewer_data
->FirstRequestIrqEntry
= g_array_new(FALSE
, FALSE
, sizeof(irq_entry
));
263 event_viewer_data
->SecondRequestIrqEntry
= g_array_new(FALSE
, FALSE
, sizeof(irq_entry
));
264 event_viewer_data
->SecondRequestIrqExit
= g_array_new(FALSE
, FALSE
, sizeof(Irq
));
266 event_viewer_data
->SumArray
= g_array_new(FALSE
, FALSE
, sizeof(SumId
));
269 /*Create tha main window for the viewer */
270 event_viewer_data
->ScrollWindow
= gtk_scrolled_window_new (NULL
, NULL
);
271 gtk_widget_show (event_viewer_data
->ScrollWindow
);
272 gtk_scrolled_window_set_policy(
273 GTK_SCROLLED_WINDOW(event_viewer_data
->ScrollWindow
),
274 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
/*GTK_POLICY_NEVER*/);
276 /* Create a model for storing the data list */
277 event_viewer_data
->ListStore
= gtk_list_store_new (
278 N_COLUMNS
, /* Total number of columns */
279 G_TYPE_INT
, /* CPUID */
280 G_TYPE_INT
, /* IRQ_ID */
281 G_TYPE_INT
, /* Frequency */
282 G_TYPE_UINT64
, /* Duration */
283 G_TYPE_INT
, /* standard deviation */
284 G_TYPE_STRING
, /* Max IRQ handler */
285 G_TYPE_STRING
, /* Min IRQ handler */
286 G_TYPE_INT
, /* Average period */
287 G_TYPE_INT
, /* period standard deviation */
288 G_TYPE_INT
/* frequency standard deviation */
292 event_viewer_data
->TreeView
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (event_viewer_data
->ListStore
));
294 g_object_unref (G_OBJECT (event_viewer_data
->ListStore
));
296 renderer
= gtk_cell_renderer_text_new ();
297 column
= gtk_tree_view_column_new_with_attributes ("CPU ID",
299 "text", CPUID_COLUMN
,
301 gtk_tree_view_column_set_alignment (column
, 0.0);
302 gtk_tree_view_column_set_fixed_width (column
, 45);
303 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
306 renderer
= gtk_cell_renderer_text_new ();
307 column
= gtk_tree_view_column_new_with_attributes ("IRQ ID",
309 "text", IRQ_ID_COLUMN
,
311 gtk_tree_view_column_set_alignment (column
, 0.0);
312 gtk_tree_view_column_set_fixed_width (column
, 220);
313 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
315 renderer
= gtk_cell_renderer_text_new ();
316 column
= gtk_tree_view_column_new_with_attributes ("Frequency (Hz)",
318 "text", FREQUENCY_COLUMN
,
320 gtk_tree_view_column_set_alignment (column
, 1.0);
321 gtk_tree_view_column_set_fixed_width (column
, 220);
322 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
324 renderer
= gtk_cell_renderer_text_new ();
325 column
= gtk_tree_view_column_new_with_attributes ("Total Duration (nsec)",
327 "text", DURATION_COLUMN
,
329 gtk_tree_view_column_set_alignment (column
, 0.0);
330 gtk_tree_view_column_set_fixed_width (column
, 145);
331 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
334 renderer
= gtk_cell_renderer_text_new ();
335 column
= gtk_tree_view_column_new_with_attributes ("Duration standard deviation (nsec)",
337 "text", DURATION_STANDARD_DEV_COLUMN
,
339 gtk_tree_view_column_set_alignment (column
, 0.0);
340 gtk_tree_view_column_set_fixed_width (column
, 200);
341 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
343 renderer
= gtk_cell_renderer_text_new ();
344 column
= gtk_tree_view_column_new_with_attributes ("Max IRQ handler duration (nsec) [time interval]",
346 "text", MAX_IRQ_HANDLER_COLUMN
,
348 gtk_tree_view_column_set_alignment (column
, 0.0);
349 gtk_tree_view_column_set_fixed_width (column
, 250);
350 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
352 renderer
= gtk_cell_renderer_text_new ();
353 column
= gtk_tree_view_column_new_with_attributes ("Min IRQ handler duration (nsec) [time interval]",
355 "text", MIN_IRQ_HANDLER_COLUMN
,
357 gtk_tree_view_column_set_alignment (column
, 0.0);
358 gtk_tree_view_column_set_fixed_width (column
, 250);
359 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
361 renderer
= gtk_cell_renderer_text_new ();
362 column
= gtk_tree_view_column_new_with_attributes (" Average period (nsec)",
364 "text", AVERAGE_PERIOD
,
366 gtk_tree_view_column_set_alignment (column
, 0.0);
367 gtk_tree_view_column_set_fixed_width (column
, 200);
368 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
370 renderer
= gtk_cell_renderer_text_new ();
371 column
= gtk_tree_view_column_new_with_attributes ("Period standard deviation (nsec)",
373 "text", PERIOD_STANDARD_DEV_COLUMN
,
375 gtk_tree_view_column_set_alignment (column
, 0.0);
376 gtk_tree_view_column_set_fixed_width (column
, 200);
377 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
379 renderer
= gtk_cell_renderer_text_new ();
380 column
= gtk_tree_view_column_new_with_attributes ("Frequency standard deviation (Hz)",
382 "text", FREQUENCY_STANDARD_DEV_COLUMN
,
384 gtk_tree_view_column_set_alignment (column
, 0.0);
385 gtk_tree_view_column_set_fixed_width (column
, 200);
386 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
389 event_viewer_data
->SelectionTree
= gtk_tree_view_get_selection (GTK_TREE_VIEW (event_viewer_data
->TreeView
));
390 gtk_tree_selection_set_mode (event_viewer_data
->SelectionTree
, GTK_SELECTION_SINGLE
);
392 gtk_container_add (GTK_CONTAINER (event_viewer_data
->ScrollWindow
), event_viewer_data
->TreeView
);
394 event_viewer_data
->Hbox
= gtk_hbox_new(0, 0);
395 gtk_box_pack_start(GTK_BOX(event_viewer_data
->Hbox
), event_viewer_data
->ScrollWindow
, TRUE
, TRUE
, 0);
397 gtk_widget_show(event_viewer_data
->Hbox
);
398 gtk_widget_show(event_viewer_data
->TreeView
);
400 interrupt_data_list
= g_slist_append(interrupt_data_list
, event_viewer_data
);
401 /* Registration for time notification */
402 lttvwindow_register_time_window_notify(tab
,
403 interrupt_update_time_window
,
406 g_object_set_data_full(G_OBJECT(event_viewer_data
->Hbox
),
409 (GDestroyNotify
) InterruptFree
);
411 FirstRequest(event_viewer_data
);
412 return event_viewer_data
;
418 * For each trace in the traceset, this function:
419 * - registers a callback function to each hook
420 * - calls lttv_trace_find_hook() registers a hook function to event_by_id_hooks
421 * - calls lttvwindow_events_request() to request data in a specific
422 * time interval to the main window
425 static void FirstRequest(InterruptEventData
*event_data
)
427 guint i
, k
, l
, nb_trace
;
437 EventsRequest
*events_request
;
439 LttvTraceHookByFacility
*thf
;
441 LttvTracesetContext
*tsc
= lttvwindow_get_traceset_context(event_data
->tab
);
444 /* Get the traceset */
445 LttvTraceset
*traceset
= tsc
->ts
;
447 nb_trace
= lttv_traceset_number(traceset
);
449 /* There are many traces in a traceset. Iteration for each trace. */
450 //for(i = 0; i<MIN(TRACE_NUMBER+1, nb_trace);i++) {
451 for(i
= 0 ; i
< nb_trace
; i
++) {
452 events_request
= g_new(EventsRequest
, 1);
454 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
456 hooks
= g_array_set_size(hooks
, 2);
458 event_data
->hooks_trace_before
= lttv_hooks_new();
460 /* Registers a hook function */
461 lttv_hooks_add(event_data
->hooks_trace_before
, trace_header
, event_data
, LTTV_PRIO_DEFAULT
);
463 event_data
->hooks_trace_after
= lttv_hooks_new();
465 /* Registers a hook function */
466 lttv_hooks_add(event_data
->hooks_trace_after
, SecondRequest
, event_data
, LTTV_PRIO_DEFAULT
);
467 /* Get a trace state */
468 ts
= (LttvTraceState
*)tsc
->traces
[i
];
469 /* Create event_by_Id hooks */
470 event_data
->event_by_id_hooks
= lttv_hooks_by_id_new();
472 /*Register event_by_id_hooks with a callback function*/
473 ret
= lttv_trace_find_hook(ts
->parent
.t
,
474 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
475 LTT_FIELD_IRQ_ID
, 0, 0,
476 FirstRequestIrqEntryCallback
,
478 &g_array_index(hooks
, LttvTraceHook
, 0));
480 ret
= lttv_trace_find_hook(ts
->parent
.t
,
481 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
482 LTT_FIELD_IRQ_ID
, 0, 0,
483 FirstRequestIrqExitCallback
,
485 &g_array_index(hooks
, LttvTraceHook
, 1));
488 /*iterate through the facility list*/
489 for(k
= 0 ; k
< hooks
->len
; k
++)
491 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
492 for(l
=0; l
<hook
->fac_list
->len
; l
++)
494 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
495 lttv_hooks_add(lttv_hooks_by_id_find(event_data
->event_by_id_hooks
, thf
->id
),
502 /* Initalize the EventsRequest structure */
503 events_request
->owner
= event_data
;
504 events_request
->viewer_data
= event_data
;
505 events_request
->servicing
= FALSE
;
506 events_request
->start_time
= event_data
->time_window
.start_time
;
507 events_request
->start_position
= NULL
;
508 events_request
->stop_flag
= FALSE
;
509 events_request
->end_time
= event_data
->time_window
.end_time
;
510 events_request
->num_events
= G_MAXUINT
;
511 events_request
->end_position
= NULL
;
512 events_request
->trace
= i
;
514 events_request
->hooks
= hooks
;
516 events_request
->before_chunk_traceset
= NULL
;
517 events_request
->before_chunk_trace
= event_data
->hooks_trace_before
;
518 events_request
->before_chunk_tracefile
= NULL
;
519 events_request
->event
= NULL
;
520 events_request
->event_by_id
= event_data
->event_by_id_hooks
;
521 events_request
->after_chunk_tracefile
= NULL
;
522 events_request
->after_chunk_trace
= NULL
;
523 events_request
->after_chunk_traceset
= NULL
;
524 events_request
->before_request
= NULL
;
525 events_request
->after_request
= event_data
->hooks_trace_after
;
527 lttvwindow_events_request(event_data
->tab
, events_request
);
533 * This function is called whenever an irq_entry event occurs.
536 static gboolean
FirstRequestIrqEntryCallback(void *hook_data
, void *call_data
)
542 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
543 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
544 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
545 GArray
* FirstRequestIrqEntry
= event_data
->FirstRequestIrqEntry
;
546 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
547 event_time
= ltt_event_time(e
);
548 cpu_id
= ltt_event_cpu_id(e
);
551 entry
.id
=get_interrupt_id(e
);
552 entry
.cpu_id
= cpu_id
;
553 entry
.event_time
= event_time
;
554 g_array_append_val (FirstRequestIrqEntry
, entry
);
560 * This function gets the id of the interrupt. The id is stored in a dynamic structure.
561 * Refer to the print.c file for how to extract data from a dynamic structure.
563 static guint64
get_interrupt_id(LttEvent
*e
)
566 LttEventType
*event_type
;
570 event_type
= ltt_event_eventtype(e
);
571 num_fields
= ltt_eventtype_num_fields(event_type
);
572 for(i
= 0 ; i
< num_fields
-1 ; i
++)
574 field
= ltt_eventtype_field(event_type
, i
);
575 irq_id
= ltt_event_get_long_unsigned(e
,field
);
581 * This function is called whenever an irq_exit event occurs.
584 gboolean
FirstRequestIrqExitCallback(void *hook_data
, void *call_data
)
588 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
589 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
590 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
591 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
592 LttEventType
*type
= ltt_event_eventtype(e
);
593 event_time
= ltt_event_time(e
);
594 cpu_id
= ltt_event_cpu_id(e
);
596 CalculateData( event_time
, cpu_id
, event_data
);
602 * This function calculates the duration of an interrupt.
605 static void CalculateData(LttTime time_exit
, guint cpu_id
,InterruptEventData
*event_data
)
611 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
612 GArray
*FirstRequestIrqEntry
= event_data
->FirstRequestIrqEntry
;
613 for(i
= 0; i
< FirstRequestIrqEntry
->len
; i
++)
615 element
= &g_array_index(FirstRequestIrqEntry
,irq_entry
,i
);
616 if(element
->cpu_id
== cpu_id
)
618 CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(element
,time_exit
, FirstRequestIrqExit
);
619 g_array_remove_index(FirstRequestIrqEntry
, i
);
627 * This function calculates the total duration of an interrupt and the longest & shortest Irq handlers.
630 static void CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(irq_entry
*e
, LttTime time_exit
, GArray
*FirstRequestIrqExit
)
636 gboolean notFound
= FALSE
;
637 memset ((void*)&irq
, 0,sizeof(Irq
));
640 if(FirstRequestIrqExit
->len
== NO_ITEMS
)
642 irq
.cpu_id
= e
->cpu_id
;
644 irq
.TotalNumberOfInterrupts
++;
645 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
647 irq
.max_irq_handler
.start_time
= e
->event_time
;
648 irq
.max_irq_handler
.end_time
= time_exit
;
649 irq
.max_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
651 irq
.min_irq_handler
.start_time
= e
->event_time
;
652 irq
.min_irq_handler
.end_time
= time_exit
;
653 irq
.min_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
655 g_array_append_val (FirstRequestIrqExit
, irq
);
659 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
661 element
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
662 if(element
->id
== e
->id
)
665 duration
= ltt_time_sub(time_exit
, e
->event_time
);
666 element
->total_duration
= ltt_time_add(element
->total_duration
, duration
);
667 element
->TotalNumberOfInterrupts
++;
669 if(ltt_time_compare(duration
,element
->max_irq_handler
.duration
) > 0)
671 element
->max_irq_handler
.duration
= duration
;
672 element
->max_irq_handler
.start_time
= e
->event_time
;
673 element
->max_irq_handler
.end_time
= time_exit
;
676 if(ltt_time_compare(duration
,element
->min_irq_handler
.duration
) < 0)
678 element
->min_irq_handler
.duration
= duration
;
679 element
->min_irq_handler
.start_time
= e
->event_time
;
680 element
->min_irq_handler
.end_time
= time_exit
;
686 irq
.cpu_id
= e
->cpu_id
;
688 irq
.TotalNumberOfInterrupts
++;
689 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
691 irq
.max_irq_handler
.start_time
= e
->event_time
;
692 irq
.max_irq_handler
.end_time
= time_exit
;
693 irq
.max_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
695 irq
.min_irq_handler
.start_time
= e
->event_time
;
696 irq
.min_irq_handler
.end_time
= time_exit
;
697 irq
.min_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
699 g_array_append_val (FirstRequestIrqExit
, irq
);
705 * This function passes the second EventsRequest to LTTV
708 static gboolean
SecondRequest(void *hook_data
, void *call_data
)
711 guint i
, k
, l
, nb_trace
;
721 EventsRequest
*events_request
;
723 LttvTraceHookByFacility
*thf
;
725 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
727 LttvTracesetContext
*tsc
= lttvwindow_get_traceset_context(event_data
->tab
);
729 CalculateAverageDurationForEachIrqId(event_data
);
731 /* Get the traceset */
732 LttvTraceset
*traceset
= tsc
->ts
;
734 nb_trace
= lttv_traceset_number(traceset
);
736 /* There are many traces in a traceset. Iteration for each trace. */
737 for(i
= 0 ; i
< nb_trace
; i
++) {
738 // fixed for(i = 0; i<MIN(TRACE_NUMBER+1, nb_trace);i++) {
739 events_request
= g_new(EventsRequest
, 1);
741 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
743 hooks
= g_array_set_size(hooks
, 2);
745 event_data
->hooks_trace_after
= lttv_hooks_new();
747 /* Registers a hook function */
748 lttv_hooks_add(event_data
->hooks_trace_after
, DisplayViewer
, event_data
, LTTV_PRIO_DEFAULT
);
750 /* Get a trace state */
751 ts
= (LttvTraceState
*)tsc
->traces
[i
];
752 /* Create event_by_Id hooks */
753 event_data
->event_by_id_hooks
= lttv_hooks_by_id_new();
755 /*Register event_by_id_hooks with a callback function*/
756 ret
= lttv_trace_find_hook(ts
->parent
.t
,
757 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
758 LTT_FIELD_IRQ_ID
, 0, 0,
759 SecondRequestIrqEntryCallback
,
761 &g_array_index(hooks
, LttvTraceHook
, 0));
763 ret
= lttv_trace_find_hook(ts
->parent
.t
,
764 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
765 LTT_FIELD_IRQ_ID
, 0, 0,
766 SecondRequestIrqExitCallback
,
768 &g_array_index(hooks
, LttvTraceHook
, 1));
772 /* iterate through the facility list */
773 for(k
= 0 ; k
< hooks
->len
; k
++)
775 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
776 for(l
=0; l
<hook
->fac_list
->len
; l
++)
778 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
779 lttv_hooks_add(lttv_hooks_by_id_find(event_data
->event_by_id_hooks
, thf
->id
),
786 /* Initalize the EventsRequest structure */
787 events_request
->owner
= event_data
;
788 events_request
->viewer_data
= event_data
;
789 events_request
->servicing
= FALSE
;
790 events_request
->start_time
= event_data
->time_window
.start_time
;
791 events_request
->start_position
= NULL
;
792 events_request
->stop_flag
= FALSE
;
793 events_request
->end_time
= event_data
->time_window
.end_time
;
794 events_request
->num_events
= G_MAXUINT
;
795 events_request
->end_position
= NULL
;
796 events_request
->trace
= i
;
798 events_request
->hooks
= hooks
;
800 events_request
->before_chunk_traceset
= NULL
;
801 events_request
->before_chunk_trace
= NULL
;
802 events_request
->before_chunk_tracefile
= NULL
;
803 events_request
->event
= NULL
;
804 events_request
->event_by_id
= event_data
->event_by_id_hooks
;
805 events_request
->after_chunk_tracefile
= NULL
;
806 events_request
->after_chunk_trace
= NULL
;
807 events_request
->after_chunk_traceset
= NULL
;
808 events_request
->before_request
= NULL
;
809 events_request
->after_request
= event_data
->hooks_trace_after
;
811 lttvwindow_events_request(event_data
->tab
, events_request
);
817 * This function calculates the average duration for each Irq Id
820 static void CalculateAverageDurationForEachIrqId(InterruptEventData
*event_data
)
825 GArray
* FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
826 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
828 element
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
829 real_data
= element
->total_duration
.tv_sec
;
830 real_data
*= NANOSECONDS_PER_SECOND
;
831 real_data
+= element
->total_duration
.tv_nsec
;
832 if(element
->TotalNumberOfInterrupts
!= 0)
833 element
->average_duration
= real_data
/ element
->TotalNumberOfInterrupts
;
835 element
->average_duration
= 0;
841 * This function is called whenever an irq_entry event occurs. Use in the second request
844 static gboolean
SecondRequestIrqEntryCallback(void *hook_data
, void *call_data
)
850 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
851 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
852 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
853 GArray
* SecondRequestIrqEntry
= event_data
->SecondRequestIrqEntry
;
854 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
855 event_time
= ltt_event_time(e
);
856 cpu_id
= ltt_event_cpu_id(e
);
859 entry
.id
=get_interrupt_id(e
);
860 entry
.cpu_id
= cpu_id
;
861 entry
.event_time
= event_time
;
862 g_array_append_val (SecondRequestIrqEntry
, entry
);
868 * This function is called whenever an irq_exit event occurs in the second request.
871 static gboolean
SecondRequestIrqExitCallback(void *hook_data
, void *call_data
)
874 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
875 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
876 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
877 LttEvent
*event
= ltt_tracefile_get_event(tfc
->tf
);
879 CalculateXi(event
, event_data
);
885 * This function is called whenever an irq_exit event occurs in the second request.
888 static void CalculateXi(LttEvent
*event_irq_exit
, InterruptEventData
*event_data
)
896 GArray
*SecondRequestIrqExit
= event_data
->SecondRequestIrqExit
;
897 GArray
*SecondRequestIrqEntry
= event_data
->SecondRequestIrqEntry
;
898 cpu_id
= ltt_event_cpu_id(event_irq_exit
);
899 for(i
= 0; i
< SecondRequestIrqEntry
->len
; i
++)
901 element
= &g_array_index(SecondRequestIrqEntry
,irq_entry
,i
);
902 if(element
->cpu_id
== cpu_id
)
905 /* time calculation */
906 exit_time
= ltt_event_time(event_irq_exit
);
907 Xi
= ltt_time_sub(exit_time
, element
->event_time
);
908 irq_id
= element
->id
;
910 SumItems(irq_id
, Xi
,event_data
);
911 g_array_remove_index(SecondRequestIrqEntry
, i
);
919 * This function computes the Sum ((xi -Xa)^2) and store the result in SumArray
922 static void SumItems(gint irq_id
, LttTime Xi
, InterruptEventData
*event_data
)
927 gint duration_inner_part
;
928 guint64 period_inner_part
;
929 guint64 frequency_inner_part
;
935 gboolean notFound
= FALSE
;
936 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
937 GArray
*SumArray
= event_data
->SumArray
;
938 Xi_in_ns
= Xi
.tv_sec
;
939 Xi_in_ns
*= NANOSECONDS_PER_SECOND
;
940 Xi_in_ns
+= Xi
.tv_nsec
;
942 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
944 average
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
945 if(irq_id
== average
->id
)
947 duration_inner_part
= Xi_in_ns
- average
->average_duration
;
948 FrequencyHZ
= FrequencyInHZ(average
->TotalNumberOfInterrupts
, event_data
->time_window
);
950 // compute (xi -Xa)^2 of the duration Standard deviation
951 sum
.TotalNumberOfInterrupts
= average
->TotalNumberOfInterrupts
;
952 sum
.sumOfDurations
= pow (duration_inner_part
, 2);
954 // compute (xi -Xa)^2 of the period Standard deviation
955 period_inner_part
= CalculatePeriodInnerPart(Xi_in_ns
, FrequencyHZ
);
957 // compute (xi -Xa)^2 of the frequency Standard deviation
958 frequency_inner_part
= CalculateFrequencyInnerPart(Xi_in_ns
, FrequencyHZ
);
960 sum
.sumOfPeriods
= period_inner_part
;
962 sum
.sumOfFrequencies
= frequency_inner_part
;
964 if(event_data
->SumArray
->len
== NO_ITEMS
)
966 g_array_append_val (SumArray
, sum
);
970 for(i
= 0; i
< SumArray
->len
; i
++)
972 sumItem
= &g_array_index(SumArray
, SumId
, i
);
973 if(sumItem
->irqId
== irq_id
)
976 sumItem
->sumOfDurations
+= sum
.sumOfDurations
;
977 sumItem
->sumOfPeriods
+= sum
.sumOfPeriods
;
978 sumItem
->sumOfFrequencies
+= sum
.sumOfFrequencies
;
983 g_array_append_val (SumArray
, sum
);
993 * This function computes the inner part of the period standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
994 * The inner part is: (xi -Xa)^2
996 static guint64
CalculatePeriodInnerPart(guint Xi
, guint FrequencyHZ
)
999 double periodInSec
; /*period in sec*/
1003 periodInSec
= (double)1/FrequencyHZ
;
1004 periodInSec
*= NANOSECONDS_PER_SECOND
;
1005 periodInNSec
= (int)periodInSec
;
1007 difference
= Xi
- periodInNSec
;
1008 result
= pow (difference
, 2);
1013 * This function computes the inner part of the frequency standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1014 * The inner part is: (xi -Xa)^2
1016 static guint64
CalculateFrequencyInnerPart(guint Xi_in_ns
, guint FrequencyHZ
)
1021 difference
= Xi_in_ns
- FrequencyHZ
;
1022 result
= pow (difference
, 2);
1026 * This function displays the result on the viewer
1029 static gboolean
DisplayViewer(void *hook_data
, void *call_data
)
1035 LttTime average_duration
;
1038 guint maxIRQduration
;
1039 guint minIRQduration
;
1042 char maxIrqHandler
[80];
1043 char minIrqHandler
[80];
1044 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
1045 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
1046 int FrequencyHZ
= 0;
1048 gtk_list_store_clear(event_data
->ListStore
);
1049 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
1051 element
= g_array_index(FirstRequestIrqExit
,Irq
,i
);
1052 real_data
= element
.total_duration
.tv_sec
;
1053 real_data
*= NANOSECONDS_PER_SECOND
;
1054 real_data
+= element
.total_duration
.tv_nsec
;
1057 maxIRQduration
= element
.max_irq_handler
.duration
.tv_sec
;
1058 maxIRQduration
*= NANOSECONDS_PER_SECOND
;
1059 maxIRQduration
+= element
.max_irq_handler
.duration
.tv_nsec
;
1061 sprintf(maxIrqHandler
, "%d [%d.%d - %d.%d]",maxIRQduration
, element
.max_irq_handler
.start_time
.tv_sec
, \
1062 element
.max_irq_handler
.start_time
.tv_nsec
, element
.max_irq_handler
.end_time
.tv_sec
, \
1063 element
.max_irq_handler
.end_time
.tv_nsec
) ;
1065 minIRQduration
= element
.min_irq_handler
.duration
.tv_sec
;
1066 minIRQduration
*= NANOSECONDS_PER_SECOND
;
1067 minIRQduration
+= element
.min_irq_handler
.duration
.tv_nsec
;
1068 sprintf(minIrqHandler
, "%d [%d.%d - %d.%d]",minIRQduration
, element
.min_irq_handler
.start_time
.tv_sec
, \
1069 element
.min_irq_handler
.start_time
.tv_nsec
, element
.min_irq_handler
.end_time
.tv_sec
, \
1070 element
.min_irq_handler
.end_time
.tv_nsec
) ;
1073 FrequencyHZ
= FrequencyInHZ(element
.TotalNumberOfInterrupts
,event_data
->time_window
);
1075 if(FrequencyHZ
!= 0)
1077 periodInSec
= (double)1/FrequencyHZ
;
1078 periodInSec
*= NANOSECONDS_PER_SECOND
;
1079 periodInNsec
= (int)periodInSec
;
1083 gtk_list_store_append (event_data
->ListStore
, &iter
);
1084 gtk_list_store_set (event_data
->ListStore
, &iter
,
1085 CPUID_COLUMN
, element
.cpu_id
,
1086 IRQ_ID_COLUMN
, element
.id
,
1087 FREQUENCY_COLUMN
, FrequencyHZ
,
1088 DURATION_COLUMN
, real_data
,
1089 DURATION_STANDARD_DEV_COLUMN
, CalculateDurationStandardDeviation(element
.id
, event_data
),
1090 MAX_IRQ_HANDLER_COLUMN
, maxIrqHandler
,
1091 MIN_IRQ_HANDLER_COLUMN
, minIrqHandler
,
1092 AVERAGE_PERIOD
, periodInNsec
,
1093 PERIOD_STANDARD_DEV_COLUMN
, CalculatePeriodStandardDeviation(element
.id
, event_data
),
1094 FREQUENCY_STANDARD_DEV_COLUMN
, CalculateFrequencyStandardDeviation(element
.id
, event_data
),
1099 if(event_data
->FirstRequestIrqExit
->len
)
1101 g_array_remove_range (event_data
->FirstRequestIrqExit
,0,event_data
->FirstRequestIrqExit
->len
);
1104 if(event_data
->FirstRequestIrqEntry
->len
)
1106 g_array_remove_range (event_data
->FirstRequestIrqEntry
,0,event_data
->FirstRequestIrqEntry
->len
);
1109 if(event_data
->SecondRequestIrqEntry
->len
)
1111 g_array_remove_range (event_data
->SecondRequestIrqEntry
,0,event_data
->SecondRequestIrqEntry
->len
);
1114 if(event_data
->SecondRequestIrqExit
->len
)
1116 g_array_remove_range (event_data
->SecondRequestIrqExit
,0, event_data
->SecondRequestIrqExit
->len
);
1119 if(event_data
->SumArray
->len
)
1121 g_array_remove_range (event_data
->SumArray
,0, event_data
->SumArray
->len
);
1129 * This function converts the number of interrupts over a time window to
1132 static int FrequencyInHZ(gint NumerofInterruptions
, TimeWindow time_window
)
1134 guint64 frequencyHz
= 0;
1135 double timeSec
; // time in second
1137 result
= ltt_time_to_double(time_window
.time_width
);
1138 timeSec
= (result
/NANOSECONDS_PER_SECOND
); //time in second
1139 frequencyHz
= NumerofInterruptions
/ timeSec
;
1144 * This function calculates the duration standard deviation
1145 * Duration standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1147 * sumId.sumOfDurations -> Sum ((xi -Xa)^2)
1148 * inner_component -> 1/N Sum ((xi -Xa)^2)
1149 * deviation-> sqrt(1/N Sum ((xi -Xa)^2))
1151 static int CalculateDurationStandardDeviation(gint id
, InterruptEventData
*event_data
)
1155 double inner_component
;
1157 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
1159 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
1160 if(id
== sumId
.irqId
)
1162 if(sumId
.TotalNumberOfInterrupts
!= 0)
1163 inner_component
= sumId
.sumOfDurations
/ sumId
.TotalNumberOfInterrupts
;
1165 inner_component
= 0.0;
1166 deviation
= sqrt(inner_component
);
1175 * This function calculates the period standard deviation
1176 * Period standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1178 * sumId.sumOfPeriods -> Sum ((xi -Xa)^2)
1179 * inner_component -> 1/N Sum ((xi -Xa)^2)
1180 * period_standard_deviation-> sqrt(1/N Sum ((xi -Xa)^2))
1184 static int CalculatePeriodStandardDeviation(gint id
, InterruptEventData
*event_data
)
1188 guint64 inner_component
;
1189 guint64 period_standard_deviation
= 0;
1191 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
1193 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
1194 if(id
== sumId
.irqId
)
1196 if(sumId
.TotalNumberOfInterrupts
!= 0)
1197 inner_component
= sumId
.sumOfPeriods
/ sumId
.TotalNumberOfInterrupts
;
1199 inner_component
= 0;
1201 period_standard_deviation
= sqrt(inner_component
);
1205 return period_standard_deviation
;
1209 * This function calculates the frequency standard deviation
1210 * Frequency standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1212 * sumId.sumOfFrequencies -> Sum ((xi -Xa)^2)
1213 * inner_component -> 1/N Sum ((xi -Xa)^2)
1214 * frequency_standard_deviation-> sqrt(1/N Sum ((xi -Xa)^2))
1217 static int CalculateFrequencyStandardDeviation(gint id
, InterruptEventData
*event_data
)
1221 guint64 inner_component
;
1222 guint64 frequency_standard_deviation
= 0;
1223 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
1225 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
1226 if(id
== sumId
.irqId
)
1228 if(sumId
.TotalNumberOfInterrupts
!= 0)
1229 inner_component
= sumId
.sumOfFrequencies
/ sumId
.TotalNumberOfInterrupts
;
1231 inner_component
= 0;
1233 frequency_standard_deviation
= sqrt(inner_component
);
1236 return frequency_standard_deviation
;
1240 * This function is called by the main window
1241 * when the time interval needs to be updated.
1243 gboolean
interrupt_update_time_window(void * hook_data
, void * call_data
)
1245 InterruptEventData
*event_data
= (InterruptEventData
*) hook_data
;
1246 const TimeWindowNotifyData
*time_window_nofify_data
= ((const TimeWindowNotifyData
*)call_data
);
1247 event_data
->time_window
= *time_window_nofify_data
->new_time_window
;
1248 g_info("interrupts: interrupt_update_time_window()\n");
1249 Tab
*tab
= event_data
->tab
;
1250 lttvwindow_events_request_remove_all(tab
, event_data
);
1251 FirstRequest(event_data
);
1256 gboolean
trace_header(void *hook_data
, void *call_data
)
1259 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
1260 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1266 void interrupt_destroy_walk(gpointer data
, gpointer user_data
)
1268 g_info("interrupt_destroy_walk");
1269 InterruptEventData
*event_data
= (InterruptEventData
*) data
;
1270 interrupt_destructor((InterruptEventData
*)data
);
1274 void interrupt_destructor(InterruptEventData
*event_viewer_data
)
1276 /* May already been done by GTK window closing */
1277 g_info("enter interrupt_destructor \n");
1278 if(GTK_IS_WIDGET(event_viewer_data
->Hbox
))
1280 gtk_widget_destroy(event_viewer_data
->Hbox
);
1285 This function is called when the viewer is destroyed to free hooks and memory
1287 static void InterruptFree(InterruptEventData
*event_viewer_data
)
1289 Tab
*tab
= event_viewer_data
->tab
;
1293 g_array_free(event_viewer_data
->FirstRequestIrqExit
, TRUE
);
1294 g_array_free(event_viewer_data
->FirstRequestIrqEntry
, TRUE
);
1295 g_array_free(event_viewer_data
->SecondRequestIrqEntry
, TRUE
);
1296 g_array_free(event_viewer_data
->SecondRequestIrqExit
, TRUE
);
1297 g_array_free(event_viewer_data
->SumArray
, TRUE
);
1299 lttvwindow_unregister_time_window_notify(tab
, interrupt_update_time_window
, event_viewer_data
);
1301 lttvwindow_events_request_remove_all(event_viewer_data
->tab
,
1304 interrupt_data_list
= g_slist_remove(interrupt_data_list
, event_viewer_data
);
1311 * plugin's destroy function
1313 * This function releases the memory reserved by the module and unregisters
1314 * everything that has been registered in the gtkTraceSet API.
1316 static void destroy()
1319 g_info("Destroy interrupts");
1320 g_slist_foreach(interrupt_data_list
, interrupt_destroy_walk
, NULL
);
1321 g_slist_free(interrupt_data_list
);
1322 lttvwindow_unregister_constructor(interrupts
);
1326 LTTV_MODULE("interrupts", "interrupts info view", \
1327 "Graphical module to display interrupts performance", \
1328 init
, destroy
, "lttvwindow")