genevent fix : warnings
[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
71 Tab * tab;
72 LttvHooks * event_hooks;
73 LttvHooks * hooks_trace_after;
74 LttvHooks * hooks_trace_before;
75 TimeWindow time_window; // time window
76 GtkWidget * scroll_win;
77 /* Model containing list data */
78 GtkListStore *store_m;
79 GtkWidget *hbox_v;
80 /* Widget to display the data in a columned list */
81 GtkWidget *tree_v;
82 /* Selection handler */
83 GtkTreeSelection *select_c;
84 GtkWidget *container;
85 GArray *interrupt_counters;
86 GArray *active_irq_entry ;
87} InterruptEventData ;
88
89
90
91static gboolean interrupt_update_time_window(void * hook_data, void * call_data);
92// Event Viewer's constructor hook
93GtkWidget *interrupts(Tab *tab);
94// Event Viewer's constructor
95InterruptEventData *system_info(Tab *tab);
96// Event Viewer's destructor
97void interrupt_destructor(InterruptEventData *event_viewer_data);
98void gui_events_free(InterruptEventData *event_viewer_data);
99static void request_event( InterruptEventData *event_data);
100 /* Prototype for selection handler callback */
101
102static void v_scroll_cb (GtkAdjustment *adjustment, gpointer data);
103
104static gboolean trace_header(void *hook_data, void *call_data);
105static gboolean parse_event(void *hook_data, void *call_data);
106static gboolean interrupt_show(void *hook_data, void *call_data);
107
108static void calcul_duration(LttTime time_exit, guint cpu_id, InterruptEventData *event_data);
109static void sum_interrupt_data(irq_entry *e, LttTime time_exit, GArray *interrupt_counters);
110/* Enumeration of the columns */
111enum{
112 CPUID_COLUMN,
113 IRQ_ID_COLUMN,
114 FREQUENCY_COLUMN,
115 DURATION_COLUMN,
116 N_COLUMNS
117};
118
119
120/**
121 * Event Viewer's constructor hook
122 *
123 * This constructor is given as a parameter to the menuitem and toolbar button
124 * registration. It creates the list.
125 * @param parent_window A pointer to the parent window.
126 * @return The widget created.
127 */
128GtkWidget *interrupts(Tab * tab){
129 InterruptEventData* event_data = system_info(tab) ;
130 if(event_data)
131 return event_data->hbox_v;
132 else
133 return NULL;
134}
135
136/**
137 * Event Viewer's constructor
138 *
139 * This constructor is used to create InterruptEventData data structure.
140 * @return The Event viewer data created.
141 */
142InterruptEventData *system_info(Tab *tab)
143{
144 LttTime end;
145 GtkTreeViewColumn *column;
146 GtkCellRenderer *renderer;
147 InterruptEventData* event_viewer_data = g_new(InterruptEventData,1) ;
148 g_info("system_info \n");
149
150 event_viewer_data->tab = tab;
151 event_viewer_data->time_window = lttvwindow_get_time_window(tab);
152 event_viewer_data->interrupt_counters = g_array_new(FALSE, FALSE, sizeof(Irq));
153 event_viewer_data->active_irq_entry = g_array_new(FALSE, FALSE, sizeof(irq_entry));
154
155 lttvwindow_register_time_window_notify(tab,
156 interrupt_update_time_window,
157 event_viewer_data);
158
159 event_viewer_data->scroll_win = gtk_scrolled_window_new (NULL, NULL);
160 gtk_widget_show (event_viewer_data->scroll_win);
161 gtk_scrolled_window_set_policy(
162 GTK_SCROLLED_WINDOW(event_viewer_data->scroll_win),
163 GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC/*GTK_POLICY_NEVER*/);
164
165 /* Create a model for storing the data list */
166 event_viewer_data->store_m = gtk_list_store_new (
167 N_COLUMNS, /* Total number of columns */
168 G_TYPE_INT, /* CPUID */
169 G_TYPE_INT, /* IRQ_ID */
170 G_TYPE_INT, /* Frequency */
171 G_TYPE_UINT64 /* Duration */
172 );
173
174 event_viewer_data->tree_v = gtk_tree_view_new_with_model (GTK_TREE_MODEL (event_viewer_data->store_m));
175
176 g_object_unref (G_OBJECT (event_viewer_data->store_m));
177
178 renderer = gtk_cell_renderer_text_new ();
179 column = gtk_tree_view_column_new_with_attributes ("CPUID",
180 renderer,
181 "text", CPUID_COLUMN,
182 NULL);
183 gtk_tree_view_column_set_alignment (column, 0.0);
184 gtk_tree_view_column_set_fixed_width (column, 45);
185 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->tree_v), column);
186
187
188 renderer = gtk_cell_renderer_text_new ();
189 column = gtk_tree_view_column_new_with_attributes ("IrqId",
190 renderer,
191 "text", IRQ_ID_COLUMN,
192 NULL);
193 gtk_tree_view_column_set_alignment (column, 0.0);
194 gtk_tree_view_column_set_fixed_width (column, 220);
195 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->tree_v), column);
196
197 renderer = gtk_cell_renderer_text_new ();
198 column = gtk_tree_view_column_new_with_attributes ("Frequency",
199 renderer,
200 "text", FREQUENCY_COLUMN,
201 NULL);
202 gtk_tree_view_column_set_alignment (column, 1.0);
203 gtk_tree_view_column_set_fixed_width (column, 220);
204 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->tree_v), column);
205
206 renderer = gtk_cell_renderer_text_new ();
207 column = gtk_tree_view_column_new_with_attributes ("Duration (nsec)",
208 renderer,
209 "text", DURATION_COLUMN,
210 NULL);
211 gtk_tree_view_column_set_alignment (column, 0.0);
212 gtk_tree_view_column_set_fixed_width (column, 145);
213 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data->tree_v), column);
214
215 event_viewer_data->select_c = gtk_tree_view_get_selection (GTK_TREE_VIEW (event_viewer_data->tree_v));
216 gtk_tree_selection_set_mode (event_viewer_data->select_c, GTK_SELECTION_SINGLE);
217
218 gtk_container_add (GTK_CONTAINER (event_viewer_data->scroll_win), event_viewer_data->tree_v);
219
220 event_viewer_data->hbox_v = gtk_hbox_new(0, 0);
221 gtk_box_pack_start(GTK_BOX(event_viewer_data->hbox_v), event_viewer_data->scroll_win, TRUE, TRUE, 0);
222
223 gtk_widget_show(event_viewer_data->hbox_v);
224 gtk_widget_show(event_viewer_data->tree_v);
225
226 interrupt_data_list = g_slist_append(interrupt_data_list, event_viewer_data);
227
228 request_event(event_viewer_data);
229 return event_viewer_data;
230}
231
232void v_scroll_cb(GtkAdjustment *adjustment, gpointer data){
233 InterruptEventData *event_data = (InterruptEventData*)data;
234 GtkTreePath *tree_path;
235 g_info("enter v_scroll_cb\n");
236}
237
238void gui_events_free(InterruptEventData *event_viewer_data)
239{
240 Tab *tab = event_viewer_data->tab;
241
242 if(event_viewer_data){
243 lttv_hooks_remove(event_viewer_data->event_hooks,parse_event);
244 lttv_hooks_destroy(event_viewer_data->event_hooks);
245
246 interrupt_data_list = g_slist_remove(interrupt_data_list, event_viewer_data);
247 g_free(event_viewer_data);
248 }
249}
250
251void interrupt_destructor(InterruptEventData *event_viewer_data)
252{
253 /* May already been done by GTK window closing */
254 g_info("enter interrupt_destructor \n");
255 if(GTK_IS_WIDGET(event_viewer_data->hbox_v)){
256 gtk_widget_destroy(event_viewer_data->hbox_v);
257 }
258}
259
260static guint64 get_event_detail(LttEvent *e, LttField *f){
261
262 LttType *type;
263 LttField *element;
264 GQuark name;
265 int nb, i;
266 guint64 irq_id;
267 type = ltt_field_type(f);
268 nb = ltt_type_member_number(type);
269 for(i = 0 ; i < nb-1 ; i++) {
270 element = ltt_field_member(f,i);
271 ltt_type_member_type(type, i, &name);
272 irq_id = ltt_event_get_long_unsigned(e,element);
273 }
274 return irq_id;
275}
276
277
278
279
280gboolean trace_header(void *hook_data, void *call_data){
281
282 InterruptEventData *event_data = (InterruptEventData *)hook_data;
283 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
284 LttEvent *e;
285 LttTime event_time;
286 return FALSE;
287}
288
289static gboolean interrupt_show(void *hook_data, void *call_data){
290
291 gint i;
292 Irq element;
293 LttTime average_duration;
294 GtkTreeIter iter;
295 guint64 real_data;
296 InterruptEventData *event_data = (InterruptEventData *)hook_data;
297 GArray *interrupt_counters = event_data->interrupt_counters;
298 g_info("interrupts: interrupt_show() \n");
299 gtk_list_store_clear(event_data->store_m);
300 for(i = 0; i < interrupt_counters->len; i++){
301 element = g_array_index(interrupt_counters,Irq,i);
302 real_data = element.total_duration.tv_sec;
303 real_data *= NANOSECONDS_PER_SECOND;
304 real_data += element.total_duration.tv_nsec;
305 //printf("total_duration:%ld\n", element.total_duration.tv_nsec);
306 gtk_list_store_append (event_data->store_m, &iter);
307 gtk_list_store_set (event_data->store_m, &iter,
308 CPUID_COLUMN, element.cpu_id,
309 IRQ_ID_COLUMN, element.id,
310 FREQUENCY_COLUMN, element.frequency,
311 DURATION_COLUMN, real_data,
312 -1);
313 }
314
315 if(event_data->interrupt_counters->len)
316 g_array_remove_range (event_data->interrupt_counters,0,event_data->interrupt_counters->len);
317
318 if(event_data->active_irq_entry->len)
319 g_array_remove_range (event_data->active_irq_entry,0,event_data->active_irq_entry->len);
320 return FALSE;
321}
322
323static void sum_interrupt_data(irq_entry *e, LttTime time_exit, GArray *interrupt_counters){
324 Irq irq;
325 Irq *element;
326 guint i;
327 LttTime duration;
328 gboolean notFound = FALSE;
329 memset ((void*)&irq, 0,sizeof(Irq));
330
331 //printf("time_exit: %ld.%ld\n",time_exit.tv_sec,time_exit.tv_nsec);
332 if(interrupt_counters->len == NO_ITEMS){
333 irq.cpu_id = e->cpu_id;
334 irq.id = e->id;
335 irq.frequency++;
336 irq.total_duration = ltt_time_sub(time_exit, e->event_time);
337 g_array_append_val (interrupt_counters, irq);
338 }
339 else{
340 for(i = 0; i < interrupt_counters->len; i++){
341 element = &g_array_index(interrupt_counters,Irq,i);
342 if(element->id == e->id){
343 notFound = TRUE;
344 duration = ltt_time_sub(time_exit, e->event_time);
345 element->total_duration = ltt_time_add(element->total_duration, duration);
346 element->frequency++;
347 }
348 }
349 if(!notFound){
350 irq.cpu_id = e->cpu_id;
351 irq.id = e->id;
352 irq.frequency++;
353 irq.total_duration = ltt_time_sub(time_exit, e->event_time);
354 g_array_append_val (interrupt_counters, irq);
355 }
356 }
357}
358
359static void calcul_duration(LttTime time_exit, guint cpu_id,InterruptEventData *event_data){
360
361 gint i, irq_id;
362 irq_entry *element;
363 LttTime duration;
364 GArray *interrupt_counters = event_data->interrupt_counters;
365 GArray *active_irq_entry = event_data->active_irq_entry;
366 for(i = 0; i < active_irq_entry->len; i++){
367 element = &g_array_index(active_irq_entry,irq_entry,i);
368 if(element->cpu_id == cpu_id){
369 sum_interrupt_data(element,time_exit, interrupt_counters);
370 g_array_remove_index(active_irq_entry, i);
371 // printf("array length:%d\n",active_irq_entry->len);
372 break;
373 }
374 }
375}
376
377gboolean parse_event(void *hook_data, void *call_data){
378
379 LttTime event_time;
380 LttEvent *e;
381 LttField *field;
382 LttEventType *event_type;
383 unsigned cpu_id;
384 irq_entry entry;
385 irq_entry *element;
386 guint i;
387 // g_info("interrupts: parse_event() \n");
388 InterruptEventData *event_data = (InterruptEventData *)hook_data;
389 GArray* active_irq_entry = event_data->active_irq_entry;
390 LttvTracefileContext *tfc = (LttvTracefileContext *)call_data;
391 LttvTracefileState *tfs = (LttvTracefileState *)call_data;
392 //e = tfc->e;
a4f37ccd 393 e = ltt_tracefile_get_event(tfc->tf);
5f5119ee 394
395 field = ltt_event_field(e);
396 event_time = ltt_event_time(e);
397 event_type = ltt_event_eventtype(e);
398 cpu_id = ltt_event_cpu_id(e);
399 GString * detail_event = g_string_new("");
400 if ((ltt_time_compare(event_time,event_data->time_window.start_time) == TRUE) &&
401 (ltt_time_compare(event_data->time_window.end_time,event_time) == TRUE)){
402 if (strcmp( g_quark_to_string(ltt_eventtype_name(event_type)),"irq_entry") == 0) {
403 entry.id = get_event_detail(e, field);
404 entry.cpu_id = cpu_id;
405 entry.event_time = event_time;
406 g_array_append_val (active_irq_entry, entry);
407
408 }
409 if(strcmp( g_quark_to_string(ltt_eventtype_name(event_type)),"irq_exit") == 0) {
410 //printf("event_time: %ld.%ld\n",event_time.tv_sec,event_time.tv_nsec);
411 calcul_duration( event_time, cpu_id, event_data);
412 }
413 }
414 g_string_free(detail_event, TRUE);
415 return FALSE;
416}
417
418static void request_event( InterruptEventData *event_data){
419
420 event_data->event_hooks = lttv_hooks_new();
421 lttv_hooks_add(event_data->event_hooks, parse_event, event_data, LTTV_PRIO_DEFAULT);
422
423 event_data->hooks_trace_after = lttv_hooks_new();
424 lttv_hooks_add(event_data->hooks_trace_after, interrupt_show, event_data, LTTV_PRIO_DEFAULT);
425
426 event_data->hooks_trace_before = lttv_hooks_new();
427 lttv_hooks_add(event_data->hooks_trace_before, trace_header, event_data, LTTV_PRIO_DEFAULT);
428
429 EventsRequest *events_request = g_new(EventsRequest, 1);
430 events_request->owner = event_data;
431 events_request->viewer_data = event_data;
432 events_request->servicing = FALSE;
433 events_request->start_time = event_data->time_window.start_time;
434 events_request->start_position = NULL;
435 events_request->stop_flag = FALSE;
436 events_request->end_time = event_data->time_window.end_time;
437 events_request->num_events = G_MAXUINT;
438 events_request->end_position = NULL;
439 events_request->trace = 0;
440 events_request->hooks = NULL;
441 events_request->before_chunk_traceset = NULL;
442 events_request->before_chunk_trace = event_data->hooks_trace_before;
443 events_request->before_chunk_tracefile= NULL;
444 events_request->event = event_data->event_hooks;
445 events_request->event_by_id = NULL;
446 events_request->after_chunk_tracefile = NULL;
447 events_request->after_chunk_trace = NULL;
448 events_request->after_chunk_traceset = NULL;
449 events_request->before_request = NULL;
450 events_request->after_request = event_data->hooks_trace_after;
451
452 lttvwindow_events_request(event_data->tab, events_request);
453}
454
455gboolean interrupt_update_time_window(void * hook_data, void * call_data){
456
457 InterruptEventData *event_data = (InterruptEventData *) hook_data;
458 const TimeWindowNotifyData *time_window_nofify_data = ((const TimeWindowNotifyData *)call_data);
459 event_data->time_window = *time_window_nofify_data->new_time_window;
460 g_info("interrupts: interrupt_update_time_window()\n");
461 Tab *tab = event_data->tab;
462 lttvwindow_events_request_remove_all(tab, event_data);
463 request_event(event_data);
464
465
466 return FALSE;
467}
468
469/**
470 * plugin's init function
471 *
472 * This function initializes the Event Viewer functionnality through the
473 * gtkTraceSet API.
474 */
475static void init() {
476 g_info("interrupts: init()");
477
478 lttvwindow_register_constructor("interrupts",
479 "/",
480 "Insert Interrupts View",
481 hInterruptsInsert_xpm,
482 "Insert Interrupts View",
483 interrupts);
a4f37ccd 484
5f5119ee 485}
486
487void interrupt_destroy_walk(gpointer data, gpointer user_data){
488 g_info("interrupt_destroy_walk");
489 interrupt_destructor((InterruptEventData*)data);
490
491}
492
493/**
494 * plugin's destroy function
495 *
496 * This function releases the memory reserved by the module and unregisters
497 * everything that has been registered in the gtkTraceSet API.
498 */
499static void destroy() {
500 g_info("Destroy interrupts");
501 g_slist_foreach(interrupt_data_list, interrupt_destroy_walk, NULL );
502 g_slist_free(interrupt_data_list);
503 lttvwindow_unregister_constructor(interrupts);
504
505}
506
507LTTV_MODULE("interrupts", "interrupts info view", \
508 "Graphical module to display interrupts performance", \
509 init, destroy, "lttvwindow")
This page took 0.041154 seconds and 4 git commands to generate.