aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2010-01-04 10:01:56 -0500
committerSteven Rostedt <rostedt@goodmis.org>2010-01-04 10:01:56 -0500
commit752cec97e9546b0477e6f4d8001b0923fdc89e9f (patch)
tree08f4cb697a93f06c094d3bf75cdb0df65af548b1
parent53b43d308e644a77829977cbd2bd123a6bc64260 (diff)
kernel-shark: Allow filtering of graph from tree view
Let the tree view pop up menu filter the graph as well. This makes finding tasks to filter on easier, as it is easier to search for a task from the tree view than with the graph. Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--Makefile5
-rw-r--r--kernel-shark.c155
-rw-r--r--kernel-shark.h1
-rw-r--r--trace-graph.c87
-rw-r--r--trace-graph.h12
-rw-r--r--trace-hash.c31
-rw-r--r--trace-hash.h8
-rw-r--r--trace-view-store.c11
-rw-r--r--trace-view-store.h2
9 files changed, 257 insertions, 55 deletions
diff --git a/Makefile b/Makefile
index e879e90..de83e44 100644
--- a/Makefile
+++ b/Makefile
@@ -51,10 +51,11 @@ trace-cmd:: trace-cmd.o trace-read.o
51trace-view:: trace-view-main.o $(TRACE_VIEW_OBJS) 51trace-view:: trace-view-main.o $(TRACE_VIEW_OBJS)
52 $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS) 52 $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS)
53 53
54trace-graph:: trace-graph-main.o trace-graph.o trace-compat.o 54trace-graph:: trace-graph-main.o trace-graph.o trace-compat.o trace-hash.o
55 $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS) 55 $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS)
56 56
57kernelshark:: kernel-shark.o trace-compat.o $(TRACE_VIEW_OBJS) trace-graph.o 57kernelshark:: kernel-shark.o trace-compat.o $(TRACE_VIEW_OBJS) trace-graph.o \
58 trace-hash.o
58 $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS) 59 $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS)
59 60
60.PHONY: gtk_depends 61.PHONY: gtk_depends
diff --git a/kernel-shark.c b/kernel-shark.c
index 6e1c206..6e92730 100644
--- a/kernel-shark.c
+++ b/kernel-shark.c
@@ -155,6 +155,158 @@ static void row_double_clicked(GtkTreeView *treeview,
155 trace_graph_select_by_time(info->ginfo, time); 155 trace_graph_select_by_time(info->ginfo, time);
156} 156}
157 157
158static void
159filter_enable_clicked (gpointer data)
160{
161 struct shark_info *info = data;
162
163 trace_graph_filter_toggle(info->ginfo);
164}
165
166static void
167filter_add_task_clicked (gpointer data)
168{
169 struct shark_info *info = data;
170
171 trace_graph_filter_add_remove_task(info->ginfo, info->selected_task);
172}
173
174static void
175filter_clear_tasks_clicked (gpointer data)
176{
177 struct shark_info *info = data;
178
179 trace_graph_clear_tasks(info->ginfo);
180}
181
182static gboolean
183do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data)
184{
185 struct shark_info *info = data;
186 struct graph_info *ginfo = info->ginfo;
187 static GtkWidget *menu;
188 static GtkWidget *menu_filter_enable;
189 static GtkWidget *menu_filter_add_task;
190 static GtkWidget *menu_filter_clear_tasks;
191 struct record *record;
192 TraceViewStore *store;
193 GtkTreeSelection *selection;
194 GtkTreeModel *model;
195 GtkTreePath *path;
196 const char *comm;
197 gchar *text;
198 gint pid;
199 gint len;
200 GList *glist;
201 gchar *spath;
202 guint64 offset;
203 gint row;
204 gint cpu;
205
206 if (!menu) {
207 menu = gtk_menu_new();
208 menu_filter_enable = gtk_menu_item_new_with_label("Enable Filter");
209 gtk_widget_show(menu_filter_enable);
210 gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_enable);
211
212 g_signal_connect_swapped (G_OBJECT (menu_filter_enable), "activate",
213 G_CALLBACK (filter_enable_clicked),
214 data);
215
216 menu_filter_add_task = gtk_menu_item_new_with_label("Add Task");
217 gtk_widget_show(menu_filter_add_task);
218 gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_add_task);
219
220 g_signal_connect_swapped (G_OBJECT (menu_filter_add_task), "activate",
221 G_CALLBACK (filter_add_task_clicked),
222 data);
223
224 menu_filter_clear_tasks = gtk_menu_item_new_with_label("Clear Task Filter");
225 gtk_widget_show(menu_filter_clear_tasks);
226 gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_clear_tasks);
227
228 g_signal_connect_swapped (G_OBJECT (menu_filter_clear_tasks), "activate",
229 G_CALLBACK (filter_clear_tasks_clicked),
230 data);
231
232 }
233
234 selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(info->treeview));
235 glist = gtk_tree_selection_get_selected_rows(GTK_TREE_SELECTION(selection), NULL);
236 if (glist) {
237 path = glist->data;
238 g_list_free(glist);
239 spath = gtk_tree_path_to_string(path);
240 gtk_tree_path_free(path);
241 row = atoi(spath);
242 g_free(spath);
243
244 model = gtk_tree_view_get_model(GTK_TREE_VIEW(info->treeview));
245 store = TRACE_VIEW_STORE(model);
246 offset = trace_view_store_get_offset_from_row(store, row);
247
248 record = tracecmd_read_at(info->handle, offset, &cpu);
249
250 if (record) {
251 pid = pevent_data_pid(ginfo->pevent, record);
252 comm = pevent_data_comm_from_pid(ginfo->pevent, pid);
253
254 len = strlen(comm) + 50;
255
256 text = g_malloc(len);
257 g_assert(text);
258
259 if (trace_graph_filter_task_find_pid(ginfo, pid))
260 snprintf(text, len, "Remove %s-%d to filter", comm, pid);
261 else
262 snprintf(text, len, "Add %s-%d to filter", comm, pid);
263
264 ginfo->filter_task_selected = pid;
265
266 gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_add_task),
267 text);
268 g_free(text);
269
270 info->selected_task = pid;
271
272 gtk_widget_show(menu_filter_add_task);
273 free_record(record);
274 }
275 } else
276 gtk_widget_hide(menu_filter_add_task);
277
278 if (ginfo->filter_enabled)
279 gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_enable),
280 "Disable Filter");
281 else
282 gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_enable),
283 "Enable Filter");
284
285 if (ginfo->filter_available)
286 gtk_widget_set_sensitive(menu_filter_enable, TRUE);
287 else
288 gtk_widget_set_sensitive(menu_filter_enable, FALSE);
289
290 if (ginfo->filter_task_count)
291 gtk_widget_set_sensitive(menu_filter_clear_tasks, TRUE);
292 else
293 gtk_widget_set_sensitive(menu_filter_clear_tasks, FALSE);
294
295 gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3,
296 gtk_get_current_event_time());
297
298 return TRUE;
299}
300
301static gboolean
302button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer data)
303{
304 if (event->button == 3)
305 return do_tree_popup(widget, event, data);
306
307 return FALSE;
308}
309
158void kernel_shark(int argc, char **argv) 310void kernel_shark(int argc, char **argv)
159{ 311{
160 struct tracecmd_input *handle; 312 struct tracecmd_input *handle;
@@ -362,6 +514,9 @@ void kernel_shark(int argc, char **argv)
362 514
363 gtk_container_add(GTK_CONTAINER(scrollwin), info->treeview); 515 gtk_container_add(GTK_CONTAINER(scrollwin), info->treeview);
364 516
517 gtk_signal_connect(GTK_OBJECT(info->treeview), "button_press_event",
518 (GtkSignalFunc) button_press_event, info);
519
365 gtk_widget_show(info->treeview); 520 gtk_widget_show(info->treeview);
366 521
367 522
diff --git a/kernel-shark.h b/kernel-shark.h
index bf9e632..59d7b7a 100644
--- a/kernel-shark.h
+++ b/kernel-shark.h
@@ -10,6 +10,7 @@ struct shark_info {
10 struct tracecmd_input *handle; 10 struct tracecmd_input *handle;
11 GtkWidget *treeview; 11 GtkWidget *treeview;
12 struct graph_callbacks graph_cbs; 12 struct graph_callbacks graph_cbs;
13 gint selected_task;
13}; 14};
14 15
15#define offset_of(type, field) (long)(&((type *)0)->field) 16#define offset_of(type, field) (long)(&((type *)0)->field)
diff --git a/trace-graph.c b/trace-graph.c
index 54ea8ea..1641d97 100644
--- a/trace-graph.c
+++ b/trace-graph.c
@@ -29,6 +29,7 @@
29#include "trace-cmd.h" 29#include "trace-cmd.h"
30#include "trace-local.h" 30#include "trace-local.h"
31#include "trace-graph.h" 31#include "trace-graph.h"
32#include "trace-hash.h"
32 33
33#define DEBUG_LEVEL 2 34#define DEBUG_LEVEL 2
34#if DEBUG_LEVEL > 0 35#if DEBUG_LEVEL > 0
@@ -57,18 +58,12 @@
57 58
58#define FILTER_TASK_HASH_SIZE 256 59#define FILTER_TASK_HASH_SIZE 256
59 60
60struct filter_task {
61 struct filter_task *next;
62 gint pid;
63};
64
65static gint ftrace_sched_switch_id = -1; 61static gint ftrace_sched_switch_id = -1;
66static gint event_sched_switch_id = -1; 62static gint event_sched_switch_id = -1;
67 63
68static gint largest_cpu_label = 0; 64static gint largest_cpu_label = 0;
69 65
70static void redraw_pixmap_backend(struct graph_info *ginfo); 66static void redraw_pixmap_backend(struct graph_info *ginfo);
71static guint do_hash(gint val);
72 67
73static void convert_nano(unsigned long long time, unsigned long *sec, 68static void convert_nano(unsigned long long time, unsigned long *sec,
74 unsigned long *usec) 69 unsigned long *usec)
@@ -88,10 +83,10 @@ static void print_time(unsigned long long time)
88 printf("%lu.%06lu", sec, usec); 83 printf("%lu.%06lu", sec, usec);
89} 84}
90 85
91static struct filter_task * 86struct filter_task *
92filter_task_find_pid(struct graph_info *ginfo, gint pid) 87trace_graph_filter_task_find_pid(struct graph_info *ginfo, gint pid)
93{ 88{
94 gint key = do_hash(pid) % FILTER_TASK_HASH_SIZE; 89 gint key = trace_hash(pid) % FILTER_TASK_HASH_SIZE;
95 struct filter_task *task = ginfo->filter_task_hash[key]; 90 struct filter_task *task = ginfo->filter_task_hash[key];
96 91
97 while (task) { 92 while (task) {
@@ -104,7 +99,7 @@ filter_task_find_pid(struct graph_info *ginfo, gint pid)
104 99
105static void filter_task_add_pid(struct graph_info *ginfo, gint pid) 100static void filter_task_add_pid(struct graph_info *ginfo, gint pid)
106{ 101{
107 gint key = do_hash(pid) % FILTER_TASK_HASH_SIZE; 102 gint key = trace_hash(pid) % FILTER_TASK_HASH_SIZE;
108 struct filter_task *task; 103 struct filter_task *task;
109 104
110 task = g_new0(typeof(*task), 1); 105 task = g_new0(typeof(*task), 1);
@@ -120,7 +115,7 @@ static void filter_task_add_pid(struct graph_info *ginfo, gint pid)
120 115
121static void filter_task_remove_pid(struct graph_info *ginfo, gint pid) 116static void filter_task_remove_pid(struct graph_info *ginfo, gint pid)
122{ 117{
123 gint key = do_hash(pid) % FILTER_TASK_HASH_SIZE; 118 gint key = trace_hash(pid) % FILTER_TASK_HASH_SIZE;
124 struct filter_task **next = &ginfo->filter_task_hash[key]; 119 struct filter_task **next = &ginfo->filter_task_hash[key];
125 struct filter_task *task; 120 struct filter_task *task;
126 121
@@ -178,7 +173,7 @@ gboolean filter_on_task(struct graph_info *ginfo, gint pid)
178 173
179 if (ginfo->filter_enabled && 174 if (ginfo->filter_enabled &&
180 ginfo->filter_task_count && 175 ginfo->filter_task_count &&
181 !filter_task_find_pid(ginfo, pid)) 176 !trace_graph_filter_task_find_pid(ginfo, pid))
182 filter = TRUE; 177 filter = TRUE;
183 178
184 return filter; 179 return filter;
@@ -288,37 +283,47 @@ find_record_on_cpu(struct graph_info *ginfo, gint cpu, guint64 time)
288 return record; 283 return record;
289} 284}
290 285
291static void 286void trace_graph_filter_toggle(struct graph_info *ginfo)
292filter_enable_clicked (gpointer data)
293{ 287{
294 struct graph_info *ginfo = data;
295
296 ginfo->filter_enabled ^= 1; 288 ginfo->filter_enabled ^= 1;
297 289
298 redraw_graph(ginfo); 290 redraw_graph(ginfo);
299} 291}
300 292
301static void 293static void
302filter_add_task_clicked (gpointer data) 294filter_enable_clicked (gpointer data)
303{ 295{
304 struct graph_info *ginfo = data; 296 struct graph_info *ginfo = data;
297
298 trace_graph_filter_toggle(ginfo);
299}
300
301void trace_graph_filter_add_remove_task(struct graph_info *ginfo,
302 gint pid)
303{
305 struct filter_task *task; 304 struct filter_task *task;
306 305
307 task = filter_task_find_pid(ginfo, ginfo->filter_task_selected); 306 task = trace_graph_filter_task_find_pid(ginfo, pid);
308 307
309 if (task) 308 if (task)
310 filter_task_remove_pid(ginfo, task->pid); 309 filter_task_remove_pid(ginfo, task->pid);
311 else 310 else
312 filter_task_add_pid(ginfo, ginfo->filter_task_selected); 311 filter_task_add_pid(ginfo, pid);
313 312
314 if (ginfo->filter_enabled) 313 if (ginfo->filter_enabled)
315 redraw_graph(ginfo); 314 redraw_graph(ginfo);
316} 315}
317 316
318static void 317static void
319filter_clear_tasks_clicked (gpointer data) 318filter_add_task_clicked (gpointer data)
320{ 319{
321 struct graph_info *ginfo = data; 320 struct graph_info *ginfo = data;
321
322 trace_graph_filter_add_remove_task(ginfo, ginfo->filter_task_selected);
323}
324
325void trace_graph_clear_tasks(struct graph_info *ginfo)
326{
322 gint filter_enabled = ginfo->filter_enabled; 327 gint filter_enabled = ginfo->filter_enabled;
323 328
324 filter_task_clear(ginfo); 329 filter_task_clear(ginfo);
@@ -327,6 +332,14 @@ filter_clear_tasks_clicked (gpointer data)
327 redraw_graph(ginfo); 332 redraw_graph(ginfo);
328} 333}
329 334
335static void
336filter_clear_tasks_clicked (gpointer data)
337{
338 struct graph_info *ginfo = data;
339
340 trace_graph_clear_tasks(ginfo);
341}
342
330static gboolean 343static gboolean
331do_pop_up(GtkWidget *widget, GdkEventButton *event, gpointer data) 344do_pop_up(GtkWidget *widget, GdkEventButton *event, gpointer data)
332{ 345{
@@ -411,7 +424,7 @@ do_pop_up(GtkWidget *widget, GdkEventButton *event, gpointer data)
411 text = g_malloc(len); 424 text = g_malloc(len);
412 g_assert(text); 425 g_assert(text);
413 426
414 if (filter_task_find_pid(ginfo, pid)) 427 if (trace_graph_filter_task_find_pid(ginfo, pid))
415 snprintf(text, len, "Remove %s-%d to filter", comm, pid); 428 snprintf(text, len, "Remove %s-%d to filter", comm, pid);
416 else 429 else
417 snprintf(text, len, "Add %s-%d to filter", comm, pid); 430 snprintf(text, len, "Add %s-%d to filter", comm, pid);
@@ -1017,43 +1030,13 @@ button_release_event(GtkWidget *widget, GdkEventMotion *event, gpointer data)
1017 return TRUE; 1030 return TRUE;
1018} 1031}
1019 1032
1020static guint do_hash(gint val)
1021{
1022 int hash, tmp;
1023
1024 /* idle always gets black */
1025 if (!val)
1026 return 0;
1027
1028 hash = 12546869; /* random prime */
1029
1030 /*
1031 * The following hash is based off of Paul Hsieh's super fast hash:
1032 * http://www.azillionmonkeys.com/qed/hash.html
1033 */
1034
1035 hash += (val & 0xffff);
1036 tmp = (val >> 16) ^ hash;
1037 hash = (hash << 16) ^ tmp;
1038 hash += hash >> 11;
1039
1040 hash ^= hash << 3;
1041 hash += hash >> 5;
1042 hash ^= hash << 4;
1043 hash += hash >> 17;
1044 hash ^= hash << 25;
1045 hash += hash >> 6;
1046
1047 return hash;
1048}
1049
1050static gint hash_pid(gint val) 1033static gint hash_pid(gint val)
1051{ 1034{
1052 /* idle always gets black */ 1035 /* idle always gets black */
1053 if (!val) 1036 if (!val)
1054 return 0; 1037 return 0;
1055 1038
1056 return do_hash(val); 1039 return trace_hash(val);
1057} 1040}
1058 1041
1059static void set_color_by_pid(GtkWidget *widget, GdkGC *gc, gint pid) 1042static void set_color_by_pid(GtkWidget *widget, GdkGC *gc, gint pid)
diff --git a/trace-graph.h b/trace-graph.h
index a3d3901..ac52003 100644
--- a/trace-graph.h
+++ b/trace-graph.h
@@ -11,7 +11,10 @@ struct graph_callbacks {
11 graph_select_cb *select; 11 graph_select_cb *select;
12}; 12};
13 13
14struct filter_task; 14struct filter_task {
15 struct filter_task *next;
16 gint pid;
17};
15 18
16struct graph_info { 19struct graph_info {
17 struct tracecmd_input *handle; 20 struct tracecmd_input *handle;
@@ -93,4 +96,11 @@ static inline GtkWidget *trace_graph_get_window(struct graph_info *ginfo)
93 return ginfo->widget; 96 return ginfo->widget;
94} 97}
95 98
99struct filter_task *
100trace_graph_filter_task_find_pid(struct graph_info *ginfo, gint pid);
101void trace_graph_filter_toggle(struct graph_info *ginfo);
102void trace_graph_filter_add_remove_task(struct graph_info *info,
103 gint pid);
104void trace_graph_clear_tasks(struct graph_info *ginfo);
105
96#endif /* _TRACE_GRAPH_H */ 106#endif /* _TRACE_GRAPH_H */
diff --git a/trace-hash.c b/trace-hash.c
new file mode 100644
index 0000000..9d830e2
--- /dev/null
+++ b/trace-hash.c
@@ -0,0 +1,31 @@
1#include <stdio.h>
2#include <string.h>
3#include <stdarg.h>
4
5#include "trace-hash.h"
6
7guint trace_hash(gint val)
8{
9 gint hash, tmp;
10
11 hash = 12546869; /* random prime */
12
13 /*
14 * The following hash is based off of Paul Hsieh's super fast hash:
15 * http://www.azillionmonkeys.com/qed/hash.html
16 */
17
18 hash += (val & 0xffff);
19 tmp = (val >> 16) ^ hash;
20 hash = (hash << 16) ^ tmp;
21 hash += hash >> 11;
22
23 hash ^= hash << 3;
24 hash += hash >> 5;
25 hash ^= hash << 4;
26 hash += hash >> 17;
27 hash ^= hash << 25;
28 hash += hash >> 6;
29
30 return hash;
31}
diff --git a/trace-hash.h b/trace-hash.h
new file mode 100644
index 0000000..8a22044
--- /dev/null
+++ b/trace-hash.h
@@ -0,0 +1,8 @@
1#ifndef _TRACE_HASH_H
2#define _TRACE_HASH_H
3
4#include <glib.h>
5
6guint trace_hash(gint val);
7
8#endif /* _TRACE_HASH_H */
diff --git a/trace-view-store.c b/trace-view-store.c
index 6f7a46a..04debbb 100644
--- a/trace-view-store.c
+++ b/trace-view-store.c
@@ -1064,6 +1064,17 @@ guint64 trace_view_store_get_time_from_row(TraceViewStore *store, gint row)
1064 return store->rows[row]->timestamp; 1064 return store->rows[row]->timestamp;
1065} 1065}
1066 1066
1067guint64 trace_view_store_get_offset_from_row(TraceViewStore *store, gint row)
1068{
1069 g_return_val_if_fail (TRACE_VIEW_IS_LIST (store), 0);
1070
1071 row += store->start_row;
1072
1073 g_return_val_if_fail (row >= 0 && row < store->actual_rows, 0);
1074
1075 return store->rows[row]->offset;
1076}
1077
1067/***************************************************************************** 1078/*****************************************************************************
1068 * 1079 *
1069 * trace_view_store_append_record: Empty lists are boring. This function can 1080 * trace_view_store_append_record: Empty lists are boring. This function can
diff --git a/trace-view-store.h b/trace-view-store.h
index 35f1193..687a946 100644
--- a/trace-view-store.h
+++ b/trace-view-store.h
@@ -116,6 +116,8 @@ gint trace_view_store_get_timestamp_visible_row(TraceViewStore *store, guint64 t
116 116
117guint64 trace_view_store_get_time_from_row(TraceViewStore *store, gint row); 117guint64 trace_view_store_get_time_from_row(TraceViewStore *store, gint row);
118 118
119guint64 trace_view_store_get_offset_from_row(TraceViewStore *store, gint row);
120
119/* TraceViewStoreClass: more boilerplate GObject stuff */ 121/* TraceViewStoreClass: more boilerplate GObject stuff */
120 122
121struct _TraceViewStoreClass 123struct _TraceViewStoreClass