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,
31 #include <ltt/event.h>
33 #include <ltt/trace.h>
34 #include <ltt/facility.h>
35 #include <lttv/module.h>
36 #include <lttv/hook.h>
37 #include <lttv/tracecontext.h>
38 #include <lttv/state.h>
39 #include <lttv/filter.h>
40 #include <lttvwindow/lttvwindow.h>
43 #include "hDiskPerformanceInsert.xpm"
46 #define g_info(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_INFO, format)
47 #define g_debug(format...) g_log (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG, format)
61 LTTV_READ_OPERATION
= 1,
65 typedef struct _DiskPerformanceData
{
68 LttvHooks
* event_hooks
;
69 LttvHooks
* hooks_trace_after
;
70 LttvHooks
* hooks_trace_before
;
71 TimeWindow time_window
; // time window
73 GtkWidget
* scroll_win
;
74 /* Model containing list data */
75 GtkListStore
*store_m
;
77 /* Widget to display the data in a columned list */
79 /* Selection handler */
80 GtkTreeSelection
*select_c
;
84 } DiskPerformanceData
;
87 typedef struct _lttv_block
{
93 typedef struct _lttv_total_block
{
95 guint64 total_bytes_read
;
96 guint num_read_operations
;
97 guint64 total_bytes_written
;
98 guint num_write_operations
;
102 GSList
*g_disk_data_list
= NULL
;
104 DiskPerformanceData
*disk_performance_data(Tab
*tab
);
105 static void disk_destroy_walk(gpointer data
, gpointer user_data
);
106 static gboolean
parse_event(void *hook_data
, void *call_data
);
107 static gboolean
disk_show(void *hook_data
, void *call_data
);
108 static gboolean
trace_header(void *hook_data
, void *call_data
);
109 static gboolean
disk_update_time_window(void * hook_data
, void * call_data
);
110 static void tree_v_size_allocate_cb (GtkWidget
*widget
, GtkAllocation
*alloc
, gpointer data
);
111 static void tree_v_size_request_cb (GtkWidget
*widget
, GtkRequisition
*requisition
, gpointer data
);
112 static void tree_v_cursor_changed_cb (GtkWidget
*widget
, gpointer data
);
113 static void tree_v_move_cursor_cb (GtkWidget
*widget
, GtkMovementStep arg1
, gint arg2
, gpointer data
);
114 static void tree_selection_changed_cb (GtkTreeSelection
*selection
, gpointer data
);
115 static void request_event( DiskPerformanceData
*disk_performance
);
116 void gui_disperformance_free(DiskPerformanceData
*event_viewer_data
);
117 static void get_event_detail(LttEvent
*e
, LttField
*f
, GString
* s
, lttv_block
* disk_data
);
118 static char * major_minor_to_diskname( lttv_block
* disk_data
);
119 static void sum_data(char* diskname
, guint size
, enum operation_t opt
, GArray
*disk_array
);
121 GtkWidget
*disk_performance(Tab
* tab
){
123 DiskPerformanceData
* disk_data
= disk_performance_data(tab
);
125 return disk_data
->hbox_v
;
131 DiskPerformanceData
*disk_performance_data(Tab
*tab
){
134 GtkTreeViewColumn
*column
;
135 GtkCellRenderer
*renderer
;
136 DiskPerformanceData
* disk_data
= g_new(DiskPerformanceData
,1) ;
138 g_info("enter disk_performance_data \n");
140 disk_data
->tab
= tab
;
141 disk_data
->time_window
= lttvwindow_get_time_window(tab
);
143 disk_data
->disk_array
= g_array_new(FALSE
, FALSE
, sizeof(lttv_total_block
));
145 lttvwindow_register_time_window_notify(tab
,
146 disk_update_time_window
,
149 disk_data
->scroll_win
= gtk_scrolled_window_new (NULL
, NULL
);
150 gtk_widget_show (disk_data
->scroll_win
);
151 gtk_scrolled_window_set_policy(
152 GTK_SCROLLED_WINDOW(disk_data
->scroll_win
),
153 GTK_POLICY_AUTOMATIC
, GTK_POLICY_AUTOMATIC
/*GTK_POLICY_NEVER*/);
156 /* Create a model for storing the data list */
157 disk_data
->store_m
= gtk_list_store_new (
158 N_COLUMNS
, /* Total number of columns */
159 G_TYPE_STRING
, /* Diskname */ // to change from INT to string later
160 G_TYPE_INT64
, /* Bytes read */
161 G_TYPE_INT64
, /* Bytes read/sec */
163 G_TYPE_INT64
, /* bytes written */
164 G_TYPE_INT64
, /* bytes written/sec */
168 disk_data
->tree_v
= gtk_tree_view_new_with_model (GTK_TREE_MODEL (disk_data
->store_m
));
170 g_signal_connect (G_OBJECT (disk_data
->tree_v
), "size-allocate",
171 G_CALLBACK (tree_v_size_allocate_cb
),
173 g_signal_connect (G_OBJECT (disk_data
->tree_v
), "size-request",
174 G_CALLBACK (tree_v_size_request_cb
),
176 g_signal_connect (G_OBJECT (disk_data
->tree_v
), "cursor-changed",
177 G_CALLBACK (tree_v_cursor_changed_cb
),
179 g_signal_connect (G_OBJECT (disk_data
->tree_v
), "move-cursor",
180 G_CALLBACK (tree_v_move_cursor_cb
),
183 g_object_unref (G_OBJECT (disk_data
->store_m
));
185 renderer
= gtk_cell_renderer_text_new ();
186 column
= gtk_tree_view_column_new_with_attributes ("DiskName",
188 "text", DISKNAME_COLUMN
,
190 gtk_tree_view_column_set_alignment (column
, 0.0);
191 gtk_tree_view_column_set_fixed_width (column
, 45);
192 gtk_tree_view_append_column (GTK_TREE_VIEW (disk_data
->tree_v
), column
);
194 renderer
= gtk_cell_renderer_text_new ();
195 column
= gtk_tree_view_column_new_with_attributes ("BytesRead",
197 "text", BYTES_RD_COLUMN
,
199 gtk_tree_view_column_set_alignment (column
, 0.0);
200 gtk_tree_view_column_set_fixed_width (column
, 220);
201 gtk_tree_view_append_column (GTK_TREE_VIEW (disk_data
->tree_v
), column
);
203 renderer
= gtk_cell_renderer_text_new ();
204 column
= gtk_tree_view_column_new_with_attributes ("BytesRead/sec",
206 "text", BYTES_RD_SEC_COLUMN
,
208 gtk_tree_view_column_set_alignment (column
, 1.0);
209 gtk_tree_view_column_set_fixed_width (column
, 220);
210 gtk_tree_view_append_column (GTK_TREE_VIEW (disk_data
->tree_v
), column
);
212 renderer
= gtk_cell_renderer_text_new ();
213 column
= gtk_tree_view_column_new_with_attributes ("NumReadOperations",
215 "text",NUM_RD_COLUMN
,
217 gtk_tree_view_column_set_alignment (column
, 1.0);
218 gtk_tree_view_column_set_fixed_width (column
, 220);
219 gtk_tree_view_append_column (GTK_TREE_VIEW (disk_data
->tree_v
), column
);
221 renderer
= gtk_cell_renderer_text_new ();
222 column
= gtk_tree_view_column_new_with_attributes ("BytesWritten",
224 "text", BYTES_WR_COLUMN
,
226 gtk_tree_view_column_set_alignment (column
, 0.0);
227 gtk_tree_view_column_set_fixed_width (column
, 145);
228 gtk_tree_view_append_column (GTK_TREE_VIEW (disk_data
->tree_v
), column
);
230 renderer
= gtk_cell_renderer_text_new ();
231 column
= gtk_tree_view_column_new_with_attributes ("BytesWritten/sec",
233 "text", BYTES_WR_SEC_COLUMN
,
235 gtk_tree_view_column_set_alignment (column
, 1.0);
236 gtk_tree_view_column_set_fixed_width (column
, 220);
237 gtk_tree_view_append_column (GTK_TREE_VIEW (disk_data
->tree_v
), column
);
239 renderer
= gtk_cell_renderer_text_new ();
240 column
= gtk_tree_view_column_new_with_attributes ("NumWriteOperations",
242 "text",NUM_WR_COLUMN
,
244 gtk_tree_view_column_set_alignment (column
, 0.0);
245 gtk_tree_view_column_set_fixed_width (column
, 145);
246 gtk_tree_view_append_column (GTK_TREE_VIEW (disk_data
->tree_v
), column
);
248 disk_data
->select_c
= gtk_tree_view_get_selection (GTK_TREE_VIEW (disk_data
->tree_v
));
249 gtk_tree_selection_set_mode (disk_data
->select_c
, GTK_SELECTION_SINGLE
);
250 g_signal_connect (G_OBJECT (disk_data
->select_c
), "changed",
251 G_CALLBACK (tree_selection_changed_cb
),
254 gtk_container_add (GTK_CONTAINER (disk_data
->scroll_win
), disk_data
->tree_v
);
256 disk_data
->hbox_v
= gtk_hbox_new(0, 0);
257 gtk_box_pack_start(GTK_BOX(disk_data
->hbox_v
), disk_data
->scroll_win
, TRUE
, TRUE
, 0);
259 gtk_widget_show(disk_data
->hbox_v
);
260 gtk_widget_show(disk_data
->tree_v
);
263 g_disk_data_list
= g_slist_append(g_disk_data_list
, disk_data
);
264 g_object_set_data_full(G_OBJECT(disk_data
->hbox_v
),
267 (GDestroyNotify
)gui_disperformance_free
);
269 request_event(disk_data
);
274 static gboolean
disk_show(void *hook_data
, void *call_data
){
277 lttv_total_block element
;
279 LttTime time_interval
;
280 guint64 time_interval_64
;
281 guint64 temp_variable
;
282 guint64 bytes_read_per_sec
, bytes_written_per_sec
;
283 g_info(" diskperformance: disk_show() \n");
284 DiskPerformanceData
*disk_performance
= (DiskPerformanceData
*)hook_data
;
285 GArray
*disk_array
= disk_performance
->disk_array
;
286 time_interval
= ltt_time_sub(disk_performance
->time_window
.end_time
, disk_performance
->time_window
.start_time
);
288 time_interval_64
= time_interval
.tv_sec
;
289 time_interval_64
*= NANOSECONDS_PER_SECOND
;
290 time_interval_64
+= time_interval
.tv_nsec
;
291 gtk_list_store_clear(disk_performance
->store_m
);
292 for(i
= 0; i
< disk_array
->len
; i
++){
294 element
= g_array_index(disk_array
,lttv_total_block
,i
);
295 temp_variable
= element
.total_bytes_read
* NANOSECONDS_PER_SECOND
;
296 bytes_read_per_sec
= (guint64
) temp_variable
/ time_interval_64
;
298 temp_variable
= element
.total_bytes_written
* NANOSECONDS_PER_SECOND
;
299 bytes_written_per_sec
= (guint64
) temp_variable
/ time_interval_64
;
301 gtk_list_store_append (disk_performance
->store_m
, &iter
);
302 gtk_list_store_set (disk_performance
->store_m
, &iter
,
303 DISKNAME_COLUMN
, element
.diskname
,
304 BYTES_RD_COLUMN
, element
.total_bytes_read
,
305 BYTES_RD_SEC_COLUMN
,bytes_read_per_sec
,
306 NUM_RD_COLUMN
, element
.num_read_operations
,
307 BYTES_WR_COLUMN
, element
.total_bytes_written
,
308 BYTES_WR_SEC_COLUMN
, bytes_written_per_sec
,
309 NUM_WR_COLUMN
, element
.num_write_operations
,
313 if(disk_performance
->disk_array
->len
)
314 g_array_remove_range (disk_performance
->disk_array
,0,disk_performance
->disk_array
->len
);
318 static gboolean
trace_header(void *hook_data
, void *call_data
){
322 void request_event(DiskPerformanceData
*disk_performance
){
324 disk_performance
->event_hooks
= lttv_hooks_new();
325 lttv_hooks_add(disk_performance
->event_hooks
, parse_event
, disk_performance
, LTTV_PRIO_DEFAULT
);
327 disk_performance
->hooks_trace_after
= lttv_hooks_new();
328 lttv_hooks_add(disk_performance
->hooks_trace_after
, disk_show
, disk_performance
, LTTV_PRIO_DEFAULT
);
330 disk_performance
->hooks_trace_before
= lttv_hooks_new();
331 lttv_hooks_add(disk_performance
->hooks_trace_before
, trace_header
, disk_performance
, LTTV_PRIO_DEFAULT
);
333 EventsRequest
*events_request
= g_new(EventsRequest
, 1);
334 events_request
->owner
= disk_performance
;
335 events_request
->viewer_data
= disk_performance
;
336 events_request
->servicing
= FALSE
;
337 events_request
->start_time
= disk_performance
->time_window
.start_time
;
338 events_request
->start_position
= NULL
;
339 events_request
->stop_flag
= FALSE
;
340 events_request
->end_time
= disk_performance
->time_window
.end_time
;
341 events_request
->num_events
= G_MAXUINT
;
342 events_request
->end_position
= NULL
;
343 events_request
->trace
= 0;
344 events_request
->hooks
= NULL
;
345 events_request
->before_chunk_traceset
= NULL
;
346 events_request
->before_chunk_trace
= disk_performance
->hooks_trace_before
;
347 events_request
->before_chunk_tracefile
= NULL
;
348 events_request
->event
= disk_performance
->event_hooks
;
349 events_request
->event_by_id
= NULL
;
350 events_request
->after_chunk_tracefile
= NULL
;
351 events_request
->after_chunk_trace
= NULL
;
352 events_request
->after_chunk_traceset
= NULL
;
353 events_request
->before_request
= NULL
;
354 events_request
->after_request
= disk_performance
->hooks_trace_after
;
356 lttvwindow_events_request(disk_performance
->tab
, events_request
);
360 static gboolean
disk_update_time_window(void * hook_data
, void * call_data
){
362 DiskPerformanceData
*disk_performance
= (DiskPerformanceData
*) hook_data
;
363 const TimeWindowNotifyData
*time_window_nofify_data
= ((const TimeWindowNotifyData
*)call_data
);
364 disk_performance
->time_window
= *time_window_nofify_data
->new_time_window
;
366 printf("end_time: %ld.%ld\n", disk_performance->time_window.end_time.tv_sec,disk_performance->time_window.end_time.tv_nsec);
368 Tab
*tab
= disk_performance
->tab
;
369 lttvwindow_events_request_remove_all(tab
, disk_performance
);
370 request_event( disk_performance
);
376 void tree_v_size_allocate_cb (GtkWidget
*widget
, GtkAllocation
*alloc
, gpointer data
){
377 g_info("enter tree_v_size_allocate_cb\n");
380 void tree_v_size_request_cb (GtkWidget
*widget
, GtkRequisition
*requisition
, gpointer data
){
384 static void tree_v_cursor_changed_cb (GtkWidget
*widget
, gpointer data
){
388 static void tree_v_move_cursor_cb (GtkWidget
*widget
, GtkMovementStep arg1
, gint arg2
, gpointer data
){
390 static void tree_selection_changed_cb (GtkTreeSelection
*selection
, gpointer data
){
393 void gui_disperformance_free(DiskPerformanceData
*eventdata
){
394 Tab
*tab
= eventdata
->tab
;
395 g_info("disperformance.c : gui_disperformance_free, %p", eventdata
);
396 g_info("%p, %p", eventdata
, tab
);
399 g_array_free (eventdata
->disk_array
, TRUE
);
401 lttvwindow_unregister_time_window_notify(tab
,
402 disk_update_time_window
,
405 lttvwindow_events_request_remove_all(eventdata
->tab
,
407 g_disk_data_list
= g_slist_remove(g_disk_data_list
, eventdata
);
410 g_info("disperformance.c : gui_disperformance_free end, %p", eventdata
);
414 static char * major_minor_to_diskname( lttv_block
* disk_data
){
415 if (disk_data
->major_number
== 3 && disk_data
->minor_number
== 0)
417 if (disk_data
->major_number
== 4 && disk_data
->minor_number
== 0)
422 static void sum_data(char* diskname
, guint size
, enum operation_t operation
, GArray
*disk_array
){
424 lttv_total_block data
;
425 lttv_total_block
*element
;
427 gboolean notFound
= FALSE
;
429 memset ((void*)&data
, 0,sizeof(lttv_total_block
));
431 if(disk_array
->len
== NO_ITEMS
){
432 strcpy(data
.diskname
, diskname
);
433 if(operation
== LTTV_READ_OPERATION
){
434 data
.total_bytes_read
= size
;
435 data
.num_read_operations
++;
438 data
.total_bytes_written
= size
;
439 data
.num_write_operations
++;
441 g_array_append_val (disk_array
, data
);
444 for(i
= 0; i
< disk_array
->len
; i
++){
445 element
= &g_array_index(disk_array
,lttv_total_block
,i
);
446 if(strcmp(element
->diskname
,diskname
) == 0){
447 if(operation
== LTTV_READ_OPERATION
){
448 element
->num_read_operations
++;
449 element
->total_bytes_read
+= size
;
452 element
->num_write_operations
++;
453 element
->total_bytes_written
+= size
;
459 strcpy(data
.diskname
, diskname
);
460 if(operation
== LTTV_READ_OPERATION
){
461 data
.total_bytes_read
= size
;
462 data
.num_read_operations
++;
465 data
.total_bytes_written
= size
;
466 data
.num_write_operations
++;
468 g_array_append_val (disk_array
, data
);
473 static void get_event_detail(LttEvent
*e
, LttField
*f
, GString
* s
, lttv_block
* disk_data
){
480 type
= ltt_field_type(f
);
481 switch(ltt_type_class(type
)) {
483 g_string_append_printf(s
, " %ld", ltt_event_get_long_int(e
,f
));
487 g_string_append_printf(s
, " %lu", ltt_event_get_long_unsigned(e
,f
));
491 g_string_append_printf(s
, " %g", ltt_event_get_double(e
,f
));
495 g_string_append_printf(s
, " \"%s\"", ltt_event_get_string(e
,f
));
499 g_string_append_printf(s
, " %s", ltt_enum_string_get(type
,
500 ltt_event_get_unsigned(e
,f
)-1));
505 g_string_append_printf(s
, " {");
506 nb
= ltt_event_field_element_number(e
,f
);
507 element
= ltt_field_element(f
);
508 for(i
= 0 ; i
< nb
; i
++) {
509 ltt_event_field_element_select(e
,f
,i
);
510 get_event_detail(e
, element
, s
, disk_data
);
512 g_string_append_printf(s
, " }");
516 g_string_append_printf(s
, " {");
517 nb
= ltt_type_member_number(type
);
518 for(i
= 0 ; i
< nb
; i
++) {
519 element
= ltt_field_member(f
,i
);
520 ltt_type_member_type(type
, i
, &name
);
521 g_string_append_printf(s
, " %s = ", name
);
523 disk_data
->major_number
= ltt_event_get_long_unsigned(e
, element
);
525 disk_data
->minor_number
= ltt_event_get_long_unsigned(e
, element
);
527 disk_data
->size
= ltt_event_get_long_unsigned(e
, element
);
529 g_string_append_printf(s
, " }");
533 g_string_append_printf(s
, " {");
534 nb
= ltt_type_member_number(type
);
535 for(i
= 0 ; i
< nb
; i
++) {
536 element
= ltt_field_member(f
,i
);
537 ltt_type_member_type(type
, i
, &name
);
538 g_string_append_printf(s
, " %s = ", name
);
539 get_event_detail(e
, element
, s
, disk_data
);
541 g_string_append_printf(s
, " }");
549 gboolean
parse_event(void *hook_data
, void *call_data
){
551 static LttTime time_entry
, previous_time
, event_time
;
554 LttEventType
*event_type
;
557 lttv_block block_read
, block_write
;
560 gboolean notFound
= FALSE
;
561 DiskPerformanceData
* disk_performance
= (DiskPerformanceData
*)hook_data
;
562 GArray
*disk_array
= disk_performance
->disk_array
; // pho
563 LttvTracefileContext
*tfc
= (LttvTracefileContext
*)call_data
;
564 LttvTracefileState
*tfs
= (LttvTracefileState
*)call_data
;
567 e
= ltt_tracefile_get_event(tfc
->tf
);
568 previous_time
= event_time
;
569 field
= ltt_event_field(e
);
570 event_time
= ltt_event_time(e
);
571 event_type
= ltt_event_eventtype(e
);
572 cpu_id
= ltt_event_cpu_id(e
);
573 GString
* detail_event
= g_string_new("");
575 if ((ltt_time_compare(event_time
,disk_performance
->time_window
.start_time
) == TRUE
) &&
576 (ltt_time_compare(disk_performance
->time_window
.end_time
,event_time
) == TRUE
)){
577 if (strcmp( g_quark_to_string(ltt_eventtype_name(event_type
)),"block_read") == 0) {
578 get_event_detail(e
, field
, detail_event
, &block_read
);
579 diskname
= major_minor_to_diskname(&block_read
);
580 sum_data(diskname
, block_read
.size
,LTTV_READ_OPERATION
, disk_array
);
583 if (strcmp( g_quark_to_string(ltt_eventtype_name(event_type
)),"block_write") == 0) {
584 get_event_detail(e
, field
, detail_event
, &block_write
);
585 diskname
= major_minor_to_diskname(&block_write
);
586 sum_data(diskname
, block_write
.size
,LTTV_WRITE_OPERATION
, disk_array
);
590 g_string_free(detail_event
, TRUE
);
595 void disk_destructor_full(DiskPerformanceData
*disk_data
)
598 if(GTK_IS_WIDGET(disk_data
->hbox_v
))
599 gtk_widget_destroy(disk_data
->hbox_v
);
603 static void disk_destroy_walk(gpointer data
, gpointer user_data
)
605 g_info("Walk destroy GUI disk performance Viewer");
606 disk_destructor_full((DiskPerformanceData
*)data
);
612 g_info("Init diskPerformance.c");
614 lttvwindow_register_constructor("diskperformance",
616 "Insert Disk Performance",
617 hDiskPerformanceInsert_xpm
,
618 "Insert Disk Performance",
624 static void destroy()
626 g_info("Destroy diskPerformance");
627 g_slist_foreach(g_disk_data_list
, disk_destroy_walk
, NULL
);
628 g_slist_free(g_disk_data_list
);
630 lttvwindow_unregister_constructor(disk_performance
);
635 LTTV_MODULE("diskperformance", "disk info view", \
636 "Produce disk I/O performance", \
637 init
, destroy
, "lttvwindow")