aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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