Commit | Line | Data |
---|---|---|
5f5119ee | 1 | /* This file is part of the Linux Trace Toolkit viewer |
2 | * Copyright (C) 2005 Peter Ho | |
3 | * | |
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; | |
7 | * | |
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. | |
12 | * | |
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, | |
16 | * MA 02111-1307, USA. | |
17 | */ | |
dc06b1bc | 18 | |
19 | /****************************************************************** | |
31935b31 | 20 | |
21 | Each field of the interrupt viewer is summarized as follows: | |
e5258c09 | 22 | |
ecafd9df | 23 | - CPUID: processor ID |
24 | ||
25 | - IrqId: IRQ ID | |
26 | ||
31935b31 | 27 | - Frequency (Hz): the number of interrupts per second (Hz). |
28 | We compute the total number of interrupts. Then | |
29 | we divide it by the time interval. | |
ecafd9df | 30 | |
31935b31 | 31 | - Total Duration (nsec): the sum of each interrupt duration in nsec. |
32 | For a given Irq ID, we sum the duration of each interrupt | |
33 | to give us the total duration | |
ecafd9df | 34 | |
35 | - Duration Standard_deviation = sqrt(1/N Sum ((xi -Xa)^2)) where | |
36 | N: number of interrupts | |
37 | xi: duration of an interrupt (nsec) | |
38 | Xa: average duration (nsec) | |
31935b31 | 39 | The formula is taken from wikipedia: http://en.wikipedia.org/wiki/Standard_deviation. |
40 | To calculate the duration standard deviation, we make two EventsRequest passes to the main window. | |
41 | In the first EventsRequest pass, we calculate the total number of interrupts to compute for | |
42 | the average Xa. In the second EventsRequest pass, calculate the standard deviation. | |
43 | ||
ecafd9df | 44 | |
45 | - Max IRQ handler duration (nsec) [time interval]: the longest IRQ handler duration in nsec. | |
46 | ||
31935b31 | 47 | - Min IRQ handler duration (nsec) [time interval]: the shortest IRQ handler duration in nsec. |
48 | ||
49 | - Average period (nsec): 1/Frequency(in HZ). The frequency is computed above. | |
ecafd9df | 50 | |
51 | -Period Standard_deviation = sqrt(1/N Sum ((xi -Xa)^2)) where | |
31935b31 | 52 | N: number of interrupts |
ecafd9df | 53 | xi: duration of an interrupt |
31935b31 | 54 | Xa: Period = 1/Frequency (in Hz) |
ecafd9df | 55 | |
56 | -Frequency Standard_deviation = sqrt(1/N Sum ((xi -Xa)^2)) | |
31935b31 | 57 | N: number of interrupts |
ecafd9df | 58 | xi: duration of an interrupt |
59 | Xa: Frequency (Hz) | |
60 | ||
05600f3b | 61 | |
31935b31 | 62 | *******************************************************************/ |
5f5119ee | 63 | |
64 | ||
65 | ||
66 | #include <math.h> | |
67 | #include <glib.h> | |
68 | #include <gtk/gtk.h> | |
69 | #include <gdk/gdk.h> | |
70 | #include <stdio.h> | |
71 | #include <stdlib.h> | |
dc06b1bc | 72 | #include <math.h> |
5f5119ee | 73 | #include <string.h> |
74 | #include <ltt/ltt.h> | |
75 | #include <ltt/event.h> | |
5f5119ee | 76 | #include <ltt/trace.h> |
5f5119ee | 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> | |
e433e6d6 | 83 | #include <lttvwindow/lttv_plugin_tab.h> |
5f5119ee | 84 | #include <ltt/time.h> |
85 | ||
86 | #include "hInterruptsInsert.xpm" | |
87 | ||
88 | #define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format) | |
5f5119ee | 89 | #define NO_ITEMS 0 |
90 | ||
446b4179 | 91 | typedef struct |
92 | { | |
93 | LttTime duration; | |
94 | LttTime start_time; | |
95 | LttTime end_time; | |
ecafd9df | 96 | }IrqDuration; |
446b4179 | 97 | |
5f5119ee | 98 | typedef struct { |
99 | guint cpu_id; | |
100 | guint id; | |
31935b31 | 101 | guint TotalNumberOfInterrupts; |
5f5119ee | 102 | LttTime total_duration; |
dc06b1bc | 103 | guint average_duration; |
ecafd9df | 104 | IrqDuration max_irq_handler; |
105 | IrqDuration min_irq_handler; | |
5f5119ee | 106 | }Irq; |
107 | ||
108 | typedef struct { | |
109 | guint id; | |
110 | guint cpu_id; | |
111 | LttTime event_time; | |
112 | }irq_entry; | |
113 | ||
dc06b1bc | 114 | |
115 | typedef struct | |
116 | { | |
117 | guint irqId; | |
31935b31 | 118 | guint TotalNumberOfInterrupts;//frequency;// |
ecafd9df | 119 | guint64 sumOfDurations; // to store the Sum ((xi -Xa)^2) of the duration Standard deviation |
120 | guint64 sumOfPeriods; // to store the Sum ((xi -Xa)^2) of the period Standard deviation | |
121 | guint64 sumOfFrequencies;// to store the Sum ((xi -Xa)^2) of the frequency Standard deviation | |
dc06b1bc | 122 | |
123 | }SumId; | |
124 | ||
5f5119ee | 125 | enum type_t { |
126 | IRQ_ENTRY, | |
127 | IRQ_EXIT | |
128 | }; | |
129 | ||
130 | /** Array containing instanced objects. Used when module is unloaded */ | |
131 | static GSList *interrupt_data_list = NULL ; | |
132 | ||
133 | ||
8402f27d | 134 | //fixed #define TRACE_NUMBER 0 |
f2ec7aa9 | 135 | |
5f5119ee | 136 | typedef struct _InterruptEventData { |
137 | ||
b3e7b125 | 138 | /*Graphical Widgets */ |
139 | GtkWidget * ScrollWindow; | |
140 | GtkListStore *ListStore; | |
141 | GtkWidget *Hbox; | |
142 | GtkWidget *TreeView; | |
143 | GtkTreeSelection *SelectionTree; | |
144 | ||
145 | Tab * tab; /* tab that contains this plug-in*/ | |
e433e6d6 | 146 | LttvPluginTab *ptab; |
5f5119ee | 147 | LttvHooks * event_hooks; |
148 | LttvHooks * hooks_trace_after; | |
149 | LttvHooks * hooks_trace_before; | |
b3e7b125 | 150 | TimeWindow time_window; |
750eb11a | 151 | LttvHooksByIdChannelArray * event_by_id_hooks; |
dc06b1bc | 152 | GArray *FirstRequestIrqExit; |
153 | GArray *FirstRequestIrqEntry; | |
154 | GArray *SecondRequestIrqEntry; | |
155 | GArray *SecondRequestIrqExit; | |
156 | GArray *SumArray; | |
157 | ||
5f5119ee | 158 | } InterruptEventData ; |
159 | ||
f2ec7aa9 | 160 | |
b3e7b125 | 161 | /* Function prototypes */ |
5f5119ee | 162 | |
163 | static gboolean interrupt_update_time_window(void * hook_data, void * call_data); | |
e433e6d6 | 164 | static GtkWidget *interrupts(LttvPlugin *plugin); |
165 | static InterruptEventData *system_info(LttvPluginTab *ptab); | |
5f5119ee | 166 | void interrupt_destructor(InterruptEventData *event_viewer_data); |
dc06b1bc | 167 | static void FirstRequest(InterruptEventData *event_data ); |
5f5119ee | 168 | static gboolean trace_header(void *hook_data, void *call_data); |
dc06b1bc | 169 | static gboolean DisplayViewer (void *hook_data, void *call_data); |
e5258c09 | 170 | static void CalculateData(LttTime time_exit, guint cpu_id, InterruptEventData *event_data); |
ecafd9df | 171 | static void CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(irq_entry *e, LttTime time_exit, GArray *FirstRequestIrqExit); |
dc06b1bc | 172 | static gboolean FirstRequestIrqEntryCallback(void *hook_data, void *call_data); |
173 | static gboolean FirstRequestIrqExitCallback(void *hook_data, void *call_data); | |
174 | static gboolean SecondRequest(void *hook_data, void *call_data); | |
175 | static void CalculateAverageDurationForEachIrqId(InterruptEventData *event_data); | |
176 | static gboolean SecondRequestIrqEntryCallback(void *hook_data, void *call_data); | |
177 | static gboolean SecondRequestIrqExitCallback(void *hook_data, void *call_data); | |
c88429fb | 178 | static void CalculateXi(LttEvent *event, InterruptEventData *event_data, guint cpu_id); |
dc06b1bc | 179 | static void SumItems(gint irq_id, LttTime Xi, InterruptEventData *event_data); |
6b0817c2 | 180 | static int CalculateDurationStandardDeviation(gint id, InterruptEventData *event_data); |
181 | static int CalculatePeriodStandardDeviation(gint id, InterruptEventData *event_data); | |
31935b31 | 182 | static int FrequencyInHZ(gint NumberOfInterruptions, TimeWindow time_window); |
6b0817c2 | 183 | static guint64 CalculatePeriodInnerPart(guint Xi, guint FrequencyHZ); |
ecafd9df | 184 | static guint64 CalculateFrequencyInnerPart(guint Xi_in_ns, guint FrequencyHZ); |
fc77fe59 | 185 | static void InterruptFree(InterruptEventData *event_viewer_data); |
ecafd9df | 186 | static int CalculateFrequencyStandardDeviation(gint id, InterruptEventData *event_data); |
187 | ||
5f5119ee | 188 | /* Enumeration of the columns */ |
189 | enum{ | |
190 | CPUID_COLUMN, | |
191 | IRQ_ID_COLUMN, | |
192 | FREQUENCY_COLUMN, | |
193 | DURATION_COLUMN, | |
dc06b1bc | 194 | DURATION_STANDARD_DEV_COLUMN, |
446b4179 | 195 | MAX_IRQ_HANDLER_COLUMN, |
05600f3b | 196 | MIN_IRQ_HANDLER_COLUMN, |
52948a62 | 197 | AVERAGE_PERIOD, |
ecafd9df | 198 | PERIOD_STANDARD_DEV_COLUMN, |
199 | FREQUENCY_STANDARD_DEV_COLUMN, | |
5f5119ee | 200 | N_COLUMNS |
201 | }; | |
f2ec7aa9 | 202 | |
203 | ||
204 | ||
205 | /** | |
206 | * init function | |
207 | * | |
208 | * | |
209 | * This is the entry point of the viewer. | |
210 | * | |
211 | */ | |
212 | static void init() { | |
213 | g_info("interrupts: init()"); | |
214 | lttvwindow_register_constructor("interrupts", | |
215 | "/", | |
216 | "Insert Interrupts View", | |
217 | hInterruptsInsert_xpm, | |
218 | "Insert Interrupts View", | |
219 | interrupts); | |
220 | ||
221 | } | |
222 | ||
5f5119ee | 223 | |
5f5119ee | 224 | /** |
f2ec7aa9 | 225 | * Constructor hook |
5f5119ee | 226 | * |
5f5119ee | 227 | */ |
e433e6d6 | 228 | static GtkWidget *interrupts(LttvPlugin *plugin) |
f2ec7aa9 | 229 | { |
e433e6d6 | 230 | LttvPluginTab *ptab = LTTV_PLUGIN_TAB(plugin); |
231 | InterruptEventData* event_data = system_info(ptab) ; | |
5f5119ee | 232 | if(event_data) |
b3e7b125 | 233 | return event_data->Hbox; |
5f5119ee | 234 | else |
235 | return NULL; | |
236 | } | |
237 | ||
f2ec7aa9 | 238 | /** |
239 | * This function initializes the Event Viewer functionnality through the | |
240 | * GTK API. | |
241 | */ | |
e433e6d6 | 242 | InterruptEventData *system_info(LttvPluginTab *ptab) |
5f5119ee | 243 | { |
5f5119ee | 244 | GtkTreeViewColumn *column; |
245 | GtkCellRenderer *renderer; | |
246 | InterruptEventData* event_viewer_data = g_new(InterruptEventData,1) ; | |
e433e6d6 | 247 | Tab *tab = ptab->tab; |
248 | event_viewer_data->ptab = ptab; | |
5f5119ee | 249 | event_viewer_data->tab = tab; |
f2ec7aa9 | 250 | |
251 | /*Get the current time frame from the main window */ | |
5f5119ee | 252 | event_viewer_data->time_window = lttvwindow_get_time_window(tab); |
dc06b1bc | 253 | |
254 | event_viewer_data->FirstRequestIrqExit = g_array_new(FALSE, FALSE, sizeof(Irq)); | |
255 | event_viewer_data->FirstRequestIrqEntry = g_array_new(FALSE, FALSE, sizeof(irq_entry)); | |
256 | ||
257 | event_viewer_data->SecondRequestIrqEntry = g_array_new(FALSE, FALSE, sizeof(irq_entry)); | |
258 | event_viewer_data->SecondRequestIrqExit = g_array_new(FALSE, FALSE, sizeof(Irq)); | |
259 | ||
260 | event_viewer_data->SumArray = g_array_new(FALSE, FALSE, sizeof(SumId)); | |
261 | ||
262 | ||
f2ec7aa9 | 263 | /*Create tha main window for the viewer */ |
b3e7b125 | 264 | event_viewer_data->ScrollWindow = gtk_scrolled_window_new (NULL, NULL); |
265 | gtk_widget_show (event_viewer_data->ScrollWindow); | |
5f5119ee | 266 | gtk_scrolled_window_set_policy( |
b3e7b125 | 267 | GTK_SCROLLED_WINDOW(event_viewer_data->ScrollWindow), |
5f5119ee | 268 | GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC/*GTK_POLICY_NEVER*/); |
269 | ||
270 | /* Create a model for storing the data list */ | |
b3e7b125 | 271 | event_viewer_data->ListStore = gtk_list_store_new ( |
5f5119ee | 272 | N_COLUMNS, /* Total number of columns */ |
273 | G_TYPE_INT, /* CPUID */ | |
274 | G_TYPE_INT, /* IRQ_ID */ | |
275 | G_TYPE_INT, /* Frequency */ | |
dc06b1bc | 276 | G_TYPE_UINT64, /* Duration */ |
446b4179 | 277 | G_TYPE_INT, /* standard deviation */ |
52948a62 | 278 | G_TYPE_STRING, /* Max IRQ handler */ |
05600f3b | 279 | G_TYPE_STRING, /* Min IRQ handler */ |
6b0817c2 | 280 | G_TYPE_INT, /* Average period */ |
ecafd9df | 281 | G_TYPE_INT, /* period standard deviation */ |
282 | G_TYPE_INT /* frequency standard deviation */ | |
283 | ||
5f5119ee | 284 | ); |
285 | ||
b3e7b125 | 286 | event_viewer_data->TreeView = gtk_tree_view_new_with_model (GTK_TREE_MODEL (event_viewer_data->ListStore)); |
5f5119ee | 287 | |
b3e7b125 | 288 | g_object_unref (G_OBJECT (event_viewer_data->ListStore)); |
5f5119ee | 289 | |
290 | renderer = gtk_cell_renderer_text_new (); | |
ecafd9df | 291 | column = gtk_tree_view_column_new_with_attributes ("CPU ID", |
5f5119ee | 292 | renderer, |
293 | "text", CPUID_COLUMN, | |
294 | NULL); | |
295 | gtk_tree_view_column_set_alignment (column, 0.0); | |
296 | gtk_tree_view_column_set_fixed_width (column, 45); | |
b3e7b125 | 297 | gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column); |
5f5119ee | 298 | |
299 | ||
300 | renderer = gtk_cell_renderer_text_new (); | |
ecafd9df | 301 | column = gtk_tree_view_column_new_with_attributes ("IRQ ID", |
5f5119ee | 302 | renderer, |
303 | "text", IRQ_ID_COLUMN, | |
304 | NULL); | |
305 | gtk_tree_view_column_set_alignment (column, 0.0); | |
306 | gtk_tree_view_column_set_fixed_width (column, 220); | |
b3e7b125 | 307 | gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column); |
5f5119ee | 308 | |
309 | renderer = gtk_cell_renderer_text_new (); | |
52948a62 | 310 | column = gtk_tree_view_column_new_with_attributes ("Frequency (Hz)", |
5f5119ee | 311 | renderer, |
312 | "text", FREQUENCY_COLUMN, | |
313 | NULL); | |
314 | gtk_tree_view_column_set_alignment (column, 1.0); | |
315 | gtk_tree_view_column_set_fixed_width (column, 220); | |
b3e7b125 | 316 | gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column); |
5f5119ee | 317 | |
318 | renderer = gtk_cell_renderer_text_new (); | |
25c6412d | 319 | column = gtk_tree_view_column_new_with_attributes ("Total Duration (nsec)", |
5f5119ee | 320 | renderer, |
321 | "text", DURATION_COLUMN, | |
322 | NULL); | |
323 | gtk_tree_view_column_set_alignment (column, 0.0); | |
324 | gtk_tree_view_column_set_fixed_width (column, 145); | |
b3e7b125 | 325 | gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column); |
5f5119ee | 326 | |
dc06b1bc | 327 | |
328 | renderer = gtk_cell_renderer_text_new (); | |
329 | column = gtk_tree_view_column_new_with_attributes ("Duration standard deviation (nsec)", | |
330 | renderer, | |
331 | "text", DURATION_STANDARD_DEV_COLUMN, | |
332 | NULL); | |
333 | gtk_tree_view_column_set_alignment (column, 0.0); | |
446b4179 | 334 | gtk_tree_view_column_set_fixed_width (column, 200); |
dc06b1bc | 335 | gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column); |
336 | ||
446b4179 | 337 | renderer = gtk_cell_renderer_text_new (); |
25c6412d | 338 | column = gtk_tree_view_column_new_with_attributes ("Max IRQ handler duration (nsec) [time interval]", |
446b4179 | 339 | renderer, |
340 | "text", MAX_IRQ_HANDLER_COLUMN, | |
341 | NULL); | |
342 | gtk_tree_view_column_set_alignment (column, 0.0); | |
343 | gtk_tree_view_column_set_fixed_width (column, 250); | |
344 | gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column); | |
05600f3b | 345 | |
346 | renderer = gtk_cell_renderer_text_new (); | |
347 | column = gtk_tree_view_column_new_with_attributes ("Min IRQ handler duration (nsec) [time interval]", | |
348 | renderer, | |
349 | "text", MIN_IRQ_HANDLER_COLUMN, | |
350 | NULL); | |
351 | gtk_tree_view_column_set_alignment (column, 0.0); | |
352 | gtk_tree_view_column_set_fixed_width (column, 250); | |
353 | gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column); | |
354 | ||
52948a62 | 355 | renderer = gtk_cell_renderer_text_new (); |
356 | column = gtk_tree_view_column_new_with_attributes (" Average period (nsec)", | |
357 | renderer, | |
358 | "text", AVERAGE_PERIOD, | |
359 | NULL); | |
360 | gtk_tree_view_column_set_alignment (column, 0.0); | |
361 | gtk_tree_view_column_set_fixed_width (column, 200); | |
362 | gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column); | |
363 | ||
364 | renderer = gtk_cell_renderer_text_new (); | |
365 | column = gtk_tree_view_column_new_with_attributes ("Period standard deviation (nsec)", | |
366 | renderer, | |
367 | "text", PERIOD_STANDARD_DEV_COLUMN, | |
368 | NULL); | |
369 | gtk_tree_view_column_set_alignment (column, 0.0); | |
370 | gtk_tree_view_column_set_fixed_width (column, 200); | |
371 | gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column); | |
372 | ||
ecafd9df | 373 | renderer = gtk_cell_renderer_text_new (); |
374 | column = gtk_tree_view_column_new_with_attributes ("Frequency standard deviation (Hz)", | |
375 | renderer, | |
376 | "text", FREQUENCY_STANDARD_DEV_COLUMN, | |
377 | NULL); | |
378 | gtk_tree_view_column_set_alignment (column, 0.0); | |
379 | gtk_tree_view_column_set_fixed_width (column, 200); | |
380 | gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column); | |
52948a62 | 381 | |
dc06b1bc | 382 | |
b3e7b125 | 383 | event_viewer_data->SelectionTree = gtk_tree_view_get_selection (GTK_TREE_VIEW (event_viewer_data->TreeView)); |
384 | gtk_tree_selection_set_mode (event_viewer_data->SelectionTree, GTK_SELECTION_SINGLE); | |
5f5119ee | 385 | |
b3e7b125 | 386 | gtk_container_add (GTK_CONTAINER (event_viewer_data->ScrollWindow), event_viewer_data->TreeView); |
5f5119ee | 387 | |
b3e7b125 | 388 | event_viewer_data->Hbox = gtk_hbox_new(0, 0); |
389 | gtk_box_pack_start(GTK_BOX(event_viewer_data->Hbox), event_viewer_data->ScrollWindow, TRUE, TRUE, 0); | |
5f5119ee | 390 | |
b3e7b125 | 391 | gtk_widget_show(event_viewer_data->Hbox); |
392 | gtk_widget_show(event_viewer_data->TreeView); | |
5f5119ee | 393 | |
b3e7b125 | 394 | interrupt_data_list = g_slist_append(interrupt_data_list, event_viewer_data); |
f2ec7aa9 | 395 | /* Registration for time notification */ |
b3e7b125 | 396 | lttvwindow_register_time_window_notify(tab, |
397 | interrupt_update_time_window, | |
398 | event_viewer_data); | |
f2ec7aa9 | 399 | |
fc77fe59 | 400 | g_object_set_data_full(G_OBJECT(event_viewer_data->Hbox), |
401 | "event_data", | |
402 | event_viewer_data, | |
403 | (GDestroyNotify) InterruptFree); | |
f2ec7aa9 | 404 | |
dc06b1bc | 405 | FirstRequest(event_viewer_data ); |
5f5119ee | 406 | return event_viewer_data; |
407 | } | |
b3e7b125 | 408 | |
fc77fe59 | 409 | |
f2ec7aa9 | 410 | /** |
411 | * | |
412 | * For each trace in the traceset, this function: | |
413 | * - registers a callback function to each hook | |
414 | * - calls lttv_trace_find_hook() registers a hook function to event_by_id_hooks | |
415 | * - calls lttvwindow_events_request() to request data in a specific | |
416 | * time interval to the main window | |
417 | * | |
418 | */ | |
dc06b1bc | 419 | static void FirstRequest(InterruptEventData *event_data ) |
f2ec7aa9 | 420 | { |
8d8c5ea7 | 421 | guint i, k, nb_trace; |
f2ec7aa9 | 422 | LttvTraceState *ts; |
f2ec7aa9 | 423 | GArray *hooks; |
f2ec7aa9 | 424 | EventsRequest *events_request; |
c88429fb | 425 | LttvTraceHook *th; |
f2ec7aa9 | 426 | LttvTracesetContext *tsc = lttvwindow_get_traceset_context(event_data->tab); |
8d8c5ea7 | 427 | |
f2ec7aa9 | 428 | /* Get the traceset */ |
429 | LttvTraceset *traceset = tsc->ts; | |
5f5119ee | 430 | |
f2ec7aa9 | 431 | nb_trace = lttv_traceset_number(traceset); |
432 | ||
433 | /* There are many traces in a traceset. Iteration for each trace. */ | |
8402f27d | 434 | //for(i = 0; i<MIN(TRACE_NUMBER+1, nb_trace);i++) { |
435 | for(i = 0 ; i < nb_trace ; i++) { | |
f2ec7aa9 | 436 | events_request = g_new(EventsRequest, 1); |
437 | ||
c88429fb | 438 | hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 2); |
b3e7b125 | 439 | |
f2ec7aa9 | 440 | event_data->hooks_trace_before = lttv_hooks_new(); |
441 | ||
442 | /* Registers a hook function */ | |
443 | lttv_hooks_add(event_data->hooks_trace_before, trace_header, event_data, LTTV_PRIO_DEFAULT); | |
444 | ||
445 | event_data->hooks_trace_after = lttv_hooks_new(); | |
dc06b1bc | 446 | |
447 | /* Registers a hook function */ | |
448 | lttv_hooks_add(event_data->hooks_trace_after, SecondRequest, event_data, LTTV_PRIO_DEFAULT); | |
f2ec7aa9 | 449 | /* Get a trace state */ |
450 | ts = (LttvTraceState *)tsc->traces[i]; | |
451 | /* Create event_by_Id hooks */ | |
750eb11a | 452 | event_data->event_by_id_hooks = lttv_hooks_by_id_channel_new(); |
b3e7b125 | 453 | |
f2ec7aa9 | 454 | /*Register event_by_id_hooks with a callback function*/ |
c88429fb | 455 | lttv_trace_find_hook(ts->parent.t, |
750eb11a | 456 | LTT_CHANNEL_KERNEL, |
c88429fb | 457 | LTT_EVENT_IRQ_ENTRY, |
458 | FIELD_ARRAY(LTT_FIELD_IRQ_ID), | |
dc06b1bc | 459 | FirstRequestIrqEntryCallback, |
f2ec7aa9 | 460 | events_request, |
c88429fb | 461 | &hooks); |
f2ec7aa9 | 462 | |
c88429fb | 463 | lttv_trace_find_hook(ts->parent.t, |
750eb11a | 464 | LTT_CHANNEL_KERNEL, |
c88429fb | 465 | LTT_EVENT_IRQ_EXIT, |
466 | NULL, | |
dc06b1bc | 467 | FirstRequestIrqExitCallback, |
f2ec7aa9 | 468 | events_request, |
c88429fb | 469 | &hooks); |
f2ec7aa9 | 470 | |
f2ec7aa9 | 471 | /*iterate through the facility list*/ |
472 | for(k = 0 ; k < hooks->len; k++) | |
473 | { | |
c88429fb | 474 | th = &g_array_index(hooks, LttvTraceHook, k); |
750eb11a | 475 | lttv_hooks_add(lttv_hooks_by_id_channel_find( |
476 | event_data->event_by_id_hooks, | |
477 | th->channel, th->id), | |
c88429fb | 478 | th->h, |
479 | th, | |
480 | LTTV_PRIO_DEFAULT); | |
f2ec7aa9 | 481 | |
f2ec7aa9 | 482 | } |
483 | /* Initalize the EventsRequest structure */ | |
484 | events_request->owner = event_data; | |
485 | events_request->viewer_data = event_data; | |
486 | events_request->servicing = FALSE; | |
487 | events_request->start_time = event_data->time_window.start_time; | |
488 | events_request->start_position = NULL; | |
489 | events_request->stop_flag = FALSE; | |
490 | events_request->end_time = event_data->time_window.end_time; | |
491 | events_request->num_events = G_MAXUINT; | |
492 | events_request->end_position = NULL; | |
493 | events_request->trace = i; | |
494 | ||
495 | events_request->hooks = hooks; | |
496 | ||
497 | events_request->before_chunk_traceset = NULL; | |
498 | events_request->before_chunk_trace = event_data->hooks_trace_before; | |
499 | events_request->before_chunk_tracefile= NULL; | |
500 | events_request->event = NULL; | |
750eb11a | 501 | events_request->event_by_id_channel = event_data->event_by_id_hooks; |
f2ec7aa9 | 502 | events_request->after_chunk_tracefile = NULL; |
231a6432 | 503 | events_request->after_chunk_trace = NULL; |
f2ec7aa9 | 504 | events_request->after_chunk_traceset = NULL; |
231a6432 | 505 | events_request->before_request = NULL; |
f2ec7aa9 | 506 | events_request->after_request = event_data->hooks_trace_after; |
507 | ||
508 | lttvwindow_events_request(event_data->tab, events_request); | |
509 | } | |
510 | ||
b3e7b125 | 511 | } |
5f5119ee | 512 | |
f2ec7aa9 | 513 | /** |
514 | * This function is called whenever an irq_entry event occurs. | |
515 | * | |
516 | */ | |
dc06b1bc | 517 | static gboolean FirstRequestIrqEntryCallback(void *hook_data, void *call_data) |
f2ec7aa9 | 518 | { |
519 | ||
b3e7b125 | 520 | LttTime event_time; |
b3e7b125 | 521 | unsigned cpu_id; |
522 | irq_entry entry; | |
b3e7b125 | 523 | LttvTracefileContext *tfc = (LttvTracefileContext *)call_data; |
524 | LttvTracefileState *tfs = (LttvTracefileState *)call_data; | |
c88429fb | 525 | LttvTraceHook *th = (LttvTraceHook*) hook_data; |
526 | EventsRequest *events_request = (EventsRequest*)th->hook_data; | |
527 | InterruptEventData *event_data = events_request->viewer_data; | |
dc06b1bc | 528 | GArray* FirstRequestIrqEntry = event_data->FirstRequestIrqEntry; |
f2ec7aa9 | 529 | LttEvent *e = ltt_tracefile_get_event(tfc->tf); |
b3e7b125 | 530 | event_time = ltt_event_time(e); |
c88429fb | 531 | cpu_id = tfs->cpu; |
f2ec7aa9 | 532 | |
231a6432 | 533 | |
c88429fb | 534 | entry.id = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 0)); |
231a6432 | 535 | entry.cpu_id = cpu_id; |
536 | entry.event_time = event_time; | |
dc06b1bc | 537 | g_array_append_val (FirstRequestIrqEntry, entry); |
231a6432 | 538 | |
f2ec7aa9 | 539 | return FALSE; |
5f5119ee | 540 | } |
541 | ||
f2ec7aa9 | 542 | /** |
543 | * This function is called whenever an irq_exit event occurs. | |
544 | * | |
545 | */ | |
dc06b1bc | 546 | gboolean FirstRequestIrqExitCallback(void *hook_data, void *call_data) |
f2ec7aa9 | 547 | { |
548 | LttTime event_time; | |
549 | unsigned cpu_id; | |
5f5119ee | 550 | LttvTracefileContext *tfc = (LttvTracefileContext *)call_data; |
f2ec7aa9 | 551 | LttvTracefileState *tfs = (LttvTracefileState *)call_data; |
c88429fb | 552 | LttvTraceHook *th = (LttvTraceHook*) hook_data; |
553 | EventsRequest *events_request = (EventsRequest*)th->hook_data; | |
554 | InterruptEventData *event_data = events_request->viewer_data; | |
f2ec7aa9 | 555 | LttEvent *e = ltt_tracefile_get_event(tfc->tf); |
f2ec7aa9 | 556 | event_time = ltt_event_time(e); |
c88429fb | 557 | cpu_id = tfs->cpu; |
231a6432 | 558 | |
e5258c09 | 559 | CalculateData( event_time, cpu_id, event_data); |
560 | ||
231a6432 | 561 | return FALSE; |
5f5119ee | 562 | } |
563 | ||
f2ec7aa9 | 564 | /** |
565 | * This function calculates the duration of an interrupt. | |
566 | * | |
567 | */ | |
e5258c09 | 568 | static void CalculateData(LttTime time_exit, guint cpu_id,InterruptEventData *event_data) |
dc06b1bc | 569 | { |
5f5119ee | 570 | |
8d8c5ea7 | 571 | gint i; |
f2ec7aa9 | 572 | irq_entry *element; |
dc06b1bc | 573 | GArray *FirstRequestIrqExit = event_data->FirstRequestIrqExit; |
574 | GArray *FirstRequestIrqEntry = event_data->FirstRequestIrqEntry; | |
1f8ff56f | 575 | for(i = FirstRequestIrqEntry->len-1; i >=0; i--) |
231a6432 | 576 | { |
dc06b1bc | 577 | element = &g_array_index(FirstRequestIrqEntry,irq_entry,i); |
231a6432 | 578 | if(element->cpu_id == cpu_id) |
579 | { | |
ecafd9df | 580 | CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(element,time_exit, FirstRequestIrqExit); |
dc06b1bc | 581 | g_array_remove_index(FirstRequestIrqEntry, i); |
f2ec7aa9 | 582 | break; |
583 | } | |
584 | } | |
e5258c09 | 585 | } |
ecafd9df | 586 | |
dc06b1bc | 587 | |
f2ec7aa9 | 588 | /** |
ecafd9df | 589 | * This function calculates the total duration of an interrupt and the longest & shortest Irq handlers. |
f2ec7aa9 | 590 | * |
591 | */ | |
ecafd9df | 592 | static void CalculateTotalDurationAndMaxIrqDurationAndMinIrqDuration(irq_entry *e, LttTime time_exit, GArray *FirstRequestIrqExit) |
593 | { | |
5f5119ee | 594 | Irq irq; |
595 | Irq *element; | |
596 | guint i; | |
597 | LttTime duration; | |
598 | gboolean notFound = FALSE; | |
599 | memset ((void*)&irq, 0,sizeof(Irq)); | |
600 | ||
231a6432 | 601 | /*first time*/ |
dc06b1bc | 602 | if(FirstRequestIrqExit->len == NO_ITEMS) |
231a6432 | 603 | { |
5f5119ee | 604 | irq.cpu_id = e->cpu_id; |
605 | irq.id = e->id; | |
31935b31 | 606 | irq.TotalNumberOfInterrupts++; |
5f5119ee | 607 | irq.total_duration = ltt_time_sub(time_exit, e->event_time); |
e5258c09 | 608 | |
446b4179 | 609 | irq.max_irq_handler.start_time = e->event_time; |
610 | irq.max_irq_handler.end_time = time_exit; | |
611 | irq.max_irq_handler.duration = ltt_time_sub(time_exit, e->event_time); | |
ecafd9df | 612 | |
613 | irq.min_irq_handler.start_time = e->event_time; | |
614 | irq.min_irq_handler.end_time = time_exit; | |
615 | irq.min_irq_handler.duration = ltt_time_sub(time_exit, e->event_time); | |
e5258c09 | 616 | |
dc06b1bc | 617 | g_array_append_val (FirstRequestIrqExit, irq); |
5f5119ee | 618 | } |
231a6432 | 619 | else |
620 | { | |
dc06b1bc | 621 | for(i = 0; i < FirstRequestIrqExit->len; i++) |
231a6432 | 622 | { |
dc06b1bc | 623 | element = &g_array_index(FirstRequestIrqExit,Irq,i); |
624 | if(element->id == e->id) | |
625 | { | |
5f5119ee | 626 | notFound = TRUE; |
627 | duration = ltt_time_sub(time_exit, e->event_time); | |
628 | element->total_duration = ltt_time_add(element->total_duration, duration); | |
31935b31 | 629 | element->TotalNumberOfInterrupts++; |
ecafd9df | 630 | // Max irq handler |
446b4179 | 631 | if(ltt_time_compare(duration,element->max_irq_handler.duration) > 0) |
632 | { | |
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; | |
636 | } | |
ecafd9df | 637 | // Min irq handler |
638 | if(ltt_time_compare(duration,element->min_irq_handler.duration) < 0) | |
639 | { | |
640 | element->min_irq_handler.duration = duration; | |
641 | element->min_irq_handler.start_time = e->event_time; | |
642 | element->min_irq_handler.end_time = time_exit; | |
643 | } | |
5f5119ee | 644 | } |
645 | } | |
231a6432 | 646 | if(!notFound) |
647 | { | |
5f5119ee | 648 | irq.cpu_id = e->cpu_id; |
649 | irq.id = e->id; | |
31935b31 | 650 | irq.TotalNumberOfInterrupts++; |
5f5119ee | 651 | irq.total_duration = ltt_time_sub(time_exit, e->event_time); |
ecafd9df | 652 | // Max irq handler |
446b4179 | 653 | irq.max_irq_handler.start_time = e->event_time; |
654 | irq.max_irq_handler.end_time = time_exit; | |
655 | irq.max_irq_handler.duration = ltt_time_sub(time_exit, e->event_time); | |
ecafd9df | 656 | // Min irq handler |
657 | irq.min_irq_handler.start_time = e->event_time; | |
658 | irq.min_irq_handler.end_time = time_exit; | |
659 | irq.min_irq_handler.duration = ltt_time_sub(time_exit, e->event_time); | |
446b4179 | 660 | |
dc06b1bc | 661 | g_array_append_val (FirstRequestIrqExit, irq); |
5f5119ee | 662 | } |
663 | } | |
664 | } | |
231a6432 | 665 | |
e5258c09 | 666 | /** |
667 | * This function passes the second EventsRequest to LTTV | |
668 | * | |
669 | */ | |
dc06b1bc | 670 | static gboolean SecondRequest(void *hook_data, void *call_data) |
671 | { | |
8d8c5ea7 | 672 | guint i, k, nb_trace; |
dc06b1bc | 673 | guint ret; |
dc06b1bc | 674 | LttvTraceState *ts; |
dc06b1bc | 675 | GArray *hooks; |
dc06b1bc | 676 | EventsRequest *events_request; |
c88429fb | 677 | LttvTraceHook *th; |
dc06b1bc | 678 | InterruptEventData *event_data = (InterruptEventData *)hook_data; |
dc06b1bc | 679 | LttvTracesetContext *tsc = lttvwindow_get_traceset_context(event_data->tab); |
dc06b1bc | 680 | CalculateAverageDurationForEachIrqId(event_data); |
681 | ||
682 | /* Get the traceset */ | |
683 | LttvTraceset *traceset = tsc->ts; | |
684 | ||
685 | nb_trace = lttv_traceset_number(traceset); | |
686 | ||
687 | /* There are many traces in a traceset. Iteration for each trace. */ | |
8402f27d | 688 | for(i = 0 ; i < nb_trace ; i++) { |
689 | // fixed for(i = 0; i<MIN(TRACE_NUMBER+1, nb_trace);i++) { | |
dc06b1bc | 690 | events_request = g_new(EventsRequest, 1); |
691 | ||
c88429fb | 692 | hooks = g_array_sized_new(FALSE, FALSE, sizeof(LttvTraceHook), 2); |
dc06b1bc | 693 | |
dc06b1bc | 694 | event_data->hooks_trace_after = lttv_hooks_new(); |
695 | ||
696 | /* Registers a hook function */ | |
697 | lttv_hooks_add(event_data->hooks_trace_after, DisplayViewer, event_data, LTTV_PRIO_DEFAULT); | |
698 | ||
699 | /* Get a trace state */ | |
700 | ts = (LttvTraceState *)tsc->traces[i]; | |
701 | /* Create event_by_Id hooks */ | |
750eb11a | 702 | event_data->event_by_id_hooks = lttv_hooks_by_id_channel_new(); |
dc06b1bc | 703 | |
704 | /*Register event_by_id_hooks with a callback function*/ | |
705 | ret = lttv_trace_find_hook(ts->parent.t, | |
750eb11a | 706 | LTT_CHANNEL_KERNEL, |
c88429fb | 707 | LTT_EVENT_IRQ_ENTRY, |
708 | FIELD_ARRAY(LTT_FIELD_IRQ_ID), | |
dc06b1bc | 709 | SecondRequestIrqEntryCallback, |
710 | events_request, | |
c88429fb | 711 | &hooks); |
dc06b1bc | 712 | |
713 | ret = lttv_trace_find_hook(ts->parent.t, | |
750eb11a | 714 | LTT_CHANNEL_KERNEL, |
c88429fb | 715 | LTT_EVENT_IRQ_EXIT, |
716 | NULL, | |
dc06b1bc | 717 | SecondRequestIrqExitCallback, |
718 | events_request, | |
c88429fb | 719 | &hooks); |
dc06b1bc | 720 | |
721 | g_assert(!ret); | |
e5258c09 | 722 | |
723 | /* iterate through the facility list */ | |
dc06b1bc | 724 | for(k = 0 ; k < hooks->len; k++) |
725 | { | |
c88429fb | 726 | th = &g_array_index(hooks, LttvTraceHook, k); |
750eb11a | 727 | lttv_hooks_add(lttv_hooks_by_id_channel_find( |
728 | event_data->event_by_id_hooks, | |
729 | th->channel, th->id), | |
c88429fb | 730 | th->h, |
731 | th, | |
732 | LTTV_PRIO_DEFAULT); | |
dc06b1bc | 733 | |
dc06b1bc | 734 | } |
735 | /* Initalize the EventsRequest structure */ | |
736 | events_request->owner = event_data; | |
737 | events_request->viewer_data = event_data; | |
738 | events_request->servicing = FALSE; | |
739 | events_request->start_time = event_data->time_window.start_time; | |
740 | events_request->start_position = NULL; | |
741 | events_request->stop_flag = FALSE; | |
742 | events_request->end_time = event_data->time_window.end_time; | |
743 | events_request->num_events = G_MAXUINT; | |
744 | events_request->end_position = NULL; | |
745 | events_request->trace = i; | |
746 | ||
747 | events_request->hooks = hooks; | |
748 | ||
749 | events_request->before_chunk_traceset = NULL; | |
750 | events_request->before_chunk_trace = NULL; | |
751 | events_request->before_chunk_tracefile= NULL; | |
752 | events_request->event = NULL; | |
750eb11a | 753 | events_request->event_by_id_channel = event_data->event_by_id_hooks; |
dc06b1bc | 754 | events_request->after_chunk_tracefile = NULL; |
755 | events_request->after_chunk_trace = NULL; | |
756 | events_request->after_chunk_traceset = NULL; | |
757 | events_request->before_request = NULL; | |
758 | events_request->after_request = event_data->hooks_trace_after; | |
759 | ||
760 | lttvwindow_events_request(event_data->tab, events_request); | |
761 | } | |
e5258c09 | 762 | return FALSE; |
dc06b1bc | 763 | } |
764 | ||
ecafd9df | 765 | /** |
766 | * This function calculates the average duration for each Irq Id | |
767 | * | |
768 | */ | |
dc06b1bc | 769 | static void CalculateAverageDurationForEachIrqId(InterruptEventData *event_data) |
770 | { | |
771 | guint64 real_data; | |
772 | Irq *element; | |
773 | gint i; | |
774 | GArray* FirstRequestIrqExit = event_data->FirstRequestIrqExit; | |
775 | for(i = 0; i < FirstRequestIrqExit->len; i++) | |
776 | { | |
777 | element = &g_array_index(FirstRequestIrqExit,Irq,i); | |
778 | real_data = element->total_duration.tv_sec; | |
779 | real_data *= NANOSECONDS_PER_SECOND; | |
780 | real_data += element->total_duration.tv_nsec; | |
31935b31 | 781 | if(element->TotalNumberOfInterrupts != 0) |
782 | element->average_duration = real_data / element->TotalNumberOfInterrupts; | |
ecafd9df | 783 | else |
784 | element->average_duration = 0; | |
dc06b1bc | 785 | } |
786 | ||
787 | } | |
788 | ||
e5258c09 | 789 | /** |
790 | * This function is called whenever an irq_entry event occurs. Use in the second request | |
791 | * | |
792 | */ | |
dc06b1bc | 793 | static gboolean SecondRequestIrqEntryCallback(void *hook_data, void *call_data) |
794 | { | |
795 | ||
796 | LttTime event_time; | |
797 | unsigned cpu_id; | |
798 | irq_entry entry; | |
799 | LttvTracefileContext *tfc = (LttvTracefileContext *)call_data; | |
800 | LttvTracefileState *tfs = (LttvTracefileState *)call_data; | |
c88429fb | 801 | LttvTraceHook *th = (LttvTraceHook *)hook_data; |
802 | EventsRequest *events_request = (EventsRequest*)th->hook_data; | |
803 | InterruptEventData *event_data = events_request->viewer_data; | |
dc06b1bc | 804 | GArray* SecondRequestIrqEntry = event_data->SecondRequestIrqEntry; |
805 | LttEvent *e = ltt_tracefile_get_event(tfc->tf); | |
806 | event_time = ltt_event_time(e); | |
c88429fb | 807 | cpu_id = tfs->cpu; |
dc06b1bc | 808 | |
809 | ||
c88429fb | 810 | entry.id = ltt_event_get_long_unsigned(e, lttv_trace_get_hook_field(th, 0)); |
dc06b1bc | 811 | entry.cpu_id = cpu_id; |
812 | entry.event_time = event_time; | |
813 | g_array_append_val (SecondRequestIrqEntry, entry); | |
814 | ||
815 | return FALSE; | |
816 | } | |
817 | ||
e5258c09 | 818 | /** |
819 | * This function is called whenever an irq_exit event occurs in the second request. | |
820 | * | |
821 | */ | |
dc06b1bc | 822 | static gboolean SecondRequestIrqExitCallback(void *hook_data, void *call_data) |
823 | { | |
824 | ||
825 | LttvTracefileContext *tfc = (LttvTracefileContext *)call_data; | |
826 | LttvTracefileState *tfs = (LttvTracefileState *)call_data; | |
c88429fb | 827 | LttvTraceHook *th = (LttvTraceHook *)hook_data; |
828 | EventsRequest *events_request = (EventsRequest*)th->hook_data; | |
829 | InterruptEventData *event_data = events_request->viewer_data; | |
830 | ||
dc06b1bc | 831 | LttEvent *event = ltt_tracefile_get_event(tfc->tf); |
832 | ||
c88429fb | 833 | CalculateXi(event, event_data, tfs->cpu); |
dc06b1bc | 834 | return FALSE; |
835 | } | |
836 | ||
e5258c09 | 837 | |
838 | /** | |
839 | * This function is called whenever an irq_exit event occurs in the second request. | |
840 | * | |
841 | */ | |
c88429fb | 842 | static void CalculateXi(LttEvent *event_irq_exit, InterruptEventData *event_data, guint cpu_id) |
dc06b1bc | 843 | { |
844 | gint i, irq_id; | |
845 | irq_entry *element; | |
846 | LttTime Xi; | |
847 | LttTime exit_time; | |
dc06b1bc | 848 | |
dc06b1bc | 849 | GArray *SecondRequestIrqEntry = event_data->SecondRequestIrqEntry; |
dc06b1bc | 850 | for(i = 0; i < SecondRequestIrqEntry->len; i++) |
851 | { | |
852 | element = &g_array_index(SecondRequestIrqEntry,irq_entry,i); | |
853 | if(element->cpu_id == cpu_id) | |
854 | { | |
855 | ||
856 | /* time calculation */ | |
857 | exit_time = ltt_event_time(event_irq_exit); | |
858 | Xi = ltt_time_sub(exit_time, element->event_time); | |
859 | irq_id = element->id; | |
860 | ||
861 | SumItems(irq_id, Xi,event_data); | |
862 | g_array_remove_index(SecondRequestIrqEntry, i); | |
863 | break; | |
864 | } | |
865 | } | |
866 | } | |
867 | ||
e5258c09 | 868 | |
869 | /** | |
870 | * This function computes the Sum ((xi -Xa)^2) and store the result in SumArray | |
871 | * | |
872 | */ | |
dc06b1bc | 873 | static void SumItems(gint irq_id, LttTime Xi, InterruptEventData *event_data) |
874 | { | |
875 | gint i; | |
6b0817c2 | 876 | guint Xi_in_ns; |
dc06b1bc | 877 | |
6b0817c2 | 878 | gint duration_inner_part; |
879 | guint64 period_inner_part; | |
ecafd9df | 880 | guint64 frequency_inner_part; |
881 | ||
dc06b1bc | 882 | Irq *average; |
883 | SumId *sumItem; | |
884 | SumId sum; | |
6b0817c2 | 885 | int FrequencyHZ = 0; |
dc06b1bc | 886 | gboolean notFound = FALSE; |
887 | GArray *FirstRequestIrqExit = event_data->FirstRequestIrqExit; | |
888 | GArray *SumArray = event_data->SumArray; | |
6b0817c2 | 889 | Xi_in_ns = Xi.tv_sec; |
890 | Xi_in_ns *= NANOSECONDS_PER_SECOND; | |
891 | Xi_in_ns += Xi.tv_nsec; | |
dc06b1bc | 892 | |
893 | for(i = 0; i < FirstRequestIrqExit->len; i++) | |
894 | { | |
895 | average = &g_array_index(FirstRequestIrqExit,Irq,i); | |
896 | if(irq_id == average->id) | |
897 | { | |
6b0817c2 | 898 | duration_inner_part = Xi_in_ns - average->average_duration; |
31935b31 | 899 | FrequencyHZ = FrequencyInHZ(average->TotalNumberOfInterrupts, event_data->time_window); |
dc06b1bc | 900 | sum.irqId = irq_id; |
ecafd9df | 901 | // compute (xi -Xa)^2 of the duration Standard deviation |
31935b31 | 902 | sum.TotalNumberOfInterrupts = average->TotalNumberOfInterrupts; |
6b0817c2 | 903 | sum.sumOfDurations = pow (duration_inner_part , 2); |
ecafd9df | 904 | |
905 | // compute (xi -Xa)^2 of the period Standard deviation | |
6b0817c2 | 906 | period_inner_part = CalculatePeriodInnerPart(Xi_in_ns, FrequencyHZ); |
ecafd9df | 907 | |
908 | // compute (xi -Xa)^2 of the frequency Standard deviation | |
909 | frequency_inner_part = CalculateFrequencyInnerPart(Xi_in_ns, FrequencyHZ); | |
910 | ||
6b0817c2 | 911 | sum.sumOfPeriods = period_inner_part; |
ecafd9df | 912 | |
913 | sum.sumOfFrequencies = frequency_inner_part; | |
914 | ||
dc06b1bc | 915 | if(event_data->SumArray->len == NO_ITEMS) |
916 | { | |
917 | g_array_append_val (SumArray, sum); | |
918 | } | |
919 | else | |
6b0817c2 | 920 | { |
dc06b1bc | 921 | for(i = 0; i < SumArray->len; i++) |
922 | { | |
923 | sumItem = &g_array_index(SumArray, SumId, i); | |
924 | if(sumItem->irqId == irq_id) | |
925 | { | |
926 | notFound = TRUE; | |
927 | sumItem->sumOfDurations += sum.sumOfDurations; | |
6b0817c2 | 928 | sumItem->sumOfPeriods += sum.sumOfPeriods; |
ecafd9df | 929 | sumItem->sumOfFrequencies += sum.sumOfFrequencies; |
930 | } | |
dc06b1bc | 931 | } |
932 | if(!notFound) | |
933 | { | |
934 | g_array_append_val (SumArray, sum); | |
935 | } | |
6b0817c2 | 936 | |
dc06b1bc | 937 | } |
938 | ||
939 | } | |
940 | } | |
941 | } | |
942 | ||
ecafd9df | 943 | /** |
944 | * This function computes the inner part of the period standard deviation = sqrt(1/N Sum ((xi -Xa)^2)) | |
945 | * The inner part is: (xi -Xa)^2 | |
946 | */ | |
6b0817c2 | 947 | static guint64 CalculatePeriodInnerPart(guint Xi, guint FrequencyHZ) |
948 | { | |
949 | ||
950 | double periodInSec; /*period in sec*/ | |
951 | int periodInNSec; | |
952 | gint difference; | |
953 | guint64 result; | |
954 | periodInSec = (double)1/FrequencyHZ; | |
955 | periodInSec *= NANOSECONDS_PER_SECOND; | |
956 | periodInNSec = (int)periodInSec; | |
957 | ||
958 | difference = Xi - periodInNSec; | |
959 | result = pow (difference , 2); | |
6b0817c2 | 960 | return result; |
ecafd9df | 961 | } |
6b0817c2 | 962 | |
ecafd9df | 963 | /** |
964 | * This function computes the inner part of the frequency standard deviation = sqrt(1/N Sum ((xi -Xa)^2)) | |
965 | * The inner part is: (xi -Xa)^2 | |
966 | */ | |
967 | static guint64 CalculateFrequencyInnerPart(guint Xi_in_ns, guint FrequencyHZ) | |
968 | { | |
969 | guint64 result; | |
970 | gint difference; | |
971 | ||
972 | difference = Xi_in_ns - FrequencyHZ; | |
973 | result = pow (difference , 2); | |
974 | return result; | |
6b0817c2 | 975 | } |
f2ec7aa9 | 976 | /** |
977 | * This function displays the result on the viewer | |
978 | * | |
979 | */ | |
dc06b1bc | 980 | static gboolean DisplayViewer(void *hook_data, void *call_data) |
981 | { | |
f2ec7aa9 | 982 | gint i; |
983 | Irq element; | |
f2ec7aa9 | 984 | GtkTreeIter iter; |
985 | guint64 real_data; | |
446b4179 | 986 | guint maxIRQduration; |
05600f3b | 987 | guint minIRQduration; |
6b0817c2 | 988 | double periodInSec; |
43ed82b5 | 989 | int periodInNsec = 0; |
e5258c09 | 990 | char maxIrqHandler[80]; |
05600f3b | 991 | char minIrqHandler[80]; |
f2ec7aa9 | 992 | InterruptEventData *event_data = (InterruptEventData *)hook_data; |
dc06b1bc | 993 | GArray *FirstRequestIrqExit = event_data->FirstRequestIrqExit; |
52948a62 | 994 | int FrequencyHZ = 0; |
6b0817c2 | 995 | periodInSec = 0; |
f2ec7aa9 | 996 | gtk_list_store_clear(event_data->ListStore); |
dc06b1bc | 997 | for(i = 0; i < FirstRequestIrqExit->len; i++) |
231a6432 | 998 | { |
dc06b1bc | 999 | element = g_array_index(FirstRequestIrqExit,Irq,i); |
f2ec7aa9 | 1000 | real_data = element.total_duration.tv_sec; |
1001 | real_data *= NANOSECONDS_PER_SECOND; | |
1002 | real_data += element.total_duration.tv_nsec; | |
446b4179 | 1003 | |
1004 | ||
1005 | maxIRQduration = element.max_irq_handler.duration.tv_sec; | |
1006 | maxIRQduration *= NANOSECONDS_PER_SECOND; | |
1007 | maxIRQduration += element.max_irq_handler.duration.tv_nsec; | |
e5258c09 | 1008 | |
43ed82b5 | 1009 | sprintf(maxIrqHandler, "%d [%lu.%lu - %lu.%lu]",maxIRQduration, element.max_irq_handler.start_time.tv_sec, \ |
fc77fe59 | 1010 | element.max_irq_handler.start_time.tv_nsec, element.max_irq_handler.end_time.tv_sec, \ |
1011 | element.max_irq_handler.end_time.tv_nsec) ; | |
05600f3b | 1012 | |
1013 | minIRQduration = element.min_irq_handler.duration.tv_sec; | |
1014 | minIRQduration *= NANOSECONDS_PER_SECOND; | |
1015 | minIRQduration += element.min_irq_handler.duration.tv_nsec; | |
43ed82b5 | 1016 | sprintf(minIrqHandler, "%d [%lu.%lu - %lu.%lu]",minIRQduration, element.min_irq_handler.start_time.tv_sec, \ |
05600f3b | 1017 | element.min_irq_handler.start_time.tv_nsec, element.min_irq_handler.end_time.tv_sec, \ |
1018 | element.min_irq_handler.end_time.tv_nsec) ; | |
1019 | ||
1020 | ||
31935b31 | 1021 | FrequencyHZ = FrequencyInHZ(element.TotalNumberOfInterrupts,event_data->time_window); |
6b0817c2 | 1022 | |
8d8c5ea7 AM |
1023 | if(FrequencyHZ != 0) |
1024 | { | |
6b0817c2 | 1025 | periodInSec = (double)1/FrequencyHZ; |
1026 | periodInSec *= NANOSECONDS_PER_SECOND; | |
1027 | periodInNsec = (int)periodInSec; | |
ecafd9df | 1028 | |
8d8c5ea7 | 1029 | } |
6b0817c2 | 1030 | |
f2ec7aa9 | 1031 | gtk_list_store_append (event_data->ListStore, &iter); |
1032 | gtk_list_store_set (event_data->ListStore, &iter, | |
1033 | CPUID_COLUMN, element.cpu_id, | |
1034 | IRQ_ID_COLUMN, element.id, | |
52948a62 | 1035 | FREQUENCY_COLUMN, FrequencyHZ, |
f2ec7aa9 | 1036 | DURATION_COLUMN, real_data, |
6b0817c2 | 1037 | DURATION_STANDARD_DEV_COLUMN, CalculateDurationStandardDeviation(element.id, event_data), |
e5258c09 | 1038 | MAX_IRQ_HANDLER_COLUMN, maxIrqHandler, |
05600f3b | 1039 | MIN_IRQ_HANDLER_COLUMN, minIrqHandler, |
6b0817c2 | 1040 | AVERAGE_PERIOD , periodInNsec, |
1041 | PERIOD_STANDARD_DEV_COLUMN, CalculatePeriodStandardDeviation(element.id, event_data), | |
ecafd9df | 1042 | FREQUENCY_STANDARD_DEV_COLUMN, CalculateFrequencyStandardDeviation(element.id, event_data), |
8f72bb94 | 1043 | -1); |
f2ec7aa9 | 1044 | } |
dc06b1bc | 1045 | |
dc06b1bc | 1046 | |
1047 | if(event_data->FirstRequestIrqExit->len) | |
231a6432 | 1048 | { |
dc06b1bc | 1049 | g_array_remove_range (event_data->FirstRequestIrqExit,0,event_data->FirstRequestIrqExit->len); |
231a6432 | 1050 | } |
1051 | ||
dc06b1bc | 1052 | if(event_data->FirstRequestIrqEntry->len) |
231a6432 | 1053 | { |
dc06b1bc | 1054 | g_array_remove_range (event_data->FirstRequestIrqEntry,0,event_data->FirstRequestIrqEntry->len); |
1055 | } | |
1056 | ||
1057 | if(event_data->SecondRequestIrqEntry->len) | |
1058 | { | |
1059 | g_array_remove_range (event_data->SecondRequestIrqEntry,0,event_data->SecondRequestIrqEntry->len); | |
1060 | } | |
231a6432 | 1061 | |
dc06b1bc | 1062 | if(event_data->SecondRequestIrqExit->len) |
1063 | { | |
1064 | g_array_remove_range (event_data->SecondRequestIrqExit,0, event_data->SecondRequestIrqExit->len); | |
1065 | } | |
1066 | ||
1067 | if(event_data->SumArray->len) | |
1068 | { | |
1069 | g_array_remove_range (event_data->SumArray,0, event_data->SumArray->len); | |
231a6432 | 1070 | } |
dc06b1bc | 1071 | |
f2ec7aa9 | 1072 | return FALSE; |
5f5119ee | 1073 | } |
dc06b1bc | 1074 | |
25c6412d | 1075 | |
6b0817c2 | 1076 | /** |
1077 | * This function converts the number of interrupts over a time window to | |
1078 | * frequency in HZ | |
1079 | */ | |
ecafd9df | 1080 | static int FrequencyInHZ(gint NumerofInterruptions, TimeWindow time_window) |
25c6412d | 1081 | { |
1082 | guint64 frequencyHz = 0; | |
6b0817c2 | 1083 | double timeSec; // time in second |
1084 | double result; | |
1085 | result = ltt_time_to_double(time_window.time_width); | |
1086 | timeSec = (result/NANOSECONDS_PER_SECOND); //time in second | |
ecafd9df | 1087 | frequencyHz = NumerofInterruptions / timeSec; |
25c6412d | 1088 | return frequencyHz; |
1089 | } | |
1090 | ||
e5258c09 | 1091 | /** |
6b0817c2 | 1092 | * This function calculates the duration standard deviation |
ecafd9df | 1093 | * Duration standard deviation = sqrt(1/N Sum ((xi -Xa)^2)) |
1094 | * Where: | |
1095 | * sumId.sumOfDurations -> Sum ((xi -Xa)^2) | |
1096 | * inner_component -> 1/N Sum ((xi -Xa)^2) | |
1097 | * deviation-> sqrt(1/N Sum ((xi -Xa)^2)) | |
e5258c09 | 1098 | */ |
6b0817c2 | 1099 | static int CalculateDurationStandardDeviation(gint id, InterruptEventData *event_data) |
dc06b1bc | 1100 | { |
1101 | int i; | |
1102 | SumId sumId; | |
1103 | double inner_component; | |
1104 | int deviation = 0; | |
1105 | for(i = 0; i < event_data->SumArray->len; i++) | |
1106 | { | |
1107 | sumId = g_array_index(event_data->SumArray, SumId, i); | |
1108 | if(id == sumId.irqId) | |
1109 | { | |
31935b31 | 1110 | if(sumId.TotalNumberOfInterrupts != 0) |
1111 | inner_component = sumId.sumOfDurations/ sumId.TotalNumberOfInterrupts; | |
ecafd9df | 1112 | else |
1113 | inner_component = 0.0; | |
dc06b1bc | 1114 | deviation = sqrt(inner_component); |
25c6412d | 1115 | return deviation; |
dc06b1bc | 1116 | } |
1117 | } | |
1118 | return deviation; | |
1119 | } | |
6b0817c2 | 1120 | |
1121 | ||
1122 | /** | |
1123 | * This function calculates the period standard deviation | |
ecafd9df | 1124 | * Period standard deviation = sqrt(1/N Sum ((xi -Xa)^2)) |
1125 | * Where: | |
1126 | * sumId.sumOfPeriods -> Sum ((xi -Xa)^2) | |
1127 | * inner_component -> 1/N Sum ((xi -Xa)^2) | |
1128 | * period_standard_deviation-> sqrt(1/N Sum ((xi -Xa)^2)) | |
1129 | ||
6b0817c2 | 1130 | * |
1131 | */ | |
1132 | static int CalculatePeriodStandardDeviation(gint id, InterruptEventData *event_data) | |
1133 | { | |
1134 | int i; | |
1135 | SumId sumId; | |
1136 | guint64 inner_component; | |
1137 | guint64 period_standard_deviation = 0; | |
ecafd9df | 1138 | |
6b0817c2 | 1139 | for(i = 0; i < event_data->SumArray->len; i++) |
1140 | { | |
1141 | sumId = g_array_index(event_data->SumArray, SumId, i); | |
1142 | if(id == sumId.irqId) | |
1143 | { | |
31935b31 | 1144 | if(sumId.TotalNumberOfInterrupts != 0) |
1145 | inner_component = sumId.sumOfPeriods / sumId.TotalNumberOfInterrupts; | |
ecafd9df | 1146 | else |
1147 | inner_component = 0; | |
1148 | ||
6b0817c2 | 1149 | period_standard_deviation = sqrt(inner_component); |
1150 | } | |
1151 | } | |
1152 | ||
1153 | return period_standard_deviation; | |
1154 | } | |
ecafd9df | 1155 | |
1156 | /** | |
1157 | * This function calculates the frequency standard deviation | |
1158 | * Frequency standard deviation = sqrt(1/N Sum ((xi -Xa)^2)) | |
1159 | * Where: | |
1160 | * sumId.sumOfFrequencies -> Sum ((xi -Xa)^2) | |
1161 | * inner_component -> 1/N Sum ((xi -Xa)^2) | |
1162 | * frequency_standard_deviation-> sqrt(1/N Sum ((xi -Xa)^2)) | |
1163 | * | |
1164 | */ | |
1165 | static int CalculateFrequencyStandardDeviation(gint id, InterruptEventData *event_data) | |
1166 | { | |
1167 | int i; | |
1168 | SumId sumId; | |
1169 | guint64 inner_component; | |
1170 | guint64 frequency_standard_deviation = 0; | |
1171 | for(i = 0; i < event_data->SumArray->len; i++) | |
1172 | { | |
1173 | sumId = g_array_index(event_data->SumArray, SumId, i); | |
1174 | if(id == sumId.irqId) | |
1175 | { | |
31935b31 | 1176 | if(sumId.TotalNumberOfInterrupts != 0) |
1177 | inner_component = sumId.sumOfFrequencies / sumId.TotalNumberOfInterrupts; | |
ecafd9df | 1178 | else |
1179 | inner_component = 0; | |
1180 | ||
1181 | frequency_standard_deviation = sqrt(inner_component); | |
1182 | } | |
1183 | } | |
1184 | return frequency_standard_deviation; | |
1185 | } | |
1186 | ||
f2ec7aa9 | 1187 | /* |
1188 | * This function is called by the main window | |
1189 | * when the time interval needs to be updated. | |
1190 | **/ | |
1191 | gboolean interrupt_update_time_window(void * hook_data, void * call_data) | |
1192 | { | |
5f5119ee | 1193 | InterruptEventData *event_data = (InterruptEventData *) hook_data; |
1194 | const TimeWindowNotifyData *time_window_nofify_data = ((const TimeWindowNotifyData *)call_data); | |
1195 | event_data->time_window = *time_window_nofify_data->new_time_window; | |
1196 | g_info("interrupts: interrupt_update_time_window()\n"); | |
1197 | Tab *tab = event_data->tab; | |
1198 | lttvwindow_events_request_remove_all(tab, event_data); | |
dc06b1bc | 1199 | FirstRequest(event_data ); |
f2ec7aa9 | 1200 | return FALSE; |
5f5119ee | 1201 | } |
1202 | ||
f2ec7aa9 | 1203 | |
1204 | gboolean trace_header(void *hook_data, void *call_data) | |
1205 | { | |
f2ec7aa9 | 1206 | return FALSE; |
5f5119ee | 1207 | } |
1208 | ||
f2ec7aa9 | 1209 | void interrupt_destroy_walk(gpointer data, gpointer user_data) |
1210 | { | |
5f5119ee | 1211 | g_info("interrupt_destroy_walk"); |
1212 | interrupt_destructor((InterruptEventData*)data); | |
5f5119ee | 1213 | } |
1214 | ||
fc77fe59 | 1215 | |
f2ec7aa9 | 1216 | void interrupt_destructor(InterruptEventData *event_viewer_data) |
1217 | { | |
1218 | /* May already been done by GTK window closing */ | |
1219 | g_info("enter interrupt_destructor \n"); | |
1220 | if(GTK_IS_WIDGET(event_viewer_data->Hbox)) | |
1221 | { | |
1222 | gtk_widget_destroy(event_viewer_data->Hbox); | |
1223 | } | |
1224 | } | |
1225 | ||
fc77fe59 | 1226 | /** |
1227 | This function is called when the viewer is destroyed to free hooks and memory | |
1228 | */ | |
1229 | static void InterruptFree(InterruptEventData *event_viewer_data) | |
1230 | { | |
1231 | Tab *tab = event_viewer_data->tab; | |
1232 | if(tab != NULL) | |
1233 | { | |
1234 | ||
1235 | g_array_free(event_viewer_data->FirstRequestIrqExit, TRUE); | |
1236 | g_array_free(event_viewer_data->FirstRequestIrqEntry, TRUE); | |
1237 | g_array_free(event_viewer_data->SecondRequestIrqEntry, TRUE); | |
1238 | g_array_free(event_viewer_data->SecondRequestIrqExit, TRUE); | |
1239 | g_array_free(event_viewer_data->SumArray, TRUE); | |
1240 | ||
1241 | lttvwindow_unregister_time_window_notify(tab, interrupt_update_time_window, event_viewer_data); | |
1242 | ||
1243 | lttvwindow_events_request_remove_all(event_viewer_data->tab, | |
1244 | event_viewer_data); | |
1245 | ||
1246 | interrupt_data_list = g_slist_remove(interrupt_data_list, event_viewer_data); | |
1247 | ||
1248 | } | |
1249 | ||
1250 | } | |
1251 | ||
5f5119ee | 1252 | /** |
1253 | * plugin's destroy function | |
1254 | * | |
1255 | * This function releases the memory reserved by the module and unregisters | |
1256 | * everything that has been registered in the gtkTraceSet API. | |
1257 | */ | |
dc06b1bc | 1258 | static void destroy() |
1259 | { | |
1260 | ||
5f5119ee | 1261 | g_info("Destroy interrupts"); |
1262 | g_slist_foreach(interrupt_data_list, interrupt_destroy_walk, NULL ); | |
1263 | g_slist_free(interrupt_data_list); | |
1264 | lttvwindow_unregister_constructor(interrupts); | |
1265 | ||
1266 | } | |
1267 | ||
1268 | LTTV_MODULE("interrupts", "interrupts info view", \ | |
1269 | "Graphical module to display interrupts performance", \ | |
1270 | init, destroy, "lttvwindow") |