Added comments
[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);
e5258c09 153
5f5119ee 154/* Enumeration of the columns */
155enum{
156 CPUID_COLUMN,
157 IRQ_ID_COLUMN,
158 FREQUENCY_COLUMN,
159 DURATION_COLUMN,
dc06b1bc 160 DURATION_STANDARD_DEV_COLUMN,
446b4179 161 MAX_IRQ_HANDLER_COLUMN,
5f5119ee 162 N_COLUMNS
163};
f2ec7aa9 164
165
166
167/**
168 * init function
169 *
170 *
171 * This is the entry point of the viewer.
172 *
173 */
174static void init() {
175 g_info("interrupts: init()");
176 lttvwindow_register_constructor("interrupts",
177 "/",
178 "Insert Interrupts View",
179 hInterruptsInsert_xpm,
180 "Insert Interrupts View",
181 interrupts);
182
183}
184
5f5119ee 185
5f5119ee 186/**
f2ec7aa9 187 * Constructor hook
5f5119ee 188 *
5f5119ee 189 */
f2ec7aa9 190static GtkWidget *interrupts(Tab * tab)
191{
b3e7b125 192
5f5119ee 193 InterruptEventData* event_data = system_info(tab) ;
194 if(event_data)
b3e7b125 195 return event_data->Hbox;
5f5119ee 196 else
197 return NULL;
198}
199
f2ec7aa9 200/**
201 * This function initializes the Event Viewer functionnality through the
202 * GTK API.
203 */
5f5119ee 204InterruptEventData *system_info(Tab *tab)
205{
dc06b1bc 206
5f5119ee 207 LttTime end;
208 GtkTreeViewColumn *column;
209 GtkCellRenderer *renderer;
210 InterruptEventData* event_viewer_data = g_new(InterruptEventData,1) ;
dc06b1bc 211
5f5119ee 212 event_viewer_data->tab = tab;
f2ec7aa9 213
214 /*Get the current time frame from the main window */
5f5119ee 215 event_viewer_data->time_window = lttvwindow_get_time_window(tab);
dc06b1bc 216
217 event_viewer_data->FirstRequestIrqExit = g_array_new(FALSE, FALSE, sizeof(Irq));
218 event_viewer_data->FirstRequestIrqEntry = g_array_new(FALSE, FALSE, sizeof(irq_entry));
219
220 event_viewer_data->SecondRequestIrqEntry = g_array_new(FALSE, FALSE, sizeof(irq_entry));
221 event_viewer_data->SecondRequestIrqExit = g_array_new(FALSE, FALSE, sizeof(Irq));
222
223 event_viewer_data->SumArray = g_array_new(FALSE, FALSE, sizeof(SumId));
224
225
f2ec7aa9 226 /*Create tha main window for the viewer */
b3e7b125 227 event_viewer_data->ScrollWindow = gtk_scrolled_window_new (NULL, NULL);
228 gtk_widget_show (event_viewer_data->ScrollWindow);
5f5119ee 229 gtk_scrolled_window_set_policy(
b3e7b125 230 GTK_SCROLLED_WINDOW(event_viewer_data->ScrollWindow),
5f5119ee 231 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC/*GTK_POLICY_NEVER*/);
232
233 /* Create a model for storing the data list */
b3e7b125 234 event_viewer_data->ListStore = gtk_list_store_new (
5f5119ee 235 N_COLUMNS, /* Total number of columns */
236 G_TYPE_INT, /* CPUID */
237 G_TYPE_INT, /* IRQ_ID */
238 G_TYPE_INT, /* Frequency */
dc06b1bc 239 G_TYPE_UINT64, /* Duration */
446b4179 240 G_TYPE_INT, /* standard deviation */
e5258c09 241 G_TYPE_STRING /* Max IRQ handler */
5f5119ee 242 );
243
b3e7b125 244 event_viewer_data->TreeView = gtk_tree_view_new_with_model (GTK_TREE_MODEL (event_viewer_data->ListStore));
5f5119ee 245
b3e7b125 246 g_object_unref (G_OBJECT (event_viewer_data->ListStore));
5f5119ee 247
248 renderer = gtk_cell_renderer_text_new ();
249 column = gtk_tree_view_column_new_with_attributes ("CPUID",
250 renderer,
251 "text", CPUID_COLUMN,
252 NULL);
253 gtk_tree_view_column_set_alignment (column, 0.0);
254 gtk_tree_view_column_set_fixed_width (column, 45);
b3e7b125 255 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
5f5119ee 256
257
258 renderer = gtk_cell_renderer_text_new ();
259 column = gtk_tree_view_column_new_with_attributes ("IrqId",
260 renderer,
261 "text", IRQ_ID_COLUMN,
262 NULL);
263 gtk_tree_view_column_set_alignment (column, 0.0);
264 gtk_tree_view_column_set_fixed_width (column, 220);
b3e7b125 265 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
5f5119ee 266
267 renderer = gtk_cell_renderer_text_new ();
268 column = gtk_tree_view_column_new_with_attributes ("Frequency",
269 renderer,
270 "text", FREQUENCY_COLUMN,
271 NULL);
272 gtk_tree_view_column_set_alignment (column, 1.0);
273 gtk_tree_view_column_set_fixed_width (column, 220);
b3e7b125 274 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
5f5119ee 275
276 renderer = gtk_cell_renderer_text_new ();
277 column = gtk_tree_view_column_new_with_attributes ("Duration (nsec)",
278 renderer,
279 "text", DURATION_COLUMN,
280 NULL);
281 gtk_tree_view_column_set_alignment (column, 0.0);
282 gtk_tree_view_column_set_fixed_width (column, 145);
b3e7b125 283 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
5f5119ee 284
dc06b1bc 285
286 renderer = gtk_cell_renderer_text_new ();
287 column = gtk_tree_view_column_new_with_attributes ("Duration standard deviation (nsec)",
288 renderer,
289 "text", DURATION_STANDARD_DEV_COLUMN,
290 NULL);
291 gtk_tree_view_column_set_alignment (column, 0.0);
446b4179 292 gtk_tree_view_column_set_fixed_width (column, 200);
dc06b1bc 293 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
294
446b4179 295 renderer = gtk_cell_renderer_text_new ();
296 column = gtk_tree_view_column_new_with_attributes ("Max IRQ handler duration (nsec)",
297 renderer,
298 "text", MAX_IRQ_HANDLER_COLUMN,
299 NULL);
300 gtk_tree_view_column_set_alignment (column, 0.0);
301 gtk_tree_view_column_set_fixed_width (column, 250);
302 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
dc06b1bc 303
304
b3e7b125 305 event_viewer_data->SelectionTree = gtk_tree_view_get_selection (GTK_TREE_VIEW (event_viewer_data->TreeView));
306 gtk_tree_selection_set_mode (event_viewer_data->SelectionTree, GTK_SELECTION_SINGLE);
5f5119ee 307
b3e7b125 308 gtk_container_add (GTK_CONTAINER (event_viewer_data->ScrollWindow), event_viewer_data->TreeView);
5f5119ee 309
b3e7b125 310 event_viewer_data->Hbox = gtk_hbox_new(0, 0);
311 gtk_box_pack_start(GTK_BOX(event_viewer_data->Hbox), event_viewer_data->ScrollWindow, TRUE, TRUE, 0);
5f5119ee 312
b3e7b125 313 gtk_widget_show(event_viewer_data->Hbox);
314 gtk_widget_show(event_viewer_data->TreeView);
5f5119ee 315
b3e7b125 316 interrupt_data_list = g_slist_append(interrupt_data_list, event_viewer_data);
f2ec7aa9 317 /* Registration for time notification */
b3e7b125 318 lttvwindow_register_time_window_notify(tab,
319 interrupt_update_time_window,
320 event_viewer_data);
f2ec7aa9 321
322
dc06b1bc 323 FirstRequest(event_viewer_data );
5f5119ee 324 return event_viewer_data;
325}
b3e7b125 326
f2ec7aa9 327/**
328 *
329 * For each trace in the traceset, this function:
330 * - registers a callback function to each hook
331 * - calls lttv_trace_find_hook() registers a hook function to event_by_id_hooks
332 * - calls lttvwindow_events_request() to request data in a specific
333 * time interval to the main window
334 *
335 */
dc06b1bc 336static void FirstRequest(InterruptEventData *event_data )
f2ec7aa9 337{
338 guint i, k, l, nb_trace;
339
340 LttvTraceHook *hook;
341
342 guint ret;
343
344 LttvTraceState *ts;
345
346 GArray *hooks;
347
348 EventsRequest *events_request;
349
350 LttvTraceHookByFacility *thf;
351
352 LttvTracesetContext *tsc = lttvwindow_get_traceset_context(event_data->tab);
5f5119ee 353
f2ec7aa9 354
355 /* Get the traceset */
356 LttvTraceset *traceset = tsc->ts;
5f5119ee 357
f2ec7aa9 358 nb_trace = lttv_traceset_number(traceset);
359
360 /* There are many traces in a traceset. Iteration for each trace. */
361 for(i = 0; i<MIN(TRACE_NUMBER+1, nb_trace);i++)
362 {
363 events_request = g_new(EventsRequest, 1);
364
365 hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook));
366
367 hooks = g_array_set_size(hooks, 2);
b3e7b125 368
f2ec7aa9 369 event_data->hooks_trace_before = lttv_hooks_new();
370
371 /* Registers a hook function */
372 lttv_hooks_add(event_data->hooks_trace_before, trace_header, event_data, LTTV_PRIO_DEFAULT);
373
374 event_data->hooks_trace_after = lttv_hooks_new();
dc06b1bc 375
376 /* Registers a hook function */
377 lttv_hooks_add(event_data->hooks_trace_after, SecondRequest, event_data, LTTV_PRIO_DEFAULT);
f2ec7aa9 378 /* Get a trace state */
379 ts = (LttvTraceState *)tsc->traces[i];
380 /* Create event_by_Id hooks */
381 event_data->event_by_id_hooks = lttv_hooks_by_id_new();
b3e7b125 382
f2ec7aa9 383 /*Register event_by_id_hooks with a callback function*/
384 ret = lttv_trace_find_hook(ts->parent.t,
385 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
386 LTT_FIELD_IRQ_ID, 0, 0,
dc06b1bc 387 FirstRequestIrqEntryCallback,
f2ec7aa9 388 events_request,
389 &g_array_index(hooks, LttvTraceHook, 0));
390
391 ret = lttv_trace_find_hook(ts->parent.t,
392 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
393 LTT_FIELD_IRQ_ID, 0, 0,
dc06b1bc 394 FirstRequestIrqExitCallback,
f2ec7aa9 395 events_request,
396 &g_array_index(hooks, LttvTraceHook, 1));
397
398 g_assert(!ret);
399 /*iterate through the facility list*/
400 for(k = 0 ; k < hooks->len; k++)
401 {
402 hook = &g_array_index(hooks, LttvTraceHook, k);
403 for(l=0; l<hook->fac_list->len; l++)
404 {
405 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
406 lttv_hooks_add(lttv_hooks_by_id_find(event_data->event_by_id_hooks, thf->id),
407 thf->h,
408 event_data,
409 LTTV_PRIO_DEFAULT);
410
411 }
412 }
413 /* Initalize the EventsRequest structure */
414 events_request->owner = event_data;
415 events_request->viewer_data = event_data;
416 events_request->servicing = FALSE;
417 events_request->start_time = event_data->time_window.start_time;
418 events_request->start_position = NULL;
419 events_request->stop_flag = FALSE;
420 events_request->end_time = event_data->time_window.end_time;
421 events_request->num_events = G_MAXUINT;
422 events_request->end_position = NULL;
423 events_request->trace = i;
424
425 events_request->hooks = hooks;
426
427 events_request->before_chunk_traceset = NULL;
428 events_request->before_chunk_trace = event_data->hooks_trace_before;
429 events_request->before_chunk_tracefile= NULL;
430 events_request->event = NULL;
431 events_request->event_by_id = event_data->event_by_id_hooks;
432 events_request->after_chunk_tracefile = NULL;
231a6432 433 events_request->after_chunk_trace = NULL;
f2ec7aa9 434 events_request->after_chunk_traceset = NULL;
231a6432 435 events_request->before_request = NULL;
f2ec7aa9 436 events_request->after_request = event_data->hooks_trace_after;
437
438 lttvwindow_events_request(event_data->tab, events_request);
439 }
440
b3e7b125 441}
5f5119ee 442
f2ec7aa9 443/**
444 * This function is called whenever an irq_entry event occurs.
445 *
446 */
dc06b1bc 447static gboolean FirstRequestIrqEntryCallback(void *hook_data, void *call_data)
f2ec7aa9 448{
449
b3e7b125 450 LttTime event_time;
b3e7b125 451 unsigned cpu_id;
452 irq_entry entry;
b3e7b125 453 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
454 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
f2ec7aa9 455 InterruptEventData *event_data = (InterruptEventData *)hook_data;
dc06b1bc 456 GArray* FirstRequestIrqEntry = event_data->FirstRequestIrqEntry;
f2ec7aa9 457 LttEvent *e = ltt_tracefile_get_event(tfc->tf);
b3e7b125 458 event_time = ltt_event_time(e);
b3e7b125 459 cpu_id = ltt_event_cpu_id(e);
f2ec7aa9 460
231a6432 461
462 entry.id =get_interrupt_id(e);
463 entry.cpu_id = cpu_id;
464 entry.event_time = event_time;
dc06b1bc 465 g_array_append_val (FirstRequestIrqEntry, entry);
231a6432 466
f2ec7aa9 467 return FALSE;
5f5119ee 468}
469
f2ec7aa9 470/**
471 * This function gets the id of the interrupt. The id is stored in a dynamic structure.
472 * Refer to the print.c file for howto extract data from a dynamic structure.
473 */
474static guint64 get_interrupt_id(LttEvent *e)
5f5119ee 475{
f2ec7aa9 476 guint i, num_fields;
477 LttEventType *event_type;
478 LttField *element;
479 LttField *field;
480 guint64 irq_id;
481 event_type = ltt_event_eventtype(e);
482 num_fields = ltt_eventtype_num_fields(event_type);
483 for(i = 0 ; i < num_fields-1 ; i++)
484 {
485 field = ltt_eventtype_field(event_type, i);
486 irq_id = ltt_event_get_long_unsigned(e,field);
5f5119ee 487 }
488 return irq_id;
5f5119ee 489
f2ec7aa9 490}
491/**
492 * This function is called whenever an irq_exit event occurs.
493 *
494 */
dc06b1bc 495gboolean FirstRequestIrqExitCallback(void *hook_data, void *call_data)
f2ec7aa9 496{
497 LttTime event_time;
498 unsigned cpu_id;
5f5119ee 499 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
f2ec7aa9 500 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
501 InterruptEventData *event_data = (InterruptEventData *)hook_data;
502 LttEvent *e = ltt_tracefile_get_event(tfc->tf);
503 LttEventType *type = ltt_event_eventtype(e);
504 event_time = ltt_event_time(e);
505 cpu_id = ltt_event_cpu_id(e);
231a6432 506
e5258c09 507 CalculateData( event_time, cpu_id, event_data);
508
231a6432 509 return FALSE;
5f5119ee 510}
511
f2ec7aa9 512/**
513 * This function calculates the duration of an interrupt.
514 *
515 */
e5258c09 516static void CalculateData(LttTime time_exit, guint cpu_id,InterruptEventData *event_data)
dc06b1bc 517{
5f5119ee 518
f2ec7aa9 519 gint i, irq_id;
520 irq_entry *element;
521 LttTime duration;
dc06b1bc 522 GArray *FirstRequestIrqExit = event_data->FirstRequestIrqExit;
523 GArray *FirstRequestIrqEntry = event_data->FirstRequestIrqEntry;
524 for(i = 0; i < FirstRequestIrqEntry->len; i++)
231a6432 525 {
dc06b1bc 526 element = &g_array_index(FirstRequestIrqEntry,irq_entry,i);
231a6432 527 if(element->cpu_id == cpu_id)
528 {
e5258c09 529 TotalDurationMaxIrqDuration(element,time_exit, FirstRequestIrqExit);
dc06b1bc 530 g_array_remove_index(FirstRequestIrqEntry, i);
f2ec7aa9 531 break;
532 }
533 }
e5258c09 534}
dc06b1bc 535
f2ec7aa9 536/**
e5258c09 537 * This function calculates the total duration of an interrupt and the longest Irq handler.
f2ec7aa9 538 *
539 */
e5258c09 540static void TotalDurationMaxIrqDuration(irq_entry *e, LttTime time_exit, GArray *FirstRequestIrqExit){
5f5119ee 541 Irq irq;
542 Irq *element;
543 guint i;
544 LttTime duration;
545 gboolean notFound = FALSE;
546 memset ((void*)&irq, 0,sizeof(Irq));
547
231a6432 548 /*first time*/
dc06b1bc 549 if(FirstRequestIrqExit->len == NO_ITEMS)
231a6432 550 {
5f5119ee 551 irq.cpu_id = e->cpu_id;
552 irq.id = e->id;
553 irq.frequency++;
554 irq.total_duration = ltt_time_sub(time_exit, e->event_time);
e5258c09 555
446b4179 556 irq.max_irq_handler.start_time = e->event_time;
557 irq.max_irq_handler.end_time = time_exit;
558 irq.max_irq_handler.duration = ltt_time_sub(time_exit, e->event_time);
e5258c09 559
446b4179 560
dc06b1bc 561 g_array_append_val (FirstRequestIrqExit, irq);
5f5119ee 562 }
231a6432 563 else
564 {
dc06b1bc 565 for(i = 0; i < FirstRequestIrqExit->len; i++)
231a6432 566 {
dc06b1bc 567 element = &g_array_index(FirstRequestIrqExit,Irq,i);
568 if(element->id == e->id)
569 {
5f5119ee 570 notFound = TRUE;
571 duration = ltt_time_sub(time_exit, e->event_time);
572 element->total_duration = ltt_time_add(element->total_duration, duration);
573 element->frequency++;
446b4179 574 if(ltt_time_compare(duration,element->max_irq_handler.duration) > 0)
575 {
576 element->max_irq_handler.duration = duration;
577 element->max_irq_handler.start_time = e->event_time;
578 element->max_irq_handler.end_time = time_exit;
579 }
5f5119ee 580 }
581 }
231a6432 582 if(!notFound)
583 {
5f5119ee 584 irq.cpu_id = e->cpu_id;
585 irq.id = e->id;
586 irq.frequency++;
587 irq.total_duration = ltt_time_sub(time_exit, e->event_time);
446b4179 588
589 irq.max_irq_handler.start_time = e->event_time;
590 irq.max_irq_handler.end_time = time_exit;
591 irq.max_irq_handler.duration = ltt_time_sub(time_exit, e->event_time);
592
dc06b1bc 593 g_array_append_val (FirstRequestIrqExit, irq);
5f5119ee 594 }
595 }
596}
231a6432 597
e5258c09 598/**
599 * This function passes the second EventsRequest to LTTV
600 *
601 */
dc06b1bc 602static gboolean SecondRequest(void *hook_data, void *call_data)
603{
604
605 guint i, k, l, nb_trace;
606
607 LttvTraceHook *hook;
608
609 guint ret;
610
611 LttvTraceState *ts;
612
613 GArray *hooks;
614
615 EventsRequest *events_request;
616
617 LttvTraceHookByFacility *thf;
618
619 InterruptEventData *event_data = (InterruptEventData *)hook_data;
620
621 LttvTracesetContext *tsc = lttvwindow_get_traceset_context(event_data->tab);
622
623 CalculateAverageDurationForEachIrqId(event_data);
624
625 /* Get the traceset */
626 LttvTraceset *traceset = tsc->ts;
627
628 nb_trace = lttv_traceset_number(traceset);
629
630 /* There are many traces in a traceset. Iteration for each trace. */
631 for(i = 0; i<MIN(TRACE_NUMBER+1, nb_trace);i++)
632 {
633 events_request = g_new(EventsRequest, 1);
634
635 hooks = g_array_new(FALSE, FALSE, sizeof(LttvTraceHook));
636
637 hooks = g_array_set_size(hooks, 2);
638
639 event_data->hooks_trace_after = lttv_hooks_new();
640
641 /* Registers a hook function */
642 lttv_hooks_add(event_data->hooks_trace_after, DisplayViewer, event_data, LTTV_PRIO_DEFAULT);
643
644 /* Get a trace state */
645 ts = (LttvTraceState *)tsc->traces[i];
646 /* Create event_by_Id hooks */
647 event_data->event_by_id_hooks = lttv_hooks_by_id_new();
648
649 /*Register event_by_id_hooks with a callback function*/
650 ret = lttv_trace_find_hook(ts->parent.t,
651 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_ENTRY,
652 LTT_FIELD_IRQ_ID, 0, 0,
653 SecondRequestIrqEntryCallback,
654 events_request,
655 &g_array_index(hooks, LttvTraceHook, 0));
656
657 ret = lttv_trace_find_hook(ts->parent.t,
658 LTT_FACILITY_KERNEL, LTT_EVENT_IRQ_EXIT,
659 LTT_FIELD_IRQ_ID, 0, 0,
660 SecondRequestIrqExitCallback,
661 events_request,
662 &g_array_index(hooks, LttvTraceHook, 1));
663
664 g_assert(!ret);
e5258c09 665
666 /* iterate through the facility list */
dc06b1bc 667 for(k = 0 ; k < hooks->len; k++)
668 {
669 hook = &g_array_index(hooks, LttvTraceHook, k);
670 for(l=0; l<hook->fac_list->len; l++)
671 {
672 thf = g_array_index(hook->fac_list, LttvTraceHookByFacility*, l);
673 lttv_hooks_add(lttv_hooks_by_id_find(event_data->event_by_id_hooks, thf->id),
674 thf->h,
675 event_data,
676 LTTV_PRIO_DEFAULT);
677
678 }
679 }
680 /* Initalize the EventsRequest structure */
681 events_request->owner = event_data;
682 events_request->viewer_data = event_data;
683 events_request->servicing = FALSE;
684 events_request->start_time = event_data->time_window.start_time;
685 events_request->start_position = NULL;
686 events_request->stop_flag = FALSE;
687 events_request->end_time = event_data->time_window.end_time;
688 events_request->num_events = G_MAXUINT;
689 events_request->end_position = NULL;
690 events_request->trace = i;
691
692 events_request->hooks = hooks;
693
694 events_request->before_chunk_traceset = NULL;
695 events_request->before_chunk_trace = NULL;
696 events_request->before_chunk_tracefile= NULL;
697 events_request->event = NULL;
698 events_request->event_by_id = event_data->event_by_id_hooks;
699 events_request->after_chunk_tracefile = NULL;
700 events_request->after_chunk_trace = NULL;
701 events_request->after_chunk_traceset = NULL;
702 events_request->before_request = NULL;
703 events_request->after_request = event_data->hooks_trace_after;
704
705 lttvwindow_events_request(event_data->tab, events_request);
706 }
e5258c09 707 return FALSE;
dc06b1bc 708}
709
710static void CalculateAverageDurationForEachIrqId(InterruptEventData *event_data)
711{
712 guint64 real_data;
713 Irq *element;
714 gint i;
715 GArray* FirstRequestIrqExit = event_data->FirstRequestIrqExit;
716 for(i = 0; i < FirstRequestIrqExit->len; i++)
717 {
718 element = &g_array_index(FirstRequestIrqExit,Irq,i);
719 real_data = element->total_duration.tv_sec;
720 real_data *= NANOSECONDS_PER_SECOND;
721 real_data += element->total_duration.tv_nsec;
722 element->average_duration = real_data / element->frequency;
dc06b1bc 723 }
724
725}
726
e5258c09 727/**
728 * This function is called whenever an irq_entry event occurs. Use in the second request
729 *
730 */
dc06b1bc 731static gboolean SecondRequestIrqEntryCallback(void *hook_data, void *call_data)
732{
733
734 LttTime event_time;
735 unsigned cpu_id;
736 irq_entry entry;
737 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
738 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
739 InterruptEventData *event_data = (InterruptEventData *)hook_data;
740 GArray* SecondRequestIrqEntry = event_data->SecondRequestIrqEntry;
741 LttEvent *e = ltt_tracefile_get_event(tfc->tf);
742 event_time = ltt_event_time(e);
743 cpu_id = ltt_event_cpu_id(e);
744
745
746 entry.id =get_interrupt_id(e);
747 entry.cpu_id = cpu_id;
748 entry.event_time = event_time;
749 g_array_append_val (SecondRequestIrqEntry, entry);
750
751 return FALSE;
752}
753
e5258c09 754/**
755 * This function is called whenever an irq_exit event occurs in the second request.
756 *
757 */
dc06b1bc 758static gboolean SecondRequestIrqExitCallback(void *hook_data, void *call_data)
759{
760
761 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
762 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
763 InterruptEventData *event_data = (InterruptEventData *)hook_data;
764 LttEvent *event = ltt_tracefile_get_event(tfc->tf);
765
766 CalculateXi(event, event_data);
767 return FALSE;
768}
769
e5258c09 770
771/**
772 * This function is called whenever an irq_exit event occurs in the second request.
773 *
774 */
dc06b1bc 775static void CalculateXi(LttEvent *event_irq_exit, InterruptEventData *event_data)
776{
777 gint i, irq_id;
778 irq_entry *element;
779 LttTime Xi;
780 LttTime exit_time;
781 unsigned cpu_id;
782
783 GArray *SecondRequestIrqExit = event_data->SecondRequestIrqExit;
784 GArray *SecondRequestIrqEntry = event_data->SecondRequestIrqEntry;
785 cpu_id = ltt_event_cpu_id(event_irq_exit);
786 for(i = 0; i < SecondRequestIrqEntry->len; i++)
787 {
788 element = &g_array_index(SecondRequestIrqEntry,irq_entry,i);
789 if(element->cpu_id == cpu_id)
790 {
791
792 /* time calculation */
793 exit_time = ltt_event_time(event_irq_exit);
794 Xi = ltt_time_sub(exit_time, element->event_time);
795 irq_id = element->id;
796
797 SumItems(irq_id, Xi,event_data);
798 g_array_remove_index(SecondRequestIrqEntry, i);
799 break;
800 }
801 }
802}
803
e5258c09 804
805/**
806 * This function computes the Sum ((xi -Xa)^2) and store the result in SumArray
807 *
808 */
dc06b1bc 809static void SumItems(gint irq_id, LttTime Xi, InterruptEventData *event_data)
810{
811 gint i;
812 guint time_in_ns;
813
814 gint temp;
815 Irq *average;
816 SumId *sumItem;
817 SumId sum;
818 gboolean notFound = FALSE;
819 GArray *FirstRequestIrqExit = event_data->FirstRequestIrqExit;
820 GArray *SumArray = event_data->SumArray;
821 time_in_ns = Xi.tv_sec;
822 time_in_ns *= NANOSECONDS_PER_SECOND;
823 time_in_ns += Xi.tv_nsec;
824
825 for(i = 0; i < FirstRequestIrqExit->len; i++)
826 {
827 average = &g_array_index(FirstRequestIrqExit,Irq,i);
828 if(irq_id == average->id)
829 {
830 temp = time_in_ns - average->average_duration;
831 sum.sumOfDurations = pow (temp , 2);
832 //printf("one : %d\n", sum.sumOfDurations);
833 sum.irqId = irq_id;
834 sum.frequency = average->frequency;
835 if(event_data->SumArray->len == NO_ITEMS)
836 {
837 g_array_append_val (SumArray, sum);
838 }
839 else
840 {
841
842 for(i = 0; i < SumArray->len; i++)
843 {
844 sumItem = &g_array_index(SumArray, SumId, i);
845 if(sumItem->irqId == irq_id)
846 {
847 notFound = TRUE;
848 sumItem->sumOfDurations += sum.sumOfDurations;
849
850 }
851 }
852 if(!notFound)
853 {
854 g_array_append_val (SumArray, sum);
855 }
856
857
858 }
859
860 }
861 }
862}
863
f2ec7aa9 864/**
865 * This function displays the result on the viewer
866 *
867 */
dc06b1bc 868static gboolean DisplayViewer(void *hook_data, void *call_data)
869{
5f5119ee 870
dc06b1bc 871 guint average;
f2ec7aa9 872 gint i;
873 Irq element;
874 LttTime average_duration;
875 GtkTreeIter iter;
876 guint64 real_data;
446b4179 877 guint maxIRQduration;
e5258c09 878 char maxIrqHandler[80];
f2ec7aa9 879 InterruptEventData *event_data = (InterruptEventData *)hook_data;
dc06b1bc 880 GArray *FirstRequestIrqExit = event_data->FirstRequestIrqExit;
f2ec7aa9 881 gtk_list_store_clear(event_data->ListStore);
dc06b1bc 882 for(i = 0; i < FirstRequestIrqExit->len; i++)
231a6432 883 {
dc06b1bc 884 element = g_array_index(FirstRequestIrqExit,Irq,i);
f2ec7aa9 885 real_data = element.total_duration.tv_sec;
886 real_data *= NANOSECONDS_PER_SECOND;
887 real_data += element.total_duration.tv_nsec;
446b4179 888
889
890 maxIRQduration = element.max_irq_handler.duration.tv_sec;
891 maxIRQduration *= NANOSECONDS_PER_SECOND;
892 maxIRQduration += element.max_irq_handler.duration.tv_nsec;
e5258c09 893
894 sprintf(maxIrqHandler, "%d [%d.%d - %d.%d]",maxIRQduration, element.max_irq_handler.start_time.tv_sec, \
895 element.max_irq_handler.start_time.tv_nsec, element.max_irq_handler.end_time.tv_sec, \
896 element.max_irq_handler.end_time.tv_nsec) ;
897
f2ec7aa9 898 gtk_list_store_append (event_data->ListStore, &iter);
899 gtk_list_store_set (event_data->ListStore, &iter,
900 CPUID_COLUMN, element.cpu_id,
901 IRQ_ID_COLUMN, element.id,
902 FREQUENCY_COLUMN, element.frequency,
903 DURATION_COLUMN, real_data,
dc06b1bc 904 DURATION_STANDARD_DEV_COLUMN, CalculateStandardDeviation(element.id, event_data),
e5258c09 905 MAX_IRQ_HANDLER_COLUMN, maxIrqHandler,
f2ec7aa9 906 -1);
dc06b1bc 907
446b4179 908
f2ec7aa9 909 }
dc06b1bc 910
dc06b1bc 911
912 if(event_data->FirstRequestIrqExit->len)
231a6432 913 {
dc06b1bc 914 g_array_remove_range (event_data->FirstRequestIrqExit,0,event_data->FirstRequestIrqExit->len);
231a6432 915 }
916
dc06b1bc 917 if(event_data->FirstRequestIrqEntry->len)
231a6432 918 {
dc06b1bc 919 g_array_remove_range (event_data->FirstRequestIrqEntry,0,event_data->FirstRequestIrqEntry->len);
920 }
921
922 if(event_data->SecondRequestIrqEntry->len)
923 {
924 g_array_remove_range (event_data->SecondRequestIrqEntry,0,event_data->SecondRequestIrqEntry->len);
925 }
231a6432 926
dc06b1bc 927 if(event_data->SecondRequestIrqExit->len)
928 {
929 g_array_remove_range (event_data->SecondRequestIrqExit,0, event_data->SecondRequestIrqExit->len);
930 }
931
932 if(event_data->SumArray->len)
933 {
934 g_array_remove_range (event_data->SumArray,0, event_data->SumArray->len);
231a6432 935 }
dc06b1bc 936
f2ec7aa9 937 return FALSE;
5f5119ee 938}
dc06b1bc 939
e5258c09 940/**
941 * This function calculatees the standard deviation
942 *
943 */
dc06b1bc 944static int CalculateStandardDeviation(gint id, InterruptEventData *event_data)
945{
946 int i;
947 SumId sumId;
948 double inner_component;
949 int deviation = 0;
950 for(i = 0; i < event_data->SumArray->len; i++)
951 {
952 sumId = g_array_index(event_data->SumArray, SumId, i);
953 if(id == sumId.irqId)
954 {
e5258c09 955// printf("id: %d\n", sumId.irqId);
dc06b1bc 956 inner_component = sumId.sumOfDurations/ sumId.frequency;
957 deviation = sqrt(inner_component);
e5258c09 958// printf("deviation: %d\n", deviation);
dc06b1bc 959 return deviation;
960
961 }
962 }
963 return deviation;
964}
f2ec7aa9 965/*
966 * This function is called by the main window
967 * when the time interval needs to be updated.
968 **/
969gboolean interrupt_update_time_window(void * hook_data, void * call_data)
970{
5f5119ee 971 InterruptEventData *event_data = (InterruptEventData *) hook_data;
972 const TimeWindowNotifyData *time_window_nofify_data = ((const TimeWindowNotifyData *)call_data);
973 event_data->time_window = *time_window_nofify_data->new_time_window;
974 g_info("interrupts: interrupt_update_time_window()\n");
975 Tab *tab = event_data->tab;
976 lttvwindow_events_request_remove_all(tab, event_data);
dc06b1bc 977 FirstRequest(event_data );
f2ec7aa9 978 return FALSE;
5f5119ee 979}
980
f2ec7aa9 981
982gboolean trace_header(void *hook_data, void *call_data)
983{
984
985 InterruptEventData *event_data = (InterruptEventData *)hook_data;
986 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
f2ec7aa9 987 LttEvent *e;
988 LttTime event_time;
989 return FALSE;
5f5119ee 990}
991
f2ec7aa9 992void interrupt_destroy_walk(gpointer data, gpointer user_data)
993{
5f5119ee 994 g_info("interrupt_destroy_walk");
995 interrupt_destructor((InterruptEventData*)data);
996
997}
998
f2ec7aa9 999void interrupt_destructor(InterruptEventData *event_viewer_data)
1000{
1001 /* May already been done by GTK window closing */
1002 g_info("enter interrupt_destructor \n");
1003 if(GTK_IS_WIDGET(event_viewer_data->Hbox))
1004 {
1005 gtk_widget_destroy(event_viewer_data->Hbox);
1006 }
1007}
1008
5f5119ee 1009/**
1010 * plugin's destroy function
1011 *
1012 * This function releases the memory reserved by the module and unregisters
1013 * everything that has been registered in the gtkTraceSet API.
1014 */
dc06b1bc 1015static void destroy()
1016{
1017
5f5119ee 1018 g_info("Destroy interrupts");
1019 g_slist_foreach(interrupt_data_list, interrupt_destroy_walk, NULL );
1020 g_slist_free(interrupt_data_list);
1021 lttvwindow_unregister_constructor(interrupts);
1022
1023}
1024
1025LTTV_MODULE("interrupts", "interrupts info view", \
1026 "Graphical module to display interrupts performance", \
1027 init, destroy, "lttvwindow")
This page took 0.071595 seconds and 4 git commands to generate.