diff options
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | kernel-shark.c | 155 | ||||
-rw-r--r-- | kernel-shark.h | 1 | ||||
-rw-r--r-- | trace-graph.c | 87 | ||||
-rw-r--r-- | trace-graph.h | 12 | ||||
-rw-r--r-- | trace-hash.c | 31 | ||||
-rw-r--r-- | trace-hash.h | 8 | ||||
-rw-r--r-- | trace-view-store.c | 11 | ||||
-rw-r--r-- | trace-view-store.h | 2 |
9 files changed, 257 insertions, 55 deletions
@@ -51,10 +51,11 @@ trace-cmd:: trace-cmd.o trace-read.o | |||
51 | trace-view:: trace-view-main.o $(TRACE_VIEW_OBJS) | 51 | trace-view:: trace-view-main.o $(TRACE_VIEW_OBJS) |
52 | $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS) | 52 | $(CC) $^ -rdynamic -o $@ $(CONFIG_LIBS) $(LIBS) |
53 | 53 | ||
54 | trace-graph:: trace-graph-main.o trace-graph.o trace-compat.o | 54 | trace-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 | ||
57 | kernelshark:: kernel-shark.o trace-compat.o $(TRACE_VIEW_OBJS) trace-graph.o | 57 | kernelshark:: 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 | ||
158 | static void | ||
159 | filter_enable_clicked (gpointer data) | ||
160 | { | ||
161 | struct shark_info *info = data; | ||
162 | |||
163 | trace_graph_filter_toggle(info->ginfo); | ||
164 | } | ||
165 | |||
166 | static void | ||
167 | filter_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 | |||
174 | static void | ||
175 | filter_clear_tasks_clicked (gpointer data) | ||
176 | { | ||
177 | struct shark_info *info = data; | ||
178 | |||
179 | trace_graph_clear_tasks(info->ginfo); | ||
180 | } | ||
181 | |||
182 | static gboolean | ||
183 | do_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 | |||
301 | static gboolean | ||
302 | button_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 | |||
158 | void kernel_shark(int argc, char **argv) | 310 | void 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 | ||
60 | struct filter_task { | ||
61 | struct filter_task *next; | ||
62 | gint pid; | ||
63 | }; | ||
64 | |||
65 | static gint ftrace_sched_switch_id = -1; | 61 | static gint ftrace_sched_switch_id = -1; |
66 | static gint event_sched_switch_id = -1; | 62 | static gint event_sched_switch_id = -1; |
67 | 63 | ||
68 | static gint largest_cpu_label = 0; | 64 | static gint largest_cpu_label = 0; |
69 | 65 | ||
70 | static void redraw_pixmap_backend(struct graph_info *ginfo); | 66 | static void redraw_pixmap_backend(struct graph_info *ginfo); |
71 | static guint do_hash(gint val); | ||
72 | 67 | ||
73 | static void convert_nano(unsigned long long time, unsigned long *sec, | 68 | static 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 | ||
91 | static struct filter_task * | 86 | struct filter_task * |
92 | filter_task_find_pid(struct graph_info *ginfo, gint pid) | 87 | trace_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 | ||
105 | static void filter_task_add_pid(struct graph_info *ginfo, gint pid) | 100 | static 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 | ||
121 | static void filter_task_remove_pid(struct graph_info *ginfo, gint pid) | 116 | static 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 | ||
291 | static void | 286 | void trace_graph_filter_toggle(struct graph_info *ginfo) |
292 | filter_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 | ||
301 | static void | 293 | static void |
302 | filter_add_task_clicked (gpointer data) | 294 | filter_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 | |||
301 | void 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 | ||
318 | static void | 317 | static void |
319 | filter_clear_tasks_clicked (gpointer data) | 318 | filter_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 | |||
325 | void 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 | ||
335 | static void | ||
336 | filter_clear_tasks_clicked (gpointer data) | ||
337 | { | ||
338 | struct graph_info *ginfo = data; | ||
339 | |||
340 | trace_graph_clear_tasks(ginfo); | ||
341 | } | ||
342 | |||
330 | static gboolean | 343 | static gboolean |
331 | do_pop_up(GtkWidget *widget, GdkEventButton *event, gpointer data) | 344 | do_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 | ||
1020 | static 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 | |||
1050 | static gint hash_pid(gint val) | 1033 | static 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 | ||
1059 | static void set_color_by_pid(GtkWidget *widget, GdkGC *gc, gint pid) | 1042 | static 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 | ||
14 | struct filter_task; | 14 | struct filter_task { |
15 | struct filter_task *next; | ||
16 | gint pid; | ||
17 | }; | ||
15 | 18 | ||
16 | struct graph_info { | 19 | struct 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 | ||
99 | struct filter_task * | ||
100 | trace_graph_filter_task_find_pid(struct graph_info *ginfo, gint pid); | ||
101 | void trace_graph_filter_toggle(struct graph_info *ginfo); | ||
102 | void trace_graph_filter_add_remove_task(struct graph_info *info, | ||
103 | gint pid); | ||
104 | void 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 | |||
7 | guint 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 | |||
6 | guint 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 | ||
1067 | guint64 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 | ||
117 | guint64 trace_view_store_get_time_from_row(TraceViewStore *store, gint row); | 117 | guint64 trace_view_store_get_time_from_row(TraceViewStore *store, gint row); |
118 | 118 | ||
119 | guint64 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 | ||
121 | struct _TraceViewStoreClass | 123 | struct _TraceViewStoreClass |