diff options
author | Steven Rostedt <srostedt@redhat.com> | 2010-02-18 09:59:42 -0500 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2010-02-18 09:59:42 -0500 |
commit | df49e6a44d60740e6730e2b5255b53c900adc9a7 (patch) | |
tree | 381e23b44acdd509ca46ba749b9eb2ca578079e3 | |
parent | ea645651cdc0ab38fddeb9f81b13eccc9a22d98d (diff) |
trace-graph: Added CPU plotting menu
Added menu for adding and removing CPU plots and Tasks.
Only CPU updates have been implemented in this change set.
Task updates will follow.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r-- | cpu.h | 34 | ||||
-rw-r--r-- | trace-graph-main.c | 77 | ||||
-rw-r--r-- | trace-graph.c | 6 | ||||
-rw-r--r-- | trace-graph.h | 18 | ||||
-rw-r--r-- | trace-plot-cpu.c | 111 | ||||
-rw-r--r-- | trace-plot-task.c | 6 | ||||
-rw-r--r-- | trace-plot.c | 13 |
7 files changed, 248 insertions, 17 deletions
@@ -57,4 +57,38 @@ static inline void set_cpus(guint64 *cpu_mask, gint cpus) | |||
57 | *(cpu_mask) = (1ULL << (cpus & ((1ULL << 6) - 1))) - 1; | 57 | *(cpu_mask) = (1ULL << (cpus & ((1ULL << 6) - 1))) - 1; |
58 | } | 58 | } |
59 | 59 | ||
60 | static inline gboolean cpus_equal(guint64 *a_mask, guint64 *b_mask, | ||
61 | gint cpus) | ||
62 | { | ||
63 | gint idx; | ||
64 | |||
65 | for (idx = 0; idx < (cpus >> 6) + 1; idx++) { | ||
66 | if (*(a_mask + idx) != *(b_mask + idx)) | ||
67 | return FALSE; | ||
68 | } | ||
69 | return TRUE; | ||
70 | } | ||
71 | |||
72 | /* Hamming weight */ | ||
73 | static inline guint hweight(guint mask) | ||
74 | { | ||
75 | guint64 w = mask; | ||
76 | |||
77 | w -= (w >> 1) & 0x5555555555555555ul; | ||
78 | w = (w & 0x3333333333333333ul) + ((w >> 2) & 0x3333333333333333ul); | ||
79 | w = (w + (w >> 4)) & 0x0f0f0f0f0f0f0f0ful; | ||
80 | return (w * 0x0101010101010101ul) >> 56; | ||
81 | } | ||
82 | |||
83 | static inline guint cpu_weight(guint64 *cpu_mask, guint cpus) | ||
84 | { | ||
85 | guint weight = 0; | ||
86 | gint idx; | ||
87 | |||
88 | for (idx = 0; idx < (cpus >> 6) + 1; idx++) | ||
89 | weight += hweight(*(cpu_mask + idx)); | ||
90 | |||
91 | return weight; | ||
92 | } | ||
93 | |||
60 | #endif /* _CPU_H */ | 94 | #endif /* _CPU_H */ |
diff --git a/trace-graph-main.c b/trace-graph-main.c index 987a80d..adc05ca 100644 --- a/trace-graph-main.c +++ b/trace-graph-main.c | |||
@@ -120,6 +120,37 @@ adv_filter_clicked (gpointer data) | |||
120 | trace_graph_adv_filter_callback, ginfo); | 120 | trace_graph_adv_filter_callback, ginfo); |
121 | } | 121 | } |
122 | 122 | ||
123 | /* Callback for the clicked signal of the plot CPUs button */ | ||
124 | static void | ||
125 | plot_cpu_clicked (gpointer data) | ||
126 | { | ||
127 | struct graph_info *ginfo = data; | ||
128 | gboolean all_cpus; | ||
129 | guint64 *cpu_mask; | ||
130 | |||
131 | if (!ginfo->handle) | ||
132 | return; | ||
133 | |||
134 | graph_plot_cpus_plotted(ginfo, &all_cpus, &cpu_mask); | ||
135 | |||
136 | trace_filter_cpu_dialog(all_cpus, cpu_mask, ginfo->cpus, | ||
137 | graph_plot_cpus_update_callback, ginfo); | ||
138 | g_free(cpu_mask); | ||
139 | } | ||
140 | |||
141 | /* Callback for the clicked signal of the plot tasks button */ | ||
142 | static void | ||
143 | plot_tasks_clicked (gpointer data) | ||
144 | { | ||
145 | struct graph_info *ginfo = data; | ||
146 | gboolean all_events = TRUE; | ||
147 | |||
148 | if (!ginfo->handle) | ||
149 | return; | ||
150 | |||
151 | all_events = ginfo->all_events; | ||
152 | } | ||
153 | |||
123 | void trace_graph(int argc, char **argv) | 154 | void trace_graph(int argc, char **argv) |
124 | { | 155 | { |
125 | struct tracecmd_input *handle = NULL; | 156 | struct tracecmd_input *handle = NULL; |
@@ -276,6 +307,52 @@ void trace_graph(int argc, char **argv) | |||
276 | gtk_menu_item_set_submenu(GTK_MENU_ITEM (menu_item), menu); | 307 | gtk_menu_item_set_submenu(GTK_MENU_ITEM (menu_item), menu); |
277 | 308 | ||
278 | 309 | ||
310 | /* --- Plot Option --- */ | ||
311 | |||
312 | menu_item = gtk_menu_item_new_with_label("Plots"); | ||
313 | gtk_widget_show(menu_item); | ||
314 | |||
315 | gtk_menu_bar_append(GTK_MENU_BAR (menu_bar), menu_item); | ||
316 | |||
317 | menu = gtk_menu_new(); /* Don't need to show menus */ | ||
318 | |||
319 | |||
320 | /* --- Plot - CPUs Option --- */ | ||
321 | |||
322 | sub_item = gtk_menu_item_new_with_label("CPUs"); | ||
323 | |||
324 | /* Add them to the menu */ | ||
325 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | ||
326 | |||
327 | /* We can attach the Quit menu item to our exit function */ | ||
328 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | ||
329 | G_CALLBACK (plot_cpu_clicked), | ||
330 | (gpointer) ginfo); | ||
331 | |||
332 | /* We do need to show menu items */ | ||
333 | gtk_widget_show(sub_item); | ||
334 | |||
335 | |||
336 | /* --- Plot - Tasks Option --- */ | ||
337 | |||
338 | sub_item = gtk_menu_item_new_with_label("Tasks"); | ||
339 | |||
340 | /* Add them to the menu */ | ||
341 | gtk_menu_shell_append(GTK_MENU_SHELL (menu), sub_item); | ||
342 | |||
343 | /* We can attach the Quit menu item to our exit function */ | ||
344 | g_signal_connect_swapped (G_OBJECT (sub_item), "activate", | ||
345 | G_CALLBACK (plot_tasks_clicked), | ||
346 | (gpointer) ginfo); | ||
347 | |||
348 | /* We do need to show menu items */ | ||
349 | gtk_widget_show(sub_item); | ||
350 | |||
351 | |||
352 | /* --- End Plot Options --- */ | ||
353 | gtk_menu_item_set_submenu(GTK_MENU_ITEM (menu_item), menu); | ||
354 | |||
355 | |||
279 | /* --- Top Level Hbox --- */ | 356 | /* --- Top Level Hbox --- */ |
280 | 357 | ||
281 | hbox = gtk_hbox_new(FALSE, 0); | 358 | hbox = gtk_hbox_new(FALSE, 0); |
diff --git a/trace-graph.c b/trace-graph.c index fa76874..3c3f98d 100644 --- a/trace-graph.c +++ b/trace-graph.c | |||
@@ -2076,6 +2076,12 @@ static int load_handle(struct graph_info *ginfo, | |||
2076 | return 0; | 2076 | return 0; |
2077 | } | 2077 | } |
2078 | 2078 | ||
2079 | void trace_graph_refresh(struct graph_info *ginfo) | ||
2080 | { | ||
2081 | update_label_window(ginfo); | ||
2082 | redraw_graph(ginfo); | ||
2083 | } | ||
2084 | |||
2079 | int trace_graph_load_handle(struct graph_info *ginfo, | 2085 | int trace_graph_load_handle(struct graph_info *ginfo, |
2080 | struct tracecmd_input *handle) | 2086 | struct tracecmd_input *handle) |
2081 | { | 2087 | { |
diff --git a/trace-graph.h b/trace-graph.h index ae5f50d..7fdc5f0 100644 --- a/trace-graph.h +++ b/trace-graph.h | |||
@@ -32,6 +32,13 @@ typedef void (graph_filter_cb)(struct graph_info *ginfo, | |||
32 | struct filter_task *task_filter, | 32 | struct filter_task *task_filter, |
33 | struct filter_task *hide_tasks); | 33 | struct filter_task *hide_tasks); |
34 | 34 | ||
35 | /* Used for quereing what plots are defined */ | ||
36 | enum graph_plot_type { | ||
37 | PLOT_TYPE_OTHER, | ||
38 | PLOT_TYPE_CPU, | ||
39 | PLOT_TYPE_TASK, | ||
40 | }; | ||
41 | |||
35 | struct graph_plot; | 42 | struct graph_plot; |
36 | 43 | ||
37 | struct plot_info { | 44 | struct plot_info { |
@@ -108,6 +115,7 @@ struct plot_callbacks { | |||
108 | }; | 115 | }; |
109 | 116 | ||
110 | struct graph_plot { | 117 | struct graph_plot { |
118 | enum graph_plot_type type; | ||
111 | int pos; | 119 | int pos; |
112 | char *label; | 120 | char *label; |
113 | const struct plot_callbacks *cb; | 121 | const struct plot_callbacks *cb; |
@@ -251,6 +259,8 @@ static inline GtkWidget *trace_graph_get_window(struct graph_info *ginfo) | |||
251 | return ginfo->widget; | 259 | return ginfo->widget; |
252 | } | 260 | } |
253 | 261 | ||
262 | void trace_graph_refresh(struct graph_info *ginfo); | ||
263 | |||
254 | struct filter_task_item * | 264 | struct filter_task_item * |
255 | trace_graph_filter_task_find_pid(struct graph_info *ginfo, gint pid); | 265 | trace_graph_filter_task_find_pid(struct graph_info *ginfo, gint pid); |
256 | struct filter_task_item * | 266 | struct filter_task_item * |
@@ -283,11 +293,13 @@ void trace_graph_plot_free(struct graph_info *ginfo); | |||
283 | void trace_graph_plot_init(struct graph_info *ginfo); | 293 | void trace_graph_plot_init(struct graph_info *ginfo); |
284 | struct graph_plot *trace_graph_plot_append(struct graph_info *ginfo, | 294 | struct graph_plot *trace_graph_plot_append(struct graph_info *ginfo, |
285 | const char *label, | 295 | const char *label, |
296 | enum graph_plot_type type, | ||
286 | const struct plot_callbacks *cb, | 297 | const struct plot_callbacks *cb, |
287 | void *data); | 298 | void *data); |
288 | struct graph_plot *trace_graph_plot_insert(struct graph_info *ginfo, | 299 | struct graph_plot *trace_graph_plot_insert(struct graph_info *ginfo, |
289 | int pos, | 300 | int pos, |
290 | const char *label, | 301 | const char *label, |
302 | enum graph_plot_type type, | ||
291 | const struct plot_callbacks *cb, | 303 | const struct plot_callbacks *cb, |
292 | void *data); | 304 | void *data); |
293 | void trace_graph_plot_remove(struct graph_info *ginfo, struct graph_plot *plot); | 305 | void trace_graph_plot_remove(struct graph_info *ginfo, struct graph_plot *plot); |
@@ -341,6 +353,12 @@ int trace_graph_plot_display_info(struct graph_info *ginfo, | |||
341 | 353 | ||
342 | /* cpu plot */ | 354 | /* cpu plot */ |
343 | void graph_plot_init_cpus(struct graph_info *ginfo, int cpus); | 355 | void graph_plot_init_cpus(struct graph_info *ginfo, int cpus); |
356 | void graph_plot_cpus_plotted(struct graph_info *ginfo, | ||
357 | gboolean *all_cpus, guint64 **cpu_mask); | ||
358 | void graph_plot_cpus_update_callback(gboolean accept, | ||
359 | gboolean all_cpus, | ||
360 | guint64 *selected_cpu_mask, | ||
361 | gpointer data); | ||
344 | 362 | ||
345 | /* task plot */ | 363 | /* task plot */ |
346 | void graph_plot_task(struct graph_info *ginfo, int pid, int pos); | 364 | void graph_plot_task(struct graph_info *ginfo, int pid, int pos); |
diff --git a/trace-plot-cpu.c b/trace-plot-cpu.c index e591f04..e99fec8 100644 --- a/trace-plot-cpu.c +++ b/trace-plot-cpu.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <string.h> | 21 | #include <string.h> |
22 | 22 | ||
23 | #include "trace-graph.h" | 23 | #include "trace-graph.h" |
24 | #include "cpu.h" | ||
24 | 25 | ||
25 | struct cpu_plot_info { | 26 | struct cpu_plot_info { |
26 | int cpu; | 27 | int cpu; |
@@ -385,7 +386,7 @@ int cpu_plot_display_info(struct graph_info *ginfo, | |||
385 | return 1; | 386 | return 1; |
386 | } | 387 | } |
387 | 388 | ||
388 | void cpu_plot_destroy(struct graph_info *ginfo, struct graph_plot *plot) | 389 | static void cpu_plot_destroy(struct graph_info *ginfo, struct graph_plot *plot) |
389 | { | 390 | { |
390 | struct cpu_plot_info *cpu_info = plot->private; | 391 | struct cpu_plot_info *cpu_info = plot->private; |
391 | 392 | ||
@@ -403,20 +404,112 @@ static const struct plot_callbacks cpu_plot_cb = { | |||
403 | .destroy = cpu_plot_destroy | 404 | .destroy = cpu_plot_destroy |
404 | }; | 405 | }; |
405 | 406 | ||
406 | void graph_plot_init_cpus(struct graph_info *ginfo, int cpus) | 407 | static void add_cpu_plot(struct graph_info *ginfo, gint cpu) |
407 | { | 408 | { |
408 | struct cpu_plot_info *cpu_info; | 409 | struct cpu_plot_info *cpu_info; |
409 | struct graph_plot *plot; | 410 | struct graph_plot *plot; |
410 | char label[100]; | 411 | char label[100]; |
411 | long cpu; | ||
412 | 412 | ||
413 | for (cpu = 0; cpu < cpus; cpu++) { | 413 | cpu_info = malloc_or_die(sizeof(*cpu_info)); |
414 | cpu_info = malloc_or_die(sizeof(*cpu_info)); | 414 | cpu_info->cpu = cpu; |
415 | cpu_info->cpu = cpu; | 415 | |
416 | snprintf(label, 100, "CPU %d", cpu); | ||
417 | |||
418 | plot = trace_graph_plot_append(ginfo, label, PLOT_TYPE_CPU, | ||
419 | &cpu_plot_cb, cpu_info); | ||
420 | trace_graph_plot_add_cpu(ginfo, plot, cpu); | ||
421 | } | ||
422 | |||
423 | void graph_plot_cpus_update_callback(gboolean accept, | ||
424 | gboolean all_cpus, | ||
425 | guint64 *selected_cpu_mask, | ||
426 | gpointer data) | ||
427 | { | ||
428 | struct graph_info *ginfo = data; | ||
429 | struct cpu_plot_info *cpu_info; | ||
430 | struct graph_plot *plot; | ||
431 | gboolean old_all_cpus; | ||
432 | guint64 *old_cpu_mask; | ||
433 | int i; | ||
434 | |||
435 | if (!accept) | ||
436 | return; | ||
437 | |||
438 | /* Get the current status */ | ||
439 | graph_plot_cpus_plotted(ginfo, &old_all_cpus, &old_cpu_mask); | ||
440 | |||
441 | if (old_all_cpus == all_cpus || | ||
442 | (selected_cpu_mask && | ||
443 | cpus_equal(old_cpu_mask, selected_cpu_mask, ginfo->cpus))) { | ||
444 | /* Nothing to do */ | ||
445 | g_free(old_cpu_mask); | ||
446 | return; | ||
447 | } | ||
416 | 448 | ||
417 | snprintf(label, 100, "CPU %ld", cpu); | 449 | if (!all_cpus) { |
450 | /* | ||
451 | * Remove any plots not selected. | ||
452 | * Go backwards, since removing a plot shifts the | ||
453 | * array from current position back. | ||
454 | */ | ||
455 | for (i = ginfo->plots - 1; i >= 0; i--) { | ||
456 | plot = ginfo->plot_array[i]; | ||
457 | if (plot->type != PLOT_TYPE_CPU) | ||
458 | continue; | ||
459 | cpu_info = plot->private; | ||
460 | if (!cpu_isset(selected_cpu_mask, cpu_info->cpu)) | ||
461 | trace_graph_plot_remove(ginfo, plot); | ||
462 | } | ||
463 | } | ||
418 | 464 | ||
419 | plot = trace_graph_plot_append(ginfo, label, &cpu_plot_cb, cpu_info); | 465 | /* Now add any plots not set */ |
420 | trace_graph_plot_add_cpu(ginfo, plot, cpu); | 466 | for (i = 0; i < ginfo->cpus; i++) { |
467 | if (!all_cpus && !cpu_isset(selected_cpu_mask, i)) | ||
468 | continue; | ||
469 | if (cpu_isset(old_cpu_mask, i)) | ||
470 | continue; | ||
471 | add_cpu_plot(ginfo, i); | ||
421 | } | 472 | } |
473 | |||
474 | g_free(old_cpu_mask); | ||
475 | |||
476 | trace_graph_refresh(ginfo); | ||
477 | } | ||
478 | |||
479 | /** | ||
480 | * graph_plot_cpus_plotted - return what CPUs are plotted | ||
481 | * @ginfo: the graph info structure | ||
482 | * @all_cpus: returns true if all CPUS are currently plotted | ||
483 | * @cpu_mask: returns an allocated mask of what cpus are set | ||
484 | * | ||
485 | * @cpu_mask must be freed with g_free() after this is called. | ||
486 | */ | ||
487 | void graph_plot_cpus_plotted(struct graph_info *ginfo, | ||
488 | gboolean *all_cpus, guint64 **cpu_mask) | ||
489 | { | ||
490 | struct cpu_plot_info *cpu_info; | ||
491 | struct graph_plot *plot; | ||
492 | int i; | ||
493 | |||
494 | *cpu_mask = g_new0(guint64, (ginfo->cpus >> 6) + 1); | ||
495 | g_assert(*cpu_mask); | ||
496 | |||
497 | for (i = 0; i < ginfo->plots; i++) { | ||
498 | plot = ginfo->plot_array[i]; | ||
499 | if (plot->type != PLOT_TYPE_CPU) | ||
500 | continue; | ||
501 | cpu_info = plot->private; | ||
502 | cpu_set(*cpu_mask, cpu_info->cpu); | ||
503 | } | ||
504 | |||
505 | *all_cpus = cpu_weight(*cpu_mask, ginfo->cpus) == ginfo->cpus ? | ||
506 | TRUE : FALSE; | ||
507 | } | ||
508 | |||
509 | void graph_plot_init_cpus(struct graph_info *ginfo, int cpus) | ||
510 | { | ||
511 | long cpu; | ||
512 | |||
513 | for (cpu = 0; cpu < cpus; cpu++) | ||
514 | add_cpu_plot(ginfo, cpu); | ||
422 | } | 515 | } |
diff --git a/trace-plot-task.c b/trace-plot-task.c index b36d565..a5b8d79 100644 --- a/trace-plot-task.c +++ b/trace-plot-task.c | |||
@@ -632,7 +632,8 @@ void graph_plot_init_tasks(struct graph_info *ginfo) | |||
632 | task_info->pid = pid; | 632 | task_info->pid = pid; |
633 | 633 | ||
634 | snprintf(label, 100, "TASK %d", pid); | 634 | snprintf(label, 100, "TASK %d", pid); |
635 | trace_graph_plot_insert(ginfo, 1, label, &task_plot_cb, task_info); | 635 | trace_graph_plot_insert(ginfo, 1, label, PLOT_TYPE_TASK, |
636 | &task_plot_cb, task_info); | ||
636 | } | 637 | } |
637 | 638 | ||
638 | void graph_plot_task(struct graph_info *ginfo, int pid, int pos) | 639 | void graph_plot_task(struct graph_info *ginfo, int pid, int pos) |
@@ -650,7 +651,8 @@ void graph_plot_task(struct graph_info *ginfo, int pid, int pos) | |||
650 | len = strlen(comm) + 100; | 651 | len = strlen(comm) + 100; |
651 | label = malloc_or_die(len); | 652 | label = malloc_or_die(len); |
652 | snprintf(label, len, "%s-%d", comm, pid); | 653 | snprintf(label, len, "%s-%d", comm, pid); |
653 | plot = trace_graph_plot_insert(ginfo, pos, label, &task_plot_cb, task_info); | 654 | plot = trace_graph_plot_insert(ginfo, pos, label, PLOT_TYPE_TASK, |
655 | &task_plot_cb, task_info); | ||
654 | free(label); | 656 | free(label); |
655 | 657 | ||
656 | trace_graph_plot_add_all_recs(ginfo, plot); | 658 | trace_graph_plot_add_all_recs(ginfo, plot); |
diff --git a/trace-plot.c b/trace-plot.c index 8376814..f8e23c0 100644 --- a/trace-plot.c +++ b/trace-plot.c | |||
@@ -75,13 +75,14 @@ allocate_plot(struct graph_info *ginfo, | |||
75 | 75 | ||
76 | struct graph_plot * | 76 | struct graph_plot * |
77 | trace_graph_plot_append(struct graph_info *ginfo, | 77 | trace_graph_plot_append(struct graph_info *ginfo, |
78 | const char *label, const struct plot_callbacks *cb, | 78 | const char *label, enum graph_plot_type type, |
79 | void *data) | 79 | const struct plot_callbacks *cb, void *data) |
80 | { | 80 | { |
81 | struct graph_plot *plot; | 81 | struct graph_plot *plot; |
82 | 82 | ||
83 | plot = allocate_plot(ginfo, label, cb, data); | 83 | plot = allocate_plot(ginfo, label, cb, data); |
84 | 84 | ||
85 | plot->type = type; | ||
85 | plot->pos = ginfo->plots; | 86 | plot->pos = ginfo->plots; |
86 | 87 | ||
87 | if (!ginfo->plots) { | 88 | if (!ginfo->plots) { |
@@ -105,21 +106,21 @@ trace_graph_plot_append(struct graph_info *ginfo, | |||
105 | 106 | ||
106 | struct graph_plot * | 107 | struct graph_plot * |
107 | trace_graph_plot_insert(struct graph_info *ginfo, | 108 | trace_graph_plot_insert(struct graph_info *ginfo, |
108 | int pos, | 109 | int pos, const char *label, enum graph_plot_type type, |
109 | const char *label, const struct plot_callbacks *cb, | 110 | const struct plot_callbacks *cb, void *data) |
110 | void *data) | ||
111 | { | 111 | { |
112 | struct graph_plot *plot; | 112 | struct graph_plot *plot; |
113 | int i; | 113 | int i; |
114 | 114 | ||
115 | if (pos >= ginfo->plots) | 115 | if (pos >= ginfo->plots) |
116 | return trace_graph_plot_append(ginfo, label, cb, data); | 116 | return trace_graph_plot_append(ginfo, label, type, cb, data); |
117 | 117 | ||
118 | if (pos < 0) | 118 | if (pos < 0) |
119 | pos = 0; | 119 | pos = 0; |
120 | 120 | ||
121 | plot = allocate_plot(ginfo, label, cb, data); | 121 | plot = allocate_plot(ginfo, label, cb, data); |
122 | plot->pos = pos; | 122 | plot->pos = pos; |
123 | plot->type = type; | ||
123 | ginfo->plot_array = realloc(ginfo->plot_array, | 124 | ginfo->plot_array = realloc(ginfo->plot_array, |
124 | sizeof(ginfo->plot_array[0]) * | 125 | sizeof(ginfo->plot_array[0]) * |
125 | (ginfo->plots + 1)); | 126 | (ginfo->plots + 1)); |