diff options
| author | Steven Rostedt <srostedt@redhat.com> | 2010-04-05 17:28:12 -0400 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2010-04-09 11:56:18 -0400 |
| commit | 81b404df1d425f146527dc3da253365071e68bea (patch) | |
| tree | b5d1c23d118f41505e7c896837ef27bf489c5e9c | |
| parent | b2a9cd2f38f6c3c30e9ef4c47eb004b41b50fe5e (diff) | |
trace-view: Add pop-up task menu for filtering tasks
Add pop-up menu over the rows that will allow to filter on tasks
in trace-view.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
| -rw-r--r-- | trace-view-main.c | 227 |
1 files changed, 214 insertions, 13 deletions
diff --git a/trace-view-main.c b/trace-view-main.c index 22b9e32..74922fb 100644 --- a/trace-view-main.c +++ b/trace-view-main.c | |||
| @@ -30,6 +30,7 @@ | |||
| 30 | #include "trace-view.h" | 30 | #include "trace-view.h" |
| 31 | #include "trace-xml.h" | 31 | #include "trace-xml.h" |
| 32 | #include "trace-gui.h" | 32 | #include "trace-gui.h" |
| 33 | #include "trace-compat.h" | ||
| 33 | 34 | ||
| 34 | #define version "0.1.1" | 35 | #define version "0.1.1" |
| 35 | 36 | ||
| @@ -40,8 +41,13 @@ | |||
| 40 | static char *input_file; | 41 | static char *input_file; |
| 41 | 42 | ||
| 42 | struct trace_tree_info { | 43 | struct trace_tree_info { |
| 43 | GtkWidget *trace_tree; | 44 | struct tracecmd_input *handle; |
| 44 | GtkWidget *spin; | 45 | GtkWidget *trace_tree; |
| 46 | GtkWidget *spin; | ||
| 47 | gint filter_enabled; | ||
| 48 | gint filter_task_selected; | ||
| 49 | struct filter_task *task_filter; | ||
| 50 | struct filter_task *hide_tasks; | ||
| 45 | }; | 51 | }; |
| 46 | 52 | ||
| 47 | void usage(char *prog) | 53 | void usage(char *prog) |
| @@ -68,6 +74,7 @@ load_clicked (gpointer data) | |||
| 68 | trace_view_reload(info->trace_tree, handle, info->spin); | 74 | trace_view_reload(info->trace_tree, handle, info->spin); |
| 69 | /* Free handle when freeing the trace tree */ | 75 | /* Free handle when freeing the trace tree */ |
| 70 | tracecmd_close(handle); | 76 | tracecmd_close(handle); |
| 77 | info->handle = handle; | ||
| 71 | } | 78 | } |
| 72 | g_free(filename); | 79 | g_free(filename); |
| 73 | } | 80 | } |
| @@ -203,24 +210,209 @@ cpus_clicked (gpointer data) | |||
| 203 | trace_view_cpu_filter_callback, trace_tree); | 210 | trace_view_cpu_filter_callback, trace_tree); |
| 204 | } | 211 | } |
| 205 | 212 | ||
| 206 | #if 0 | 213 | static void |
| 207 | static GtkTreeModel * | 214 | filter_list_clicked (gpointer data) |
| 208 | create_combo_box_model(void) | 215 | { |
| 216 | struct trace_tree_info *info = data; | ||
| 217 | |||
| 218 | if (!filter_task_count(info->task_filter) && | ||
| 219 | !filter_task_count(info->hide_tasks)) | ||
| 220 | return; | ||
| 221 | |||
| 222 | info->filter_enabled ^= 1; | ||
| 223 | |||
| 224 | if (info->filter_enabled) | ||
| 225 | trace_view_update_filters(info->trace_tree, | ||
| 226 | info->task_filter, | ||
| 227 | info->hide_tasks); | ||
| 228 | else | ||
| 229 | trace_view_update_filters(info->trace_tree, NULL, NULL); | ||
| 230 | } | ||
| 231 | |||
| 232 | static void update_task_filter(struct trace_tree_info *info, | ||
| 233 | struct filter_task *filter) | ||
| 234 | { | ||
| 235 | struct filter_task_item *task; | ||
| 236 | gint pid = info->filter_task_selected; | ||
| 237 | |||
| 238 | task = filter_task_find_pid(filter, pid); | ||
| 239 | |||
| 240 | if (task) | ||
| 241 | filter_task_remove_pid(filter, pid); | ||
| 242 | else | ||
| 243 | filter_task_add_pid(filter, pid); | ||
| 244 | |||
| 245 | if (info->filter_enabled) | ||
| 246 | trace_view_update_filters(info->trace_tree, | ||
| 247 | info->task_filter, | ||
| 248 | info->hide_tasks); | ||
| 249 | } | ||
| 250 | |||
| 251 | static void filter_add_task_clicked(gpointer data) | ||
| 252 | { | ||
| 253 | struct trace_tree_info *info = data; | ||
| 254 | |||
| 255 | update_task_filter(info, info->task_filter); | ||
| 256 | } | ||
| 257 | |||
| 258 | static void filter_hide_task_clicked(gpointer data) | ||
| 209 | { | 259 | { |
| 210 | GtkListStore *store; | 260 | struct trace_tree_info *info = data; |
| 211 | GtkTreeIter iter; | ||
| 212 | 261 | ||
| 213 | store = gtk_list_store_new(1, G_TYPE_STRING); | 262 | update_task_filter(info, info->hide_tasks); |
| 214 | gtk_list_store_append(store, &iter); | 263 | } |
| 215 | gtk_list_store_set(store, &iter, 0, "1", -1); | 264 | |
| 265 | static void | ||
| 266 | filter_clear_tasks_clicked (gpointer data) | ||
| 267 | { | ||
| 268 | struct trace_tree_info *info = data; | ||
| 216 | 269 | ||
| 217 | return GTK_TREE_MODEL(store); | 270 | trace_view_update_filters(info->trace_tree, NULL, NULL); |
| 271 | info->filter_enabled = 0; | ||
| 272 | } | ||
| 273 | |||
| 274 | static gboolean | ||
| 275 | do_tree_popup(GtkWidget *widget, GdkEventButton *event, gpointer data) | ||
| 276 | { | ||
| 277 | struct trace_tree_info *info = data; | ||
| 278 | static GtkWidget *menu; | ||
| 279 | static GtkWidget *menu_filter_enable; | ||
| 280 | static GtkWidget *menu_filter_add_task; | ||
| 281 | static GtkWidget *menu_filter_hide_task; | ||
| 282 | static GtkWidget *menu_filter_clear_tasks; | ||
| 283 | struct pevent *pevent; | ||
| 284 | struct record *record; | ||
| 285 | TraceViewRecord *vrec; | ||
| 286 | GtkTreeModel *model; | ||
| 287 | const char *comm; | ||
| 288 | gchar *text; | ||
| 289 | gint pid; | ||
| 290 | gint len; | ||
| 291 | guint64 offset; | ||
| 292 | gint row; | ||
| 293 | gint cpu; | ||
| 294 | |||
| 295 | if (!menu) { | ||
| 296 | menu = gtk_menu_new(); | ||
| 297 | |||
| 298 | menu_filter_enable = gtk_menu_item_new_with_label("Enable Filter"); | ||
| 299 | gtk_widget_show(menu_filter_enable); | ||
| 300 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_enable); | ||
| 301 | |||
| 302 | g_signal_connect_swapped (G_OBJECT (menu_filter_enable), "activate", | ||
| 303 | G_CALLBACK (filter_list_clicked), | ||
| 304 | data); | ||
| 305 | |||
| 306 | menu_filter_add_task = gtk_menu_item_new_with_label("Add Task"); | ||
| 307 | gtk_widget_show(menu_filter_add_task); | ||
| 308 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_add_task); | ||
| 309 | |||
| 310 | g_signal_connect_swapped (G_OBJECT (menu_filter_add_task), "activate", | ||
| 311 | G_CALLBACK (filter_add_task_clicked), | ||
| 312 | data); | ||
| 313 | |||
| 314 | menu_filter_hide_task = gtk_menu_item_new_with_label("Hide Task"); | ||
| 315 | gtk_widget_show(menu_filter_hide_task); | ||
| 316 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_hide_task); | ||
| 317 | |||
| 318 | g_signal_connect_swapped (G_OBJECT (menu_filter_hide_task), "activate", | ||
| 319 | G_CALLBACK (filter_hide_task_clicked), | ||
| 320 | data); | ||
| 321 | |||
| 322 | menu_filter_clear_tasks = gtk_menu_item_new_with_label("Clear Task Filter"); | ||
| 323 | gtk_widget_show(menu_filter_clear_tasks); | ||
| 324 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), menu_filter_clear_tasks); | ||
| 325 | |||
| 326 | g_signal_connect_swapped (G_OBJECT (menu_filter_clear_tasks), "activate", | ||
| 327 | G_CALLBACK (filter_clear_tasks_clicked), | ||
| 328 | data); | ||
| 329 | |||
| 330 | } | ||
| 331 | |||
| 332 | row = trace_view_get_selected_row(GTK_WIDGET(info->trace_tree)); | ||
| 333 | if (row >= 0) { | ||
| 334 | |||
| 335 | model = gtk_tree_view_get_model(GTK_TREE_VIEW(info->trace_tree)); | ||
| 336 | vrec = trace_view_store_get_row(TRACE_VIEW_STORE(model), row); | ||
| 337 | offset = vrec->offset; | ||
| 338 | |||
| 339 | record = tracecmd_read_at(info->handle, offset, &cpu); | ||
| 340 | |||
| 341 | if (record) { | ||
| 342 | pevent = tracecmd_get_pevent(info->handle); | ||
| 343 | pid = pevent_data_pid(pevent, record); | ||
| 344 | comm = pevent_data_comm_from_pid(pevent, pid); | ||
| 345 | |||
| 346 | len = strlen(comm) + 50; | ||
| 347 | |||
| 348 | text = g_malloc(len); | ||
| 349 | g_assert(text); | ||
| 350 | |||
| 351 | if (filter_task_find_pid(info->task_filter, pid)) | ||
| 352 | snprintf(text, len, "Remove %s-%d to filter", comm, pid); | ||
| 353 | else | ||
| 354 | snprintf(text, len, "Add %s-%d to filter", comm, pid); | ||
| 355 | |||
| 356 | info->filter_task_selected = pid; | ||
| 357 | |||
| 358 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_add_task), | ||
| 359 | text); | ||
| 360 | |||
| 361 | if (filter_task_find_pid(info->hide_tasks, pid)) | ||
| 362 | snprintf(text, len, "Show %s-%d", comm, pid); | ||
| 363 | else | ||
| 364 | snprintf(text, len, "Hide %s-%d", comm, pid); | ||
| 365 | |||
| 366 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_hide_task), | ||
| 367 | text); | ||
| 368 | |||
| 369 | g_free(text); | ||
| 370 | |||
| 371 | info->filter_task_selected = pid; | ||
| 372 | |||
| 373 | gtk_widget_show(menu_filter_add_task); | ||
| 374 | gtk_widget_show(menu_filter_hide_task); | ||
| 375 | free_record(record); | ||
| 376 | } | ||
| 377 | } else { | ||
| 378 | gtk_widget_hide(menu_filter_add_task); | ||
| 379 | gtk_widget_hide(menu_filter_hide_task); | ||
| 380 | } | ||
| 381 | |||
| 382 | if (info->filter_enabled) | ||
| 383 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_enable), | ||
| 384 | "Disable List Filter"); | ||
| 385 | else | ||
| 386 | gtk_menu_item_set_label(GTK_MENU_ITEM(menu_filter_enable), | ||
| 387 | "Enable List Filter"); | ||
| 388 | |||
| 389 | if (filter_task_count(info->task_filter) || | ||
| 390 | filter_task_count(info->hide_tasks)) { | ||
| 391 | gtk_widget_set_sensitive(menu_filter_clear_tasks, TRUE); | ||
| 392 | gtk_widget_set_sensitive(menu_filter_enable, TRUE); | ||
| 393 | } else { | ||
| 394 | gtk_widget_set_sensitive(menu_filter_clear_tasks, FALSE); | ||
| 395 | gtk_widget_set_sensitive(menu_filter_enable, FALSE); | ||
| 396 | } | ||
| 397 | |||
| 398 | gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, | ||
| 399 | gtk_get_current_event_time()); | ||
| 400 | |||
| 401 | return TRUE; | ||
| 402 | } | ||
| 403 | |||
| 404 | static gboolean | ||
| 405 | button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer data) | ||
| 406 | { | ||
| 407 | if (event->button == 3) | ||
| 408 | return do_tree_popup(widget, event, data); | ||
| 409 | |||
| 410 | return FALSE; | ||
| 218 | } | 411 | } |
| 219 | #endif | ||
| 220 | 412 | ||
| 221 | void trace_view(int argc, char **argv) | 413 | void trace_view(int argc, char **argv) |
| 222 | { | 414 | { |
| 223 | static struct tracecmd_input *handle; | 415 | static struct tracecmd_input *handle = NULL; |
| 224 | struct trace_tree_info tree_info; | 416 | struct trace_tree_info tree_info; |
| 225 | struct stat st; | 417 | struct stat st; |
| 226 | GtkWidget *trace_tree; | 418 | GtkWidget *trace_tree; |
| @@ -268,6 +460,11 @@ void trace_view(int argc, char **argv) | |||
| 268 | if (input_file) | 460 | if (input_file) |
| 269 | handle = tracecmd_open(input_file); | 461 | handle = tracecmd_open(input_file); |
| 270 | 462 | ||
| 463 | memset(&tree_info, 0, sizeof(tree_info)); | ||
| 464 | tree_info.handle = handle; | ||
| 465 | tree_info.task_filter = filter_task_hash_alloc(); | ||
| 466 | tree_info.hide_tasks = filter_task_hash_alloc(); | ||
| 467 | |||
| 271 | /* --- Main window --- */ | 468 | /* --- Main window --- */ |
| 272 | 469 | ||
| 273 | window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | 470 | window = gtk_window_new(GTK_WINDOW_TOPLEVEL); |
| @@ -455,6 +652,10 @@ void trace_view(int argc, char **argv) | |||
| 455 | gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); | 652 | gtk_box_pack_start(GTK_BOX(hbox), label, FALSE, FALSE, 0); |
| 456 | gtk_widget_show(label); | 653 | gtk_widget_show(label); |
| 457 | 654 | ||
| 655 | gtk_signal_connect(GTK_OBJECT(trace_tree), "button_press_event", | ||
| 656 | (GtkSignalFunc) button_press_event, | ||
| 657 | (gpointer) &tree_info); | ||
| 658 | |||
| 458 | trace_view_search_setup(GTK_BOX(hbox), GTK_TREE_VIEW(trace_tree)); | 659 | trace_view_search_setup(GTK_BOX(hbox), GTK_TREE_VIEW(trace_tree)); |
| 459 | 660 | ||
| 460 | /* --- Top Level Hbox --- */ | 661 | /* --- Top Level Hbox --- */ |
