diff options
| author | Steven Rostedt <srostedt@redhat.com> | 2009-10-12 12:39:27 -0400 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2009-12-17 21:43:46 -0500 |
| commit | ab91bd24b899d73d7552c5d1947656a3b446660e (patch) | |
| tree | 7368767744c5af3d97c5f98e6d19b2ff2021feac | |
| parent | bed6e5c19bf745300dc045aa2242790cd6cc062b (diff) | |
Add GTK viewer for reading trace data
This is the start of adding a GTK front end to read the trace data.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
| -rw-r--r-- | Makefile | 18 | ||||
| -rw-r--r-- | trace-cmd.c | 3 | ||||
| -rw-r--r-- | trace-local.h | 2 | ||||
| -rw-r--r-- | trace-view.c | 366 |
4 files changed, 385 insertions, 4 deletions
| @@ -1,11 +1,17 @@ | |||
| 1 | CC = gcc | 1 | CC = gcc |
| 2 | AR = ar | 2 | AR = ar |
| 3 | EXT = -std=gnu99 | 3 | EXT = -std=gnu99 |
| 4 | CFLAGS = -g -Wall # -O2 | ||
| 5 | INCLUDES = -I. -I/usr/local/include | 4 | INCLUDES = -I. -I/usr/local/include |
| 6 | 5 | ||
| 7 | LIBS = -L. -ltracecmd -ldl | 6 | LIBS = -L. -ltracecmd -ldl |
| 8 | 7 | ||
| 8 | PACKAGES= gtk+-2.0 libgnome-2.0 libgnomecanvas-2.0 libgnomeui-2.0 libxml-2.0 | ||
| 9 | |||
| 10 | CONFIG_FLAGS = $(shell pkg-config --cflags $(PACKAGES)) | ||
| 11 | CONFIG_LIBS = $(shell pkg-config --libs $(PACKAGES)) | ||
| 12 | |||
| 13 | CFLAGS = -g -Wall $(CONFIG_FLAGS) | ||
| 14 | |||
| 9 | %.o: %.c | 15 | %.o: %.c |
| 10 | $(CC) -c $(CFLAGS) $(EXT) $(INCLUDES) $< -o $@ | 16 | $(CC) -c $(CFLAGS) $(EXT) $(INCLUDES) $< -o $@ |
| 11 | 17 | ||
| @@ -24,8 +30,14 @@ trace-util.o:: $(HEADERS) | |||
| 24 | trace-ftrace.o:: $(HEADERS) | 30 | trace-ftrace.o:: $(HEADERS) |
| 25 | trace-input.o:: $(HEADERS) | 31 | trace-input.o:: $(HEADERS) |
| 26 | 32 | ||
| 27 | trace-cmd:: trace-cmd.o trace-read.o | 33 | trace-cmd:: trace-cmd.o trace-read.o trace-view.o |
| 28 | $(CC) $^ $(LIBS) -rdynamic -o $@ | 34 | $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS) |
| 35 | |||
| 36 | .PHONY: view_depends | ||
| 37 | view_depends: | ||
| 38 | @pkg-config --cflags $(PACKAGES) | ||
| 39 | |||
| 40 | trace-view.o:: parse-events.h view_depends | ||
| 29 | 41 | ||
| 30 | parse-events.o: parse-events.c parse-events.h | 42 | parse-events.o: parse-events.c parse-events.h |
| 31 | $(CC) -c $(CFLAGS) $(EXT) $(INCLUDES) -fPIC $< -o $@ | 43 | $(CC) -c $(CFLAGS) $(EXT) $(INCLUDES) -fPIC $< -o $@ |
diff --git a/trace-cmd.c b/trace-cmd.c index ac14a61..cfd8ba5 100644 --- a/trace-cmd.c +++ b/trace-cmd.c | |||
| @@ -720,6 +720,9 @@ int main (int argc, char **argv) | |||
| 720 | if (strcmp(argv[1], "report") == 0) { | 720 | if (strcmp(argv[1], "report") == 0) { |
| 721 | trace_report(argc, argv); | 721 | trace_report(argc, argv); |
| 722 | exit(0); | 722 | exit(0); |
| 723 | } else if (strcmp(argv[1], "view") == 0) { | ||
| 724 | trace_view(argc, argv); | ||
| 725 | exit(0); | ||
| 723 | } else if ((record = (strcmp(argv[1], "record") == 0)) || | 726 | } else if ((record = (strcmp(argv[1], "record") == 0)) || |
| 724 | (strcmp(argv[1], "start") == 0)) { | 727 | (strcmp(argv[1], "start") == 0)) { |
| 725 | 728 | ||
diff --git a/trace-local.h b/trace-local.h index 2fab032..4b3deff 100644 --- a/trace-local.h +++ b/trace-local.h | |||
| @@ -11,6 +11,6 @@ struct tracecmd_input *read_trace_header(void); | |||
| 11 | int read_trace_files(void); | 11 | int read_trace_files(void); |
| 12 | 12 | ||
| 13 | void trace_report(int argc, char **argv); | 13 | void trace_report(int argc, char **argv); |
| 14 | 14 | void trace_view(int argc, char **argv); | |
| 15 | 15 | ||
| 16 | #endif /* __TRACE_LOCAL_H */ | 16 | #endif /* __TRACE_LOCAL_H */ |
diff --git a/trace-view.c b/trace-view.c new file mode 100644 index 0000000..744f9a2 --- /dev/null +++ b/trace-view.c | |||
| @@ -0,0 +1,366 @@ | |||
| 1 | /* | ||
| 2 | * Copyright (C) 2009, Steven Rostedt <srostedt@redhat.com> | ||
| 3 | * | ||
| 4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 5 | * | ||
| 6 | * This program is free software; you can redistribute it and/or modify | ||
| 7 | * it under the terms of the GNU General Public License as published by | ||
| 8 | * the Free Software Foundation; version 2 of the License (not later!) | ||
| 9 | * | ||
| 10 | * This program is distributed in the hope that it will be useful, | ||
| 11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | * GNU General Public License for more details. | ||
| 14 | * | ||
| 15 | * You should have received a copy of the GNU General Public License | ||
| 16 | * along with this program; if not, write to the Free Software | ||
| 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 18 | * | ||
| 19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 20 | */ | ||
| 21 | #include <stdio.h> | ||
| 22 | #include <string.h> | ||
| 23 | #include <stdarg.h> | ||
| 24 | #include <gnome.h> | ||
| 25 | |||
| 26 | #include "trace-cmd.h" | ||
| 27 | #include "trace-local.h" | ||
| 28 | |||
| 29 | #define version "0.1.1" | ||
| 30 | |||
| 31 | enum { | ||
| 32 | COL_CPU, | ||
| 33 | COL_TS, | ||
| 34 | COL_COMM, | ||
| 35 | COL_PID, | ||
| 36 | COL_LAT, | ||
| 37 | COL_EVENT, | ||
| 38 | COL_INFO, | ||
| 39 | NUM_COLS | ||
| 40 | }; | ||
| 41 | |||
| 42 | struct tracecmd_input *trace_handle; | ||
| 43 | |||
| 44 | GtkWidget *trace_tree; | ||
| 45 | |||
| 46 | static void add_data_to_model(GtkTreeModel *model, | ||
| 47 | struct tracecmd_input *handle, | ||
| 48 | int cpu) | ||
| 49 | { | ||
| 50 | struct pevent *pevent; | ||
| 51 | GtkTreeIter iter; | ||
| 52 | struct record *record; | ||
| 53 | struct event *event; | ||
| 54 | struct trace_seq s; | ||
| 55 | struct trace_seq l; | ||
| 56 | unsigned long secs; | ||
| 57 | unsigned long usecs; | ||
| 58 | unsigned long nsecs; | ||
| 59 | const char *comm; | ||
| 60 | int pid, type; | ||
| 61 | char *print; | ||
| 62 | char buf[100]; | ||
| 63 | |||
| 64 | pevent = tracecmd_get_pevent(handle); | ||
| 65 | |||
| 66 | record = tracecmd_read_data(handle, cpu); | ||
| 67 | nsecs = record->ts; | ||
| 68 | |||
| 69 | type = pevent_data_type(pevent, record->data); | ||
| 70 | event = pevent_data_event_from_type(pevent, type); | ||
| 71 | if (!event) | ||
| 72 | return; | ||
| 73 | |||
| 74 | pid = pevent_data_pid(pevent, record->data); | ||
| 75 | comm = pevent_data_comm_from_pid(pevent, pid); | ||
| 76 | |||
| 77 | trace_seq_init(&l); | ||
| 78 | pevent_data_lat_fmt(pevent, &l, record->data, record->size); | ||
| 79 | l.buffer[l.len] = 0; | ||
| 80 | |||
| 81 | trace_seq_init(&s); | ||
| 82 | pevent_event_info(&s, event, cpu, record->data, record->size, nsecs); | ||
| 83 | if (s.full) { | ||
| 84 | print = malloc(s.len + 1); | ||
| 85 | memcpy(print, s.buffer, s.len); | ||
| 86 | } else | ||
| 87 | print = s.buffer; | ||
| 88 | print[s.len] = 0; | ||
| 89 | |||
| 90 | secs = nsecs / NSECS_PER_SEC; | ||
| 91 | usecs = nsecs - secs * NSECS_PER_SEC; | ||
| 92 | usecs = usecs / NSECS_PER_USEC; | ||
| 93 | |||
| 94 | sprintf(buf, "%5lu.%06lu", secs, usecs); | ||
| 95 | |||
| 96 | gtk_list_store_append(GTK_LIST_STORE(model), &iter); | ||
| 97 | gtk_list_store_set(GTK_LIST_STORE(model), &iter, | ||
| 98 | COL_CPU, cpu, | ||
| 99 | COL_TS, buf, | ||
| 100 | COL_COMM, comm, | ||
| 101 | COL_PID, pid, | ||
| 102 | COL_LAT, l.buffer, | ||
| 103 | COL_EVENT, event->name, | ||
| 104 | COL_INFO, print, | ||
| 105 | -1); | ||
| 106 | if (s.full) | ||
| 107 | free(print); | ||
| 108 | |||
| 109 | free(record); | ||
| 110 | } | ||
| 111 | |||
| 112 | static void trace_load_tree(struct tracecmd_input *handle, GtkWidget *trace_tree) | ||
| 113 | { | ||
| 114 | GtkTreeModel *model; | ||
| 115 | unsigned long long ts; | ||
| 116 | struct record *data; | ||
| 117 | int cpus; | ||
| 118 | int next; | ||
| 119 | int cpu; | ||
| 120 | int filter_cpu = -1; /* TODO */ | ||
| 121 | |||
| 122 | cpus = tracecmd_cpus(handle); | ||
| 123 | |||
| 124 | model = gtk_tree_view_get_model(GTK_TREE_VIEW(trace_tree)); | ||
| 125 | g_object_ref(model); | ||
| 126 | gtk_tree_view_set_model(GTK_TREE_VIEW(trace_tree), NULL); | ||
| 127 | |||
| 128 | do { | ||
| 129 | next = -1; | ||
| 130 | ts = 0; | ||
| 131 | if (filter_cpu >= 0) { | ||
| 132 | cpu = filter_cpu; | ||
| 133 | data = tracecmd_peek_data(handle, cpu); | ||
| 134 | if (data) | ||
| 135 | next = cpu; | ||
| 136 | } else { | ||
| 137 | for (cpu = 0; cpu < cpus; cpu++) { | ||
| 138 | data = tracecmd_peek_data(handle, cpu); | ||
| 139 | if (data && (!ts || data->ts < ts)) { | ||
| 140 | ts = data->ts; | ||
| 141 | next = cpu; | ||
| 142 | } | ||
| 143 | } | ||
| 144 | } | ||
| 145 | if (next >= 0) | ||
| 146 | add_data_to_model(model, handle, next); | ||
| 147 | |||
| 148 | } while (next >= 0); | ||
| 149 | |||
| 150 | gtk_tree_view_set_model(GTK_TREE_VIEW(trace_tree), model); | ||
| 151 | g_object_unref(model); | ||
| 152 | } | ||
| 153 | |||
| 154 | /* Callback for the clicked signal of the Exit button */ | ||
| 155 | static void | ||
| 156 | exit_clicked (GtkWidget *widget, gpointer data) | ||
| 157 | { | ||
| 158 | gtk_widget_destroy (GTK_WIDGET (data)); /* the user data points to the main window */ | ||
| 159 | gtk_main_quit (); | ||
| 160 | } | ||
| 161 | |||
| 162 | /* Callback for the delete_event signal of the main application window */ | ||
| 163 | static gint | ||
| 164 | delete_event (GtkWidget *widget, GdkEvent *event, gpointer data) | ||
| 165 | { | ||
| 166 | gtk_widget_destroy (widget); /* destroy the main window */ | ||
| 167 | gtk_main_quit (); | ||
| 168 | return TRUE; | ||
| 169 | } | ||
| 170 | |||
| 171 | static GtkTreeModel * | ||
| 172 | create_trace_view_model(void) | ||
| 173 | { | ||
| 174 | GtkListStore *store; | ||
| 175 | |||
| 176 | store = gtk_list_store_new(NUM_COLS, | ||
| 177 | G_TYPE_UINT, | ||
| 178 | G_TYPE_STRING, | ||
| 179 | G_TYPE_STRING, | ||
| 180 | G_TYPE_UINT, | ||
| 181 | G_TYPE_STRING, | ||
| 182 | G_TYPE_STRING, | ||
| 183 | G_TYPE_STRING); | ||
| 184 | |||
| 185 | return GTK_TREE_MODEL(store); | ||
| 186 | } | ||
| 187 | |||
| 188 | static GtkWidget * | ||
| 189 | create_trace_view(void) | ||
| 190 | { | ||
| 191 | GtkTreeViewColumn *col; | ||
| 192 | GtkCellRenderer *renderer; | ||
| 193 | GtkWidget *view; | ||
| 194 | GtkTreeModel *model; | ||
| 195 | |||
| 196 | view = gtk_tree_view_new(); | ||
| 197 | |||
| 198 | /* --- CPU column --- */ | ||
| 199 | |||
| 200 | col = gtk_tree_view_column_new(); | ||
| 201 | |||
| 202 | renderer = gtk_cell_renderer_text_new(); | ||
| 203 | |||
| 204 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | ||
| 205 | -1, | ||
| 206 | "CPU", | ||
| 207 | renderer, | ||
| 208 | "text", COL_CPU, | ||
| 209 | NULL); | ||
| 210 | |||
| 211 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | ||
| 212 | -1, | ||
| 213 | "Time Stamp", | ||
| 214 | renderer, | ||
| 215 | "text", COL_TS, | ||
| 216 | NULL); | ||
| 217 | |||
| 218 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | ||
| 219 | -1, | ||
| 220 | "Task", | ||
| 221 | renderer, | ||
| 222 | "text", COL_COMM, | ||
| 223 | NULL); | ||
| 224 | |||
| 225 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | ||
| 226 | -1, | ||
| 227 | "PID", | ||
| 228 | renderer, | ||
| 229 | "text", COL_PID, | ||
| 230 | NULL); | ||
| 231 | |||
| 232 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | ||
| 233 | -1, | ||
| 234 | "Latency", | ||
| 235 | renderer, | ||
| 236 | "text", COL_LAT, | ||
| 237 | NULL); | ||
| 238 | |||
| 239 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | ||
| 240 | -1, | ||
| 241 | "Event", | ||
| 242 | renderer, | ||
| 243 | "text", COL_EVENT, | ||
| 244 | NULL); | ||
| 245 | |||
| 246 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | ||
| 247 | -1, | ||
| 248 | "Info", | ||
| 249 | renderer, | ||
| 250 | "text", COL_INFO, | ||
| 251 | NULL); | ||
| 252 | |||
| 253 | model = create_trace_view_model(); | ||
| 254 | |||
| 255 | gtk_tree_view_set_model(GTK_TREE_VIEW(view), model); | ||
| 256 | |||
| 257 | g_object_unref(model); /* destroy model automatically with view */ | ||
| 258 | |||
| 259 | return view; | ||
| 260 | } | ||
| 261 | |||
| 262 | void trace_view(int argc, char **argv) | ||
| 263 | { | ||
| 264 | struct tracecmd_input *handle; | ||
| 265 | GtkWidget *window; | ||
| 266 | GtkWidget *vbox; | ||
| 267 | GtkWidget *hbox; | ||
| 268 | GtkWidget *menu_bar; | ||
| 269 | GtkWidget *menu; | ||
| 270 | GtkWidget *menu_item; | ||
| 271 | GtkWidget *quit_item; | ||
| 272 | GtkWidget *scrollwin; | ||
| 273 | |||
| 274 | handle = read_trace_header(); | ||
| 275 | if (!handle) | ||
| 276 | die("error reading header"); | ||
| 277 | |||
| 278 | if (tracecmd_read_headers(handle) < 0) | ||
| 279 | return; | ||
| 280 | |||
| 281 | if (tracecmd_init_data(handle) < 0) | ||
| 282 | die("failed to init data"); | ||
| 283 | |||
| 284 | trace_handle = handle; | ||
| 285 | |||
| 286 | gnome_init("trace-cmd", version, argc, argv); | ||
| 287 | |||
| 288 | /* --- Main window --- */ | ||
| 289 | |||
| 290 | window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | ||
| 291 | |||
| 292 | /* --- Top Level Vbox --- */ | ||
| 293 | |||
| 294 | vbox = gtk_vbox_new(FALSE, 0); | ||
| 295 | gtk_container_add(GTK_CONTAINER (window), vbox); | ||
| 296 | gtk_widget_show(vbox); | ||
| 297 | |||
| 298 | /* --- Menu Bar --- */ | ||
| 299 | |||
| 300 | menu_bar = gtk_menu_bar_new(); | ||
| 301 | gtk_box_pack_start(GTK_BOX (vbox), menu_bar, FALSE, FALSE, 0); | ||
| 302 | gtk_widget_show(menu_bar); | ||
| 303 | |||
| 304 | /* --- File Option --- */ | ||
| 305 | |||
| 306 | menu_item = gtk_menu_item_new_with_label("File"); | ||
| 307 | gtk_widget_show(menu_item); | ||
| 308 | |||
| 309 | gtk_menu_bar_append(GTK_MENU_BAR (menu_bar), menu_item); | ||
| 310 | |||
| 311 | menu = gtk_menu_new(); /* Don't need to show menus */ | ||
| 312 | |||
| 313 | |||
| 314 | /* --- Quit Option --- */ | ||
| 315 | |||
| 316 | quit_item = gtk_menu_item_new_with_label("Quit"); | ||
| 317 | |||
| 318 | /* Add them to the menu */ | ||
| 319 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), quit_item); | ||
| 320 | |||
| 321 | /* We can attach the Quit menu item to our exit function */ | ||
| 322 | g_signal_connect_swapped (G_OBJECT (quit_item), "activate", | ||
| 323 | G_CALLBACK (exit_clicked), | ||
| 324 | (gpointer) window); | ||
| 325 | |||
| 326 | /* We do need to show menu items */ | ||
| 327 | gtk_widget_show(quit_item); | ||
| 328 | |||
| 329 | |||
| 330 | gtk_menu_item_set_submenu(GTK_MENU_ITEM (menu_item), menu); | ||
| 331 | /* --- Top Level Hbox --- */ | ||
| 332 | |||
| 333 | hbox = gtk_hbox_new(FALSE, 0); | ||
| 334 | gtk_box_pack_start(GTK_BOX(vbox), hbox, TRUE, TRUE, 0); | ||
| 335 | gtk_widget_show(hbox); | ||
| 336 | |||
| 337 | /* --- Scroll Window --- */ | ||
| 338 | scrollwin = gtk_scrolled_window_new(NULL, NULL); | ||
| 339 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrollwin), | ||
| 340 | GTK_POLICY_AUTOMATIC, | ||
| 341 | GTK_POLICY_AUTOMATIC); | ||
| 342 | gtk_box_pack_start(GTK_BOX (hbox), scrollwin, TRUE, TRUE, 0); | ||
| 343 | gtk_widget_show(scrollwin); | ||
| 344 | |||
| 345 | /* --- Trace Tree --- */ | ||
| 346 | |||
| 347 | trace_tree = create_trace_view(); | ||
| 348 | gtk_scrolled_window_add_with_viewport(GTK_SCROLLED_WINDOW(scrollwin), | ||
| 349 | trace_tree); | ||
| 350 | gtk_widget_show(trace_tree); | ||
| 351 | |||
| 352 | trace_load_tree(handle, trace_tree); | ||
| 353 | |||
| 354 | /********************************************** | ||
| 355 | * Main Window | ||
| 356 | **********************************************/ | ||
| 357 | |||
| 358 | /* Connect to the delete_event signal and Run the application */ | ||
| 359 | |||
| 360 | gtk_signal_connect (GTK_OBJECT (window), "delete_event", | ||
| 361 | (GtkSignalFunc) delete_event, | ||
| 362 | NULL); | ||
| 363 | |||
| 364 | gtk_widget_show (window); | ||
| 365 | gtk_main (); | ||
| 366 | } | ||
