Added comments
[lttv.git] / ltt / branches / poly / lttv / modules / gui / interrupts / interrupts.c
... / ...
CommitLineData
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 */
18
19 /******************************************************************
20
21 The standard deviation calculation is based on:
22 http://en.wikipedia.org/wiki/Standard_deviation
23
24 Standard_deviation = sqrt(1/N Sum ((xi -Xa)^2))
25
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
34 *******************************************************************/
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>
44#include <math.h>
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
65typedef struct
66{
67 LttTime duration;
68 LttTime start_time;
69 LttTime end_time;
70}MaxDuration;
71
72typedef struct {
73 guint cpu_id;
74 guint id;
75 guint frequency;
76 LttTime total_duration;
77 guint average_duration;
78 MaxDuration max_irq_handler;
79
80}Irq;
81
82typedef struct {
83 guint id;
84 guint cpu_id;
85 LttTime event_time;
86}irq_entry;
87
88
89typedef struct
90{
91 guint irqId;
92 guint frequency;
93 guint64 sumOfDurations;
94
95}SumId;
96
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
106#define TRACE_NUMBER 0
107
108typedef struct _InterruptEventData {
109
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*/
118 LttvHooks * event_hooks;
119 LttvHooks * hooks_trace_after;
120 LttvHooks * hooks_trace_before;
121 TimeWindow time_window;
122 LttvHooksById * event_by_id_hooks;
123 GArray *FirstRequestIrqExit;
124 GArray *FirstRequestIrqEntry;
125 GArray *SecondRequestIrqEntry;
126 GArray *SecondRequestIrqExit;
127 GArray *SumArray;
128
129} InterruptEventData ;
130
131
132/* Function prototypes */
133
134static gboolean interrupt_update_time_window(void * hook_data, void * call_data);
135static GtkWidget *interrupts(Tab *tab);
136static InterruptEventData *system_info(Tab *tab);
137void interrupt_destructor(InterruptEventData *event_viewer_data);
138static void FirstRequest(InterruptEventData *event_data );
139static guint64 get_interrupt_id(LttEvent *e);
140static gboolean trace_header(void *hook_data, void *call_data);
141static gboolean DisplayViewer (void *hook_data, void *call_data);
142static void CalculateData(LttTime time_exit, guint cpu_id, InterruptEventData *event_data);
143static void TotalDurationMaxIrqDuration(irq_entry *e, LttTime time_exit, GArray *FirstRequestIrqExit);
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);
153
154/* Enumeration of the columns */
155enum{
156 CPUID_COLUMN,
157 IRQ_ID_COLUMN,
158 FREQUENCY_COLUMN,
159 DURATION_COLUMN,
160 DURATION_STANDARD_DEV_COLUMN,
161 MAX_IRQ_HANDLER_COLUMN,
162 N_COLUMNS
163};
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
185
186/**
187 * Constructor hook
188 *
189 */
190static GtkWidget *interrupts(Tab * tab)
191{
192
193 InterruptEventData* event_data = system_info(tab) ;
194 if(event_data)
195 return event_data->Hbox;
196 else
197 return NULL;
198}
199
200/**
201 * This function initializes the Event Viewer functionnality through the
202 * GTK API.
203 */
204InterruptEventData *system_info(Tab *tab)
205{
206
207 LttTime end;
208 GtkTreeViewColumn *column;
209 GtkCellRenderer *renderer;
210 InterruptEventData* event_viewer_data = g_new(InterruptEventData,1) ;
211
212 event_viewer_data->tab = tab;
213
214 /*Get the current time frame from the main window */
215 event_viewer_data->time_window = lttvwindow_get_time_window(tab);
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
226 /*Create tha main window for the viewer */
227 event_viewer_data->ScrollWindow = gtk_scrolled_window_new (NULL, NULL);
228 gtk_widget_show (event_viewer_data->ScrollWindow);
229 gtk_scrolled_window_set_policy(
230 GTK_SCROLLED_WINDOW(event_viewer_data->ScrollWindow),
231 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC/*GTK_POLICY_NEVER*/);
232
233 /* Create a model for storing the data list */
234 event_viewer_data->ListStore = gtk_list_store_new (
235 N_COLUMNS, /* Total number of columns */
236 G_TYPE_INT, /* CPUID */
237 G_TYPE_INT, /* IRQ_ID */
238 G_TYPE_INT, /* Frequency */
239 G_TYPE_UINT64, /* Duration */
240 G_TYPE_INT, /* standard deviation */
241 G_TYPE_STRING /* Max IRQ handler */
242 );
243
244 event_viewer_data->TreeView = gtk_tree_view_new_with_model (GTK_TREE_MODEL (event_viewer_data->ListStore));
245
246 g_object_unref (G_OBJECT (event_viewer_data->ListStore));
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);
255 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
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);
265 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
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);
274 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
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);
283 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
284
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);
292 gtk_tree_view_column_set_fixed_width (column, 200);
293 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
294
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);
303
304
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);
307
308 gtk_container_add (GTK_CONTAINER (event_viewer_data->ScrollWindow), event_viewer_data->TreeView);
309
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);
312
313 gtk_widget_show(event_viewer_data->Hbox);
314 gtk_widget_show(event_viewer_data->TreeView);
315
316 interrupt_data_list = g_slist_append(interrupt_data_list, event_viewer_data);
317 /* Registration for time notification */
318 lttvwindow_register_time_window_notify(tab,
319 interrupt_update_time_window,
320 event_viewer_data);
321
322
323 FirstRequest(event_viewer_data );
324 return event_viewer_data;
325}
326
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 */
336static void FirstRequest(InterruptEventData *event_data )
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);
353
354
355 /* Get the traceset */
356 LttvTraceset *traceset = tsc->ts;
357
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);
368
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();
375
376 /* Registers a hook function */
377 lttv_hooks_add(event_data->hooks_trace_after, SecondRequest, event_data, LTTV_PRIO_DEFAULT);
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();
382
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,
387 FirstRequestIrqEntryCallback,
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,
394 FirstRequestIrqExitCallback,
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;
433 events_request->after_chunk_trace = NULL;
434 events_request->after_chunk_traceset = NULL;
435 events_request->before_request = NULL;
436 events_request->after_request = event_data->hooks_trace_after;
437
438 lttvwindow_events_request(event_data->tab, events_request);
439 }
440
441}
442
443/**
444 * This function is called whenever an irq_entry event occurs.
445 *
446 */
447static gboolean FirstRequestIrqEntryCallback(void *hook_data, void *call_data)
448{
449
450 LttTime event_time;
451 unsigned cpu_id;
452 irq_entry entry;
453 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
454 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
455 InterruptEventData *event_data = (InterruptEventData *)hook_data;
456 GArray* FirstRequestIrqEntry = event_data->FirstRequestIrqEntry;
457 LttEvent *e = ltt_tracefile_get_event(tfc->tf);
458 event_time = ltt_event_time(e);
459 cpu_id = ltt_event_cpu_id(e);
460
461
462 entry.id =get_interrupt_id(e);
463 entry.cpu_id = cpu_id;
464 entry.event_time = event_time;
465 g_array_append_val (FirstRequestIrqEntry, entry);
466
467 return FALSE;
468}
469
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)
475{
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);
487 }
488 return irq_id;
489
490}
491/**
492 * This function is called whenever an irq_exit event occurs.
493 *
494 */
495gboolean FirstRequestIrqExitCallback(void *hook_data, void *call_data)
496{
497 LttTime event_time;
498 unsigned cpu_id;
499 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
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);
506
507 CalculateData( event_time, cpu_id, event_data);
508
509 return FALSE;
510}
511
512/**
513 * This function calculates the duration of an interrupt.
514 *
515 */
516static void CalculateData(LttTime time_exit, guint cpu_id,InterruptEventData *event_data)
517{
518
519 gint i, irq_id;
520 irq_entry *element;
521 LttTime duration;
522 GArray *FirstRequestIrqExit = event_data->FirstRequestIrqExit;
523 GArray *FirstRequestIrqEntry = event_data->FirstRequestIrqEntry;
524 for(i = 0; i < FirstRequestIrqEntry->len; i++)
525 {
526 element = &g_array_index(FirstRequestIrqEntry,irq_entry,i);
527 if(element->cpu_id == cpu_id)
528 {
529 TotalDurationMaxIrqDuration(element,time_exit, FirstRequestIrqExit);
530 g_array_remove_index(FirstRequestIrqEntry, i);
531 break;
532 }
533 }
534}
535
536/**
537 * This function calculates the total duration of an interrupt and the longest Irq handler.
538 *
539 */
540static void TotalDurationMaxIrqDuration(irq_entry *e, LttTime time_exit, GArray *FirstRequestIrqExit){
541 Irq irq;
542 Irq *element;
543 guint i;
544 LttTime duration;
545 gboolean notFound = FALSE;
546 memset ((void*)&irq, 0,sizeof(Irq));
547
548 /*first time*/
549 if(FirstRequestIrqExit->len == NO_ITEMS)
550 {
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);
555
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);
559
560
561 g_array_append_val (FirstRequestIrqExit, irq);
562 }
563 else
564 {
565 for(i = 0; i < FirstRequestIrqExit->len; i++)
566 {
567 element = &g_array_index(FirstRequestIrqExit,Irq,i);
568 if(element->id == e->id)
569 {
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++;
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 }
580 }
581 }
582 if(!notFound)
583 {
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);
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
593 g_array_append_val (FirstRequestIrqExit, irq);
594 }
595 }
596}
597
598/**
599 * This function passes the second EventsRequest to LTTV
600 *
601 */
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);
665
666 /* iterate through the facility list */
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 }
707 return FALSE;
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;
723 }
724
725}
726
727/**
728 * This function is called whenever an irq_entry event occurs. Use in the second request
729 *
730 */
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
754/**
755 * This function is called whenever an irq_exit event occurs in the second request.
756 *
757 */
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
770
771/**
772 * This function is called whenever an irq_exit event occurs in the second request.
773 *
774 */
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
804
805/**
806 * This function computes the Sum ((xi -Xa)^2) and store the result in SumArray
807 *
808 */
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
864/**
865 * This function displays the result on the viewer
866 *
867 */
868static gboolean DisplayViewer(void *hook_data, void *call_data)
869{
870
871 guint average;
872 gint i;
873 Irq element;
874 LttTime average_duration;
875 GtkTreeIter iter;
876 guint64 real_data;
877 guint maxIRQduration;
878 char maxIrqHandler[80];
879 InterruptEventData *event_data = (InterruptEventData *)hook_data;
880 GArray *FirstRequestIrqExit = event_data->FirstRequestIrqExit;
881 gtk_list_store_clear(event_data->ListStore);
882 for(i = 0; i < FirstRequestIrqExit->len; i++)
883 {
884 element = g_array_index(FirstRequestIrqExit,Irq,i);
885 real_data = element.total_duration.tv_sec;
886 real_data *= NANOSECONDS_PER_SECOND;
887 real_data += element.total_duration.tv_nsec;
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;
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
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,
904 DURATION_STANDARD_DEV_COLUMN, CalculateStandardDeviation(element.id, event_data),
905 MAX_IRQ_HANDLER_COLUMN, maxIrqHandler,
906 -1);
907
908
909 }
910
911
912 if(event_data->FirstRequestIrqExit->len)
913 {
914 g_array_remove_range (event_data->FirstRequestIrqExit,0,event_data->FirstRequestIrqExit->len);
915 }
916
917 if(event_data->FirstRequestIrqEntry->len)
918 {
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 }
926
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);
935 }
936
937 return FALSE;
938}
939
940/**
941 * This function calculatees the standard deviation
942 *
943 */
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 {
955// printf("id: %d\n", sumId.irqId);
956 inner_component = sumId.sumOfDurations/ sumId.frequency;
957 deviation = sqrt(inner_component);
958// printf("deviation: %d\n", deviation);
959 return deviation;
960
961 }
962 }
963 return deviation;
964}
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{
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);
977 FirstRequest(event_data );
978 return FALSE;
979}
980
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;
987 LttEvent *e;
988 LttTime event_time;
989 return FALSE;
990}
991
992void interrupt_destroy_walk(gpointer data, gpointer user_data)
993{
994 g_info("interrupt_destroy_walk");
995 interrupt_destructor((InterruptEventData*)data);
996
997}
998
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
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 */
1015static void destroy()
1016{
1017
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.026345 seconds and 4 git commands to generate.