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 /******************************************************************
25 - Frequency (Hz): the number of interruptions per second (Hz)
27 - Total Duration (nsec): the sum of each interrupt duration in nsec
29 - Duration Standard_deviation = sqrt(1/N Sum ((xi -Xa)^2)) where
30 N: number of interrupts
31 xi: duration of an interrupt (nsec)
32 Xa: average duration (nsec)
34 - Max IRQ handler duration (nsec) [time interval]: the longest IRQ handler duration in nsec.
36 -Average period (nsec): 1/Frequency(in HZ)
38 -Period Standard_deviation = sqrt(1/N Sum ((xi -Xa)^2)) where
39 N: number of interruptions
40 xi: duration of an interrupt
41 Xa: 1/Frequency (in Hz)
43 -Frequency Standard_deviation = sqrt(1/N Sum ((xi -Xa)^2))
44 N: number of interruptions
45 xi: duration of an interrupt
50 The standard deviation calculation is based on:
51 http://en.wikipedia.org/wiki/Standard_deviation
53 Standard_deviation = sqrt(1/N Sum ((xi -Xa)^2))
57 To compute the standard deviation, we need to make two EventRequests to LTTV. In
58 the first EventRequest, we compute the average duration (Xa) and the Number of interruptions (N) of
59 each IrqID. We store the information calculated in the first EventRequest in an array
60 called FirstRequestIrqExit. In the second EventRequest, we compute the Sum ((xi -Xa)^2)
61 and store this information in a array called SumArray. The function CalculateDurationStandardDeviation() uses
62 FirstRequestIrqExit and SumArray arrays to calculate the duration standard deviation.
64 *******************************************************************/
77 #include <ltt/event.h>
79 #include <ltt/trace.h>
80 #include <ltt/facility.h>
81 #include <lttv/module.h>
82 #include <lttv/hook.h>
83 #include <lttv/tracecontext.h>
84 #include <lttv/state.h>
85 #include <lttv/filter.h>
86 #include <lttvwindow/lttvwindow.h>
89 #include "hInterruptsInsert.xpm"
91 #define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
92 #define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format)
105 guint NumerofInterruptions
;
106 LttTime total_duration
;
107 guint average_duration
;
108 IrqDuration max_irq_handler
;
109 IrqDuration min_irq_handler
;
122 guint NumerofInterruptions
;//frequency;//
123 guint64 sumOfDurations
; // to store the Sum ((xi -Xa)^2) of the duration Standard deviation
124 guint64 sumOfPeriods
; // to store the Sum ((xi -Xa)^2) of the period Standard deviation
125 guint64 sumOfFrequencies
;// to store the Sum ((xi -Xa)^2) of the frequency Standard deviation
134 /** Array containing instanced objects. Used when module is unloaded */
135 static GSList
*interrupt_data_list
= NULL
;
138 #define TRACE_NUMBER 0
140 typedef struct _InterruptEventData
{
142 /*Graphical Widgets */
143 GtkWidget
* ScrollWindow
;
144 GtkListStore
*ListStore
;
147 GtkTreeSelection
*SelectionTree
;
149 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(Tab
*tab
);
168 static InterruptEventData
*system_info(Tab
*tab
);
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 NumerofInterruptions
, 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(Tab
* tab
)
235 InterruptEventData
* event_data
= system_info(tab
) ;
237 return event_data
->Hbox
;
243 * This function initializes the Event Viewer functionnality through the
246 InterruptEventData
*system_info(Tab
*tab
)
250 GtkTreeViewColumn
*column
;
251 GtkCellRenderer
*renderer
;
252 InterruptEventData
* event_viewer_data
= g_new(InterruptEventData
,1) ;
254 event_viewer_data
->tab
= tab
;
256 /*Get the current time frame from the main window */
257 event_viewer_data
->time_window
= lttvwindow_get_time_window(tab
);
259 event_viewer_data
->FirstRequestIrqExit
= g_array_new(FALSE
, FALSE
, sizeof(Irq
));
260 event_viewer_data
->FirstRequestIrqEntry
= g_array_new(FALSE
, FALSE
, sizeof(irq_entry
));
262 event_viewer_data
->SecondRequestIrqEntry
= g_array_new(FALSE
, FALSE
, sizeof(irq_entry
));
263 event_viewer_data
->SecondRequestIrqExit
= g_array_new(FALSE
, FALSE
, sizeof(Irq
));
265 event_viewer_data
->SumArray
= g_array_new(FALSE
, FALSE
, sizeof(SumId
));
268 /*Create tha main window for the viewer */
269 event_viewer_data
->ScrollWindow
= gtk_scrolled_window_new (NULL
, NULL
);
270 gtk_widget_show (event_viewer_data
->ScrollWindow
);
271 gtk_scrolled_window_set_policy(
272 GTK_SCROLLED_WINDOW(event_viewer_data
->ScrollWindow
),
273 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
/*GTK_POLICY_NEVER*/);
275 /* Create a model for storing the data list */
276 event_viewer_data
->ListStore
= gtk_list_store_new (
277 N_COLUMNS
, /* Total number of columns */
278 G_TYPE_INT
, /* CPUID */
279 G_TYPE_INT
, /* IRQ_ID */
280 G_TYPE_INT
, /* Frequency */
281 G_TYPE_UINT64
, /* Duration */
282 G_TYPE_INT
, /* standard deviation */
283 G_TYPE_STRING
, /* Max IRQ handler */
284 G_TYPE_STRING
, /* Min IRQ handler */
285 G_TYPE_INT
, /* Average period */
286 G_TYPE_INT
, /* period standard deviation */
287 G_TYPE_INT
/* frequency standard deviation */
291 event_viewer_data
->TreeView
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (event_viewer_data
->ListStore
));
293 g_object_unref (G_OBJECT (event_viewer_data
->ListStore
));
295 renderer
= gtk_cell_renderer_text_new ();
296 column
= gtk_tree_view_column_new_with_attributes ("CPU ID",
298 "text", CPUID_COLUMN
,
300 gtk_tree_view_column_set_alignment (column
, 0.0);
301 gtk_tree_view_column_set_fixed_width (column
, 45);
302 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
305 renderer
= gtk_cell_renderer_text_new ();
306 column
= gtk_tree_view_column_new_with_attributes ("IRQ ID",
308 "text", IRQ_ID_COLUMN
,
310 gtk_tree_view_column_set_alignment (column
, 0.0);
311 gtk_tree_view_column_set_fixed_width (column
, 220);
312 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
314 renderer
= gtk_cell_renderer_text_new ();
315 column
= gtk_tree_view_column_new_with_attributes ("Frequency (Hz)",
317 "text", FREQUENCY_COLUMN
,
319 gtk_tree_view_column_set_alignment (column
, 1.0);
320 gtk_tree_view_column_set_fixed_width (column
, 220);
321 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
323 renderer
= gtk_cell_renderer_text_new ();
324 column
= gtk_tree_view_column_new_with_attributes ("Total Duration (nsec)",
326 "text", DURATION_COLUMN
,
328 gtk_tree_view_column_set_alignment (column
, 0.0);
329 gtk_tree_view_column_set_fixed_width (column
, 145);
330 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
333 renderer
= gtk_cell_renderer_text_new ();
334 column
= gtk_tree_view_column_new_with_attributes ("Duration standard deviation (nsec)",
336 "text", DURATION_STANDARD_DEV_COLUMN
,
338 gtk_tree_view_column_set_alignment (column
, 0.0);
339 gtk_tree_view_column_set_fixed_width (column
, 200);
340 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
342 renderer
= gtk_cell_renderer_text_new ();
343 column
= gtk_tree_view_column_new_with_attributes ("Max IRQ handler duration (nsec) [time interval]",
345 "text", MAX_IRQ_HANDLER_COLUMN
,
347 gtk_tree_view_column_set_alignment (column
, 0.0);
348 gtk_tree_view_column_set_fixed_width (column
, 250);
349 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
351 renderer
= gtk_cell_renderer_text_new ();
352 column
= gtk_tree_view_column_new_with_attributes ("Min IRQ handler duration (nsec) [time interval]",
354 "text", MIN_IRQ_HANDLER_COLUMN
,
356 gtk_tree_view_column_set_alignment (column
, 0.0);
357 gtk_tree_view_column_set_fixed_width (column
, 250);
358 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
360 renderer
= gtk_cell_renderer_text_new ();
361 column
= gtk_tree_view_column_new_with_attributes (" Average period (nsec)",
363 "text", AVERAGE_PERIOD
,
365 gtk_tree_view_column_set_alignment (column
, 0.0);
366 gtk_tree_view_column_set_fixed_width (column
, 200);
367 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
369 renderer
= gtk_cell_renderer_text_new ();
370 column
= gtk_tree_view_column_new_with_attributes ("Period standard deviation (nsec)",
372 "text", PERIOD_STANDARD_DEV_COLUMN
,
374 gtk_tree_view_column_set_alignment (column
, 0.0);
375 gtk_tree_view_column_set_fixed_width (column
, 200);
376 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
378 renderer
= gtk_cell_renderer_text_new ();
379 column
= gtk_tree_view_column_new_with_attributes ("Frequency standard deviation (Hz)",
381 "text", FREQUENCY_STANDARD_DEV_COLUMN
,
383 gtk_tree_view_column_set_alignment (column
, 0.0);
384 gtk_tree_view_column_set_fixed_width (column
, 200);
385 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
388 event_viewer_data
->SelectionTree
= gtk_tree_view_get_selection (GTK_TREE_VIEW (event_viewer_data
->TreeView
));
389 gtk_tree_selection_set_mode (event_viewer_data
->SelectionTree
, GTK_SELECTION_SINGLE
);
391 gtk_container_add (GTK_CONTAINER (event_viewer_data
->ScrollWindow
), event_viewer_data
->TreeView
);
393 event_viewer_data
->Hbox
= gtk_hbox_new(0, 0);
394 gtk_box_pack_start(GTK_BOX(event_viewer_data
->Hbox
), event_viewer_data
->ScrollWindow
, TRUE
, TRUE
, 0);
396 gtk_widget_show(event_viewer_data
->Hbox
);
397 gtk_widget_show(event_viewer_data
->TreeView
);
399 interrupt_data_list
= g_slist_append(interrupt_data_list
, event_viewer_data
);
400 /* Registration for time notification */
401 lttvwindow_register_time_window_notify(tab
,
402 interrupt_update_time_window
,
405 g_object_set_data_full(G_OBJECT(event_viewer_data
->Hbox
),
408 (GDestroyNotify
) InterruptFree
);
410 FirstRequest(event_viewer_data
);
411 return event_viewer_data
;
417 * For each trace in the traceset, this function:
418 * - registers a callback function to each hook
419 * - calls lttv_trace_find_hook() registers a hook function to event_by_id_hooks
420 * - calls lttvwindow_events_request() to request data in a specific
421 * time interval to the main window
424 static void FirstRequest(InterruptEventData
*event_data
)
426 guint i
, k
, l
, nb_trace
;
436 EventsRequest
*events_request
;
438 LttvTraceHookByFacility
*thf
;
440 LttvTracesetContext
*tsc
= lttvwindow_get_traceset_context(event_data
->tab
);
443 /* Get the traceset */
444 LttvTraceset
*traceset
= tsc
->ts
;
446 nb_trace
= lttv_traceset_number(traceset
);
448 /* There are many traces in a traceset. Iteration for each trace. */
449 for(i
= 0; i
<MIN(TRACE_NUMBER
+1, nb_trace
);i
++)
451 events_request
= g_new(EventsRequest
, 1);
453 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
455 hooks
= g_array_set_size(hooks
, 2);
457 event_data
->hooks_trace_before
= lttv_hooks_new();
459 /* Registers a hook function */
460 lttv_hooks_add(event_data
->hooks_trace_before
, trace_header
, event_data
, LTTV_PRIO_DEFAULT
);
462 event_data
->hooks_trace_after
= lttv_hooks_new();
464 /* Registers a hook function */
465 lttv_hooks_add(event_data
->hooks_trace_after
, SecondRequest
, event_data
, LTTV_PRIO_DEFAULT
);
466 /* Get a trace state */
467 ts
= (LttvTraceState
*)tsc
->traces
[i
];
468 /* Create event_by_Id hooks */
469 event_data
->event_by_id_hooks
= lttv_hooks_by_id_new();
471 /*Register event_by_id_hooks with a callback function*/
472 ret
= lttv_trace_find_hook(ts
->parent
.t
,
473 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
474 LTT_FIELD_IRQ_ID
, 0, 0,
475 FirstRequestIrqEntryCallback
,
477 &g_array_index(hooks
, LttvTraceHook
, 0));
479 ret
= lttv_trace_find_hook(ts
->parent
.t
,
480 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
481 LTT_FIELD_IRQ_ID
, 0, 0,
482 FirstRequestIrqExitCallback
,
484 &g_array_index(hooks
, LttvTraceHook
, 1));
487 /*iterate through the facility list*/
488 for(k
= 0 ; k
< hooks
->len
; k
++)
490 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
491 for(l
=0; l
<hook
->fac_list
->len
; l
++)
493 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
494 lttv_hooks_add(lttv_hooks_by_id_find(event_data
->event_by_id_hooks
, thf
->id
),
501 /* Initalize the EventsRequest structure */
502 events_request
->owner
= event_data
;
503 events_request
->viewer_data
= event_data
;
504 events_request
->servicing
= FALSE
;
505 events_request
->start_time
= event_data
->time_window
.start_time
;
506 events_request
->start_position
= NULL
;
507 events_request
->stop_flag
= FALSE
;
508 events_request
->end_time
= event_data
->time_window
.end_time
;
509 events_request
->num_events
= G_MAXUINT
;
510 events_request
->end_position
= NULL
;
511 events_request
->trace
= i
;
513 events_request
->hooks
= hooks
;
515 events_request
->before_chunk_traceset
= NULL
;
516 events_request
->before_chunk_trace
= event_data
->hooks_trace_before
;
517 events_request
->before_chunk_tracefile
= NULL
;
518 events_request
->event
= NULL
;
519 events_request
->event_by_id
= event_data
->event_by_id_hooks
;
520 events_request
->after_chunk_tracefile
= NULL
;
521 events_request
->after_chunk_trace
= NULL
;
522 events_request
->after_chunk_traceset
= NULL
;
523 events_request
->before_request
= NULL
;
524 events_request
->after_request
= event_data
->hooks_trace_after
;
526 lttvwindow_events_request(event_data
->tab
, events_request
);
532 * This function is called whenever an irq_entry event occurs.
535 static gboolean
FirstRequestIrqEntryCallback(void *hook_data
, void *call_data
)
541 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
542 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
543 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
544 GArray
* FirstRequestIrqEntry
= event_data
->FirstRequestIrqEntry
;
545 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
546 event_time
= ltt_event_time(e
);
547 cpu_id
= ltt_event_cpu_id(e
);
550 entry
.id
=get_interrupt_id(e
);
551 entry
.cpu_id
= cpu_id
;
552 entry
.event_time
= event_time
;
553 g_array_append_val (FirstRequestIrqEntry
, entry
);
559 * This function gets the id of the interrupt. The id is stored in a dynamic structure.
560 * Refer to the print.c file for how to extract data from a dynamic structure.
562 static guint64
get_interrupt_id(LttEvent
*e
)
565 LttEventType
*event_type
;
569 event_type
= ltt_event_eventtype(e
);
570 num_fields
= ltt_eventtype_num_fields(event_type
);
571 for(i
= 0 ; i
< num_fields
-1 ; i
++)
573 field
= ltt_eventtype_field(event_type
, i
);
574 irq_id
= ltt_event_get_long_unsigned(e
,field
);
580 * This function is called whenever an irq_exit event occurs.
583 gboolean
FirstRequestIrqExitCallback(void *hook_data
, void *call_data
)
587 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
588 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
589 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
590 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
591 LttEventType
*type
= ltt_event_eventtype(e
);
592 event_time
= ltt_event_time(e
);
593 cpu_id
= ltt_event_cpu_id(e
);
595 CalculateData( event_time
, cpu_id
, event_data
);
601 * This function calculates the duration of an interrupt.
604 static void CalculateData(LttTime time_exit
, guint cpu_id
,InterruptEventData
*event_data
)
610 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
611 GArray
*FirstRequestIrqEntry
= event_data
->FirstRequestIrqEntry
;
612 for(i
= 0; i
< FirstRequestIrqEntry
->len
; i
++)
614 element
= &g_array_index(FirstRequestIrqEntry
,irq_entry
,i
);
615 if(element
->cpu_id
== cpu_id
)
617 CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(element
,time_exit
, FirstRequestIrqExit
);
618 g_array_remove_index(FirstRequestIrqEntry
, i
);
626 * This function calculates the total duration of an interrupt and the longest & shortest Irq handlers.
629 static void CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(irq_entry
*e
, LttTime time_exit
, GArray
*FirstRequestIrqExit
)
635 gboolean notFound
= FALSE
;
636 memset ((void*)&irq
, 0,sizeof(Irq
));
639 if(FirstRequestIrqExit
->len
== NO_ITEMS
)
641 irq
.cpu_id
= e
->cpu_id
;
643 irq
.NumerofInterruptions
++;
644 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
646 irq
.max_irq_handler
.start_time
= e
->event_time
;
647 irq
.max_irq_handler
.end_time
= time_exit
;
648 irq
.max_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
650 irq
.min_irq_handler
.start_time
= e
->event_time
;
651 irq
.min_irq_handler
.end_time
= time_exit
;
652 irq
.min_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
654 g_array_append_val (FirstRequestIrqExit
, irq
);
658 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
660 element
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
661 if(element
->id
== e
->id
)
664 duration
= ltt_time_sub(time_exit
, e
->event_time
);
665 element
->total_duration
= ltt_time_add(element
->total_duration
, duration
);
666 element
->NumerofInterruptions
++;
668 if(ltt_time_compare(duration
,element
->max_irq_handler
.duration
) > 0)
670 element
->max_irq_handler
.duration
= duration
;
671 element
->max_irq_handler
.start_time
= e
->event_time
;
672 element
->max_irq_handler
.end_time
= time_exit
;
675 if(ltt_time_compare(duration
,element
->min_irq_handler
.duration
) < 0)
677 element
->min_irq_handler
.duration
= duration
;
678 element
->min_irq_handler
.start_time
= e
->event_time
;
679 element
->min_irq_handler
.end_time
= time_exit
;
685 irq
.cpu_id
= e
->cpu_id
;
687 irq
.NumerofInterruptions
++;
688 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
690 irq
.max_irq_handler
.start_time
= e
->event_time
;
691 irq
.max_irq_handler
.end_time
= time_exit
;
692 irq
.max_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
694 irq
.min_irq_handler
.start_time
= e
->event_time
;
695 irq
.min_irq_handler
.end_time
= time_exit
;
696 irq
.min_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
698 g_array_append_val (FirstRequestIrqExit
, irq
);
704 * This function passes the second EventsRequest to LTTV
707 static gboolean
SecondRequest(void *hook_data
, void *call_data
)
710 guint i
, k
, l
, nb_trace
;
720 EventsRequest
*events_request
;
722 LttvTraceHookByFacility
*thf
;
724 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
726 LttvTracesetContext
*tsc
= lttvwindow_get_traceset_context(event_data
->tab
);
728 CalculateAverageDurationForEachIrqId(event_data
);
730 /* Get the traceset */
731 LttvTraceset
*traceset
= tsc
->ts
;
733 nb_trace
= lttv_traceset_number(traceset
);
735 /* There are many traces in a traceset. Iteration for each trace. */
736 for(i
= 0; i
<MIN(TRACE_NUMBER
+1, nb_trace
);i
++)
738 events_request
= g_new(EventsRequest
, 1);
740 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
742 hooks
= g_array_set_size(hooks
, 2);
744 event_data
->hooks_trace_after
= lttv_hooks_new();
746 /* Registers a hook function */
747 lttv_hooks_add(event_data
->hooks_trace_after
, DisplayViewer
, event_data
, LTTV_PRIO_DEFAULT
);
749 /* Get a trace state */
750 ts
= (LttvTraceState
*)tsc
->traces
[i
];
751 /* Create event_by_Id hooks */
752 event_data
->event_by_id_hooks
= lttv_hooks_by_id_new();
754 /*Register event_by_id_hooks with a callback function*/
755 ret
= lttv_trace_find_hook(ts
->parent
.t
,
756 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
757 LTT_FIELD_IRQ_ID
, 0, 0,
758 SecondRequestIrqEntryCallback
,
760 &g_array_index(hooks
, LttvTraceHook
, 0));
762 ret
= lttv_trace_find_hook(ts
->parent
.t
,
763 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
764 LTT_FIELD_IRQ_ID
, 0, 0,
765 SecondRequestIrqExitCallback
,
767 &g_array_index(hooks
, LttvTraceHook
, 1));
771 /* iterate through the facility list */
772 for(k
= 0 ; k
< hooks
->len
; k
++)
774 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
775 for(l
=0; l
<hook
->fac_list
->len
; l
++)
777 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
778 lttv_hooks_add(lttv_hooks_by_id_find(event_data
->event_by_id_hooks
, thf
->id
),
785 /* Initalize the EventsRequest structure */
786 events_request
->owner
= event_data
;
787 events_request
->viewer_data
= event_data
;
788 events_request
->servicing
= FALSE
;
789 events_request
->start_time
= event_data
->time_window
.start_time
;
790 events_request
->start_position
= NULL
;
791 events_request
->stop_flag
= FALSE
;
792 events_request
->end_time
= event_data
->time_window
.end_time
;
793 events_request
->num_events
= G_MAXUINT
;
794 events_request
->end_position
= NULL
;
795 events_request
->trace
= i
;
797 events_request
->hooks
= hooks
;
799 events_request
->before_chunk_traceset
= NULL
;
800 events_request
->before_chunk_trace
= NULL
;
801 events_request
->before_chunk_tracefile
= NULL
;
802 events_request
->event
= NULL
;
803 events_request
->event_by_id
= event_data
->event_by_id_hooks
;
804 events_request
->after_chunk_tracefile
= NULL
;
805 events_request
->after_chunk_trace
= NULL
;
806 events_request
->after_chunk_traceset
= NULL
;
807 events_request
->before_request
= NULL
;
808 events_request
->after_request
= event_data
->hooks_trace_after
;
810 lttvwindow_events_request(event_data
->tab
, events_request
);
816 * This function calculates the average duration for each Irq Id
819 static void CalculateAverageDurationForEachIrqId(InterruptEventData
*event_data
)
824 GArray
* FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
825 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
827 element
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
828 real_data
= element
->total_duration
.tv_sec
;
829 real_data
*= NANOSECONDS_PER_SECOND
;
830 real_data
+= element
->total_duration
.tv_nsec
;
831 if(element
->NumerofInterruptions
!= 0)
832 element
->average_duration
= real_data
/ element
->NumerofInterruptions
;
834 element
->average_duration
= 0;
840 * This function is called whenever an irq_entry event occurs. Use in the second request
843 static gboolean
SecondRequestIrqEntryCallback(void *hook_data
, void *call_data
)
849 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
850 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
851 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
852 GArray
* SecondRequestIrqEntry
= event_data
->SecondRequestIrqEntry
;
853 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
854 event_time
= ltt_event_time(e
);
855 cpu_id
= ltt_event_cpu_id(e
);
858 entry
.id
=get_interrupt_id(e
);
859 entry
.cpu_id
= cpu_id
;
860 entry
.event_time
= event_time
;
861 g_array_append_val (SecondRequestIrqEntry
, entry
);
867 * This function is called whenever an irq_exit event occurs in the second request.
870 static gboolean
SecondRequestIrqExitCallback(void *hook_data
, void *call_data
)
873 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
874 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
875 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
876 LttEvent
*event
= ltt_tracefile_get_event(tfc
->tf
);
878 CalculateXi(event
, event_data
);
884 * This function is called whenever an irq_exit event occurs in the second request.
887 static void CalculateXi(LttEvent
*event_irq_exit
, InterruptEventData
*event_data
)
895 GArray
*SecondRequestIrqExit
= event_data
->SecondRequestIrqExit
;
896 GArray
*SecondRequestIrqEntry
= event_data
->SecondRequestIrqEntry
;
897 cpu_id
= ltt_event_cpu_id(event_irq_exit
);
898 for(i
= 0; i
< SecondRequestIrqEntry
->len
; i
++)
900 element
= &g_array_index(SecondRequestIrqEntry
,irq_entry
,i
);
901 if(element
->cpu_id
== cpu_id
)
904 /* time calculation */
905 exit_time
= ltt_event_time(event_irq_exit
);
906 Xi
= ltt_time_sub(exit_time
, element
->event_time
);
907 irq_id
= element
->id
;
909 SumItems(irq_id
, Xi
,event_data
);
910 g_array_remove_index(SecondRequestIrqEntry
, i
);
918 * This function computes the Sum ((xi -Xa)^2) and store the result in SumArray
921 static void SumItems(gint irq_id
, LttTime Xi
, InterruptEventData
*event_data
)
926 gint duration_inner_part
;
927 guint64 period_inner_part
;
928 guint64 frequency_inner_part
;
934 gboolean notFound
= FALSE
;
935 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
936 GArray
*SumArray
= event_data
->SumArray
;
937 Xi_in_ns
= Xi
.tv_sec
;
938 Xi_in_ns
*= NANOSECONDS_PER_SECOND
;
939 Xi_in_ns
+= Xi
.tv_nsec
;
941 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
943 average
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
944 if(irq_id
== average
->id
)
946 duration_inner_part
= Xi_in_ns
- average
->average_duration
;
947 FrequencyHZ
= FrequencyInHZ(average
->NumerofInterruptions
, event_data
->time_window
);
949 // compute (xi -Xa)^2 of the duration Standard deviation
950 sum
.NumerofInterruptions
= average
->NumerofInterruptions
;
951 sum
.sumOfDurations
= pow (duration_inner_part
, 2);
953 // compute (xi -Xa)^2 of the period Standard deviation
954 period_inner_part
= CalculatePeriodInnerPart(Xi_in_ns
, FrequencyHZ
);
956 // compute (xi -Xa)^2 of the frequency Standard deviation
957 frequency_inner_part
= CalculateFrequencyInnerPart(Xi_in_ns
, FrequencyHZ
);
959 sum
.sumOfPeriods
= period_inner_part
;
961 sum
.sumOfFrequencies
= frequency_inner_part
;
963 if(event_data
->SumArray
->len
== NO_ITEMS
)
965 g_array_append_val (SumArray
, sum
);
969 for(i
= 0; i
< SumArray
->len
; i
++)
971 sumItem
= &g_array_index(SumArray
, SumId
, i
);
972 if(sumItem
->irqId
== irq_id
)
975 sumItem
->sumOfDurations
+= sum
.sumOfDurations
;
976 sumItem
->sumOfPeriods
+= sum
.sumOfPeriods
;
977 sumItem
->sumOfFrequencies
+= sum
.sumOfFrequencies
;
982 g_array_append_val (SumArray
, sum
);
992 * This function computes the inner part of the period standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
993 * The inner part is: (xi -Xa)^2
995 static guint64
CalculatePeriodInnerPart(guint Xi
, guint FrequencyHZ
)
998 double periodInSec
; /*period in sec*/
1002 periodInSec
= (double)1/FrequencyHZ
;
1003 periodInSec
*= NANOSECONDS_PER_SECOND
;
1004 periodInNSec
= (int)periodInSec
;
1006 difference
= Xi
- periodInNSec
;
1007 result
= pow (difference
, 2);
1012 * This function computes the inner part of the frequency standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1013 * The inner part is: (xi -Xa)^2
1015 static guint64
CalculateFrequencyInnerPart(guint Xi_in_ns
, guint FrequencyHZ
)
1020 difference
= Xi_in_ns
- FrequencyHZ
;
1021 result
= pow (difference
, 2);
1025 * This function displays the result on the viewer
1028 static gboolean
DisplayViewer(void *hook_data
, void *call_data
)
1034 LttTime average_duration
;
1037 guint maxIRQduration
;
1038 guint minIRQduration
;
1041 char maxIrqHandler
[80];
1042 char minIrqHandler
[80];
1043 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
1044 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
1045 int FrequencyHZ
= 0;
1047 gtk_list_store_clear(event_data
->ListStore
);
1048 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
1050 element
= g_array_index(FirstRequestIrqExit
,Irq
,i
);
1051 real_data
= element
.total_duration
.tv_sec
;
1052 real_data
*= NANOSECONDS_PER_SECOND
;
1053 real_data
+= element
.total_duration
.tv_nsec
;
1056 maxIRQduration
= element
.max_irq_handler
.duration
.tv_sec
;
1057 maxIRQduration
*= NANOSECONDS_PER_SECOND
;
1058 maxIRQduration
+= element
.max_irq_handler
.duration
.tv_nsec
;
1060 sprintf(maxIrqHandler
, "%d [%d.%d - %d.%d]",maxIRQduration
, element
.max_irq_handler
.start_time
.tv_sec
, \
1061 element
.max_irq_handler
.start_time
.tv_nsec
, element
.max_irq_handler
.end_time
.tv_sec
, \
1062 element
.max_irq_handler
.end_time
.tv_nsec
) ;
1064 minIRQduration
= element
.min_irq_handler
.duration
.tv_sec
;
1065 minIRQduration
*= NANOSECONDS_PER_SECOND
;
1066 minIRQduration
+= element
.min_irq_handler
.duration
.tv_nsec
;
1067 sprintf(minIrqHandler
, "%d [%d.%d - %d.%d]",minIRQduration
, element
.min_irq_handler
.start_time
.tv_sec
, \
1068 element
.min_irq_handler
.start_time
.tv_nsec
, element
.min_irq_handler
.end_time
.tv_sec
, \
1069 element
.min_irq_handler
.end_time
.tv_nsec
) ;
1072 FrequencyHZ
= FrequencyInHZ(element
.NumerofInterruptions
,event_data
->time_window
);
1074 if(FrequencyHZ
!= 0)
1076 periodInSec
= (double)1/FrequencyHZ
;
1077 periodInSec
*= NANOSECONDS_PER_SECOND
;
1078 periodInNsec
= (int)periodInSec
;
1082 gtk_list_store_append (event_data
->ListStore
, &iter
);
1083 gtk_list_store_set (event_data
->ListStore
, &iter
,
1084 CPUID_COLUMN
, element
.cpu_id
,
1085 IRQ_ID_COLUMN
, element
.id
,
1086 FREQUENCY_COLUMN
, FrequencyHZ
,
1087 DURATION_COLUMN
, real_data
,
1088 DURATION_STANDARD_DEV_COLUMN
, CalculateDurationStandardDeviation(element
.id
, event_data
),
1089 MAX_IRQ_HANDLER_COLUMN
, maxIrqHandler
,
1090 MIN_IRQ_HANDLER_COLUMN
, minIrqHandler
,
1091 AVERAGE_PERIOD
, periodInNsec
,
1092 PERIOD_STANDARD_DEV_COLUMN
, CalculatePeriodStandardDeviation(element
.id
, event_data
),
1093 FREQUENCY_STANDARD_DEV_COLUMN
, CalculateFrequencyStandardDeviation(element
.id
, event_data
),
1100 if(event_data
->FirstRequestIrqExit
->len
)
1102 g_array_remove_range (event_data
->FirstRequestIrqExit
,0,event_data
->FirstRequestIrqExit
->len
);
1105 if(event_data
->FirstRequestIrqEntry
->len
)
1107 g_array_remove_range (event_data
->FirstRequestIrqEntry
,0,event_data
->FirstRequestIrqEntry
->len
);
1110 if(event_data
->SecondRequestIrqEntry
->len
)
1112 g_array_remove_range (event_data
->SecondRequestIrqEntry
,0,event_data
->SecondRequestIrqEntry
->len
);
1115 if(event_data
->SecondRequestIrqExit
->len
)
1117 g_array_remove_range (event_data
->SecondRequestIrqExit
,0, event_data
->SecondRequestIrqExit
->len
);
1120 if(event_data
->SumArray
->len
)
1122 g_array_remove_range (event_data
->SumArray
,0, event_data
->SumArray
->len
);
1130 * This function converts the number of interrupts over a time window to
1133 static int FrequencyInHZ(gint NumerofInterruptions
, TimeWindow time_window
)
1135 guint64 frequencyHz
= 0;
1136 double timeSec
; // time in second
1138 result
= ltt_time_to_double(time_window
.time_width
);
1139 timeSec
= (result
/NANOSECONDS_PER_SECOND
); //time in second
1140 frequencyHz
= NumerofInterruptions
/ timeSec
;
1145 * This function calculates the duration standard deviation
1146 * Duration standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1148 * sumId.sumOfDurations -> Sum ((xi -Xa)^2)
1149 * inner_component -> 1/N Sum ((xi -Xa)^2)
1150 * deviation-> sqrt(1/N Sum ((xi -Xa)^2))
1152 static int CalculateDurationStandardDeviation(gint id
, InterruptEventData
*event_data
)
1156 double inner_component
;
1158 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
1160 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
1161 if(id
== sumId
.irqId
)
1163 if(sumId
.NumerofInterruptions
!= 0)
1164 inner_component
= sumId
.sumOfDurations
/ sumId
.NumerofInterruptions
;
1166 inner_component
= 0.0;
1167 deviation
= sqrt(inner_component
);
1176 * This function calculates the period standard deviation
1177 * Period standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1179 * sumId.sumOfPeriods -> Sum ((xi -Xa)^2)
1180 * inner_component -> 1/N Sum ((xi -Xa)^2)
1181 * period_standard_deviation-> sqrt(1/N Sum ((xi -Xa)^2))
1185 static int CalculatePeriodStandardDeviation(gint id
, InterruptEventData
*event_data
)
1189 guint64 inner_component
;
1190 guint64 period_standard_deviation
= 0;
1192 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
1194 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
1195 if(id
== sumId
.irqId
)
1197 if(sumId
.NumerofInterruptions
!= 0)
1198 inner_component
= sumId
.sumOfPeriods
/ sumId
.NumerofInterruptions
;
1200 inner_component
= 0;
1202 period_standard_deviation
= sqrt(inner_component
);
1206 return period_standard_deviation
;
1210 * This function calculates the frequency standard deviation
1211 * Frequency standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1213 * sumId.sumOfFrequencies -> Sum ((xi -Xa)^2)
1214 * inner_component -> 1/N Sum ((xi -Xa)^2)
1215 * frequency_standard_deviation-> sqrt(1/N Sum ((xi -Xa)^2))
1218 static int CalculateFrequencyStandardDeviation(gint id
, InterruptEventData
*event_data
)
1222 guint64 inner_component
;
1223 guint64 frequency_standard_deviation
= 0;
1224 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
1226 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
1227 if(id
== sumId
.irqId
)
1229 if(sumId
.NumerofInterruptions
!= 0)
1230 inner_component
= sumId
.sumOfFrequencies
/ sumId
.NumerofInterruptions
;
1232 inner_component
= 0;
1234 frequency_standard_deviation
= sqrt(inner_component
);
1237 return frequency_standard_deviation
;
1241 * This function is called by the main window
1242 * when the time interval needs to be updated.
1244 gboolean
interrupt_update_time_window(void * hook_data
, void * call_data
)
1246 InterruptEventData
*event_data
= (InterruptEventData
*) hook_data
;
1247 const TimeWindowNotifyData
*time_window_nofify_data
= ((const TimeWindowNotifyData
*)call_data
);
1248 event_data
->time_window
= *time_window_nofify_data
->new_time_window
;
1249 g_info("interrupts: interrupt_update_time_window()\n");
1250 Tab
*tab
= event_data
->tab
;
1251 lttvwindow_events_request_remove_all(tab
, event_data
);
1252 FirstRequest(event_data
);
1257 gboolean
trace_header(void *hook_data
, void *call_data
)
1260 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
1261 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1267 void interrupt_destroy_walk(gpointer data
, gpointer user_data
)
1269 g_info("interrupt_destroy_walk");
1270 InterruptEventData
*event_data
= (InterruptEventData
*) data
;
1271 interrupt_destructor((InterruptEventData
*)data
);
1275 void interrupt_destructor(InterruptEventData
*event_viewer_data
)
1277 /* May already been done by GTK window closing */
1278 g_info("enter interrupt_destructor \n");
1279 if(GTK_IS_WIDGET(event_viewer_data
->Hbox
))
1281 gtk_widget_destroy(event_viewer_data
->Hbox
);
1286 This function is called when the viewer is destroyed to free hooks and memory
1288 static void InterruptFree(InterruptEventData
*event_viewer_data
)
1290 Tab
*tab
= event_viewer_data
->tab
;
1294 g_array_free(event_viewer_data
->FirstRequestIrqExit
, TRUE
);
1295 g_array_free(event_viewer_data
->FirstRequestIrqEntry
, TRUE
);
1296 g_array_free(event_viewer_data
->SecondRequestIrqEntry
, TRUE
);
1297 g_array_free(event_viewer_data
->SecondRequestIrqExit
, TRUE
);
1298 g_array_free(event_viewer_data
->SumArray
, TRUE
);
1300 lttvwindow_unregister_time_window_notify(tab
, interrupt_update_time_window
, event_viewer_data
);
1302 lttvwindow_events_request_remove_all(event_viewer_data
->tab
,
1305 interrupt_data_list
= g_slist_remove(interrupt_data_list
, event_viewer_data
);
1312 * plugin's destroy function
1314 * This function releases the memory reserved by the module and unregisters
1315 * everything that has been registered in the gtkTraceSet API.
1317 static void destroy()
1320 g_info("Destroy interrupts");
1321 g_slist_foreach(interrupt_data_list
, interrupt_destroy_walk
, NULL
);
1322 g_slist_free(interrupt_data_list
);
1323 lttvwindow_unregister_constructor(interrupts
);
1327 LTTV_MODULE("interrupts", "interrupts info view", \
1328 "Graphical module to display interrupts performance", \
1329 init
, destroy
, "lttvwindow")