fix check version
[lttv.git] / ltt / branches / poly / lttv / modules / gui / interrupts / interrupts.c
CommitLineData
5f5119ee 1/* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2005 Peter Ho
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License Version 2 as
6 * published by the Free Software Foundation;
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
16 * MA 02111-1307, USA.
17 */
18
19
20
21#include <math.h>
22#include <glib.h>
23#include <gtk/gtk.h>
24#include <gdk/gdk.h>
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <ltt/ltt.h>
29#include <ltt/event.h>
30#include <ltt/type.h>
31#include <ltt/trace.h>
32#include <ltt/facility.h>
33#include <lttv/module.h>
34#include <lttv/hook.h>
35#include <lttv/tracecontext.h>
36#include <lttv/state.h>
37#include <lttv/filter.h>
38#include <lttvwindow/lttvwindow.h>
39#include <ltt/time.h>
40
41#include "hInterruptsInsert.xpm"
42
43#define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
44#define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format)
45#define NO_ITEMS 0
46
47typedef struct {
48 guint cpu_id;
49 guint id;
50 guint frequency;
51 LttTime total_duration;
52}Irq;
53
54typedef struct {
55 guint id;
56 guint cpu_id;
57 LttTime event_time;
58}irq_entry;
59
60enum type_t {
61 IRQ_ENTRY,
62 IRQ_EXIT
63};
64
65/** Array containing instanced objects. Used when module is unloaded */
66static GSList *interrupt_data_list = NULL ;
67
68
69typedef struct _InterruptEventData {
70
b3e7b125 71 /*Graphical Widgets */
72 GtkWidget * ScrollWindow;
73 GtkListStore *ListStore;
74 GtkWidget *Hbox;
75 GtkWidget *TreeView;
76 GtkTreeSelection *SelectionTree;
77
78 Tab * tab; /* tab that contains this plug-in*/
5f5119ee 79 LttvHooks * event_hooks;
80 LttvHooks * hooks_trace_after;
81 LttvHooks * hooks_trace_before;
b3e7b125 82 TimeWindow time_window;
83
5f5119ee 84 GArray *interrupt_counters;
85 GArray *active_irq_entry ;
86} InterruptEventData ;
87
b3e7b125 88/* Function prototypes */
5f5119ee 89
90static gboolean interrupt_update_time_window(void * hook_data, void * call_data);
5f5119ee 91GtkWidget *interrupts(Tab *tab);
b3e7b125 92// Plug-in's constructor
5f5119ee 93InterruptEventData *system_info(Tab *tab);
b3e7b125 94// Plug-in's destructor
5f5119ee 95void interrupt_destructor(InterruptEventData *event_viewer_data);
5f5119ee 96
b3e7b125 97static void request_event( InterruptEventData *event_data);
98static guint64 get_event_detail(LttEvent *e, LttField *f);
5f5119ee 99static gboolean trace_header(void *hook_data, void *call_data);
100static gboolean parse_event(void *hook_data, void *call_data);
101static gboolean interrupt_show(void *hook_data, void *call_data);
5f5119ee 102static void calcul_duration(LttTime time_exit, guint cpu_id, InterruptEventData *event_data);
103static void sum_interrupt_data(irq_entry *e, LttTime time_exit, GArray *interrupt_counters);
104/* Enumeration of the columns */
105enum{
106 CPUID_COLUMN,
107 IRQ_ID_COLUMN,
108 FREQUENCY_COLUMN,
109 DURATION_COLUMN,
110 N_COLUMNS
111};
112
5f5119ee 113/**
b3e7b125 114 * constructor hook
5f5119ee 115 *
116 * This constructor is given as a parameter to the menuitem and toolbar button
117 * registration. It creates the list.
118 * @param parent_window A pointer to the parent window.
119 * @return The widget created.
120 */
121GtkWidget *interrupts(Tab * tab){
b3e7b125 122
5f5119ee 123 InterruptEventData* event_data = system_info(tab) ;
124 if(event_data)
b3e7b125 125 return event_data->Hbox;
5f5119ee 126 else
127 return NULL;
128}
129
5f5119ee 130InterruptEventData *system_info(Tab *tab)
131{
132 LttTime end;
133 GtkTreeViewColumn *column;
134 GtkCellRenderer *renderer;
135 InterruptEventData* event_viewer_data = g_new(InterruptEventData,1) ;
136 g_info("system_info \n");
b3e7b125 137
5f5119ee 138 event_viewer_data->tab = tab;
139 event_viewer_data->time_window = lttvwindow_get_time_window(tab);
140 event_viewer_data->interrupt_counters = g_array_new(FALSE, FALSE, sizeof(Irq));
141 event_viewer_data->active_irq_entry = g_array_new(FALSE, FALSE, sizeof(irq_entry));
b3e7b125 142
143 event_viewer_data->ScrollWindow = gtk_scrolled_window_new (NULL, NULL);
144 gtk_widget_show (event_viewer_data->ScrollWindow);
5f5119ee 145 gtk_scrolled_window_set_policy(
b3e7b125 146 GTK_SCROLLED_WINDOW(event_viewer_data->ScrollWindow),
5f5119ee 147 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC/*GTK_POLICY_NEVER*/);
148
149 /* Create a model for storing the data list */
b3e7b125 150 event_viewer_data->ListStore = gtk_list_store_new (
5f5119ee 151 N_COLUMNS, /* Total number of columns */
152 G_TYPE_INT, /* CPUID */
153 G_TYPE_INT, /* IRQ_ID */
154 G_TYPE_INT, /* Frequency */
155 G_TYPE_UINT64 /* Duration */
156 );
157
b3e7b125 158 event_viewer_data->TreeView = gtk_tree_view_new_with_model (GTK_TREE_MODEL (event_viewer_data->ListStore));
5f5119ee 159
b3e7b125 160 g_object_unref (G_OBJECT (event_viewer_data->ListStore));
5f5119ee 161
162 renderer = gtk_cell_renderer_text_new ();
163 column = gtk_tree_view_column_new_with_attributes ("CPUID",
164 renderer,
165 "text", CPUID_COLUMN,
166 NULL);
167 gtk_tree_view_column_set_alignment (column, 0.0);
168 gtk_tree_view_column_set_fixed_width (column, 45);
b3e7b125 169 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
5f5119ee 170
171
172 renderer = gtk_cell_renderer_text_new ();
173 column = gtk_tree_view_column_new_with_attributes ("IrqId",
174 renderer,
175 "text", IRQ_ID_COLUMN,
176 NULL);
177 gtk_tree_view_column_set_alignment (column, 0.0);
178 gtk_tree_view_column_set_fixed_width (column, 220);
b3e7b125 179 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
5f5119ee 180
181 renderer = gtk_cell_renderer_text_new ();
182 column = gtk_tree_view_column_new_with_attributes ("Frequency",
183 renderer,
184 "text", FREQUENCY_COLUMN,
185 NULL);
186 gtk_tree_view_column_set_alignment (column, 1.0);
187 gtk_tree_view_column_set_fixed_width (column, 220);
b3e7b125 188 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
5f5119ee 189
190 renderer = gtk_cell_renderer_text_new ();
191 column = gtk_tree_view_column_new_with_attributes ("Duration (nsec)",
192 renderer,
193 "text", DURATION_COLUMN,
194 NULL);
195 gtk_tree_view_column_set_alignment (column, 0.0);
196 gtk_tree_view_column_set_fixed_width (column, 145);
b3e7b125 197 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->TreeView), column);
5f5119ee 198
b3e7b125 199 event_viewer_data->SelectionTree = gtk_tree_view_get_selection (GTK_TREE_VIEW (event_viewer_data->TreeView));
200 gtk_tree_selection_set_mode (event_viewer_data->SelectionTree, GTK_SELECTION_SINGLE);
5f5119ee 201
b3e7b125 202 gtk_container_add (GTK_CONTAINER (event_viewer_data->ScrollWindow), event_viewer_data->TreeView);
5f5119ee 203
b3e7b125 204 event_viewer_data->Hbox = gtk_hbox_new(0, 0);
205 gtk_box_pack_start(GTK_BOX(event_viewer_data->Hbox), event_viewer_data->ScrollWindow, TRUE, TRUE, 0);
5f5119ee 206
b3e7b125 207 gtk_widget_show(event_viewer_data->Hbox);
208 gtk_widget_show(event_viewer_data->TreeView);
5f5119ee 209
b3e7b125 210 interrupt_data_list = g_slist_append(interrupt_data_list, event_viewer_data);
5f5119ee 211
b3e7b125 212 lttvwindow_register_time_window_notify(tab,
213 interrupt_update_time_window,
214 event_viewer_data);
5f5119ee 215 request_event(event_viewer_data);
216 return event_viewer_data;
217}
b3e7b125 218
219
220static void request_event( InterruptEventData *event_data){
221
222 event_data->hooks_trace_before = lttv_hooks_new();
223 lttv_hooks_add(event_data->hooks_trace_before, trace_header, event_data, LTTV_PRIO_DEFAULT);
5f5119ee 224
b3e7b125 225 event_data->event_hooks = lttv_hooks_new();
226 lttv_hooks_add(event_data->event_hooks, parse_event, event_data, LTTV_PRIO_DEFAULT);
5f5119ee 227
b3e7b125 228 event_data->hooks_trace_after = lttv_hooks_new();
229 lttv_hooks_add(event_data->hooks_trace_after, interrupt_show, event_data, LTTV_PRIO_DEFAULT);
230
231 EventsRequest *events_request = g_new(EventsRequest, 1);
232 events_request->owner = event_data;
233 events_request->viewer_data = event_data;
234 events_request->servicing = FALSE;
235 events_request->start_time = event_data->time_window.start_time;
236 events_request->start_position = NULL;
237 events_request->stop_flag = FALSE;
238 events_request->end_time = event_data->time_window.end_time;
239 events_request->num_events = G_MAXUINT;
240 events_request->end_position = NULL;
241 events_request->trace = 0;
242 events_request->hooks = NULL;
243 events_request->before_chunk_traceset = NULL;
244 events_request->before_chunk_trace = event_data->hooks_trace_before;
245 events_request->before_chunk_tracefile= NULL;
246 events_request->event = event_data->event_hooks;
247 events_request->event_by_id = NULL;
248 events_request->after_chunk_tracefile = NULL;
249 events_request->after_chunk_trace = NULL;
250 events_request->after_chunk_traceset = NULL;
251 events_request->before_request = NULL;
252 events_request->after_request = event_data->hooks_trace_after;
253
254 lttvwindow_events_request(event_data->tab, events_request);
255}
5f5119ee 256
b3e7b125 257gboolean parse_event(void *hook_data, void *call_data){
258
259 LttTime event_time;
260 LttEvent *e;
261 LttField *field;
262 LttEventType *event_type;
263 unsigned cpu_id;
264 irq_entry entry;
265 irq_entry *element;
266 guint i;
267 // g_info("interrupts: parse_event() \n");
268 InterruptEventData *event_data = (InterruptEventData *)hook_data;
269 GArray* active_irq_entry = event_data->active_irq_entry;
270 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
271 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
272 //e = tfc->e;
273 e = ltt_tracefile_get_event(tfc->tf);
274
275 field = ltt_event_field(e);
276 event_time = ltt_event_time(e);
277 event_type = ltt_event_eventtype(e);
278 cpu_id = ltt_event_cpu_id(e);
279 GString * detail_event = g_string_new("");
280 if ((ltt_time_compare(event_time,event_data->time_window.start_time) == TRUE) &&
281 (ltt_time_compare(event_data->time_window.end_time,event_time) == TRUE)){
282 if (strcmp( g_quark_to_string(ltt_eventtype_name(event_type)),"irq_entry") == 0) {
283 entry.id = get_event_detail(e, field);
284 entry.cpu_id = cpu_id;
285 entry.event_time = event_time;
286 g_array_append_val (active_irq_entry, entry);
287
288 }
289 if(strcmp( g_quark_to_string(ltt_eventtype_name(event_type)),"irq_exit") == 0) {
290 //printf("event_time: %ld.%ld\n",event_time.tv_sec,event_time.tv_nsec);
291 calcul_duration( event_time, cpu_id, event_data);
292 }
293 }
294 g_string_free(detail_event, TRUE);
295 return FALSE;
5f5119ee 296}
297
b3e7b125 298
5f5119ee 299void interrupt_destructor(InterruptEventData *event_viewer_data)
300{
301 /* May already been done by GTK window closing */
302 g_info("enter interrupt_destructor \n");
b3e7b125 303 if(GTK_IS_WIDGET(event_viewer_data->Hbox)){
304 gtk_widget_destroy(event_viewer_data->Hbox);
5f5119ee 305 }
306}
307
308static guint64 get_event_detail(LttEvent *e, LttField *f){
309
310 LttType *type;
311 LttField *element;
312 GQuark name;
313 int nb, i;
314 guint64 irq_id;
315 type = ltt_field_type(f);
316 nb = ltt_type_member_number(type);
317 for(i = 0 ; i < nb-1 ; i++) {
318 element = ltt_field_member(f,i);
319 ltt_type_member_type(type, i, &name);
320 irq_id = ltt_event_get_long_unsigned(e,element);
321 }
322 return irq_id;
323}
324
325
326
327
328gboolean trace_header(void *hook_data, void *call_data){
329
330 InterruptEventData *event_data = (InterruptEventData *)hook_data;
331 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
332 LttEvent *e;
333 LttTime event_time;
334 return FALSE;
335}
336
337static gboolean interrupt_show(void *hook_data, void *call_data){
338
339 gint i;
340 Irq element;
341 LttTime average_duration;
342 GtkTreeIter iter;
343 guint64 real_data;
344 InterruptEventData *event_data = (InterruptEventData *)hook_data;
345 GArray *interrupt_counters = event_data->interrupt_counters;
346 g_info("interrupts: interrupt_show() \n");
b3e7b125 347 gtk_list_store_clear(event_data->ListStore);
5f5119ee 348 for(i = 0; i < interrupt_counters->len; i++){
349 element = g_array_index(interrupt_counters,Irq,i);
350 real_data = element.total_duration.tv_sec;
351 real_data *= NANOSECONDS_PER_SECOND;
352 real_data += element.total_duration.tv_nsec;
353 //printf("total_duration:%ld\n", element.total_duration.tv_nsec);
b3e7b125 354 gtk_list_store_append (event_data->ListStore, &iter);
355 gtk_list_store_set (event_data->ListStore, &iter,
5f5119ee 356 CPUID_COLUMN, element.cpu_id,
357 IRQ_ID_COLUMN, element.id,
358 FREQUENCY_COLUMN, element.frequency,
359 DURATION_COLUMN, real_data,
360 -1);
361 }
362
363 if(event_data->interrupt_counters->len)
364 g_array_remove_range (event_data->interrupt_counters,0,event_data->interrupt_counters->len);
365
366 if(event_data->active_irq_entry->len)
367 g_array_remove_range (event_data->active_irq_entry,0,event_data->active_irq_entry->len);
368 return FALSE;
369}
370
371static void sum_interrupt_data(irq_entry *e, LttTime time_exit, GArray *interrupt_counters){
372 Irq irq;
373 Irq *element;
374 guint i;
375 LttTime duration;
376 gboolean notFound = FALSE;
377 memset ((void*)&irq, 0,sizeof(Irq));
378
379 //printf("time_exit: %ld.%ld\n",time_exit.tv_sec,time_exit.tv_nsec);
380 if(interrupt_counters->len == NO_ITEMS){
381 irq.cpu_id = e->cpu_id;
382 irq.id = e->id;
383 irq.frequency++;
384 irq.total_duration = ltt_time_sub(time_exit, e->event_time);
385 g_array_append_val (interrupt_counters, irq);
386 }
387 else{
388 for(i = 0; i < interrupt_counters->len; i++){
389 element = &g_array_index(interrupt_counters,Irq,i);
390 if(element->id == e->id){
391 notFound = TRUE;
392 duration = ltt_time_sub(time_exit, e->event_time);
393 element->total_duration = ltt_time_add(element->total_duration, duration);
394 element->frequency++;
395 }
396 }
397 if(!notFound){
398 irq.cpu_id = e->cpu_id;
399 irq.id = e->id;
400 irq.frequency++;
401 irq.total_duration = ltt_time_sub(time_exit, e->event_time);
402 g_array_append_val (interrupt_counters, irq);
403 }
404 }
405}
406
407static void calcul_duration(LttTime time_exit, guint cpu_id,InterruptEventData *event_data){
408
409 gint i, irq_id;
410 irq_entry *element;
411 LttTime duration;
412 GArray *interrupt_counters = event_data->interrupt_counters;
413 GArray *active_irq_entry = event_data->active_irq_entry;
414 for(i = 0; i < active_irq_entry->len; i++){
415 element = &g_array_index(active_irq_entry,irq_entry,i);
416 if(element->cpu_id == cpu_id){
417 sum_interrupt_data(element,time_exit, interrupt_counters);
418 g_array_remove_index(active_irq_entry, i);
419 // printf("array length:%d\n",active_irq_entry->len);
420 break;
421 }
422 }
423}
424
5f5119ee 425
426gboolean interrupt_update_time_window(void * hook_data, void * call_data){
427
428 InterruptEventData *event_data = (InterruptEventData *) hook_data;
429 const TimeWindowNotifyData *time_window_nofify_data = ((const TimeWindowNotifyData *)call_data);
430 event_data->time_window = *time_window_nofify_data->new_time_window;
431 g_info("interrupts: interrupt_update_time_window()\n");
432 Tab *tab = event_data->tab;
433 lttvwindow_events_request_remove_all(tab, event_data);
434 request_event(event_data);
435
436
437 return FALSE;
438}
439
440/**
441 * plugin's init function
442 *
443 * This function initializes the Event Viewer functionnality through the
444 * gtkTraceSet API.
445 */
446static void init() {
447 g_info("interrupts: init()");
5f5119ee 448 lttvwindow_register_constructor("interrupts",
449 "/",
450 "Insert Interrupts View",
451 hInterruptsInsert_xpm,
452 "Insert Interrupts View",
453 interrupts);
a4f37ccd 454
5f5119ee 455}
456
457void interrupt_destroy_walk(gpointer data, gpointer user_data){
458 g_info("interrupt_destroy_walk");
459 interrupt_destructor((InterruptEventData*)data);
460
461}
462
463/**
464 * plugin's destroy function
465 *
466 * This function releases the memory reserved by the module and unregisters
467 * everything that has been registered in the gtkTraceSet API.
468 */
469static void destroy() {
470 g_info("Destroy interrupts");
471 g_slist_foreach(interrupt_data_list, interrupt_destroy_walk, NULL );
472 g_slist_free(interrupt_data_list);
473 lttvwindow_unregister_constructor(interrupts);
474
475}
476
477LTTV_MODULE("interrupts", "interrupts info view", \
478 "Graphical module to display interrupts performance", \
479 init, destroy, "lttvwindow")
This page took 0.044846 seconds and 4 git commands to generate.