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