1 /* This file is part of the Linux Trace Toolkit viewer
2 * Copyright (C) 2005 Peter Ho
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;
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.
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,
29 #include <ltt/event.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>
41 #include "hInterruptsInsert.xpm"
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)
51 LttTime total_duration
;
65 /** Array containing instanced objects. Used when module is unloaded */
66 static GSList
*interrupt_data_list
= NULL
;
69 typedef struct _InterruptEventData
{
71 /*Graphical Widgets */
72 GtkWidget
* ScrollWindow
;
73 GtkListStore
*ListStore
;
76 GtkTreeSelection
*SelectionTree
;
78 Tab
* tab
; /* tab that contains this plug-in*/
79 LttvHooks
* event_hooks
;
80 LttvHooks
* hooks_trace_after
;
81 LttvHooks
* hooks_trace_before
;
82 TimeWindow time_window
;
84 GArray
*interrupt_counters
;
85 GArray
*active_irq_entry
;
86 } InterruptEventData
;
88 /* Function prototypes */
90 static gboolean
interrupt_update_time_window(void * hook_data
, void * call_data
);
91 GtkWidget
*interrupts(Tab
*tab
);
92 // Plug-in's constructor
93 InterruptEventData
*system_info(Tab
*tab
);
94 // Plug-in's destructor
95 void interrupt_destructor(InterruptEventData
*event_viewer_data
);
97 static void request_event( InterruptEventData
*event_data
);
98 static guint64
get_event_detail(LttEvent
*e
, LttField
*f
);
99 static gboolean
trace_header(void *hook_data
, void *call_data
);
100 static gboolean
parse_event(void *hook_data
, void *call_data
);
101 static gboolean
interrupt_show(void *hook_data
, void *call_data
);
102 static void calcul_duration(LttTime time_exit
, guint cpu_id
, InterruptEventData
*event_data
);
103 static void sum_interrupt_data(irq_entry
*e
, LttTime time_exit
, GArray
*interrupt_counters
);
104 /* Enumeration of the columns */
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.
121 GtkWidget
*interrupts(Tab
* tab
){
123 InterruptEventData
* event_data
= system_info(tab
) ;
125 return event_data
->Hbox
;
130 InterruptEventData
*system_info(Tab
*tab
)
133 GtkTreeViewColumn
*column
;
134 GtkCellRenderer
*renderer
;
135 InterruptEventData
* event_viewer_data
= g_new(InterruptEventData
,1) ;
136 g_info("system_info \n");
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
));
143 event_viewer_data
->ScrollWindow
= gtk_scrolled_window_new (NULL
, NULL
);
144 gtk_widget_show (event_viewer_data
->ScrollWindow
);
145 gtk_scrolled_window_set_policy(
146 GTK_SCROLLED_WINDOW(event_viewer_data
->ScrollWindow
),
147 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
/*GTK_POLICY_NEVER*/);
149 /* Create a model for storing the data list */
150 event_viewer_data
->ListStore
= gtk_list_store_new (
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 */
158 event_viewer_data
->TreeView
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (event_viewer_data
->ListStore
));
160 g_object_unref (G_OBJECT (event_viewer_data
->ListStore
));
162 renderer
= gtk_cell_renderer_text_new ();
163 column
= gtk_tree_view_column_new_with_attributes ("CPUID",
165 "text", CPUID_COLUMN
,
167 gtk_tree_view_column_set_alignment (column
, 0.0);
168 gtk_tree_view_column_set_fixed_width (column
, 45);
169 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
172 renderer
= gtk_cell_renderer_text_new ();
173 column
= gtk_tree_view_column_new_with_attributes ("IrqId",
175 "text", IRQ_ID_COLUMN
,
177 gtk_tree_view_column_set_alignment (column
, 0.0);
178 gtk_tree_view_column_set_fixed_width (column
, 220);
179 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
181 renderer
= gtk_cell_renderer_text_new ();
182 column
= gtk_tree_view_column_new_with_attributes ("Frequency",
184 "text", FREQUENCY_COLUMN
,
186 gtk_tree_view_column_set_alignment (column
, 1.0);
187 gtk_tree_view_column_set_fixed_width (column
, 220);
188 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
190 renderer
= gtk_cell_renderer_text_new ();
191 column
= gtk_tree_view_column_new_with_attributes ("Duration (nsec)",
193 "text", DURATION_COLUMN
,
195 gtk_tree_view_column_set_alignment (column
, 0.0);
196 gtk_tree_view_column_set_fixed_width (column
, 145);
197 gtk_tree_view_append_column (GTK_TREE_VIEW (event_viewer_data
->TreeView
), column
);
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
);
202 gtk_container_add (GTK_CONTAINER (event_viewer_data
->ScrollWindow
), event_viewer_data
->TreeView
);
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);
207 gtk_widget_show(event_viewer_data
->Hbox
);
208 gtk_widget_show(event_viewer_data
->TreeView
);
210 interrupt_data_list
= g_slist_append(interrupt_data_list
, event_viewer_data
);
212 lttvwindow_register_time_window_notify(tab
,
213 interrupt_update_time_window
,
215 request_event(event_viewer_data
);
216 return event_viewer_data
;
220 static void request_event( InterruptEventData
*event_data
){
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
);
225 event_data
->event_hooks
= lttv_hooks_new();
226 lttv_hooks_add(event_data
->event_hooks
, parse_event
, event_data
, LTTV_PRIO_DEFAULT
);
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
);
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
;
254 lttvwindow_events_request(event_data
->tab
, events_request
);
257 gboolean
parse_event(void *hook_data
, void *call_data
){
262 LttEventType
*event_type
;
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
;
273 e
= ltt_tracefile_get_event(tfc
->tf
);
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
);
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
);
294 g_string_free(detail_event
, TRUE
);
299 void interrupt_destructor(InterruptEventData
*event_viewer_data
)
301 /* May already been done by GTK window closing */
302 g_info("enter interrupt_destructor \n");
303 if(GTK_IS_WIDGET(event_viewer_data
->Hbox
)){
304 gtk_widget_destroy(event_viewer_data
->Hbox
);
308 static guint64
get_event_detail(LttEvent
*e
, LttField
*f
){
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
);
328 gboolean
trace_header(void *hook_data
, void *call_data
){
330 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
331 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
337 static gboolean
interrupt_show(void *hook_data
, void *call_data
){
341 LttTime average_duration
;
344 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
345 GArray
*interrupt_counters
= event_data
->interrupt_counters
;
346 g_info("interrupts: interrupt_show() \n");
347 gtk_list_store_clear(event_data
->ListStore
);
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);
354 gtk_list_store_append (event_data
->ListStore
, &iter
);
355 gtk_list_store_set (event_data
->ListStore
, &iter
,
356 CPUID_COLUMN
, element
.cpu_id
,
357 IRQ_ID_COLUMN
, element
.id
,
358 FREQUENCY_COLUMN
, element
.frequency
,
359 DURATION_COLUMN
, real_data
,
363 if(event_data
->interrupt_counters
->len
)
364 g_array_remove_range (event_data
->interrupt_counters
,0,event_data
->interrupt_counters
->len
);
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
);
371 static void sum_interrupt_data(irq_entry
*e
, LttTime time_exit
, GArray
*interrupt_counters
){
376 gboolean notFound
= FALSE
;
377 memset ((void*)&irq
, 0,sizeof(Irq
));
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
;
384 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
385 g_array_append_val (interrupt_counters
, irq
);
388 for(i
= 0; i
< interrupt_counters
->len
; i
++){
389 element
= &g_array_index(interrupt_counters
,Irq
,i
);
390 if(element
->id
== e
->id
){
392 duration
= ltt_time_sub(time_exit
, e
->event_time
);
393 element
->total_duration
= ltt_time_add(element
->total_duration
, duration
);
394 element
->frequency
++;
398 irq
.cpu_id
= e
->cpu_id
;
401 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
402 g_array_append_val (interrupt_counters
, irq
);
407 static void calcul_duration(LttTime time_exit
, guint cpu_id
,InterruptEventData
*event_data
){
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);
426 gboolean
interrupt_update_time_window(void * hook_data
, void * call_data
){
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
);
441 * plugin's init function
443 * This function initializes the Event Viewer functionnality through the
447 g_info("interrupts: init()");
448 lttvwindow_register_constructor("interrupts",
450 "Insert Interrupts View",
451 hInterruptsInsert_xpm
,
452 "Insert Interrupts View",
457 void interrupt_destroy_walk(gpointer data
, gpointer user_data
){
458 g_info("interrupt_destroy_walk");
459 interrupt_destructor((InterruptEventData
*)data
);
464 * plugin's destroy function
466 * This function releases the memory reserved by the module and unregisters
467 * everything that has been registered in the gtkTraceSet API.
469 static 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
);
477 LTTV_MODULE("interrupts", "interrupts info view", \
478 "Graphical module to display interrupts performance", \
479 init
, destroy
, "lttvwindow")