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