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
);
153 static int FrequencyInHZ(gint frequency
, TimeWindow time_window
);
155 /* Enumeration of the columns */
161 DURATION_STANDARD_DEV_COLUMN
,
162 MAX_IRQ_HANDLER_COLUMN
,
172 * This is the entry point of the viewer.
176 g_info("interrupts: init()");
177 lttvwindow_register_constructor("interrupts",
179 "Insert Interrupts View",
180 hInterruptsInsert_xpm
,
181 "Insert Interrupts View",
191 static GtkWidget
*interrupts(Tab
* tab
)
194 InterruptEventData
* event_data
= system_info(tab
) ;
196 return event_data
->Hbox
;
202 * This function initializes the Event Viewer functionnality through the
205 InterruptEventData
*system_info(Tab
*tab
)
209 GtkTreeViewColumn
*column
;
210 GtkCellRenderer
*renderer
;
211 InterruptEventData
* event_viewer_data
= g_new(InterruptEventData
,1) ;
213 event_viewer_data
->tab
= tab
;
215 /*Get the current time frame from the main window */
216 event_viewer_data
->time_window
= lttvwindow_get_time_window(tab
);
218 event_viewer_data
->FirstRequestIrqExit
= g_array_new(FALSE
, FALSE
, sizeof(Irq
));
219 event_viewer_data
->FirstRequestIrqEntry
= g_array_new(FALSE
, FALSE
, sizeof(irq_entry
));
221 event_viewer_data
->SecondRequestIrqEntry
= g_array_new(FALSE
, FALSE
, sizeof(irq_entry
));
222 event_viewer_data
->SecondRequestIrqExit
= g_array_new(FALSE
, FALSE
, sizeof(Irq
));
224 event_viewer_data
->SumArray
= g_array_new(FALSE
, FALSE
, sizeof(SumId
));
227 /*Create tha main window for the viewer */
228 event_viewer_data
->ScrollWindow
= gtk_scrolled_window_new (NULL
, NULL
);
229 gtk_widget_show (event_viewer_data
->ScrollWindow
);
230 gtk_scrolled_window_set_policy(
231 GTK_SCROLLED_WINDOW(event_viewer_data
->ScrollWindow
),
232 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
/*GTK_POLICY_NEVER*/);
234 /* Create a model for storing the data list */
235 event_viewer_data
->ListStore
= gtk_list_store_new (
236 N_COLUMNS
, /* Total number of columns */
237 G_TYPE_INT
, /* CPUID */
238 G_TYPE_INT
, /* IRQ_ID */
239 G_TYPE_INT
, /* Frequency */
240 G_TYPE_UINT64
, /* Duration */
241 G_TYPE_INT
, /* standard deviation */
242 G_TYPE_STRING
/* Max IRQ handler */
245 event_viewer_data
->TreeView
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (event_viewer_data
->ListStore
));
247 g_object_unref (G_OBJECT (event_viewer_data
->ListStore
));
249 renderer
= gtk_cell_renderer_text_new ();
250 column
= gtk_tree_view_column_new_with_attributes ("CPUID",
252 "text", CPUID_COLUMN
,
254 gtk_tree_view_column_set_alignment (column
, 0.0);
255 gtk_tree_view_column_set_fixed_width (column
, 45);
256 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
259 renderer
= gtk_cell_renderer_text_new ();
260 column
= gtk_tree_view_column_new_with_attributes ("IrqId",
262 "text", IRQ_ID_COLUMN
,
264 gtk_tree_view_column_set_alignment (column
, 0.0);
265 gtk_tree_view_column_set_fixed_width (column
, 220);
266 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
268 renderer
= gtk_cell_renderer_text_new ();
269 column
= gtk_tree_view_column_new_with_attributes ("Frequency ",
271 "text", FREQUENCY_COLUMN
,
273 gtk_tree_view_column_set_alignment (column
, 1.0);
274 gtk_tree_view_column_set_fixed_width (column
, 220);
275 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
277 renderer
= gtk_cell_renderer_text_new ();
278 column
= gtk_tree_view_column_new_with_attributes ("Total Duration (nsec)",
280 "text", DURATION_COLUMN
,
282 gtk_tree_view_column_set_alignment (column
, 0.0);
283 gtk_tree_view_column_set_fixed_width (column
, 145);
284 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
287 renderer
= gtk_cell_renderer_text_new ();
288 column
= gtk_tree_view_column_new_with_attributes ("Duration standard deviation (nsec)",
290 "text", DURATION_STANDARD_DEV_COLUMN
,
292 gtk_tree_view_column_set_alignment (column
, 0.0);
293 gtk_tree_view_column_set_fixed_width (column
, 200);
294 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
296 renderer
= gtk_cell_renderer_text_new ();
297 column
= gtk_tree_view_column_new_with_attributes ("Max IRQ handler duration (nsec) [time interval]",
299 "text", MAX_IRQ_HANDLER_COLUMN
,
301 gtk_tree_view_column_set_alignment (column
, 0.0);
302 gtk_tree_view_column_set_fixed_width (column
, 250);
303 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
306 event_viewer_data
->SelectionTree
= gtk_tree_view_get_selection (GTK_TREE_VIEW (event_viewer_data
->TreeView
));
307 gtk_tree_selection_set_mode (event_viewer_data
->SelectionTree
, GTK_SELECTION_SINGLE
);
309 gtk_container_add (GTK_CONTAINER (event_viewer_data
->ScrollWindow
), event_viewer_data
->TreeView
);
311 event_viewer_data
->Hbox
= gtk_hbox_new(0, 0);
312 gtk_box_pack_start(GTK_BOX(event_viewer_data
->Hbox
), event_viewer_data
->ScrollWindow
, TRUE
, TRUE
, 0);
314 gtk_widget_show(event_viewer_data
->Hbox
);
315 gtk_widget_show(event_viewer_data
->TreeView
);
317 interrupt_data_list
= g_slist_append(interrupt_data_list
, event_viewer_data
);
318 /* Registration for time notification */
319 lttvwindow_register_time_window_notify(tab
,
320 interrupt_update_time_window
,
324 FirstRequest(event_viewer_data
);
325 return event_viewer_data
;
330 * For each trace in the traceset, this function:
331 * - registers a callback function to each hook
332 * - calls lttv_trace_find_hook() registers a hook function to event_by_id_hooks
333 * - calls lttvwindow_events_request() to request data in a specific
334 * time interval to the main window
337 static void FirstRequest(InterruptEventData
*event_data
)
339 guint i
, k
, l
, nb_trace
;
349 EventsRequest
*events_request
;
351 LttvTraceHookByFacility
*thf
;
353 LttvTracesetContext
*tsc
= lttvwindow_get_traceset_context(event_data
->tab
);
356 /* Get the traceset */
357 LttvTraceset
*traceset
= tsc
->ts
;
359 nb_trace
= lttv_traceset_number(traceset
);
361 /* There are many traces in a traceset. Iteration for each trace. */
362 for(i
= 0; i
<MIN(TRACE_NUMBER
+1, nb_trace
);i
++)
364 events_request
= g_new(EventsRequest
, 1);
366 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
368 hooks
= g_array_set_size(hooks
, 2);
370 event_data
->hooks_trace_before
= lttv_hooks_new();
372 /* Registers a hook function */
373 lttv_hooks_add(event_data
->hooks_trace_before
, trace_header
, event_data
, LTTV_PRIO_DEFAULT
);
375 event_data
->hooks_trace_after
= lttv_hooks_new();
377 /* Registers a hook function */
378 lttv_hooks_add(event_data
->hooks_trace_after
, SecondRequest
, event_data
, LTTV_PRIO_DEFAULT
);
379 /* Get a trace state */
380 ts
= (LttvTraceState
*)tsc
->traces
[i
];
381 /* Create event_by_Id hooks */
382 event_data
->event_by_id_hooks
= lttv_hooks_by_id_new();
384 /*Register event_by_id_hooks with a callback function*/
385 ret
= lttv_trace_find_hook(ts
->parent
.t
,
386 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
387 LTT_FIELD_IRQ_ID
, 0, 0,
388 FirstRequestIrqEntryCallback
,
390 &g_array_index(hooks
, LttvTraceHook
, 0));
392 ret
= lttv_trace_find_hook(ts
->parent
.t
,
393 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
394 LTT_FIELD_IRQ_ID
, 0, 0,
395 FirstRequestIrqExitCallback
,
397 &g_array_index(hooks
, LttvTraceHook
, 1));
400 /*iterate through the facility list*/
401 for(k
= 0 ; k
< hooks
->len
; k
++)
403 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
404 for(l
=0; l
<hook
->fac_list
->len
; l
++)
406 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
407 lttv_hooks_add(lttv_hooks_by_id_find(event_data
->event_by_id_hooks
, thf
->id
),
414 /* Initalize the EventsRequest structure */
415 events_request
->owner
= event_data
;
416 events_request
->viewer_data
= event_data
;
417 events_request
->servicing
= FALSE
;
418 events_request
->start_time
= event_data
->time_window
.start_time
;
419 events_request
->start_position
= NULL
;
420 events_request
->stop_flag
= FALSE
;
421 events_request
->end_time
= event_data
->time_window
.end_time
;
422 events_request
->num_events
= G_MAXUINT
;
423 events_request
->end_position
= NULL
;
424 events_request
->trace
= i
;
426 events_request
->hooks
= hooks
;
428 events_request
->before_chunk_traceset
= NULL
;
429 events_request
->before_chunk_trace
= event_data
->hooks_trace_before
;
430 events_request
->before_chunk_tracefile
= NULL
;
431 events_request
->event
= NULL
;
432 events_request
->event_by_id
= event_data
->event_by_id_hooks
;
433 events_request
->after_chunk_tracefile
= NULL
;
434 events_request
->after_chunk_trace
= NULL
;
435 events_request
->after_chunk_traceset
= NULL
;
436 events_request
->before_request
= NULL
;
437 events_request
->after_request
= event_data
->hooks_trace_after
;
439 lttvwindow_events_request(event_data
->tab
, events_request
);
445 * This function is called whenever an irq_entry event occurs.
448 static gboolean
FirstRequestIrqEntryCallback(void *hook_data
, void *call_data
)
454 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
455 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
456 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
457 GArray
* FirstRequestIrqEntry
= event_data
->FirstRequestIrqEntry
;
458 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
459 event_time
= ltt_event_time(e
);
460 cpu_id
= ltt_event_cpu_id(e
);
463 entry
.id
=get_interrupt_id(e
);
464 entry
.cpu_id
= cpu_id
;
465 entry
.event_time
= event_time
;
466 g_array_append_val (FirstRequestIrqEntry
, entry
);
472 * This function gets the id of the interrupt. The id is stored in a dynamic structure.
473 * Refer to the print.c file for howto extract data from a dynamic structure.
475 static guint64
get_interrupt_id(LttEvent
*e
)
478 LttEventType
*event_type
;
482 event_type
= ltt_event_eventtype(e
);
483 num_fields
= ltt_eventtype_num_fields(event_type
);
484 for(i
= 0 ; i
< num_fields
-1 ; i
++)
486 field
= ltt_eventtype_field(event_type
, i
);
487 irq_id
= ltt_event_get_long_unsigned(e
,field
);
493 * This function is called whenever an irq_exit event occurs.
496 gboolean
FirstRequestIrqExitCallback(void *hook_data
, void *call_data
)
500 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
501 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
502 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
503 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
504 LttEventType
*type
= ltt_event_eventtype(e
);
505 event_time
= ltt_event_time(e
);
506 cpu_id
= ltt_event_cpu_id(e
);
508 CalculateData( event_time
, cpu_id
, event_data
);
514 * This function calculates the duration of an interrupt.
517 static void CalculateData(LttTime time_exit
, guint cpu_id
,InterruptEventData
*event_data
)
523 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
524 GArray
*FirstRequestIrqEntry
= event_data
->FirstRequestIrqEntry
;
525 for(i
= 0; i
< FirstRequestIrqEntry
->len
; i
++)
527 element
= &g_array_index(FirstRequestIrqEntry
,irq_entry
,i
);
528 if(element
->cpu_id
== cpu_id
)
530 TotalDurationMaxIrqDuration(element
,time_exit
, FirstRequestIrqExit
);
531 g_array_remove_index(FirstRequestIrqEntry
, i
);
538 * This function calculates the total duration of an interrupt and the longest Irq handler.
541 static void TotalDurationMaxIrqDuration(irq_entry
*e
, LttTime time_exit
, GArray
*FirstRequestIrqExit
){
546 gboolean notFound
= FALSE
;
547 memset ((void*)&irq
, 0,sizeof(Irq
));
550 if(FirstRequestIrqExit
->len
== NO_ITEMS
)
552 irq
.cpu_id
= e
->cpu_id
;
555 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
557 irq
.max_irq_handler
.start_time
= e
->event_time
;
558 irq
.max_irq_handler
.end_time
= time_exit
;
559 irq
.max_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
562 g_array_append_val (FirstRequestIrqExit
, irq
);
566 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
568 element
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
569 if(element
->id
== e
->id
)
572 duration
= ltt_time_sub(time_exit
, e
->event_time
);
573 element
->total_duration
= ltt_time_add(element
->total_duration
, duration
);
574 element
->frequency
++;
575 if(ltt_time_compare(duration
,element
->max_irq_handler
.duration
) > 0)
577 element
->max_irq_handler
.duration
= duration
;
578 element
->max_irq_handler
.start_time
= e
->event_time
;
579 element
->max_irq_handler
.end_time
= time_exit
;
585 irq
.cpu_id
= e
->cpu_id
;
588 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
590 irq
.max_irq_handler
.start_time
= e
->event_time
;
591 irq
.max_irq_handler
.end_time
= time_exit
;
592 irq
.max_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
594 g_array_append_val (FirstRequestIrqExit
, irq
);
600 * This function passes the second EventsRequest to LTTV
603 static gboolean
SecondRequest(void *hook_data
, void *call_data
)
606 guint i
, k
, l
, nb_trace
;
616 EventsRequest
*events_request
;
618 LttvTraceHookByFacility
*thf
;
620 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
622 LttvTracesetContext
*tsc
= lttvwindow_get_traceset_context(event_data
->tab
);
624 CalculateAverageDurationForEachIrqId(event_data
);
626 /* Get the traceset */
627 LttvTraceset
*traceset
= tsc
->ts
;
629 nb_trace
= lttv_traceset_number(traceset
);
631 /* There are many traces in a traceset. Iteration for each trace. */
632 for(i
= 0; i
<MIN(TRACE_NUMBER
+1, nb_trace
);i
++)
634 events_request
= g_new(EventsRequest
, 1);
636 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
638 hooks
= g_array_set_size(hooks
, 2);
640 event_data
->hooks_trace_after
= lttv_hooks_new();
642 /* Registers a hook function */
643 lttv_hooks_add(event_data
->hooks_trace_after
, DisplayViewer
, event_data
, LTTV_PRIO_DEFAULT
);
645 /* Get a trace state */
646 ts
= (LttvTraceState
*)tsc
->traces
[i
];
647 /* Create event_by_Id hooks */
648 event_data
->event_by_id_hooks
= lttv_hooks_by_id_new();
650 /*Register event_by_id_hooks with a callback function*/
651 ret
= lttv_trace_find_hook(ts
->parent
.t
,
652 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
653 LTT_FIELD_IRQ_ID
, 0, 0,
654 SecondRequestIrqEntryCallback
,
656 &g_array_index(hooks
, LttvTraceHook
, 0));
658 ret
= lttv_trace_find_hook(ts
->parent
.t
,
659 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
660 LTT_FIELD_IRQ_ID
, 0, 0,
661 SecondRequestIrqExitCallback
,
663 &g_array_index(hooks
, LttvTraceHook
, 1));
667 /* iterate through the facility list */
668 for(k
= 0 ; k
< hooks
->len
; k
++)
670 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
671 for(l
=0; l
<hook
->fac_list
->len
; l
++)
673 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
674 lttv_hooks_add(lttv_hooks_by_id_find(event_data
->event_by_id_hooks
, thf
->id
),
681 /* Initalize the EventsRequest structure */
682 events_request
->owner
= event_data
;
683 events_request
->viewer_data
= event_data
;
684 events_request
->servicing
= FALSE
;
685 events_request
->start_time
= event_data
->time_window
.start_time
;
686 events_request
->start_position
= NULL
;
687 events_request
->stop_flag
= FALSE
;
688 events_request
->end_time
= event_data
->time_window
.end_time
;
689 events_request
->num_events
= G_MAXUINT
;
690 events_request
->end_position
= NULL
;
691 events_request
->trace
= i
;
693 events_request
->hooks
= hooks
;
695 events_request
->before_chunk_traceset
= NULL
;
696 events_request
->before_chunk_trace
= NULL
;
697 events_request
->before_chunk_tracefile
= NULL
;
698 events_request
->event
= NULL
;
699 events_request
->event_by_id
= event_data
->event_by_id_hooks
;
700 events_request
->after_chunk_tracefile
= NULL
;
701 events_request
->after_chunk_trace
= NULL
;
702 events_request
->after_chunk_traceset
= NULL
;
703 events_request
->before_request
= NULL
;
704 events_request
->after_request
= event_data
->hooks_trace_after
;
706 lttvwindow_events_request(event_data
->tab
, events_request
);
711 static void CalculateAverageDurationForEachIrqId(InterruptEventData
*event_data
)
716 GArray
* FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
717 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
719 element
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
720 real_data
= element
->total_duration
.tv_sec
;
721 real_data
*= NANOSECONDS_PER_SECOND
;
722 real_data
+= element
->total_duration
.tv_nsec
;
723 element
->average_duration
= real_data
/ element
->frequency
;
729 * This function is called whenever an irq_entry event occurs. Use in the second request
732 static gboolean
SecondRequestIrqEntryCallback(void *hook_data
, void *call_data
)
738 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
739 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
740 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
741 GArray
* SecondRequestIrqEntry
= event_data
->SecondRequestIrqEntry
;
742 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
743 event_time
= ltt_event_time(e
);
744 cpu_id
= ltt_event_cpu_id(e
);
747 entry
.id
=get_interrupt_id(e
);
748 entry
.cpu_id
= cpu_id
;
749 entry
.event_time
= event_time
;
750 g_array_append_val (SecondRequestIrqEntry
, entry
);
756 * This function is called whenever an irq_exit event occurs in the second request.
759 static gboolean
SecondRequestIrqExitCallback(void *hook_data
, void *call_data
)
762 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
763 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
764 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
765 LttEvent
*event
= ltt_tracefile_get_event(tfc
->tf
);
767 CalculateXi(event
, event_data
);
773 * This function is called whenever an irq_exit event occurs in the second request.
776 static void CalculateXi(LttEvent
*event_irq_exit
, InterruptEventData
*event_data
)
784 GArray
*SecondRequestIrqExit
= event_data
->SecondRequestIrqExit
;
785 GArray
*SecondRequestIrqEntry
= event_data
->SecondRequestIrqEntry
;
786 cpu_id
= ltt_event_cpu_id(event_irq_exit
);
787 for(i
= 0; i
< SecondRequestIrqEntry
->len
; i
++)
789 element
= &g_array_index(SecondRequestIrqEntry
,irq_entry
,i
);
790 if(element
->cpu_id
== cpu_id
)
793 /* time calculation */
794 exit_time
= ltt_event_time(event_irq_exit
);
795 Xi
= ltt_time_sub(exit_time
, element
->event_time
);
796 irq_id
= element
->id
;
798 SumItems(irq_id
, Xi
,event_data
);
799 g_array_remove_index(SecondRequestIrqEntry
, i
);
807 * This function computes the Sum ((xi -Xa)^2) and store the result in SumArray
810 static void SumItems(gint irq_id
, LttTime Xi
, InterruptEventData
*event_data
)
819 gboolean notFound
= FALSE
;
820 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
821 GArray
*SumArray
= event_data
->SumArray
;
822 time_in_ns
= Xi
.tv_sec
;
823 time_in_ns
*= NANOSECONDS_PER_SECOND
;
824 time_in_ns
+= Xi
.tv_nsec
;
826 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
828 average
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
829 if(irq_id
== average
->id
)
831 temp
= time_in_ns
- average
->average_duration
;
832 sum
.sumOfDurations
= pow (temp
, 2);
833 //printf("one : %d\n", sum.sumOfDurations);
835 sum
.frequency
= average
->frequency
;
836 if(event_data
->SumArray
->len
== NO_ITEMS
)
838 g_array_append_val (SumArray
, sum
);
843 for(i
= 0; i
< SumArray
->len
; i
++)
845 sumItem
= &g_array_index(SumArray
, SumId
, i
);
846 if(sumItem
->irqId
== irq_id
)
849 sumItem
->sumOfDurations
+= sum
.sumOfDurations
;
855 g_array_append_val (SumArray
, sum
);
866 * This function displays the result on the viewer
869 static gboolean
DisplayViewer(void *hook_data
, void *call_data
)
875 LttTime average_duration
;
878 guint maxIRQduration
;
879 char maxIrqHandler
[80];
880 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
881 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
882 gtk_list_store_clear(event_data
->ListStore
);
883 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
885 element
= g_array_index(FirstRequestIrqExit
,Irq
,i
);
886 real_data
= element
.total_duration
.tv_sec
;
887 real_data
*= NANOSECONDS_PER_SECOND
;
888 real_data
+= element
.total_duration
.tv_nsec
;
891 maxIRQduration
= element
.max_irq_handler
.duration
.tv_sec
;
892 maxIRQduration
*= NANOSECONDS_PER_SECOND
;
893 maxIRQduration
+= element
.max_irq_handler
.duration
.tv_nsec
;
895 sprintf(maxIrqHandler
, "%d [%d.%d - %d.%d]",maxIRQduration
, element
.max_irq_handler
.start_time
.tv_sec
, \
896 element
.max_irq_handler
.start_time
.tv_nsec
, element
.max_irq_handler
.end_time
.tv_sec
, \
897 element
.max_irq_handler
.end_time
.tv_nsec
) ;
901 gtk_list_store_append (event_data
->ListStore
, &iter
);
902 gtk_list_store_set (event_data
->ListStore
, &iter
,
903 CPUID_COLUMN
, element
.cpu_id
,
904 IRQ_ID_COLUMN
, element
.id
,
905 FREQUENCY_COLUMN
, element
.frequency
,
906 DURATION_COLUMN
, real_data
,
907 DURATION_STANDARD_DEV_COLUMN
, CalculateStandardDeviation(element
.id
, event_data
),
908 MAX_IRQ_HANDLER_COLUMN
, maxIrqHandler
,
915 if(event_data
->FirstRequestIrqExit
->len
)
917 g_array_remove_range (event_data
->FirstRequestIrqExit
,0,event_data
->FirstRequestIrqExit
->len
);
920 if(event_data
->FirstRequestIrqEntry
->len
)
922 g_array_remove_range (event_data
->FirstRequestIrqEntry
,0,event_data
->FirstRequestIrqEntry
->len
);
925 if(event_data
->SecondRequestIrqEntry
->len
)
927 g_array_remove_range (event_data
->SecondRequestIrqEntry
,0,event_data
->SecondRequestIrqEntry
->len
);
930 if(event_data
->SecondRequestIrqExit
->len
)
932 g_array_remove_range (event_data
->SecondRequestIrqExit
,0, event_data
->SecondRequestIrqExit
->len
);
935 if(event_data
->SumArray
->len
)
937 g_array_remove_range (event_data
->SumArray
,0, event_data
->SumArray
->len
);
944 static int FrequencyInHZ(gint frequency
, TimeWindow time_window
)
946 guint64 frequencyHz
= 0;
948 guint64 time
= time_window
.time_width
.tv_sec
;
949 time
*= NANOSECONDS_PER_SECOND
;
950 time
+= time_window
.time_width
.tv_nsec
;
951 timeSec
= time
/NANOSECONDS_PER_SECOND
;
952 frequencyHz
= frequency
/timeSec
;
957 * This function calculatees the standard deviation
960 static int CalculateStandardDeviation(gint id
, InterruptEventData
*event_data
)
964 double inner_component
;
966 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
968 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
969 if(id
== sumId
.irqId
)
971 inner_component
= sumId
.sumOfDurations
/ sumId
.frequency
;
972 deviation
= sqrt(inner_component
);
979 * This function is called by the main window
980 * when the time interval needs to be updated.
982 gboolean
interrupt_update_time_window(void * hook_data
, void * call_data
)
984 InterruptEventData
*event_data
= (InterruptEventData
*) hook_data
;
985 const TimeWindowNotifyData
*time_window_nofify_data
= ((const TimeWindowNotifyData
*)call_data
);
986 event_data
->time_window
= *time_window_nofify_data
->new_time_window
;
987 g_info("interrupts: interrupt_update_time_window()\n");
988 Tab
*tab
= event_data
->tab
;
989 lttvwindow_events_request_remove_all(tab
, event_data
);
990 FirstRequest(event_data
);
995 gboolean
trace_header(void *hook_data
, void *call_data
)
998 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
999 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1005 void interrupt_destroy_walk(gpointer data
, gpointer user_data
)
1007 g_info("interrupt_destroy_walk");
1008 interrupt_destructor((InterruptEventData
*)data
);
1012 void interrupt_destructor(InterruptEventData
*event_viewer_data
)
1014 /* May already been done by GTK window closing */
1015 g_info("enter interrupt_destructor \n");
1016 if(GTK_IS_WIDGET(event_viewer_data
->Hbox
))
1018 gtk_widget_destroy(event_viewer_data
->Hbox
);
1023 * plugin's destroy function
1025 * This function releases the memory reserved by the module and unregisters
1026 * everything that has been registered in the gtkTraceSet API.
1028 static void destroy()
1031 g_info("Destroy interrupts");
1032 g_slist_foreach(interrupt_data_list
, interrupt_destroy_walk
, NULL
);
1033 g_slist_free(interrupt_data_list
);
1034 lttvwindow_unregister_constructor(interrupts
);
1038 LTTV_MODULE("interrupts", "interrupts info view", \
1039 "Graphical module to display interrupts performance", \
1040 init
, destroy
, "lttvwindow")