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