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