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
,
164 PERIOD_STANDARD_DEV_COLUMN
,
174 * This is the entry point of the viewer.
178 g_info("interrupts: init()");
179 lttvwindow_register_constructor("interrupts",
181 "Insert Interrupts View",
182 hInterruptsInsert_xpm
,
183 "Insert Interrupts View",
193 static GtkWidget
*interrupts(Tab
* tab
)
196 InterruptEventData
* event_data
= system_info(tab
) ;
198 return event_data
->Hbox
;
204 * This function initializes the Event Viewer functionnality through the
207 InterruptEventData
*system_info(Tab
*tab
)
211 GtkTreeViewColumn
*column
;
212 GtkCellRenderer
*renderer
;
213 InterruptEventData
* event_viewer_data
= g_new(InterruptEventData
,1) ;
215 event_viewer_data
->tab
= tab
;
217 /*Get the current time frame from the main window */
218 event_viewer_data
->time_window
= lttvwindow_get_time_window(tab
);
220 event_viewer_data
->FirstRequestIrqExit
= g_array_new(FALSE
, FALSE
, sizeof(Irq
));
221 event_viewer_data
->FirstRequestIrqEntry
= g_array_new(FALSE
, FALSE
, sizeof(irq_entry
));
223 event_viewer_data
->SecondRequestIrqEntry
= g_array_new(FALSE
, FALSE
, sizeof(irq_entry
));
224 event_viewer_data
->SecondRequestIrqExit
= g_array_new(FALSE
, FALSE
, sizeof(Irq
));
226 event_viewer_data
->SumArray
= g_array_new(FALSE
, FALSE
, sizeof(SumId
));
229 /*Create tha main window for the viewer */
230 event_viewer_data
->ScrollWindow
= gtk_scrolled_window_new (NULL
, NULL
);
231 gtk_widget_show (event_viewer_data
->ScrollWindow
);
232 gtk_scrolled_window_set_policy(
233 GTK_SCROLLED_WINDOW(event_viewer_data
->ScrollWindow
),
234 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
/*GTK_POLICY_NEVER*/);
236 /* Create a model for storing the data list */
237 event_viewer_data
->ListStore
= gtk_list_store_new (
238 N_COLUMNS
, /* Total number of columns */
239 G_TYPE_INT
, /* CPUID */
240 G_TYPE_INT
, /* IRQ_ID */
241 G_TYPE_INT
, /* Frequency */
242 G_TYPE_UINT64
, /* Duration */
243 G_TYPE_INT
, /* standard deviation */
244 G_TYPE_STRING
, /* Max IRQ handler */
245 G_TYPE_DOUBLE
, /* Average period */
246 G_TYPE_DOUBLE
/* period standard deviation */
249 event_viewer_data
->TreeView
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (event_viewer_data
->ListStore
));
251 g_object_unref (G_OBJECT (event_viewer_data
->ListStore
));
253 renderer
= gtk_cell_renderer_text_new ();
254 column
= gtk_tree_view_column_new_with_attributes ("CPUID",
256 "text", CPUID_COLUMN
,
258 gtk_tree_view_column_set_alignment (column
, 0.0);
259 gtk_tree_view_column_set_fixed_width (column
, 45);
260 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
263 renderer
= gtk_cell_renderer_text_new ();
264 column
= gtk_tree_view_column_new_with_attributes ("IrqId",
266 "text", IRQ_ID_COLUMN
,
268 gtk_tree_view_column_set_alignment (column
, 0.0);
269 gtk_tree_view_column_set_fixed_width (column
, 220);
270 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
272 renderer
= gtk_cell_renderer_text_new ();
273 column
= gtk_tree_view_column_new_with_attributes ("Frequency (Hz)",
275 "text", FREQUENCY_COLUMN
,
277 gtk_tree_view_column_set_alignment (column
, 1.0);
278 gtk_tree_view_column_set_fixed_width (column
, 220);
279 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
281 renderer
= gtk_cell_renderer_text_new ();
282 column
= gtk_tree_view_column_new_with_attributes ("Total Duration (nsec)",
284 "text", DURATION_COLUMN
,
286 gtk_tree_view_column_set_alignment (column
, 0.0);
287 gtk_tree_view_column_set_fixed_width (column
, 145);
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 ("Duration standard deviation (nsec)",
294 "text", DURATION_STANDARD_DEV_COLUMN
,
296 gtk_tree_view_column_set_alignment (column
, 0.0);
297 gtk_tree_view_column_set_fixed_width (column
, 200);
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 ("Max IRQ handler duration (nsec) [time interval]",
303 "text", MAX_IRQ_HANDLER_COLUMN
,
305 gtk_tree_view_column_set_alignment (column
, 0.0);
306 gtk_tree_view_column_set_fixed_width (column
, 250);
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 (" Average period (nsec)",
312 "text", AVERAGE_PERIOD
,
314 gtk_tree_view_column_set_alignment (column
, 0.0);
315 gtk_tree_view_column_set_fixed_width (column
, 200);
316 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
318 renderer
= gtk_cell_renderer_text_new ();
319 column
= gtk_tree_view_column_new_with_attributes ("Period standard deviation (nsec)",
321 "text", PERIOD_STANDARD_DEV_COLUMN
,
323 gtk_tree_view_column_set_alignment (column
, 0.0);
324 gtk_tree_view_column_set_fixed_width (column
, 200);
325 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
329 event_viewer_data
->SelectionTree
= gtk_tree_view_get_selection (GTK_TREE_VIEW (event_viewer_data
->TreeView
));
330 gtk_tree_selection_set_mode (event_viewer_data
->SelectionTree
, GTK_SELECTION_SINGLE
);
332 gtk_container_add (GTK_CONTAINER (event_viewer_data
->ScrollWindow
), event_viewer_data
->TreeView
);
334 event_viewer_data
->Hbox
= gtk_hbox_new(0, 0);
335 gtk_box_pack_start(GTK_BOX(event_viewer_data
->Hbox
), event_viewer_data
->ScrollWindow
, TRUE
, TRUE
, 0);
337 gtk_widget_show(event_viewer_data
->Hbox
);
338 gtk_widget_show(event_viewer_data
->TreeView
);
340 interrupt_data_list
= g_slist_append(interrupt_data_list
, event_viewer_data
);
341 /* Registration for time notification */
342 lttvwindow_register_time_window_notify(tab
,
343 interrupt_update_time_window
,
347 FirstRequest(event_viewer_data
);
348 return event_viewer_data
;
353 * For each trace in the traceset, this function:
354 * - registers a callback function to each hook
355 * - calls lttv_trace_find_hook() registers a hook function to event_by_id_hooks
356 * - calls lttvwindow_events_request() to request data in a specific
357 * time interval to the main window
360 static void FirstRequest(InterruptEventData
*event_data
)
362 guint i
, k
, l
, nb_trace
;
372 EventsRequest
*events_request
;
374 LttvTraceHookByFacility
*thf
;
376 LttvTracesetContext
*tsc
= lttvwindow_get_traceset_context(event_data
->tab
);
379 /* Get the traceset */
380 LttvTraceset
*traceset
= tsc
->ts
;
382 nb_trace
= lttv_traceset_number(traceset
);
384 /* There are many traces in a traceset. Iteration for each trace. */
385 for(i
= 0; i
<MIN(TRACE_NUMBER
+1, nb_trace
);i
++)
387 events_request
= g_new(EventsRequest
, 1);
389 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
391 hooks
= g_array_set_size(hooks
, 2);
393 event_data
->hooks_trace_before
= lttv_hooks_new();
395 /* Registers a hook function */
396 lttv_hooks_add(event_data
->hooks_trace_before
, trace_header
, event_data
, LTTV_PRIO_DEFAULT
);
398 event_data
->hooks_trace_after
= lttv_hooks_new();
400 /* Registers a hook function */
401 lttv_hooks_add(event_data
->hooks_trace_after
, SecondRequest
, event_data
, LTTV_PRIO_DEFAULT
);
402 /* Get a trace state */
403 ts
= (LttvTraceState
*)tsc
->traces
[i
];
404 /* Create event_by_Id hooks */
405 event_data
->event_by_id_hooks
= lttv_hooks_by_id_new();
407 /*Register event_by_id_hooks with a callback function*/
408 ret
= lttv_trace_find_hook(ts
->parent
.t
,
409 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
410 LTT_FIELD_IRQ_ID
, 0, 0,
411 FirstRequestIrqEntryCallback
,
413 &g_array_index(hooks
, LttvTraceHook
, 0));
415 ret
= lttv_trace_find_hook(ts
->parent
.t
,
416 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
417 LTT_FIELD_IRQ_ID
, 0, 0,
418 FirstRequestIrqExitCallback
,
420 &g_array_index(hooks
, LttvTraceHook
, 1));
423 /*iterate through the facility list*/
424 for(k
= 0 ; k
< hooks
->len
; k
++)
426 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
427 for(l
=0; l
<hook
->fac_list
->len
; l
++)
429 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
430 lttv_hooks_add(lttv_hooks_by_id_find(event_data
->event_by_id_hooks
, thf
->id
),
437 /* Initalize the EventsRequest structure */
438 events_request
->owner
= event_data
;
439 events_request
->viewer_data
= event_data
;
440 events_request
->servicing
= FALSE
;
441 events_request
->start_time
= event_data
->time_window
.start_time
;
442 events_request
->start_position
= NULL
;
443 events_request
->stop_flag
= FALSE
;
444 events_request
->end_time
= event_data
->time_window
.end_time
;
445 events_request
->num_events
= G_MAXUINT
;
446 events_request
->end_position
= NULL
;
447 events_request
->trace
= i
;
449 events_request
->hooks
= hooks
;
451 events_request
->before_chunk_traceset
= NULL
;
452 events_request
->before_chunk_trace
= event_data
->hooks_trace_before
;
453 events_request
->before_chunk_tracefile
= NULL
;
454 events_request
->event
= NULL
;
455 events_request
->event_by_id
= event_data
->event_by_id_hooks
;
456 events_request
->after_chunk_tracefile
= NULL
;
457 events_request
->after_chunk_trace
= NULL
;
458 events_request
->after_chunk_traceset
= NULL
;
459 events_request
->before_request
= NULL
;
460 events_request
->after_request
= event_data
->hooks_trace_after
;
462 lttvwindow_events_request(event_data
->tab
, events_request
);
468 * This function is called whenever an irq_entry event occurs.
471 static gboolean
FirstRequestIrqEntryCallback(void *hook_data
, void *call_data
)
477 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
478 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
479 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
480 GArray
* FirstRequestIrqEntry
= event_data
->FirstRequestIrqEntry
;
481 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
482 event_time
= ltt_event_time(e
);
483 cpu_id
= ltt_event_cpu_id(e
);
486 entry
.id
=get_interrupt_id(e
);
487 entry
.cpu_id
= cpu_id
;
488 entry
.event_time
= event_time
;
489 g_array_append_val (FirstRequestIrqEntry
, entry
);
495 * This function gets the id of the interrupt. The id is stored in a dynamic structure.
496 * Refer to the print.c file for howto extract data from a dynamic structure.
498 static guint64
get_interrupt_id(LttEvent
*e
)
501 LttEventType
*event_type
;
505 event_type
= ltt_event_eventtype(e
);
506 num_fields
= ltt_eventtype_num_fields(event_type
);
507 for(i
= 0 ; i
< num_fields
-1 ; i
++)
509 field
= ltt_eventtype_field(event_type
, i
);
510 irq_id
= ltt_event_get_long_unsigned(e
,field
);
516 * This function is called whenever an irq_exit event occurs.
519 gboolean
FirstRequestIrqExitCallback(void *hook_data
, void *call_data
)
523 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
524 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
525 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
526 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
527 LttEventType
*type
= ltt_event_eventtype(e
);
528 event_time
= ltt_event_time(e
);
529 cpu_id
= ltt_event_cpu_id(e
);
531 CalculateData( event_time
, cpu_id
, event_data
);
537 * This function calculates the duration of an interrupt.
540 static void CalculateData(LttTime time_exit
, guint cpu_id
,InterruptEventData
*event_data
)
546 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
547 GArray
*FirstRequestIrqEntry
= event_data
->FirstRequestIrqEntry
;
548 for(i
= 0; i
< FirstRequestIrqEntry
->len
; i
++)
550 element
= &g_array_index(FirstRequestIrqEntry
,irq_entry
,i
);
551 if(element
->cpu_id
== cpu_id
)
553 TotalDurationMaxIrqDuration(element
,time_exit
, FirstRequestIrqExit
);
554 g_array_remove_index(FirstRequestIrqEntry
, i
);
561 * This function calculates the total duration of an interrupt and the longest Irq handler.
564 static void TotalDurationMaxIrqDuration(irq_entry
*e
, LttTime time_exit
, GArray
*FirstRequestIrqExit
){
569 gboolean notFound
= FALSE
;
570 memset ((void*)&irq
, 0,sizeof(Irq
));
573 if(FirstRequestIrqExit
->len
== NO_ITEMS
)
575 irq
.cpu_id
= e
->cpu_id
;
578 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
580 irq
.max_irq_handler
.start_time
= e
->event_time
;
581 irq
.max_irq_handler
.end_time
= time_exit
;
582 irq
.max_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
585 g_array_append_val (FirstRequestIrqExit
, irq
);
589 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
591 element
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
592 if(element
->id
== e
->id
)
595 duration
= ltt_time_sub(time_exit
, e
->event_time
);
596 element
->total_duration
= ltt_time_add(element
->total_duration
, duration
);
597 element
->frequency
++;
598 if(ltt_time_compare(duration
,element
->max_irq_handler
.duration
) > 0)
600 element
->max_irq_handler
.duration
= duration
;
601 element
->max_irq_handler
.start_time
= e
->event_time
;
602 element
->max_irq_handler
.end_time
= time_exit
;
608 irq
.cpu_id
= e
->cpu_id
;
611 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
613 irq
.max_irq_handler
.start_time
= e
->event_time
;
614 irq
.max_irq_handler
.end_time
= time_exit
;
615 irq
.max_irq_handler
.duration
= ltt_time_sub(time_exit
, e
->event_time
);
617 g_array_append_val (FirstRequestIrqExit
, irq
);
623 * This function passes the second EventsRequest to LTTV
626 static gboolean
SecondRequest(void *hook_data
, void *call_data
)
629 guint i
, k
, l
, nb_trace
;
639 EventsRequest
*events_request
;
641 LttvTraceHookByFacility
*thf
;
643 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
645 LttvTracesetContext
*tsc
= lttvwindow_get_traceset_context(event_data
->tab
);
647 CalculateAverageDurationForEachIrqId(event_data
);
649 /* Get the traceset */
650 LttvTraceset
*traceset
= tsc
->ts
;
652 nb_trace
= lttv_traceset_number(traceset
);
654 /* There are many traces in a traceset. Iteration for each trace. */
655 for(i
= 0; i
<MIN(TRACE_NUMBER
+1, nb_trace
);i
++)
657 events_request
= g_new(EventsRequest
, 1);
659 hooks
= g_array_new(FALSE
, FALSE
, sizeof(LttvTraceHook
));
661 hooks
= g_array_set_size(hooks
, 2);
663 event_data
->hooks_trace_after
= lttv_hooks_new();
665 /* Registers a hook function */
666 lttv_hooks_add(event_data
->hooks_trace_after
, DisplayViewer
, event_data
, LTTV_PRIO_DEFAULT
);
668 /* Get a trace state */
669 ts
= (LttvTraceState
*)tsc
->traces
[i
];
670 /* Create event_by_Id hooks */
671 event_data
->event_by_id_hooks
= lttv_hooks_by_id_new();
673 /*Register event_by_id_hooks with a callback function*/
674 ret
= lttv_trace_find_hook(ts
->parent
.t
,
675 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_ENTRY
,
676 LTT_FIELD_IRQ_ID
, 0, 0,
677 SecondRequestIrqEntryCallback
,
679 &g_array_index(hooks
, LttvTraceHook
, 0));
681 ret
= lttv_trace_find_hook(ts
->parent
.t
,
682 LTT_FACILITY_KERNEL
, LTT_EVENT_IRQ_EXIT
,
683 LTT_FIELD_IRQ_ID
, 0, 0,
684 SecondRequestIrqExitCallback
,
686 &g_array_index(hooks
, LttvTraceHook
, 1));
690 /* iterate through the facility list */
691 for(k
= 0 ; k
< hooks
->len
; k
++)
693 hook
= &g_array_index(hooks
, LttvTraceHook
, k
);
694 for(l
=0; l
<hook
->fac_list
->len
; l
++)
696 thf
= g_array_index(hook
->fac_list
, LttvTraceHookByFacility
*, l
);
697 lttv_hooks_add(lttv_hooks_by_id_find(event_data
->event_by_id_hooks
, thf
->id
),
704 /* Initalize the EventsRequest structure */
705 events_request
->owner
= event_data
;
706 events_request
->viewer_data
= event_data
;
707 events_request
->servicing
= FALSE
;
708 events_request
->start_time
= event_data
->time_window
.start_time
;
709 events_request
->start_position
= NULL
;
710 events_request
->stop_flag
= FALSE
;
711 events_request
->end_time
= event_data
->time_window
.end_time
;
712 events_request
->num_events
= G_MAXUINT
;
713 events_request
->end_position
= NULL
;
714 events_request
->trace
= i
;
716 events_request
->hooks
= hooks
;
718 events_request
->before_chunk_traceset
= NULL
;
719 events_request
->before_chunk_trace
= NULL
;
720 events_request
->before_chunk_tracefile
= NULL
;
721 events_request
->event
= NULL
;
722 events_request
->event_by_id
= event_data
->event_by_id_hooks
;
723 events_request
->after_chunk_tracefile
= NULL
;
724 events_request
->after_chunk_trace
= NULL
;
725 events_request
->after_chunk_traceset
= NULL
;
726 events_request
->before_request
= NULL
;
727 events_request
->after_request
= event_data
->hooks_trace_after
;
729 lttvwindow_events_request(event_data
->tab
, events_request
);
734 static void CalculateAverageDurationForEachIrqId(InterruptEventData
*event_data
)
739 GArray
* FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
740 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
742 element
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
743 real_data
= element
->total_duration
.tv_sec
;
744 real_data
*= NANOSECONDS_PER_SECOND
;
745 real_data
+= element
->total_duration
.tv_nsec
;
746 element
->average_duration
= real_data
/ element
->frequency
;
752 * This function is called whenever an irq_entry event occurs. Use in the second request
755 static gboolean
SecondRequestIrqEntryCallback(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 GArray
* SecondRequestIrqEntry
= event_data
->SecondRequestIrqEntry
;
765 LttEvent
*e
= ltt_tracefile_get_event(tfc
->tf
);
766 event_time
= ltt_event_time(e
);
767 cpu_id
= ltt_event_cpu_id(e
);
770 entry
.id
=get_interrupt_id(e
);
771 entry
.cpu_id
= cpu_id
;
772 entry
.event_time
= event_time
;
773 g_array_append_val (SecondRequestIrqEntry
, entry
);
779 * This function is called whenever an irq_exit event occurs in the second request.
782 static gboolean
SecondRequestIrqExitCallback(void *hook_data
, void *call_data
)
785 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
786 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
787 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
788 LttEvent
*event
= ltt_tracefile_get_event(tfc
->tf
);
790 CalculateXi(event
, event_data
);
796 * This function is called whenever an irq_exit event occurs in the second request.
799 static void CalculateXi(LttEvent
*event_irq_exit
, InterruptEventData
*event_data
)
807 GArray
*SecondRequestIrqExit
= event_data
->SecondRequestIrqExit
;
808 GArray
*SecondRequestIrqEntry
= event_data
->SecondRequestIrqEntry
;
809 cpu_id
= ltt_event_cpu_id(event_irq_exit
);
810 for(i
= 0; i
< SecondRequestIrqEntry
->len
; i
++)
812 element
= &g_array_index(SecondRequestIrqEntry
,irq_entry
,i
);
813 if(element
->cpu_id
== cpu_id
)
816 /* time calculation */
817 exit_time
= ltt_event_time(event_irq_exit
);
818 Xi
= ltt_time_sub(exit_time
, element
->event_time
);
819 irq_id
= element
->id
;
821 SumItems(irq_id
, Xi
,event_data
);
822 g_array_remove_index(SecondRequestIrqEntry
, i
);
830 * This function computes the Sum ((xi -Xa)^2) and store the result in SumArray
833 static void SumItems(gint irq_id
, LttTime Xi
, InterruptEventData
*event_data
)
842 gboolean notFound
= FALSE
;
843 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
844 GArray
*SumArray
= event_data
->SumArray
;
845 time_in_ns
= Xi
.tv_sec
;
846 time_in_ns
*= NANOSECONDS_PER_SECOND
;
847 time_in_ns
+= Xi
.tv_nsec
;
849 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
851 average
= &g_array_index(FirstRequestIrqExit
,Irq
,i
);
852 if(irq_id
== average
->id
)
854 temp
= time_in_ns
- average
->average_duration
;
855 sum
.sumOfDurations
= pow (temp
, 2);
856 //printf("one : %d\n", sum.sumOfDurations);
858 sum
.frequency
= average
->frequency
;
859 if(event_data
->SumArray
->len
== NO_ITEMS
)
861 g_array_append_val (SumArray
, sum
);
866 for(i
= 0; i
< SumArray
->len
; i
++)
868 sumItem
= &g_array_index(SumArray
, SumId
, i
);
869 if(sumItem
->irqId
== irq_id
)
872 sumItem
->sumOfDurations
+= sum
.sumOfDurations
;
878 g_array_append_val (SumArray
, sum
);
889 * This function displays the result on the viewer
892 static gboolean
DisplayViewer(void *hook_data
, void *call_data
)
898 LttTime average_duration
;
901 guint maxIRQduration
;
903 char maxIrqHandler
[80];
904 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
905 GArray
*FirstRequestIrqExit
= event_data
->FirstRequestIrqExit
;
908 gtk_list_store_clear(event_data
->ListStore
);
909 for(i
= 0; i
< FirstRequestIrqExit
->len
; i
++)
911 element
= g_array_index(FirstRequestIrqExit
,Irq
,i
);
912 real_data
= element
.total_duration
.tv_sec
;
913 real_data
*= NANOSECONDS_PER_SECOND
;
914 real_data
+= element
.total_duration
.tv_nsec
;
917 maxIRQduration
= element
.max_irq_handler
.duration
.tv_sec
;
918 maxIRQduration
*= NANOSECONDS_PER_SECOND
;
919 maxIRQduration
+= element
.max_irq_handler
.duration
.tv_nsec
;
921 sprintf(maxIrqHandler
, "%d [%d.%d - %d.%d]",maxIRQduration
, element
.max_irq_handler
.start_time
.tv_sec
, \
922 element
.max_irq_handler
.start_time
.tv_nsec
, element
.max_irq_handler
.end_time
.tv_sec
, \
923 element
.max_irq_handler
.end_time
.tv_nsec
) ;
924 FrequencyHZ
= FrequencyInHZ(element
.frequency
,event_data
->time_window
);
927 period
=(double)1/FrequencyHZ
;
930 gtk_list_store_append (event_data
->ListStore
, &iter
);
931 gtk_list_store_set (event_data
->ListStore
, &iter
,
932 CPUID_COLUMN
, element
.cpu_id
,
933 IRQ_ID_COLUMN
, element
.id
,
934 FREQUENCY_COLUMN
, FrequencyHZ
,
935 DURATION_COLUMN
, real_data
,
936 DURATION_STANDARD_DEV_COLUMN
, CalculateStandardDeviation(element
.id
, event_data
),
937 MAX_IRQ_HANDLER_COLUMN
, maxIrqHandler
,
938 AVERAGE_PERIOD
, period
,
945 if(event_data
->FirstRequestIrqExit
->len
)
947 g_array_remove_range (event_data
->FirstRequestIrqExit
,0,event_data
->FirstRequestIrqExit
->len
);
950 if(event_data
->FirstRequestIrqEntry
->len
)
952 g_array_remove_range (event_data
->FirstRequestIrqEntry
,0,event_data
->FirstRequestIrqEntry
->len
);
955 if(event_data
->SecondRequestIrqEntry
->len
)
957 g_array_remove_range (event_data
->SecondRequestIrqEntry
,0,event_data
->SecondRequestIrqEntry
->len
);
960 if(event_data
->SecondRequestIrqExit
->len
)
962 g_array_remove_range (event_data
->SecondRequestIrqExit
,0, event_data
->SecondRequestIrqExit
->len
);
965 if(event_data
->SumArray
->len
)
967 g_array_remove_range (event_data
->SumArray
,0, event_data
->SumArray
->len
);
974 static int FrequencyInHZ(gint frequency
, TimeWindow time_window
)
976 guint64 frequencyHz
= 0;
979 timeSec
= ltt_time_to_double(time_window
.time_width
);
980 double result
= (timeSec
/NANOSECONDS_PER_SECOND
);
981 frequencyHz
= frequency
/ result
;
986 * This function calculatees the standard deviation
989 static int CalculateStandardDeviation(gint id
, InterruptEventData
*event_data
)
993 double inner_component
;
995 for(i
= 0; i
< event_data
->SumArray
->len
; i
++)
997 sumId
= g_array_index(event_data
->SumArray
, SumId
, i
);
998 if(id
== sumId
.irqId
)
1000 inner_component
= sumId
.sumOfDurations
/ sumId
.frequency
;
1001 deviation
= sqrt(inner_component
);
1008 * This function is called by the main window
1009 * when the time interval needs to be updated.
1011 gboolean
interrupt_update_time_window(void * hook_data
, void * call_data
)
1013 InterruptEventData
*event_data
= (InterruptEventData
*) hook_data
;
1014 const TimeWindowNotifyData
*time_window_nofify_data
= ((const TimeWindowNotifyData
*)call_data
);
1015 event_data
->time_window
= *time_window_nofify_data
->new_time_window
;
1016 g_info("interrupts: interrupt_update_time_window()\n");
1017 Tab
*tab
= event_data
->tab
;
1018 lttvwindow_events_request_remove_all(tab
, event_data
);
1019 FirstRequest(event_data
);
1024 gboolean
trace_header(void *hook_data
, void *call_data
)
1027 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
1028 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
1034 void interrupt_destroy_walk(gpointer data
, gpointer user_data
)
1036 g_info("interrupt_destroy_walk");
1037 interrupt_destructor((InterruptEventData
*)data
);
1041 void interrupt_destructor(InterruptEventData
*event_viewer_data
)
1043 /* May already been done by GTK window closing */
1044 g_info("enter interrupt_destructor \n");
1045 if(GTK_IS_WIDGET(event_viewer_data
->Hbox
))
1047 gtk_widget_destroy(event_viewer_data
->Hbox
);
1052 * plugin's destroy function
1054 * This function releases the memory reserved by the module and unregisters
1055 * everything that has been registered in the gtkTraceSet API.
1057 static void destroy()
1060 g_info("Destroy interrupts");
1061 g_slist_foreach(interrupt_data_list
, interrupt_destroy_walk
, NULL
);
1062 g_slist_free(interrupt_data_list
);
1063 lttvwindow_unregister_constructor(interrupts
);
1067 LTTV_MODULE("interrupts", "interrupts info view", \
1068 "Graphical module to display interrupts performance", \
1069 init
, destroy
, "lttvwindow")