fix format
[lttv.git] / ltt / branches / poly / lttv / modules / gui / interrupts / interrupts.c
CommitLineData
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 /******************************************************************
e5258c09 20
21 The standard deviation calculation is based on:
dc06b1bc 22 http://en.wikipedia.org/wiki/Standard_deviation
23
e5258c09 24 Standard_deviation = sqrt(1/N Sum ((xi -Xa)^2))
dc06b1bc 25
e5258c09 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.
33
dc06b1bc 34 *******************************************************************/
5f5119ee 35
36
37
38#include <math.h>
39#include <glib.h>
40#include <gtk/gtk.h>
41#include <gdk/gdk.h>
42#include <stdio.h>
43#include <stdlib.h>
dc06b1bc 44#include <math.h>
5f5119ee 45#include <string.h>
46#include <ltt/ltt.h>
47#include <ltt/event.h>
48#include <ltt/type.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>
57#include <ltt/time.h>
58
59#include "hInterruptsInsert.xpm"
60
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)
63#define NO_ITEMS 0
64
446b4179 65typedef struct
66{
67 LttTime duration;
68 LttTime start_time;
69 LttTime end_time;
70}MaxDuration;
71
5f5119ee 72typedef struct {
73 guint cpu_id;
74 guint id;
75 guint frequency;
76 LttTime total_duration;
dc06b1bc 77 guint average_duration;
446b4179 78 MaxDuration max_irq_handler;
dc06b1bc 79
5f5119ee 80}Irq;
81
82typedef struct {
83 guint id;
84 guint cpu_id;
85 LttTime event_time;
86}irq_entry;
87
dc06b1bc 88
89typedef struct
90{
91 guint irqId;
92 guint frequency;
93 guint64 sumOfDurations;
94
95}SumId;
96
5f5119ee 97enum type_t {
98 IRQ_ENTRY,
99 IRQ_EXIT
100};
101
102/** Array containing instanced objects. Used when module is unloaded */
103static GSList *interrupt_data_list = NULL ;
104
105
f2ec7aa9 106#define TRACE_NUMBER 0
107
5f5119ee 108typedef struct _InterruptEventData {
109
b3e7b125 110 /*Graphical Widgets */
111 GtkWidget * ScrollWindow;
112 GtkListStore *ListStore;
113 GtkWidget *Hbox;
114 GtkWidget *TreeView;
115 GtkTreeSelection *SelectionTree;
116
117 Tab * tab; /* tab that contains this plug-in*/
5f5119ee 118 LttvHooks * event_hooks;
119 LttvHooks * hooks_trace_after;
120 LttvHooks * hooks_trace_before;
b3e7b125 121 TimeWindow time_window;
f2ec7aa9 122 LttvHooksById * event_by_id_hooks;
dc06b1bc 123 GArray *FirstRequestIrqExit;
124 GArray *FirstRequestIrqEntry;
125 GArray *SecondRequestIrqEntry;
126 GArray *SecondRequestIrqExit;
127 GArray *SumArray;
128
5f5119ee 129} InterruptEventData ;
130
f2ec7aa9 131
b3e7b125 132/* Function prototypes */
5f5119ee 133
134static gboolean interrupt_update_time_window(void * hook_data, void * call_data);
f2ec7aa9 135static GtkWidget *interrupts(Tab *tab);
136static InterruptEventData *system_info(Tab *tab);
5f5119ee 137void interrupt_destructor(InterruptEventData *event_viewer_data);
dc06b1bc 138static void FirstRequest(InterruptEventData *event_data );
f2ec7aa9 139static guint64 get_interrupt_id(LttEvent *e);
5f5119ee 140static gboolean trace_header(void *hook_data, void *call_data);
dc06b1bc 141static gboolean DisplayViewer (void *hook_data, void *call_data);
e5258c09 142static void CalculateData(LttTime time_exit, guint cpu_id, InterruptEventData *event_data);
143static void TotalDurationMaxIrqDuration(irq_entry *e, LttTime time_exit, GArray *FirstRequestIrqExit);
dc06b1bc 144static gboolean FirstRequestIrqEntryCallback(void *hook_data, void *call_data);
145static gboolean FirstRequestIrqExitCallback(void *hook_data, void *call_data);
146static gboolean SecondRequest(void *hook_data, void *call_data);
147static void CalculateAverageDurationForEachIrqId(InterruptEventData *event_data);
148static gboolean SecondRequestIrqEntryCallback(void *hook_data, void *call_data);
149static gboolean SecondRequestIrqExitCallback(void *hook_data, void *call_data);
150static void CalculateXi(LttEvent *event, InterruptEventData *event_data);
151static void SumItems(gint irq_id, LttTime Xi, InterruptEventData *event_data);
152static int CalculateStandardDeviation(gint id, InterruptEventData *event_data);
25c6412d 153static int FrequencyInHZ(gint frequency, TimeWindow time_window);
154
5f5119ee 155/* Enumeration of the columns */
156enum{
157 CPUID_COLUMN,
158 IRQ_ID_COLUMN,
159 FREQUENCY_COLUMN,
160 DURATION_COLUMN,
dc06b1bc 161 DURATION_STANDARD_DEV_COLUMN,
446b4179 162 MAX_IRQ_HANDLER_COLUMN,
52948a62 163 AVERAGE_PERIOD,
164 PERIOD_STANDARD_DEV_COLUMN,
5f5119ee 165 N_COLUMNS
166};
f2ec7aa9 167
168
169
170/**
171 * init function
172 *
173 *
174 * This is the entry point of the viewer.
175 *
176 */
177static void init() {
178 g_info("interrupts: init()");
179 lttvwindow_register_constructor("interrupts",
180 "/",
181 "Insert Interrupts View",
182 hInterruptsInsert_xpm,
183 "Insert Interrupts View",
184 interrupts);
185
186}
187
5f5119ee 188
5f5119ee 189/**
f2ec7aa9 190 * Constructor hook
5f5119ee 191 *
5f5119ee 192 */
f2ec7aa9 193static GtkWidget *interrupts(Tab * tab)
194{
b3e7b125 195
5f5119ee 196 InterruptEventData* event_data = system_info(tab) ;
197 if(event_data)
b3e7b125 198 return event_data->Hbox;
5f5119ee 199 else
200 return NULL;
201}
202
f2ec7aa9 203/**
204 * This function initializes the Event Viewer functionnality through the
205 * GTK API.
206 */
5f5119ee 207InterruptEventData *system_info(Tab *tab)
208{
dc06b1bc 209
5f5119ee 210 LttTime end;
211 GtkTreeViewColumn *column;
212 GtkCellRenderer *renderer;
213 InterruptEventData* event_viewer_data = g_new(InterruptEventData,1) ;
dc06b1bc 214
5f5119ee 215 event_viewer_data->tab = tab;
f2ec7aa9 216
217 /*Get the current time frame from the main window */
5f5119ee 218 event_viewer_data->time_window = lttvwindow_get_time_window(tab);
dc06b1bc 219
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));
222
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));
225
226 event_viewer_data->SumArray = g_array_new(FALSE, FALSE, sizeof(SumId));
227
228
f2ec7aa9 229 /*Create tha main window for the viewer */
b3e7b125 230 event_viewer_data->ScrollWindow = gtk_scrolled_window_new (NULL, NULL);
231 gtk_widget_show (event_viewer_data->ScrollWindow);
5f5119ee 232 gtk_scrolled_window_set_policy(
b3e7b125 233 GTK_SCROLLED_WINDOW(event_viewer_data->ScrollWindow),
5f5119ee 234 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC/*GTK_POLICY_NEVER*/);
235
236 /* Create a model for storing the data list */
b3e7b125 237 event_viewer_data->ListStore = gtk_list_store_new (
5f5119ee 238 N_COLUMNS, /* Total number of columns */
239 G_TYPE_INT, /* CPUID */
240 G_TYPE_INT, /* IRQ_ID */
241 G_TYPE_INT, /* Frequency */
dc06b1bc 242 G_TYPE_UINT64, /* Duration */
446b4179 243 G_TYPE_INT, /* standard deviation */
52948a62 244 G_TYPE_STRING, /* Max IRQ handler */
245 G_TYPE_DOUBLE, /* Average period */
246 G_TYPE_DOUBLE /* period standard deviation */
5f5119ee 247 );
248
b3e7b125 249 event_viewer_data->TreeView = gtk_tree_view_new_with_model (GTK_TREE_MODEL (event_viewer_data->ListStore));
5f5119ee 250
b3e7b125 251 g_object_unref (G_OBJECT (event_viewer_data->ListStore));
5f5119ee 252
253 renderer = gtk_cell_renderer_text_new ();
254 column = gtk_tree_view_column_new_with_attributes ("CPUID",
255 renderer,
256 "text", CPUID_COLUMN,
257 NULL);
258 gtk_tree_view_column_set_alignment (column, 0.0);
259 gtk_tree_view_column_set_fixed_width (column, 45);
b3e7b125 260 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
5f5119ee 261
262
263 renderer = gtk_cell_renderer_text_new ();
264 column = gtk_tree_view_column_new_with_attributes ("IrqId",
265 renderer,
266 "text", IRQ_ID_COLUMN,
267 NULL);
268 gtk_tree_view_column_set_alignment (column, 0.0);
269 gtk_tree_view_column_set_fixed_width (column, 220);
b3e7b125 270 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
5f5119ee 271
272 renderer = gtk_cell_renderer_text_new ();
52948a62 273 column = gtk_tree_view_column_new_with_attributes ("Frequency (Hz)",
5f5119ee 274 renderer,
275 "text", FREQUENCY_COLUMN,
276 NULL);
277 gtk_tree_view_column_set_alignment (column, 1.0);
278 gtk_tree_view_column_set_fixed_width (column, 220);
b3e7b125 279 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
5f5119ee 280
281 renderer = gtk_cell_renderer_text_new ();
25c6412d 282 column = gtk_tree_view_column_new_with_attributes ("Total Duration (nsec)",
5f5119ee 283 renderer,
284 "text", DURATION_COLUMN,
285 NULL);
286 gtk_tree_view_column_set_alignment (column, 0.0);
287 gtk_tree_view_column_set_fixed_width (column, 145);
b3e7b125 288 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
5f5119ee 289
dc06b1bc 290
291 renderer = gtk_cell_renderer_text_new ();
292 column = gtk_tree_view_column_new_with_attributes ("Duration standard deviation (nsec)",
293 renderer,
294 "text", DURATION_STANDARD_DEV_COLUMN,
295 NULL);
296 gtk_tree_view_column_set_alignment (column, 0.0);
446b4179 297 gtk_tree_view_column_set_fixed_width (column, 200);
dc06b1bc 298 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
299
446b4179 300 renderer = gtk_cell_renderer_text_new ();
25c6412d 301 column = gtk_tree_view_column_new_with_attributes ("Max IRQ handler duration (nsec) [time interval]",
446b4179 302 renderer,
303 "text", MAX_IRQ_HANDLER_COLUMN,
304 NULL);
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);
dc06b1bc 308
52948a62 309 renderer = gtk_cell_renderer_text_new ();
310 column = gtk_tree_view_column_new_with_attributes (" Average period (nsec)",
311 renderer,
312 "text", AVERAGE_PERIOD,
313 NULL);
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);
317
318 renderer = gtk_cell_renderer_text_new ();
319 column = gtk_tree_view_column_new_with_attributes ("Period standard deviation (nsec)",
320 renderer,
321 "text", PERIOD_STANDARD_DEV_COLUMN,
322 NULL);
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);
326
327
dc06b1bc 328
b3e7b125 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);
5f5119ee 331
b3e7b125 332 gtk_container_add (GTK_CONTAINER (event_viewer_data->ScrollWindow), event_viewer_data->TreeView);
5f5119ee 333
b3e7b125 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);
5f5119ee 336
b3e7b125 337 gtk_widget_show(event_viewer_data->Hbox);
338 gtk_widget_show(event_viewer_data->TreeView);
5f5119ee 339
b3e7b125 340 interrupt_data_list = g_slist_append(interrupt_data_list, event_viewer_data);
f2ec7aa9 341 /* Registration for time notification */
b3e7b125 342 lttvwindow_register_time_window_notify(tab,
343 interrupt_update_time_window,
344 event_viewer_data);
f2ec7aa9 345
346
dc06b1bc 347 FirstRequest(event_viewer_data );
5f5119ee 348 return event_viewer_data;
349}
b3e7b125 350
f2ec7aa9 351/**
352 *
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
358 *
359 */
dc06b1bc 360static void FirstRequest(InterruptEventData *event_data )
f2ec7aa9 361{
362 guint i, k, l, nb_trace;
363
364 LttvTraceHook *hook;
365
366 guint ret;
367
368 LttvTraceState *ts;
369
370 GArray *hooks;
371
372 EventsRequest *events_request;
373
374 LttvTraceHookByFacility *thf;
375
376 LttvTracesetContext *tsc = lttvwindow_get_traceset_context(event_data->tab);
5f5119ee 377
f2ec7aa9 378
379 /* Get the traceset */
380 LttvTraceset *traceset = tsc->ts;
5f5119ee 381
f2ec7aa9 382 nb_trace = lttv_traceset_number(traceset);
383
384 /* There are many traces in a traceset. Iteration for each trace. */
385 for(i = 0; i<MIN(TRACE_NUMBER+1, nb_trace);i++)
386 {
387 events_request = g_new(EventsRequest, 1);
388
389 hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook));
390
391 hooks = g_array_set_size(hooks, 2);
b3e7b125 392
f2ec7aa9 393 event_data->hooks_trace_before = lttv_hooks_new();
394
395 /* Registers a hook function */
396 lttv_hooks_add(event_data->hooks_trace_before, trace_header, event_data, LTTV_PRIO_DEFAULT);
397
398 event_data->hooks_trace_after = lttv_hooks_new();
dc06b1bc 399
400 /* Registers a hook function */
401 lttv_hooks_add(event_data->hooks_trace_after, SecondRequest, event_data, LTTV_PRIO_DEFAULT);
f2ec7aa9 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();
b3e7b125 406
f2ec7aa9 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,
dc06b1bc 411 FirstRequestIrqEntryCallback,
f2ec7aa9 412 events_request,
413 &g_array_index(hooks, LttvTraceHook, 0));
414
415 ret = lttv_trace_find_hook(ts->parent.t,
416 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
417 LTT_FIELD_IRQ_ID, 0, 0,
dc06b1bc 418 FirstRequestIrqExitCallback,
f2ec7aa9 419 events_request,
420 &g_array_index(hooks, LttvTraceHook, 1));
421
422 g_assert(!ret);
423 /*iterate through the facility list*/
424 for(k = 0 ; k < hooks->len; k++)
425 {
426 hook = &g_array_index(hooks, LttvTraceHook, k);
427 for(l=0; l<hook->fac_list->len; l++)
428 {
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),
431 thf->h,
432 event_data,
433 LTTV_PRIO_DEFAULT);
434
435 }
436 }
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;
448
449 events_request->hooks = hooks;
450
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;
231a6432 457 events_request->after_chunk_trace = NULL;
f2ec7aa9 458 events_request->after_chunk_traceset = NULL;
231a6432 459 events_request->before_request = NULL;
f2ec7aa9 460 events_request->after_request = event_data->hooks_trace_after;
461
462 lttvwindow_events_request(event_data->tab, events_request);
463 }
464
b3e7b125 465}
5f5119ee 466
f2ec7aa9 467/**
468 * This function is called whenever an irq_entry event occurs.
469 *
470 */
dc06b1bc 471static gboolean FirstRequestIrqEntryCallback(void *hook_data, void *call_data)
f2ec7aa9 472{
473
b3e7b125 474 LttTime event_time;
b3e7b125 475 unsigned cpu_id;
476 irq_entry entry;
b3e7b125 477 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
478 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
f2ec7aa9 479 InterruptEventData *event_data = (InterruptEventData *)hook_data;
dc06b1bc 480 GArray* FirstRequestIrqEntry = event_data->FirstRequestIrqEntry;
f2ec7aa9 481 LttEvent *e = ltt_tracefile_get_event(tfc->tf);
b3e7b125 482 event_time = ltt_event_time(e);
b3e7b125 483 cpu_id = ltt_event_cpu_id(e);
f2ec7aa9 484
231a6432 485
486 entry.id =get_interrupt_id(e);
487 entry.cpu_id = cpu_id;
488 entry.event_time = event_time;
dc06b1bc 489 g_array_append_val (FirstRequestIrqEntry, entry);
231a6432 490
f2ec7aa9 491 return FALSE;
5f5119ee 492}
493
f2ec7aa9 494/**
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.
497 */
498static guint64 get_interrupt_id(LttEvent *e)
5f5119ee 499{
f2ec7aa9 500 guint i, num_fields;
501 LttEventType *event_type;
502 LttField *element;
503 LttField *field;
504 guint64 irq_id;
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++)
508 {
509 field = ltt_eventtype_field(event_type, i);
510 irq_id = ltt_event_get_long_unsigned(e,field);
5f5119ee 511 }
512 return irq_id;
5f5119ee 513
f2ec7aa9 514}
515/**
516 * This function is called whenever an irq_exit event occurs.
517 *
518 */
dc06b1bc 519gboolean FirstRequestIrqExitCallback(void *hook_data, void *call_data)
f2ec7aa9 520{
521 LttTime event_time;
522 unsigned cpu_id;
5f5119ee 523 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
f2ec7aa9 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);
231a6432 530
e5258c09 531 CalculateData( event_time, cpu_id, event_data);
532
231a6432 533 return FALSE;
5f5119ee 534}
535
f2ec7aa9 536/**
537 * This function calculates the duration of an interrupt.
538 *
539 */
e5258c09 540static void CalculateData(LttTime time_exit, guint cpu_id,InterruptEventData *event_data)
dc06b1bc 541{
5f5119ee 542
f2ec7aa9 543 gint i, irq_id;
544 irq_entry *element;
545 LttTime duration;
dc06b1bc 546 GArray *FirstRequestIrqExit = event_data->FirstRequestIrqExit;
547 GArray *FirstRequestIrqEntry = event_data->FirstRequestIrqEntry;
548 for(i = 0; i < FirstRequestIrqEntry->len; i++)
231a6432 549 {
dc06b1bc 550 element = &g_array_index(FirstRequestIrqEntry,irq_entry,i);
231a6432 551 if(element->cpu_id == cpu_id)
552 {
e5258c09 553 TotalDurationMaxIrqDuration(element,time_exit, FirstRequestIrqExit);
dc06b1bc 554 g_array_remove_index(FirstRequestIrqEntry, i);
f2ec7aa9 555 break;
556 }
557 }
e5258c09 558}
dc06b1bc 559
f2ec7aa9 560/**
e5258c09 561 * This function calculates the total duration of an interrupt and the longest Irq handler.
f2ec7aa9 562 *
563 */
e5258c09 564static void TotalDurationMaxIrqDuration(irq_entry *e, LttTime time_exit, GArray *FirstRequestIrqExit){
5f5119ee 565 Irq irq;
566 Irq *element;
567 guint i;
568 LttTime duration;
569 gboolean notFound = FALSE;
570 memset ((void*)&irq, 0,sizeof(Irq));
571
231a6432 572 /*first time*/
dc06b1bc 573 if(FirstRequestIrqExit->len == NO_ITEMS)
231a6432 574 {
5f5119ee 575 irq.cpu_id = e->cpu_id;
576 irq.id = e->id;
577 irq.frequency++;
578 irq.total_duration = ltt_time_sub(time_exit, e->event_time);
e5258c09 579
446b4179 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);
e5258c09 583
446b4179 584
dc06b1bc 585 g_array_append_val (FirstRequestIrqExit, irq);
5f5119ee 586 }
231a6432 587 else
588 {
dc06b1bc 589 for(i = 0; i < FirstRequestIrqExit->len; i++)
231a6432 590 {
dc06b1bc 591 element = &g_array_index(FirstRequestIrqExit,Irq,i);
592 if(element->id == e->id)
593 {
5f5119ee 594 notFound = TRUE;
595 duration = ltt_time_sub(time_exit, e->event_time);
596 element->total_duration = ltt_time_add(element->total_duration, duration);
597 element->frequency++;
446b4179 598 if(ltt_time_compare(duration,element->max_irq_handler.duration) > 0)
599 {
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;
603 }
5f5119ee 604 }
605 }
231a6432 606 if(!notFound)
607 {
5f5119ee 608 irq.cpu_id = e->cpu_id;
609 irq.id = e->id;
610 irq.frequency++;
611 irq.total_duration = ltt_time_sub(time_exit, e->event_time);
446b4179 612
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);
616
dc06b1bc 617 g_array_append_val (FirstRequestIrqExit, irq);
5f5119ee 618 }
619 }
620}
231a6432 621
e5258c09 622/**
623 * This function passes the second EventsRequest to LTTV
624 *
625 */
dc06b1bc 626static gboolean SecondRequest(void *hook_data, void *call_data)
627{
628
629 guint i, k, l, nb_trace;
630
631 LttvTraceHook *hook;
632
633 guint ret;
634
635 LttvTraceState *ts;
636
637 GArray *hooks;
638
639 EventsRequest *events_request;
640
641 LttvTraceHookByFacility *thf;
642
643 InterruptEventData *event_data = (InterruptEventData *)hook_data;
644
645 LttvTracesetContext *tsc = lttvwindow_get_traceset_context(event_data->tab);
646
647 CalculateAverageDurationForEachIrqId(event_data);
648
649 /* Get the traceset */
650 LttvTraceset *traceset = tsc->ts;
651
652 nb_trace = lttv_traceset_number(traceset);
653
654 /* There are many traces in a traceset. Iteration for each trace. */
655 for(i = 0; i<MIN(TRACE_NUMBER+1, nb_trace);i++)
656 {
657 events_request = g_new(EventsRequest, 1);
658
659 hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook));
660
661 hooks = g_array_set_size(hooks, 2);
662
663 event_data->hooks_trace_after = lttv_hooks_new();
664
665 /* Registers a hook function */
666 lttv_hooks_add(event_data->hooks_trace_after, DisplayViewer, event_data, LTTV_PRIO_DEFAULT);
667
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();
672
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,
678 events_request,
679 &g_array_index(hooks, LttvTraceHook, 0));
680
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,
685 events_request,
686 &g_array_index(hooks, LttvTraceHook, 1));
687
688 g_assert(!ret);
e5258c09 689
690 /* iterate through the facility list */
dc06b1bc 691 for(k = 0 ; k < hooks->len; k++)
692 {
693 hook = &g_array_index(hooks, LttvTraceHook, k);
694 for(l=0; l<hook->fac_list->len; l++)
695 {
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),
698 thf->h,
699 event_data,
700 LTTV_PRIO_DEFAULT);
701
702 }
703 }
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;
715
716 events_request->hooks = hooks;
717
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;
728
729 lttvwindow_events_request(event_data->tab, events_request);
730 }
e5258c09 731 return FALSE;
dc06b1bc 732}
733
734static void CalculateAverageDurationForEachIrqId(InterruptEventData *event_data)
735{
736 guint64 real_data;
737 Irq *element;
738 gint i;
739 GArray* FirstRequestIrqExit = event_data->FirstRequestIrqExit;
740 for(i = 0; i < FirstRequestIrqExit->len; i++)
741 {
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;
dc06b1bc 747 }
748
749}
750
e5258c09 751/**
752 * This function is called whenever an irq_entry event occurs. Use in the second request
753 *
754 */
dc06b1bc 755static gboolean SecondRequestIrqEntryCallback(void *hook_data, void *call_data)
756{
757
758 LttTime event_time;
759 unsigned cpu_id;
760 irq_entry entry;
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);
768
769
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);
774
775 return FALSE;
776}
777
e5258c09 778/**
779 * This function is called whenever an irq_exit event occurs in the second request.
780 *
781 */
dc06b1bc 782static gboolean SecondRequestIrqExitCallback(void *hook_data, void *call_data)
783{
784
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);
789
790 CalculateXi(event, event_data);
791 return FALSE;
792}
793
e5258c09 794
795/**
796 * This function is called whenever an irq_exit event occurs in the second request.
797 *
798 */
dc06b1bc 799static void CalculateXi(LttEvent *event_irq_exit, InterruptEventData *event_data)
800{
801 gint i, irq_id;
802 irq_entry *element;
803 LttTime Xi;
804 LttTime exit_time;
805 unsigned cpu_id;
806
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++)
811 {
812 element = &g_array_index(SecondRequestIrqEntry,irq_entry,i);
813 if(element->cpu_id == cpu_id)
814 {
815
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;
820
821 SumItems(irq_id, Xi,event_data);
822 g_array_remove_index(SecondRequestIrqEntry, i);
823 break;
824 }
825 }
826}
827
e5258c09 828
829/**
830 * This function computes the Sum ((xi -Xa)^2) and store the result in SumArray
831 *
832 */
dc06b1bc 833static void SumItems(gint irq_id, LttTime Xi, InterruptEventData *event_data)
834{
835 gint i;
836 guint time_in_ns;
837
838 gint temp;
839 Irq *average;
840 SumId *sumItem;
841 SumId sum;
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;
848
849 for(i = 0; i < FirstRequestIrqExit->len; i++)
850 {
851 average = &g_array_index(FirstRequestIrqExit,Irq,i);
852 if(irq_id == average->id)
853 {
854 temp = time_in_ns - average->average_duration;
855 sum.sumOfDurations = pow (temp , 2);
856 //printf("one : %d\n", sum.sumOfDurations);
857 sum.irqId = irq_id;
858 sum.frequency = average->frequency;
859 if(event_data->SumArray->len == NO_ITEMS)
860 {
861 g_array_append_val (SumArray, sum);
862 }
863 else
864 {
865
866 for(i = 0; i < SumArray->len; i++)
867 {
868 sumItem = &g_array_index(SumArray, SumId, i);
869 if(sumItem->irqId == irq_id)
870 {
871 notFound = TRUE;
872 sumItem->sumOfDurations += sum.sumOfDurations;
873
874 }
875 }
876 if(!notFound)
877 {
878 g_array_append_val (SumArray, sum);
879 }
880
881
882 }
883
884 }
885 }
886}
887
f2ec7aa9 888/**
889 * This function displays the result on the viewer
890 *
891 */
dc06b1bc 892static gboolean DisplayViewer(void *hook_data, void *call_data)
893{
5f5119ee 894
dc06b1bc 895 guint average;
f2ec7aa9 896 gint i;
897 Irq element;
898 LttTime average_duration;
899 GtkTreeIter iter;
900 guint64 real_data;
446b4179 901 guint maxIRQduration;
52948a62 902 double period;
e5258c09 903 char maxIrqHandler[80];
f2ec7aa9 904 InterruptEventData *event_data = (InterruptEventData *)hook_data;
dc06b1bc 905 GArray *FirstRequestIrqExit = event_data->FirstRequestIrqExit;
52948a62 906 int FrequencyHZ = 0;
907 period = 0.0;
f2ec7aa9 908 gtk_list_store_clear(event_data->ListStore);
dc06b1bc 909 for(i = 0; i < FirstRequestIrqExit->len; i++)
231a6432 910 {
dc06b1bc 911 element = g_array_index(FirstRequestIrqExit,Irq,i);
f2ec7aa9 912 real_data = element.total_duration.tv_sec;
913 real_data *= NANOSECONDS_PER_SECOND;
914 real_data += element.total_duration.tv_nsec;
446b4179 915
916
917 maxIRQduration = element.max_irq_handler.duration.tv_sec;
918 maxIRQduration *= NANOSECONDS_PER_SECOND;
919 maxIRQduration += element.max_irq_handler.duration.tv_nsec;
e5258c09 920
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) ;
52948a62 924 FrequencyHZ = FrequencyInHZ(element.frequency,event_data->time_window);
925 if(FrequencyHZ != 0)
926 {
927 period =(double)1/FrequencyHZ;
928 }
25c6412d 929
f2ec7aa9 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,
52948a62 934 FREQUENCY_COLUMN, FrequencyHZ,
f2ec7aa9 935 DURATION_COLUMN, real_data,
dc06b1bc 936 DURATION_STANDARD_DEV_COLUMN, CalculateStandardDeviation(element.id, event_data),
e5258c09 937 MAX_IRQ_HANDLER_COLUMN, maxIrqHandler,
52948a62 938 AVERAGE_PERIOD , period,
f2ec7aa9 939 -1);
dc06b1bc 940
446b4179 941
f2ec7aa9 942 }
dc06b1bc 943
dc06b1bc 944
945 if(event_data->FirstRequestIrqExit->len)
231a6432 946 {
dc06b1bc 947 g_array_remove_range (event_data->FirstRequestIrqExit,0,event_data->FirstRequestIrqExit->len);
231a6432 948 }
949
dc06b1bc 950 if(event_data->FirstRequestIrqEntry->len)
231a6432 951 {
dc06b1bc 952 g_array_remove_range (event_data->FirstRequestIrqEntry,0,event_data->FirstRequestIrqEntry->len);
953 }
954
955 if(event_data->SecondRequestIrqEntry->len)
956 {
957 g_array_remove_range (event_data->SecondRequestIrqEntry,0,event_data->SecondRequestIrqEntry->len);
958 }
231a6432 959
dc06b1bc 960 if(event_data->SecondRequestIrqExit->len)
961 {
962 g_array_remove_range (event_data->SecondRequestIrqExit,0, event_data->SecondRequestIrqExit->len);
963 }
964
965 if(event_data->SumArray->len)
966 {
967 g_array_remove_range (event_data->SumArray,0, event_data->SumArray->len);
231a6432 968 }
dc06b1bc 969
f2ec7aa9 970 return FALSE;
5f5119ee 971}
dc06b1bc 972
25c6412d 973
974static int FrequencyInHZ(gint frequency, TimeWindow time_window)
975{
976 guint64 frequencyHz = 0;
977 double timeSec;
52948a62 978
979 timeSec = ltt_time_to_double(time_window.time_width);
980 double result = (timeSec/NANOSECONDS_PER_SECOND);
981 frequencyHz = frequency / result;
25c6412d 982 return frequencyHz;
983}
984
e5258c09 985/**
986 * This function calculatees the standard deviation
987 *
988 */
dc06b1bc 989static int CalculateStandardDeviation(gint id, InterruptEventData *event_data)
990{
991 int i;
992 SumId sumId;
993 double inner_component;
994 int deviation = 0;
995 for(i = 0; i < event_data->SumArray->len; i++)
996 {
997 sumId = g_array_index(event_data->SumArray, SumId, i);
998 if(id == sumId.irqId)
999 {
25c6412d 1000 inner_component = sumId.sumOfDurations/ sumId.frequency;
dc06b1bc 1001 deviation = sqrt(inner_component);
25c6412d 1002 return deviation;
dc06b1bc 1003 }
1004 }
1005 return deviation;
1006}
f2ec7aa9 1007/*
1008 * This function is called by the main window
1009 * when the time interval needs to be updated.
1010 **/
1011gboolean interrupt_update_time_window(void * hook_data, void * call_data)
1012{
5f5119ee 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);
dc06b1bc 1019 FirstRequest(event_data );
f2ec7aa9 1020 return FALSE;
5f5119ee 1021}
1022
f2ec7aa9 1023
1024gboolean trace_header(void *hook_data, void *call_data)
1025{
1026
1027 InterruptEventData *event_data = (InterruptEventData *)hook_data;
1028 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
f2ec7aa9 1029 LttEvent *e;
1030 LttTime event_time;
1031 return FALSE;
5f5119ee 1032}
1033
f2ec7aa9 1034void interrupt_destroy_walk(gpointer data, gpointer user_data)
1035{
5f5119ee 1036 g_info("interrupt_destroy_walk");
1037 interrupt_destructor((InterruptEventData*)data);
1038
1039}
1040
f2ec7aa9 1041void interrupt_destructor(InterruptEventData *event_viewer_data)
1042{
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))
1046 {
1047 gtk_widget_destroy(event_viewer_data->Hbox);
1048 }
1049}
1050
5f5119ee 1051/**
1052 * plugin's destroy function
1053 *
1054 * This function releases the memory reserved by the module and unregisters
1055 * everything that has been registered in the gtkTraceSet API.
1056 */
dc06b1bc 1057static void destroy()
1058{
1059
5f5119ee 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);
1064
1065}
1066
1067LTTV_MODULE("interrupts", "interrupts info view", \
1068 "Graphical module to display interrupts performance", \
1069 init, destroy, "lttvwindow")
This page took 0.075565 seconds and 4 git commands to generate.