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 CalculateStandardDeviation() uses FirstRequestIrqExit
32 and SumArray arrays to calculate the standard deviation.
34 *******************************************************************/
47 #include <ltt/event.h>
49 #include <ltt/trace.h>
50 #include <ltt/facility.h>
51 #include <lttv/module.h>
52 #include <lttv/hook.h>
53 #include <lttv/tracecontext.h>
54 #include <lttv/state.h>
55 #include <lttv/filter.h>
56 #include <lttvwindow/lttvwindow.h>
59 #include "hInterruptsInsert.xpm"
61 #define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
62 #define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format)
76 LttTime total_duration
;
77 guint average_duration
;
78 MaxDuration max_irq_handler
;
93 guint64 sumOfDurations
;
102 /** Array containing instanced objects. Used when module is unloaded */
103 static GSList
*interrupt_data_list
= NULL
;
106 #define TRACE_NUMBER 0
108 typedef struct _InterruptEventData
{
110 /*Graphical Widgets */
111 GtkWidget
* ScrollWindow
;
112 GtkListStore
*ListStore
;
115 GtkTreeSelection
*SelectionTree
;
117 Tab
* tab
; /* tab that contains this plug-in*/
118 LttvHooks
* event_hooks
;
119 LttvHooks
* hooks_trace_after
;
120 LttvHooks
* hooks_trace_before
;
121 TimeWindow time_window
;
122 LttvHooksById
* event_by_id_hooks
;
123 GArray
*FirstRequestIrqExit
;
124 GArray
*FirstRequestIrqEntry
;
125 GArray
*SecondRequestIrqEntry
;
126 GArray
*SecondRequestIrqExit
;
129 } InterruptEventData
;
132 /* Function prototypes */
134 static gboolean
interrupt_update_time_window(void * hook_data
, void * call_data
);
135 static GtkWidget
*interrupts(Tab
*tab
);
136 static InterruptEventData
*system_info(Tab
*tab
);
137 void interrupt_destructor(InterruptEventData
*event_viewer_data
);
138 static void FirstRequest(InterruptEventData
*event_data
);
139 static guint64
get_interrupt_id(LttEvent
*e
);
140 static gboolean
trace_header(void *hook_data
, void *call_data
);
141 static gboolean
DisplayViewer (void *hook_data
, void *call_data
);
142 static void CalculateData(LttTime time_exit
, guint cpu_id
, InterruptEventData
*event_data
);
143 static void TotalDurationMaxIrqDuration(irq_entry
*e
, LttTime time_exit
, GArray
*FirstRequestIrqExit
);
144 static gboolean
FirstRequestIrqEntryCallback(void *hook_data
, void *call_data
);
145 static gboolean
FirstRequestIrqExitCallback(void *hook_data
, void *call_data
);
146 static gboolean
SecondRequest(void *hook_data
, void *call_data
);
147 static void CalculateAverageDurationForEachIrqId(InterruptEventData
*event_data
);
148 static gboolean
SecondRequestIrqEntryCallback(void *hook_data
, void *call_data
);
149 static gboolean
SecondRequestIrqExitCallback(void *hook_data
, void *call_data
);
150 static void CalculateXi(LttEvent
*event
, InterruptEventData
*event_data
);
151 static void SumItems(gint irq_id
, LttTime Xi
, InterruptEventData
*event_data
);
152 static int CalculateStandardDeviation(gint id
, InterruptEventData
*event_data
);
154 /* Enumeration of the columns */
160 DURATION_STANDARD_DEV_COLUMN
,
161 MAX_IRQ_HANDLER_COLUMN
,
171 * This is the entry point of the viewer.
175 g_info("interrupts: init()");
176 lttvwindow_register_constructor("interrupts",
178 "Insert Interrupts View",
179 hInterruptsInsert_xpm
,
180 "Insert Interrupts View",
190 static GtkWidget
*interrupts(Tab
* tab
)
193 InterruptEventData
* event_data
= system_info(tab
) ;
195 return event_data
->Hbox
;
201 * This function initializes the Event Viewer functionnality through the
204 InterruptEventData
*system_info(Tab
*tab
)
208 GtkTreeViewColumn
*column
;
209 GtkCellRenderer
*renderer
;
210 InterruptEventData
* event_viewer_data
= g_new(InterruptEventData
,1) ;
212 event_viewer_data
->tab
= tab
;
214 /*Get the current time frame from the main window */
215 event_viewer_data
->time_window
= lttvwindow_get_time_window(tab
);
217 event_viewer_data
->FirstRequestIrqExit
= g_array_new(FALSE
, FALSE
, sizeof(Irq
));
218 event_viewer_data
->FirstRequestIrqEntry
= g_array_new(FALSE
, FALSE
, sizeof(irq_entry
));
220 event_viewer_data
->SecondRequestIrqEntry
= g_array_new(FALSE
, FALSE
, sizeof(irq_entry
));
221 event_viewer_data
->SecondRequestIrqExit
= g_array_new(FALSE
, FALSE
, sizeof(Irq
));
223 event_viewer_data
->SumArray
= g_array_new(FALSE
, FALSE
, sizeof(SumId
));
226 /*Create tha main window for the viewer */
227 event_viewer_data
->ScrollWindow
= gtk_scrolled_window_new (NULL
, NULL
);
228 gtk_widget_show (event_viewer_data
->ScrollWindow
);
229 gtk_scrolled_window_set_policy(
230 GTK_SCROLLED_WINDOW(event_viewer_data
->ScrollWindow
),
231 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
/*GTK_POLICY_NEVER*/);
233 /* Create a model for storing the data list */
234 event_viewer_data
->ListStore
= gtk_list_store_new (
235 N_COLUMNS
, /* Total number of columns */
236 G_TYPE_INT
, /* CPUID */
237 G_TYPE_INT
, /* IRQ_ID */
238 G_TYPE_INT
, /* Frequency */
239 G_TYPE_UINT64
, /* Duration */
240 G_TYPE_INT
, /* standard deviation */
241 G_TYPE_STRING
/* Max IRQ handler */
244 event_viewer_data
->TreeView
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (event_viewer_data
->ListStore
));
246 g_object_unref (G_OBJECT (event_viewer_data
->ListStore
));
248 renderer
= gtk_cell_renderer_text_new ();
249 column
= gtk_tree_view_column_new_with_attributes ("CPUID",
251 "text", CPUID_COLUMN
,
253 gtk_tree_view_column_set_alignment (column
, 0.0);
254 gtk_tree_view_column_set_fixed_width (column
, 45);
255 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
258 renderer
= gtk_cell_renderer_text_new ();
259 column
= gtk_tree_view_column_new_with_attributes ("IrqId",
261 "text", IRQ_ID_COLUMN
,
263 gtk_tree_view_column_set_alignment (column
, 0.0);
264 gtk_tree_view_column_set_fixed_width (column
, 220);
265 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
267 renderer
= gtk_cell_renderer_text_new ();
268 column
= gtk_tree_view_column_new_with_attributes ("Frequency",
270 "text", FREQUENCY_COLUMN
,
272 gtk_tree_view_column_set_alignment (column
, 1.0);
273 gtk_tree_view_column_set_fixed_width (column
, 220);
274 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
276 renderer
= gtk_cell_renderer_text_new ();
277 column
= gtk_tree_view_column_new_with_attributes ("Duration (nsec)",
279 "text", DURATION_COLUMN
,
281 gtk_tree_view_column_set_alignment (column
, 0.0);
282 gtk_tree_view_column_set_fixed_width (column
, 145);
283 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
286 renderer
= gtk_cell_renderer_text_new ();
287 column
= gtk_tree_view_column_new_with_attributes ("Duration standard deviation (nsec)",
289 "text", DURATION_STANDARD_DEV_COLUMN
,
291 gtk_tree_view_column_set_alignment (column
, 0.0);
292 gtk_tree_view_column_set_fixed_width (column
, 200);
293 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
295 renderer
= gtk_cell_renderer_text_new ();
296 column
= gtk_tree_view_column_new_with_attributes ("Max IRQ handler duration (nsec)",
298 "text", MAX_IRQ_HANDLER_COLUMN
,
300 gtk_tree_view_column_set_alignment (column
, 0.0);
301 gtk_tree_view_column_set_fixed_width (column
, 250);
302 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
305 event_viewer_data
->SelectionTree
= gtk_tree_view_get_selection (GTK_TREE_VIEW (event_viewer_data
->TreeView
));
306 gtk_tree_selection_set_mode (event_viewer_data
->SelectionTree
, GTK_SELECTION_SINGLE
);
308 gtk_container_add (GTK_CONTAINER (event_viewer_data
->ScrollWindow
), event_viewer_data
->TreeView
);
310 event_viewer_data
->Hbox
= gtk_hbox_new(0, 0);
311 gtk_box_pack_start(GTK_BOX(event_viewer_data
->Hbox
), event_viewer_data
->ScrollWindow
, TRUE
, TRUE
, 0);
313 gtk_widget_show(event_viewer_data
->Hbox
);
314 gtk_widget_show(event_viewer_data
->TreeView
);
316 interrupt_data_list
= g_slist_append(interrupt_data_list
, event_viewer_data
);
317 /* Registration for time notification */
318 lttvwindow_register_time_window_notify(tab
,
319 interrupt_update_time_window
,
323 FirstRequest(event_viewer_data
);
324 return event_viewer_data
;
329 * For each trace in the traceset, this function:
330 * - registers a callback function to each hook
331 * - calls lttv_trace_find_hook() registers a hook function to event_by_id_hooks
332 * - calls lttvwindow_events_request() to request data in a specific
333 * time interval to the main window
336 static void FirstRequest(InterruptEventData
*event_data
)
338 guint i
, k
, l
, nb_trace
;
348 EventsRequest
*events_request
;
350 LttvTraceHookByFacility
*thf
;
352 LttvTracesetContext
*tsc
= lttvwindow_get_traceset_context(event_data
->tab
);
355 /* Get the traceset */
356 LttvTraceset
*traceset
= tsc
->ts
;
358 nb_trace
= lttv_traceset_number(traceset
);
360 /* There are many traces in a traceset. Iteration for each trace. */
361 for(i
= 0; i
<MIN(TRACE_NUMBER
+1, nb_trace
);i
++)
363 events_request
= g_new(EventsRequest
, 1);
365 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
367 hooks
= g_array_set_size(hooks
, 2);
369 event_data
->hooks_trace_before
= lttv_hooks_new();
371 /* Registers a hook function */
372 lttv_hooks_add(event_data
->hooks_trace_before
, trace_header
, event_data
, LTTV_PRIO_DEFAULT
);
374 event_data
->hooks_trace_after
= lttv_hooks_new();
376 /* Registers a hook function */
377 lttv_hooks_add(event_data
->hooks_trace_after
, SecondRequest
, event_data
, LTTV_PRIO_DEFAULT
);
378 /* Get a trace state */
379 ts
= (LttvTraceState
*)tsc
->traces
[i
];
380 /* Create event_by_Id hooks */
381 event_data
->event_by_id_hooks
= lttv_hooks_by_id_new();
383 /*Register event_by_id_hooks with a callback function*/
384 ret
= lttv_trace_find_hook(ts
->parent
.t
,
385 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
386 LTT_FIELD_IRQ_ID
, 0, 0,
387 FirstRequestIrqEntryCallback
,
389 &g_array_index(hooks
, LttvTraceHook
, 0));
391 ret
= lttv_trace_find_hook(ts
->parent
.t
,
392 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
393 LTT_FIELD_IRQ_ID
, 0, 0,
394 FirstRequestIrqExitCallback
,
396 &g_array_index(hooks
, LttvTraceHook
, 1));
399 /*iterate through the facility list*/
400 for(k
= 0 ; k
< hooks
->len
; k
++)
402 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
403 for(l
=0; l
<hook
->fac_list
->len
; l
++)
405 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
406 lttv_hooks_add(lttv_hooks_by_id_find(event_data
->event_by_id_hooks
, thf
->id
),
413 /* Initalize the EventsRequest structure */
414 events_request
->owner
= event_data
;
415 events_request
->viewer_data
= event_data
;
416 events_request
->servicing
= FALSE
;
417 events_request
->start_time
= event_data
->time_window
.start_time
;
418 events_request
->start_position
= NULL
;
419 events_request
->stop_flag
= FALSE
;
420 events_request
->end_time
= event_data
->time_window
.end_time
;
421 events_request
->num_events
= G_MAXUINT
;
422 events_request
->end_position
= NULL
;
423 events_request
->trace
= i
;
425 events_request
->hooks
= hooks
;
427 events_request
->before_chunk_traceset
= NULL
;
428 events_request
->before_chunk_trace
= event_data
->hooks_trace_before
;
429 events_request
->before_chunk_tracefile
= NULL
;
430 events_request
->event
= NULL
;
431 events_request
->event_by_id
= event_data
->event_by_id_hooks
;
432 events_request
->after_chunk_tracefile
= NULL
;
433 events_request
->after_chunk_trace
= NULL
;
434 events_request
->after_chunk_traceset
= NULL
;
435 events_request
->before_request
= NULL
;
436 events_request
->after_request
= event_data
->hooks_trace_after
;
438 lttvwindow_events_request(event_data
->tab
, events_request
);
444 * This function is called whenever an irq_entry event occurs.
447 static gboolean
FirstRequestIrqEntryCallback(void *hook_data
, void *call_data
)
453 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
454 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
455 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
456 GArray
* FirstRequestIrqEntry
= event_data
->FirstRequestIrqEntry
;
457 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
458 event_time
= ltt_event_time(e
);
459 cpu_id
= ltt_event_cpu_id(e
);
462 entry
.id
=get_interrupt_id(e
);
463 entry
.cpu_id
= cpu_id
;
464 entry
.event_time
= event_time
;
465 g_array_append_val (FirstRequestIrqEntry
, entry
);
471 * This function gets the id of the interrupt. The id is stored in a dynamic structure.
472 * Refer to the print.c file for howto extract data from a dynamic structure.
474 static guint64
get_interrupt_id(LttEvent
*e
)
477 LttEventType
*event_type
;
481 event_type
= ltt_event_eventtype(e
);
482 num_fields
= ltt_eventtype_num_fields(event_type
);
483 for(i
= 0 ; i
< num_fields
-1 ; i
++)
485 field
= ltt_eventtype_field(event_type
, i
);
486 irq_id
= ltt_event_get_long_unsigned(e
,field
);
492 * This function is called whenever an irq_exit event occurs.
495 gboolean
FirstRequestIrqExitCallback(void *hook_data
, void *call_data
)
499 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
500 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
501 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
502 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
503 LttEventType
*type
= ltt_event_eventtype(e
);
504 event_time
= ltt_event_time(e
);
505 cpu_id
= ltt_event_cpu_id(e
);
507 CalculateData( event_time
, cpu_id
, event_data
);
513 * This function calculates the duration of an interrupt.
516 static void CalculateData(LttTime time_exit
, guint cpu_id
,InterruptEventData
*event_data
)
522 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
523 GArray
*FirstRequestIrqEntry
= event_data
->FirstRequestIrqEntry
;
524 for(i
= 0; i
< FirstRequestIrqEntry
->len
; i
++)
526 element
= &g_array_index(FirstRequestIrqEntry
,irq_entry
,i
);
527 if(element
->cpu_id
== cpu_id
)
529 TotalDurationMaxIrqDuration(element
,time_exit
, FirstRequestIrqExit
);
530 g_array_remove_index(FirstRequestIrqEntry
, i
);
537 * This function calculates the total duration of an interrupt and the longest Irq handler.
540 static void TotalDurationMaxIrqDuration(irq_entry
*e
, LttTime time_exit
, GArray
*FirstRequestIrqExit
){
545 gboolean notFound
= FALSE
;
546 memset ((void*)&irq
, 0,sizeof(Irq
));
549 if(FirstRequestIrqExit
->len
== NO_ITEMS
)
551 irq
.cpu_id
= e
->cpu_id
;
554 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
556 irq
.max_irq_handler
.start_time
= e
->event_time
;
557 irq
.max_irq_handler
.end_time
= time_exit
;
558 irq
.max_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
561 g_array_append_val (FirstRequestIrqExit
, irq
);
565 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
567 element
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
568 if(element
->id
== e
->id
)
571 duration
= ltt_time_sub(time_exit
, e
->event_time
);
572 element
->total_duration
= ltt_time_add(element
->total_duration
, duration
);
573 element
->frequency
++;
574 if(ltt_time_compare(duration
,element
->max_irq_handler
.duration
) > 0)
576 element
->max_irq_handler
.duration
= duration
;
577 element
->max_irq_handler
.start_time
= e
->event_time
;
578 element
->max_irq_handler
.end_time
= time_exit
;
584 irq
.cpu_id
= e
->cpu_id
;
587 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
589 irq
.max_irq_handler
.start_time
= e
->event_time
;
590 irq
.max_irq_handler
.end_time
= time_exit
;
591 irq
.max_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
593 g_array_append_val (FirstRequestIrqExit
, irq
);
599 * This function passes the second EventsRequest to LTTV
602 static gboolean
SecondRequest(void *hook_data
, void *call_data
)
605 guint i
, k
, l
, nb_trace
;
615 EventsRequest
*events_request
;
617 LttvTraceHookByFacility
*thf
;
619 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
621 LttvTracesetContext
*tsc
= lttvwindow_get_traceset_context(event_data
->tab
);
623 CalculateAverageDurationForEachIrqId(event_data
);
625 /* Get the traceset */
626 LttvTraceset
*traceset
= tsc
->ts
;
628 nb_trace
= lttv_traceset_number(traceset
);
630 /* There are many traces in a traceset. Iteration for each trace. */
631 for(i
= 0; i
<MIN(TRACE_NUMBER
+1, nb_trace
);i
++)
633 events_request
= g_new(EventsRequest
, 1);
635 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
637 hooks
= g_array_set_size(hooks
, 2);
639 event_data
->hooks_trace_after
= lttv_hooks_new();
641 /* Registers a hook function */
642 lttv_hooks_add(event_data
->hooks_trace_after
, DisplayViewer
, event_data
, LTTV_PRIO_DEFAULT
);
644 /* Get a trace state */
645 ts
= (LttvTraceState
*)tsc
->traces
[i
];
646 /* Create event_by_Id hooks */
647 event_data
->event_by_id_hooks
= lttv_hooks_by_id_new();
649 /*Register event_by_id_hooks with a callback function*/
650 ret
= lttv_trace_find_hook(ts
->parent
.t
,
651 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
652 LTT_FIELD_IRQ_ID
, 0, 0,
653 SecondRequestIrqEntryCallback
,
655 &g_array_index(hooks
, LttvTraceHook
, 0));
657 ret
= lttv_trace_find_hook(ts
->parent
.t
,
658 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
659 LTT_FIELD_IRQ_ID
, 0, 0,
660 SecondRequestIrqExitCallback
,
662 &g_array_index(hooks
, LttvTraceHook
, 1));
666 /* iterate through the facility list */
667 for(k
= 0 ; k
< hooks
->len
; k
++)
669 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
670 for(l
=0; l
<hook
->fac_list
->len
; l
++)
672 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
673 lttv_hooks_add(lttv_hooks_by_id_find(event_data
->event_by_id_hooks
, thf
->id
),
680 /* Initalize the EventsRequest structure */
681 events_request
->owner
= event_data
;
682 events_request
->viewer_data
= event_data
;
683 events_request
->servicing
= FALSE
;
684 events_request
->start_time
= event_data
->time_window
.start_time
;
685 events_request
->start_position
= NULL
;
686 events_request
->stop_flag
= FALSE
;
687 events_request
->end_time
= event_data
->time_window
.end_time
;
688 events_request
->num_events
= G_MAXUINT
;
689 events_request
->end_position
= NULL
;
690 events_request
->trace
= i
;
692 events_request
->hooks
= hooks
;
694 events_request
->before_chunk_traceset
= NULL
;
695 events_request
->before_chunk_trace
= NULL
;
696 events_request
->before_chunk_tracefile
= NULL
;
697 events_request
->event
= NULL
;
698 events_request
->event_by_id
= event_data
->event_by_id_hooks
;
699 events_request
->after_chunk_tracefile
= NULL
;
700 events_request
->after_chunk_trace
= NULL
;
701 events_request
->after_chunk_traceset
= NULL
;
702 events_request
->before_request
= NULL
;
703 events_request
->after_request
= event_data
->hooks_trace_after
;
705 lttvwindow_events_request(event_data
->tab
, events_request
);
710 static void CalculateAverageDurationForEachIrqId(InterruptEventData
*event_data
)
715 GArray
* FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
716 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
718 element
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
719 real_data
= element
->total_duration
.tv_sec
;
720 real_data
*= NANOSECONDS_PER_SECOND
;
721 real_data
+= element
->total_duration
.tv_nsec
;
722 element
->average_duration
= real_data
/ element
->frequency
;
728 * This function is called whenever an irq_entry event occurs. Use in the second request
731 static gboolean
SecondRequestIrqEntryCallback(void *hook_data
, void *call_data
)
737 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
738 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
739 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
740 GArray
* SecondRequestIrqEntry
= event_data
->SecondRequestIrqEntry
;
741 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
742 event_time
= ltt_event_time(e
);
743 cpu_id
= ltt_event_cpu_id(e
);
746 entry
.id
=get_interrupt_id(e
);
747 entry
.cpu_id
= cpu_id
;
748 entry
.event_time
= event_time
;
749 g_array_append_val (SecondRequestIrqEntry
, entry
);
755 * This function is called whenever an irq_exit event occurs in the second request.
758 static gboolean
SecondRequestIrqExitCallback(void *hook_data
, void *call_data
)
761 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
762 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
763 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
764 LttEvent
*event
= ltt_tracefile_get_event(tfc
->tf
);
766 CalculateXi(event
, event_data
);
772 * This function is called whenever an irq_exit event occurs in the second request.
775 static void CalculateXi(LttEvent
*event_irq_exit
, InterruptEventData
*event_data
)
783 GArray
*SecondRequestIrqExit
= event_data
->SecondRequestIrqExit
;
784 GArray
*SecondRequestIrqEntry
= event_data
->SecondRequestIrqEntry
;
785 cpu_id
= ltt_event_cpu_id(event_irq_exit
);
786 for(i
= 0; i
< SecondRequestIrqEntry
->len
; i
++)
788 element
= &g_array_index(SecondRequestIrqEntry
,irq_entry
,i
);
789 if(element
->cpu_id
== cpu_id
)
792 /* time calculation */
793 exit_time
= ltt_event_time(event_irq_exit
);
794 Xi
= ltt_time_sub(exit_time
, element
->event_time
);
795 irq_id
= element
->id
;
797 SumItems(irq_id
, Xi
,event_data
);
798 g_array_remove_index(SecondRequestIrqEntry
, i
);
806 * This function computes the Sum ((xi -Xa)^2) and store the result in SumArray
809 static void SumItems(gint irq_id
, LttTime Xi
, InterruptEventData
*event_data
)
818 gboolean notFound
= FALSE
;
819 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
820 GArray
*SumArray
= event_data
->SumArray
;
821 time_in_ns
= Xi
.tv_sec
;
822 time_in_ns
*= NANOSECONDS_PER_SECOND
;
823 time_in_ns
+= Xi
.tv_nsec
;
825 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
827 average
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
828 if(irq_id
== average
->id
)
830 temp
= time_in_ns
- average
->average_duration
;
831 sum
.sumOfDurations
= pow (temp
, 2);
832 //printf("one : %d\n", sum.sumOfDurations);
834 sum
.frequency
= average
->frequency
;
835 if(event_data
->SumArray
->len
== NO_ITEMS
)
837 g_array_append_val (SumArray
, sum
);
842 for(i
= 0; i
< SumArray
->len
; i
++)
844 sumItem
= &g_array_index(SumArray
, SumId
, i
);
845 if(sumItem
->irqId
== irq_id
)
848 sumItem
->sumOfDurations
+= sum
.sumOfDurations
;
854 g_array_append_val (SumArray
, sum
);
865 * This function displays the result on the viewer
868 static gboolean
DisplayViewer(void *hook_data
, void *call_data
)
874 LttTime average_duration
;
877 guint maxIRQduration
;
878 char maxIrqHandler
[80];
879 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
880 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
881 gtk_list_store_clear(event_data
->ListStore
);
882 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
884 element
= g_array_index(FirstRequestIrqExit
,Irq
,i
);
885 real_data
= element
.total_duration
.tv_sec
;
886 real_data
*= NANOSECONDS_PER_SECOND
;
887 real_data
+= element
.total_duration
.tv_nsec
;
890 maxIRQduration
= element
.max_irq_handler
.duration
.tv_sec
;
891 maxIRQduration
*= NANOSECONDS_PER_SECOND
;
892 maxIRQduration
+= element
.max_irq_handler
.duration
.tv_nsec
;
894 sprintf(maxIrqHandler
, "%d [%d.%d - %d.%d]",maxIRQduration
, element
.max_irq_handler
.start_time
.tv_sec
, \
895 element
.max_irq_handler
.start_time
.tv_nsec
, element
.max_irq_handler
.end_time
.tv_sec
, \
896 element
.max_irq_handler
.end_time
.tv_nsec
) ;
898 gtk_list_store_append (event_data
->ListStore
, &iter
);
899 gtk_list_store_set (event_data
->ListStore
, &iter
,
900 CPUID_COLUMN
, element
.cpu_id
,
901 IRQ_ID_COLUMN
, element
.id
,
902 FREQUENCY_COLUMN
, element
.frequency
,
903 DURATION_COLUMN
, real_data
,
904 DURATION_STANDARD_DEV_COLUMN
, CalculateStandardDeviation(element
.id
, event_data
),
905 MAX_IRQ_HANDLER_COLUMN
, maxIrqHandler
,
912 if(event_data
->FirstRequestIrqExit
->len
)
914 g_array_remove_range (event_data
->FirstRequestIrqExit
,0,event_data
->FirstRequestIrqExit
->len
);
917 if(event_data
->FirstRequestIrqEntry
->len
)
919 g_array_remove_range (event_data
->FirstRequestIrqEntry
,0,event_data
->FirstRequestIrqEntry
->len
);
922 if(event_data
->SecondRequestIrqEntry
->len
)
924 g_array_remove_range (event_data
->SecondRequestIrqEntry
,0,event_data
->SecondRequestIrqEntry
->len
);
927 if(event_data
->SecondRequestIrqExit
->len
)
929 g_array_remove_range (event_data
->SecondRequestIrqExit
,0, event_data
->SecondRequestIrqExit
->len
);
932 if(event_data
->SumArray
->len
)
934 g_array_remove_range (event_data
->SumArray
,0, event_data
->SumArray
->len
);
941 * This function calculatees the standard deviation
944 static int CalculateStandardDeviation(gint id
, InterruptEventData
*event_data
)
948 double inner_component
;
950 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
952 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
953 if(id
== sumId
.irqId
)
955 // printf("id: %d\n", sumId.irqId);
956 inner_component
= sumId
.sumOfDurations
/ sumId
.frequency
;
957 deviation
= sqrt(inner_component
);
958 // printf("deviation: %d\n", deviation);
966 * This function is called by the main window
967 * when the time interval needs to be updated.
969 gboolean
interrupt_update_time_window(void * hook_data
, void * call_data
)
971 InterruptEventData
*event_data
= (InterruptEventData
*) hook_data
;
972 const TimeWindowNotifyData
*time_window_nofify_data
= ((const TimeWindowNotifyData
*)call_data
);
973 event_data
->time_window
= *time_window_nofify_data
->new_time_window
;
974 g_info("interrupts: interrupt_update_time_window()\n");
975 Tab
*tab
= event_data
->tab
;
976 lttvwindow_events_request_remove_all(tab
, event_data
);
977 FirstRequest(event_data
);
982 gboolean
trace_header(void *hook_data
, void *call_data
)
985 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
986 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
992 void interrupt_destroy_walk(gpointer data
, gpointer user_data
)
994 g_info("interrupt_destroy_walk");
995 interrupt_destructor((InterruptEventData
*)data
);
999 void interrupt_destructor(InterruptEventData
*event_viewer_data
)
1001 /* May already been done by GTK window closing */
1002 g_info("enter interrupt_destructor \n");
1003 if(GTK_IS_WIDGET(event_viewer_data
->Hbox
))
1005 gtk_widget_destroy(event_viewer_data
->Hbox
);
1010 * plugin's destroy function
1012 * This function releases the memory reserved by the module and unregisters
1013 * everything that has been registered in the gtkTraceSet API.
1015 static void destroy()
1018 g_info("Destroy interrupts");
1019 g_slist_foreach(interrupt_data_list
, interrupt_destroy_walk
, NULL
);
1020 g_slist_free(interrupt_data_list
);
1021 lttvwindow_unregister_constructor(interrupts
);
1025 LTTV_MODULE("interrupts", "interrupts info view", \
1026 "Graphical module to display interrupts performance", \
1027 init
, destroy
, "lttvwindow")