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 EventRequests to LTTV. In
58 the first EventRequest, we compute the average duration (Xa) and the
59 Number of interruptions (N) of each IrqID. We store the information calculated in the first
60 EventRequest in an array called FirstRequestIrqExit.
61 In the second EventRequest, we compute the Sum ((xi -Xa)^2) and store this information
62 in a array called SumArray. The function CalculateDurationStandardDeviation() uses FirstRequestIrqExit
63 and SumArray arrays to calculate the standard deviation.
67 *******************************************************************/
80 #include <ltt/event.h>
82 #include <ltt/trace.h>
83 #include <ltt/facility.h>
84 #include <lttv/module.h>
85 #include <lttv/hook.h>
86 #include <lttv/tracecontext.h>
87 #include <lttv/state.h>
88 #include <lttv/filter.h>
89 #include <lttvwindow/lttvwindow.h>
92 #include "hInterruptsInsert.xpm"
94 #define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
95 #define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format)
108 guint NumerofInterruptions
;
109 LttTime total_duration
;
110 guint average_duration
;
111 IrqDuration max_irq_handler
;
112 IrqDuration min_irq_handler
;
125 guint NumerofInterruptions
;//frequency;//
126 guint64 sumOfDurations
; // to store the Sum ((xi -Xa)^2) of the duration Standard deviation
127 guint64 sumOfPeriods
; // to store the Sum ((xi -Xa)^2) of the period Standard deviation
128 guint64 sumOfFrequencies
;// to store the Sum ((xi -Xa)^2) of the frequency Standard deviation
137 /** Array containing instanced objects. Used when module is unloaded */
138 static GSList
*interrupt_data_list
= NULL
;
141 #define TRACE_NUMBER 0
143 typedef struct _InterruptEventData
{
145 /*Graphical Widgets */
146 GtkWidget
* ScrollWindow
;
147 GtkListStore
*ListStore
;
150 GtkTreeSelection
*SelectionTree
;
152 Tab
* tab
; /* tab that contains this plug-in*/
153 LttvHooks
* event_hooks
;
154 LttvHooks
* hooks_trace_after
;
155 LttvHooks
* hooks_trace_before
;
156 TimeWindow time_window
;
157 LttvHooksById
* event_by_id_hooks
;
158 GArray
*FirstRequestIrqExit
;
159 GArray
*FirstRequestIrqEntry
;
160 GArray
*SecondRequestIrqEntry
;
161 GArray
*SecondRequestIrqExit
;
164 } InterruptEventData
;
167 /* Function prototypes */
169 static gboolean
interrupt_update_time_window(void * hook_data
, void * call_data
);
170 static GtkWidget
*interrupts(Tab
*tab
);
171 static InterruptEventData
*system_info(Tab
*tab
);
172 void interrupt_destructor(InterruptEventData
*event_viewer_data
);
173 static void FirstRequest(InterruptEventData
*event_data
);
174 static guint64
get_interrupt_id(LttEvent
*e
);
175 static gboolean
trace_header(void *hook_data
, void *call_data
);
176 static gboolean
DisplayViewer (void *hook_data
, void *call_data
);
177 static void CalculateData(LttTime time_exit
, guint cpu_id
, InterruptEventData
*event_data
);
178 static void CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(irq_entry
*e
, LttTime time_exit
, GArray
*FirstRequestIrqExit
);
179 static gboolean
FirstRequestIrqEntryCallback(void *hook_data
, void *call_data
);
180 static gboolean
FirstRequestIrqExitCallback(void *hook_data
, void *call_data
);
181 static gboolean
SecondRequest(void *hook_data
, void *call_data
);
182 static void CalculateAverageDurationForEachIrqId(InterruptEventData
*event_data
);
183 static gboolean
SecondRequestIrqEntryCallback(void *hook_data
, void *call_data
);
184 static gboolean
SecondRequestIrqExitCallback(void *hook_data
, void *call_data
);
185 static void CalculateXi(LttEvent
*event
, InterruptEventData
*event_data
);
186 static void SumItems(gint irq_id
, LttTime Xi
, InterruptEventData
*event_data
);
187 static int CalculateDurationStandardDeviation(gint id
, InterruptEventData
*event_data
);
188 static int CalculatePeriodStandardDeviation(gint id
, InterruptEventData
*event_data
);
189 static int FrequencyInHZ(gint NumerofInterruptions
, TimeWindow time_window
);
190 static guint64
CalculatePeriodInnerPart(guint Xi
, guint FrequencyHZ
);
191 static guint64
CalculateFrequencyInnerPart(guint Xi_in_ns
, guint FrequencyHZ
);
192 static void InterruptFree(InterruptEventData
*event_viewer_data
);
193 static int CalculateFrequencyStandardDeviation(gint id
, InterruptEventData
*event_data
);
195 /* Enumeration of the columns */
201 DURATION_STANDARD_DEV_COLUMN
,
202 MAX_IRQ_HANDLER_COLUMN
,
204 PERIOD_STANDARD_DEV_COLUMN
,
205 FREQUENCY_STANDARD_DEV_COLUMN
,
215 * This is the entry point of the viewer.
219 g_info("interrupts: init()");
220 lttvwindow_register_constructor("interrupts",
222 "Insert Interrupts View",
223 hInterruptsInsert_xpm
,
224 "Insert Interrupts View",
234 static GtkWidget
*interrupts(Tab
* tab
)
237 InterruptEventData
* event_data
= system_info(tab
) ;
239 return event_data
->Hbox
;
245 * This function initializes the Event Viewer functionnality through the
248 InterruptEventData
*system_info(Tab
*tab
)
252 GtkTreeViewColumn
*column
;
253 GtkCellRenderer
*renderer
;
254 InterruptEventData
* event_viewer_data
= g_new(InterruptEventData
,1) ;
256 event_viewer_data
->tab
= tab
;
258 /*Get the current time frame from the main window */
259 event_viewer_data
->time_window
= lttvwindow_get_time_window(tab
);
261 event_viewer_data
->FirstRequestIrqExit
= g_array_new(FALSE
, FALSE
, sizeof(Irq
));
262 event_viewer_data
->FirstRequestIrqEntry
= g_array_new(FALSE
, FALSE
, sizeof(irq_entry
));
264 event_viewer_data
->SecondRequestIrqEntry
= g_array_new(FALSE
, FALSE
, sizeof(irq_entry
));
265 event_viewer_data
->SecondRequestIrqExit
= g_array_new(FALSE
, FALSE
, sizeof(Irq
));
267 event_viewer_data
->SumArray
= g_array_new(FALSE
, FALSE
, sizeof(SumId
));
270 /*Create tha main window for the viewer */
271 event_viewer_data
->ScrollWindow
= gtk_scrolled_window_new (NULL
, NULL
);
272 gtk_widget_show (event_viewer_data
->ScrollWindow
);
273 gtk_scrolled_window_set_policy(
274 GTK_SCROLLED_WINDOW(event_viewer_data
->ScrollWindow
),
275 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
/*GTK_POLICY_NEVER*/);
277 /* Create a model for storing the data list */
278 event_viewer_data
->ListStore
= gtk_list_store_new (
279 N_COLUMNS
, /* Total number of columns */
280 G_TYPE_INT
, /* CPUID */
281 G_TYPE_INT
, /* IRQ_ID */
282 G_TYPE_INT
, /* Frequency */
283 G_TYPE_UINT64
, /* Duration */
284 G_TYPE_INT
, /* standard deviation */
285 G_TYPE_STRING
, /* Max 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 (" Average period (nsec)",
355 "text", AVERAGE_PERIOD
,
357 gtk_tree_view_column_set_alignment (column
, 0.0);
358 gtk_tree_view_column_set_fixed_width (column
, 200);
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 ("Period standard deviation (nsec)",
364 "text", PERIOD_STANDARD_DEV_COLUMN
,
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 ("Frequency standard deviation (Hz)",
373 "text", FREQUENCY_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
);
380 event_viewer_data
->SelectionTree
= gtk_tree_view_get_selection (GTK_TREE_VIEW (event_viewer_data
->TreeView
));
381 gtk_tree_selection_set_mode (event_viewer_data
->SelectionTree
, GTK_SELECTION_SINGLE
);
383 gtk_container_add (GTK_CONTAINER (event_viewer_data
->ScrollWindow
), event_viewer_data
->TreeView
);
385 event_viewer_data
->Hbox
= gtk_hbox_new(0, 0);
386 gtk_box_pack_start(GTK_BOX(event_viewer_data
->Hbox
), event_viewer_data
->ScrollWindow
, TRUE
, TRUE
, 0);
388 gtk_widget_show(event_viewer_data
->Hbox
);
389 gtk_widget_show(event_viewer_data
->TreeView
);
391 interrupt_data_list
= g_slist_append(interrupt_data_list
, event_viewer_data
);
392 /* Registration for time notification */
393 lttvwindow_register_time_window_notify(tab
,
394 interrupt_update_time_window
,
397 g_object_set_data_full(G_OBJECT(event_viewer_data
->Hbox
),
400 (GDestroyNotify
) InterruptFree
);
402 FirstRequest(event_viewer_data
);
403 return event_viewer_data
;
409 * For each trace in the traceset, this function:
410 * - registers a callback function to each hook
411 * - calls lttv_trace_find_hook() registers a hook function to event_by_id_hooks
412 * - calls lttvwindow_events_request() to request data in a specific
413 * time interval to the main window
416 static void FirstRequest(InterruptEventData
*event_data
)
418 guint i
, k
, l
, nb_trace
;
428 EventsRequest
*events_request
;
430 LttvTraceHookByFacility
*thf
;
432 LttvTracesetContext
*tsc
= lttvwindow_get_traceset_context(event_data
->tab
);
435 /* Get the traceset */
436 LttvTraceset
*traceset
= tsc
->ts
;
438 nb_trace
= lttv_traceset_number(traceset
);
440 /* There are many traces in a traceset. Iteration for each trace. */
441 for(i
= 0; i
<MIN(TRACE_NUMBER
+1, nb_trace
);i
++)
443 events_request
= g_new(EventsRequest
, 1);
445 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
447 hooks
= g_array_set_size(hooks
, 2);
449 event_data
->hooks_trace_before
= lttv_hooks_new();
451 /* Registers a hook function */
452 lttv_hooks_add(event_data
->hooks_trace_before
, trace_header
, event_data
, LTTV_PRIO_DEFAULT
);
454 event_data
->hooks_trace_after
= lttv_hooks_new();
456 /* Registers a hook function */
457 lttv_hooks_add(event_data
->hooks_trace_after
, SecondRequest
, event_data
, LTTV_PRIO_DEFAULT
);
458 /* Get a trace state */
459 ts
= (LttvTraceState
*)tsc
->traces
[i
];
460 /* Create event_by_Id hooks */
461 event_data
->event_by_id_hooks
= lttv_hooks_by_id_new();
463 /*Register event_by_id_hooks with a callback function*/
464 ret
= lttv_trace_find_hook(ts
->parent
.t
,
465 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
466 LTT_FIELD_IRQ_ID
, 0, 0,
467 FirstRequestIrqEntryCallback
,
469 &g_array_index(hooks
, LttvTraceHook
, 0));
471 ret
= lttv_trace_find_hook(ts
->parent
.t
,
472 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
473 LTT_FIELD_IRQ_ID
, 0, 0,
474 FirstRequestIrqExitCallback
,
476 &g_array_index(hooks
, LttvTraceHook
, 1));
479 /*iterate through the facility list*/
480 for(k
= 0 ; k
< hooks
->len
; k
++)
482 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
483 for(l
=0; l
<hook
->fac_list
->len
; l
++)
485 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
486 lttv_hooks_add(lttv_hooks_by_id_find(event_data
->event_by_id_hooks
, thf
->id
),
493 /* Initalize the EventsRequest structure */
494 events_request
->owner
= event_data
;
495 events_request
->viewer_data
= event_data
;
496 events_request
->servicing
= FALSE
;
497 events_request
->start_time
= event_data
->time_window
.start_time
;
498 events_request
->start_position
= NULL
;
499 events_request
->stop_flag
= FALSE
;
500 events_request
->end_time
= event_data
->time_window
.end_time
;
501 events_request
->num_events
= G_MAXUINT
;
502 events_request
->end_position
= NULL
;
503 events_request
->trace
= i
;
505 events_request
->hooks
= hooks
;
507 events_request
->before_chunk_traceset
= NULL
;
508 events_request
->before_chunk_trace
= event_data
->hooks_trace_before
;
509 events_request
->before_chunk_tracefile
= NULL
;
510 events_request
->event
= NULL
;
511 events_request
->event_by_id
= event_data
->event_by_id_hooks
;
512 events_request
->after_chunk_tracefile
= NULL
;
513 events_request
->after_chunk_trace
= NULL
;
514 events_request
->after_chunk_traceset
= NULL
;
515 events_request
->before_request
= NULL
;
516 events_request
->after_request
= event_data
->hooks_trace_after
;
518 lttvwindow_events_request(event_data
->tab
, events_request
);
524 * This function is called whenever an irq_entry event occurs.
527 static gboolean
FirstRequestIrqEntryCallback(void *hook_data
, void *call_data
)
533 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
534 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
535 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
536 GArray
* FirstRequestIrqEntry
= event_data
->FirstRequestIrqEntry
;
537 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
538 event_time
= ltt_event_time(e
);
539 cpu_id
= ltt_event_cpu_id(e
);
542 entry
.id
=get_interrupt_id(e
);
543 entry
.cpu_id
= cpu_id
;
544 entry
.event_time
= event_time
;
545 g_array_append_val (FirstRequestIrqEntry
, entry
);
551 * This function gets the id of the interrupt. The id is stored in a dynamic structure.
552 * Refer to the print.c file for how to extract data from a dynamic structure.
554 static guint64
get_interrupt_id(LttEvent
*e
)
557 LttEventType
*event_type
;
561 event_type
= ltt_event_eventtype(e
);
562 num_fields
= ltt_eventtype_num_fields(event_type
);
563 for(i
= 0 ; i
< num_fields
-1 ; i
++)
565 field
= ltt_eventtype_field(event_type
, i
);
566 irq_id
= ltt_event_get_long_unsigned(e
,field
);
572 * This function is called whenever an irq_exit event occurs.
575 gboolean
FirstRequestIrqExitCallback(void *hook_data
, void *call_data
)
579 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
580 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
581 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
582 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
583 LttEventType
*type
= ltt_event_eventtype(e
);
584 event_time
= ltt_event_time(e
);
585 cpu_id
= ltt_event_cpu_id(e
);
587 CalculateData( event_time
, cpu_id
, event_data
);
593 * This function calculates the duration of an interrupt.
596 static void CalculateData(LttTime time_exit
, guint cpu_id
,InterruptEventData
*event_data
)
602 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
603 GArray
*FirstRequestIrqEntry
= event_data
->FirstRequestIrqEntry
;
604 for(i
= 0; i
< FirstRequestIrqEntry
->len
; i
++)
606 element
= &g_array_index(FirstRequestIrqEntry
,irq_entry
,i
);
607 if(element
->cpu_id
== cpu_id
)
609 CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(element
,time_exit
, FirstRequestIrqExit
);
610 g_array_remove_index(FirstRequestIrqEntry
, i
);
618 * This function calculates the total duration of an interrupt and the longest & shortest Irq handlers.
621 static void CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(irq_entry
*e
, LttTime time_exit
, GArray
*FirstRequestIrqExit
)
627 gboolean notFound
= FALSE
;
628 memset ((void*)&irq
, 0,sizeof(Irq
));
631 if(FirstRequestIrqExit
->len
== NO_ITEMS
)
633 irq
.cpu_id
= e
->cpu_id
;
635 irq
.NumerofInterruptions
++;
636 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
638 irq
.max_irq_handler
.start_time
= e
->event_time
;
639 irq
.max_irq_handler
.end_time
= time_exit
;
640 irq
.max_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
642 irq
.min_irq_handler
.start_time
= e
->event_time
;
643 irq
.min_irq_handler
.end_time
= time_exit
;
644 irq
.min_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
646 g_array_append_val (FirstRequestIrqExit
, irq
);
650 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
652 element
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
653 if(element
->id
== e
->id
)
656 duration
= ltt_time_sub(time_exit
, e
->event_time
);
657 element
->total_duration
= ltt_time_add(element
->total_duration
, duration
);
658 element
->NumerofInterruptions
++;
660 if(ltt_time_compare(duration
,element
->max_irq_handler
.duration
) > 0)
662 element
->max_irq_handler
.duration
= duration
;
663 element
->max_irq_handler
.start_time
= e
->event_time
;
664 element
->max_irq_handler
.end_time
= time_exit
;
667 if(ltt_time_compare(duration
,element
->min_irq_handler
.duration
) < 0)
669 element
->min_irq_handler
.duration
= duration
;
670 element
->min_irq_handler
.start_time
= e
->event_time
;
671 element
->min_irq_handler
.end_time
= time_exit
;
677 irq
.cpu_id
= e
->cpu_id
;
679 irq
.NumerofInterruptions
++;
680 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
682 irq
.max_irq_handler
.start_time
= e
->event_time
;
683 irq
.max_irq_handler
.end_time
= time_exit
;
684 irq
.max_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
686 irq
.min_irq_handler
.start_time
= e
->event_time
;
687 irq
.min_irq_handler
.end_time
= time_exit
;
688 irq
.min_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
690 g_array_append_val (FirstRequestIrqExit
, irq
);
696 * This function passes the second EventsRequest to LTTV
699 static gboolean
SecondRequest(void *hook_data
, void *call_data
)
702 guint i
, k
, l
, nb_trace
;
712 EventsRequest
*events_request
;
714 LttvTraceHookByFacility
*thf
;
716 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
718 LttvTracesetContext
*tsc
= lttvwindow_get_traceset_context(event_data
->tab
);
720 CalculateAverageDurationForEachIrqId(event_data
);
722 /* Get the traceset */
723 LttvTraceset
*traceset
= tsc
->ts
;
725 nb_trace
= lttv_traceset_number(traceset
);
727 /* There are many traces in a traceset. Iteration for each trace. */
728 for(i
= 0; i
<MIN(TRACE_NUMBER
+1, nb_trace
);i
++)
730 events_request
= g_new(EventsRequest
, 1);
732 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
734 hooks
= g_array_set_size(hooks
, 2);
736 event_data
->hooks_trace_after
= lttv_hooks_new();
738 /* Registers a hook function */
739 lttv_hooks_add(event_data
->hooks_trace_after
, DisplayViewer
, event_data
, LTTV_PRIO_DEFAULT
);
741 /* Get a trace state */
742 ts
= (LttvTraceState
*)tsc
->traces
[i
];
743 /* Create event_by_Id hooks */
744 event_data
->event_by_id_hooks
= lttv_hooks_by_id_new();
746 /*Register event_by_id_hooks with a callback function*/
747 ret
= lttv_trace_find_hook(ts
->parent
.t
,
748 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
749 LTT_FIELD_IRQ_ID
, 0, 0,
750 SecondRequestIrqEntryCallback
,
752 &g_array_index(hooks
, LttvTraceHook
, 0));
754 ret
= lttv_trace_find_hook(ts
->parent
.t
,
755 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
756 LTT_FIELD_IRQ_ID
, 0, 0,
757 SecondRequestIrqExitCallback
,
759 &g_array_index(hooks
, LttvTraceHook
, 1));
763 /* iterate through the facility list */
764 for(k
= 0 ; k
< hooks
->len
; k
++)
766 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
767 for(l
=0; l
<hook
->fac_list
->len
; l
++)
769 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
770 lttv_hooks_add(lttv_hooks_by_id_find(event_data
->event_by_id_hooks
, thf
->id
),
777 /* Initalize the EventsRequest structure */
778 events_request
->owner
= event_data
;
779 events_request
->viewer_data
= event_data
;
780 events_request
->servicing
= FALSE
;
781 events_request
->start_time
= event_data
->time_window
.start_time
;
782 events_request
->start_position
= NULL
;
783 events_request
->stop_flag
= FALSE
;
784 events_request
->end_time
= event_data
->time_window
.end_time
;
785 events_request
->num_events
= G_MAXUINT
;
786 events_request
->end_position
= NULL
;
787 events_request
->trace
= i
;
789 events_request
->hooks
= hooks
;
791 events_request
->before_chunk_traceset
= NULL
;
792 events_request
->before_chunk_trace
= NULL
;
793 events_request
->before_chunk_tracefile
= NULL
;
794 events_request
->event
= NULL
;
795 events_request
->event_by_id
= event_data
->event_by_id_hooks
;
796 events_request
->after_chunk_tracefile
= NULL
;
797 events_request
->after_chunk_trace
= NULL
;
798 events_request
->after_chunk_traceset
= NULL
;
799 events_request
->before_request
= NULL
;
800 events_request
->after_request
= event_data
->hooks_trace_after
;
802 lttvwindow_events_request(event_data
->tab
, events_request
);
808 * This function calculates the average duration for each Irq Id
811 static void CalculateAverageDurationForEachIrqId(InterruptEventData
*event_data
)
816 GArray
* FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
817 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
819 element
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
820 real_data
= element
->total_duration
.tv_sec
;
821 real_data
*= NANOSECONDS_PER_SECOND
;
822 real_data
+= element
->total_duration
.tv_nsec
;
823 if(element
->NumerofInterruptions
!= 0)
824 element
->average_duration
= real_data
/ element
->NumerofInterruptions
;
826 element
->average_duration
= 0;
832 * This function is called whenever an irq_entry event occurs. Use in the second request
835 static gboolean
SecondRequestIrqEntryCallback(void *hook_data
, void *call_data
)
841 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
842 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
843 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
844 GArray
* SecondRequestIrqEntry
= event_data
->SecondRequestIrqEntry
;
845 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
846 event_time
= ltt_event_time(e
);
847 cpu_id
= ltt_event_cpu_id(e
);
850 entry
.id
=get_interrupt_id(e
);
851 entry
.cpu_id
= cpu_id
;
852 entry
.event_time
= event_time
;
853 g_array_append_val (SecondRequestIrqEntry
, entry
);
859 * This function is called whenever an irq_exit event occurs in the second request.
862 static gboolean
SecondRequestIrqExitCallback(void *hook_data
, void *call_data
)
865 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
866 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
867 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
868 LttEvent
*event
= ltt_tracefile_get_event(tfc
->tf
);
870 CalculateXi(event
, event_data
);
876 * This function is called whenever an irq_exit event occurs in the second request.
879 static void CalculateXi(LttEvent
*event_irq_exit
, InterruptEventData
*event_data
)
887 GArray
*SecondRequestIrqExit
= event_data
->SecondRequestIrqExit
;
888 GArray
*SecondRequestIrqEntry
= event_data
->SecondRequestIrqEntry
;
889 cpu_id
= ltt_event_cpu_id(event_irq_exit
);
890 for(i
= 0; i
< SecondRequestIrqEntry
->len
; i
++)
892 element
= &g_array_index(SecondRequestIrqEntry
,irq_entry
,i
);
893 if(element
->cpu_id
== cpu_id
)
896 /* time calculation */
897 exit_time
= ltt_event_time(event_irq_exit
);
898 Xi
= ltt_time_sub(exit_time
, element
->event_time
);
899 irq_id
= element
->id
;
901 SumItems(irq_id
, Xi
,event_data
);
902 g_array_remove_index(SecondRequestIrqEntry
, i
);
910 * This function computes the Sum ((xi -Xa)^2) and store the result in SumArray
913 static void SumItems(gint irq_id
, LttTime Xi
, InterruptEventData
*event_data
)
918 gint duration_inner_part
;
919 guint64 period_inner_part
;
920 guint64 frequency_inner_part
;
926 gboolean notFound
= FALSE
;
927 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
928 GArray
*SumArray
= event_data
->SumArray
;
929 Xi_in_ns
= Xi
.tv_sec
;
930 Xi_in_ns
*= NANOSECONDS_PER_SECOND
;
931 Xi_in_ns
+= Xi
.tv_nsec
;
933 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
935 average
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
936 if(irq_id
== average
->id
)
938 duration_inner_part
= Xi_in_ns
- average
->average_duration
;
939 FrequencyHZ
= FrequencyInHZ(average
->NumerofInterruptions
, event_data
->time_window
);
941 // compute (xi -Xa)^2 of the duration Standard deviation
942 sum
.NumerofInterruptions
= average
->NumerofInterruptions
;
943 sum
.sumOfDurations
= pow (duration_inner_part
, 2);
945 // compute (xi -Xa)^2 of the period Standard deviation
946 period_inner_part
= CalculatePeriodInnerPart(Xi_in_ns
, FrequencyHZ
);
948 // compute (xi -Xa)^2 of the frequency Standard deviation
949 frequency_inner_part
= CalculateFrequencyInnerPart(Xi_in_ns
, FrequencyHZ
);
951 sum
.sumOfPeriods
= period_inner_part
;
953 sum
.sumOfFrequencies
= frequency_inner_part
;
955 if(event_data
->SumArray
->len
== NO_ITEMS
)
957 g_array_append_val (SumArray
, sum
);
961 for(i
= 0; i
< SumArray
->len
; i
++)
963 sumItem
= &g_array_index(SumArray
, SumId
, i
);
964 if(sumItem
->irqId
== irq_id
)
967 sumItem
->sumOfDurations
+= sum
.sumOfDurations
;
968 sumItem
->sumOfPeriods
+= sum
.sumOfPeriods
;
969 sumItem
->sumOfFrequencies
+= sum
.sumOfFrequencies
;
974 g_array_append_val (SumArray
, sum
);
984 * This function computes the inner part of the period standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
985 * The inner part is: (xi -Xa)^2
987 static guint64
CalculatePeriodInnerPart(guint Xi
, guint FrequencyHZ
)
990 double periodInSec
; /*period in sec*/
994 periodInSec
= (double)1/FrequencyHZ
;
995 periodInSec
*= NANOSECONDS_PER_SECOND
;
996 periodInNSec
= (int)periodInSec
;
998 difference
= Xi
- periodInNSec
;
999 result
= pow (difference
, 2);
1004 * This function computes the inner part of the frequency standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1005 * The inner part is: (xi -Xa)^2
1007 static guint64
CalculateFrequencyInnerPart(guint Xi_in_ns
, guint FrequencyHZ
)
1012 difference
= Xi_in_ns
- FrequencyHZ
;
1013 result
= pow (difference
, 2);
1017 * This function displays the result on the viewer
1020 static gboolean
DisplayViewer(void *hook_data
, void *call_data
)
1026 LttTime average_duration
;
1029 guint maxIRQduration
;
1032 char maxIrqHandler
[80];
1033 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
1034 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
1035 int FrequencyHZ
= 0;
1037 gtk_list_store_clear(event_data
->ListStore
);
1038 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
1040 element
= g_array_index(FirstRequestIrqExit
,Irq
,i
);
1041 real_data
= element
.total_duration
.tv_sec
;
1042 real_data
*= NANOSECONDS_PER_SECOND
;
1043 real_data
+= element
.total_duration
.tv_nsec
;
1046 maxIRQduration
= element
.max_irq_handler
.duration
.tv_sec
;
1047 maxIRQduration
*= NANOSECONDS_PER_SECOND
;
1048 maxIRQduration
+= element
.max_irq_handler
.duration
.tv_nsec
;
1050 sprintf(maxIrqHandler
, "%d [%d.%d - %d.%d]",maxIRQduration
, element
.max_irq_handler
.start_time
.tv_sec
, \
1051 element
.max_irq_handler
.start_time
.tv_nsec
, element
.max_irq_handler
.end_time
.tv_sec
, \
1052 element
.max_irq_handler
.end_time
.tv_nsec
) ;
1053 FrequencyHZ
= FrequencyInHZ(element
.NumerofInterruptions
,event_data
->time_window
);
1055 if(FrequencyHZ
!= 0)
1057 periodInSec
= (double)1/FrequencyHZ
;
1058 periodInSec
*= NANOSECONDS_PER_SECOND
;
1059 periodInNsec
= (int)periodInSec
;
1063 gtk_list_store_append (event_data
->ListStore
, &iter
);
1064 gtk_list_store_set (event_data
->ListStore
, &iter
,
1065 CPUID_COLUMN
, element
.cpu_id
,
1066 IRQ_ID_COLUMN
, element
.id
,
1067 FREQUENCY_COLUMN
, FrequencyHZ
,
1068 DURATION_COLUMN
, real_data
,
1069 DURATION_STANDARD_DEV_COLUMN
, CalculateDurationStandardDeviation(element
.id
, event_data
),
1070 MAX_IRQ_HANDLER_COLUMN
, maxIrqHandler
,
1071 AVERAGE_PERIOD
, periodInNsec
,
1072 PERIOD_STANDARD_DEV_COLUMN
, CalculatePeriodStandardDeviation(element
.id
, event_data
),
1073 FREQUENCY_STANDARD_DEV_COLUMN
, CalculateFrequencyStandardDeviation(element
.id
, event_data
),
1078 printf("%d %d %lld %d %s %d %d %d\n\n",element
.id
, FrequencyHZ
,real_data
,CalculateDurationStandardDeviation(element
.id
, event_data
), maxIrqHandler
, periodInNsec
, CalculatePeriodStandardDeviation(element
.id
, event_data
), CalculateFrequencyStandardDeviation(element
.id
, event_data
));
1082 if(event_data
->FirstRequestIrqExit
->len
)
1084 g_array_remove_range (event_data
->FirstRequestIrqExit
,0,event_data
->FirstRequestIrqExit
->len
);
1087 if(event_data
->FirstRequestIrqEntry
->len
)
1089 g_array_remove_range (event_data
->FirstRequestIrqEntry
,0,event_data
->FirstRequestIrqEntry
->len
);
1092 if(event_data
->SecondRequestIrqEntry
->len
)
1094 g_array_remove_range (event_data
->SecondRequestIrqEntry
,0,event_data
->SecondRequestIrqEntry
->len
);
1097 if(event_data
->SecondRequestIrqExit
->len
)
1099 g_array_remove_range (event_data
->SecondRequestIrqExit
,0, event_data
->SecondRequestIrqExit
->len
);
1102 if(event_data
->SumArray
->len
)
1104 g_array_remove_range (event_data
->SumArray
,0, event_data
->SumArray
->len
);
1112 * This function converts the number of interrupts over a time window to
1115 static int FrequencyInHZ(gint NumerofInterruptions
, TimeWindow time_window
)
1117 guint64 frequencyHz
= 0;
1118 double timeSec
; // time in second
1120 result
= ltt_time_to_double(time_window
.time_width
);
1121 timeSec
= (result
/NANOSECONDS_PER_SECOND
); //time in second
1122 frequencyHz
= NumerofInterruptions
/ timeSec
;
1127 * This function calculates the duration standard deviation
1128 * Duration standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1130 * sumId.sumOfDurations -> Sum ((xi -Xa)^2)
1131 * inner_component -> 1/N Sum ((xi -Xa)^2)
1132 * deviation-> sqrt(1/N Sum ((xi -Xa)^2))
1134 static int CalculateDurationStandardDeviation(gint id
, InterruptEventData
*event_data
)
1138 double inner_component
;
1140 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
1142 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
1143 if(id
== sumId
.irqId
)
1145 if(sumId
.NumerofInterruptions
!= 0)
1146 inner_component
= sumId
.sumOfDurations
/ sumId
.NumerofInterruptions
;
1148 inner_component
= 0.0;
1149 deviation
= sqrt(inner_component
);
1158 * This function calculates the period standard deviation
1159 * Period standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1161 * sumId.sumOfPeriods -> Sum ((xi -Xa)^2)
1162 * inner_component -> 1/N Sum ((xi -Xa)^2)
1163 * period_standard_deviation-> sqrt(1/N Sum ((xi -Xa)^2))
1167 static int CalculatePeriodStandardDeviation(gint id
, InterruptEventData
*event_data
)
1171 guint64 inner_component
;
1172 guint64 period_standard_deviation
= 0;
1174 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
1176 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
1177 if(id
== sumId
.irqId
)
1179 if(sumId
.NumerofInterruptions
!= 0)
1180 inner_component
= sumId
.sumOfPeriods
/ sumId
.NumerofInterruptions
;
1182 inner_component
= 0;
1184 period_standard_deviation
= sqrt(inner_component
);
1188 return period_standard_deviation
;
1192 * This function calculates the frequency standard deviation
1193 * Frequency standard deviation = sqrt(1/N Sum ((xi -Xa)^2))
1195 * sumId.sumOfFrequencies -> Sum ((xi -Xa)^2)
1196 * inner_component -> 1/N Sum ((xi -Xa)^2)
1197 * frequency_standard_deviation-> sqrt(1/N Sum ((xi -Xa)^2))
1200 static int CalculateFrequencyStandardDeviation(gint id
, InterruptEventData
*event_data
)
1204 guint64 inner_component
;
1205 guint64 frequency_standard_deviation
= 0;
1206 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
1208 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
1209 if(id
== sumId
.irqId
)
1211 if(sumId
.NumerofInterruptions
!= 0)
1212 inner_component
= sumId
.sumOfFrequencies
/ sumId
.NumerofInterruptions
;
1214 inner_component
= 0;
1216 frequency_standard_deviation
= sqrt(inner_component
);
1219 return frequency_standard_deviation
;
1223 * This function is called by the main window
1224 * when the time interval needs to be updated.
1226 gboolean
interrupt_update_time_window(void * hook_data
, void * call_data
)
1228 InterruptEventData
*event_data
= (InterruptEventData
*) hook_data
;
1229 const TimeWindowNotifyData
*time_window_nofify_data
= ((const TimeWindowNotifyData
*)call_data
);
1230 event_data
->time_window
= *time_window_nofify_data
->new_time_window
;
1231 g_info("interrupts: interrupt_update_time_window()\n");
1232 Tab
*tab
= event_data
->tab
;
1233 lttvwindow_events_request_remove_all(tab
, event_data
);
1234 FirstRequest(event_data
);
1239 gboolean
trace_header(void *hook_data
, void *call_data
)
1242 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
1243 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1249 void interrupt_destroy_walk(gpointer data
, gpointer user_data
)
1251 g_info("interrupt_destroy_walk");
1252 InterruptEventData
*event_data
= (InterruptEventData
*) data
;
1253 interrupt_destructor((InterruptEventData
*)data
);
1257 void interrupt_destructor(InterruptEventData
*event_viewer_data
)
1259 /* May already been done by GTK window closing */
1260 g_info("enter interrupt_destructor \n");
1261 if(GTK_IS_WIDGET(event_viewer_data
->Hbox
))
1263 gtk_widget_destroy(event_viewer_data
->Hbox
);
1268 This function is called when the viewer is destroyed to free hooks and memory
1270 static void InterruptFree(InterruptEventData
*event_viewer_data
)
1272 Tab
*tab
= event_viewer_data
->tab
;
1276 g_array_free(event_viewer_data
->FirstRequestIrqExit
, TRUE
);
1277 g_array_free(event_viewer_data
->FirstRequestIrqEntry
, TRUE
);
1278 g_array_free(event_viewer_data
->SecondRequestIrqEntry
, TRUE
);
1279 g_array_free(event_viewer_data
->SecondRequestIrqExit
, TRUE
);
1280 g_array_free(event_viewer_data
->SumArray
, TRUE
);
1282 lttvwindow_unregister_time_window_notify(tab
, interrupt_update_time_window
, event_viewer_data
);
1284 lttvwindow_events_request_remove_all(event_viewer_data
->tab
,
1287 interrupt_data_list
= g_slist_remove(interrupt_data_list
, event_viewer_data
);
1294 * plugin's destroy function
1296 * This function releases the memory reserved by the module and unregisters
1297 * everything that has been registered in the gtkTraceSet API.
1299 static void destroy()
1302 g_info("Destroy interrupts");
1303 g_slist_foreach(interrupt_data_list
, interrupt_destroy_walk
, NULL
);
1304 g_slist_free(interrupt_data_list
);
1305 lttvwindow_unregister_constructor(interrupts
);
1309 LTTV_MODULE("interrupts", "interrupts info view", \
1310 "Graphical module to display interrupts performance", \
1311 init
, destroy
, "lttvwindow")