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: 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 static void InterruptFree(InterruptEventData
*event_viewer_data
);
184 /* Enumeration of the columns */
190 DURATION_STANDARD_DEV_COLUMN
,
191 MAX_IRQ_HANDLER_COLUMN
,
193 PERIOD_STANDARD_DEV_COLUMN
,
203 * This is the entry point of the viewer.
207 g_info("interrupts: init()");
208 lttvwindow_register_constructor("interrupts",
210 "Insert Interrupts View",
211 hInterruptsInsert_xpm
,
212 "Insert Interrupts View",
222 static GtkWidget
*interrupts(Tab
* tab
)
225 InterruptEventData
* event_data
= system_info(tab
) ;
227 return event_data
->Hbox
;
233 * This function initializes the Event Viewer functionnality through the
236 InterruptEventData
*system_info(Tab
*tab
)
240 GtkTreeViewColumn
*column
;
241 GtkCellRenderer
*renderer
;
242 InterruptEventData
* event_viewer_data
= g_new(InterruptEventData
,1) ;
244 event_viewer_data
->tab
= tab
;
246 /*Get the current time frame from the main window */
247 event_viewer_data
->time_window
= lttvwindow_get_time_window(tab
);
249 event_viewer_data
->FirstRequestIrqExit
= g_array_new(FALSE
, FALSE
, sizeof(Irq
));
250 event_viewer_data
->FirstRequestIrqEntry
= g_array_new(FALSE
, FALSE
, sizeof(irq_entry
));
252 event_viewer_data
->SecondRequestIrqEntry
= g_array_new(FALSE
, FALSE
, sizeof(irq_entry
));
253 event_viewer_data
->SecondRequestIrqExit
= g_array_new(FALSE
, FALSE
, sizeof(Irq
));
255 event_viewer_data
->SumArray
= g_array_new(FALSE
, FALSE
, sizeof(SumId
));
258 /*Create tha main window for the viewer */
259 event_viewer_data
->ScrollWindow
= gtk_scrolled_window_new (NULL
, NULL
);
260 gtk_widget_show (event_viewer_data
->ScrollWindow
);
261 gtk_scrolled_window_set_policy(
262 GTK_SCROLLED_WINDOW(event_viewer_data
->ScrollWindow
),
263 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
/*GTK_POLICY_NEVER*/);
265 /* Create a model for storing the data list */
266 event_viewer_data
->ListStore
= gtk_list_store_new (
267 N_COLUMNS
, /* Total number of columns */
268 G_TYPE_INT
, /* CPUID */
269 G_TYPE_INT
, /* IRQ_ID */
270 G_TYPE_INT
, /* Frequency */
271 G_TYPE_UINT64
, /* Duration */
272 G_TYPE_INT
, /* standard deviation */
273 G_TYPE_STRING
, /* Max IRQ handler */
274 G_TYPE_INT
, /* Average period */
275 G_TYPE_INT
/* period standard deviation */
278 event_viewer_data
->TreeView
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (event_viewer_data
->ListStore
));
280 g_object_unref (G_OBJECT (event_viewer_data
->ListStore
));
282 renderer
= gtk_cell_renderer_text_new ();
283 column
= gtk_tree_view_column_new_with_attributes ("CPUID",
285 "text", CPUID_COLUMN
,
287 gtk_tree_view_column_set_alignment (column
, 0.0);
288 gtk_tree_view_column_set_fixed_width (column
, 45);
289 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
292 renderer
= gtk_cell_renderer_text_new ();
293 column
= gtk_tree_view_column_new_with_attributes ("IrqId",
295 "text", IRQ_ID_COLUMN
,
297 gtk_tree_view_column_set_alignment (column
, 0.0);
298 gtk_tree_view_column_set_fixed_width (column
, 220);
299 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
301 renderer
= gtk_cell_renderer_text_new ();
302 column
= gtk_tree_view_column_new_with_attributes ("Frequency (Hz)",
304 "text", FREQUENCY_COLUMN
,
306 gtk_tree_view_column_set_alignment (column
, 1.0);
307 gtk_tree_view_column_set_fixed_width (column
, 220);
308 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
310 renderer
= gtk_cell_renderer_text_new ();
311 column
= gtk_tree_view_column_new_with_attributes ("Total Duration (nsec)",
313 "text", DURATION_COLUMN
,
315 gtk_tree_view_column_set_alignment (column
, 0.0);
316 gtk_tree_view_column_set_fixed_width (column
, 145);
317 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
320 renderer
= gtk_cell_renderer_text_new ();
321 column
= gtk_tree_view_column_new_with_attributes ("Duration standard deviation (nsec)",
323 "text", DURATION_STANDARD_DEV_COLUMN
,
325 gtk_tree_view_column_set_alignment (column
, 0.0);
326 gtk_tree_view_column_set_fixed_width (column
, 200);
327 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
329 renderer
= gtk_cell_renderer_text_new ();
330 column
= gtk_tree_view_column_new_with_attributes ("Max IRQ handler duration (nsec) [time interval]",
332 "text", MAX_IRQ_HANDLER_COLUMN
,
334 gtk_tree_view_column_set_alignment (column
, 0.0);
335 gtk_tree_view_column_set_fixed_width (column
, 250);
336 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
338 renderer
= gtk_cell_renderer_text_new ();
339 column
= gtk_tree_view_column_new_with_attributes (" Average period (nsec)",
341 "text", AVERAGE_PERIOD
,
343 gtk_tree_view_column_set_alignment (column
, 0.0);
344 gtk_tree_view_column_set_fixed_width (column
, 200);
345 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
347 renderer
= gtk_cell_renderer_text_new ();
348 column
= gtk_tree_view_column_new_with_attributes ("Period standard deviation (nsec)",
350 "text", PERIOD_STANDARD_DEV_COLUMN
,
352 gtk_tree_view_column_set_alignment (column
, 0.0);
353 gtk_tree_view_column_set_fixed_width (column
, 200);
354 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
358 event_viewer_data
->SelectionTree
= gtk_tree_view_get_selection (GTK_TREE_VIEW (event_viewer_data
->TreeView
));
359 gtk_tree_selection_set_mode (event_viewer_data
->SelectionTree
, GTK_SELECTION_SINGLE
);
361 gtk_container_add (GTK_CONTAINER (event_viewer_data
->ScrollWindow
), event_viewer_data
->TreeView
);
363 event_viewer_data
->Hbox
= gtk_hbox_new(0, 0);
364 gtk_box_pack_start(GTK_BOX(event_viewer_data
->Hbox
), event_viewer_data
->ScrollWindow
, TRUE
, TRUE
, 0);
366 gtk_widget_show(event_viewer_data
->Hbox
);
367 gtk_widget_show(event_viewer_data
->TreeView
);
369 interrupt_data_list
= g_slist_append(interrupt_data_list
, event_viewer_data
);
370 /* Registration for time notification */
371 lttvwindow_register_time_window_notify(tab
,
372 interrupt_update_time_window
,
375 g_object_set_data_full(G_OBJECT(event_viewer_data
->Hbox
),
378 (GDestroyNotify
) InterruptFree
);
380 FirstRequest(event_viewer_data
);
381 return event_viewer_data
;
387 * For each trace in the traceset, this function:
388 * - registers a callback function to each hook
389 * - calls lttv_trace_find_hook() registers a hook function to event_by_id_hooks
390 * - calls lttvwindow_events_request() to request data in a specific
391 * time interval to the main window
394 static void FirstRequest(InterruptEventData
*event_data
)
396 guint i
, k
, l
, nb_trace
;
406 EventsRequest
*events_request
;
408 LttvTraceHookByFacility
*thf
;
410 LttvTracesetContext
*tsc
= lttvwindow_get_traceset_context(event_data
->tab
);
413 /* Get the traceset */
414 LttvTraceset
*traceset
= tsc
->ts
;
416 nb_trace
= lttv_traceset_number(traceset
);
418 /* There are many traces in a traceset. Iteration for each trace. */
419 for(i
= 0; i
<MIN(TRACE_NUMBER
+1, nb_trace
);i
++)
421 events_request
= g_new(EventsRequest
, 1);
423 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
425 hooks
= g_array_set_size(hooks
, 2);
427 event_data
->hooks_trace_before
= lttv_hooks_new();
429 /* Registers a hook function */
430 lttv_hooks_add(event_data
->hooks_trace_before
, trace_header
, event_data
, LTTV_PRIO_DEFAULT
);
432 event_data
->hooks_trace_after
= lttv_hooks_new();
434 /* Registers a hook function */
435 lttv_hooks_add(event_data
->hooks_trace_after
, SecondRequest
, event_data
, LTTV_PRIO_DEFAULT
);
436 /* Get a trace state */
437 ts
= (LttvTraceState
*)tsc
->traces
[i
];
438 /* Create event_by_Id hooks */
439 event_data
->event_by_id_hooks
= lttv_hooks_by_id_new();
441 /*Register event_by_id_hooks with a callback function*/
442 ret
= lttv_trace_find_hook(ts
->parent
.t
,
443 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
444 LTT_FIELD_IRQ_ID
, 0, 0,
445 FirstRequestIrqEntryCallback
,
447 &g_array_index(hooks
, LttvTraceHook
, 0));
449 ret
= lttv_trace_find_hook(ts
->parent
.t
,
450 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
451 LTT_FIELD_IRQ_ID
, 0, 0,
452 FirstRequestIrqExitCallback
,
454 &g_array_index(hooks
, LttvTraceHook
, 1));
457 /*iterate through the facility list*/
458 for(k
= 0 ; k
< hooks
->len
; k
++)
460 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
461 for(l
=0; l
<hook
->fac_list
->len
; l
++)
463 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
464 lttv_hooks_add(lttv_hooks_by_id_find(event_data
->event_by_id_hooks
, thf
->id
),
471 /* Initalize the EventsRequest structure */
472 events_request
->owner
= event_data
;
473 events_request
->viewer_data
= event_data
;
474 events_request
->servicing
= FALSE
;
475 events_request
->start_time
= event_data
->time_window
.start_time
;
476 events_request
->start_position
= NULL
;
477 events_request
->stop_flag
= FALSE
;
478 events_request
->end_time
= event_data
->time_window
.end_time
;
479 events_request
->num_events
= G_MAXUINT
;
480 events_request
->end_position
= NULL
;
481 events_request
->trace
= i
;
483 events_request
->hooks
= hooks
;
485 events_request
->before_chunk_traceset
= NULL
;
486 events_request
->before_chunk_trace
= event_data
->hooks_trace_before
;
487 events_request
->before_chunk_tracefile
= NULL
;
488 events_request
->event
= NULL
;
489 events_request
->event_by_id
= event_data
->event_by_id_hooks
;
490 events_request
->after_chunk_tracefile
= NULL
;
491 events_request
->after_chunk_trace
= NULL
;
492 events_request
->after_chunk_traceset
= NULL
;
493 events_request
->before_request
= NULL
;
494 events_request
->after_request
= event_data
->hooks_trace_after
;
496 lttvwindow_events_request(event_data
->tab
, events_request
);
502 * This function is called whenever an irq_entry event occurs.
505 static gboolean
FirstRequestIrqEntryCallback(void *hook_data
, void *call_data
)
511 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
512 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
513 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
514 GArray
* FirstRequestIrqEntry
= event_data
->FirstRequestIrqEntry
;
515 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
516 event_time
= ltt_event_time(e
);
517 cpu_id
= ltt_event_cpu_id(e
);
520 entry
.id
=get_interrupt_id(e
);
521 entry
.cpu_id
= cpu_id
;
522 entry
.event_time
= event_time
;
523 g_array_append_val (FirstRequestIrqEntry
, entry
);
529 * This function gets the id of the interrupt. The id is stored in a dynamic structure.
530 * Refer to the print.c file for howto extract data from a dynamic structure.
532 static guint64
get_interrupt_id(LttEvent
*e
)
535 LttEventType
*event_type
;
539 event_type
= ltt_event_eventtype(e
);
540 num_fields
= ltt_eventtype_num_fields(event_type
);
541 for(i
= 0 ; i
< num_fields
-1 ; i
++)
543 field
= ltt_eventtype_field(event_type
, i
);
544 irq_id
= ltt_event_get_long_unsigned(e
,field
);
550 * This function is called whenever an irq_exit event occurs.
553 gboolean
FirstRequestIrqExitCallback(void *hook_data
, void *call_data
)
557 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
558 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
559 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
560 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
561 LttEventType
*type
= ltt_event_eventtype(e
);
562 event_time
= ltt_event_time(e
);
563 cpu_id
= ltt_event_cpu_id(e
);
565 CalculateData( event_time
, cpu_id
, event_data
);
571 * This function calculates the duration of an interrupt.
574 static void CalculateData(LttTime time_exit
, guint cpu_id
,InterruptEventData
*event_data
)
580 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
581 GArray
*FirstRequestIrqEntry
= event_data
->FirstRequestIrqEntry
;
582 for(i
= 0; i
< FirstRequestIrqEntry
->len
; i
++)
584 element
= &g_array_index(FirstRequestIrqEntry
,irq_entry
,i
);
585 if(element
->cpu_id
== cpu_id
)
587 TotalDurationMaxIrqDuration(element
,time_exit
, FirstRequestIrqExit
);
588 g_array_remove_index(FirstRequestIrqEntry
, i
);
595 * This function calculates the total duration of an interrupt and the longest Irq handler.
598 static void TotalDurationMaxIrqDuration(irq_entry
*e
, LttTime time_exit
, GArray
*FirstRequestIrqExit
){
603 gboolean notFound
= FALSE
;
604 memset ((void*)&irq
, 0,sizeof(Irq
));
607 if(FirstRequestIrqExit
->len
== NO_ITEMS
)
609 irq
.cpu_id
= e
->cpu_id
;
612 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
614 irq
.max_irq_handler
.start_time
= e
->event_time
;
615 irq
.max_irq_handler
.end_time
= time_exit
;
616 irq
.max_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
618 g_array_append_val (FirstRequestIrqExit
, irq
);
622 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
624 element
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
625 if(element
->id
== e
->id
)
628 duration
= ltt_time_sub(time_exit
, e
->event_time
);
629 element
->total_duration
= ltt_time_add(element
->total_duration
, duration
);
630 element
->frequency
++;
631 if(ltt_time_compare(duration
,element
->max_irq_handler
.duration
) > 0)
633 element
->max_irq_handler
.duration
= duration
;
634 element
->max_irq_handler
.start_time
= e
->event_time
;
635 element
->max_irq_handler
.end_time
= time_exit
;
641 irq
.cpu_id
= e
->cpu_id
;
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 g_array_append_val (FirstRequestIrqExit
, irq
);
656 * This function passes the second EventsRequest to LTTV
659 static gboolean
SecondRequest(void *hook_data
, void *call_data
)
662 guint i
, k
, l
, nb_trace
;
672 EventsRequest
*events_request
;
674 LttvTraceHookByFacility
*thf
;
676 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
678 LttvTracesetContext
*tsc
= lttvwindow_get_traceset_context(event_data
->tab
);
680 CalculateAverageDurationForEachIrqId(event_data
);
682 /* Get the traceset */
683 LttvTraceset
*traceset
= tsc
->ts
;
685 nb_trace
= lttv_traceset_number(traceset
);
687 /* There are many traces in a traceset. Iteration for each trace. */
688 for(i
= 0; i
<MIN(TRACE_NUMBER
+1, nb_trace
);i
++)
690 events_request
= g_new(EventsRequest
, 1);
692 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
694 hooks
= g_array_set_size(hooks
, 2);
696 event_data
->hooks_trace_after
= lttv_hooks_new();
698 /* Registers a hook function */
699 lttv_hooks_add(event_data
->hooks_trace_after
, DisplayViewer
, event_data
, LTTV_PRIO_DEFAULT
);
701 /* Get a trace state */
702 ts
= (LttvTraceState
*)tsc
->traces
[i
];
703 /* Create event_by_Id hooks */
704 event_data
->event_by_id_hooks
= lttv_hooks_by_id_new();
706 /*Register event_by_id_hooks with a callback function*/
707 ret
= lttv_trace_find_hook(ts
->parent
.t
,
708 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
709 LTT_FIELD_IRQ_ID
, 0, 0,
710 SecondRequestIrqEntryCallback
,
712 &g_array_index(hooks
, LttvTraceHook
, 0));
714 ret
= lttv_trace_find_hook(ts
->parent
.t
,
715 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
716 LTT_FIELD_IRQ_ID
, 0, 0,
717 SecondRequestIrqExitCallback
,
719 &g_array_index(hooks
, LttvTraceHook
, 1));
723 /* iterate through the facility list */
724 for(k
= 0 ; k
< hooks
->len
; k
++)
726 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
727 for(l
=0; l
<hook
->fac_list
->len
; l
++)
729 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
730 lttv_hooks_add(lttv_hooks_by_id_find(event_data
->event_by_id_hooks
, thf
->id
),
737 /* Initalize the EventsRequest structure */
738 events_request
->owner
= event_data
;
739 events_request
->viewer_data
= event_data
;
740 events_request
->servicing
= FALSE
;
741 events_request
->start_time
= event_data
->time_window
.start_time
;
742 events_request
->start_position
= NULL
;
743 events_request
->stop_flag
= FALSE
;
744 events_request
->end_time
= event_data
->time_window
.end_time
;
745 events_request
->num_events
= G_MAXUINT
;
746 events_request
->end_position
= NULL
;
747 events_request
->trace
= i
;
749 events_request
->hooks
= hooks
;
751 events_request
->before_chunk_traceset
= NULL
;
752 events_request
->before_chunk_trace
= NULL
;
753 events_request
->before_chunk_tracefile
= NULL
;
754 events_request
->event
= NULL
;
755 events_request
->event_by_id
= event_data
->event_by_id_hooks
;
756 events_request
->after_chunk_tracefile
= NULL
;
757 events_request
->after_chunk_trace
= NULL
;
758 events_request
->after_chunk_traceset
= NULL
;
759 events_request
->before_request
= NULL
;
760 events_request
->after_request
= event_data
->hooks_trace_after
;
762 lttvwindow_events_request(event_data
->tab
, events_request
);
767 static void CalculateAverageDurationForEachIrqId(InterruptEventData
*event_data
)
772 GArray
* FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
773 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
775 element
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
776 real_data
= element
->total_duration
.tv_sec
;
777 real_data
*= NANOSECONDS_PER_SECOND
;
778 real_data
+= element
->total_duration
.tv_nsec
;
779 element
->average_duration
= real_data
/ element
->frequency
;
785 * This function is called whenever an irq_entry event occurs. Use in the second request
788 static gboolean
SecondRequestIrqEntryCallback(void *hook_data
, void *call_data
)
794 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
795 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
796 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
797 GArray
* SecondRequestIrqEntry
= event_data
->SecondRequestIrqEntry
;
798 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
799 event_time
= ltt_event_time(e
);
800 cpu_id
= ltt_event_cpu_id(e
);
803 entry
.id
=get_interrupt_id(e
);
804 entry
.cpu_id
= cpu_id
;
805 entry
.event_time
= event_time
;
806 g_array_append_val (SecondRequestIrqEntry
, entry
);
812 * This function is called whenever an irq_exit event occurs in the second request.
815 static gboolean
SecondRequestIrqExitCallback(void *hook_data
, void *call_data
)
818 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
819 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
820 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
821 LttEvent
*event
= ltt_tracefile_get_event(tfc
->tf
);
823 CalculateXi(event
, event_data
);
829 * This function is called whenever an irq_exit event occurs in the second request.
832 static void CalculateXi(LttEvent
*event_irq_exit
, InterruptEventData
*event_data
)
840 GArray
*SecondRequestIrqExit
= event_data
->SecondRequestIrqExit
;
841 GArray
*SecondRequestIrqEntry
= event_data
->SecondRequestIrqEntry
;
842 cpu_id
= ltt_event_cpu_id(event_irq_exit
);
843 for(i
= 0; i
< SecondRequestIrqEntry
->len
; i
++)
845 element
= &g_array_index(SecondRequestIrqEntry
,irq_entry
,i
);
846 if(element
->cpu_id
== cpu_id
)
849 /* time calculation */
850 exit_time
= ltt_event_time(event_irq_exit
);
851 Xi
= ltt_time_sub(exit_time
, element
->event_time
);
852 irq_id
= element
->id
;
854 SumItems(irq_id
, Xi
,event_data
);
855 g_array_remove_index(SecondRequestIrqEntry
, i
);
863 * This function computes the Sum ((xi -Xa)^2) and store the result in SumArray
866 static void SumItems(gint irq_id
, LttTime Xi
, InterruptEventData
*event_data
)
871 gint duration_inner_part
;
872 guint64 period_inner_part
;
877 gboolean notFound
= FALSE
;
878 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
879 GArray
*SumArray
= event_data
->SumArray
;
880 Xi_in_ns
= Xi
.tv_sec
;
881 Xi_in_ns
*= NANOSECONDS_PER_SECOND
;
882 Xi_in_ns
+= Xi
.tv_nsec
;
884 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
886 average
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
887 if(irq_id
== average
->id
)
889 duration_inner_part
= Xi_in_ns
- average
->average_duration
;
890 FrequencyHZ
= FrequencyInHZ(average
->frequency
, event_data
->time_window
);
893 sum
.frequency
= average
->frequency
;
894 sum
.sumOfDurations
= pow (duration_inner_part
, 2);
895 period_inner_part
= CalculatePeriodInnerPart(Xi_in_ns
, FrequencyHZ
);
896 sum
.sumOfPeriods
= period_inner_part
;
897 if(event_data
->SumArray
->len
== NO_ITEMS
)
899 g_array_append_val (SumArray
, sum
);
903 for(i
= 0; i
< SumArray
->len
; i
++)
905 sumItem
= &g_array_index(SumArray
, SumId
, i
);
906 if(sumItem
->irqId
== irq_id
)
909 sumItem
->sumOfDurations
+= sum
.sumOfDurations
;
910 sumItem
->sumOfPeriods
+= sum
.sumOfPeriods
;
915 g_array_append_val (SumArray
, sum
);
924 static guint64
CalculatePeriodInnerPart(guint Xi
, guint FrequencyHZ
)
927 double periodInSec
; /*period in sec*/
931 periodInSec
= (double)1/FrequencyHZ
;
932 periodInSec
*= NANOSECONDS_PER_SECOND
;
933 periodInNSec
= (int)periodInSec
;
935 difference
= Xi
- periodInNSec
;
936 result
= pow (difference
, 2);
945 * This function displays the result on the viewer
948 static gboolean
DisplayViewer(void *hook_data
, void *call_data
)
954 LttTime average_duration
;
957 guint maxIRQduration
;
960 char maxIrqHandler
[80];
961 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
962 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
965 gtk_list_store_clear(event_data
->ListStore
);
966 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
968 element
= g_array_index(FirstRequestIrqExit
,Irq
,i
);
969 real_data
= element
.total_duration
.tv_sec
;
970 real_data
*= NANOSECONDS_PER_SECOND
;
971 real_data
+= element
.total_duration
.tv_nsec
;
974 maxIRQduration
= element
.max_irq_handler
.duration
.tv_sec
;
975 maxIRQduration
*= NANOSECONDS_PER_SECOND
;
976 maxIRQduration
+= element
.max_irq_handler
.duration
.tv_nsec
;
978 sprintf(maxIrqHandler
, "%d [%d.%d - %d.%d]",maxIRQduration
, element
.max_irq_handler
.start_time
.tv_sec
, \
979 element
.max_irq_handler
.start_time
.tv_nsec
, element
.max_irq_handler
.end_time
.tv_sec
, \
980 element
.max_irq_handler
.end_time
.tv_nsec
) ;
981 FrequencyHZ
= FrequencyInHZ(element
.frequency
,event_data
->time_window
);
985 periodInSec
= (double)1/FrequencyHZ
;
986 periodInSec
*= NANOSECONDS_PER_SECOND
;
987 periodInNsec
= (int)periodInSec
;
988 //printf("period1:%d\n", periodInNsec);
991 gtk_list_store_append (event_data
->ListStore
, &iter
);
992 gtk_list_store_set (event_data
->ListStore
, &iter
,
993 CPUID_COLUMN
, element
.cpu_id
,
994 IRQ_ID_COLUMN
, element
.id
,
995 FREQUENCY_COLUMN
, FrequencyHZ
,
996 DURATION_COLUMN
, real_data
,
997 DURATION_STANDARD_DEV_COLUMN
, CalculateDurationStandardDeviation(element
.id
, event_data
),
998 MAX_IRQ_HANDLER_COLUMN
, maxIrqHandler
,
999 AVERAGE_PERIOD
, periodInNsec
,
1000 PERIOD_STANDARD_DEV_COLUMN
, CalculatePeriodStandardDeviation(element
.id
, event_data
),
1007 if(event_data
->FirstRequestIrqExit
->len
)
1009 g_array_remove_range (event_data
->FirstRequestIrqExit
,0,event_data
->FirstRequestIrqExit
->len
);
1012 if(event_data
->FirstRequestIrqEntry
->len
)
1014 g_array_remove_range (event_data
->FirstRequestIrqEntry
,0,event_data
->FirstRequestIrqEntry
->len
);
1017 if(event_data
->SecondRequestIrqEntry
->len
)
1019 g_array_remove_range (event_data
->SecondRequestIrqEntry
,0,event_data
->SecondRequestIrqEntry
->len
);
1022 if(event_data
->SecondRequestIrqExit
->len
)
1024 g_array_remove_range (event_data
->SecondRequestIrqExit
,0, event_data
->SecondRequestIrqExit
->len
);
1027 if(event_data
->SumArray
->len
)
1029 g_array_remove_range (event_data
->SumArray
,0, event_data
->SumArray
->len
);
1037 * This function converts the number of interrupts over a time window to
1040 static int FrequencyInHZ(gint frequency
, TimeWindow time_window
)
1042 guint64 frequencyHz
= 0;
1043 double timeSec
; // time in second
1045 result
= ltt_time_to_double(time_window
.time_width
);
1046 timeSec
= (result
/NANOSECONDS_PER_SECOND
); //time in second
1047 frequencyHz
= frequency
/ timeSec
;
1052 * This function calculates the duration standard deviation
1055 static int CalculateDurationStandardDeviation(gint id
, InterruptEventData
*event_data
)
1059 double inner_component
;
1061 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
1063 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
1064 if(id
== sumId
.irqId
)
1066 inner_component
= sumId
.sumOfDurations
/ sumId
.frequency
;
1067 deviation
= sqrt(inner_component
);
1076 * This function calculates the period standard deviation
1079 static int CalculatePeriodStandardDeviation(gint id
, InterruptEventData
*event_data
)
1083 guint64 inner_component
;
1084 guint64 period_standard_deviation
= 0;
1085 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
1087 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
1088 if(id
== sumId
.irqId
)
1090 inner_component
= sumId
.sumOfPeriods
/ sumId
.frequency
;
1091 period_standard_deviation
= sqrt(inner_component
);
1095 return period_standard_deviation
;
1098 * This function is called by the main window
1099 * when the time interval needs to be updated.
1101 gboolean
interrupt_update_time_window(void * hook_data
, void * call_data
)
1103 InterruptEventData
*event_data
= (InterruptEventData
*) hook_data
;
1104 const TimeWindowNotifyData
*time_window_nofify_data
= ((const TimeWindowNotifyData
*)call_data
);
1105 event_data
->time_window
= *time_window_nofify_data
->new_time_window
;
1106 g_info("interrupts: interrupt_update_time_window()\n");
1107 Tab
*tab
= event_data
->tab
;
1108 lttvwindow_events_request_remove_all(tab
, event_data
);
1109 FirstRequest(event_data
);
1114 gboolean
trace_header(void *hook_data
, void *call_data
)
1117 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
1118 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1124 void interrupt_destroy_walk(gpointer data
, gpointer user_data
)
1126 g_info("interrupt_destroy_walk");
1127 InterruptEventData
*event_data
= (InterruptEventData
*) data
;
1130 interrupt_destructor((InterruptEventData
*)data
);
1135 void interrupt_destructor(InterruptEventData
*event_viewer_data
)
1137 /* May already been done by GTK window closing */
1138 g_info("enter interrupt_destructor \n");
1139 if(GTK_IS_WIDGET(event_viewer_data
->Hbox
))
1141 gtk_widget_destroy(event_viewer_data
->Hbox
);
1146 This function is called when the viewer is destroyed to free hooks and memory
1148 static void InterruptFree(InterruptEventData
*event_viewer_data
)
1150 Tab
*tab
= event_viewer_data
->tab
;
1154 g_array_free(event_viewer_data
->FirstRequestIrqExit
, TRUE
);
1155 g_array_free(event_viewer_data
->FirstRequestIrqEntry
, TRUE
);
1156 g_array_free(event_viewer_data
->SecondRequestIrqEntry
, TRUE
);
1157 g_array_free(event_viewer_data
->SecondRequestIrqExit
, TRUE
);
1158 g_array_free(event_viewer_data
->SumArray
, TRUE
);
1160 lttvwindow_unregister_time_window_notify(tab
, interrupt_update_time_window
, event_viewer_data
);
1162 lttvwindow_events_request_remove_all(event_viewer_data
->tab
,
1165 interrupt_data_list
= g_slist_remove(interrupt_data_list
, event_viewer_data
);
1172 * plugin's destroy function
1174 * This function releases the memory reserved by the module and unregisters
1175 * everything that has been registered in the gtkTraceSet API.
1177 static void destroy()
1180 g_info("Destroy interrupts");
1181 g_slist_foreach(interrupt_data_list
, interrupt_destroy_walk
, NULL
);
1182 g_slist_free(interrupt_data_list
);
1183 lttvwindow_unregister_constructor(interrupts
);
1187 LTTV_MODULE("interrupts", "interrupts info view", \
1188 "Graphical module to display interrupts performance", \
1189 init
, destroy
, "lttvwindow")