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