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 The standard deviation calculation is based on:
22 http://en.wikipedia.org/wiki/Standard_deviation
24 Standard_deviation = sqrt(1/N Sum ((xi -Xa)^2))
26 To compute the standard deviation, we need to make EventRequests to LTTV. In
27 the first EventRequest, we compute the average duration (Xa) and the
28 frequency (N) of each IrqID. We store the information calculated in the first
29 EventRequest in an array called FirstRequestIrqExit.
30 In the second EventRequest, we compute the Sum ((xi -Xa)^2) and store this information
31 in a array called SumArray. The function CalculateDurationStandardDeviation() uses FirstRequestIrqExit
32 and SumArray arrays to calculate the standard deviation.
40 Frequency (Hz): the number of interruptions per second (Hz)
42 Total Duration (nsec): the sum of each interrupt duration in nsec
44 Duration standard deviation (nsec): taken from http://en.wikipedia.org/wiki/Standard_deviation
45 Duration Standard_deviation = sqrt(1/N Sum ((xi -Xa)^2)) where
46 N: number of interrupts
47 xi: duration of an interrupt (nsec)
48 Xa: average duration (nsec)
50 Max IRQ handler duration (nsec) [time interval]: the longest IRQ handler duration in nsec.
52 Average period (nsec): 1/frequency
55 Period Standard_deviation = sqrt(1/N Sum ((xi -Xa)^2)) where
56 N: number of interrupts
57 xi: 1/duration of an interrupt
60 *******************************************************************/
73 #include <ltt/event.h>
75 #include <ltt/trace.h>
76 #include <ltt/facility.h>
77 #include <lttv/module.h>
78 #include <lttv/hook.h>
79 #include <lttv/tracecontext.h>
80 #include <lttv/state.h>
81 #include <lttv/filter.h>
82 #include <lttvwindow/lttvwindow.h>
85 #include "hInterruptsInsert.xpm"
87 #define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
88 #define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format)
102 LttTime total_duration
;
103 guint average_duration
;
104 MaxDuration max_irq_handler
;
119 guint64 sumOfDurations
;
120 guint64 sumOfPeriods
;
129 /** Array containing instanced objects. Used when module is unloaded */
130 static GSList
*interrupt_data_list
= NULL
;
133 #define TRACE_NUMBER 0
135 typedef struct _InterruptEventData
{
137 /*Graphical Widgets */
138 GtkWidget
* ScrollWindow
;
139 GtkListStore
*ListStore
;
142 GtkTreeSelection
*SelectionTree
;
144 Tab
* tab
; /* tab that contains this plug-in*/
145 LttvHooks
* event_hooks
;
146 LttvHooks
* hooks_trace_after
;
147 LttvHooks
* hooks_trace_before
;
148 TimeWindow time_window
;
149 LttvHooksById
* event_by_id_hooks
;
150 GArray
*FirstRequestIrqExit
;
151 GArray
*FirstRequestIrqEntry
;
152 GArray
*SecondRequestIrqEntry
;
153 GArray
*SecondRequestIrqExit
;
156 } InterruptEventData
;
159 /* Function prototypes */
161 static gboolean
interrupt_update_time_window(void * hook_data
, void * call_data
);
162 static GtkWidget
*interrupts(Tab
*tab
);
163 static InterruptEventData
*system_info(Tab
*tab
);
164 void interrupt_destructor(InterruptEventData
*event_viewer_data
);
165 static void FirstRequest(InterruptEventData
*event_data
);
166 static guint64
get_interrupt_id(LttEvent
*e
);
167 static gboolean
trace_header(void *hook_data
, void *call_data
);
168 static gboolean
DisplayViewer (void *hook_data
, void *call_data
);
169 static void CalculateData(LttTime time_exit
, guint cpu_id
, InterruptEventData
*event_data
);
170 static void TotalDurationMaxIrqDuration(irq_entry
*e
, LttTime time_exit
, GArray
*FirstRequestIrqExit
);
171 static gboolean
FirstRequestIrqEntryCallback(void *hook_data
, void *call_data
);
172 static gboolean
FirstRequestIrqExitCallback(void *hook_data
, void *call_data
);
173 static gboolean
SecondRequest(void *hook_data
, void *call_data
);
174 static void CalculateAverageDurationForEachIrqId(InterruptEventData
*event_data
);
175 static gboolean
SecondRequestIrqEntryCallback(void *hook_data
, void *call_data
);
176 static gboolean
SecondRequestIrqExitCallback(void *hook_data
, void *call_data
);
177 static void CalculateXi(LttEvent
*event
, InterruptEventData
*event_data
);
178 static void SumItems(gint irq_id
, LttTime Xi
, InterruptEventData
*event_data
);
179 static int CalculateDurationStandardDeviation(gint id
, InterruptEventData
*event_data
);
180 static int CalculatePeriodStandardDeviation(gint id
, InterruptEventData
*event_data
);
181 static int FrequencyInHZ(gint frequency
, TimeWindow time_window
);
182 static guint64
CalculatePeriodInnerPart(guint Xi
, guint FrequencyHZ
);
183 /* Enumeration of the columns */
189 DURATION_STANDARD_DEV_COLUMN
,
190 MAX_IRQ_HANDLER_COLUMN
,
192 PERIOD_STANDARD_DEV_COLUMN
,
202 * This is the entry point of the viewer.
206 g_info("interrupts: init()");
207 lttvwindow_register_constructor("interrupts",
209 "Insert Interrupts View",
210 hInterruptsInsert_xpm
,
211 "Insert Interrupts View",
221 static GtkWidget
*interrupts(Tab
* tab
)
224 InterruptEventData
* event_data
= system_info(tab
) ;
226 return event_data
->Hbox
;
232 * This function initializes the Event Viewer functionnality through the
235 InterruptEventData
*system_info(Tab
*tab
)
239 GtkTreeViewColumn
*column
;
240 GtkCellRenderer
*renderer
;
241 InterruptEventData
* event_viewer_data
= g_new(InterruptEventData
,1) ;
243 event_viewer_data
->tab
= tab
;
245 /*Get the current time frame from the main window */
246 event_viewer_data
->time_window
= lttvwindow_get_time_window(tab
);
248 event_viewer_data
->FirstRequestIrqExit
= g_array_new(FALSE
, FALSE
, sizeof(Irq
));
249 event_viewer_data
->FirstRequestIrqEntry
= g_array_new(FALSE
, FALSE
, sizeof(irq_entry
));
251 event_viewer_data
->SecondRequestIrqEntry
= g_array_new(FALSE
, FALSE
, sizeof(irq_entry
));
252 event_viewer_data
->SecondRequestIrqExit
= g_array_new(FALSE
, FALSE
, sizeof(Irq
));
254 event_viewer_data
->SumArray
= g_array_new(FALSE
, FALSE
, sizeof(SumId
));
257 /*Create tha main window for the viewer */
258 event_viewer_data
->ScrollWindow
= gtk_scrolled_window_new (NULL
, NULL
);
259 gtk_widget_show (event_viewer_data
->ScrollWindow
);
260 gtk_scrolled_window_set_policy(
261 GTK_SCROLLED_WINDOW(event_viewer_data
->ScrollWindow
),
262 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
/*GTK_POLICY_NEVER*/);
264 /* Create a model for storing the data list */
265 event_viewer_data
->ListStore
= gtk_list_store_new (
266 N_COLUMNS
, /* Total number of columns */
267 G_TYPE_INT
, /* CPUID */
268 G_TYPE_INT
, /* IRQ_ID */
269 G_TYPE_INT
, /* Frequency */
270 G_TYPE_UINT64
, /* Duration */
271 G_TYPE_INT
, /* standard deviation */
272 G_TYPE_STRING
, /* Max IRQ handler */
273 G_TYPE_INT
, /* Average period */
274 G_TYPE_INT
/* period standard deviation */
277 event_viewer_data
->TreeView
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (event_viewer_data
->ListStore
));
279 g_object_unref (G_OBJECT (event_viewer_data
->ListStore
));
281 renderer
= gtk_cell_renderer_text_new ();
282 column
= gtk_tree_view_column_new_with_attributes ("CPUID",
284 "text", CPUID_COLUMN
,
286 gtk_tree_view_column_set_alignment (column
, 0.0);
287 gtk_tree_view_column_set_fixed_width (column
, 45);
288 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
291 renderer
= gtk_cell_renderer_text_new ();
292 column
= gtk_tree_view_column_new_with_attributes ("IrqId",
294 "text", IRQ_ID_COLUMN
,
296 gtk_tree_view_column_set_alignment (column
, 0.0);
297 gtk_tree_view_column_set_fixed_width (column
, 220);
298 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
300 renderer
= gtk_cell_renderer_text_new ();
301 column
= gtk_tree_view_column_new_with_attributes ("Frequency (Hz)",
303 "text", FREQUENCY_COLUMN
,
305 gtk_tree_view_column_set_alignment (column
, 1.0);
306 gtk_tree_view_column_set_fixed_width (column
, 220);
307 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
309 renderer
= gtk_cell_renderer_text_new ();
310 column
= gtk_tree_view_column_new_with_attributes ("Total Duration (nsec)",
312 "text", DURATION_COLUMN
,
314 gtk_tree_view_column_set_alignment (column
, 0.0);
315 gtk_tree_view_column_set_fixed_width (column
, 145);
316 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
319 renderer
= gtk_cell_renderer_text_new ();
320 column
= gtk_tree_view_column_new_with_attributes ("Duration standard deviation (nsec)",
322 "text", DURATION_STANDARD_DEV_COLUMN
,
324 gtk_tree_view_column_set_alignment (column
, 0.0);
325 gtk_tree_view_column_set_fixed_width (column
, 200);
326 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
328 renderer
= gtk_cell_renderer_text_new ();
329 column
= gtk_tree_view_column_new_with_attributes ("Max IRQ handler duration (nsec) [time interval]",
331 "text", MAX_IRQ_HANDLER_COLUMN
,
333 gtk_tree_view_column_set_alignment (column
, 0.0);
334 gtk_tree_view_column_set_fixed_width (column
, 250);
335 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
337 renderer
= gtk_cell_renderer_text_new ();
338 column
= gtk_tree_view_column_new_with_attributes (" Average period (nsec)",
340 "text", AVERAGE_PERIOD
,
342 gtk_tree_view_column_set_alignment (column
, 0.0);
343 gtk_tree_view_column_set_fixed_width (column
, 200);
344 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
346 renderer
= gtk_cell_renderer_text_new ();
347 column
= gtk_tree_view_column_new_with_attributes ("Period standard deviation (nsec)",
349 "text", PERIOD_STANDARD_DEV_COLUMN
,
351 gtk_tree_view_column_set_alignment (column
, 0.0);
352 gtk_tree_view_column_set_fixed_width (column
, 200);
353 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
357 event_viewer_data
->SelectionTree
= gtk_tree_view_get_selection (GTK_TREE_VIEW (event_viewer_data
->TreeView
));
358 gtk_tree_selection_set_mode (event_viewer_data
->SelectionTree
, GTK_SELECTION_SINGLE
);
360 gtk_container_add (GTK_CONTAINER (event_viewer_data
->ScrollWindow
), event_viewer_data
->TreeView
);
362 event_viewer_data
->Hbox
= gtk_hbox_new(0, 0);
363 gtk_box_pack_start(GTK_BOX(event_viewer_data
->Hbox
), event_viewer_data
->ScrollWindow
, TRUE
, TRUE
, 0);
365 gtk_widget_show(event_viewer_data
->Hbox
);
366 gtk_widget_show(event_viewer_data
->TreeView
);
368 interrupt_data_list
= g_slist_append(interrupt_data_list
, event_viewer_data
);
369 /* Registration for time notification */
370 lttvwindow_register_time_window_notify(tab
,
371 interrupt_update_time_window
,
375 FirstRequest(event_viewer_data
);
376 return event_viewer_data
;
381 * For each trace in the traceset, this function:
382 * - registers a callback function to each hook
383 * - calls lttv_trace_find_hook() registers a hook function to event_by_id_hooks
384 * - calls lttvwindow_events_request() to request data in a specific
385 * time interval to the main window
388 static void FirstRequest(InterruptEventData
*event_data
)
390 guint i
, k
, l
, nb_trace
;
400 EventsRequest
*events_request
;
402 LttvTraceHookByFacility
*thf
;
404 LttvTracesetContext
*tsc
= lttvwindow_get_traceset_context(event_data
->tab
);
407 /* Get the traceset */
408 LttvTraceset
*traceset
= tsc
->ts
;
410 nb_trace
= lttv_traceset_number(traceset
);
412 /* There are many traces in a traceset. Iteration for each trace. */
413 for(i
= 0; i
<MIN(TRACE_NUMBER
+1, nb_trace
);i
++)
415 events_request
= g_new(EventsRequest
, 1);
417 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
419 hooks
= g_array_set_size(hooks
, 2);
421 event_data
->hooks_trace_before
= lttv_hooks_new();
423 /* Registers a hook function */
424 lttv_hooks_add(event_data
->hooks_trace_before
, trace_header
, event_data
, LTTV_PRIO_DEFAULT
);
426 event_data
->hooks_trace_after
= lttv_hooks_new();
428 /* Registers a hook function */
429 lttv_hooks_add(event_data
->hooks_trace_after
, SecondRequest
, event_data
, LTTV_PRIO_DEFAULT
);
430 /* Get a trace state */
431 ts
= (LttvTraceState
*)tsc
->traces
[i
];
432 /* Create event_by_Id hooks */
433 event_data
->event_by_id_hooks
= lttv_hooks_by_id_new();
435 /*Register event_by_id_hooks with a callback function*/
436 ret
= lttv_trace_find_hook(ts
->parent
.t
,
437 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
438 LTT_FIELD_IRQ_ID
, 0, 0,
439 FirstRequestIrqEntryCallback
,
441 &g_array_index(hooks
, LttvTraceHook
, 0));
443 ret
= lttv_trace_find_hook(ts
->parent
.t
,
444 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
445 LTT_FIELD_IRQ_ID
, 0, 0,
446 FirstRequestIrqExitCallback
,
448 &g_array_index(hooks
, LttvTraceHook
, 1));
451 /*iterate through the facility list*/
452 for(k
= 0 ; k
< hooks
->len
; k
++)
454 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
455 for(l
=0; l
<hook
->fac_list
->len
; l
++)
457 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
458 lttv_hooks_add(lttv_hooks_by_id_find(event_data
->event_by_id_hooks
, thf
->id
),
465 /* Initalize the EventsRequest structure */
466 events_request
->owner
= event_data
;
467 events_request
->viewer_data
= event_data
;
468 events_request
->servicing
= FALSE
;
469 events_request
->start_time
= event_data
->time_window
.start_time
;
470 events_request
->start_position
= NULL
;
471 events_request
->stop_flag
= FALSE
;
472 events_request
->end_time
= event_data
->time_window
.end_time
;
473 events_request
->num_events
= G_MAXUINT
;
474 events_request
->end_position
= NULL
;
475 events_request
->trace
= i
;
477 events_request
->hooks
= hooks
;
479 events_request
->before_chunk_traceset
= NULL
;
480 events_request
->before_chunk_trace
= event_data
->hooks_trace_before
;
481 events_request
->before_chunk_tracefile
= NULL
;
482 events_request
->event
= NULL
;
483 events_request
->event_by_id
= event_data
->event_by_id_hooks
;
484 events_request
->after_chunk_tracefile
= NULL
;
485 events_request
->after_chunk_trace
= NULL
;
486 events_request
->after_chunk_traceset
= NULL
;
487 events_request
->before_request
= NULL
;
488 events_request
->after_request
= event_data
->hooks_trace_after
;
490 lttvwindow_events_request(event_data
->tab
, events_request
);
496 * This function is called whenever an irq_entry event occurs.
499 static gboolean
FirstRequestIrqEntryCallback(void *hook_data
, void *call_data
)
505 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
506 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
507 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
508 GArray
* FirstRequestIrqEntry
= event_data
->FirstRequestIrqEntry
;
509 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
510 event_time
= ltt_event_time(e
);
511 cpu_id
= ltt_event_cpu_id(e
);
514 entry
.id
=get_interrupt_id(e
);
515 entry
.cpu_id
= cpu_id
;
516 entry
.event_time
= event_time
;
517 g_array_append_val (FirstRequestIrqEntry
, entry
);
523 * This function gets the id of the interrupt. The id is stored in a dynamic structure.
524 * Refer to the print.c file for howto extract data from a dynamic structure.
526 static guint64
get_interrupt_id(LttEvent
*e
)
529 LttEventType
*event_type
;
533 event_type
= ltt_event_eventtype(e
);
534 num_fields
= ltt_eventtype_num_fields(event_type
);
535 for(i
= 0 ; i
< num_fields
-1 ; i
++)
537 field
= ltt_eventtype_field(event_type
, i
);
538 irq_id
= ltt_event_get_long_unsigned(e
,field
);
544 * This function is called whenever an irq_exit event occurs.
547 gboolean
FirstRequestIrqExitCallback(void *hook_data
, void *call_data
)
551 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
552 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
553 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
554 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
555 LttEventType
*type
= ltt_event_eventtype(e
);
556 event_time
= ltt_event_time(e
);
557 cpu_id
= ltt_event_cpu_id(e
);
559 CalculateData( event_time
, cpu_id
, event_data
);
565 * This function calculates the duration of an interrupt.
568 static void CalculateData(LttTime time_exit
, guint cpu_id
,InterruptEventData
*event_data
)
574 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
575 GArray
*FirstRequestIrqEntry
= event_data
->FirstRequestIrqEntry
;
576 for(i
= 0; i
< FirstRequestIrqEntry
->len
; i
++)
578 element
= &g_array_index(FirstRequestIrqEntry
,irq_entry
,i
);
579 if(element
->cpu_id
== cpu_id
)
581 TotalDurationMaxIrqDuration(element
,time_exit
, FirstRequestIrqExit
);
582 g_array_remove_index(FirstRequestIrqEntry
, i
);
589 * This function calculates the total duration of an interrupt and the longest Irq handler.
592 static void TotalDurationMaxIrqDuration(irq_entry
*e
, LttTime time_exit
, GArray
*FirstRequestIrqExit
){
597 gboolean notFound
= FALSE
;
598 memset ((void*)&irq
, 0,sizeof(Irq
));
601 if(FirstRequestIrqExit
->len
== NO_ITEMS
)
603 irq
.cpu_id
= e
->cpu_id
;
606 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
608 irq
.max_irq_handler
.start_time
= e
->event_time
;
609 irq
.max_irq_handler
.end_time
= time_exit
;
610 irq
.max_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
612 g_array_append_val (FirstRequestIrqExit
, irq
);
616 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
618 element
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
619 if(element
->id
== e
->id
)
622 duration
= ltt_time_sub(time_exit
, e
->event_time
);
623 element
->total_duration
= ltt_time_add(element
->total_duration
, duration
);
624 element
->frequency
++;
625 if(ltt_time_compare(duration
,element
->max_irq_handler
.duration
) > 0)
627 element
->max_irq_handler
.duration
= duration
;
628 element
->max_irq_handler
.start_time
= e
->event_time
;
629 element
->max_irq_handler
.end_time
= time_exit
;
635 irq
.cpu_id
= e
->cpu_id
;
638 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
640 irq
.max_irq_handler
.start_time
= e
->event_time
;
641 irq
.max_irq_handler
.end_time
= time_exit
;
642 irq
.max_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
644 g_array_append_val (FirstRequestIrqExit
, irq
);
650 * This function passes the second EventsRequest to LTTV
653 static gboolean
SecondRequest(void *hook_data
, void *call_data
)
656 guint i
, k
, l
, nb_trace
;
666 EventsRequest
*events_request
;
668 LttvTraceHookByFacility
*thf
;
670 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
672 LttvTracesetContext
*tsc
= lttvwindow_get_traceset_context(event_data
->tab
);
674 CalculateAverageDurationForEachIrqId(event_data
);
676 /* Get the traceset */
677 LttvTraceset
*traceset
= tsc
->ts
;
679 nb_trace
= lttv_traceset_number(traceset
);
681 /* There are many traces in a traceset. Iteration for each trace. */
682 for(i
= 0; i
<MIN(TRACE_NUMBER
+1, nb_trace
);i
++)
684 events_request
= g_new(EventsRequest
, 1);
686 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
688 hooks
= g_array_set_size(hooks
, 2);
690 event_data
->hooks_trace_after
= lttv_hooks_new();
692 /* Registers a hook function */
693 lttv_hooks_add(event_data
->hooks_trace_after
, DisplayViewer
, event_data
, LTTV_PRIO_DEFAULT
);
695 /* Get a trace state */
696 ts
= (LttvTraceState
*)tsc
->traces
[i
];
697 /* Create event_by_Id hooks */
698 event_data
->event_by_id_hooks
= lttv_hooks_by_id_new();
700 /*Register event_by_id_hooks with a callback function*/
701 ret
= lttv_trace_find_hook(ts
->parent
.t
,
702 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
703 LTT_FIELD_IRQ_ID
, 0, 0,
704 SecondRequestIrqEntryCallback
,
706 &g_array_index(hooks
, LttvTraceHook
, 0));
708 ret
= lttv_trace_find_hook(ts
->parent
.t
,
709 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
710 LTT_FIELD_IRQ_ID
, 0, 0,
711 SecondRequestIrqExitCallback
,
713 &g_array_index(hooks
, LttvTraceHook
, 1));
717 /* iterate through the facility list */
718 for(k
= 0 ; k
< hooks
->len
; k
++)
720 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
721 for(l
=0; l
<hook
->fac_list
->len
; l
++)
723 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
724 lttv_hooks_add(lttv_hooks_by_id_find(event_data
->event_by_id_hooks
, thf
->id
),
731 /* Initalize the EventsRequest structure */
732 events_request
->owner
= event_data
;
733 events_request
->viewer_data
= event_data
;
734 events_request
->servicing
= FALSE
;
735 events_request
->start_time
= event_data
->time_window
.start_time
;
736 events_request
->start_position
= NULL
;
737 events_request
->stop_flag
= FALSE
;
738 events_request
->end_time
= event_data
->time_window
.end_time
;
739 events_request
->num_events
= G_MAXUINT
;
740 events_request
->end_position
= NULL
;
741 events_request
->trace
= i
;
743 events_request
->hooks
= hooks
;
745 events_request
->before_chunk_traceset
= NULL
;
746 events_request
->before_chunk_trace
= NULL
;
747 events_request
->before_chunk_tracefile
= NULL
;
748 events_request
->event
= NULL
;
749 events_request
->event_by_id
= event_data
->event_by_id_hooks
;
750 events_request
->after_chunk_tracefile
= NULL
;
751 events_request
->after_chunk_trace
= NULL
;
752 events_request
->after_chunk_traceset
= NULL
;
753 events_request
->before_request
= NULL
;
754 events_request
->after_request
= event_data
->hooks_trace_after
;
756 lttvwindow_events_request(event_data
->tab
, events_request
);
761 static void CalculateAverageDurationForEachIrqId(InterruptEventData
*event_data
)
766 GArray
* FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
767 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
769 element
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
770 real_data
= element
->total_duration
.tv_sec
;
771 real_data
*= NANOSECONDS_PER_SECOND
;
772 real_data
+= element
->total_duration
.tv_nsec
;
773 element
->average_duration
= real_data
/ element
->frequency
;
779 * This function is called whenever an irq_entry event occurs. Use in the second request
782 static gboolean
SecondRequestIrqEntryCallback(void *hook_data
, void *call_data
)
788 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
789 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
790 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
791 GArray
* SecondRequestIrqEntry
= event_data
->SecondRequestIrqEntry
;
792 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
793 event_time
= ltt_event_time(e
);
794 cpu_id
= ltt_event_cpu_id(e
);
797 entry
.id
=get_interrupt_id(e
);
798 entry
.cpu_id
= cpu_id
;
799 entry
.event_time
= event_time
;
800 g_array_append_val (SecondRequestIrqEntry
, entry
);
806 * This function is called whenever an irq_exit event occurs in the second request.
809 static gboolean
SecondRequestIrqExitCallback(void *hook_data
, void *call_data
)
812 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
813 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
814 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
815 LttEvent
*event
= ltt_tracefile_get_event(tfc
->tf
);
817 CalculateXi(event
, event_data
);
823 * This function is called whenever an irq_exit event occurs in the second request.
826 static void CalculateXi(LttEvent
*event_irq_exit
, InterruptEventData
*event_data
)
834 GArray
*SecondRequestIrqExit
= event_data
->SecondRequestIrqExit
;
835 GArray
*SecondRequestIrqEntry
= event_data
->SecondRequestIrqEntry
;
836 cpu_id
= ltt_event_cpu_id(event_irq_exit
);
837 for(i
= 0; i
< SecondRequestIrqEntry
->len
; i
++)
839 element
= &g_array_index(SecondRequestIrqEntry
,irq_entry
,i
);
840 if(element
->cpu_id
== cpu_id
)
843 /* time calculation */
844 exit_time
= ltt_event_time(event_irq_exit
);
845 Xi
= ltt_time_sub(exit_time
, element
->event_time
);
846 irq_id
= element
->id
;
848 SumItems(irq_id
, Xi
,event_data
);
849 g_array_remove_index(SecondRequestIrqEntry
, i
);
857 * This function computes the Sum ((xi -Xa)^2) and store the result in SumArray
860 static void SumItems(gint irq_id
, LttTime Xi
, InterruptEventData
*event_data
)
865 gint duration_inner_part
;
866 guint64 period_inner_part
;
871 gboolean notFound
= FALSE
;
872 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
873 GArray
*SumArray
= event_data
->SumArray
;
874 Xi_in_ns
= Xi
.tv_sec
;
875 Xi_in_ns
*= NANOSECONDS_PER_SECOND
;
876 Xi_in_ns
+= Xi
.tv_nsec
;
878 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
880 average
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
881 if(irq_id
== average
->id
)
883 duration_inner_part
= Xi_in_ns
- average
->average_duration
;
884 FrequencyHZ
= FrequencyInHZ(average
->frequency
, event_data
->time_window
);
887 sum
.frequency
= average
->frequency
;
888 sum
.sumOfDurations
= pow (duration_inner_part
, 2);
889 period_inner_part
= CalculatePeriodInnerPart(Xi_in_ns
, FrequencyHZ
);
890 sum
.sumOfPeriods
= period_inner_part
;
891 if(event_data
->SumArray
->len
== NO_ITEMS
)
893 g_array_append_val (SumArray
, sum
);
897 for(i
= 0; i
< SumArray
->len
; i
++)
899 sumItem
= &g_array_index(SumArray
, SumId
, i
);
900 if(sumItem
->irqId
== irq_id
)
903 sumItem
->sumOfDurations
+= sum
.sumOfDurations
;
904 sumItem
->sumOfPeriods
+= sum
.sumOfPeriods
;
909 g_array_append_val (SumArray
, sum
);
918 static guint64
CalculatePeriodInnerPart(guint Xi
, guint FrequencyHZ
)
921 double periodInSec
; /*period in sec*/
925 periodInSec
= (double)1/FrequencyHZ
;
926 periodInSec
*= NANOSECONDS_PER_SECOND
;
927 periodInNSec
= (int)periodInSec
;
929 difference
= Xi
- periodInNSec
;
930 result
= pow (difference
, 2);
939 * This function displays the result on the viewer
942 static gboolean
DisplayViewer(void *hook_data
, void *call_data
)
948 LttTime average_duration
;
951 guint maxIRQduration
;
954 char maxIrqHandler
[80];
955 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
956 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
959 gtk_list_store_clear(event_data
->ListStore
);
960 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
962 element
= g_array_index(FirstRequestIrqExit
,Irq
,i
);
963 real_data
= element
.total_duration
.tv_sec
;
964 real_data
*= NANOSECONDS_PER_SECOND
;
965 real_data
+= element
.total_duration
.tv_nsec
;
968 maxIRQduration
= element
.max_irq_handler
.duration
.tv_sec
;
969 maxIRQduration
*= NANOSECONDS_PER_SECOND
;
970 maxIRQduration
+= element
.max_irq_handler
.duration
.tv_nsec
;
972 sprintf(maxIrqHandler
, "%d [%d.%d - %d.%d]",maxIRQduration
, element
.max_irq_handler
.start_time
.tv_sec
, \
973 element
.max_irq_handler
.start_time
.tv_nsec
, element
.max_irq_handler
.end_time
.tv_sec
, \
974 element
.max_irq_handler
.end_time
.tv_nsec
) ;
975 FrequencyHZ
= FrequencyInHZ(element
.frequency
,event_data
->time_window
);
979 periodInSec
= (double)1/FrequencyHZ
;
980 periodInSec
*= NANOSECONDS_PER_SECOND
;
981 periodInNsec
= (int)periodInSec
;
982 //printf("period1:%d\n", periodInNsec);
985 gtk_list_store_append (event_data
->ListStore
, &iter
);
986 gtk_list_store_set (event_data
->ListStore
, &iter
,
987 CPUID_COLUMN
, element
.cpu_id
,
988 IRQ_ID_COLUMN
, element
.id
,
989 FREQUENCY_COLUMN
, FrequencyHZ
,
990 DURATION_COLUMN
, real_data
,
991 DURATION_STANDARD_DEV_COLUMN
, CalculateDurationStandardDeviation(element
.id
, event_data
),
992 MAX_IRQ_HANDLER_COLUMN
, maxIrqHandler
,
993 AVERAGE_PERIOD
, periodInNsec
,
994 PERIOD_STANDARD_DEV_COLUMN
, CalculatePeriodStandardDeviation(element
.id
, event_data
),
1001 if(event_data
->FirstRequestIrqExit
->len
)
1003 g_array_remove_range (event_data
->FirstRequestIrqExit
,0,event_data
->FirstRequestIrqExit
->len
);
1006 if(event_data
->FirstRequestIrqEntry
->len
)
1008 g_array_remove_range (event_data
->FirstRequestIrqEntry
,0,event_data
->FirstRequestIrqEntry
->len
);
1011 if(event_data
->SecondRequestIrqEntry
->len
)
1013 g_array_remove_range (event_data
->SecondRequestIrqEntry
,0,event_data
->SecondRequestIrqEntry
->len
);
1016 if(event_data
->SecondRequestIrqExit
->len
)
1018 g_array_remove_range (event_data
->SecondRequestIrqExit
,0, event_data
->SecondRequestIrqExit
->len
);
1021 if(event_data
->SumArray
->len
)
1023 g_array_remove_range (event_data
->SumArray
,0, event_data
->SumArray
->len
);
1031 * This function converts the number of interrupts over a time window to
1034 static int FrequencyInHZ(gint frequency
, TimeWindow time_window
)
1036 guint64 frequencyHz
= 0;
1037 double timeSec
; // time in second
1039 result
= ltt_time_to_double(time_window
.time_width
);
1040 timeSec
= (result
/NANOSECONDS_PER_SECOND
); //time in second
1041 frequencyHz
= frequency
/ timeSec
;
1046 * This function calculates the duration standard deviation
1049 static int CalculateDurationStandardDeviation(gint id
, InterruptEventData
*event_data
)
1053 double inner_component
;
1055 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
1057 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
1058 if(id
== sumId
.irqId
)
1060 inner_component
= sumId
.sumOfDurations
/ sumId
.frequency
;
1061 deviation
= sqrt(inner_component
);
1070 * This function calculates the period standard deviation
1073 static int CalculatePeriodStandardDeviation(gint id
, InterruptEventData
*event_data
)
1077 guint64 inner_component
;
1078 guint64 period_standard_deviation
= 0;
1079 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
1081 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
1082 if(id
== sumId
.irqId
)
1084 inner_component
= sumId
.sumOfPeriods
/ sumId
.frequency
;
1085 period_standard_deviation
= sqrt(inner_component
);
1089 return period_standard_deviation
;
1092 * This function is called by the main window
1093 * when the time interval needs to be updated.
1095 gboolean
interrupt_update_time_window(void * hook_data
, void * call_data
)
1097 InterruptEventData
*event_data
= (InterruptEventData
*) hook_data
;
1098 const TimeWindowNotifyData
*time_window_nofify_data
= ((const TimeWindowNotifyData
*)call_data
);
1099 event_data
->time_window
= *time_window_nofify_data
->new_time_window
;
1100 g_info("interrupts: interrupt_update_time_window()\n");
1101 Tab
*tab
= event_data
->tab
;
1102 lttvwindow_events_request_remove_all(tab
, event_data
);
1103 FirstRequest(event_data
);
1108 gboolean
trace_header(void *hook_data
, void *call_data
)
1111 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
1112 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1118 void interrupt_destroy_walk(gpointer data
, gpointer user_data
)
1120 g_info("interrupt_destroy_walk");
1121 interrupt_destructor((InterruptEventData
*)data
);
1125 void interrupt_destructor(InterruptEventData
*event_viewer_data
)
1127 /* May already been done by GTK window closing */
1128 g_info("enter interrupt_destructor \n");
1129 if(GTK_IS_WIDGET(event_viewer_data
->Hbox
))
1131 gtk_widget_destroy(event_viewer_data
->Hbox
);
1136 * plugin's destroy function
1138 * This function releases the memory reserved by the module and unregisters
1139 * everything that has been registered in the gtkTraceSet API.
1141 static void destroy()
1144 g_info("Destroy interrupts");
1145 g_slist_foreach(interrupt_data_list
, interrupt_destroy_walk
, NULL
);
1146 g_slist_free(interrupt_data_list
);
1147 lttvwindow_unregister_constructor(interrupts
);
1151 LTTV_MODULE("interrupts", "interrupts info view", \
1152 "Graphical module to display interrupts performance", \
1153 init
, destroy
, "lttvwindow")