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