diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/Makefile | 2 | ||||
-rw-r--r-- | tools/perf/util/newt.c | 34 | ||||
-rw-r--r-- | tools/perf/util/pstack.c | 75 | ||||
-rw-r--r-- | tools/perf/util/pstack.h | 12 |
4 files changed, 120 insertions, 3 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 9c4dc30cdc13..a9281cca4114 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -416,6 +416,7 @@ LIB_H += util/thread.h | |||
416 | LIB_H += util/trace-event.h | 416 | LIB_H += util/trace-event.h |
417 | LIB_H += util/probe-finder.h | 417 | LIB_H += util/probe-finder.h |
418 | LIB_H += util/probe-event.h | 418 | LIB_H += util/probe-event.h |
419 | LIB_H += util/pstack.h | ||
419 | LIB_H += util/cpumap.h | 420 | LIB_H += util/cpumap.h |
420 | 421 | ||
421 | LIB_OBJS += $(OUTPUT)util/abspath.o | 422 | LIB_OBJS += $(OUTPUT)util/abspath.o |
@@ -451,6 +452,7 @@ LIB_OBJS += $(OUTPUT)util/callchain.o | |||
451 | LIB_OBJS += $(OUTPUT)util/values.o | 452 | LIB_OBJS += $(OUTPUT)util/values.o |
452 | LIB_OBJS += $(OUTPUT)util/debug.o | 453 | LIB_OBJS += $(OUTPUT)util/debug.o |
453 | LIB_OBJS += $(OUTPUT)util/map.o | 454 | LIB_OBJS += $(OUTPUT)util/map.o |
455 | LIB_OBJS += $(OUTPUT)util/pstack.o | ||
454 | LIB_OBJS += $(OUTPUT)util/session.o | 456 | LIB_OBJS += $(OUTPUT)util/session.o |
455 | LIB_OBJS += $(OUTPUT)util/thread.o | 457 | LIB_OBJS += $(OUTPUT)util/thread.o |
456 | LIB_OBJS += $(OUTPUT)util/trace-event-parse.o | 458 | LIB_OBJS += $(OUTPUT)util/trace-event-parse.o |
diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c index 3402453812b3..e74df1240ef6 100644 --- a/tools/perf/util/newt.c +++ b/tools/perf/util/newt.c | |||
@@ -9,6 +9,7 @@ | |||
9 | 9 | ||
10 | #include "cache.h" | 10 | #include "cache.h" |
11 | #include "hist.h" | 11 | #include "hist.h" |
12 | #include "pstack.h" | ||
12 | #include "session.h" | 13 | #include "session.h" |
13 | #include "sort.h" | 14 | #include "sort.h" |
14 | #include "symbol.h" | 15 | #include "symbol.h" |
@@ -750,6 +751,7 @@ static int hist_browser__populate(struct hist_browser *self, struct hists *hists | |||
750 | newtFormAddHotKey(self->form, 'A'); | 751 | newtFormAddHotKey(self->form, 'A'); |
751 | newtFormAddHotKey(self->form, 'a'); | 752 | newtFormAddHotKey(self->form, 'a'); |
752 | newtFormAddHotKey(self->form, NEWT_KEY_RIGHT); | 753 | newtFormAddHotKey(self->form, NEWT_KEY_RIGHT); |
754 | newtFormAddHotKey(self->form, NEWT_KEY_LEFT); | ||
753 | newtFormAddComponents(self->form, self->tree, NULL); | 755 | newtFormAddComponents(self->form, self->tree, NULL); |
754 | self->selection = newt__symbol_tree_get_current(self->tree); | 756 | self->selection = newt__symbol_tree_get_current(self->tree); |
755 | 757 | ||
@@ -801,6 +803,7 @@ static int hist_browser__title(char *bf, size_t size, const char *input_name, | |||
801 | int hists__browse(struct hists *self, const char *helpline, const char *input_name) | 803 | int hists__browse(struct hists *self, const char *helpline, const char *input_name) |
802 | { | 804 | { |
803 | struct hist_browser *browser = hist_browser__new(); | 805 | struct hist_browser *browser = hist_browser__new(); |
806 | struct pstack *fstack = pstack__new(2); | ||
804 | const struct thread *thread_filter = NULL; | 807 | const struct thread *thread_filter = NULL; |
805 | const struct dso *dso_filter = NULL; | 808 | const struct dso *dso_filter = NULL; |
806 | struct newtExitStruct es; | 809 | struct newtExitStruct es; |
@@ -810,12 +813,16 @@ int hists__browse(struct hists *self, const char *helpline, const char *input_na | |||
810 | if (browser == NULL) | 813 | if (browser == NULL) |
811 | return -1; | 814 | return -1; |
812 | 815 | ||
816 | fstack = pstack__new(2); | ||
817 | if (fstack == NULL) | ||
818 | goto out; | ||
819 | |||
813 | ui_helpline__push(helpline); | 820 | ui_helpline__push(helpline); |
814 | 821 | ||
815 | hist_browser__title(msg, sizeof(msg), input_name, | 822 | hist_browser__title(msg, sizeof(msg), input_name, |
816 | dso_filter, thread_filter); | 823 | dso_filter, thread_filter); |
817 | if (hist_browser__populate(browser, self, msg) < 0) | 824 | if (hist_browser__populate(browser, self, msg) < 0) |
818 | goto out; | 825 | goto out_free_stack; |
819 | 826 | ||
820 | while (1) { | 827 | while (1) { |
821 | const struct thread *thread; | 828 | const struct thread *thread; |
@@ -836,6 +843,19 @@ int hists__browse(struct hists *self, const char *helpline, const char *input_na | |||
836 | else | 843 | else |
837 | continue; | 844 | continue; |
838 | } | 845 | } |
846 | |||
847 | if (es.u.key == NEWT_KEY_LEFT) { | ||
848 | const void *top; | ||
849 | |||
850 | if (pstack__empty(fstack)) | ||
851 | continue; | ||
852 | top = pstack__pop(fstack); | ||
853 | if (top == &dso_filter) | ||
854 | goto zoom_out_dso; | ||
855 | if (top == &thread_filter) | ||
856 | goto zoom_out_thread; | ||
857 | continue; | ||
858 | } | ||
839 | } | 859 | } |
840 | 860 | ||
841 | if (browser->selection->sym != NULL && | 861 | if (browser->selection->sym != NULL && |
@@ -888,12 +908,15 @@ do_annotate: | |||
888 | hist_entry__annotate_browser(he); | 908 | hist_entry__annotate_browser(he); |
889 | } else if (choice == zoom_dso) { | 909 | } else if (choice == zoom_dso) { |
890 | if (dso_filter) { | 910 | if (dso_filter) { |
911 | pstack__remove(fstack, &dso_filter); | ||
912 | zoom_out_dso: | ||
891 | ui_helpline__pop(); | 913 | ui_helpline__pop(); |
892 | dso_filter = NULL; | 914 | dso_filter = NULL; |
893 | } else { | 915 | } else { |
894 | ui_helpline__fpush("To zoom out press -> + \"Zoom out of %s DSO\"", | 916 | ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s DSO\"", |
895 | dso->kernel ? "the Kernel" : dso->short_name); | 917 | dso->kernel ? "the Kernel" : dso->short_name); |
896 | dso_filter = dso; | 918 | dso_filter = dso; |
919 | pstack__push(fstack, &dso_filter); | ||
897 | } | 920 | } |
898 | hists__filter_by_dso(self, dso_filter); | 921 | hists__filter_by_dso(self, dso_filter); |
899 | hist_browser__title(msg, sizeof(msg), input_name, | 922 | hist_browser__title(msg, sizeof(msg), input_name, |
@@ -902,13 +925,16 @@ do_annotate: | |||
902 | goto out; | 925 | goto out; |
903 | } else if (choice == zoom_thread) { | 926 | } else if (choice == zoom_thread) { |
904 | if (thread_filter) { | 927 | if (thread_filter) { |
928 | pstack__remove(fstack, &thread_filter); | ||
929 | zoom_out_thread: | ||
905 | ui_helpline__pop(); | 930 | ui_helpline__pop(); |
906 | thread_filter = NULL; | 931 | thread_filter = NULL; |
907 | } else { | 932 | } else { |
908 | ui_helpline__fpush("To zoom out press -> + \"Zoom out of %s(%d) thread\"", | 933 | ui_helpline__fpush("To zoom out press <- or -> + \"Zoom out of %s(%d) thread\"", |
909 | thread->comm_set ? thread->comm : "", | 934 | thread->comm_set ? thread->comm : "", |
910 | thread->pid); | 935 | thread->pid); |
911 | thread_filter = thread; | 936 | thread_filter = thread; |
937 | pstack__push(fstack, &thread_filter); | ||
912 | } | 938 | } |
913 | hists__filter_by_thread(self, thread_filter); | 939 | hists__filter_by_thread(self, thread_filter); |
914 | hist_browser__title(msg, sizeof(msg), input_name, | 940 | hist_browser__title(msg, sizeof(msg), input_name, |
@@ -918,6 +944,8 @@ do_annotate: | |||
918 | } | 944 | } |
919 | } | 945 | } |
920 | err = 0; | 946 | err = 0; |
947 | out_free_stack: | ||
948 | pstack__delete(fstack); | ||
921 | out: | 949 | out: |
922 | hist_browser__delete(browser); | 950 | hist_browser__delete(browser); |
923 | return err; | 951 | return err; |
diff --git a/tools/perf/util/pstack.c b/tools/perf/util/pstack.c new file mode 100644 index 000000000000..13d36faf64eb --- /dev/null +++ b/tools/perf/util/pstack.c | |||
@@ -0,0 +1,75 @@ | |||
1 | /* | ||
2 | * Simple pointer stack | ||
3 | * | ||
4 | * (c) 2010 Arnaldo Carvalho de Melo <acme@redhat.com> | ||
5 | */ | ||
6 | |||
7 | #include "util.h" | ||
8 | #include "pstack.h" | ||
9 | #include <linux/kernel.h> | ||
10 | #include <stdlib.h> | ||
11 | |||
12 | struct pstack { | ||
13 | unsigned short top; | ||
14 | unsigned short max_nr_entries; | ||
15 | void *entries[0]; | ||
16 | }; | ||
17 | |||
18 | struct pstack *pstack__new(unsigned short max_nr_entries) | ||
19 | { | ||
20 | struct pstack *self = zalloc((sizeof(*self) + | ||
21 | max_nr_entries * sizeof(void *))); | ||
22 | if (self != NULL) | ||
23 | self->max_nr_entries = max_nr_entries; | ||
24 | return self; | ||
25 | } | ||
26 | |||
27 | void pstack__delete(struct pstack *self) | ||
28 | { | ||
29 | free(self); | ||
30 | } | ||
31 | |||
32 | bool pstack__empty(const struct pstack *self) | ||
33 | { | ||
34 | return self->top == 0; | ||
35 | } | ||
36 | |||
37 | void pstack__remove(struct pstack *self, void *key) | ||
38 | { | ||
39 | unsigned short i = self->top, last_index = self->top - 1; | ||
40 | |||
41 | while (i-- != 0) { | ||
42 | if (self->entries[i] == key) { | ||
43 | if (i < last_index) | ||
44 | memmove(self->entries + i, | ||
45 | self->entries + i + 1, | ||
46 | (last_index - i) * sizeof(void *)); | ||
47 | --self->top; | ||
48 | return; | ||
49 | } | ||
50 | } | ||
51 | pr_err("%s: %p not on the pstack!\n", __func__, key); | ||
52 | } | ||
53 | |||
54 | void pstack__push(struct pstack *self, void *key) | ||
55 | { | ||
56 | if (self->top == self->max_nr_entries) { | ||
57 | pr_err("%s: top=%d, overflow!\n", __func__, self->top); | ||
58 | return; | ||
59 | } | ||
60 | self->entries[self->top++] = key; | ||
61 | } | ||
62 | |||
63 | void *pstack__pop(struct pstack *self) | ||
64 | { | ||
65 | void *ret; | ||
66 | |||
67 | if (self->top == 0) { | ||
68 | pr_err("%s: underflow!\n", __func__); | ||
69 | return NULL; | ||
70 | } | ||
71 | |||
72 | ret = self->entries[--self->top]; | ||
73 | self->entries[self->top] = NULL; | ||
74 | return ret; | ||
75 | } | ||
diff --git a/tools/perf/util/pstack.h b/tools/perf/util/pstack.h new file mode 100644 index 000000000000..5ad07023504b --- /dev/null +++ b/tools/perf/util/pstack.h | |||
@@ -0,0 +1,12 @@ | |||
1 | #ifndef _PERF_PSTACK_ | ||
2 | #define _PERF_PSTACK_ | ||
3 | |||
4 | struct pstack; | ||
5 | struct pstack *pstack__new(unsigned short max_nr_entries); | ||
6 | void pstack__delete(struct pstack *self); | ||
7 | bool pstack__empty(const struct pstack *self); | ||
8 | void pstack__remove(struct pstack *self, void *key); | ||
9 | void pstack__push(struct pstack *self, void *key); | ||
10 | void *pstack__pop(struct pstack *self); | ||
11 | |||
12 | #endif /* _PERF_PSTACK_ */ | ||