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 | } | ||