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
{
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
;
80 /* Widget to display the data in a columned list */
82 /* Selection handler */
83 GtkTreeSelection
*select_c
;
85 GArray
*interrupt_counters
;
86 GArray
*active_irq_entry
;
87 } InterruptEventData
;
91 static gboolean
interrupt_update_time_window(void * hook_data
, void * call_data
);
92 // Event Viewer's constructor hook
93 GtkWidget
*interrupts(Tab
*tab
);
94 // Event Viewer's constructor
95 InterruptEventData
*system_info(Tab
*tab
);
96 // Event Viewer's destructor
97 void interrupt_destructor(InterruptEventData
*event_viewer_data
);
98 void gui_events_free(InterruptEventData
*event_viewer_data
);
99 static void request_event( InterruptEventData
*event_data
);
100 /* Prototype for selection handler callback */
102 static void v_scroll_cb (GtkAdjustment
*adjustment
, gpointer data
);
104 static gboolean
trace_header(void *hook_data
, void *call_data
);
105 static gboolean
parse_event(void *hook_data
, void *call_data
);
106 static gboolean
interrupt_show(void *hook_data
, void *call_data
);
108 static void calcul_duration(LttTime time_exit
, guint cpu_id
, InterruptEventData
*event_data
);
109 static void sum_interrupt_data(irq_entry
*e
, LttTime time_exit
, GArray
*interrupt_counters
);
110 /* Enumeration of the columns */
121 * Event Viewer's constructor hook
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.
128 GtkWidget
*interrupts(Tab
* tab
){
129 InterruptEventData
* event_data
= system_info(tab
) ;
131 return event_data
->hbox_v
;
137 * Event Viewer's constructor
139 * This constructor is used to create InterruptEventData data structure.
140 * @return The Event viewer data created.
142 InterruptEventData
*system_info(Tab
*tab
)
145 GtkTreeViewColumn
*column
;
146 GtkCellRenderer
*renderer
;
147 InterruptEventData
* event_viewer_data
= g_new(InterruptEventData
,1) ;
148 g_info("system_info \n");
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
));
155 lttvwindow_register_time_window_notify(tab
,
156 interrupt_update_time_window
,
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*/);
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 */
174 event_viewer_data
->tree_v
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (event_viewer_data
->store_m
));
176 g_object_unref (G_OBJECT (event_viewer_data
->store_m
));
178 renderer
= gtk_cell_renderer_text_new ();
179 column
= gtk_tree_view_column_new_with_attributes ("CPUID",
181 "text", CPUID_COLUMN
,
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
);
188 renderer
= gtk_cell_renderer_text_new ();
189 column
= gtk_tree_view_column_new_with_attributes ("IrqId",
191 "text", IRQ_ID_COLUMN
,
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
);
197 renderer
= gtk_cell_renderer_text_new ();
198 column
= gtk_tree_view_column_new_with_attributes ("Frequency",
200 "text", FREQUENCY_COLUMN
,
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
);
206 renderer
= gtk_cell_renderer_text_new ();
207 column
= gtk_tree_view_column_new_with_attributes ("Duration (nsec)",
209 "text", DURATION_COLUMN
,
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
);
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
);
218 gtk_container_add (GTK_CONTAINER (event_viewer_data
->scroll_win
), event_viewer_data
->tree_v
);
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);
223 gtk_widget_show(event_viewer_data
->hbox_v
);
224 gtk_widget_show(event_viewer_data
->tree_v
);
226 interrupt_data_list
= g_slist_append(interrupt_data_list
, event_viewer_data
);
228 request_event(event_viewer_data
);
229 return event_viewer_data
;
232 void 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");
238 void gui_events_free(InterruptEventData
*event_viewer_data
)
240 Tab
*tab
= event_viewer_data
->tab
;
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
);
246 interrupt_data_list
= g_slist_remove(interrupt_data_list
, event_viewer_data
);
247 g_free(event_viewer_data
);
251 void interrupt_destructor(InterruptEventData
*event_viewer_data
)
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
);
260 static guint64
get_event_detail(LttEvent
*e
, LttField
*f
){
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
);
280 gboolean
trace_header(void *hook_data
, void *call_data
){
282 InterruptEventData
*event_data
= (InterruptEventData
*)hook_data
;
283 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
289 static gboolean
interrupt_show(void *hook_data
, void *call_data
){
293 LttTime average_duration
;
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
,
315 if(event_data
->interrupt_counters
->len
)
316 g_array_remove_range (event_data
->interrupt_counters
,0,event_data
->interrupt_counters
->len
);
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
);
323 static void sum_interrupt_data(irq_entry
*e
, LttTime time_exit
, GArray
*interrupt_counters
){
328 gboolean notFound
= FALSE
;
329 memset ((void*)&irq
, 0,sizeof(Irq
));
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
;
336 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
337 g_array_append_val (interrupt_counters
, irq
);
340 for(i
= 0; i
< interrupt_counters
->len
; i
++){
341 element
= &g_array_index(interrupt_counters
,Irq
,i
);
342 if(element
->id
== e
->id
){
344 duration
= ltt_time_sub(time_exit
, e
->event_time
);
345 element
->total_duration
= ltt_time_add(element
->total_duration
, duration
);
346 element
->frequency
++;
350 irq
.cpu_id
= e
->cpu_id
;
353 irq
.total_duration
= ltt_time_sub(time_exit
, e
->event_time
);
354 g_array_append_val (interrupt_counters
, irq
);
359 static void calcul_duration(LttTime time_exit
, guint cpu_id
,InterruptEventData
*event_data
){
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);
377 gboolean
parse_event(void *hook_data
, void *call_data
){
382 LttEventType
*event_type
;
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
;
393 e
= e
= ltt_tracefile_get_event(tfc
->tf
);
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
);
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
);
414 g_string_free(detail_event
, TRUE
);
418 static void request_event( InterruptEventData
*event_data
){
420 event_data
->event_hooks
= lttv_hooks_new();
421 lttv_hooks_add(event_data
->event_hooks
, parse_event
, event_data
, LTTV_PRIO_DEFAULT
);
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
);
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
);
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
;
452 lttvwindow_events_request(event_data
->tab
, events_request
);
455 gboolean
interrupt_update_time_window(void * hook_data
, void * call_data
){
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
);
470 * plugin's init function
472 * This function initializes the Event Viewer functionnality through the
476 g_info("interrupts: init()");
478 lttvwindow_register_constructor("interrupts",
480 "Insert Interrupts View",
481 hInterruptsInsert_xpm
,
482 "Insert Interrupts View",
484 printf("out: init()\n");
487 void interrupt_destroy_walk(gpointer data
, gpointer user_data
){
488 g_info("interrupt_destroy_walk");
489 interrupt_destructor((InterruptEventData
*)data
);
494 * plugin's destroy function
496 * This function releases the memory reserved by the module and unregisters
497 * everything that has been registered in the gtkTraceSet API.
499 static 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
);
507 LTTV_MODULE("interrupts", "interrupts info view", \
508 "Graphical module to display interrupts performance", \
509 init
, destroy
, "lttvwindow")