diff options
Diffstat (limited to 'tools')
242 files changed, 8986 insertions, 3151 deletions
diff --git a/tools/Makefile b/tools/Makefile index 60c7e6c8ff17..6bf68fe7dd29 100644 --- a/tools/Makefile +++ b/tools/Makefile | |||
@@ -137,7 +137,8 @@ libsubcmd_clean: | |||
137 | $(call descend,lib/subcmd,clean) | 137 | $(call descend,lib/subcmd,clean) |
138 | 138 | ||
139 | perf_clean: | 139 | perf_clean: |
140 | $(call descend,$(@:_clean=),clean) | 140 | $(Q)mkdir -p $(PERF_O) . |
141 | $(Q)$(MAKE) --no-print-directory -C perf O=$(PERF_O) subdir= clean | ||
141 | 142 | ||
142 | selftests_clean: | 143 | selftests_clean: |
143 | $(call descend,testing/$(@:_clean=),clean) | 144 | $(call descend,testing/$(@:_clean=),clean) |
diff --git a/tools/build/Makefile.feature b/tools/build/Makefile.feature index 6b7707270aa3..57c8f98874e8 100644 --- a/tools/build/Makefile.feature +++ b/tools/build/Makefile.feature | |||
@@ -30,6 +30,7 @@ endef | |||
30 | FEATURE_TESTS_BASIC := \ | 30 | FEATURE_TESTS_BASIC := \ |
31 | backtrace \ | 31 | backtrace \ |
32 | dwarf \ | 32 | dwarf \ |
33 | dwarf_getlocations \ | ||
33 | fortify-source \ | 34 | fortify-source \ |
34 | sync-compare-and-swap \ | 35 | sync-compare-and-swap \ |
35 | glibc \ | 36 | glibc \ |
@@ -48,6 +49,10 @@ FEATURE_TESTS_BASIC := \ | |||
48 | libslang \ | 49 | libslang \ |
49 | libcrypto \ | 50 | libcrypto \ |
50 | libunwind \ | 51 | libunwind \ |
52 | libunwind-x86 \ | ||
53 | libunwind-x86_64 \ | ||
54 | libunwind-arm \ | ||
55 | libunwind-aarch64 \ | ||
51 | pthread-attr-setaffinity-np \ | 56 | pthread-attr-setaffinity-np \ |
52 | stackprotector-all \ | 57 | stackprotector-all \ |
53 | timerfd \ | 58 | timerfd \ |
@@ -68,7 +73,9 @@ FEATURE_TESTS_EXTRA := \ | |||
68 | libbabeltrace \ | 73 | libbabeltrace \ |
69 | liberty \ | 74 | liberty \ |
70 | liberty-z \ | 75 | liberty-z \ |
71 | libunwind-debug-frame | 76 | libunwind-debug-frame \ |
77 | libunwind-debug-frame-arm \ | ||
78 | libunwind-debug-frame-aarch64 | ||
72 | 79 | ||
73 | FEATURE_TESTS ?= $(FEATURE_TESTS_BASIC) | 80 | FEATURE_TESTS ?= $(FEATURE_TESTS_BASIC) |
74 | 81 | ||
@@ -78,6 +85,7 @@ endif | |||
78 | 85 | ||
79 | FEATURE_DISPLAY ?= \ | 86 | FEATURE_DISPLAY ?= \ |
80 | dwarf \ | 87 | dwarf \ |
88 | dwarf_getlocations \ | ||
81 | glibc \ | 89 | glibc \ |
82 | gtk2 \ | 90 | gtk2 \ |
83 | libaudit \ | 91 | libaudit \ |
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile index c5f4c417428d..3d88f09e188b 100644 --- a/tools/build/feature/Makefile +++ b/tools/build/feature/Makefile | |||
@@ -3,6 +3,7 @@ FILES= \ | |||
3 | test-backtrace.bin \ | 3 | test-backtrace.bin \ |
4 | test-bionic.bin \ | 4 | test-bionic.bin \ |
5 | test-dwarf.bin \ | 5 | test-dwarf.bin \ |
6 | test-dwarf_getlocations.bin \ | ||
6 | test-fortify-source.bin \ | 7 | test-fortify-source.bin \ |
7 | test-sync-compare-and-swap.bin \ | 8 | test-sync-compare-and-swap.bin \ |
8 | test-glibc.bin \ | 9 | test-glibc.bin \ |
@@ -26,6 +27,12 @@ FILES= \ | |||
26 | test-libcrypto.bin \ | 27 | test-libcrypto.bin \ |
27 | test-libunwind.bin \ | 28 | test-libunwind.bin \ |
28 | test-libunwind-debug-frame.bin \ | 29 | test-libunwind-debug-frame.bin \ |
30 | test-libunwind-x86.bin \ | ||
31 | test-libunwind-x86_64.bin \ | ||
32 | test-libunwind-arm.bin \ | ||
33 | test-libunwind-aarch64.bin \ | ||
34 | test-libunwind-debug-frame-arm.bin \ | ||
35 | test-libunwind-debug-frame-aarch64.bin \ | ||
29 | test-pthread-attr-setaffinity-np.bin \ | 36 | test-pthread-attr-setaffinity-np.bin \ |
30 | test-stackprotector-all.bin \ | 37 | test-stackprotector-all.bin \ |
31 | test-timerfd.bin \ | 38 | test-timerfd.bin \ |
@@ -82,6 +89,9 @@ endif | |||
82 | $(OUTPUT)test-dwarf.bin: | 89 | $(OUTPUT)test-dwarf.bin: |
83 | $(BUILD) $(DWARFLIBS) | 90 | $(BUILD) $(DWARFLIBS) |
84 | 91 | ||
92 | $(OUTPUT)test-dwarf_getlocations.bin: | ||
93 | $(BUILD) $(DWARFLIBS) | ||
94 | |||
85 | $(OUTPUT)test-libelf-mmap.bin: | 95 | $(OUTPUT)test-libelf-mmap.bin: |
86 | $(BUILD) -lelf | 96 | $(BUILD) -lelf |
87 | 97 | ||
@@ -99,6 +109,23 @@ $(OUTPUT)test-libunwind.bin: | |||
99 | 109 | ||
100 | $(OUTPUT)test-libunwind-debug-frame.bin: | 110 | $(OUTPUT)test-libunwind-debug-frame.bin: |
101 | $(BUILD) -lelf | 111 | $(BUILD) -lelf |
112 | $(OUTPUT)test-libunwind-x86.bin: | ||
113 | $(BUILD) -lelf -lunwind-x86 | ||
114 | |||
115 | $(OUTPUT)test-libunwind-x86_64.bin: | ||
116 | $(BUILD) -lelf -lunwind-x86_64 | ||
117 | |||
118 | $(OUTPUT)test-libunwind-arm.bin: | ||
119 | $(BUILD) -lelf -lunwind-arm | ||
120 | |||
121 | $(OUTPUT)test-libunwind-aarch64.bin: | ||
122 | $(BUILD) -lelf -lunwind-aarch64 | ||
123 | |||
124 | $(OUTPUT)test-libunwind-debug-frame-arm.bin: | ||
125 | $(BUILD) -lelf -lunwind-arm | ||
126 | |||
127 | $(OUTPUT)test-libunwind-debug-frame-aarch64.bin: | ||
128 | $(BUILD) -lelf -lunwind-aarch64 | ||
102 | 129 | ||
103 | $(OUTPUT)test-libaudit.bin: | 130 | $(OUTPUT)test-libaudit.bin: |
104 | $(BUILD) -laudit | 131 | $(BUILD) -laudit |
diff --git a/tools/build/feature/test-all.c b/tools/build/feature/test-all.c index e499a36c1e4a..a282e8cb84f3 100644 --- a/tools/build/feature/test-all.c +++ b/tools/build/feature/test-all.c | |||
@@ -41,6 +41,10 @@ | |||
41 | # include "test-dwarf.c" | 41 | # include "test-dwarf.c" |
42 | #undef main | 42 | #undef main |
43 | 43 | ||
44 | #define main main_test_dwarf_getlocations | ||
45 | # include "test-dwarf_getlocations.c" | ||
46 | #undef main | ||
47 | |||
44 | #define main main_test_libelf_getphdrnum | 48 | #define main main_test_libelf_getphdrnum |
45 | # include "test-libelf-getphdrnum.c" | 49 | # include "test-libelf-getphdrnum.c" |
46 | #undef main | 50 | #undef main |
@@ -143,6 +147,7 @@ int main(int argc, char *argv[]) | |||
143 | main_test_libelf_mmap(); | 147 | main_test_libelf_mmap(); |
144 | main_test_glibc(); | 148 | main_test_glibc(); |
145 | main_test_dwarf(); | 149 | main_test_dwarf(); |
150 | main_test_dwarf_getlocations(); | ||
146 | main_test_libelf_getphdrnum(); | 151 | main_test_libelf_getphdrnum(); |
147 | main_test_libunwind(); | 152 | main_test_libunwind(); |
148 | main_test_libaudit(); | 153 | main_test_libaudit(); |
diff --git a/tools/build/feature/test-bpf.c b/tools/build/feature/test-bpf.c index b389026839b9..e04ab89a1013 100644 --- a/tools/build/feature/test-bpf.c +++ b/tools/build/feature/test-bpf.c | |||
@@ -27,10 +27,9 @@ int main(void) | |||
27 | attr.log_level = 0; | 27 | attr.log_level = 0; |
28 | attr.kern_version = 0; | 28 | attr.kern_version = 0; |
29 | 29 | ||
30 | attr = attr; | ||
31 | /* | 30 | /* |
32 | * Test existence of __NR_bpf and BPF_PROG_LOAD. | 31 | * Test existence of __NR_bpf and BPF_PROG_LOAD. |
33 | * This call should fail if we run the testcase. | 32 | * This call should fail if we run the testcase. |
34 | */ | 33 | */ |
35 | return syscall(__NR_bpf, BPF_PROG_LOAD, attr, sizeof(attr)); | 34 | return syscall(__NR_bpf, BPF_PROG_LOAD, &attr, sizeof(attr)); |
36 | } | 35 | } |
diff --git a/tools/build/feature/test-dwarf_getlocations.c b/tools/build/feature/test-dwarf_getlocations.c new file mode 100644 index 000000000000..70162699dd43 --- /dev/null +++ b/tools/build/feature/test-dwarf_getlocations.c | |||
@@ -0,0 +1,12 @@ | |||
1 | #include <stdlib.h> | ||
2 | #include <elfutils/libdw.h> | ||
3 | |||
4 | int main(void) | ||
5 | { | ||
6 | Dwarf_Addr base, start, end; | ||
7 | Dwarf_Attribute attr; | ||
8 | Dwarf_Op *op; | ||
9 | size_t nops; | ||
10 | ptrdiff_t offset = 0; | ||
11 | return (int)dwarf_getlocations(&attr, offset, &base, &start, &end, &op, &nops); | ||
12 | } | ||
diff --git a/tools/build/feature/test-libunwind-aarch64.c b/tools/build/feature/test-libunwind-aarch64.c new file mode 100644 index 000000000000..fc03fb64e8c1 --- /dev/null +++ b/tools/build/feature/test-libunwind-aarch64.c | |||
@@ -0,0 +1,26 @@ | |||
1 | #include <libunwind-aarch64.h> | ||
2 | #include <stdlib.h> | ||
3 | |||
4 | extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, | ||
5 | unw_word_t ip, | ||
6 | unw_dyn_info_t *di, | ||
7 | unw_proc_info_t *pi, | ||
8 | int need_unwind_info, void *arg); | ||
9 | |||
10 | #define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) | ||
11 | |||
12 | static unw_accessors_t accessors; | ||
13 | |||
14 | int main(void) | ||
15 | { | ||
16 | unw_addr_space_t addr_space; | ||
17 | |||
18 | addr_space = unw_create_addr_space(&accessors, 0); | ||
19 | if (addr_space) | ||
20 | return 0; | ||
21 | |||
22 | unw_init_remote(NULL, addr_space, NULL); | ||
23 | dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL); | ||
24 | |||
25 | return 0; | ||
26 | } | ||
diff --git a/tools/build/feature/test-libunwind-arm.c b/tools/build/feature/test-libunwind-arm.c new file mode 100644 index 000000000000..632d95ec641f --- /dev/null +++ b/tools/build/feature/test-libunwind-arm.c | |||
@@ -0,0 +1,27 @@ | |||
1 | #include <libunwind-arm.h> | ||
2 | #include <stdlib.h> | ||
3 | |||
4 | extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, | ||
5 | unw_word_t ip, | ||
6 | unw_dyn_info_t *di, | ||
7 | unw_proc_info_t *pi, | ||
8 | int need_unwind_info, void *arg); | ||
9 | |||
10 | |||
11 | #define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) | ||
12 | |||
13 | static unw_accessors_t accessors; | ||
14 | |||
15 | int main(void) | ||
16 | { | ||
17 | unw_addr_space_t addr_space; | ||
18 | |||
19 | addr_space = unw_create_addr_space(&accessors, 0); | ||
20 | if (addr_space) | ||
21 | return 0; | ||
22 | |||
23 | unw_init_remote(NULL, addr_space, NULL); | ||
24 | dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL); | ||
25 | |||
26 | return 0; | ||
27 | } | ||
diff --git a/tools/build/feature/test-libunwind-debug-frame-aarch64.c b/tools/build/feature/test-libunwind-debug-frame-aarch64.c new file mode 100644 index 000000000000..22844673fc26 --- /dev/null +++ b/tools/build/feature/test-libunwind-debug-frame-aarch64.c | |||
@@ -0,0 +1,16 @@ | |||
1 | #include <libunwind-aarch64.h> | ||
2 | #include <stdlib.h> | ||
3 | |||
4 | extern int | ||
5 | UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug, | ||
6 | unw_word_t ip, unw_word_t segbase, | ||
7 | const char *obj_name, unw_word_t start, | ||
8 | unw_word_t end); | ||
9 | |||
10 | #define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) | ||
11 | |||
12 | int main(void) | ||
13 | { | ||
14 | dwarf_find_debug_frame(0, NULL, 0, 0, NULL, 0, 0); | ||
15 | return 0; | ||
16 | } | ||
diff --git a/tools/build/feature/test-libunwind-debug-frame-arm.c b/tools/build/feature/test-libunwind-debug-frame-arm.c new file mode 100644 index 000000000000..f98859684fee --- /dev/null +++ b/tools/build/feature/test-libunwind-debug-frame-arm.c | |||
@@ -0,0 +1,16 @@ | |||
1 | #include <libunwind-arm.h> | ||
2 | #include <stdlib.h> | ||
3 | |||
4 | extern int | ||
5 | UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug, | ||
6 | unw_word_t ip, unw_word_t segbase, | ||
7 | const char *obj_name, unw_word_t start, | ||
8 | unw_word_t end); | ||
9 | |||
10 | #define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame) | ||
11 | |||
12 | int main(void) | ||
13 | { | ||
14 | dwarf_find_debug_frame(0, NULL, 0, 0, NULL, 0, 0); | ||
15 | return 0; | ||
16 | } | ||
diff --git a/tools/build/feature/test-libunwind-x86.c b/tools/build/feature/test-libunwind-x86.c new file mode 100644 index 000000000000..3561edce305e --- /dev/null +++ b/tools/build/feature/test-libunwind-x86.c | |||
@@ -0,0 +1,27 @@ | |||
1 | #include <libunwind-x86.h> | ||
2 | #include <stdlib.h> | ||
3 | |||
4 | extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, | ||
5 | unw_word_t ip, | ||
6 | unw_dyn_info_t *di, | ||
7 | unw_proc_info_t *pi, | ||
8 | int need_unwind_info, void *arg); | ||
9 | |||
10 | |||
11 | #define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) | ||
12 | |||
13 | static unw_accessors_t accessors; | ||
14 | |||
15 | int main(void) | ||
16 | { | ||
17 | unw_addr_space_t addr_space; | ||
18 | |||
19 | addr_space = unw_create_addr_space(&accessors, 0); | ||
20 | if (addr_space) | ||
21 | return 0; | ||
22 | |||
23 | unw_init_remote(NULL, addr_space, NULL); | ||
24 | dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL); | ||
25 | |||
26 | return 0; | ||
27 | } | ||
diff --git a/tools/build/feature/test-libunwind-x86_64.c b/tools/build/feature/test-libunwind-x86_64.c new file mode 100644 index 000000000000..5add2517b2a1 --- /dev/null +++ b/tools/build/feature/test-libunwind-x86_64.c | |||
@@ -0,0 +1,27 @@ | |||
1 | #include <libunwind-x86_64.h> | ||
2 | #include <stdlib.h> | ||
3 | |||
4 | extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, | ||
5 | unw_word_t ip, | ||
6 | unw_dyn_info_t *di, | ||
7 | unw_proc_info_t *pi, | ||
8 | int need_unwind_info, void *arg); | ||
9 | |||
10 | |||
11 | #define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table) | ||
12 | |||
13 | static unw_accessors_t accessors; | ||
14 | |||
15 | int main(void) | ||
16 | { | ||
17 | unw_addr_space_t addr_space; | ||
18 | |||
19 | addr_space = unw_create_addr_space(&accessors, 0); | ||
20 | if (addr_space) | ||
21 | return 0; | ||
22 | |||
23 | unw_init_remote(NULL, addr_space, NULL); | ||
24 | dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL); | ||
25 | |||
26 | return 0; | ||
27 | } | ||
diff --git a/tools/gpio/Makefile b/tools/gpio/Makefile index 4d198d5c4203..c155d6bc47a7 100644 --- a/tools/gpio/Makefile +++ b/tools/gpio/Makefile | |||
@@ -1,5 +1,5 @@ | |||
1 | CC = $(CROSS_COMPILE)gcc | 1 | CC = $(CROSS_COMPILE)gcc |
2 | CFLAGS += -Wall -g -D_GNU_SOURCE | 2 | CFLAGS += -O2 -Wall -g -D_GNU_SOURCE |
3 | 3 | ||
4 | all: lsgpio | 4 | all: lsgpio |
5 | 5 | ||
diff --git a/tools/gpio/lsgpio.c b/tools/gpio/lsgpio.c index 1124da375942..eb3f56efd215 100644 --- a/tools/gpio/lsgpio.c +++ b/tools/gpio/lsgpio.c | |||
@@ -147,7 +147,7 @@ void print_usage(void) | |||
147 | 147 | ||
148 | int main(int argc, char **argv) | 148 | int main(int argc, char **argv) |
149 | { | 149 | { |
150 | const char *device_name; | 150 | const char *device_name = NULL; |
151 | int ret; | 151 | int ret; |
152 | int c; | 152 | int c; |
153 | 153 | ||
diff --git a/tools/lguest/lguest.c b/tools/lguest/lguest.c index 80159e6811c2..d9836c5eb694 100644 --- a/tools/lguest/lguest.c +++ b/tools/lguest/lguest.c | |||
@@ -3351,12 +3351,18 @@ int main(int argc, char *argv[]) | |||
3351 | /* Boot protocol version: 2.07 supports the fields for lguest. */ | 3351 | /* Boot protocol version: 2.07 supports the fields for lguest. */ |
3352 | boot->hdr.version = 0x207; | 3352 | boot->hdr.version = 0x207; |
3353 | 3353 | ||
3354 | /* The hardware_subarch value of "1" tells the Guest it's an lguest. */ | 3354 | /* X86_SUBARCH_LGUEST tells the Guest it's an lguest. */ |
3355 | boot->hdr.hardware_subarch = 1; | 3355 | boot->hdr.hardware_subarch = X86_SUBARCH_LGUEST; |
3356 | 3356 | ||
3357 | /* Tell the entry path not to try to reload segment registers. */ | 3357 | /* Tell the entry path not to try to reload segment registers. */ |
3358 | boot->hdr.loadflags |= KEEP_SEGMENTS; | 3358 | boot->hdr.loadflags |= KEEP_SEGMENTS; |
3359 | 3359 | ||
3360 | /* We don't support tboot: */ | ||
3361 | boot->tboot_addr = 0; | ||
3362 | |||
3363 | /* Ensure this is 0 to prevent APM from loading: */ | ||
3364 | boot->apm_bios_info.version = 0; | ||
3365 | |||
3360 | /* We tell the kernel to initialize the Guest. */ | 3366 | /* We tell the kernel to initialize the Guest. */ |
3361 | tell_kernel(start); | 3367 | tell_kernel(start); |
3362 | 3368 | ||
diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index ef78c22ff44d..08556cf2c70d 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c | |||
@@ -351,6 +351,19 @@ int filename__read_str(const char *filename, char **buf, size_t *sizep) | |||
351 | return err; | 351 | return err; |
352 | } | 352 | } |
353 | 353 | ||
354 | int procfs__read_str(const char *entry, char **buf, size_t *sizep) | ||
355 | { | ||
356 | char path[PATH_MAX]; | ||
357 | const char *procfs = procfs__mountpoint(); | ||
358 | |||
359 | if (!procfs) | ||
360 | return -1; | ||
361 | |||
362 | snprintf(path, sizeof(path), "%s/%s", procfs, entry); | ||
363 | |||
364 | return filename__read_str(path, buf, sizep); | ||
365 | } | ||
366 | |||
354 | int sysfs__read_ull(const char *entry, unsigned long long *value) | 367 | int sysfs__read_ull(const char *entry, unsigned long long *value) |
355 | { | 368 | { |
356 | char path[PATH_MAX]; | 369 | char path[PATH_MAX]; |
diff --git a/tools/lib/api/fs/fs.h b/tools/lib/api/fs/fs.h index 9f6598098dc5..16c9c2ed7c5b 100644 --- a/tools/lib/api/fs/fs.h +++ b/tools/lib/api/fs/fs.h | |||
@@ -29,6 +29,8 @@ int filename__read_int(const char *filename, int *value); | |||
29 | int filename__read_ull(const char *filename, unsigned long long *value); | 29 | int filename__read_ull(const char *filename, unsigned long long *value); |
30 | int filename__read_str(const char *filename, char **buf, size_t *sizep); | 30 | int filename__read_str(const char *filename, char **buf, size_t *sizep); |
31 | 31 | ||
32 | int procfs__read_str(const char *entry, char **buf, size_t *sizep); | ||
33 | |||
32 | int sysctl__read_int(const char *sysctl, int *value); | 34 | int sysctl__read_int(const char *sysctl, int *value); |
33 | int sysfs__read_int(const char *entry, int *value); | 35 | int sysfs__read_int(const char *entry, int *value); |
34 | int sysfs__read_ull(const char *entry, unsigned long long *value); | 36 | int sysfs__read_ull(const char *entry, unsigned long long *value); |
diff --git a/tools/lib/traceevent/parse-filter.c b/tools/lib/traceevent/parse-filter.c index 0144b3d1bb77..88cccea3ca99 100644 --- a/tools/lib/traceevent/parse-filter.c +++ b/tools/lib/traceevent/parse-filter.c | |||
@@ -1164,11 +1164,11 @@ process_filter(struct event_format *event, struct filter_arg **parg, | |||
1164 | current_op = current_exp; | 1164 | current_op = current_exp; |
1165 | 1165 | ||
1166 | ret = collapse_tree(current_op, parg, error_str); | 1166 | ret = collapse_tree(current_op, parg, error_str); |
1167 | /* collapse_tree() may free current_op, and updates parg accordingly */ | ||
1168 | current_op = NULL; | ||
1167 | if (ret < 0) | 1169 | if (ret < 0) |
1168 | goto fail; | 1170 | goto fail; |
1169 | 1171 | ||
1170 | *parg = current_op; | ||
1171 | |||
1172 | free(token); | 1172 | free(token); |
1173 | return 0; | 1173 | return 0; |
1174 | 1174 | ||
diff --git a/tools/net/bpf_jit_disasm.c b/tools/net/bpf_jit_disasm.c index 5b3241340945..544b05a53b70 100644 --- a/tools/net/bpf_jit_disasm.c +++ b/tools/net/bpf_jit_disasm.c | |||
@@ -98,6 +98,9 @@ static char *get_klog_buff(unsigned int *klen) | |||
98 | char *buff; | 98 | char *buff; |
99 | 99 | ||
100 | len = klogctl(CMD_ACTION_SIZE_BUFFER, NULL, 0); | 100 | len = klogctl(CMD_ACTION_SIZE_BUFFER, NULL, 0); |
101 | if (len < 0) | ||
102 | return NULL; | ||
103 | |||
101 | buff = malloc(len); | 104 | buff = malloc(len); |
102 | if (!buff) | 105 | if (!buff) |
103 | return NULL; | 106 | return NULL; |
diff --git a/tools/objtool/Documentation/stack-validation.txt b/tools/objtool/Documentation/stack-validation.txt index 5a95896105bc..55a60d331f47 100644 --- a/tools/objtool/Documentation/stack-validation.txt +++ b/tools/objtool/Documentation/stack-validation.txt | |||
@@ -299,18 +299,38 @@ they mean, and suggestions for how to fix them. | |||
299 | Errors in .c files | 299 | Errors in .c files |
300 | ------------------ | 300 | ------------------ |
301 | 301 | ||
302 | If you're getting an objtool error in a compiled .c file, chances are | 302 | 1. c_file.o: warning: objtool: funcA() falls through to next function funcB() |
303 | the file uses an asm() statement which has a "call" instruction. An | ||
304 | asm() statement with a call instruction must declare the use of the | ||
305 | stack pointer in its output operand. For example, on x86_64: | ||
306 | 303 | ||
307 | register void *__sp asm("rsp"); | 304 | This means that funcA() doesn't end with a return instruction or an |
308 | asm volatile("call func" : "+r" (__sp)); | 305 | unconditional jump, and that objtool has determined that the function |
306 | can fall through into the next function. There could be different | ||
307 | reasons for this: | ||
309 | 308 | ||
310 | Otherwise the stack frame may not get created before the call. | 309 | 1) funcA()'s last instruction is a call to a "noreturn" function like |
310 | panic(). In this case the noreturn function needs to be added to | ||
311 | objtool's hard-coded global_noreturns array. Feel free to bug the | ||
312 | objtool maintainer, or you can submit a patch. | ||
311 | 313 | ||
312 | Another possible cause for errors in C code is if the Makefile removes | 314 | 2) funcA() uses the unreachable() annotation in a section of code |
313 | -fno-omit-frame-pointer or adds -fomit-frame-pointer to the gcc options. | 315 | that is actually reachable. |
316 | |||
317 | 3) If funcA() calls an inline function, the object code for funcA() | ||
318 | might be corrupt due to a gcc bug. For more details, see: | ||
319 | https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70646 | ||
320 | |||
321 | 2. If you're getting any other objtool error in a compiled .c file, it | ||
322 | may be because the file uses an asm() statement which has a "call" | ||
323 | instruction. An asm() statement with a call instruction must declare | ||
324 | the use of the stack pointer in its output operand. For example, on | ||
325 | x86_64: | ||
326 | |||
327 | register void *__sp asm("rsp"); | ||
328 | asm volatile("call func" : "+r" (__sp)); | ||
329 | |||
330 | Otherwise the stack frame may not get created before the call. | ||
331 | |||
332 | 3. Another possible cause for errors in C code is if the Makefile removes | ||
333 | -fno-omit-frame-pointer or adds -fomit-frame-pointer to the gcc options. | ||
314 | 334 | ||
315 | Also see the above section for .S file errors for more information what | 335 | Also see the above section for .S file errors for more information what |
316 | the individual error messages mean. | 336 | the individual error messages mean. |
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index 7515cb2e879a..e8a1e69eb92c 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c | |||
@@ -54,6 +54,7 @@ struct instruction { | |||
54 | struct symbol *call_dest; | 54 | struct symbol *call_dest; |
55 | struct instruction *jump_dest; | 55 | struct instruction *jump_dest; |
56 | struct list_head alts; | 56 | struct list_head alts; |
57 | struct symbol *func; | ||
57 | }; | 58 | }; |
58 | 59 | ||
59 | struct alternative { | 60 | struct alternative { |
@@ -66,6 +67,7 @@ struct objtool_file { | |||
66 | struct list_head insn_list; | 67 | struct list_head insn_list; |
67 | DECLARE_HASHTABLE(insn_hash, 16); | 68 | DECLARE_HASHTABLE(insn_hash, 16); |
68 | struct section *rodata, *whitelist; | 69 | struct section *rodata, *whitelist; |
70 | bool ignore_unreachables, c_file; | ||
69 | }; | 71 | }; |
70 | 72 | ||
71 | const char *objname; | 73 | const char *objname; |
@@ -228,7 +230,7 @@ static int __dead_end_function(struct objtool_file *file, struct symbol *func, | |||
228 | } | 230 | } |
229 | } | 231 | } |
230 | 232 | ||
231 | if (insn->type == INSN_JUMP_DYNAMIC) | 233 | if (insn->type == INSN_JUMP_DYNAMIC && list_empty(&insn->alts)) |
232 | /* sibling call */ | 234 | /* sibling call */ |
233 | return 0; | 235 | return 0; |
234 | } | 236 | } |
@@ -248,6 +250,7 @@ static int dead_end_function(struct objtool_file *file, struct symbol *func) | |||
248 | static int decode_instructions(struct objtool_file *file) | 250 | static int decode_instructions(struct objtool_file *file) |
249 | { | 251 | { |
250 | struct section *sec; | 252 | struct section *sec; |
253 | struct symbol *func; | ||
251 | unsigned long offset; | 254 | unsigned long offset; |
252 | struct instruction *insn; | 255 | struct instruction *insn; |
253 | int ret; | 256 | int ret; |
@@ -281,6 +284,21 @@ static int decode_instructions(struct objtool_file *file) | |||
281 | hash_add(file->insn_hash, &insn->hash, insn->offset); | 284 | hash_add(file->insn_hash, &insn->hash, insn->offset); |
282 | list_add_tail(&insn->list, &file->insn_list); | 285 | list_add_tail(&insn->list, &file->insn_list); |
283 | } | 286 | } |
287 | |||
288 | list_for_each_entry(func, &sec->symbol_list, list) { | ||
289 | if (func->type != STT_FUNC) | ||
290 | continue; | ||
291 | |||
292 | if (!find_insn(file, sec, func->offset)) { | ||
293 | WARN("%s(): can't find starting instruction", | ||
294 | func->name); | ||
295 | return -1; | ||
296 | } | ||
297 | |||
298 | func_for_each_insn(file, func, insn) | ||
299 | if (!insn->func) | ||
300 | insn->func = func; | ||
301 | } | ||
284 | } | 302 | } |
285 | 303 | ||
286 | return 0; | 304 | return 0; |
@@ -664,13 +682,40 @@ static int add_func_switch_tables(struct objtool_file *file, | |||
664 | text_rela->addend); | 682 | text_rela->addend); |
665 | 683 | ||
666 | /* | 684 | /* |
667 | * TODO: Document where this is needed, or get rid of it. | ||
668 | * | ||
669 | * rare case: jmpq *[addr](%rip) | 685 | * rare case: jmpq *[addr](%rip) |
686 | * | ||
687 | * This check is for a rare gcc quirk, currently only seen in | ||
688 | * three driver functions in the kernel, only with certain | ||
689 | * obscure non-distro configs. | ||
690 | * | ||
691 | * As part of an optimization, gcc makes a copy of an existing | ||
692 | * switch jump table, modifies it, and then hard-codes the jump | ||
693 | * (albeit with an indirect jump) to use a single entry in the | ||
694 | * table. The rest of the jump table and some of its jump | ||
695 | * targets remain as dead code. | ||
696 | * | ||
697 | * In such a case we can just crudely ignore all unreachable | ||
698 | * instruction warnings for the entire object file. Ideally we | ||
699 | * would just ignore them for the function, but that would | ||
700 | * require redesigning the code quite a bit. And honestly | ||
701 | * that's just not worth doing: unreachable instruction | ||
702 | * warnings are of questionable value anyway, and this is such | ||
703 | * a rare issue. | ||
704 | * | ||
705 | * kbuild reports: | ||
706 | * - https://lkml.kernel.org/r/201603231906.LWcVUpxm%25fengguang.wu@intel.com | ||
707 | * - https://lkml.kernel.org/r/201603271114.K9i45biy%25fengguang.wu@intel.com | ||
708 | * - https://lkml.kernel.org/r/201603291058.zuJ6ben1%25fengguang.wu@intel.com | ||
709 | * | ||
710 | * gcc bug: | ||
711 | * - https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70604 | ||
670 | */ | 712 | */ |
671 | if (!rodata_rela) | 713 | if (!rodata_rela) { |
672 | rodata_rela = find_rela_by_dest(file->rodata, | 714 | rodata_rela = find_rela_by_dest(file->rodata, |
673 | text_rela->addend + 4); | 715 | text_rela->addend + 4); |
716 | if (rodata_rela) | ||
717 | file->ignore_unreachables = true; | ||
718 | } | ||
674 | 719 | ||
675 | if (!rodata_rela) | 720 | if (!rodata_rela) |
676 | continue; | 721 | continue; |
@@ -732,9 +777,6 @@ static int decode_sections(struct objtool_file *file) | |||
732 | { | 777 | { |
733 | int ret; | 778 | int ret; |
734 | 779 | ||
735 | file->whitelist = find_section_by_name(file->elf, "__func_stack_frame_non_standard"); | ||
736 | file->rodata = find_section_by_name(file->elf, ".rodata"); | ||
737 | |||
738 | ret = decode_instructions(file); | 780 | ret = decode_instructions(file); |
739 | if (ret) | 781 | if (ret) |
740 | return ret; | 782 | return ret; |
@@ -799,6 +841,7 @@ static int validate_branch(struct objtool_file *file, | |||
799 | struct alternative *alt; | 841 | struct alternative *alt; |
800 | struct instruction *insn; | 842 | struct instruction *insn; |
801 | struct section *sec; | 843 | struct section *sec; |
844 | struct symbol *func = NULL; | ||
802 | unsigned char state; | 845 | unsigned char state; |
803 | int ret; | 846 | int ret; |
804 | 847 | ||
@@ -813,6 +856,16 @@ static int validate_branch(struct objtool_file *file, | |||
813 | } | 856 | } |
814 | 857 | ||
815 | while (1) { | 858 | while (1) { |
859 | if (file->c_file && insn->func) { | ||
860 | if (func && func != insn->func) { | ||
861 | WARN("%s() falls through to next function %s()", | ||
862 | func->name, insn->func->name); | ||
863 | return 1; | ||
864 | } | ||
865 | |||
866 | func = insn->func; | ||
867 | } | ||
868 | |||
816 | if (insn->visited) { | 869 | if (insn->visited) { |
817 | if (frame_state(insn->state) != frame_state(state)) { | 870 | if (frame_state(insn->state) != frame_state(state)) { |
818 | WARN_FUNC("frame pointer state mismatch", | 871 | WARN_FUNC("frame pointer state mismatch", |
@@ -823,13 +876,6 @@ static int validate_branch(struct objtool_file *file, | |||
823 | return 0; | 876 | return 0; |
824 | } | 877 | } |
825 | 878 | ||
826 | /* | ||
827 | * Catch a rare case where a noreturn function falls through to | ||
828 | * the next function. | ||
829 | */ | ||
830 | if (is_fentry_call(insn) && (state & STATE_FENTRY)) | ||
831 | return 0; | ||
832 | |||
833 | insn->visited = true; | 879 | insn->visited = true; |
834 | insn->state = state; | 880 | insn->state = state; |
835 | 881 | ||
@@ -1035,12 +1081,8 @@ static int validate_functions(struct objtool_file *file) | |||
1035 | continue; | 1081 | continue; |
1036 | 1082 | ||
1037 | insn = find_insn(file, sec, func->offset); | 1083 | insn = find_insn(file, sec, func->offset); |
1038 | if (!insn) { | 1084 | if (!insn) |
1039 | WARN("%s(): can't find starting instruction", | ||
1040 | func->name); | ||
1041 | warnings++; | ||
1042 | continue; | 1085 | continue; |
1043 | } | ||
1044 | 1086 | ||
1045 | ret = validate_branch(file, insn, 0); | 1087 | ret = validate_branch(file, insn, 0); |
1046 | warnings += ret; | 1088 | warnings += ret; |
@@ -1056,13 +1098,14 @@ static int validate_functions(struct objtool_file *file) | |||
1056 | if (insn->visited) | 1098 | if (insn->visited) |
1057 | continue; | 1099 | continue; |
1058 | 1100 | ||
1059 | if (!ignore_unreachable_insn(func, insn) && | ||
1060 | !warnings) { | ||
1061 | WARN_FUNC("function has unreachable instruction", insn->sec, insn->offset); | ||
1062 | warnings++; | ||
1063 | } | ||
1064 | |||
1065 | insn->visited = true; | 1101 | insn->visited = true; |
1102 | |||
1103 | if (file->ignore_unreachables || warnings || | ||
1104 | ignore_unreachable_insn(func, insn)) | ||
1105 | continue; | ||
1106 | |||
1107 | WARN_FUNC("function has unreachable instruction", insn->sec, insn->offset); | ||
1108 | warnings++; | ||
1066 | } | 1109 | } |
1067 | } | 1110 | } |
1068 | } | 1111 | } |
@@ -1133,6 +1176,10 @@ int cmd_check(int argc, const char **argv) | |||
1133 | 1176 | ||
1134 | INIT_LIST_HEAD(&file.insn_list); | 1177 | INIT_LIST_HEAD(&file.insn_list); |
1135 | hash_init(file.insn_hash); | 1178 | hash_init(file.insn_hash); |
1179 | file.whitelist = find_section_by_name(file.elf, "__func_stack_frame_non_standard"); | ||
1180 | file.rodata = find_section_by_name(file.elf, ".rodata"); | ||
1181 | file.ignore_unreachables = false; | ||
1182 | file.c_file = find_section_by_name(file.elf, ".comment"); | ||
1136 | 1183 | ||
1137 | ret = decode_sections(&file); | 1184 | ret = decode_sections(&file); |
1138 | if (ret < 0) | 1185 | if (ret < 0) |
diff --git a/tools/perf/Documentation/intel-pt.txt b/tools/perf/Documentation/intel-pt.txt index be764f9ec769..c6c8318e38a2 100644 --- a/tools/perf/Documentation/intel-pt.txt +++ b/tools/perf/Documentation/intel-pt.txt | |||
@@ -672,6 +672,7 @@ The letters are: | |||
672 | d create a debug log | 672 | d create a debug log |
673 | g synthesize a call chain (use with i or x) | 673 | g synthesize a call chain (use with i or x) |
674 | l synthesize last branch entries (use with i or x) | 674 | l synthesize last branch entries (use with i or x) |
675 | s skip initial number of events | ||
675 | 676 | ||
676 | "Instructions" events look like they were recorded by "perf record -e | 677 | "Instructions" events look like they were recorded by "perf record -e |
677 | instructions". | 678 | instructions". |
@@ -730,6 +731,12 @@ from one sample to the next. | |||
730 | 731 | ||
731 | To disable trace decoding entirely, use the option --no-itrace. | 732 | To disable trace decoding entirely, use the option --no-itrace. |
732 | 733 | ||
734 | It is also possible to skip events generated (instructions, branches, transactions) | ||
735 | at the beginning. This is useful to ignore initialization code. | ||
736 | |||
737 | --itrace=i0nss1000000 | ||
738 | |||
739 | skips the first million instructions. | ||
733 | 740 | ||
734 | dump option | 741 | dump option |
735 | ----------- | 742 | ----------- |
diff --git a/tools/perf/Documentation/itrace.txt b/tools/perf/Documentation/itrace.txt index 65453f4c7006..e2a4c5e0dbe5 100644 --- a/tools/perf/Documentation/itrace.txt +++ b/tools/perf/Documentation/itrace.txt | |||
@@ -7,6 +7,7 @@ | |||
7 | d create a debug log | 7 | d create a debug log |
8 | g synthesize a call chain (use with i or x) | 8 | g synthesize a call chain (use with i or x) |
9 | l synthesize last branch entries (use with i or x) | 9 | l synthesize last branch entries (use with i or x) |
10 | s skip initial number of events | ||
10 | 11 | ||
11 | The default is all events i.e. the same as --itrace=ibxe | 12 | The default is all events i.e. the same as --itrace=ibxe |
12 | 13 | ||
@@ -24,3 +25,10 @@ | |||
24 | 25 | ||
25 | Also the number of last branch entries (default 64, max. 1024) for | 26 | Also the number of last branch entries (default 64, max. 1024) for |
26 | instructions or transactions events can be specified. | 27 | instructions or transactions events can be specified. |
28 | |||
29 | It is also possible to skip events generated (instructions, branches, transactions) | ||
30 | at the beginning. This is useful to ignore initialization code. | ||
31 | |||
32 | --itrace=i0nss1000000 | ||
33 | |||
34 | skips the first million instructions. | ||
diff --git a/tools/perf/Documentation/perf-annotate.txt b/tools/perf/Documentation/perf-annotate.txt index e9cd39a92dc2..778f54d4d0bd 100644 --- a/tools/perf/Documentation/perf-annotate.txt +++ b/tools/perf/Documentation/perf-annotate.txt | |||
@@ -33,7 +33,7 @@ OPTIONS | |||
33 | 33 | ||
34 | -f:: | 34 | -f:: |
35 | --force:: | 35 | --force:: |
36 | Don't complain, do it. | 36 | Don't do ownership validation. |
37 | 37 | ||
38 | -v:: | 38 | -v:: |
39 | --verbose:: | 39 | --verbose:: |
diff --git a/tools/perf/Documentation/perf-diff.txt b/tools/perf/Documentation/perf-diff.txt index d1deb573877f..3e9490b9c533 100644 --- a/tools/perf/Documentation/perf-diff.txt +++ b/tools/perf/Documentation/perf-diff.txt | |||
@@ -75,7 +75,7 @@ OPTIONS | |||
75 | 75 | ||
76 | -f:: | 76 | -f:: |
77 | --force:: | 77 | --force:: |
78 | Don't complain, do it. | 78 | Don't do ownership validation. |
79 | 79 | ||
80 | --symfs=<directory>:: | 80 | --symfs=<directory>:: |
81 | Look for files with symbols relative to this directory. | 81 | Look for files with symbols relative to this directory. |
diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt index ec723d0a5bb3..a126e97a8114 100644 --- a/tools/perf/Documentation/perf-list.txt +++ b/tools/perf/Documentation/perf-list.txt | |||
@@ -93,6 +93,67 @@ raw encoding of 0x1A8 can be used: | |||
93 | You should refer to the processor specific documentation for getting these | 93 | You should refer to the processor specific documentation for getting these |
94 | details. Some of them are referenced in the SEE ALSO section below. | 94 | details. Some of them are referenced in the SEE ALSO section below. |
95 | 95 | ||
96 | ARBITRARY PMUS | ||
97 | -------------- | ||
98 | |||
99 | perf also supports an extended syntax for specifying raw parameters | ||
100 | to PMUs. Using this typically requires looking up the specific event | ||
101 | in the CPU vendor specific documentation. | ||
102 | |||
103 | The available PMUs and their raw parameters can be listed with | ||
104 | |||
105 | ls /sys/devices/*/format | ||
106 | |||
107 | For example the raw event "LSD.UOPS" core pmu event above could | ||
108 | be specified as | ||
109 | |||
110 | perf stat -e cpu/event=0xa8,umask=0x1,name=LSD.UOPS_CYCLES,cmask=1/ ... | ||
111 | |||
112 | PER SOCKET PMUS | ||
113 | --------------- | ||
114 | |||
115 | Some PMUs are not associated with a core, but with a whole CPU socket. | ||
116 | Events on these PMUs generally cannot be sampled, but only counted globally | ||
117 | with perf stat -a. They can be bound to one logical CPU, but will measure | ||
118 | all the CPUs in the same socket. | ||
119 | |||
120 | This example measures memory bandwidth every second | ||
121 | on the first memory controller on socket 0 of a Intel Xeon system | ||
122 | |||
123 | perf stat -C 0 -a uncore_imc_0/cas_count_read/,uncore_imc_0/cas_count_write/ -I 1000 ... | ||
124 | |||
125 | Each memory controller has its own PMU. Measuring the complete system | ||
126 | bandwidth would require specifying all imc PMUs (see perf list output), | ||
127 | and adding the values together. | ||
128 | |||
129 | This example measures the combined core power every second | ||
130 | |||
131 | perf stat -I 1000 -e power/energy-cores/ -a | ||
132 | |||
133 | ACCESS RESTRICTIONS | ||
134 | ------------------- | ||
135 | |||
136 | For non root users generally only context switched PMU events are available. | ||
137 | This is normally only the events in the cpu PMU, the predefined events | ||
138 | like cycles and instructions and some software events. | ||
139 | |||
140 | Other PMUs and global measurements are normally root only. | ||
141 | Some event qualifiers, such as "any", are also root only. | ||
142 | |||
143 | This can be overriden by setting the kernel.perf_event_paranoid | ||
144 | sysctl to -1, which allows non root to use these events. | ||
145 | |||
146 | For accessing trace point events perf needs to have read access to | ||
147 | /sys/kernel/debug/tracing, even when perf_event_paranoid is in a relaxed | ||
148 | setting. | ||
149 | |||
150 | TRACING | ||
151 | ------- | ||
152 | |||
153 | Some PMUs control advanced hardware tracing capabilities, such as Intel PT, | ||
154 | that allows low overhead execution tracing. These are described in a separate | ||
155 | intel-pt.txt document. | ||
156 | |||
96 | PARAMETERIZED EVENTS | 157 | PARAMETERIZED EVENTS |
97 | -------------------- | 158 | -------------------- |
98 | 159 | ||
@@ -106,6 +167,50 @@ also be supplied. For example: | |||
106 | 167 | ||
107 | perf stat -C 0 -e 'hv_gpci/dtbp_ptitc,phys_processor_idx=0x2/' ... | 168 | perf stat -C 0 -e 'hv_gpci/dtbp_ptitc,phys_processor_idx=0x2/' ... |
108 | 169 | ||
170 | EVENT GROUPS | ||
171 | ------------ | ||
172 | |||
173 | Perf supports time based multiplexing of events, when the number of events | ||
174 | active exceeds the number of hardware performance counters. Multiplexing | ||
175 | can cause measurement errors when the workload changes its execution | ||
176 | profile. | ||
177 | |||
178 | When metrics are computed using formulas from event counts, it is useful to | ||
179 | ensure some events are always measured together as a group to minimize multiplexing | ||
180 | errors. Event groups can be specified using { }. | ||
181 | |||
182 | perf stat -e '{instructions,cycles}' ... | ||
183 | |||
184 | The number of available performance counters depend on the CPU. A group | ||
185 | cannot contain more events than available counters. | ||
186 | For example Intel Core CPUs typically have four generic performance counters | ||
187 | for the core, plus three fixed counters for instructions, cycles and | ||
188 | ref-cycles. Some special events have restrictions on which counter they | ||
189 | can schedule, and may not support multiple instances in a single group. | ||
190 | When too many events are specified in the group none of them will not | ||
191 | be measured. | ||
192 | |||
193 | Globally pinned events can limit the number of counters available for | ||
194 | other groups. On x86 systems, the NMI watchdog pins a counter by default. | ||
195 | The nmi watchdog can be disabled as root with | ||
196 | |||
197 | echo 0 > /proc/sys/kernel/nmi_watchdog | ||
198 | |||
199 | Events from multiple different PMUs cannot be mixed in a group, with | ||
200 | some exceptions for software events. | ||
201 | |||
202 | LEADER SAMPLING | ||
203 | --------------- | ||
204 | |||
205 | perf also supports group leader sampling using the :S specifier. | ||
206 | |||
207 | perf record -e '{cycles,instructions}:S' ... | ||
208 | perf report --group | ||
209 | |||
210 | Normally all events in a event group sample, but with :S only | ||
211 | the first event (the leader) samples, and it only reads the values of the | ||
212 | other events in the group. | ||
213 | |||
109 | OPTIONS | 214 | OPTIONS |
110 | ------- | 215 | ------- |
111 | 216 | ||
@@ -143,5 +248,5 @@ SEE ALSO | |||
143 | -------- | 248 | -------- |
144 | linkperf:perf-stat[1], linkperf:perf-top[1], | 249 | linkperf:perf-stat[1], linkperf:perf-top[1], |
145 | linkperf:perf-record[1], | 250 | linkperf:perf-record[1], |
146 | http://www.intel.com/Assets/PDF/manual/253669.pdf[Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 3B: System Programming Guide], | 251 | http://www.intel.com/sdm/[Intel® 64 and IA-32 Architectures Software Developer's Manual Volume 3B: System Programming Guide], |
147 | http://support.amd.com/us/Processor_TechDocs/24593_APM_v2.pdf[AMD64 Architecture Programmer’s Manual Volume 2: System Programming] | 252 | http://support.amd.com/us/Processor_TechDocs/24593_APM_v2.pdf[AMD64 Architecture Programmer’s Manual Volume 2: System Programming] |
diff --git a/tools/perf/Documentation/perf-mem.txt b/tools/perf/Documentation/perf-mem.txt index 43310d8661fe..1d6092c460dd 100644 --- a/tools/perf/Documentation/perf-mem.txt +++ b/tools/perf/Documentation/perf-mem.txt | |||
@@ -48,6 +48,14 @@ OPTIONS | |||
48 | option can be passed in record mode. It will be interpreted the same way as perf | 48 | option can be passed in record mode. It will be interpreted the same way as perf |
49 | record. | 49 | record. |
50 | 50 | ||
51 | -K:: | ||
52 | --all-kernel:: | ||
53 | Configure all used events to run in kernel space. | ||
54 | |||
55 | -U:: | ||
56 | --all-user:: | ||
57 | Configure all used events to run in user space. | ||
58 | |||
51 | SEE ALSO | 59 | SEE ALSO |
52 | -------- | 60 | -------- |
53 | linkperf:perf-record[1], linkperf:perf-report[1] | 61 | linkperf:perf-record[1], linkperf:perf-report[1] |
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 19aa17532a16..8dbee832abd9 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
@@ -347,6 +347,19 @@ Configure all used events to run in kernel space. | |||
347 | --all-user:: | 347 | --all-user:: |
348 | Configure all used events to run in user space. | 348 | Configure all used events to run in user space. |
349 | 349 | ||
350 | --timestamp-filename | ||
351 | Append timestamp to output file name. | ||
352 | |||
353 | --switch-output:: | ||
354 | Generate multiple perf.data files, timestamp prefixed, switching to a new one | ||
355 | when receiving a SIGUSR2. | ||
356 | |||
357 | A possible use case is to, given an external event, slice the perf.data file | ||
358 | that gets then processed, possibly via a perf script, to decide if that | ||
359 | particular perf.data snapshot should be kept or not. | ||
360 | |||
361 | Implies --timestamp-filename, --no-buildid and --no-buildid-cache. | ||
362 | |||
350 | SEE ALSO | 363 | SEE ALSO |
351 | -------- | 364 | -------- |
352 | linkperf:perf-stat[1], linkperf:perf-list[1] | 365 | linkperf:perf-stat[1], linkperf:perf-list[1] |
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt index 12113992ac9d..ebaf849e30ef 100644 --- a/tools/perf/Documentation/perf-report.txt +++ b/tools/perf/Documentation/perf-report.txt | |||
@@ -248,7 +248,7 @@ OPTIONS | |||
248 | Note that when using the --itrace option the synthesized callchain size | 248 | Note that when using the --itrace option the synthesized callchain size |
249 | will override this value if the synthesized callchain size is bigger. | 249 | will override this value if the synthesized callchain size is bigger. |
250 | 250 | ||
251 | Default: 127 | 251 | Default: /proc/sys/kernel/perf_event_max_stack when present, 127 otherwise. |
252 | 252 | ||
253 | -G:: | 253 | -G:: |
254 | --inverted:: | 254 | --inverted:: |
@@ -285,7 +285,7 @@ OPTIONS | |||
285 | 285 | ||
286 | -f:: | 286 | -f:: |
287 | --force:: | 287 | --force:: |
288 | Don't complain, do it. | 288 | Don't do ownership validation. |
289 | 289 | ||
290 | --symfs=<directory>:: | 290 | --symfs=<directory>:: |
291 | Look for files with symbols relative to this directory. | 291 | Look for files with symbols relative to this directory. |
diff --git a/tools/perf/Documentation/perf-sched.txt b/tools/perf/Documentation/perf-sched.txt index 8ff4df956951..1cc08cc47ac5 100644 --- a/tools/perf/Documentation/perf-sched.txt +++ b/tools/perf/Documentation/perf-sched.txt | |||
@@ -50,6 +50,22 @@ OPTIONS | |||
50 | --dump-raw-trace=:: | 50 | --dump-raw-trace=:: |
51 | Display verbose dump of the sched data. | 51 | Display verbose dump of the sched data. |
52 | 52 | ||
53 | OPTIONS for 'perf sched map' | ||
54 | ---------------------------- | ||
55 | |||
56 | --compact:: | ||
57 | Show only CPUs with activity. Helps visualizing on high core | ||
58 | count systems. | ||
59 | |||
60 | --cpus:: | ||
61 | Show just entries with activities for the given CPUs. | ||
62 | |||
63 | --color-cpus:: | ||
64 | Highlight the given cpus. | ||
65 | |||
66 | --color-pids:: | ||
67 | Highlight the given pids. | ||
68 | |||
53 | SEE ALSO | 69 | SEE ALSO |
54 | -------- | 70 | -------- |
55 | linkperf:perf-record[1] | 71 | linkperf:perf-record[1] |
diff --git a/tools/perf/Documentation/perf-script.txt b/tools/perf/Documentation/perf-script.txt index 382ddfb45d1d..a856a1095893 100644 --- a/tools/perf/Documentation/perf-script.txt +++ b/tools/perf/Documentation/perf-script.txt | |||
@@ -259,9 +259,23 @@ include::itrace.txt[] | |||
259 | --full-source-path:: | 259 | --full-source-path:: |
260 | Show the full path for source files for srcline output. | 260 | Show the full path for source files for srcline output. |
261 | 261 | ||
262 | --max-stack:: | ||
263 | Set the stack depth limit when parsing the callchain, anything | ||
264 | beyond the specified depth will be ignored. This is a trade-off | ||
265 | between information loss and faster processing especially for | ||
266 | workloads that can have a very long callchain stack. | ||
267 | Note that when using the --itrace option the synthesized callchain size | ||
268 | will override this value if the synthesized callchain size is bigger. | ||
269 | |||
270 | Default: /proc/sys/kernel/perf_event_max_stack when present, 127 otherwise. | ||
271 | |||
262 | --ns:: | 272 | --ns:: |
263 | Use 9 decimal places when displaying time (i.e. show the nanoseconds) | 273 | Use 9 decimal places when displaying time (i.e. show the nanoseconds) |
264 | 274 | ||
275 | -f:: | ||
276 | --force:: | ||
277 | Don't do ownership validation. | ||
278 | |||
265 | SEE ALSO | 279 | SEE ALSO |
266 | -------- | 280 | -------- |
267 | linkperf:perf-record[1], linkperf:perf-script-perl[1], | 281 | linkperf:perf-record[1], linkperf:perf-script-perl[1], |
diff --git a/tools/perf/Documentation/perf-top.txt b/tools/perf/Documentation/perf-top.txt index 19f046f027cd..91d638df3a6b 100644 --- a/tools/perf/Documentation/perf-top.txt +++ b/tools/perf/Documentation/perf-top.txt | |||
@@ -177,7 +177,7 @@ Default is to monitor all CPUS. | |||
177 | between information loss and faster processing especially for | 177 | between information loss and faster processing especially for |
178 | workloads that can have a very long callchain stack. | 178 | workloads that can have a very long callchain stack. |
179 | 179 | ||
180 | Default: 127 | 180 | Default: /proc/sys/kernel/perf_event_max_stack when present, 127 otherwise. |
181 | 181 | ||
182 | --ignore-callees=<regex>:: | 182 | --ignore-callees=<regex>:: |
183 | Ignore callees of the function(s) matching the given regex. | 183 | Ignore callees of the function(s) matching the given regex. |
diff --git a/tools/perf/Documentation/perf-trace.txt b/tools/perf/Documentation/perf-trace.txt index 13293de8869f..6afe20121bc0 100644 --- a/tools/perf/Documentation/perf-trace.txt +++ b/tools/perf/Documentation/perf-trace.txt | |||
@@ -117,9 +117,41 @@ the thread executes on the designated CPUs. Default is to monitor all CPUs. | |||
117 | --syscalls:: | 117 | --syscalls:: |
118 | Trace system calls. This options is enabled by default. | 118 | Trace system calls. This options is enabled by default. |
119 | 119 | ||
120 | --call-graph [mode,type,min[,limit],order[,key][,branch]]:: | ||
121 | Setup and enable call-graph (stack chain/backtrace) recording. | ||
122 | See `--call-graph` section in perf-record and perf-report | ||
123 | man pages for details. The ones that are most useful in 'perf trace' | ||
124 | are 'dwarf' and 'lbr', where available, try: 'perf trace --call-graph dwarf'. | ||
125 | |||
126 | Using this will, for the root user, bump the value of --mmap-pages to 4 | ||
127 | times the maximum for non-root users, based on the kernel.perf_event_mlock_kb | ||
128 | sysctl. This is done only if the user doesn't specify a --mmap-pages value. | ||
129 | |||
130 | --kernel-syscall-graph:: | ||
131 | Show the kernel callchains on the syscall exit path. | ||
132 | |||
120 | --event:: | 133 | --event:: |
121 | Trace other events, see 'perf list' for a complete list. | 134 | Trace other events, see 'perf list' for a complete list. |
122 | 135 | ||
136 | --max-stack:: | ||
137 | Set the stack depth limit when parsing the callchain, anything | ||
138 | beyond the specified depth will be ignored. Note that at this point | ||
139 | this is just about the presentation part, i.e. the kernel is still | ||
140 | not limiting, the overhead of callchains needs to be set via the | ||
141 | knobs in --call-graph dwarf. | ||
142 | |||
143 | Implies '--call-graph dwarf' when --call-graph not present on the | ||
144 | command line, on systems where DWARF unwinding was built in. | ||
145 | |||
146 | Default: /proc/sys/kernel/perf_event_max_stack when present, 127 otherwise. | ||
147 | |||
148 | --min-stack:: | ||
149 | Set the stack depth limit when parsing the callchain, anything | ||
150 | below the specified depth will be ignored. Disabled by default. | ||
151 | |||
152 | Implies '--call-graph dwarf' when --call-graph not present on the | ||
153 | command line, on systems where DWARF unwinding was built in. | ||
154 | |||
123 | --proc-map-timeout:: | 155 | --proc-map-timeout:: |
124 | When processing pre-existing threads /proc/XXX/mmap, it may take a long time, | 156 | When processing pre-existing threads /proc/XXX/mmap, it may take a long time, |
125 | because the file may be huge. A time out is needed in such cases. | 157 | because the file may be huge. A time out is needed in such cases. |
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 000ea210389d..bde8cbae7dd9 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -183,6 +183,11 @@ endif | |||
183 | include config/Makefile | 183 | include config/Makefile |
184 | endif | 184 | endif |
185 | 185 | ||
186 | ifeq ($(config),0) | ||
187 | include $(srctree)/tools/scripts/Makefile.arch | ||
188 | -include arch/$(ARCH)/Makefile | ||
189 | endif | ||
190 | |||
186 | # The FEATURE_DUMP_EXPORT holds location of the actual | 191 | # The FEATURE_DUMP_EXPORT holds location of the actual |
187 | # FEATURE_DUMP file to be used to bypass feature detection | 192 | # FEATURE_DUMP file to be used to bypass feature detection |
188 | # (for bpf or any other subproject) | 193 | # (for bpf or any other subproject) |
@@ -297,8 +302,6 @@ endif | |||
297 | # because maintaining the nesting to match is a pain. If | 302 | # because maintaining the nesting to match is a pain. If |
298 | # we had "elif" things would have been much nicer... | 303 | # we had "elif" things would have been much nicer... |
299 | 304 | ||
300 | -include arch/$(ARCH)/Makefile | ||
301 | |||
302 | ifneq ($(OUTPUT),) | 305 | ifneq ($(OUTPUT),) |
303 | CFLAGS += -I$(OUTPUT) | 306 | CFLAGS += -I$(OUTPUT) |
304 | endif | 307 | endif |
@@ -390,7 +393,7 @@ endif | |||
390 | __build-dir = $(subst $(OUTPUT),,$(dir $@)) | 393 | __build-dir = $(subst $(OUTPUT),,$(dir $@)) |
391 | build-dir = $(if $(__build-dir),$(__build-dir),.) | 394 | build-dir = $(if $(__build-dir),$(__build-dir),.) |
392 | 395 | ||
393 | prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h fixdep | 396 | prepare: $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)common-cmds.h fixdep archheaders |
394 | 397 | ||
395 | $(OUTPUT)%.o: %.c prepare FORCE | 398 | $(OUTPUT)%.o: %.c prepare FORCE |
396 | $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ | 399 | $(Q)$(MAKE) -f $(srctree)/tools/build/Makefile.build dir=$(build-dir) $@ |
@@ -430,7 +433,7 @@ $(patsubst perf-%,%.o,$(PROGRAMS)): $(wildcard */*.h) | |||
430 | 433 | ||
431 | LIBPERF_IN := $(OUTPUT)libperf-in.o | 434 | LIBPERF_IN := $(OUTPUT)libperf-in.o |
432 | 435 | ||
433 | $(LIBPERF_IN): fixdep FORCE | 436 | $(LIBPERF_IN): prepare fixdep FORCE |
434 | $(Q)$(MAKE) $(build)=libperf | 437 | $(Q)$(MAKE) $(build)=libperf |
435 | 438 | ||
436 | $(LIB_FILE): $(LIBPERF_IN) | 439 | $(LIB_FILE): $(LIBPERF_IN) |
@@ -625,7 +628,7 @@ config-clean: | |||
625 | $(call QUIET_CLEAN, config) | 628 | $(call QUIET_CLEAN, config) |
626 | $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ $(if $(OUTPUT),OUTPUT=$(OUTPUT)feature/,) clean >/dev/null | 629 | $(Q)$(MAKE) -C $(srctree)/tools/build/feature/ $(if $(OUTPUT),OUTPUT=$(OUTPUT)feature/,) clean >/dev/null |
627 | 630 | ||
628 | clean: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean config-clean | 631 | clean:: $(LIBTRACEEVENT)-clean $(LIBAPI)-clean $(LIBBPF)-clean $(LIBSUBCMD)-clean config-clean |
629 | $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS) | 632 | $(call QUIET_CLEAN, core-objs) $(RM) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(LANG_BINDINGS) |
630 | $(Q)find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete | 633 | $(Q)find $(if $(OUTPUT),$(OUTPUT),.) -name '*.o' -delete -o -name '\.*.cmd' -delete -o -name '\.*.d' -delete |
631 | $(Q)$(RM) $(OUTPUT).config-detected | 634 | $(Q)$(RM) $(OUTPUT).config-detected |
@@ -662,5 +665,5 @@ FORCE: | |||
662 | .PHONY: all install clean config-clean strip install-gtk | 665 | .PHONY: all install clean config-clean strip install-gtk |
663 | .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell | 666 | .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell |
664 | .PHONY: $(GIT-HEAD-PHONY) TAGS tags cscope FORCE prepare | 667 | .PHONY: $(GIT-HEAD-PHONY) TAGS tags cscope FORCE prepare |
665 | .PHONY: libtraceevent_plugins | 668 | .PHONY: libtraceevent_plugins archheaders |
666 | 669 | ||
diff --git a/tools/perf/arch/powerpc/Makefile b/tools/perf/arch/powerpc/Makefile index 56e05f126ad8..cc3930904d68 100644 --- a/tools/perf/arch/powerpc/Makefile +++ b/tools/perf/arch/powerpc/Makefile | |||
@@ -3,4 +3,5 @@ PERF_HAVE_DWARF_REGS := 1 | |||
3 | endif | 3 | endif |
4 | 4 | ||
5 | HAVE_KVM_STAT_SUPPORT := 1 | 5 | HAVE_KVM_STAT_SUPPORT := 1 |
6 | PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1 | ||
6 | PERF_HAVE_JITDUMP := 1 | 7 | PERF_HAVE_JITDUMP := 1 |
diff --git a/tools/perf/arch/powerpc/util/dwarf-regs.c b/tools/perf/arch/powerpc/util/dwarf-regs.c index 733151cdf46e..41bdf9530d82 100644 --- a/tools/perf/arch/powerpc/util/dwarf-regs.c +++ b/tools/perf/arch/powerpc/util/dwarf-regs.c | |||
@@ -10,19 +10,26 @@ | |||
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <stddef.h> | 12 | #include <stddef.h> |
13 | #include <errno.h> | ||
14 | #include <string.h> | ||
13 | #include <dwarf-regs.h> | 15 | #include <dwarf-regs.h> |
14 | 16 | #include <linux/ptrace.h> | |
17 | #include <linux/kernel.h> | ||
18 | #include "util.h" | ||
15 | 19 | ||
16 | struct pt_regs_dwarfnum { | 20 | struct pt_regs_dwarfnum { |
17 | const char *name; | 21 | const char *name; |
18 | unsigned int dwarfnum; | 22 | unsigned int dwarfnum; |
23 | unsigned int ptregs_offset; | ||
19 | }; | 24 | }; |
20 | 25 | ||
21 | #define STR(s) #s | 26 | #define REG_DWARFNUM_NAME(r, num) \ |
22 | #define REG_DWARFNUM_NAME(r, num) {.name = r, .dwarfnum = num} | 27 | {.name = STR(%)STR(r), .dwarfnum = num, \ |
23 | #define GPR_DWARFNUM_NAME(num) \ | 28 | .ptregs_offset = offsetof(struct pt_regs, r)} |
24 | {.name = STR(%gpr##num), .dwarfnum = num} | 29 | #define GPR_DWARFNUM_NAME(num) \ |
25 | #define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0} | 30 | {.name = STR(%gpr##num), .dwarfnum = num, \ |
31 | .ptregs_offset = offsetof(struct pt_regs, gpr[num])} | ||
32 | #define REG_DWARFNUM_END {.name = NULL, .dwarfnum = 0, .ptregs_offset = 0} | ||
26 | 33 | ||
27 | /* | 34 | /* |
28 | * Reference: | 35 | * Reference: |
@@ -61,12 +68,12 @@ static const struct pt_regs_dwarfnum regdwarfnum_table[] = { | |||
61 | GPR_DWARFNUM_NAME(29), | 68 | GPR_DWARFNUM_NAME(29), |
62 | GPR_DWARFNUM_NAME(30), | 69 | GPR_DWARFNUM_NAME(30), |
63 | GPR_DWARFNUM_NAME(31), | 70 | GPR_DWARFNUM_NAME(31), |
64 | REG_DWARFNUM_NAME("%msr", 66), | 71 | REG_DWARFNUM_NAME(msr, 66), |
65 | REG_DWARFNUM_NAME("%ctr", 109), | 72 | REG_DWARFNUM_NAME(ctr, 109), |
66 | REG_DWARFNUM_NAME("%link", 108), | 73 | REG_DWARFNUM_NAME(link, 108), |
67 | REG_DWARFNUM_NAME("%xer", 101), | 74 | REG_DWARFNUM_NAME(xer, 101), |
68 | REG_DWARFNUM_NAME("%dar", 119), | 75 | REG_DWARFNUM_NAME(dar, 119), |
69 | REG_DWARFNUM_NAME("%dsisr", 118), | 76 | REG_DWARFNUM_NAME(dsisr, 118), |
70 | REG_DWARFNUM_END, | 77 | REG_DWARFNUM_END, |
71 | }; | 78 | }; |
72 | 79 | ||
@@ -86,3 +93,12 @@ const char *get_arch_regstr(unsigned int n) | |||
86 | return roff->name; | 93 | return roff->name; |
87 | return NULL; | 94 | return NULL; |
88 | } | 95 | } |
96 | |||
97 | int regs_query_register_offset(const char *name) | ||
98 | { | ||
99 | const struct pt_regs_dwarfnum *roff; | ||
100 | for (roff = regdwarfnum_table; roff->name != NULL; roff++) | ||
101 | if (!strcmp(roff->name, name)) | ||
102 | return roff->ptregs_offset; | ||
103 | return -EINVAL; | ||
104 | } | ||
diff --git a/tools/perf/arch/powerpc/util/sym-handling.c b/tools/perf/arch/powerpc/util/sym-handling.c index bbc1a50768dd..c6d0f91731a1 100644 --- a/tools/perf/arch/powerpc/util/sym-handling.c +++ b/tools/perf/arch/powerpc/util/sym-handling.c | |||
@@ -19,12 +19,6 @@ bool elf__needs_adjust_symbols(GElf_Ehdr ehdr) | |||
19 | ehdr.e_type == ET_DYN; | 19 | ehdr.e_type == ET_DYN; |
20 | } | 20 | } |
21 | 21 | ||
22 | #if defined(_CALL_ELF) && _CALL_ELF == 2 | ||
23 | void arch__elf_sym_adjust(GElf_Sym *sym) | ||
24 | { | ||
25 | sym->st_value += PPC64_LOCAL_ENTRY_OFFSET(sym->st_other); | ||
26 | } | ||
27 | #endif | ||
28 | #endif | 22 | #endif |
29 | 23 | ||
30 | #if !defined(_CALL_ELF) || _CALL_ELF != 2 | 24 | #if !defined(_CALL_ELF) || _CALL_ELF != 2 |
@@ -65,18 +59,45 @@ bool arch__prefers_symtab(void) | |||
65 | return true; | 59 | return true; |
66 | } | 60 | } |
67 | 61 | ||
62 | #ifdef HAVE_LIBELF_SUPPORT | ||
63 | void arch__sym_update(struct symbol *s, GElf_Sym *sym) | ||
64 | { | ||
65 | s->arch_sym = sym->st_other; | ||
66 | } | ||
67 | #endif | ||
68 | |||
68 | #define PPC64LE_LEP_OFFSET 8 | 69 | #define PPC64LE_LEP_OFFSET 8 |
69 | 70 | ||
70 | void arch__fix_tev_from_maps(struct perf_probe_event *pev, | 71 | void arch__fix_tev_from_maps(struct perf_probe_event *pev, |
71 | struct probe_trace_event *tev, struct map *map) | 72 | struct probe_trace_event *tev, struct map *map, |
73 | struct symbol *sym) | ||
72 | { | 74 | { |
75 | int lep_offset; | ||
76 | |||
73 | /* | 77 | /* |
74 | * ppc64 ABIv2 local entry point is currently always 2 instructions | 78 | * When probing at a function entry point, we normally always want the |
75 | * (8 bytes) after the global entry point. | 79 | * LEP since that catches calls to the function through both the GEP and |
80 | * the LEP. Hence, we would like to probe at an offset of 8 bytes if | ||
81 | * the user only specified the function entry. | ||
82 | * | ||
83 | * However, if the user specifies an offset, we fall back to using the | ||
84 | * GEP since all userspace applications (objdump/readelf) show function | ||
85 | * disassembly with offsets from the GEP. | ||
86 | * | ||
87 | * In addition, we shouldn't specify an offset for kretprobes. | ||
76 | */ | 88 | */ |
77 | if (!pev->uprobes && map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) { | 89 | if (pev->point.offset || pev->point.retprobe || !map || !sym) |
78 | tev->point.address += PPC64LE_LEP_OFFSET; | 90 | return; |
91 | |||
92 | lep_offset = PPC64_LOCAL_ENTRY_OFFSET(sym->arch_sym); | ||
93 | |||
94 | if (map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) | ||
79 | tev->point.offset += PPC64LE_LEP_OFFSET; | 95 | tev->point.offset += PPC64LE_LEP_OFFSET; |
96 | else if (lep_offset) { | ||
97 | if (pev->uprobes) | ||
98 | tev->point.address += lep_offset; | ||
99 | else | ||
100 | tev->point.offset += lep_offset; | ||
80 | } | 101 | } |
81 | } | 102 | } |
82 | #endif | 103 | #endif |
diff --git a/tools/perf/arch/x86/Makefile b/tools/perf/arch/x86/Makefile index 269af2143735..6c9211b18ec0 100644 --- a/tools/perf/arch/x86/Makefile +++ b/tools/perf/arch/x86/Makefile | |||
@@ -4,3 +4,26 @@ endif | |||
4 | HAVE_KVM_STAT_SUPPORT := 1 | 4 | HAVE_KVM_STAT_SUPPORT := 1 |
5 | PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1 | 5 | PERF_HAVE_ARCH_REGS_QUERY_REGISTER_OFFSET := 1 |
6 | PERF_HAVE_JITDUMP := 1 | 6 | PERF_HAVE_JITDUMP := 1 |
7 | |||
8 | ### | ||
9 | # Syscall table generation | ||
10 | # | ||
11 | |||
12 | out := $(OUTPUT)arch/x86/include/generated/asm | ||
13 | header := $(out)/syscalls_64.c | ||
14 | sys := $(srctree)/tools/perf/arch/x86/entry/syscalls | ||
15 | systbl := $(sys)/syscalltbl.sh | ||
16 | |||
17 | # Create output directory if not already present | ||
18 | _dummy := $(shell [ -d '$(out)' ] || mkdir -p '$(out)') | ||
19 | |||
20 | $(header): $(sys)/syscall_64.tbl $(systbl) | ||
21 | @(test -d ../../kernel -a -d ../../tools -a -d ../perf && ( \ | ||
22 | (diff -B arch/x86/entry/syscalls/syscall_64.tbl ../../arch/x86/entry/syscalls/syscall_64.tbl >/dev/null) \ | ||
23 | || echo "Warning: x86_64's syscall_64.tbl differs from kernel" >&2 )) || true | ||
24 | $(Q)$(SHELL) '$(systbl)' $(sys)/syscall_64.tbl 'x86_64' > $@ | ||
25 | |||
26 | clean:: | ||
27 | $(call QUIET_CLEAN, x86) $(RM) $(header) | ||
28 | |||
29 | archheaders: $(header) | ||
diff --git a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl new file mode 100644 index 000000000000..cac6d17ce5db --- /dev/null +++ b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl | |||
@@ -0,0 +1,376 @@ | |||
1 | # | ||
2 | # 64-bit system call numbers and entry vectors | ||
3 | # | ||
4 | # The format is: | ||
5 | # <number> <abi> <name> <entry point> | ||
6 | # | ||
7 | # The abi is "common", "64" or "x32" for this file. | ||
8 | # | ||
9 | 0 common read sys_read | ||
10 | 1 common write sys_write | ||
11 | 2 common open sys_open | ||
12 | 3 common close sys_close | ||
13 | 4 common stat sys_newstat | ||
14 | 5 common fstat sys_newfstat | ||
15 | 6 common lstat sys_newlstat | ||
16 | 7 common poll sys_poll | ||
17 | 8 common lseek sys_lseek | ||
18 | 9 common mmap sys_mmap | ||
19 | 10 common mprotect sys_mprotect | ||
20 | 11 common munmap sys_munmap | ||
21 | 12 common brk sys_brk | ||
22 | 13 64 rt_sigaction sys_rt_sigaction | ||
23 | 14 common rt_sigprocmask sys_rt_sigprocmask | ||
24 | 15 64 rt_sigreturn sys_rt_sigreturn/ptregs | ||
25 | 16 64 ioctl sys_ioctl | ||
26 | 17 common pread64 sys_pread64 | ||
27 | 18 common pwrite64 sys_pwrite64 | ||
28 | 19 64 readv sys_readv | ||
29 | 20 64 writev sys_writev | ||
30 | 21 common access sys_access | ||
31 | 22 common pipe sys_pipe | ||
32 | 23 common select sys_select | ||
33 | 24 common sched_yield sys_sched_yield | ||
34 | 25 common mremap sys_mremap | ||
35 | 26 common msync sys_msync | ||
36 | 27 common mincore sys_mincore | ||
37 | 28 common madvise sys_madvise | ||
38 | 29 common shmget sys_shmget | ||
39 | 30 common shmat sys_shmat | ||
40 | 31 common shmctl sys_shmctl | ||
41 | 32 common dup sys_dup | ||
42 | 33 common dup2 sys_dup2 | ||
43 | 34 common pause sys_pause | ||
44 | 35 common nanosleep sys_nanosleep | ||
45 | 36 common getitimer sys_getitimer | ||
46 | 37 common alarm sys_alarm | ||
47 | 38 common setitimer sys_setitimer | ||
48 | 39 common getpid sys_getpid | ||
49 | 40 common sendfile sys_sendfile64 | ||
50 | 41 common socket sys_socket | ||
51 | 42 common connect sys_connect | ||
52 | 43 common accept sys_accept | ||
53 | 44 common sendto sys_sendto | ||
54 | 45 64 recvfrom sys_recvfrom | ||
55 | 46 64 sendmsg sys_sendmsg | ||
56 | 47 64 recvmsg sys_recvmsg | ||
57 | 48 common shutdown sys_shutdown | ||
58 | 49 common bind sys_bind | ||
59 | 50 common listen sys_listen | ||
60 | 51 common getsockname sys_getsockname | ||
61 | 52 common getpeername sys_getpeername | ||
62 | 53 common socketpair sys_socketpair | ||
63 | 54 64 setsockopt sys_setsockopt | ||
64 | 55 64 getsockopt sys_getsockopt | ||
65 | 56 common clone sys_clone/ptregs | ||
66 | 57 common fork sys_fork/ptregs | ||
67 | 58 common vfork sys_vfork/ptregs | ||
68 | 59 64 execve sys_execve/ptregs | ||
69 | 60 common exit sys_exit | ||
70 | 61 common wait4 sys_wait4 | ||
71 | 62 common kill sys_kill | ||
72 | 63 common uname sys_newuname | ||
73 | 64 common semget sys_semget | ||
74 | 65 common semop sys_semop | ||
75 | 66 common semctl sys_semctl | ||
76 | 67 common shmdt sys_shmdt | ||
77 | 68 common msgget sys_msgget | ||
78 | 69 common msgsnd sys_msgsnd | ||
79 | 70 common msgrcv sys_msgrcv | ||
80 | 71 common msgctl sys_msgctl | ||
81 | 72 common fcntl sys_fcntl | ||
82 | 73 common flock sys_flock | ||
83 | 74 common fsync sys_fsync | ||
84 | 75 common fdatasync sys_fdatasync | ||
85 | 76 common truncate sys_truncate | ||
86 | 77 common ftruncate sys_ftruncate | ||
87 | 78 common getdents sys_getdents | ||
88 | 79 common getcwd sys_getcwd | ||
89 | 80 common chdir sys_chdir | ||
90 | 81 common fchdir sys_fchdir | ||
91 | 82 common rename sys_rename | ||
92 | 83 common mkdir sys_mkdir | ||
93 | 84 common rmdir sys_rmdir | ||
94 | 85 common creat sys_creat | ||
95 | 86 common link sys_link | ||
96 | 87 common unlink sys_unlink | ||
97 | 88 common symlink sys_symlink | ||
98 | 89 common readlink sys_readlink | ||
99 | 90 common chmod sys_chmod | ||
100 | 91 common fchmod sys_fchmod | ||
101 | 92 common chown sys_chown | ||
102 | 93 common fchown sys_fchown | ||
103 | 94 common lchown sys_lchown | ||
104 | 95 common umask sys_umask | ||
105 | 96 common gettimeofday sys_gettimeofday | ||
106 | 97 common getrlimit sys_getrlimit | ||
107 | 98 common getrusage sys_getrusage | ||
108 | 99 common sysinfo sys_sysinfo | ||
109 | 100 common times sys_times | ||
110 | 101 64 ptrace sys_ptrace | ||
111 | 102 common getuid sys_getuid | ||
112 | 103 common syslog sys_syslog | ||
113 | 104 common getgid sys_getgid | ||
114 | 105 common setuid sys_setuid | ||
115 | 106 common setgid sys_setgid | ||
116 | 107 common geteuid sys_geteuid | ||
117 | 108 common getegid sys_getegid | ||
118 | 109 common setpgid sys_setpgid | ||
119 | 110 common getppid sys_getppid | ||
120 | 111 common getpgrp sys_getpgrp | ||
121 | 112 common setsid sys_setsid | ||
122 | 113 common setreuid sys_setreuid | ||
123 | 114 common setregid sys_setregid | ||
124 | 115 common getgroups sys_getgroups | ||
125 | 116 common setgroups sys_setgroups | ||
126 | 117 common setresuid sys_setresuid | ||
127 | 118 common getresuid sys_getresuid | ||
128 | 119 common setresgid sys_setresgid | ||
129 | 120 common getresgid sys_getresgid | ||
130 | 121 common getpgid sys_getpgid | ||
131 | 122 common setfsuid sys_setfsuid | ||
132 | 123 common setfsgid sys_setfsgid | ||
133 | 124 common getsid sys_getsid | ||
134 | 125 common capget sys_capget | ||
135 | 126 common capset sys_capset | ||
136 | 127 64 rt_sigpending sys_rt_sigpending | ||
137 | 128 64 rt_sigtimedwait sys_rt_sigtimedwait | ||
138 | 129 64 rt_sigqueueinfo sys_rt_sigqueueinfo | ||
139 | 130 common rt_sigsuspend sys_rt_sigsuspend | ||
140 | 131 64 sigaltstack sys_sigaltstack | ||
141 | 132 common utime sys_utime | ||
142 | 133 common mknod sys_mknod | ||
143 | 134 64 uselib | ||
144 | 135 common personality sys_personality | ||
145 | 136 common ustat sys_ustat | ||
146 | 137 common statfs sys_statfs | ||
147 | 138 common fstatfs sys_fstatfs | ||
148 | 139 common sysfs sys_sysfs | ||
149 | 140 common getpriority sys_getpriority | ||
150 | 141 common setpriority sys_setpriority | ||
151 | 142 common sched_setparam sys_sched_setparam | ||
152 | 143 common sched_getparam sys_sched_getparam | ||
153 | 144 common sched_setscheduler sys_sched_setscheduler | ||
154 | 145 common sched_getscheduler sys_sched_getscheduler | ||
155 | 146 common sched_get_priority_max sys_sched_get_priority_max | ||
156 | 147 common sched_get_priority_min sys_sched_get_priority_min | ||
157 | 148 common sched_rr_get_interval sys_sched_rr_get_interval | ||
158 | 149 common mlock sys_mlock | ||
159 | 150 common munlock sys_munlock | ||
160 | 151 common mlockall sys_mlockall | ||
161 | 152 common munlockall sys_munlockall | ||
162 | 153 common vhangup sys_vhangup | ||
163 | 154 common modify_ldt sys_modify_ldt | ||
164 | 155 common pivot_root sys_pivot_root | ||
165 | 156 64 _sysctl sys_sysctl | ||
166 | 157 common prctl sys_prctl | ||
167 | 158 common arch_prctl sys_arch_prctl | ||
168 | 159 common adjtimex sys_adjtimex | ||
169 | 160 common setrlimit sys_setrlimit | ||
170 | 161 common chroot sys_chroot | ||
171 | 162 common sync sys_sync | ||
172 | 163 common acct sys_acct | ||
173 | 164 common settimeofday sys_settimeofday | ||
174 | 165 common mount sys_mount | ||
175 | 166 common umount2 sys_umount | ||
176 | 167 common swapon sys_swapon | ||
177 | 168 common swapoff sys_swapoff | ||
178 | 169 common reboot sys_reboot | ||
179 | 170 common sethostname sys_sethostname | ||
180 | 171 common setdomainname sys_setdomainname | ||
181 | 172 common iopl sys_iopl/ptregs | ||
182 | 173 common ioperm sys_ioperm | ||
183 | 174 64 create_module | ||
184 | 175 common init_module sys_init_module | ||
185 | 176 common delete_module sys_delete_module | ||
186 | 177 64 get_kernel_syms | ||
187 | 178 64 query_module | ||
188 | 179 common quotactl sys_quotactl | ||
189 | 180 64 nfsservctl | ||
190 | 181 common getpmsg | ||
191 | 182 common putpmsg | ||
192 | 183 common afs_syscall | ||
193 | 184 common tuxcall | ||
194 | 185 common security | ||
195 | 186 common gettid sys_gettid | ||
196 | 187 common readahead sys_readahead | ||
197 | 188 common setxattr sys_setxattr | ||
198 | 189 common lsetxattr sys_lsetxattr | ||
199 | 190 common fsetxattr sys_fsetxattr | ||
200 | 191 common getxattr sys_getxattr | ||
201 | 192 common lgetxattr sys_lgetxattr | ||
202 | 193 common fgetxattr sys_fgetxattr | ||
203 | 194 common listxattr sys_listxattr | ||
204 | 195 common llistxattr sys_llistxattr | ||
205 | 196 common flistxattr sys_flistxattr | ||
206 | 197 common removexattr sys_removexattr | ||
207 | 198 common lremovexattr sys_lremovexattr | ||
208 | 199 common fremovexattr sys_fremovexattr | ||
209 | 200 common tkill sys_tkill | ||
210 | 201 common time sys_time | ||
211 | 202 common futex sys_futex | ||
212 | 203 common sched_setaffinity sys_sched_setaffinity | ||
213 | 204 common sched_getaffinity sys_sched_getaffinity | ||
214 | 205 64 set_thread_area | ||
215 | 206 64 io_setup sys_io_setup | ||
216 | 207 common io_destroy sys_io_destroy | ||
217 | 208 common io_getevents sys_io_getevents | ||
218 | 209 64 io_submit sys_io_submit | ||
219 | 210 common io_cancel sys_io_cancel | ||
220 | 211 64 get_thread_area | ||
221 | 212 common lookup_dcookie sys_lookup_dcookie | ||
222 | 213 common epoll_create sys_epoll_create | ||
223 | 214 64 epoll_ctl_old | ||
224 | 215 64 epoll_wait_old | ||
225 | 216 common remap_file_pages sys_remap_file_pages | ||
226 | 217 common getdents64 sys_getdents64 | ||
227 | 218 common set_tid_address sys_set_tid_address | ||
228 | 219 common restart_syscall sys_restart_syscall | ||
229 | 220 common semtimedop sys_semtimedop | ||
230 | 221 common fadvise64 sys_fadvise64 | ||
231 | 222 64 timer_create sys_timer_create | ||
232 | 223 common timer_settime sys_timer_settime | ||
233 | 224 common timer_gettime sys_timer_gettime | ||
234 | 225 common timer_getoverrun sys_timer_getoverrun | ||
235 | 226 common timer_delete sys_timer_delete | ||
236 | 227 common clock_settime sys_clock_settime | ||
237 | 228 common clock_gettime sys_clock_gettime | ||
238 | 229 common clock_getres sys_clock_getres | ||
239 | 230 common clock_nanosleep sys_clock_nanosleep | ||
240 | 231 common exit_group sys_exit_group | ||
241 | 232 common epoll_wait sys_epoll_wait | ||
242 | 233 common epoll_ctl sys_epoll_ctl | ||
243 | 234 common tgkill sys_tgkill | ||
244 | 235 common utimes sys_utimes | ||
245 | 236 64 vserver | ||
246 | 237 common mbind sys_mbind | ||
247 | 238 common set_mempolicy sys_set_mempolicy | ||
248 | 239 common get_mempolicy sys_get_mempolicy | ||
249 | 240 common mq_open sys_mq_open | ||
250 | 241 common mq_unlink sys_mq_unlink | ||
251 | 242 common mq_timedsend sys_mq_timedsend | ||
252 | 243 common mq_timedreceive sys_mq_timedreceive | ||
253 | 244 64 mq_notify sys_mq_notify | ||
254 | 245 common mq_getsetattr sys_mq_getsetattr | ||
255 | 246 64 kexec_load sys_kexec_load | ||
256 | 247 64 waitid sys_waitid | ||
257 | 248 common add_key sys_add_key | ||
258 | 249 common request_key sys_request_key | ||
259 | 250 common keyctl sys_keyctl | ||
260 | 251 common ioprio_set sys_ioprio_set | ||
261 | 252 common ioprio_get sys_ioprio_get | ||
262 | 253 common inotify_init sys_inotify_init | ||
263 | 254 common inotify_add_watch sys_inotify_add_watch | ||
264 | 255 common inotify_rm_watch sys_inotify_rm_watch | ||
265 | 256 common migrate_pages sys_migrate_pages | ||
266 | 257 common openat sys_openat | ||
267 | 258 common mkdirat sys_mkdirat | ||
268 | 259 common mknodat sys_mknodat | ||
269 | 260 common fchownat sys_fchownat | ||
270 | 261 common futimesat sys_futimesat | ||
271 | 262 common newfstatat sys_newfstatat | ||
272 | 263 common unlinkat sys_unlinkat | ||
273 | 264 common renameat sys_renameat | ||
274 | 265 common linkat sys_linkat | ||
275 | 266 common symlinkat sys_symlinkat | ||
276 | 267 common readlinkat sys_readlinkat | ||
277 | 268 common fchmodat sys_fchmodat | ||
278 | 269 common faccessat sys_faccessat | ||
279 | 270 common pselect6 sys_pselect6 | ||
280 | 271 common ppoll sys_ppoll | ||
281 | 272 common unshare sys_unshare | ||
282 | 273 64 set_robust_list sys_set_robust_list | ||
283 | 274 64 get_robust_list sys_get_robust_list | ||
284 | 275 common splice sys_splice | ||
285 | 276 common tee sys_tee | ||
286 | 277 common sync_file_range sys_sync_file_range | ||
287 | 278 64 vmsplice sys_vmsplice | ||
288 | 279 64 move_pages sys_move_pages | ||
289 | 280 common utimensat sys_utimensat | ||
290 | 281 common epoll_pwait sys_epoll_pwait | ||
291 | 282 common signalfd sys_signalfd | ||
292 | 283 common timerfd_create sys_timerfd_create | ||
293 | 284 common eventfd sys_eventfd | ||
294 | 285 common fallocate sys_fallocate | ||
295 | 286 common timerfd_settime sys_timerfd_settime | ||
296 | 287 common timerfd_gettime sys_timerfd_gettime | ||
297 | 288 common accept4 sys_accept4 | ||
298 | 289 common signalfd4 sys_signalfd4 | ||
299 | 290 common eventfd2 sys_eventfd2 | ||
300 | 291 common epoll_create1 sys_epoll_create1 | ||
301 | 292 common dup3 sys_dup3 | ||
302 | 293 common pipe2 sys_pipe2 | ||
303 | 294 common inotify_init1 sys_inotify_init1 | ||
304 | 295 64 preadv sys_preadv | ||
305 | 296 64 pwritev sys_pwritev | ||
306 | 297 64 rt_tgsigqueueinfo sys_rt_tgsigqueueinfo | ||
307 | 298 common perf_event_open sys_perf_event_open | ||
308 | 299 64 recvmmsg sys_recvmmsg | ||
309 | 300 common fanotify_init sys_fanotify_init | ||
310 | 301 common fanotify_mark sys_fanotify_mark | ||
311 | 302 common prlimit64 sys_prlimit64 | ||
312 | 303 common name_to_handle_at sys_name_to_handle_at | ||
313 | 304 common open_by_handle_at sys_open_by_handle_at | ||
314 | 305 common clock_adjtime sys_clock_adjtime | ||
315 | 306 common syncfs sys_syncfs | ||
316 | 307 64 sendmmsg sys_sendmmsg | ||
317 | 308 common setns sys_setns | ||
318 | 309 common getcpu sys_getcpu | ||
319 | 310 64 process_vm_readv sys_process_vm_readv | ||
320 | 311 64 process_vm_writev sys_process_vm_writev | ||
321 | 312 common kcmp sys_kcmp | ||
322 | 313 common finit_module sys_finit_module | ||
323 | 314 common sched_setattr sys_sched_setattr | ||
324 | 315 common sched_getattr sys_sched_getattr | ||
325 | 316 common renameat2 sys_renameat2 | ||
326 | 317 common seccomp sys_seccomp | ||
327 | 318 common getrandom sys_getrandom | ||
328 | 319 common memfd_create sys_memfd_create | ||
329 | 320 common kexec_file_load sys_kexec_file_load | ||
330 | 321 common bpf sys_bpf | ||
331 | 322 64 execveat sys_execveat/ptregs | ||
332 | 323 common userfaultfd sys_userfaultfd | ||
333 | 324 common membarrier sys_membarrier | ||
334 | 325 common mlock2 sys_mlock2 | ||
335 | 326 common copy_file_range sys_copy_file_range | ||
336 | 327 64 preadv2 sys_preadv2 | ||
337 | 328 64 pwritev2 sys_pwritev2 | ||
338 | |||
339 | # | ||
340 | # x32-specific system call numbers start at 512 to avoid cache impact | ||
341 | # for native 64-bit operation. | ||
342 | # | ||
343 | 512 x32 rt_sigaction compat_sys_rt_sigaction | ||
344 | 513 x32 rt_sigreturn sys32_x32_rt_sigreturn | ||
345 | 514 x32 ioctl compat_sys_ioctl | ||
346 | 515 x32 readv compat_sys_readv | ||
347 | 516 x32 writev compat_sys_writev | ||
348 | 517 x32 recvfrom compat_sys_recvfrom | ||
349 | 518 x32 sendmsg compat_sys_sendmsg | ||
350 | 519 x32 recvmsg compat_sys_recvmsg | ||
351 | 520 x32 execve compat_sys_execve/ptregs | ||
352 | 521 x32 ptrace compat_sys_ptrace | ||
353 | 522 x32 rt_sigpending compat_sys_rt_sigpending | ||
354 | 523 x32 rt_sigtimedwait compat_sys_rt_sigtimedwait | ||
355 | 524 x32 rt_sigqueueinfo compat_sys_rt_sigqueueinfo | ||
356 | 525 x32 sigaltstack compat_sys_sigaltstack | ||
357 | 526 x32 timer_create compat_sys_timer_create | ||
358 | 527 x32 mq_notify compat_sys_mq_notify | ||
359 | 528 x32 kexec_load compat_sys_kexec_load | ||
360 | 529 x32 waitid compat_sys_waitid | ||
361 | 530 x32 set_robust_list compat_sys_set_robust_list | ||
362 | 531 x32 get_robust_list compat_sys_get_robust_list | ||
363 | 532 x32 vmsplice compat_sys_vmsplice | ||
364 | 533 x32 move_pages compat_sys_move_pages | ||
365 | 534 x32 preadv compat_sys_preadv64 | ||
366 | 535 x32 pwritev compat_sys_pwritev64 | ||
367 | 536 x32 rt_tgsigqueueinfo compat_sys_rt_tgsigqueueinfo | ||
368 | 537 x32 recvmmsg compat_sys_recvmmsg | ||
369 | 538 x32 sendmmsg compat_sys_sendmmsg | ||
370 | 539 x32 process_vm_readv compat_sys_process_vm_readv | ||
371 | 540 x32 process_vm_writev compat_sys_process_vm_writev | ||
372 | 541 x32 setsockopt compat_sys_setsockopt | ||
373 | 542 x32 getsockopt compat_sys_getsockopt | ||
374 | 543 x32 io_setup compat_sys_io_setup | ||
375 | 544 x32 io_submit compat_sys_io_submit | ||
376 | 545 x32 execveat compat_sys_execveat/ptregs | ||
diff --git a/tools/perf/arch/x86/entry/syscalls/syscalltbl.sh b/tools/perf/arch/x86/entry/syscalls/syscalltbl.sh new file mode 100755 index 000000000000..49a18b9ad9cf --- /dev/null +++ b/tools/perf/arch/x86/entry/syscalls/syscalltbl.sh | |||
@@ -0,0 +1,39 @@ | |||
1 | #!/bin/sh | ||
2 | |||
3 | in="$1" | ||
4 | arch="$2" | ||
5 | |||
6 | syscall_macro() { | ||
7 | nr="$1" | ||
8 | name="$2" | ||
9 | |||
10 | echo " [$nr] = \"$name\"," | ||
11 | } | ||
12 | |||
13 | emit() { | ||
14 | nr="$1" | ||
15 | entry="$2" | ||
16 | |||
17 | syscall_macro "$nr" "$entry" | ||
18 | } | ||
19 | |||
20 | echo "static const char *syscalltbl_${arch}[] = {" | ||
21 | |||
22 | sorted_table=$(mktemp /tmp/syscalltbl.XXXXXX) | ||
23 | grep '^[0-9]' "$in" | sort -n > $sorted_table | ||
24 | |||
25 | max_nr=0 | ||
26 | while read nr abi name entry compat; do | ||
27 | if [ $nr -ge 512 ] ; then # discard compat sycalls | ||
28 | break | ||
29 | fi | ||
30 | |||
31 | emit "$nr" "$name" | ||
32 | max_nr=$nr | ||
33 | done < $sorted_table | ||
34 | |||
35 | rm -f $sorted_table | ||
36 | |||
37 | echo "};" | ||
38 | |||
39 | echo "#define SYSCALLTBL_${arch}_MAX_ID ${max_nr}" | ||
diff --git a/tools/perf/arch/x86/tests/perf-time-to-tsc.c b/tools/perf/arch/x86/tests/perf-time-to-tsc.c index 9d29ee283ac5..d4aa567a29c4 100644 --- a/tools/perf/arch/x86/tests/perf-time-to-tsc.c +++ b/tools/perf/arch/x86/tests/perf-time-to-tsc.c | |||
@@ -71,7 +71,7 @@ int test__perf_time_to_tsc(int subtest __maybe_unused) | |||
71 | 71 | ||
72 | CHECK__(parse_events(evlist, "cycles:u", NULL)); | 72 | CHECK__(parse_events(evlist, "cycles:u", NULL)); |
73 | 73 | ||
74 | perf_evlist__config(evlist, &opts); | 74 | perf_evlist__config(evlist, &opts, NULL); |
75 | 75 | ||
76 | evsel = perf_evlist__first(evlist); | 76 | evsel = perf_evlist__first(evlist); |
77 | 77 | ||
diff --git a/tools/perf/arch/x86/util/dwarf-regs.c b/tools/perf/arch/x86/util/dwarf-regs.c index 9223c164e545..1f86ee8fb831 100644 --- a/tools/perf/arch/x86/util/dwarf-regs.c +++ b/tools/perf/arch/x86/util/dwarf-regs.c | |||
@@ -63,6 +63,8 @@ struct pt_regs_offset { | |||
63 | # define REG_OFFSET_NAME_32(n, r) {.name = n, .offset = offsetof(struct pt_regs, r)} | 63 | # define REG_OFFSET_NAME_32(n, r) {.name = n, .offset = offsetof(struct pt_regs, r)} |
64 | #endif | 64 | #endif |
65 | 65 | ||
66 | /* TODO: switching by dwarf address size */ | ||
67 | #ifndef __x86_64__ | ||
66 | static const struct pt_regs_offset x86_32_regoffset_table[] = { | 68 | static const struct pt_regs_offset x86_32_regoffset_table[] = { |
67 | REG_OFFSET_NAME_32("%ax", eax), | 69 | REG_OFFSET_NAME_32("%ax", eax), |
68 | REG_OFFSET_NAME_32("%cx", ecx), | 70 | REG_OFFSET_NAME_32("%cx", ecx), |
@@ -75,6 +77,8 @@ static const struct pt_regs_offset x86_32_regoffset_table[] = { | |||
75 | REG_OFFSET_END, | 77 | REG_OFFSET_END, |
76 | }; | 78 | }; |
77 | 79 | ||
80 | #define regoffset_table x86_32_regoffset_table | ||
81 | #else | ||
78 | static const struct pt_regs_offset x86_64_regoffset_table[] = { | 82 | static const struct pt_regs_offset x86_64_regoffset_table[] = { |
79 | REG_OFFSET_NAME_64("%ax", rax), | 83 | REG_OFFSET_NAME_64("%ax", rax), |
80 | REG_OFFSET_NAME_64("%dx", rdx), | 84 | REG_OFFSET_NAME_64("%dx", rdx), |
@@ -95,11 +99,7 @@ static const struct pt_regs_offset x86_64_regoffset_table[] = { | |||
95 | REG_OFFSET_END, | 99 | REG_OFFSET_END, |
96 | }; | 100 | }; |
97 | 101 | ||
98 | /* TODO: switching by dwarf address size */ | ||
99 | #ifdef __x86_64__ | ||
100 | #define regoffset_table x86_64_regoffset_table | 102 | #define regoffset_table x86_64_regoffset_table |
101 | #else | ||
102 | #define regoffset_table x86_32_regoffset_table | ||
103 | #endif | 103 | #endif |
104 | 104 | ||
105 | /* Minus 1 for the ending REG_OFFSET_END */ | 105 | /* Minus 1 for the ending REG_OFFSET_END */ |
diff --git a/tools/perf/arch/x86/util/intel-bts.c b/tools/perf/arch/x86/util/intel-bts.c index d66f9ad4df2e..7dc30637cf66 100644 --- a/tools/perf/arch/x86/util/intel-bts.c +++ b/tools/perf/arch/x86/util/intel-bts.c | |||
@@ -438,6 +438,11 @@ struct auxtrace_record *intel_bts_recording_init(int *err) | |||
438 | if (!intel_bts_pmu) | 438 | if (!intel_bts_pmu) |
439 | return NULL; | 439 | return NULL; |
440 | 440 | ||
441 | if (setenv("JITDUMP_USE_ARCH_TIMESTAMP", "1", 1)) { | ||
442 | *err = -errno; | ||
443 | return NULL; | ||
444 | } | ||
445 | |||
441 | btsr = zalloc(sizeof(struct intel_bts_recording)); | 446 | btsr = zalloc(sizeof(struct intel_bts_recording)); |
442 | if (!btsr) { | 447 | if (!btsr) { |
443 | *err = -ENOMEM; | 448 | *err = -ENOMEM; |
diff --git a/tools/perf/arch/x86/util/intel-pt.c b/tools/perf/arch/x86/util/intel-pt.c index a3395179c9ee..a07b9605e93b 100644 --- a/tools/perf/arch/x86/util/intel-pt.c +++ b/tools/perf/arch/x86/util/intel-pt.c | |||
@@ -1027,6 +1027,11 @@ struct auxtrace_record *intel_pt_recording_init(int *err) | |||
1027 | if (!intel_pt_pmu) | 1027 | if (!intel_pt_pmu) |
1028 | return NULL; | 1028 | return NULL; |
1029 | 1029 | ||
1030 | if (setenv("JITDUMP_USE_ARCH_TIMESTAMP", "1", 1)) { | ||
1031 | *err = -errno; | ||
1032 | return NULL; | ||
1033 | } | ||
1034 | |||
1030 | ptr = zalloc(sizeof(struct intel_pt_recording)); | 1035 | ptr = zalloc(sizeof(struct intel_pt_recording)); |
1031 | if (!ptr) { | 1036 | if (!ptr) { |
1032 | *err = -ENOMEM; | 1037 | *err = -ENOMEM; |
diff --git a/tools/perf/arch/x86/util/tsc.c b/tools/perf/arch/x86/util/tsc.c index fd2868490d00..357f1b13b5ae 100644 --- a/tools/perf/arch/x86/util/tsc.c +++ b/tools/perf/arch/x86/util/tsc.c | |||
@@ -7,7 +7,6 @@ | |||
7 | #include <linux/types.h> | 7 | #include <linux/types.h> |
8 | #include "../../util/debug.h" | 8 | #include "../../util/debug.h" |
9 | #include "../../util/tsc.h" | 9 | #include "../../util/tsc.h" |
10 | #include "tsc.h" | ||
11 | 10 | ||
12 | int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, | 11 | int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, |
13 | struct perf_tsc_conversion *tc) | 12 | struct perf_tsc_conversion *tc) |
@@ -46,3 +45,34 @@ u64 rdtsc(void) | |||
46 | 45 | ||
47 | return low | ((u64)high) << 32; | 46 | return low | ((u64)high) << 32; |
48 | } | 47 | } |
48 | |||
49 | int perf_event__synth_time_conv(const struct perf_event_mmap_page *pc, | ||
50 | struct perf_tool *tool, | ||
51 | perf_event__handler_t process, | ||
52 | struct machine *machine) | ||
53 | { | ||
54 | union perf_event event = { | ||
55 | .time_conv = { | ||
56 | .header = { | ||
57 | .type = PERF_RECORD_TIME_CONV, | ||
58 | .size = sizeof(struct time_conv_event), | ||
59 | }, | ||
60 | }, | ||
61 | }; | ||
62 | struct perf_tsc_conversion tc; | ||
63 | int err; | ||
64 | |||
65 | err = perf_read_tsc_conversion(pc, &tc); | ||
66 | if (err == -EOPNOTSUPP) | ||
67 | return 0; | ||
68 | if (err) | ||
69 | return err; | ||
70 | |||
71 | pr_debug2("Synthesizing TSC conversion information\n"); | ||
72 | |||
73 | event.time_conv.time_mult = tc.time_mult; | ||
74 | event.time_conv.time_shift = tc.time_shift; | ||
75 | event.time_conv.time_zero = tc.time_zero; | ||
76 | |||
77 | return process(tool, &event, NULL, machine); | ||
78 | } | ||
diff --git a/tools/perf/arch/x86/util/tsc.h b/tools/perf/arch/x86/util/tsc.h deleted file mode 100644 index 2edc4d31065c..000000000000 --- a/tools/perf/arch/x86/util/tsc.h +++ /dev/null | |||
@@ -1,17 +0,0 @@ | |||
1 | #ifndef TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ | ||
2 | #define TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ | ||
3 | |||
4 | #include <linux/types.h> | ||
5 | |||
6 | struct perf_tsc_conversion { | ||
7 | u16 time_shift; | ||
8 | u32 time_mult; | ||
9 | u64 time_zero; | ||
10 | }; | ||
11 | |||
12 | struct perf_event_mmap_page; | ||
13 | |||
14 | int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, | ||
15 | struct perf_tsc_conversion *tc); | ||
16 | |||
17 | #endif /* TOOLS_PERF_ARCH_X86_UTIL_TSC_H__ */ | ||
diff --git a/tools/perf/bench/futex-lock-pi.c b/tools/perf/bench/futex-lock-pi.c index 6a18ce21f865..6952db65508a 100644 --- a/tools/perf/bench/futex-lock-pi.c +++ b/tools/perf/bench/futex-lock-pi.c | |||
@@ -83,7 +83,7 @@ static void *workerfn(void *arg) | |||
83 | do { | 83 | do { |
84 | int ret; | 84 | int ret; |
85 | again: | 85 | again: |
86 | ret = futex_lock_pi(w->futex, NULL, 0, futex_flag); | 86 | ret = futex_lock_pi(w->futex, NULL, futex_flag); |
87 | 87 | ||
88 | if (ret) { /* handle lock acquisition */ | 88 | if (ret) { /* handle lock acquisition */ |
89 | if (!silent) | 89 | if (!silent) |
diff --git a/tools/perf/bench/futex.h b/tools/perf/bench/futex.h index d44de9f44281..b2e06d1190d0 100644 --- a/tools/perf/bench/futex.h +++ b/tools/perf/bench/futex.h | |||
@@ -57,13 +57,11 @@ futex_wake(u_int32_t *uaddr, int nr_wake, int opflags) | |||
57 | 57 | ||
58 | /** | 58 | /** |
59 | * futex_lock_pi() - block on uaddr as a PI mutex | 59 | * futex_lock_pi() - block on uaddr as a PI mutex |
60 | * @detect: whether (1) or not (0) to perform deadlock detection | ||
61 | */ | 60 | */ |
62 | static inline int | 61 | static inline int |
63 | futex_lock_pi(u_int32_t *uaddr, struct timespec *timeout, int detect, | 62 | futex_lock_pi(u_int32_t *uaddr, struct timespec *timeout, int opflags) |
64 | int opflags) | ||
65 | { | 63 | { |
66 | return futex(uaddr, FUTEX_LOCK_PI, detect, timeout, NULL, 0, opflags); | 64 | return futex(uaddr, FUTEX_LOCK_PI, 0, timeout, NULL, 0, opflags); |
67 | } | 65 | } |
68 | 66 | ||
69 | /** | 67 | /** |
diff --git a/tools/perf/bench/mem-functions.c b/tools/perf/bench/mem-functions.c index a91aa85d80ff..2b54d0f2672a 100644 --- a/tools/perf/bench/mem-functions.c +++ b/tools/perf/bench/mem-functions.c | |||
@@ -6,6 +6,7 @@ | |||
6 | * Written by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> | 6 | * Written by Hitoshi Mitake <mitake@dcl.info.waseda.ac.jp> |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include "debug.h" | ||
9 | #include "../perf.h" | 10 | #include "../perf.h" |
10 | #include "../util/util.h" | 11 | #include "../util/util.h" |
11 | #include <subcmd/parse-options.h> | 12 | #include <subcmd/parse-options.h> |
@@ -63,14 +64,16 @@ static struct perf_event_attr cycle_attr = { | |||
63 | .config = PERF_COUNT_HW_CPU_CYCLES | 64 | .config = PERF_COUNT_HW_CPU_CYCLES |
64 | }; | 65 | }; |
65 | 66 | ||
66 | static void init_cycles(void) | 67 | static int init_cycles(void) |
67 | { | 68 | { |
68 | cycles_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, perf_event_open_cloexec_flag()); | 69 | cycles_fd = sys_perf_event_open(&cycle_attr, getpid(), -1, -1, perf_event_open_cloexec_flag()); |
69 | 70 | ||
70 | if (cycles_fd < 0 && errno == ENOSYS) | 71 | if (cycles_fd < 0 && errno == ENOSYS) { |
71 | die("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); | 72 | pr_debug("No CONFIG_PERF_EVENTS=y kernel support configured?\n"); |
72 | else | 73 | return -1; |
73 | BUG_ON(cycles_fd < 0); | 74 | } |
75 | |||
76 | return cycles_fd; | ||
74 | } | 77 | } |
75 | 78 | ||
76 | static u64 get_cycles(void) | 79 | static u64 get_cycles(void) |
@@ -155,8 +158,13 @@ static int bench_mem_common(int argc, const char **argv, struct bench_mem_info * | |||
155 | 158 | ||
156 | argc = parse_options(argc, argv, options, info->usage, 0); | 159 | argc = parse_options(argc, argv, options, info->usage, 0); |
157 | 160 | ||
158 | if (use_cycles) | 161 | if (use_cycles) { |
159 | init_cycles(); | 162 | i = init_cycles(); |
163 | if (i < 0) { | ||
164 | fprintf(stderr, "Failed to open cycles counter\n"); | ||
165 | return i; | ||
166 | } | ||
167 | } | ||
160 | 168 | ||
161 | size = (size_t)perf_atoll((char *)size_str); | 169 | size = (size_t)perf_atoll((char *)size_str); |
162 | size_total = (double)size * nr_loops; | 170 | size_total = (double)size * nr_loops; |
diff --git a/tools/perf/builtin-config.c b/tools/perf/builtin-config.c index c42448ed5dfe..fe1b77fa21f9 100644 --- a/tools/perf/builtin-config.c +++ b/tools/perf/builtin-config.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <subcmd/parse-options.h> | 12 | #include <subcmd/parse-options.h> |
13 | #include "util/util.h" | 13 | #include "util/util.h" |
14 | #include "util/debug.h" | 14 | #include "util/debug.h" |
15 | #include "util/config.h" | ||
15 | 16 | ||
16 | static bool use_system_config, use_user_config; | 17 | static bool use_system_config, use_user_config; |
17 | 18 | ||
@@ -32,13 +33,28 @@ static struct option config_options[] = { | |||
32 | OPT_END() | 33 | OPT_END() |
33 | }; | 34 | }; |
34 | 35 | ||
35 | static int show_config(const char *key, const char *value, | 36 | static int show_config(struct perf_config_set *set) |
36 | void *cb __maybe_unused) | ||
37 | { | 37 | { |
38 | if (value) | 38 | struct perf_config_section *section; |
39 | printf("%s=%s\n", key, value); | 39 | struct perf_config_item *item; |
40 | else | 40 | struct list_head *sections; |
41 | printf("%s\n", key); | 41 | |
42 | if (set == NULL) | ||
43 | return -1; | ||
44 | |||
45 | sections = &set->sections; | ||
46 | if (list_empty(sections)) | ||
47 | return -1; | ||
48 | |||
49 | list_for_each_entry(section, sections, node) { | ||
50 | list_for_each_entry(item, §ion->items, node) { | ||
51 | char *value = item->value; | ||
52 | |||
53 | if (value) | ||
54 | printf("%s.%s=%s\n", section->name, | ||
55 | item->name, value); | ||
56 | } | ||
57 | } | ||
42 | 58 | ||
43 | return 0; | 59 | return 0; |
44 | } | 60 | } |
@@ -46,6 +62,7 @@ static int show_config(const char *key, const char *value, | |||
46 | int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused) | 62 | int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused) |
47 | { | 63 | { |
48 | int ret = 0; | 64 | int ret = 0; |
65 | struct perf_config_set *set; | ||
49 | char *user_config = mkpath("%s/.perfconfig", getenv("HOME")); | 66 | char *user_config = mkpath("%s/.perfconfig", getenv("HOME")); |
50 | 67 | ||
51 | argc = parse_options(argc, argv, config_options, config_usage, | 68 | argc = parse_options(argc, argv, config_options, config_usage, |
@@ -63,13 +80,19 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused) | |||
63 | else if (use_user_config) | 80 | else if (use_user_config) |
64 | config_exclusive_filename = user_config; | 81 | config_exclusive_filename = user_config; |
65 | 82 | ||
83 | set = perf_config_set__new(); | ||
84 | if (!set) { | ||
85 | ret = -1; | ||
86 | goto out_err; | ||
87 | } | ||
88 | |||
66 | switch (actions) { | 89 | switch (actions) { |
67 | case ACTION_LIST: | 90 | case ACTION_LIST: |
68 | if (argc) { | 91 | if (argc) { |
69 | pr_err("Error: takes no arguments\n"); | 92 | pr_err("Error: takes no arguments\n"); |
70 | parse_options_usage(config_usage, config_options, "l", 1); | 93 | parse_options_usage(config_usage, config_options, "l", 1); |
71 | } else { | 94 | } else { |
72 | ret = perf_config(show_config, NULL); | 95 | ret = show_config(set); |
73 | if (ret < 0) { | 96 | if (ret < 0) { |
74 | const char * config_filename = config_exclusive_filename; | 97 | const char * config_filename = config_exclusive_filename; |
75 | if (!config_exclusive_filename) | 98 | if (!config_exclusive_filename) |
@@ -83,5 +106,7 @@ int cmd_config(int argc, const char **argv, const char *prefix __maybe_unused) | |||
83 | usage_with_options(config_usage, config_options); | 106 | usage_with_options(config_usage, config_options); |
84 | } | 107 | } |
85 | 108 | ||
109 | perf_config_set__delete(set); | ||
110 | out_err: | ||
86 | return ret; | 111 | return ret; |
87 | } | 112 | } |
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c index 8053a8ceefda..9ce354f469dc 100644 --- a/tools/perf/builtin-diff.c +++ b/tools/perf/builtin-diff.c | |||
@@ -428,7 +428,7 @@ static void hists__baseline_only(struct hists *hists) | |||
428 | struct rb_root *root; | 428 | struct rb_root *root; |
429 | struct rb_node *next; | 429 | struct rb_node *next; |
430 | 430 | ||
431 | if (sort__need_collapse) | 431 | if (hists__has(hists, need_collapse)) |
432 | root = &hists->entries_collapsed; | 432 | root = &hists->entries_collapsed; |
433 | else | 433 | else |
434 | root = hists->entries_in; | 434 | root = hists->entries_in; |
@@ -450,7 +450,7 @@ static void hists__precompute(struct hists *hists) | |||
450 | struct rb_root *root; | 450 | struct rb_root *root; |
451 | struct rb_node *next; | 451 | struct rb_node *next; |
452 | 452 | ||
453 | if (sort__need_collapse) | 453 | if (hists__has(hists, need_collapse)) |
454 | root = &hists->entries_collapsed; | 454 | root = &hists->entries_collapsed; |
455 | else | 455 | else |
456 | root = hists->entries_in; | 456 | root = hists->entries_in; |
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c index bc1de9b8fd67..f9830c902b78 100644 --- a/tools/perf/builtin-help.c +++ b/tools/perf/builtin-help.c | |||
@@ -61,6 +61,7 @@ static int check_emacsclient_version(void) | |||
61 | struct child_process ec_process; | 61 | struct child_process ec_process; |
62 | const char *argv_ec[] = { "emacsclient", "--version", NULL }; | 62 | const char *argv_ec[] = { "emacsclient", "--version", NULL }; |
63 | int version; | 63 | int version; |
64 | int ret = -1; | ||
64 | 65 | ||
65 | /* emacsclient prints its version number on stderr */ | 66 | /* emacsclient prints its version number on stderr */ |
66 | memset(&ec_process, 0, sizeof(ec_process)); | 67 | memset(&ec_process, 0, sizeof(ec_process)); |
@@ -71,7 +72,10 @@ static int check_emacsclient_version(void) | |||
71 | fprintf(stderr, "Failed to start emacsclient.\n"); | 72 | fprintf(stderr, "Failed to start emacsclient.\n"); |
72 | return -1; | 73 | return -1; |
73 | } | 74 | } |
74 | strbuf_read(&buffer, ec_process.err, 20); | 75 | if (strbuf_read(&buffer, ec_process.err, 20) < 0) { |
76 | fprintf(stderr, "Failed to read emacsclient version\n"); | ||
77 | goto out; | ||
78 | } | ||
75 | close(ec_process.err); | 79 | close(ec_process.err); |
76 | 80 | ||
77 | /* | 81 | /* |
@@ -82,8 +86,7 @@ static int check_emacsclient_version(void) | |||
82 | 86 | ||
83 | if (prefixcmp(buffer.buf, "emacsclient")) { | 87 | if (prefixcmp(buffer.buf, "emacsclient")) { |
84 | fprintf(stderr, "Failed to parse emacsclient version.\n"); | 88 | fprintf(stderr, "Failed to parse emacsclient version.\n"); |
85 | strbuf_release(&buffer); | 89 | goto out; |
86 | return -1; | ||
87 | } | 90 | } |
88 | 91 | ||
89 | version = atoi(buffer.buf + strlen("emacsclient")); | 92 | version = atoi(buffer.buf + strlen("emacsclient")); |
@@ -92,12 +95,11 @@ static int check_emacsclient_version(void) | |||
92 | fprintf(stderr, | 95 | fprintf(stderr, |
93 | "emacsclient version '%d' too old (< 22).\n", | 96 | "emacsclient version '%d' too old (< 22).\n", |
94 | version); | 97 | version); |
95 | strbuf_release(&buffer); | 98 | } else |
96 | return -1; | 99 | ret = 0; |
97 | } | 100 | out: |
98 | |||
99 | strbuf_release(&buffer); | 101 | strbuf_release(&buffer); |
100 | return 0; | 102 | return ret; |
101 | } | 103 | } |
102 | 104 | ||
103 | static void exec_woman_emacs(const char *path, const char *page) | 105 | static void exec_woman_emacs(const char *path, const char *page) |
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c index d1a2d104f2bc..e5afa8fe1bf1 100644 --- a/tools/perf/builtin-inject.c +++ b/tools/perf/builtin-inject.c | |||
@@ -748,6 +748,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused) | |||
748 | .auxtrace_info = perf_event__repipe_op2_synth, | 748 | .auxtrace_info = perf_event__repipe_op2_synth, |
749 | .auxtrace = perf_event__repipe_auxtrace, | 749 | .auxtrace = perf_event__repipe_auxtrace, |
750 | .auxtrace_error = perf_event__repipe_op2_synth, | 750 | .auxtrace_error = perf_event__repipe_op2_synth, |
751 | .time_conv = perf_event__repipe_op2_synth, | ||
751 | .finished_round = perf_event__repipe_oe_synth, | 752 | .finished_round = perf_event__repipe_oe_synth, |
752 | .build_id = perf_event__repipe_op2_synth, | 753 | .build_id = perf_event__repipe_op2_synth, |
753 | .id_index = perf_event__repipe_op2_synth, | 754 | .id_index = perf_event__repipe_op2_synth, |
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index c9cb3be47cff..58adfee230de 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
@@ -375,7 +375,7 @@ static u64 find_callsite(struct perf_evsel *evsel, struct perf_sample *sample) | |||
375 | } | 375 | } |
376 | 376 | ||
377 | al.thread = machine__findnew_thread(machine, sample->pid, sample->tid); | 377 | al.thread = machine__findnew_thread(machine, sample->pid, sample->tid); |
378 | sample__resolve_callchain(sample, NULL, evsel, &al, 16); | 378 | sample__resolve_callchain(sample, &callchain_cursor, NULL, evsel, &al, 16); |
379 | 379 | ||
380 | callchain_cursor_commit(&callchain_cursor); | 380 | callchain_cursor_commit(&callchain_cursor); |
381 | while (true) { | 381 | while (true) { |
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index bff666458b28..6487c06d2708 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c | |||
@@ -982,7 +982,7 @@ static int kvm_live_open_events(struct perf_kvm_stat *kvm) | |||
982 | struct perf_evlist *evlist = kvm->evlist; | 982 | struct perf_evlist *evlist = kvm->evlist; |
983 | char sbuf[STRERR_BUFSIZE]; | 983 | char sbuf[STRERR_BUFSIZE]; |
984 | 984 | ||
985 | perf_evlist__config(evlist, &kvm->opts); | 985 | perf_evlist__config(evlist, &kvm->opts, NULL); |
986 | 986 | ||
987 | /* | 987 | /* |
988 | * Note: exclude_{guest,host} do not apply here. | 988 | * Note: exclude_{guest,host} do not apply here. |
diff --git a/tools/perf/builtin-mem.c b/tools/perf/builtin-mem.c index 85db3be4b3cb..1dc140c5481d 100644 --- a/tools/perf/builtin-mem.c +++ b/tools/perf/builtin-mem.c | |||
@@ -62,19 +62,22 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem) | |||
62 | int rec_argc, i = 0, j; | 62 | int rec_argc, i = 0, j; |
63 | const char **rec_argv; | 63 | const char **rec_argv; |
64 | int ret; | 64 | int ret; |
65 | bool all_user = false, all_kernel = false; | ||
65 | struct option options[] = { | 66 | struct option options[] = { |
66 | OPT_CALLBACK('e', "event", &mem, "event", | 67 | OPT_CALLBACK('e', "event", &mem, "event", |
67 | "event selector. use 'perf mem record -e list' to list available events", | 68 | "event selector. use 'perf mem record -e list' to list available events", |
68 | parse_record_events), | 69 | parse_record_events), |
69 | OPT_INCR('v', "verbose", &verbose, | 70 | OPT_INCR('v', "verbose", &verbose, |
70 | "be more verbose (show counter open errors, etc)"), | 71 | "be more verbose (show counter open errors, etc)"), |
72 | OPT_BOOLEAN('U', "--all-user", &all_user, "collect only user level data"), | ||
73 | OPT_BOOLEAN('K', "--all-kernel", &all_kernel, "collect only kernel level data"), | ||
71 | OPT_END() | 74 | OPT_END() |
72 | }; | 75 | }; |
73 | 76 | ||
74 | argc = parse_options(argc, argv, options, record_mem_usage, | 77 | argc = parse_options(argc, argv, options, record_mem_usage, |
75 | PARSE_OPT_STOP_AT_NON_OPTION); | 78 | PARSE_OPT_STOP_AT_NON_OPTION); |
76 | 79 | ||
77 | rec_argc = argc + 7; /* max number of arguments */ | 80 | rec_argc = argc + 9; /* max number of arguments */ |
78 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); | 81 | rec_argv = calloc(rec_argc + 1, sizeof(char *)); |
79 | if (!rec_argv) | 82 | if (!rec_argv) |
80 | return -1; | 83 | return -1; |
@@ -103,6 +106,12 @@ static int __cmd_record(int argc, const char **argv, struct perf_mem *mem) | |||
103 | rec_argv[i++] = perf_mem_events__name(j); | 106 | rec_argv[i++] = perf_mem_events__name(j); |
104 | }; | 107 | }; |
105 | 108 | ||
109 | if (all_user) | ||
110 | rec_argv[i++] = "--all-user"; | ||
111 | |||
112 | if (all_kernel) | ||
113 | rec_argv[i++] = "--all-kernel"; | ||
114 | |||
106 | for (j = 0; j < argc; j++, i++) | 115 | for (j = 0; j < argc; j++, i++) |
107 | rec_argv[i] = argv[j]; | 116 | rec_argv[i] = argv[j]; |
108 | 117 | ||
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 515510ecc76a..f3679c44d3f3 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -29,10 +29,12 @@ | |||
29 | #include "util/data.h" | 29 | #include "util/data.h" |
30 | #include "util/perf_regs.h" | 30 | #include "util/perf_regs.h" |
31 | #include "util/auxtrace.h" | 31 | #include "util/auxtrace.h" |
32 | #include "util/tsc.h" | ||
32 | #include "util/parse-branch-options.h" | 33 | #include "util/parse-branch-options.h" |
33 | #include "util/parse-regs-options.h" | 34 | #include "util/parse-regs-options.h" |
34 | #include "util/llvm-utils.h" | 35 | #include "util/llvm-utils.h" |
35 | #include "util/bpf-loader.h" | 36 | #include "util/bpf-loader.h" |
37 | #include "util/trigger.h" | ||
36 | #include "asm/bug.h" | 38 | #include "asm/bug.h" |
37 | 39 | ||
38 | #include <unistd.h> | 40 | #include <unistd.h> |
@@ -55,6 +57,8 @@ struct record { | |||
55 | bool no_buildid_cache; | 57 | bool no_buildid_cache; |
56 | bool no_buildid_cache_set; | 58 | bool no_buildid_cache_set; |
57 | bool buildid_all; | 59 | bool buildid_all; |
60 | bool timestamp_filename; | ||
61 | bool switch_output; | ||
58 | unsigned long long samples; | 62 | unsigned long long samples; |
59 | }; | 63 | }; |
60 | 64 | ||
@@ -124,9 +128,10 @@ out: | |||
124 | static volatile int done; | 128 | static volatile int done; |
125 | static volatile int signr = -1; | 129 | static volatile int signr = -1; |
126 | static volatile int child_finished; | 130 | static volatile int child_finished; |
127 | static volatile int auxtrace_snapshot_enabled; | 131 | |
128 | static volatile int auxtrace_snapshot_err; | ||
129 | static volatile int auxtrace_record__snapshot_started; | 132 | static volatile int auxtrace_record__snapshot_started; |
133 | static DEFINE_TRIGGER(auxtrace_snapshot_trigger); | ||
134 | static DEFINE_TRIGGER(switch_output_trigger); | ||
130 | 135 | ||
131 | static void sig_handler(int sig) | 136 | static void sig_handler(int sig) |
132 | { | 137 | { |
@@ -244,11 +249,12 @@ static void record__read_auxtrace_snapshot(struct record *rec) | |||
244 | { | 249 | { |
245 | pr_debug("Recording AUX area tracing snapshot\n"); | 250 | pr_debug("Recording AUX area tracing snapshot\n"); |
246 | if (record__auxtrace_read_snapshot_all(rec) < 0) { | 251 | if (record__auxtrace_read_snapshot_all(rec) < 0) { |
247 | auxtrace_snapshot_err = -1; | 252 | trigger_error(&auxtrace_snapshot_trigger); |
248 | } else { | 253 | } else { |
249 | auxtrace_snapshot_err = auxtrace_record__snapshot_finish(rec->itr); | 254 | if (auxtrace_record__snapshot_finish(rec->itr)) |
250 | if (!auxtrace_snapshot_err) | 255 | trigger_error(&auxtrace_snapshot_trigger); |
251 | auxtrace_snapshot_enabled = 1; | 256 | else |
257 | trigger_ready(&auxtrace_snapshot_trigger); | ||
252 | } | 258 | } |
253 | } | 259 | } |
254 | 260 | ||
@@ -283,7 +289,7 @@ static int record__open(struct record *rec) | |||
283 | struct record_opts *opts = &rec->opts; | 289 | struct record_opts *opts = &rec->opts; |
284 | int rc = 0; | 290 | int rc = 0; |
285 | 291 | ||
286 | perf_evlist__config(evlist, opts); | 292 | perf_evlist__config(evlist, opts, &callchain_param); |
287 | 293 | ||
288 | evlist__for_each(evlist, pos) { | 294 | evlist__for_each(evlist, pos) { |
289 | try_again: | 295 | try_again: |
@@ -494,6 +500,73 @@ record__finish_output(struct record *rec) | |||
494 | return; | 500 | return; |
495 | } | 501 | } |
496 | 502 | ||
503 | static int record__synthesize_workload(struct record *rec) | ||
504 | { | ||
505 | struct { | ||
506 | struct thread_map map; | ||
507 | struct thread_map_data map_data; | ||
508 | } thread_map; | ||
509 | |||
510 | thread_map.map.nr = 1; | ||
511 | thread_map.map.map[0].pid = rec->evlist->workload.pid; | ||
512 | thread_map.map.map[0].comm = NULL; | ||
513 | return perf_event__synthesize_thread_map(&rec->tool, &thread_map.map, | ||
514 | process_synthesized_event, | ||
515 | &rec->session->machines.host, | ||
516 | rec->opts.sample_address, | ||
517 | rec->opts.proc_map_timeout); | ||
518 | } | ||
519 | |||
520 | static int record__synthesize(struct record *rec); | ||
521 | |||
522 | static int | ||
523 | record__switch_output(struct record *rec, bool at_exit) | ||
524 | { | ||
525 | struct perf_data_file *file = &rec->file; | ||
526 | int fd, err; | ||
527 | |||
528 | /* Same Size: "2015122520103046"*/ | ||
529 | char timestamp[] = "InvalidTimestamp"; | ||
530 | |||
531 | rec->samples = 0; | ||
532 | record__finish_output(rec); | ||
533 | err = fetch_current_timestamp(timestamp, sizeof(timestamp)); | ||
534 | if (err) { | ||
535 | pr_err("Failed to get current timestamp\n"); | ||
536 | return -EINVAL; | ||
537 | } | ||
538 | |||
539 | fd = perf_data_file__switch(file, timestamp, | ||
540 | rec->session->header.data_offset, | ||
541 | at_exit); | ||
542 | if (fd >= 0 && !at_exit) { | ||
543 | rec->bytes_written = 0; | ||
544 | rec->session->header.data_size = 0; | ||
545 | } | ||
546 | |||
547 | if (!quiet) | ||
548 | fprintf(stderr, "[ perf record: Dump %s.%s ]\n", | ||
549 | file->path, timestamp); | ||
550 | |||
551 | /* Output tracking events */ | ||
552 | if (!at_exit) { | ||
553 | record__synthesize(rec); | ||
554 | |||
555 | /* | ||
556 | * In 'perf record --switch-output' without -a, | ||
557 | * record__synthesize() in record__switch_output() won't | ||
558 | * generate tracking events because there's no thread_map | ||
559 | * in evlist. Which causes newly created perf.data doesn't | ||
560 | * contain map and comm information. | ||
561 | * Create a fake thread_map and directly call | ||
562 | * perf_event__synthesize_thread_map() for those events. | ||
563 | */ | ||
564 | if (target__none(&rec->opts.target)) | ||
565 | record__synthesize_workload(rec); | ||
566 | } | ||
567 | return fd; | ||
568 | } | ||
569 | |||
497 | static volatile int workload_exec_errno; | 570 | static volatile int workload_exec_errno; |
498 | 571 | ||
499 | /* | 572 | /* |
@@ -512,6 +585,15 @@ static void workload_exec_failed_signal(int signo __maybe_unused, | |||
512 | 585 | ||
513 | static void snapshot_sig_handler(int sig); | 586 | static void snapshot_sig_handler(int sig); |
514 | 587 | ||
588 | int __weak | ||
589 | perf_event__synth_time_conv(const struct perf_event_mmap_page *pc __maybe_unused, | ||
590 | struct perf_tool *tool __maybe_unused, | ||
591 | perf_event__handler_t process __maybe_unused, | ||
592 | struct machine *machine __maybe_unused) | ||
593 | { | ||
594 | return 0; | ||
595 | } | ||
596 | |||
515 | static int record__synthesize(struct record *rec) | 597 | static int record__synthesize(struct record *rec) |
516 | { | 598 | { |
517 | struct perf_session *session = rec->session; | 599 | struct perf_session *session = rec->session; |
@@ -549,6 +631,11 @@ static int record__synthesize(struct record *rec) | |||
549 | } | 631 | } |
550 | } | 632 | } |
551 | 633 | ||
634 | err = perf_event__synth_time_conv(rec->evlist->mmap[0].base, tool, | ||
635 | process_synthesized_event, machine); | ||
636 | if (err) | ||
637 | goto out; | ||
638 | |||
552 | if (rec->opts.full_auxtrace) { | 639 | if (rec->opts.full_auxtrace) { |
553 | err = perf_event__synthesize_auxtrace_info(rec->itr, tool, | 640 | err = perf_event__synthesize_auxtrace_info(rec->itr, tool, |
554 | session, process_synthesized_event); | 641 | session, process_synthesized_event); |
@@ -600,10 +687,16 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
600 | signal(SIGCHLD, sig_handler); | 687 | signal(SIGCHLD, sig_handler); |
601 | signal(SIGINT, sig_handler); | 688 | signal(SIGINT, sig_handler); |
602 | signal(SIGTERM, sig_handler); | 689 | signal(SIGTERM, sig_handler); |
603 | if (rec->opts.auxtrace_snapshot_mode) | 690 | |
691 | if (rec->opts.auxtrace_snapshot_mode || rec->switch_output) { | ||
604 | signal(SIGUSR2, snapshot_sig_handler); | 692 | signal(SIGUSR2, snapshot_sig_handler); |
605 | else | 693 | if (rec->opts.auxtrace_snapshot_mode) |
694 | trigger_on(&auxtrace_snapshot_trigger); | ||
695 | if (rec->switch_output) | ||
696 | trigger_on(&switch_output_trigger); | ||
697 | } else { | ||
606 | signal(SIGUSR2, SIG_IGN); | 698 | signal(SIGUSR2, SIG_IGN); |
699 | } | ||
607 | 700 | ||
608 | session = perf_session__new(file, false, tool); | 701 | session = perf_session__new(file, false, tool); |
609 | if (session == NULL) { | 702 | if (session == NULL) { |
@@ -729,27 +822,45 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
729 | perf_evlist__enable(rec->evlist); | 822 | perf_evlist__enable(rec->evlist); |
730 | } | 823 | } |
731 | 824 | ||
732 | auxtrace_snapshot_enabled = 1; | 825 | trigger_ready(&auxtrace_snapshot_trigger); |
826 | trigger_ready(&switch_output_trigger); | ||
733 | for (;;) { | 827 | for (;;) { |
734 | unsigned long long hits = rec->samples; | 828 | unsigned long long hits = rec->samples; |
735 | 829 | ||
736 | if (record__mmap_read_all(rec) < 0) { | 830 | if (record__mmap_read_all(rec) < 0) { |
737 | auxtrace_snapshot_enabled = 0; | 831 | trigger_error(&auxtrace_snapshot_trigger); |
832 | trigger_error(&switch_output_trigger); | ||
738 | err = -1; | 833 | err = -1; |
739 | goto out_child; | 834 | goto out_child; |
740 | } | 835 | } |
741 | 836 | ||
742 | if (auxtrace_record__snapshot_started) { | 837 | if (auxtrace_record__snapshot_started) { |
743 | auxtrace_record__snapshot_started = 0; | 838 | auxtrace_record__snapshot_started = 0; |
744 | if (!auxtrace_snapshot_err) | 839 | if (!trigger_is_error(&auxtrace_snapshot_trigger)) |
745 | record__read_auxtrace_snapshot(rec); | 840 | record__read_auxtrace_snapshot(rec); |
746 | if (auxtrace_snapshot_err) { | 841 | if (trigger_is_error(&auxtrace_snapshot_trigger)) { |
747 | pr_err("AUX area tracing snapshot failed\n"); | 842 | pr_err("AUX area tracing snapshot failed\n"); |
748 | err = -1; | 843 | err = -1; |
749 | goto out_child; | 844 | goto out_child; |
750 | } | 845 | } |
751 | } | 846 | } |
752 | 847 | ||
848 | if (trigger_is_hit(&switch_output_trigger)) { | ||
849 | trigger_ready(&switch_output_trigger); | ||
850 | |||
851 | if (!quiet) | ||
852 | fprintf(stderr, "[ perf record: dump data: Woken up %ld times ]\n", | ||
853 | waking); | ||
854 | waking = 0; | ||
855 | fd = record__switch_output(rec, false); | ||
856 | if (fd < 0) { | ||
857 | pr_err("Failed to switch to new file\n"); | ||
858 | trigger_error(&switch_output_trigger); | ||
859 | err = fd; | ||
860 | goto out_child; | ||
861 | } | ||
862 | } | ||
863 | |||
753 | if (hits == rec->samples) { | 864 | if (hits == rec->samples) { |
754 | if (done || draining) | 865 | if (done || draining) |
755 | break; | 866 | break; |
@@ -772,12 +883,13 @@ static int __cmd_record(struct record *rec, int argc, const char **argv) | |||
772 | * disable events in this case. | 883 | * disable events in this case. |
773 | */ | 884 | */ |
774 | if (done && !disabled && !target__none(&opts->target)) { | 885 | if (done && !disabled && !target__none(&opts->target)) { |
775 | auxtrace_snapshot_enabled = 0; | 886 | trigger_off(&auxtrace_snapshot_trigger); |
776 | perf_evlist__disable(rec->evlist); | 887 | perf_evlist__disable(rec->evlist); |
777 | disabled = true; | 888 | disabled = true; |
778 | } | 889 | } |
779 | } | 890 | } |
780 | auxtrace_snapshot_enabled = 0; | 891 | trigger_off(&auxtrace_snapshot_trigger); |
892 | trigger_off(&switch_output_trigger); | ||
781 | 893 | ||
782 | if (forks && workload_exec_errno) { | 894 | if (forks && workload_exec_errno) { |
783 | char msg[STRERR_BUFSIZE]; | 895 | char msg[STRERR_BUFSIZE]; |
@@ -811,11 +923,22 @@ out_child: | |||
811 | /* this will be recalculated during process_buildids() */ | 923 | /* this will be recalculated during process_buildids() */ |
812 | rec->samples = 0; | 924 | rec->samples = 0; |
813 | 925 | ||
814 | if (!err) | 926 | if (!err) { |
815 | record__finish_output(rec); | 927 | if (!rec->timestamp_filename) { |
928 | record__finish_output(rec); | ||
929 | } else { | ||
930 | fd = record__switch_output(rec, true); | ||
931 | if (fd < 0) { | ||
932 | status = fd; | ||
933 | goto out_delete_session; | ||
934 | } | ||
935 | } | ||
936 | } | ||
816 | 937 | ||
817 | if (!err && !quiet) { | 938 | if (!err && !quiet) { |
818 | char samples[128]; | 939 | char samples[128]; |
940 | const char *postfix = rec->timestamp_filename ? | ||
941 | ".<timestamp>" : ""; | ||
819 | 942 | ||
820 | if (rec->samples && !rec->opts.full_auxtrace) | 943 | if (rec->samples && !rec->opts.full_auxtrace) |
821 | scnprintf(samples, sizeof(samples), | 944 | scnprintf(samples, sizeof(samples), |
@@ -823,9 +946,9 @@ out_child: | |||
823 | else | 946 | else |
824 | samples[0] = '\0'; | 947 | samples[0] = '\0'; |
825 | 948 | ||
826 | fprintf(stderr, "[ perf record: Captured and wrote %.3f MB %s%s ]\n", | 949 | fprintf(stderr, "[ perf record: Captured and wrote %.3f MB %s%s%s ]\n", |
827 | perf_data_file__size(file) / 1024.0 / 1024.0, | 950 | perf_data_file__size(file) / 1024.0 / 1024.0, |
828 | file->path, samples); | 951 | file->path, postfix, samples); |
829 | } | 952 | } |
830 | 953 | ||
831 | out_delete_session: | 954 | out_delete_session: |
@@ -833,58 +956,61 @@ out_delete_session: | |||
833 | return status; | 956 | return status; |
834 | } | 957 | } |
835 | 958 | ||
836 | static void callchain_debug(void) | 959 | static void callchain_debug(struct callchain_param *callchain) |
837 | { | 960 | { |
838 | static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF", "LBR" }; | 961 | static const char *str[CALLCHAIN_MAX] = { "NONE", "FP", "DWARF", "LBR" }; |
839 | 962 | ||
840 | pr_debug("callchain: type %s\n", str[callchain_param.record_mode]); | 963 | pr_debug("callchain: type %s\n", str[callchain->record_mode]); |
841 | 964 | ||
842 | if (callchain_param.record_mode == CALLCHAIN_DWARF) | 965 | if (callchain->record_mode == CALLCHAIN_DWARF) |
843 | pr_debug("callchain: stack dump size %d\n", | 966 | pr_debug("callchain: stack dump size %d\n", |
844 | callchain_param.dump_size); | 967 | callchain->dump_size); |
845 | } | 968 | } |
846 | 969 | ||
847 | int record_parse_callchain_opt(const struct option *opt, | 970 | int record_opts__parse_callchain(struct record_opts *record, |
848 | const char *arg, | 971 | struct callchain_param *callchain, |
849 | int unset) | 972 | const char *arg, bool unset) |
850 | { | 973 | { |
851 | int ret; | 974 | int ret; |
852 | struct record_opts *record = (struct record_opts *)opt->value; | 975 | callchain->enabled = !unset; |
853 | |||
854 | record->callgraph_set = true; | ||
855 | callchain_param.enabled = !unset; | ||
856 | 976 | ||
857 | /* --no-call-graph */ | 977 | /* --no-call-graph */ |
858 | if (unset) { | 978 | if (unset) { |
859 | callchain_param.record_mode = CALLCHAIN_NONE; | 979 | callchain->record_mode = CALLCHAIN_NONE; |
860 | pr_debug("callchain: disabled\n"); | 980 | pr_debug("callchain: disabled\n"); |
861 | return 0; | 981 | return 0; |
862 | } | 982 | } |
863 | 983 | ||
864 | ret = parse_callchain_record_opt(arg, &callchain_param); | 984 | ret = parse_callchain_record_opt(arg, callchain); |
865 | if (!ret) { | 985 | if (!ret) { |
866 | /* Enable data address sampling for DWARF unwind. */ | 986 | /* Enable data address sampling for DWARF unwind. */ |
867 | if (callchain_param.record_mode == CALLCHAIN_DWARF) | 987 | if (callchain->record_mode == CALLCHAIN_DWARF) |
868 | record->sample_address = true; | 988 | record->sample_address = true; |
869 | callchain_debug(); | 989 | callchain_debug(callchain); |
870 | } | 990 | } |
871 | 991 | ||
872 | return ret; | 992 | return ret; |
873 | } | 993 | } |
874 | 994 | ||
995 | int record_parse_callchain_opt(const struct option *opt, | ||
996 | const char *arg, | ||
997 | int unset) | ||
998 | { | ||
999 | return record_opts__parse_callchain(opt->value, &callchain_param, arg, unset); | ||
1000 | } | ||
1001 | |||
875 | int record_callchain_opt(const struct option *opt, | 1002 | int record_callchain_opt(const struct option *opt, |
876 | const char *arg __maybe_unused, | 1003 | const char *arg __maybe_unused, |
877 | int unset __maybe_unused) | 1004 | int unset __maybe_unused) |
878 | { | 1005 | { |
879 | struct record_opts *record = (struct record_opts *)opt->value; | 1006 | struct callchain_param *callchain = opt->value; |
880 | 1007 | ||
881 | record->callgraph_set = true; | 1008 | callchain->enabled = true; |
882 | callchain_param.enabled = true; | ||
883 | 1009 | ||
884 | if (callchain_param.record_mode == CALLCHAIN_NONE) | 1010 | if (callchain->record_mode == CALLCHAIN_NONE) |
885 | callchain_param.record_mode = CALLCHAIN_FP; | 1011 | callchain->record_mode = CALLCHAIN_FP; |
886 | 1012 | ||
887 | callchain_debug(); | 1013 | callchain_debug(callchain); |
888 | return 0; | 1014 | return 0; |
889 | } | 1015 | } |
890 | 1016 | ||
@@ -1122,7 +1248,7 @@ struct option __record_options[] = { | |||
1122 | record__parse_mmap_pages), | 1248 | record__parse_mmap_pages), |
1123 | OPT_BOOLEAN(0, "group", &record.opts.group, | 1249 | OPT_BOOLEAN(0, "group", &record.opts.group, |
1124 | "put the counters into a counter group"), | 1250 | "put the counters into a counter group"), |
1125 | OPT_CALLBACK_NOOPT('g', NULL, &record.opts, | 1251 | OPT_CALLBACK_NOOPT('g', NULL, &callchain_param, |
1126 | NULL, "enables call-graph recording" , | 1252 | NULL, "enables call-graph recording" , |
1127 | &record_callchain_opt), | 1253 | &record_callchain_opt), |
1128 | OPT_CALLBACK(0, "call-graph", &record.opts, | 1254 | OPT_CALLBACK(0, "call-graph", &record.opts, |
@@ -1195,6 +1321,10 @@ struct option __record_options[] = { | |||
1195 | "file", "vmlinux pathname"), | 1321 | "file", "vmlinux pathname"), |
1196 | OPT_BOOLEAN(0, "buildid-all", &record.buildid_all, | 1322 | OPT_BOOLEAN(0, "buildid-all", &record.buildid_all, |
1197 | "Record build-id of all DSOs regardless of hits"), | 1323 | "Record build-id of all DSOs regardless of hits"), |
1324 | OPT_BOOLEAN(0, "timestamp-filename", &record.timestamp_filename, | ||
1325 | "append timestamp to output filename"), | ||
1326 | OPT_BOOLEAN(0, "switch-output", &record.switch_output, | ||
1327 | "Switch output when receive SIGUSR2"), | ||
1198 | OPT_END() | 1328 | OPT_END() |
1199 | }; | 1329 | }; |
1200 | 1330 | ||
@@ -1250,6 +1380,9 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1250 | return -EINVAL; | 1380 | return -EINVAL; |
1251 | } | 1381 | } |
1252 | 1382 | ||
1383 | if (rec->switch_output) | ||
1384 | rec->timestamp_filename = true; | ||
1385 | |||
1253 | if (!rec->itr) { | 1386 | if (!rec->itr) { |
1254 | rec->itr = auxtrace_record__init(rec->evlist, &err); | 1387 | rec->itr = auxtrace_record__init(rec->evlist, &err); |
1255 | if (err) | 1388 | if (err) |
@@ -1261,6 +1394,14 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1261 | if (err) | 1394 | if (err) |
1262 | return err; | 1395 | return err; |
1263 | 1396 | ||
1397 | err = bpf__setup_stdout(rec->evlist); | ||
1398 | if (err) { | ||
1399 | bpf__strerror_setup_stdout(rec->evlist, err, errbuf, sizeof(errbuf)); | ||
1400 | pr_err("ERROR: Setup BPF stdout failed: %s\n", | ||
1401 | errbuf); | ||
1402 | return err; | ||
1403 | } | ||
1404 | |||
1264 | err = -ENOMEM; | 1405 | err = -ENOMEM; |
1265 | 1406 | ||
1266 | symbol__init(NULL); | 1407 | symbol__init(NULL); |
@@ -1275,8 +1416,36 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1275 | "If some relocation was applied (e.g. kexec) symbols may be misresolved\n" | 1416 | "If some relocation was applied (e.g. kexec) symbols may be misresolved\n" |
1276 | "even with a suitable vmlinux or kallsyms file.\n\n"); | 1417 | "even with a suitable vmlinux or kallsyms file.\n\n"); |
1277 | 1418 | ||
1278 | if (rec->no_buildid_cache || rec->no_buildid) | 1419 | if (rec->no_buildid_cache || rec->no_buildid) { |
1279 | disable_buildid_cache(); | 1420 | disable_buildid_cache(); |
1421 | } else if (rec->switch_output) { | ||
1422 | /* | ||
1423 | * In 'perf record --switch-output', disable buildid | ||
1424 | * generation by default to reduce data file switching | ||
1425 | * overhead. Still generate buildid if they are required | ||
1426 | * explicitly using | ||
1427 | * | ||
1428 | * perf record --signal-trigger --no-no-buildid \ | ||
1429 | * --no-no-buildid-cache | ||
1430 | * | ||
1431 | * Following code equals to: | ||
1432 | * | ||
1433 | * if ((rec->no_buildid || !rec->no_buildid_set) && | ||
1434 | * (rec->no_buildid_cache || !rec->no_buildid_cache_set)) | ||
1435 | * disable_buildid_cache(); | ||
1436 | */ | ||
1437 | bool disable = true; | ||
1438 | |||
1439 | if (rec->no_buildid_set && !rec->no_buildid) | ||
1440 | disable = false; | ||
1441 | if (rec->no_buildid_cache_set && !rec->no_buildid_cache) | ||
1442 | disable = false; | ||
1443 | if (disable) { | ||
1444 | rec->no_buildid = true; | ||
1445 | rec->no_buildid_cache = true; | ||
1446 | disable_buildid_cache(); | ||
1447 | } | ||
1448 | } | ||
1280 | 1449 | ||
1281 | if (rec->evlist->nr_entries == 0 && | 1450 | if (rec->evlist->nr_entries == 0 && |
1282 | perf_evlist__add_default(rec->evlist) < 0) { | 1451 | perf_evlist__add_default(rec->evlist) < 0) { |
@@ -1335,9 +1504,13 @@ out_symbol_exit: | |||
1335 | 1504 | ||
1336 | static void snapshot_sig_handler(int sig __maybe_unused) | 1505 | static void snapshot_sig_handler(int sig __maybe_unused) |
1337 | { | 1506 | { |
1338 | if (!auxtrace_snapshot_enabled) | 1507 | if (trigger_is_ready(&auxtrace_snapshot_trigger)) { |
1339 | return; | 1508 | trigger_hit(&auxtrace_snapshot_trigger); |
1340 | auxtrace_snapshot_enabled = 0; | 1509 | auxtrace_record__snapshot_started = 1; |
1341 | auxtrace_snapshot_err = auxtrace_record__snapshot_start(record.itr); | 1510 | if (auxtrace_record__snapshot_start(record.itr)) |
1342 | auxtrace_record__snapshot_started = 1; | 1511 | trigger_error(&auxtrace_snapshot_trigger); |
1512 | } | ||
1513 | |||
1514 | if (trigger_is_ready(&switch_output_trigger)) | ||
1515 | trigger_hit(&switch_output_trigger); | ||
1343 | } | 1516 | } |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 160ea23b45aa..87d40e3c4078 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -47,7 +47,6 @@ struct report { | |||
47 | struct perf_tool tool; | 47 | struct perf_tool tool; |
48 | struct perf_session *session; | 48 | struct perf_session *session; |
49 | bool use_tui, use_gtk, use_stdio; | 49 | bool use_tui, use_gtk, use_stdio; |
50 | bool dont_use_callchains; | ||
51 | bool show_full_info; | 50 | bool show_full_info; |
52 | bool show_threads; | 51 | bool show_threads; |
53 | bool inverted_callchain; | 52 | bool inverted_callchain; |
@@ -235,7 +234,7 @@ static int report__setup_sample_type(struct report *rep) | |||
235 | sample_type |= PERF_SAMPLE_BRANCH_STACK; | 234 | sample_type |= PERF_SAMPLE_BRANCH_STACK; |
236 | 235 | ||
237 | if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) { | 236 | if (!is_pipe && !(sample_type & PERF_SAMPLE_CALLCHAIN)) { |
238 | if (sort__has_parent) { | 237 | if (perf_hpp_list.parent) { |
239 | ui__error("Selected --sort parent, but no " | 238 | ui__error("Selected --sort parent, but no " |
240 | "callchain data. Did you call " | 239 | "callchain data. Did you call " |
241 | "'perf record' without -g?\n"); | 240 | "'perf record' without -g?\n"); |
@@ -247,7 +246,7 @@ static int report__setup_sample_type(struct report *rep) | |||
247 | "you call 'perf record' without -g?\n"); | 246 | "you call 'perf record' without -g?\n"); |
248 | return -1; | 247 | return -1; |
249 | } | 248 | } |
250 | } else if (!rep->dont_use_callchains && | 249 | } else if (!callchain_param.enabled && |
251 | callchain_param.mode != CHAIN_NONE && | 250 | callchain_param.mode != CHAIN_NONE && |
252 | !symbol_conf.use_callchain) { | 251 | !symbol_conf.use_callchain) { |
253 | symbol_conf.use_callchain = true; | 252 | symbol_conf.use_callchain = true; |
@@ -599,13 +598,15 @@ static int __cmd_report(struct report *rep) | |||
599 | static int | 598 | static int |
600 | report_parse_callchain_opt(const struct option *opt, const char *arg, int unset) | 599 | report_parse_callchain_opt(const struct option *opt, const char *arg, int unset) |
601 | { | 600 | { |
602 | struct report *rep = (struct report *)opt->value; | 601 | struct callchain_param *callchain = opt->value; |
603 | 602 | ||
603 | callchain->enabled = !unset; | ||
604 | /* | 604 | /* |
605 | * --no-call-graph | 605 | * --no-call-graph |
606 | */ | 606 | */ |
607 | if (unset) { | 607 | if (unset) { |
608 | rep->dont_use_callchains = true; | 608 | symbol_conf.use_callchain = false; |
609 | callchain->mode = CHAIN_NONE; | ||
609 | return 0; | 610 | return 0; |
610 | } | 611 | } |
611 | 612 | ||
@@ -690,7 +691,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
690 | .ordered_events = true, | 691 | .ordered_events = true, |
691 | .ordering_requires_timestamps = true, | 692 | .ordering_requires_timestamps = true, |
692 | }, | 693 | }, |
693 | .max_stack = PERF_MAX_STACK_DEPTH, | 694 | .max_stack = sysctl_perf_event_max_stack, |
694 | .pretty_printing_style = "normal", | 695 | .pretty_printing_style = "normal", |
695 | .socket_filter = -1, | 696 | .socket_filter = -1, |
696 | }; | 697 | }; |
@@ -734,7 +735,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
734 | "regex filter to identify parent, see: '--sort parent'"), | 735 | "regex filter to identify parent, see: '--sort parent'"), |
735 | OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, | 736 | OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other, |
736 | "Only display entries with parent-match"), | 737 | "Only display entries with parent-match"), |
737 | OPT_CALLBACK_DEFAULT('g', "call-graph", &report, | 738 | OPT_CALLBACK_DEFAULT('g', "call-graph", &callchain_param, |
738 | "print_type,threshold[,print_limit],order,sort_key[,branch],value", | 739 | "print_type,threshold[,print_limit],order,sort_key[,branch],value", |
739 | report_callchain_help, &report_parse_callchain_opt, | 740 | report_callchain_help, &report_parse_callchain_opt, |
740 | callchain_default_opt), | 741 | callchain_default_opt), |
@@ -743,7 +744,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) | |||
743 | OPT_INTEGER(0, "max-stack", &report.max_stack, | 744 | OPT_INTEGER(0, "max-stack", &report.max_stack, |
744 | "Set the maximum stack depth when parsing the callchain, " | 745 | "Set the maximum stack depth when parsing the callchain, " |
745 | "anything beyond the specified depth will be ignored. " | 746 | "anything beyond the specified depth will be ignored. " |
746 | "Default: " __stringify(PERF_MAX_STACK_DEPTH)), | 747 | "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)), |
747 | OPT_BOOLEAN('G', "inverted", &report.inverted_callchain, | 748 | OPT_BOOLEAN('G', "inverted", &report.inverted_callchain, |
748 | "alias for inverted call graph"), | 749 | "alias for inverted call graph"), |
749 | OPT_CALLBACK(0, "ignore-callees", NULL, "regex", | 750 | OPT_CALLBACK(0, "ignore-callees", NULL, "regex", |
@@ -935,7 +936,7 @@ repeat: | |||
935 | goto error; | 936 | goto error; |
936 | } | 937 | } |
937 | 938 | ||
938 | sort__need_collapse = true; | 939 | perf_hpp_list.need_collapse = true; |
939 | } | 940 | } |
940 | 941 | ||
941 | /* Force tty output for header output and per-thread stat. */ | 942 | /* Force tty output for header output and per-thread stat. */ |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 871b55ae22a4..afa057666c2a 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -11,6 +11,8 @@ | |||
11 | #include "util/session.h" | 11 | #include "util/session.h" |
12 | #include "util/tool.h" | 12 | #include "util/tool.h" |
13 | #include "util/cloexec.h" | 13 | #include "util/cloexec.h" |
14 | #include "util/thread_map.h" | ||
15 | #include "util/color.h" | ||
14 | 16 | ||
15 | #include <subcmd/parse-options.h> | 17 | #include <subcmd/parse-options.h> |
16 | #include "util/trace-event.h" | 18 | #include "util/trace-event.h" |
@@ -122,6 +124,21 @@ struct trace_sched_handler { | |||
122 | struct machine *machine); | 124 | struct machine *machine); |
123 | }; | 125 | }; |
124 | 126 | ||
127 | #define COLOR_PIDS PERF_COLOR_BLUE | ||
128 | #define COLOR_CPUS PERF_COLOR_BG_RED | ||
129 | |||
130 | struct perf_sched_map { | ||
131 | DECLARE_BITMAP(comp_cpus_mask, MAX_CPUS); | ||
132 | int *comp_cpus; | ||
133 | bool comp; | ||
134 | struct thread_map *color_pids; | ||
135 | const char *color_pids_str; | ||
136 | struct cpu_map *color_cpus; | ||
137 | const char *color_cpus_str; | ||
138 | struct cpu_map *cpus; | ||
139 | const char *cpus_str; | ||
140 | }; | ||
141 | |||
125 | struct perf_sched { | 142 | struct perf_sched { |
126 | struct perf_tool tool; | 143 | struct perf_tool tool; |
127 | const char *sort_order; | 144 | const char *sort_order; |
@@ -173,6 +190,7 @@ struct perf_sched { | |||
173 | struct list_head sort_list, cmp_pid; | 190 | struct list_head sort_list, cmp_pid; |
174 | bool force; | 191 | bool force; |
175 | bool skip_merge; | 192 | bool skip_merge; |
193 | struct perf_sched_map map; | ||
176 | }; | 194 | }; |
177 | 195 | ||
178 | static u64 get_nsecs(void) | 196 | static u64 get_nsecs(void) |
@@ -1339,6 +1357,38 @@ static int process_sched_wakeup_event(struct perf_tool *tool, | |||
1339 | return 0; | 1357 | return 0; |
1340 | } | 1358 | } |
1341 | 1359 | ||
1360 | union map_priv { | ||
1361 | void *ptr; | ||
1362 | bool color; | ||
1363 | }; | ||
1364 | |||
1365 | static bool thread__has_color(struct thread *thread) | ||
1366 | { | ||
1367 | union map_priv priv = { | ||
1368 | .ptr = thread__priv(thread), | ||
1369 | }; | ||
1370 | |||
1371 | return priv.color; | ||
1372 | } | ||
1373 | |||
1374 | static struct thread* | ||
1375 | map__findnew_thread(struct perf_sched *sched, struct machine *machine, pid_t pid, pid_t tid) | ||
1376 | { | ||
1377 | struct thread *thread = machine__findnew_thread(machine, pid, tid); | ||
1378 | union map_priv priv = { | ||
1379 | .color = false, | ||
1380 | }; | ||
1381 | |||
1382 | if (!sched->map.color_pids || !thread || thread__priv(thread)) | ||
1383 | return thread; | ||
1384 | |||
1385 | if (thread_map__has(sched->map.color_pids, tid)) | ||
1386 | priv.color = true; | ||
1387 | |||
1388 | thread__set_priv(thread, priv.ptr); | ||
1389 | return thread; | ||
1390 | } | ||
1391 | |||
1342 | static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, | 1392 | static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, |
1343 | struct perf_sample *sample, struct machine *machine) | 1393 | struct perf_sample *sample, struct machine *machine) |
1344 | { | 1394 | { |
@@ -1347,13 +1397,25 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, | |||
1347 | int new_shortname; | 1397 | int new_shortname; |
1348 | u64 timestamp0, timestamp = sample->time; | 1398 | u64 timestamp0, timestamp = sample->time; |
1349 | s64 delta; | 1399 | s64 delta; |
1350 | int cpu, this_cpu = sample->cpu; | 1400 | int i, this_cpu = sample->cpu; |
1401 | int cpus_nr; | ||
1402 | bool new_cpu = false; | ||
1403 | const char *color = PERF_COLOR_NORMAL; | ||
1351 | 1404 | ||
1352 | BUG_ON(this_cpu >= MAX_CPUS || this_cpu < 0); | 1405 | BUG_ON(this_cpu >= MAX_CPUS || this_cpu < 0); |
1353 | 1406 | ||
1354 | if (this_cpu > sched->max_cpu) | 1407 | if (this_cpu > sched->max_cpu) |
1355 | sched->max_cpu = this_cpu; | 1408 | sched->max_cpu = this_cpu; |
1356 | 1409 | ||
1410 | if (sched->map.comp) { | ||
1411 | cpus_nr = bitmap_weight(sched->map.comp_cpus_mask, MAX_CPUS); | ||
1412 | if (!test_and_set_bit(this_cpu, sched->map.comp_cpus_mask)) { | ||
1413 | sched->map.comp_cpus[cpus_nr++] = this_cpu; | ||
1414 | new_cpu = true; | ||
1415 | } | ||
1416 | } else | ||
1417 | cpus_nr = sched->max_cpu; | ||
1418 | |||
1357 | timestamp0 = sched->cpu_last_switched[this_cpu]; | 1419 | timestamp0 = sched->cpu_last_switched[this_cpu]; |
1358 | sched->cpu_last_switched[this_cpu] = timestamp; | 1420 | sched->cpu_last_switched[this_cpu] = timestamp; |
1359 | if (timestamp0) | 1421 | if (timestamp0) |
@@ -1366,7 +1428,7 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, | |||
1366 | return -1; | 1428 | return -1; |
1367 | } | 1429 | } |
1368 | 1430 | ||
1369 | sched_in = machine__findnew_thread(machine, -1, next_pid); | 1431 | sched_in = map__findnew_thread(sched, machine, -1, next_pid); |
1370 | if (sched_in == NULL) | 1432 | if (sched_in == NULL) |
1371 | return -1; | 1433 | return -1; |
1372 | 1434 | ||
@@ -1400,26 +1462,52 @@ static int map_switch_event(struct perf_sched *sched, struct perf_evsel *evsel, | |||
1400 | new_shortname = 1; | 1462 | new_shortname = 1; |
1401 | } | 1463 | } |
1402 | 1464 | ||
1403 | for (cpu = 0; cpu <= sched->max_cpu; cpu++) { | 1465 | for (i = 0; i < cpus_nr; i++) { |
1466 | int cpu = sched->map.comp ? sched->map.comp_cpus[i] : i; | ||
1467 | struct thread *curr_thread = sched->curr_thread[cpu]; | ||
1468 | const char *pid_color = color; | ||
1469 | const char *cpu_color = color; | ||
1470 | |||
1471 | if (curr_thread && thread__has_color(curr_thread)) | ||
1472 | pid_color = COLOR_PIDS; | ||
1473 | |||
1474 | if (sched->map.cpus && !cpu_map__has(sched->map.cpus, cpu)) | ||
1475 | continue; | ||
1476 | |||
1477 | if (sched->map.color_cpus && cpu_map__has(sched->map.color_cpus, cpu)) | ||
1478 | cpu_color = COLOR_CPUS; | ||
1479 | |||
1404 | if (cpu != this_cpu) | 1480 | if (cpu != this_cpu) |
1405 | printf(" "); | 1481 | color_fprintf(stdout, cpu_color, " "); |
1406 | else | 1482 | else |
1407 | printf("*"); | 1483 | color_fprintf(stdout, cpu_color, "*"); |
1408 | 1484 | ||
1409 | if (sched->curr_thread[cpu]) | 1485 | if (sched->curr_thread[cpu]) |
1410 | printf("%2s ", sched->curr_thread[cpu]->shortname); | 1486 | color_fprintf(stdout, pid_color, "%2s ", sched->curr_thread[cpu]->shortname); |
1411 | else | 1487 | else |
1412 | printf(" "); | 1488 | color_fprintf(stdout, color, " "); |
1413 | } | 1489 | } |
1414 | 1490 | ||
1415 | printf(" %12.6f secs ", (double)timestamp/1e9); | 1491 | if (sched->map.cpus && !cpu_map__has(sched->map.cpus, this_cpu)) |
1492 | goto out; | ||
1493 | |||
1494 | color_fprintf(stdout, color, " %12.6f secs ", (double)timestamp/1e9); | ||
1416 | if (new_shortname) { | 1495 | if (new_shortname) { |
1417 | printf("%s => %s:%d\n", | 1496 | const char *pid_color = color; |
1497 | |||
1498 | if (thread__has_color(sched_in)) | ||
1499 | pid_color = COLOR_PIDS; | ||
1500 | |||
1501 | color_fprintf(stdout, pid_color, "%s => %s:%d", | ||
1418 | sched_in->shortname, thread__comm_str(sched_in), sched_in->tid); | 1502 | sched_in->shortname, thread__comm_str(sched_in), sched_in->tid); |
1419 | } else { | ||
1420 | printf("\n"); | ||
1421 | } | 1503 | } |
1422 | 1504 | ||
1505 | if (sched->map.comp && new_cpu) | ||
1506 | color_fprintf(stdout, color, " (CPU %d)", this_cpu); | ||
1507 | |||
1508 | out: | ||
1509 | color_fprintf(stdout, color, "\n"); | ||
1510 | |||
1423 | thread__put(sched_in); | 1511 | thread__put(sched_in); |
1424 | 1512 | ||
1425 | return 0; | 1513 | return 0; |
@@ -1675,9 +1763,75 @@ static int perf_sched__lat(struct perf_sched *sched) | |||
1675 | return 0; | 1763 | return 0; |
1676 | } | 1764 | } |
1677 | 1765 | ||
1766 | static int setup_map_cpus(struct perf_sched *sched) | ||
1767 | { | ||
1768 | struct cpu_map *map; | ||
1769 | |||
1770 | sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF); | ||
1771 | |||
1772 | if (sched->map.comp) { | ||
1773 | sched->map.comp_cpus = zalloc(sched->max_cpu * sizeof(int)); | ||
1774 | if (!sched->map.comp_cpus) | ||
1775 | return -1; | ||
1776 | } | ||
1777 | |||
1778 | if (!sched->map.cpus_str) | ||
1779 | return 0; | ||
1780 | |||
1781 | map = cpu_map__new(sched->map.cpus_str); | ||
1782 | if (!map) { | ||
1783 | pr_err("failed to get cpus map from %s\n", sched->map.cpus_str); | ||
1784 | return -1; | ||
1785 | } | ||
1786 | |||
1787 | sched->map.cpus = map; | ||
1788 | return 0; | ||
1789 | } | ||
1790 | |||
1791 | static int setup_color_pids(struct perf_sched *sched) | ||
1792 | { | ||
1793 | struct thread_map *map; | ||
1794 | |||
1795 | if (!sched->map.color_pids_str) | ||
1796 | return 0; | ||
1797 | |||
1798 | map = thread_map__new_by_tid_str(sched->map.color_pids_str); | ||
1799 | if (!map) { | ||
1800 | pr_err("failed to get thread map from %s\n", sched->map.color_pids_str); | ||
1801 | return -1; | ||
1802 | } | ||
1803 | |||
1804 | sched->map.color_pids = map; | ||
1805 | return 0; | ||
1806 | } | ||
1807 | |||
1808 | static int setup_color_cpus(struct perf_sched *sched) | ||
1809 | { | ||
1810 | struct cpu_map *map; | ||
1811 | |||
1812 | if (!sched->map.color_cpus_str) | ||
1813 | return 0; | ||
1814 | |||
1815 | map = cpu_map__new(sched->map.color_cpus_str); | ||
1816 | if (!map) { | ||
1817 | pr_err("failed to get thread map from %s\n", sched->map.color_cpus_str); | ||
1818 | return -1; | ||
1819 | } | ||
1820 | |||
1821 | sched->map.color_cpus = map; | ||
1822 | return 0; | ||
1823 | } | ||
1824 | |||
1678 | static int perf_sched__map(struct perf_sched *sched) | 1825 | static int perf_sched__map(struct perf_sched *sched) |
1679 | { | 1826 | { |
1680 | sched->max_cpu = sysconf(_SC_NPROCESSORS_CONF); | 1827 | if (setup_map_cpus(sched)) |
1828 | return -1; | ||
1829 | |||
1830 | if (setup_color_pids(sched)) | ||
1831 | return -1; | ||
1832 | |||
1833 | if (setup_color_cpus(sched)) | ||
1834 | return -1; | ||
1681 | 1835 | ||
1682 | setup_pager(); | 1836 | setup_pager(); |
1683 | if (perf_sched__read_events(sched)) | 1837 | if (perf_sched__read_events(sched)) |
@@ -1831,6 +1985,17 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1831 | "dump raw trace in ASCII"), | 1985 | "dump raw trace in ASCII"), |
1832 | OPT_END() | 1986 | OPT_END() |
1833 | }; | 1987 | }; |
1988 | const struct option map_options[] = { | ||
1989 | OPT_BOOLEAN(0, "compact", &sched.map.comp, | ||
1990 | "map output in compact mode"), | ||
1991 | OPT_STRING(0, "color-pids", &sched.map.color_pids_str, "pids", | ||
1992 | "highlight given pids in map"), | ||
1993 | OPT_STRING(0, "color-cpus", &sched.map.color_cpus_str, "cpus", | ||
1994 | "highlight given CPUs in map"), | ||
1995 | OPT_STRING(0, "cpus", &sched.map.cpus_str, "cpus", | ||
1996 | "display given CPUs in map"), | ||
1997 | OPT_END() | ||
1998 | }; | ||
1834 | const char * const latency_usage[] = { | 1999 | const char * const latency_usage[] = { |
1835 | "perf sched latency [<options>]", | 2000 | "perf sched latency [<options>]", |
1836 | NULL | 2001 | NULL |
@@ -1839,6 +2004,10 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1839 | "perf sched replay [<options>]", | 2004 | "perf sched replay [<options>]", |
1840 | NULL | 2005 | NULL |
1841 | }; | 2006 | }; |
2007 | const char * const map_usage[] = { | ||
2008 | "perf sched map [<options>]", | ||
2009 | NULL | ||
2010 | }; | ||
1842 | const char *const sched_subcommands[] = { "record", "latency", "map", | 2011 | const char *const sched_subcommands[] = { "record", "latency", "map", |
1843 | "replay", "script", NULL }; | 2012 | "replay", "script", NULL }; |
1844 | const char *sched_usage[] = { | 2013 | const char *sched_usage[] = { |
@@ -1887,6 +2056,11 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1887 | setup_sorting(&sched, latency_options, latency_usage); | 2056 | setup_sorting(&sched, latency_options, latency_usage); |
1888 | return perf_sched__lat(&sched); | 2057 | return perf_sched__lat(&sched); |
1889 | } else if (!strcmp(argv[0], "map")) { | 2058 | } else if (!strcmp(argv[0], "map")) { |
2059 | if (argc) { | ||
2060 | argc = parse_options(argc, argv, map_options, map_usage, 0); | ||
2061 | if (argc) | ||
2062 | usage_with_options(map_usage, map_options); | ||
2063 | } | ||
1890 | sched.tp_handler = &map_ops; | 2064 | sched.tp_handler = &map_ops; |
1891 | setup_sorting(&sched, latency_options, latency_usage); | 2065 | setup_sorting(&sched, latency_options, latency_usage); |
1892 | return perf_sched__map(&sched); | 2066 | return perf_sched__map(&sched); |
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 3770c3dffe5e..efca81679bb3 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include "util/thread_map.h" | 22 | #include "util/thread_map.h" |
23 | #include "util/stat.h" | 23 | #include "util/stat.h" |
24 | #include <linux/bitmap.h> | 24 | #include <linux/bitmap.h> |
25 | #include <linux/stringify.h> | ||
25 | #include "asm/bug.h" | 26 | #include "asm/bug.h" |
26 | #include "util/mem-events.h" | 27 | #include "util/mem-events.h" |
27 | 28 | ||
@@ -317,19 +318,19 @@ static void set_print_ip_opts(struct perf_event_attr *attr) | |||
317 | 318 | ||
318 | output[type].print_ip_opts = 0; | 319 | output[type].print_ip_opts = 0; |
319 | if (PRINT_FIELD(IP)) | 320 | if (PRINT_FIELD(IP)) |
320 | output[type].print_ip_opts |= PRINT_IP_OPT_IP; | 321 | output[type].print_ip_opts |= EVSEL__PRINT_IP; |
321 | 322 | ||
322 | if (PRINT_FIELD(SYM)) | 323 | if (PRINT_FIELD(SYM)) |
323 | output[type].print_ip_opts |= PRINT_IP_OPT_SYM; | 324 | output[type].print_ip_opts |= EVSEL__PRINT_SYM; |
324 | 325 | ||
325 | if (PRINT_FIELD(DSO)) | 326 | if (PRINT_FIELD(DSO)) |
326 | output[type].print_ip_opts |= PRINT_IP_OPT_DSO; | 327 | output[type].print_ip_opts |= EVSEL__PRINT_DSO; |
327 | 328 | ||
328 | if (PRINT_FIELD(SYMOFFSET)) | 329 | if (PRINT_FIELD(SYMOFFSET)) |
329 | output[type].print_ip_opts |= PRINT_IP_OPT_SYMOFFSET; | 330 | output[type].print_ip_opts |= EVSEL__PRINT_SYMOFFSET; |
330 | 331 | ||
331 | if (PRINT_FIELD(SRCLINE)) | 332 | if (PRINT_FIELD(SRCLINE)) |
332 | output[type].print_ip_opts |= PRINT_IP_OPT_SRCLINE; | 333 | output[type].print_ip_opts |= EVSEL__PRINT_SRCLINE; |
333 | } | 334 | } |
334 | 335 | ||
335 | /* | 336 | /* |
@@ -569,18 +570,23 @@ static void print_sample_bts(struct perf_sample *sample, | |||
569 | /* print branch_from information */ | 570 | /* print branch_from information */ |
570 | if (PRINT_FIELD(IP)) { | 571 | if (PRINT_FIELD(IP)) { |
571 | unsigned int print_opts = output[attr->type].print_ip_opts; | 572 | unsigned int print_opts = output[attr->type].print_ip_opts; |
573 | struct callchain_cursor *cursor = NULL; | ||
572 | 574 | ||
573 | if (symbol_conf.use_callchain && sample->callchain) { | 575 | if (symbol_conf.use_callchain && sample->callchain && |
574 | printf("\n"); | 576 | thread__resolve_callchain(al->thread, &callchain_cursor, evsel, |
575 | } else { | 577 | sample, NULL, NULL, scripting_max_stack) == 0) |
576 | printf(" "); | 578 | cursor = &callchain_cursor; |
577 | if (print_opts & PRINT_IP_OPT_SRCLINE) { | 579 | |
580 | if (cursor == NULL) { | ||
581 | putchar(' '); | ||
582 | if (print_opts & EVSEL__PRINT_SRCLINE) { | ||
578 | print_srcline_last = true; | 583 | print_srcline_last = true; |
579 | print_opts &= ~PRINT_IP_OPT_SRCLINE; | 584 | print_opts &= ~EVSEL__PRINT_SRCLINE; |
580 | } | 585 | } |
581 | } | 586 | } else |
582 | perf_evsel__print_ip(evsel, sample, al, print_opts, | 587 | putchar('\n'); |
583 | scripting_max_stack); | 588 | |
589 | sample__fprintf_sym(sample, al, 0, print_opts, cursor, stdout); | ||
584 | } | 590 | } |
585 | 591 | ||
586 | /* print branch_to information */ | 592 | /* print branch_to information */ |
@@ -783,14 +789,15 @@ static void process_event(struct perf_script *script, | |||
783 | printf("%16" PRIu64, sample->weight); | 789 | printf("%16" PRIu64, sample->weight); |
784 | 790 | ||
785 | if (PRINT_FIELD(IP)) { | 791 | if (PRINT_FIELD(IP)) { |
786 | if (!symbol_conf.use_callchain) | 792 | struct callchain_cursor *cursor = NULL; |
787 | printf(" "); | 793 | |
788 | else | 794 | if (symbol_conf.use_callchain && sample->callchain && |
789 | printf("\n"); | 795 | thread__resolve_callchain(al->thread, &callchain_cursor, evsel, |
796 | sample, NULL, NULL, scripting_max_stack) == 0) | ||
797 | cursor = &callchain_cursor; | ||
790 | 798 | ||
791 | perf_evsel__print_ip(evsel, sample, al, | 799 | putchar(cursor ? '\n' : ' '); |
792 | output[attr->type].print_ip_opts, | 800 | sample__fprintf_sym(sample, al, 0, output[attr->type].print_ip_opts, cursor, stdout); |
793 | scripting_max_stack); | ||
794 | } | 801 | } |
795 | 802 | ||
796 | if (PRINT_FIELD(IREGS)) | 803 | if (PRINT_FIELD(IREGS)) |
@@ -1415,21 +1422,19 @@ static int is_directory(const char *base_path, const struct dirent *dent) | |||
1415 | return S_ISDIR(st.st_mode); | 1422 | return S_ISDIR(st.st_mode); |
1416 | } | 1423 | } |
1417 | 1424 | ||
1418 | #define for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next)\ | 1425 | #define for_each_lang(scripts_path, scripts_dir, lang_dirent) \ |
1419 | while (!readdir_r(scripts_dir, &lang_dirent, &lang_next) && \ | 1426 | while ((lang_dirent = readdir(scripts_dir)) != NULL) \ |
1420 | lang_next) \ | 1427 | if ((lang_dirent->d_type == DT_DIR || \ |
1421 | if ((lang_dirent.d_type == DT_DIR || \ | 1428 | (lang_dirent->d_type == DT_UNKNOWN && \ |
1422 | (lang_dirent.d_type == DT_UNKNOWN && \ | 1429 | is_directory(scripts_path, lang_dirent))) && \ |
1423 | is_directory(scripts_path, &lang_dirent))) && \ | 1430 | (strcmp(lang_dirent->d_name, ".")) && \ |
1424 | (strcmp(lang_dirent.d_name, ".")) && \ | 1431 | (strcmp(lang_dirent->d_name, ".."))) |
1425 | (strcmp(lang_dirent.d_name, ".."))) | ||
1426 | 1432 | ||
1427 | #define for_each_script(lang_path, lang_dir, script_dirent, script_next)\ | 1433 | #define for_each_script(lang_path, lang_dir, script_dirent) \ |
1428 | while (!readdir_r(lang_dir, &script_dirent, &script_next) && \ | 1434 | while ((script_dirent = readdir(lang_dir)) != NULL) \ |
1429 | script_next) \ | 1435 | if (script_dirent->d_type != DT_DIR && \ |
1430 | if (script_dirent.d_type != DT_DIR && \ | 1436 | (script_dirent->d_type != DT_UNKNOWN || \ |
1431 | (script_dirent.d_type != DT_UNKNOWN || \ | 1437 | !is_directory(lang_path, script_dirent))) |
1432 | !is_directory(lang_path, &script_dirent))) | ||
1433 | 1438 | ||
1434 | 1439 | ||
1435 | #define RECORD_SUFFIX "-record" | 1440 | #define RECORD_SUFFIX "-record" |
@@ -1575,7 +1580,7 @@ static int list_available_scripts(const struct option *opt __maybe_unused, | |||
1575 | const char *s __maybe_unused, | 1580 | const char *s __maybe_unused, |
1576 | int unset __maybe_unused) | 1581 | int unset __maybe_unused) |
1577 | { | 1582 | { |
1578 | struct dirent *script_next, *lang_next, script_dirent, lang_dirent; | 1583 | struct dirent *script_dirent, *lang_dirent; |
1579 | char scripts_path[MAXPATHLEN]; | 1584 | char scripts_path[MAXPATHLEN]; |
1580 | DIR *scripts_dir, *lang_dir; | 1585 | DIR *scripts_dir, *lang_dir; |
1581 | char script_path[MAXPATHLEN]; | 1586 | char script_path[MAXPATHLEN]; |
@@ -1590,19 +1595,19 @@ static int list_available_scripts(const struct option *opt __maybe_unused, | |||
1590 | if (!scripts_dir) | 1595 | if (!scripts_dir) |
1591 | return -1; | 1596 | return -1; |
1592 | 1597 | ||
1593 | for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) { | 1598 | for_each_lang(scripts_path, scripts_dir, lang_dirent) { |
1594 | snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, | 1599 | snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, |
1595 | lang_dirent.d_name); | 1600 | lang_dirent->d_name); |
1596 | lang_dir = opendir(lang_path); | 1601 | lang_dir = opendir(lang_path); |
1597 | if (!lang_dir) | 1602 | if (!lang_dir) |
1598 | continue; | 1603 | continue; |
1599 | 1604 | ||
1600 | for_each_script(lang_path, lang_dir, script_dirent, script_next) { | 1605 | for_each_script(lang_path, lang_dir, script_dirent) { |
1601 | script_root = get_script_root(&script_dirent, REPORT_SUFFIX); | 1606 | script_root = get_script_root(script_dirent, REPORT_SUFFIX); |
1602 | if (script_root) { | 1607 | if (script_root) { |
1603 | desc = script_desc__findnew(script_root); | 1608 | desc = script_desc__findnew(script_root); |
1604 | snprintf(script_path, MAXPATHLEN, "%s/%s", | 1609 | snprintf(script_path, MAXPATHLEN, "%s/%s", |
1605 | lang_path, script_dirent.d_name); | 1610 | lang_path, script_dirent->d_name); |
1606 | read_script_info(desc, script_path); | 1611 | read_script_info(desc, script_path); |
1607 | free(script_root); | 1612 | free(script_root); |
1608 | } | 1613 | } |
@@ -1690,7 +1695,7 @@ static int check_ev_match(char *dir_name, char *scriptname, | |||
1690 | */ | 1695 | */ |
1691 | int find_scripts(char **scripts_array, char **scripts_path_array) | 1696 | int find_scripts(char **scripts_array, char **scripts_path_array) |
1692 | { | 1697 | { |
1693 | struct dirent *script_next, *lang_next, script_dirent, lang_dirent; | 1698 | struct dirent *script_dirent, *lang_dirent; |
1694 | char scripts_path[MAXPATHLEN], lang_path[MAXPATHLEN]; | 1699 | char scripts_path[MAXPATHLEN], lang_path[MAXPATHLEN]; |
1695 | DIR *scripts_dir, *lang_dir; | 1700 | DIR *scripts_dir, *lang_dir; |
1696 | struct perf_session *session; | 1701 | struct perf_session *session; |
@@ -1713,9 +1718,9 @@ int find_scripts(char **scripts_array, char **scripts_path_array) | |||
1713 | return -1; | 1718 | return -1; |
1714 | } | 1719 | } |
1715 | 1720 | ||
1716 | for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) { | 1721 | for_each_lang(scripts_path, scripts_dir, lang_dirent) { |
1717 | snprintf(lang_path, MAXPATHLEN, "%s/%s", scripts_path, | 1722 | snprintf(lang_path, MAXPATHLEN, "%s/%s", scripts_path, |
1718 | lang_dirent.d_name); | 1723 | lang_dirent->d_name); |
1719 | #ifdef NO_LIBPERL | 1724 | #ifdef NO_LIBPERL |
1720 | if (strstr(lang_path, "perl")) | 1725 | if (strstr(lang_path, "perl")) |
1721 | continue; | 1726 | continue; |
@@ -1729,16 +1734,16 @@ int find_scripts(char **scripts_array, char **scripts_path_array) | |||
1729 | if (!lang_dir) | 1734 | if (!lang_dir) |
1730 | continue; | 1735 | continue; |
1731 | 1736 | ||
1732 | for_each_script(lang_path, lang_dir, script_dirent, script_next) { | 1737 | for_each_script(lang_path, lang_dir, script_dirent) { |
1733 | /* Skip those real time scripts: xxxtop.p[yl] */ | 1738 | /* Skip those real time scripts: xxxtop.p[yl] */ |
1734 | if (strstr(script_dirent.d_name, "top.")) | 1739 | if (strstr(script_dirent->d_name, "top.")) |
1735 | continue; | 1740 | continue; |
1736 | sprintf(scripts_path_array[i], "%s/%s", lang_path, | 1741 | sprintf(scripts_path_array[i], "%s/%s", lang_path, |
1737 | script_dirent.d_name); | 1742 | script_dirent->d_name); |
1738 | temp = strchr(script_dirent.d_name, '.'); | 1743 | temp = strchr(script_dirent->d_name, '.'); |
1739 | snprintf(scripts_array[i], | 1744 | snprintf(scripts_array[i], |
1740 | (temp - script_dirent.d_name) + 1, | 1745 | (temp - script_dirent->d_name) + 1, |
1741 | "%s", script_dirent.d_name); | 1746 | "%s", script_dirent->d_name); |
1742 | 1747 | ||
1743 | if (check_ev_match(lang_path, | 1748 | if (check_ev_match(lang_path, |
1744 | scripts_array[i], session)) | 1749 | scripts_array[i], session)) |
@@ -1756,7 +1761,7 @@ int find_scripts(char **scripts_array, char **scripts_path_array) | |||
1756 | 1761 | ||
1757 | static char *get_script_path(const char *script_root, const char *suffix) | 1762 | static char *get_script_path(const char *script_root, const char *suffix) |
1758 | { | 1763 | { |
1759 | struct dirent *script_next, *lang_next, script_dirent, lang_dirent; | 1764 | struct dirent *script_dirent, *lang_dirent; |
1760 | char scripts_path[MAXPATHLEN]; | 1765 | char scripts_path[MAXPATHLEN]; |
1761 | char script_path[MAXPATHLEN]; | 1766 | char script_path[MAXPATHLEN]; |
1762 | DIR *scripts_dir, *lang_dir; | 1767 | DIR *scripts_dir, *lang_dir; |
@@ -1769,21 +1774,21 @@ static char *get_script_path(const char *script_root, const char *suffix) | |||
1769 | if (!scripts_dir) | 1774 | if (!scripts_dir) |
1770 | return NULL; | 1775 | return NULL; |
1771 | 1776 | ||
1772 | for_each_lang(scripts_path, scripts_dir, lang_dirent, lang_next) { | 1777 | for_each_lang(scripts_path, scripts_dir, lang_dirent) { |
1773 | snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, | 1778 | snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path, |
1774 | lang_dirent.d_name); | 1779 | lang_dirent->d_name); |
1775 | lang_dir = opendir(lang_path); | 1780 | lang_dir = opendir(lang_path); |
1776 | if (!lang_dir) | 1781 | if (!lang_dir) |
1777 | continue; | 1782 | continue; |
1778 | 1783 | ||
1779 | for_each_script(lang_path, lang_dir, script_dirent, script_next) { | 1784 | for_each_script(lang_path, lang_dir, script_dirent) { |
1780 | __script_root = get_script_root(&script_dirent, suffix); | 1785 | __script_root = get_script_root(script_dirent, suffix); |
1781 | if (__script_root && !strcmp(script_root, __script_root)) { | 1786 | if (__script_root && !strcmp(script_root, __script_root)) { |
1782 | free(__script_root); | 1787 | free(__script_root); |
1783 | closedir(lang_dir); | 1788 | closedir(lang_dir); |
1784 | closedir(scripts_dir); | 1789 | closedir(scripts_dir); |
1785 | snprintf(script_path, MAXPATHLEN, "%s/%s", | 1790 | snprintf(script_path, MAXPATHLEN, "%s/%s", |
1786 | lang_path, script_dirent.d_name); | 1791 | lang_path, script_dirent->d_name); |
1787 | return strdup(script_path); | 1792 | return strdup(script_path); |
1788 | } | 1793 | } |
1789 | free(__script_root); | 1794 | free(__script_root); |
@@ -1961,6 +1966,7 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1961 | .exit = perf_event__process_exit, | 1966 | .exit = perf_event__process_exit, |
1962 | .fork = perf_event__process_fork, | 1967 | .fork = perf_event__process_fork, |
1963 | .attr = process_attr, | 1968 | .attr = process_attr, |
1969 | .event_update = perf_event__process_event_update, | ||
1964 | .tracing_data = perf_event__process_tracing_data, | 1970 | .tracing_data = perf_event__process_tracing_data, |
1965 | .build_id = perf_event__process_build_id, | 1971 | .build_id = perf_event__process_build_id, |
1966 | .id_index = perf_event__process_id_index, | 1972 | .id_index = perf_event__process_id_index, |
@@ -2022,6 +2028,10 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
2022 | "only consider symbols in these pids"), | 2028 | "only consider symbols in these pids"), |
2023 | OPT_STRING(0, "tid", &symbol_conf.tid_list_str, "tid[,tid...]", | 2029 | OPT_STRING(0, "tid", &symbol_conf.tid_list_str, "tid[,tid...]", |
2024 | "only consider symbols in these tids"), | 2030 | "only consider symbols in these tids"), |
2031 | OPT_UINTEGER(0, "max-stack", &scripting_max_stack, | ||
2032 | "Set the maximum stack depth when parsing the callchain, " | ||
2033 | "anything beyond the specified depth will be ignored. " | ||
2034 | "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)), | ||
2025 | OPT_BOOLEAN('I', "show-info", &show_full_info, | 2035 | OPT_BOOLEAN('I', "show-info", &show_full_info, |
2026 | "display extended information from perf.data file"), | 2036 | "display extended information from perf.data file"), |
2027 | OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path, | 2037 | OPT_BOOLEAN('\0', "show-kernel-path", &symbol_conf.show_kernel_path, |
@@ -2057,6 +2067,8 @@ int cmd_script(int argc, const char **argv, const char *prefix __maybe_unused) | |||
2057 | NULL | 2067 | NULL |
2058 | }; | 2068 | }; |
2059 | 2069 | ||
2070 | scripting_max_stack = sysctl_perf_event_max_stack; | ||
2071 | |||
2060 | setup_scripting(); | 2072 | setup_scripting(); |
2061 | 2073 | ||
2062 | argc = parse_options_subcommand(argc, argv, options, script_subcommands, script_usage, | 2074 | argc = parse_options_subcommand(argc, argv, options, script_subcommands, script_usage, |
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 1f19f2f999c8..e459b685a4e9 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c | |||
@@ -298,6 +298,14 @@ static int read_counter(struct perf_evsel *counter) | |||
298 | return -1; | 298 | return -1; |
299 | } | 299 | } |
300 | } | 300 | } |
301 | |||
302 | if (verbose > 1) { | ||
303 | fprintf(stat_config.output, | ||
304 | "%s: %d: %" PRIu64 " %" PRIu64 " %" PRIu64 "\n", | ||
305 | perf_evsel__name(counter), | ||
306 | cpu, | ||
307 | count->val, count->ena, count->run); | ||
308 | } | ||
301 | } | 309 | } |
302 | } | 310 | } |
303 | 311 | ||
@@ -528,6 +536,7 @@ static int __run_perf_stat(int argc, const char **argv) | |||
528 | perf_evlist__set_leader(evsel_list); | 536 | perf_evlist__set_leader(evsel_list); |
529 | 537 | ||
530 | evlist__for_each(evsel_list, counter) { | 538 | evlist__for_each(evsel_list, counter) { |
539 | try_again: | ||
531 | if (create_perf_stat_counter(counter) < 0) { | 540 | if (create_perf_stat_counter(counter) < 0) { |
532 | /* | 541 | /* |
533 | * PPC returns ENXIO for HW counters until 2.6.37 | 542 | * PPC returns ENXIO for HW counters until 2.6.37 |
@@ -544,7 +553,11 @@ static int __run_perf_stat(int argc, const char **argv) | |||
544 | if ((counter->leader != counter) || | 553 | if ((counter->leader != counter) || |
545 | !(counter->leader->nr_members > 1)) | 554 | !(counter->leader->nr_members > 1)) |
546 | continue; | 555 | continue; |
547 | } | 556 | } else if (perf_evsel__fallback(counter, errno, msg, sizeof(msg))) { |
557 | if (verbose) | ||
558 | ui__warning("%s\n", msg); | ||
559 | goto try_again; | ||
560 | } | ||
548 | 561 | ||
549 | perf_evsel__open_strerror(counter, &target, | 562 | perf_evsel__open_strerror(counter, &target, |
550 | errno, msg, sizeof(msg)); | 563 | errno, msg, sizeof(msg)); |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 833214979c4f..1793da585676 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -688,7 +688,7 @@ static int hist_iter__top_callback(struct hist_entry_iter *iter, | |||
688 | struct hist_entry *he = iter->he; | 688 | struct hist_entry *he = iter->he; |
689 | struct perf_evsel *evsel = iter->evsel; | 689 | struct perf_evsel *evsel = iter->evsel; |
690 | 690 | ||
691 | if (sort__has_sym && single) | 691 | if (perf_hpp_list.sym && single) |
692 | perf_top__record_precise_ip(top, he, evsel->idx, al->addr); | 692 | perf_top__record_precise_ip(top, he, evsel->idx, al->addr); |
693 | 693 | ||
694 | hist__account_cycles(iter->sample->branch_stack, al, iter->sample, | 694 | hist__account_cycles(iter->sample->branch_stack, al, iter->sample, |
@@ -886,7 +886,7 @@ static int perf_top__start_counters(struct perf_top *top) | |||
886 | struct perf_evlist *evlist = top->evlist; | 886 | struct perf_evlist *evlist = top->evlist; |
887 | struct record_opts *opts = &top->record_opts; | 887 | struct record_opts *opts = &top->record_opts; |
888 | 888 | ||
889 | perf_evlist__config(evlist, opts); | 889 | perf_evlist__config(evlist, opts, &callchain_param); |
890 | 890 | ||
891 | evlist__for_each(evlist, counter) { | 891 | evlist__for_each(evlist, counter) { |
892 | try_again: | 892 | try_again: |
@@ -917,15 +917,15 @@ out_err: | |||
917 | return -1; | 917 | return -1; |
918 | } | 918 | } |
919 | 919 | ||
920 | static int perf_top__setup_sample_type(struct perf_top *top __maybe_unused) | 920 | static int callchain_param__setup_sample_type(struct callchain_param *callchain) |
921 | { | 921 | { |
922 | if (!sort__has_sym) { | 922 | if (!perf_hpp_list.sym) { |
923 | if (symbol_conf.use_callchain) { | 923 | if (callchain->enabled) { |
924 | ui__error("Selected -g but \"sym\" not present in --sort/-s."); | 924 | ui__error("Selected -g but \"sym\" not present in --sort/-s."); |
925 | return -EINVAL; | 925 | return -EINVAL; |
926 | } | 926 | } |
927 | } else if (callchain_param.mode != CHAIN_NONE) { | 927 | } else if (callchain->mode != CHAIN_NONE) { |
928 | if (callchain_register_param(&callchain_param) < 0) { | 928 | if (callchain_register_param(callchain) < 0) { |
929 | ui__error("Can't register callchain params.\n"); | 929 | ui__error("Can't register callchain params.\n"); |
930 | return -EINVAL; | 930 | return -EINVAL; |
931 | } | 931 | } |
@@ -952,7 +952,7 @@ static int __cmd_top(struct perf_top *top) | |||
952 | goto out_delete; | 952 | goto out_delete; |
953 | } | 953 | } |
954 | 954 | ||
955 | ret = perf_top__setup_sample_type(top); | 955 | ret = callchain_param__setup_sample_type(&callchain_param); |
956 | if (ret) | 956 | if (ret) |
957 | goto out_delete; | 957 | goto out_delete; |
958 | 958 | ||
@@ -962,7 +962,7 @@ static int __cmd_top(struct perf_top *top) | |||
962 | machine__synthesize_threads(&top->session->machines.host, &opts->target, | 962 | machine__synthesize_threads(&top->session->machines.host, &opts->target, |
963 | top->evlist->threads, false, opts->proc_map_timeout); | 963 | top->evlist->threads, false, opts->proc_map_timeout); |
964 | 964 | ||
965 | if (sort__has_socket) { | 965 | if (perf_hpp_list.socket) { |
966 | ret = perf_env__read_cpu_topology_map(&perf_env); | 966 | ret = perf_env__read_cpu_topology_map(&perf_env); |
967 | if (ret < 0) | 967 | if (ret < 0) |
968 | goto out_err_cpu_topo; | 968 | goto out_err_cpu_topo; |
@@ -1045,18 +1045,17 @@ callchain_opt(const struct option *opt, const char *arg, int unset) | |||
1045 | static int | 1045 | static int |
1046 | parse_callchain_opt(const struct option *opt, const char *arg, int unset) | 1046 | parse_callchain_opt(const struct option *opt, const char *arg, int unset) |
1047 | { | 1047 | { |
1048 | struct record_opts *record = (struct record_opts *)opt->value; | 1048 | struct callchain_param *callchain = opt->value; |
1049 | 1049 | ||
1050 | record->callgraph_set = true; | 1050 | callchain->enabled = !unset; |
1051 | callchain_param.enabled = !unset; | 1051 | callchain->record_mode = CALLCHAIN_FP; |
1052 | callchain_param.record_mode = CALLCHAIN_FP; | ||
1053 | 1052 | ||
1054 | /* | 1053 | /* |
1055 | * --no-call-graph | 1054 | * --no-call-graph |
1056 | */ | 1055 | */ |
1057 | if (unset) { | 1056 | if (unset) { |
1058 | symbol_conf.use_callchain = false; | 1057 | symbol_conf.use_callchain = false; |
1059 | callchain_param.record_mode = CALLCHAIN_NONE; | 1058 | callchain->record_mode = CALLCHAIN_NONE; |
1060 | return 0; | 1059 | return 0; |
1061 | } | 1060 | } |
1062 | 1061 | ||
@@ -1104,7 +1103,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1104 | }, | 1103 | }, |
1105 | .proc_map_timeout = 500, | 1104 | .proc_map_timeout = 500, |
1106 | }, | 1105 | }, |
1107 | .max_stack = PERF_MAX_STACK_DEPTH, | 1106 | .max_stack = sysctl_perf_event_max_stack, |
1108 | .sym_pcnt_filter = 5, | 1107 | .sym_pcnt_filter = 5, |
1109 | }; | 1108 | }; |
1110 | struct record_opts *opts = &top.record_opts; | 1109 | struct record_opts *opts = &top.record_opts; |
@@ -1162,17 +1161,17 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1162 | "output field(s): overhead, period, sample plus all of sort keys"), | 1161 | "output field(s): overhead, period, sample plus all of sort keys"), |
1163 | OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, | 1162 | OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, |
1164 | "Show a column with the number of samples"), | 1163 | "Show a column with the number of samples"), |
1165 | OPT_CALLBACK_NOOPT('g', NULL, &top.record_opts, | 1164 | OPT_CALLBACK_NOOPT('g', NULL, &callchain_param, |
1166 | NULL, "enables call-graph recording and display", | 1165 | NULL, "enables call-graph recording and display", |
1167 | &callchain_opt), | 1166 | &callchain_opt), |
1168 | OPT_CALLBACK(0, "call-graph", &top.record_opts, | 1167 | OPT_CALLBACK(0, "call-graph", &callchain_param, |
1169 | "record_mode[,record_size],print_type,threshold[,print_limit],order,sort_key[,branch]", | 1168 | "record_mode[,record_size],print_type,threshold[,print_limit],order,sort_key[,branch]", |
1170 | top_callchain_help, &parse_callchain_opt), | 1169 | top_callchain_help, &parse_callchain_opt), |
1171 | OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain, | 1170 | OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain, |
1172 | "Accumulate callchains of children and show total overhead as well"), | 1171 | "Accumulate callchains of children and show total overhead as well"), |
1173 | OPT_INTEGER(0, "max-stack", &top.max_stack, | 1172 | OPT_INTEGER(0, "max-stack", &top.max_stack, |
1174 | "Set the maximum stack depth when parsing the callchain. " | 1173 | "Set the maximum stack depth when parsing the callchain. " |
1175 | "Default: " __stringify(PERF_MAX_STACK_DEPTH)), | 1174 | "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)), |
1176 | OPT_CALLBACK(0, "ignore-callees", NULL, "regex", | 1175 | OPT_CALLBACK(0, "ignore-callees", NULL, "regex", |
1177 | "ignore callees of these functions in call graphs", | 1176 | "ignore callees of these functions in call graphs", |
1178 | report_parse_ignore_callees_opt), | 1177 | report_parse_ignore_callees_opt), |
@@ -1256,7 +1255,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1256 | 1255 | ||
1257 | sort__mode = SORT_MODE__TOP; | 1256 | sort__mode = SORT_MODE__TOP; |
1258 | /* display thread wants entries to be collapsed in a different tree */ | 1257 | /* display thread wants entries to be collapsed in a different tree */ |
1259 | sort__need_collapse = 1; | 1258 | perf_hpp_list.need_collapse = 1; |
1260 | 1259 | ||
1261 | if (top.use_stdio) | 1260 | if (top.use_stdio) |
1262 | use_browser = 0; | 1261 | use_browser = 0; |
@@ -1312,7 +1311,7 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1312 | 1311 | ||
1313 | top.sym_evsel = perf_evlist__first(top.evlist); | 1312 | top.sym_evsel = perf_evlist__first(top.evlist); |
1314 | 1313 | ||
1315 | if (!symbol_conf.use_callchain) { | 1314 | if (!callchain_param.enabled) { |
1316 | symbol_conf.cumulate_callchain = false; | 1315 | symbol_conf.cumulate_callchain = false; |
1317 | perf_hpp__cancel_cumulate(); | 1316 | perf_hpp__cancel_cumulate(); |
1318 | } | 1317 | } |
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 93ac724fb635..6e5c325148e4 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c | |||
@@ -34,79 +34,76 @@ | |||
34 | #include "trace-event.h" | 34 | #include "trace-event.h" |
35 | #include "util/parse-events.h" | 35 | #include "util/parse-events.h" |
36 | #include "util/bpf-loader.h" | 36 | #include "util/bpf-loader.h" |
37 | #include "callchain.h" | ||
38 | #include "syscalltbl.h" | ||
39 | #include "rb_resort.h" | ||
37 | 40 | ||
38 | #include <libaudit.h> | 41 | #include <libaudit.h> /* FIXME: Still needed for audit_errno_to_name */ |
39 | #include <stdlib.h> | 42 | #include <stdlib.h> |
40 | #include <sys/mman.h> | ||
41 | #include <linux/futex.h> | ||
42 | #include <linux/err.h> | 43 | #include <linux/err.h> |
43 | 44 | #include <linux/filter.h> | |
44 | /* For older distros: */ | 45 | #include <linux/audit.h> |
45 | #ifndef MAP_STACK | 46 | #include <sys/ptrace.h> |
46 | # define MAP_STACK 0x20000 | 47 | #include <linux/random.h> |
47 | #endif | 48 | #include <linux/stringify.h> |
48 | |||
49 | #ifndef MADV_HWPOISON | ||
50 | # define MADV_HWPOISON 100 | ||
51 | |||
52 | #endif | ||
53 | |||
54 | #ifndef MADV_MERGEABLE | ||
55 | # define MADV_MERGEABLE 12 | ||
56 | #endif | ||
57 | |||
58 | #ifndef MADV_UNMERGEABLE | ||
59 | # define MADV_UNMERGEABLE 13 | ||
60 | #endif | ||
61 | |||
62 | #ifndef EFD_SEMAPHORE | ||
63 | # define EFD_SEMAPHORE 1 | ||
64 | #endif | ||
65 | |||
66 | #ifndef EFD_NONBLOCK | ||
67 | # define EFD_NONBLOCK 00004000 | ||
68 | #endif | ||
69 | |||
70 | #ifndef EFD_CLOEXEC | ||
71 | # define EFD_CLOEXEC 02000000 | ||
72 | #endif | ||
73 | 49 | ||
74 | #ifndef O_CLOEXEC | 50 | #ifndef O_CLOEXEC |
75 | # define O_CLOEXEC 02000000 | 51 | # define O_CLOEXEC 02000000 |
76 | #endif | 52 | #endif |
77 | 53 | ||
78 | #ifndef SOCK_DCCP | 54 | struct trace { |
79 | # define SOCK_DCCP 6 | 55 | struct perf_tool tool; |
80 | #endif | 56 | struct syscalltbl *sctbl; |
81 | 57 | struct { | |
82 | #ifndef SOCK_CLOEXEC | 58 | int max; |
83 | # define SOCK_CLOEXEC 02000000 | 59 | struct syscall *table; |
84 | #endif | 60 | struct { |
85 | 61 | struct perf_evsel *sys_enter, | |
86 | #ifndef SOCK_NONBLOCK | 62 | *sys_exit; |
87 | # define SOCK_NONBLOCK 00004000 | 63 | } events; |
88 | #endif | 64 | } syscalls; |
89 | 65 | struct record_opts opts; | |
90 | #ifndef MSG_CMSG_CLOEXEC | 66 | struct perf_evlist *evlist; |
91 | # define MSG_CMSG_CLOEXEC 0x40000000 | 67 | struct machine *host; |
92 | #endif | 68 | struct thread *current; |
93 | 69 | u64 base_time; | |
94 | #ifndef PERF_FLAG_FD_NO_GROUP | 70 | FILE *output; |
95 | # define PERF_FLAG_FD_NO_GROUP (1UL << 0) | 71 | unsigned long nr_events; |
96 | #endif | 72 | struct strlist *ev_qualifier; |
97 | 73 | struct { | |
98 | #ifndef PERF_FLAG_FD_OUTPUT | 74 | size_t nr; |
99 | # define PERF_FLAG_FD_OUTPUT (1UL << 1) | 75 | int *entries; |
100 | #endif | 76 | } ev_qualifier_ids; |
101 | 77 | struct intlist *tid_list; | |
102 | #ifndef PERF_FLAG_PID_CGROUP | 78 | struct intlist *pid_list; |
103 | # define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */ | 79 | struct { |
104 | #endif | 80 | size_t nr; |
105 | 81 | pid_t *entries; | |
106 | #ifndef PERF_FLAG_FD_CLOEXEC | 82 | } filter_pids; |
107 | # define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */ | 83 | double duration_filter; |
108 | #endif | 84 | double runtime_ms; |
109 | 85 | struct { | |
86 | u64 vfs_getname, | ||
87 | proc_getname; | ||
88 | } stats; | ||
89 | unsigned int max_stack; | ||
90 | unsigned int min_stack; | ||
91 | bool not_ev_qualifier; | ||
92 | bool live; | ||
93 | bool full_time; | ||
94 | bool sched; | ||
95 | bool multiple_threads; | ||
96 | bool summary; | ||
97 | bool summary_only; | ||
98 | bool show_comm; | ||
99 | bool show_tool_stats; | ||
100 | bool trace_syscalls; | ||
101 | bool kernel_syscallchains; | ||
102 | bool force; | ||
103 | bool vfs_getname; | ||
104 | int trace_pgfaults; | ||
105 | int open_id; | ||
106 | }; | ||
110 | 107 | ||
111 | struct tp_field { | 108 | struct tp_field { |
112 | int offset; | 109 | int offset; |
@@ -371,221 +368,6 @@ static size_t syscall_arg__scnprintf_int(char *bf, size_t size, | |||
371 | 368 | ||
372 | #define SCA_INT syscall_arg__scnprintf_int | 369 | #define SCA_INT syscall_arg__scnprintf_int |
373 | 370 | ||
374 | static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size, | ||
375 | struct syscall_arg *arg) | ||
376 | { | ||
377 | int printed = 0, prot = arg->val; | ||
378 | |||
379 | if (prot == PROT_NONE) | ||
380 | return scnprintf(bf, size, "NONE"); | ||
381 | #define P_MMAP_PROT(n) \ | ||
382 | if (prot & PROT_##n) { \ | ||
383 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
384 | prot &= ~PROT_##n; \ | ||
385 | } | ||
386 | |||
387 | P_MMAP_PROT(EXEC); | ||
388 | P_MMAP_PROT(READ); | ||
389 | P_MMAP_PROT(WRITE); | ||
390 | #ifdef PROT_SEM | ||
391 | P_MMAP_PROT(SEM); | ||
392 | #endif | ||
393 | P_MMAP_PROT(GROWSDOWN); | ||
394 | P_MMAP_PROT(GROWSUP); | ||
395 | #undef P_MMAP_PROT | ||
396 | |||
397 | if (prot) | ||
398 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot); | ||
399 | |||
400 | return printed; | ||
401 | } | ||
402 | |||
403 | #define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot | ||
404 | |||
405 | static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, | ||
406 | struct syscall_arg *arg) | ||
407 | { | ||
408 | int printed = 0, flags = arg->val; | ||
409 | |||
410 | #define P_MMAP_FLAG(n) \ | ||
411 | if (flags & MAP_##n) { \ | ||
412 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
413 | flags &= ~MAP_##n; \ | ||
414 | } | ||
415 | |||
416 | P_MMAP_FLAG(SHARED); | ||
417 | P_MMAP_FLAG(PRIVATE); | ||
418 | #ifdef MAP_32BIT | ||
419 | P_MMAP_FLAG(32BIT); | ||
420 | #endif | ||
421 | P_MMAP_FLAG(ANONYMOUS); | ||
422 | P_MMAP_FLAG(DENYWRITE); | ||
423 | P_MMAP_FLAG(EXECUTABLE); | ||
424 | P_MMAP_FLAG(FILE); | ||
425 | P_MMAP_FLAG(FIXED); | ||
426 | P_MMAP_FLAG(GROWSDOWN); | ||
427 | #ifdef MAP_HUGETLB | ||
428 | P_MMAP_FLAG(HUGETLB); | ||
429 | #endif | ||
430 | P_MMAP_FLAG(LOCKED); | ||
431 | P_MMAP_FLAG(NONBLOCK); | ||
432 | P_MMAP_FLAG(NORESERVE); | ||
433 | P_MMAP_FLAG(POPULATE); | ||
434 | P_MMAP_FLAG(STACK); | ||
435 | #ifdef MAP_UNINITIALIZED | ||
436 | P_MMAP_FLAG(UNINITIALIZED); | ||
437 | #endif | ||
438 | #undef P_MMAP_FLAG | ||
439 | |||
440 | if (flags) | ||
441 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
442 | |||
443 | return printed; | ||
444 | } | ||
445 | |||
446 | #define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags | ||
447 | |||
448 | static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size, | ||
449 | struct syscall_arg *arg) | ||
450 | { | ||
451 | int printed = 0, flags = arg->val; | ||
452 | |||
453 | #define P_MREMAP_FLAG(n) \ | ||
454 | if (flags & MREMAP_##n) { \ | ||
455 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
456 | flags &= ~MREMAP_##n; \ | ||
457 | } | ||
458 | |||
459 | P_MREMAP_FLAG(MAYMOVE); | ||
460 | #ifdef MREMAP_FIXED | ||
461 | P_MREMAP_FLAG(FIXED); | ||
462 | #endif | ||
463 | #undef P_MREMAP_FLAG | ||
464 | |||
465 | if (flags) | ||
466 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
467 | |||
468 | return printed; | ||
469 | } | ||
470 | |||
471 | #define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags | ||
472 | |||
473 | static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size, | ||
474 | struct syscall_arg *arg) | ||
475 | { | ||
476 | int behavior = arg->val; | ||
477 | |||
478 | switch (behavior) { | ||
479 | #define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n) | ||
480 | P_MADV_BHV(NORMAL); | ||
481 | P_MADV_BHV(RANDOM); | ||
482 | P_MADV_BHV(SEQUENTIAL); | ||
483 | P_MADV_BHV(WILLNEED); | ||
484 | P_MADV_BHV(DONTNEED); | ||
485 | P_MADV_BHV(REMOVE); | ||
486 | P_MADV_BHV(DONTFORK); | ||
487 | P_MADV_BHV(DOFORK); | ||
488 | P_MADV_BHV(HWPOISON); | ||
489 | #ifdef MADV_SOFT_OFFLINE | ||
490 | P_MADV_BHV(SOFT_OFFLINE); | ||
491 | #endif | ||
492 | P_MADV_BHV(MERGEABLE); | ||
493 | P_MADV_BHV(UNMERGEABLE); | ||
494 | #ifdef MADV_HUGEPAGE | ||
495 | P_MADV_BHV(HUGEPAGE); | ||
496 | #endif | ||
497 | #ifdef MADV_NOHUGEPAGE | ||
498 | P_MADV_BHV(NOHUGEPAGE); | ||
499 | #endif | ||
500 | #ifdef MADV_DONTDUMP | ||
501 | P_MADV_BHV(DONTDUMP); | ||
502 | #endif | ||
503 | #ifdef MADV_DODUMP | ||
504 | P_MADV_BHV(DODUMP); | ||
505 | #endif | ||
506 | #undef P_MADV_PHV | ||
507 | default: break; | ||
508 | } | ||
509 | |||
510 | return scnprintf(bf, size, "%#x", behavior); | ||
511 | } | ||
512 | |||
513 | #define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior | ||
514 | |||
515 | static size_t syscall_arg__scnprintf_flock(char *bf, size_t size, | ||
516 | struct syscall_arg *arg) | ||
517 | { | ||
518 | int printed = 0, op = arg->val; | ||
519 | |||
520 | if (op == 0) | ||
521 | return scnprintf(bf, size, "NONE"); | ||
522 | #define P_CMD(cmd) \ | ||
523 | if ((op & LOCK_##cmd) == LOCK_##cmd) { \ | ||
524 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \ | ||
525 | op &= ~LOCK_##cmd; \ | ||
526 | } | ||
527 | |||
528 | P_CMD(SH); | ||
529 | P_CMD(EX); | ||
530 | P_CMD(NB); | ||
531 | P_CMD(UN); | ||
532 | P_CMD(MAND); | ||
533 | P_CMD(RW); | ||
534 | P_CMD(READ); | ||
535 | P_CMD(WRITE); | ||
536 | #undef P_OP | ||
537 | |||
538 | if (op) | ||
539 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op); | ||
540 | |||
541 | return printed; | ||
542 | } | ||
543 | |||
544 | #define SCA_FLOCK syscall_arg__scnprintf_flock | ||
545 | |||
546 | static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg) | ||
547 | { | ||
548 | enum syscall_futex_args { | ||
549 | SCF_UADDR = (1 << 0), | ||
550 | SCF_OP = (1 << 1), | ||
551 | SCF_VAL = (1 << 2), | ||
552 | SCF_TIMEOUT = (1 << 3), | ||
553 | SCF_UADDR2 = (1 << 4), | ||
554 | SCF_VAL3 = (1 << 5), | ||
555 | }; | ||
556 | int op = arg->val; | ||
557 | int cmd = op & FUTEX_CMD_MASK; | ||
558 | size_t printed = 0; | ||
559 | |||
560 | switch (cmd) { | ||
561 | #define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n); | ||
562 | P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break; | ||
563 | P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; | ||
564 | P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; | ||
565 | P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break; | ||
566 | P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break; | ||
567 | P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break; | ||
568 | P_FUTEX_OP(WAKE_OP); break; | ||
569 | P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; | ||
570 | P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; | ||
571 | P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break; | ||
572 | P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break; | ||
573 | P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break; | ||
574 | P_FUTEX_OP(WAIT_REQUEUE_PI); break; | ||
575 | default: printed = scnprintf(bf, size, "%#x", cmd); break; | ||
576 | } | ||
577 | |||
578 | if (op & FUTEX_PRIVATE_FLAG) | ||
579 | printed += scnprintf(bf + printed, size - printed, "|PRIV"); | ||
580 | |||
581 | if (op & FUTEX_CLOCK_REALTIME) | ||
582 | printed += scnprintf(bf + printed, size - printed, "|CLKRT"); | ||
583 | |||
584 | return printed; | ||
585 | } | ||
586 | |||
587 | #define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op | ||
588 | |||
589 | static const char *bpf_cmd[] = { | 371 | static const char *bpf_cmd[] = { |
590 | "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM", | 372 | "MAP_CREATE", "MAP_LOOKUP_ELEM", "MAP_UPDATE_ELEM", "MAP_DELETE_ELEM", |
591 | "MAP_GET_NEXT_KEY", "PROG_LOAD", | 373 | "MAP_GET_NEXT_KEY", "PROG_LOAD", |
@@ -652,110 +434,6 @@ static const char *socket_families[] = { | |||
652 | }; | 434 | }; |
653 | static DEFINE_STRARRAY(socket_families); | 435 | static DEFINE_STRARRAY(socket_families); |
654 | 436 | ||
655 | #ifndef SOCK_TYPE_MASK | ||
656 | #define SOCK_TYPE_MASK 0xf | ||
657 | #endif | ||
658 | |||
659 | static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size, | ||
660 | struct syscall_arg *arg) | ||
661 | { | ||
662 | size_t printed; | ||
663 | int type = arg->val, | ||
664 | flags = type & ~SOCK_TYPE_MASK; | ||
665 | |||
666 | type &= SOCK_TYPE_MASK; | ||
667 | /* | ||
668 | * Can't use a strarray, MIPS may override for ABI reasons. | ||
669 | */ | ||
670 | switch (type) { | ||
671 | #define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break; | ||
672 | P_SK_TYPE(STREAM); | ||
673 | P_SK_TYPE(DGRAM); | ||
674 | P_SK_TYPE(RAW); | ||
675 | P_SK_TYPE(RDM); | ||
676 | P_SK_TYPE(SEQPACKET); | ||
677 | P_SK_TYPE(DCCP); | ||
678 | P_SK_TYPE(PACKET); | ||
679 | #undef P_SK_TYPE | ||
680 | default: | ||
681 | printed = scnprintf(bf, size, "%#x", type); | ||
682 | } | ||
683 | |||
684 | #define P_SK_FLAG(n) \ | ||
685 | if (flags & SOCK_##n) { \ | ||
686 | printed += scnprintf(bf + printed, size - printed, "|%s", #n); \ | ||
687 | flags &= ~SOCK_##n; \ | ||
688 | } | ||
689 | |||
690 | P_SK_FLAG(CLOEXEC); | ||
691 | P_SK_FLAG(NONBLOCK); | ||
692 | #undef P_SK_FLAG | ||
693 | |||
694 | if (flags) | ||
695 | printed += scnprintf(bf + printed, size - printed, "|%#x", flags); | ||
696 | |||
697 | return printed; | ||
698 | } | ||
699 | |||
700 | #define SCA_SK_TYPE syscall_arg__scnprintf_socket_type | ||
701 | |||
702 | #ifndef MSG_PROBE | ||
703 | #define MSG_PROBE 0x10 | ||
704 | #endif | ||
705 | #ifndef MSG_WAITFORONE | ||
706 | #define MSG_WAITFORONE 0x10000 | ||
707 | #endif | ||
708 | #ifndef MSG_SENDPAGE_NOTLAST | ||
709 | #define MSG_SENDPAGE_NOTLAST 0x20000 | ||
710 | #endif | ||
711 | #ifndef MSG_FASTOPEN | ||
712 | #define MSG_FASTOPEN 0x20000000 | ||
713 | #endif | ||
714 | |||
715 | static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size, | ||
716 | struct syscall_arg *arg) | ||
717 | { | ||
718 | int printed = 0, flags = arg->val; | ||
719 | |||
720 | if (flags == 0) | ||
721 | return scnprintf(bf, size, "NONE"); | ||
722 | #define P_MSG_FLAG(n) \ | ||
723 | if (flags & MSG_##n) { \ | ||
724 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
725 | flags &= ~MSG_##n; \ | ||
726 | } | ||
727 | |||
728 | P_MSG_FLAG(OOB); | ||
729 | P_MSG_FLAG(PEEK); | ||
730 | P_MSG_FLAG(DONTROUTE); | ||
731 | P_MSG_FLAG(TRYHARD); | ||
732 | P_MSG_FLAG(CTRUNC); | ||
733 | P_MSG_FLAG(PROBE); | ||
734 | P_MSG_FLAG(TRUNC); | ||
735 | P_MSG_FLAG(DONTWAIT); | ||
736 | P_MSG_FLAG(EOR); | ||
737 | P_MSG_FLAG(WAITALL); | ||
738 | P_MSG_FLAG(FIN); | ||
739 | P_MSG_FLAG(SYN); | ||
740 | P_MSG_FLAG(CONFIRM); | ||
741 | P_MSG_FLAG(RST); | ||
742 | P_MSG_FLAG(ERRQUEUE); | ||
743 | P_MSG_FLAG(NOSIGNAL); | ||
744 | P_MSG_FLAG(MORE); | ||
745 | P_MSG_FLAG(WAITFORONE); | ||
746 | P_MSG_FLAG(SENDPAGE_NOTLAST); | ||
747 | P_MSG_FLAG(FASTOPEN); | ||
748 | P_MSG_FLAG(CMSG_CLOEXEC); | ||
749 | #undef P_MSG_FLAG | ||
750 | |||
751 | if (flags) | ||
752 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
753 | |||
754 | return printed; | ||
755 | } | ||
756 | |||
757 | #define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags | ||
758 | |||
759 | static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size, | 437 | static size_t syscall_arg__scnprintf_access_mode(char *bf, size_t size, |
760 | struct syscall_arg *arg) | 438 | struct syscall_arg *arg) |
761 | { | 439 | { |
@@ -788,116 +466,6 @@ static size_t syscall_arg__scnprintf_filename(char *bf, size_t size, | |||
788 | 466 | ||
789 | #define SCA_FILENAME syscall_arg__scnprintf_filename | 467 | #define SCA_FILENAME syscall_arg__scnprintf_filename |
790 | 468 | ||
791 | static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size, | ||
792 | struct syscall_arg *arg) | ||
793 | { | ||
794 | int printed = 0, flags = arg->val; | ||
795 | |||
796 | if (!(flags & O_CREAT)) | ||
797 | arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */ | ||
798 | |||
799 | if (flags == 0) | ||
800 | return scnprintf(bf, size, "RDONLY"); | ||
801 | #define P_FLAG(n) \ | ||
802 | if (flags & O_##n) { \ | ||
803 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
804 | flags &= ~O_##n; \ | ||
805 | } | ||
806 | |||
807 | P_FLAG(APPEND); | ||
808 | P_FLAG(ASYNC); | ||
809 | P_FLAG(CLOEXEC); | ||
810 | P_FLAG(CREAT); | ||
811 | P_FLAG(DIRECT); | ||
812 | P_FLAG(DIRECTORY); | ||
813 | P_FLAG(EXCL); | ||
814 | P_FLAG(LARGEFILE); | ||
815 | P_FLAG(NOATIME); | ||
816 | P_FLAG(NOCTTY); | ||
817 | #ifdef O_NONBLOCK | ||
818 | P_FLAG(NONBLOCK); | ||
819 | #elif O_NDELAY | ||
820 | P_FLAG(NDELAY); | ||
821 | #endif | ||
822 | #ifdef O_PATH | ||
823 | P_FLAG(PATH); | ||
824 | #endif | ||
825 | P_FLAG(RDWR); | ||
826 | #ifdef O_DSYNC | ||
827 | if ((flags & O_SYNC) == O_SYNC) | ||
828 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC"); | ||
829 | else { | ||
830 | P_FLAG(DSYNC); | ||
831 | } | ||
832 | #else | ||
833 | P_FLAG(SYNC); | ||
834 | #endif | ||
835 | P_FLAG(TRUNC); | ||
836 | P_FLAG(WRONLY); | ||
837 | #undef P_FLAG | ||
838 | |||
839 | if (flags) | ||
840 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
841 | |||
842 | return printed; | ||
843 | } | ||
844 | |||
845 | #define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags | ||
846 | |||
847 | static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size, | ||
848 | struct syscall_arg *arg) | ||
849 | { | ||
850 | int printed = 0, flags = arg->val; | ||
851 | |||
852 | if (flags == 0) | ||
853 | return 0; | ||
854 | |||
855 | #define P_FLAG(n) \ | ||
856 | if (flags & PERF_FLAG_##n) { \ | ||
857 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
858 | flags &= ~PERF_FLAG_##n; \ | ||
859 | } | ||
860 | |||
861 | P_FLAG(FD_NO_GROUP); | ||
862 | P_FLAG(FD_OUTPUT); | ||
863 | P_FLAG(PID_CGROUP); | ||
864 | P_FLAG(FD_CLOEXEC); | ||
865 | #undef P_FLAG | ||
866 | |||
867 | if (flags) | ||
868 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
869 | |||
870 | return printed; | ||
871 | } | ||
872 | |||
873 | #define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags | ||
874 | |||
875 | static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size, | ||
876 | struct syscall_arg *arg) | ||
877 | { | ||
878 | int printed = 0, flags = arg->val; | ||
879 | |||
880 | if (flags == 0) | ||
881 | return scnprintf(bf, size, "NONE"); | ||
882 | #define P_FLAG(n) \ | ||
883 | if (flags & EFD_##n) { \ | ||
884 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
885 | flags &= ~EFD_##n; \ | ||
886 | } | ||
887 | |||
888 | P_FLAG(SEMAPHORE); | ||
889 | P_FLAG(CLOEXEC); | ||
890 | P_FLAG(NONBLOCK); | ||
891 | #undef P_FLAG | ||
892 | |||
893 | if (flags) | ||
894 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
895 | |||
896 | return printed; | ||
897 | } | ||
898 | |||
899 | #define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags | ||
900 | |||
901 | static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size, | 469 | static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size, |
902 | struct syscall_arg *arg) | 470 | struct syscall_arg *arg) |
903 | { | 471 | { |
@@ -921,59 +489,6 @@ static size_t syscall_arg__scnprintf_pipe_flags(char *bf, size_t size, | |||
921 | 489 | ||
922 | #define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags | 490 | #define SCA_PIPE_FLAGS syscall_arg__scnprintf_pipe_flags |
923 | 491 | ||
924 | static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg) | ||
925 | { | ||
926 | int sig = arg->val; | ||
927 | |||
928 | switch (sig) { | ||
929 | #define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n) | ||
930 | P_SIGNUM(HUP); | ||
931 | P_SIGNUM(INT); | ||
932 | P_SIGNUM(QUIT); | ||
933 | P_SIGNUM(ILL); | ||
934 | P_SIGNUM(TRAP); | ||
935 | P_SIGNUM(ABRT); | ||
936 | P_SIGNUM(BUS); | ||
937 | P_SIGNUM(FPE); | ||
938 | P_SIGNUM(KILL); | ||
939 | P_SIGNUM(USR1); | ||
940 | P_SIGNUM(SEGV); | ||
941 | P_SIGNUM(USR2); | ||
942 | P_SIGNUM(PIPE); | ||
943 | P_SIGNUM(ALRM); | ||
944 | P_SIGNUM(TERM); | ||
945 | P_SIGNUM(CHLD); | ||
946 | P_SIGNUM(CONT); | ||
947 | P_SIGNUM(STOP); | ||
948 | P_SIGNUM(TSTP); | ||
949 | P_SIGNUM(TTIN); | ||
950 | P_SIGNUM(TTOU); | ||
951 | P_SIGNUM(URG); | ||
952 | P_SIGNUM(XCPU); | ||
953 | P_SIGNUM(XFSZ); | ||
954 | P_SIGNUM(VTALRM); | ||
955 | P_SIGNUM(PROF); | ||
956 | P_SIGNUM(WINCH); | ||
957 | P_SIGNUM(IO); | ||
958 | P_SIGNUM(PWR); | ||
959 | P_SIGNUM(SYS); | ||
960 | #ifdef SIGEMT | ||
961 | P_SIGNUM(EMT); | ||
962 | #endif | ||
963 | #ifdef SIGSTKFLT | ||
964 | P_SIGNUM(STKFLT); | ||
965 | #endif | ||
966 | #ifdef SIGSWI | ||
967 | P_SIGNUM(SWI); | ||
968 | #endif | ||
969 | default: break; | ||
970 | } | ||
971 | |||
972 | return scnprintf(bf, size, "%#x", sig); | ||
973 | } | ||
974 | |||
975 | #define SCA_SIGNUM syscall_arg__scnprintf_signum | ||
976 | |||
977 | #if defined(__i386__) || defined(__x86_64__) | 492 | #if defined(__i386__) || defined(__x86_64__) |
978 | /* | 493 | /* |
979 | * FIXME: Make this available to all arches. | 494 | * FIXME: Make this available to all arches. |
@@ -1001,16 +516,62 @@ static const char *tioctls[] = { | |||
1001 | static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401); | 516 | static DEFINE_STRARRAY_OFFSET(tioctls, 0x5401); |
1002 | #endif /* defined(__i386__) || defined(__x86_64__) */ | 517 | #endif /* defined(__i386__) || defined(__x86_64__) */ |
1003 | 518 | ||
519 | #ifndef GRND_NONBLOCK | ||
520 | #define GRND_NONBLOCK 0x0001 | ||
521 | #endif | ||
522 | #ifndef GRND_RANDOM | ||
523 | #define GRND_RANDOM 0x0002 | ||
524 | #endif | ||
525 | |||
526 | static size_t syscall_arg__scnprintf_getrandom_flags(char *bf, size_t size, | ||
527 | struct syscall_arg *arg) | ||
528 | { | ||
529 | int printed = 0, flags = arg->val; | ||
530 | |||
531 | #define P_FLAG(n) \ | ||
532 | if (flags & GRND_##n) { \ | ||
533 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
534 | flags &= ~GRND_##n; \ | ||
535 | } | ||
536 | |||
537 | P_FLAG(RANDOM); | ||
538 | P_FLAG(NONBLOCK); | ||
539 | #undef P_FLAG | ||
540 | |||
541 | if (flags) | ||
542 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
543 | |||
544 | return printed; | ||
545 | } | ||
546 | |||
547 | #define SCA_GETRANDOM_FLAGS syscall_arg__scnprintf_getrandom_flags | ||
548 | |||
1004 | #define STRARRAY(arg, name, array) \ | 549 | #define STRARRAY(arg, name, array) \ |
1005 | .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \ | 550 | .arg_scnprintf = { [arg] = SCA_STRARRAY, }, \ |
1006 | .arg_parm = { [arg] = &strarray__##array, } | 551 | .arg_parm = { [arg] = &strarray__##array, } |
1007 | 552 | ||
553 | #include "trace/beauty/eventfd.c" | ||
554 | #include "trace/beauty/flock.c" | ||
555 | #include "trace/beauty/futex_op.c" | ||
556 | #include "trace/beauty/mmap.c" | ||
557 | #include "trace/beauty/mode_t.c" | ||
558 | #include "trace/beauty/msg_flags.c" | ||
559 | #include "trace/beauty/open_flags.c" | ||
560 | #include "trace/beauty/perf_event_open.c" | ||
561 | #include "trace/beauty/pid.c" | ||
562 | #include "trace/beauty/sched_policy.c" | ||
563 | #include "trace/beauty/seccomp.c" | ||
564 | #include "trace/beauty/signum.c" | ||
565 | #include "trace/beauty/socket_type.c" | ||
566 | #include "trace/beauty/waitid_options.c" | ||
567 | |||
1008 | static struct syscall_fmt { | 568 | static struct syscall_fmt { |
1009 | const char *name; | 569 | const char *name; |
1010 | const char *alias; | 570 | const char *alias; |
1011 | size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg); | 571 | size_t (*arg_scnprintf[6])(char *bf, size_t size, struct syscall_arg *arg); |
1012 | void *arg_parm[6]; | 572 | void *arg_parm[6]; |
1013 | bool errmsg; | 573 | bool errmsg; |
574 | bool errpid; | ||
1014 | bool timeout; | 575 | bool timeout; |
1015 | bool hexret; | 576 | bool hexret; |
1016 | } syscall_fmts[] = { | 577 | } syscall_fmts[] = { |
@@ -1028,6 +589,7 @@ static struct syscall_fmt { | |||
1028 | { .name = "chroot", .errmsg = true, | 589 | { .name = "chroot", .errmsg = true, |
1029 | .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, }, | 590 | .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, }, |
1030 | { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), }, | 591 | { .name = "clock_gettime", .errmsg = true, STRARRAY(0, clk_id, clockid), }, |
592 | { .name = "clone", .errpid = true, }, | ||
1031 | { .name = "close", .errmsg = true, | 593 | { .name = "close", .errmsg = true, |
1032 | .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, }, | 594 | .arg_scnprintf = { [0] = SCA_CLOSE_FD, /* fd */ }, }, |
1033 | { .name = "connect", .errmsg = true, }, | 595 | { .name = "connect", .errmsg = true, }, |
@@ -1093,6 +655,11 @@ static struct syscall_fmt { | |||
1093 | { .name = "getdents64", .errmsg = true, | 655 | { .name = "getdents64", .errmsg = true, |
1094 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 656 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
1095 | { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), }, | 657 | { .name = "getitimer", .errmsg = true, STRARRAY(0, which, itimers), }, |
658 | { .name = "getpid", .errpid = true, }, | ||
659 | { .name = "getpgid", .errpid = true, }, | ||
660 | { .name = "getppid", .errpid = true, }, | ||
661 | { .name = "getrandom", .errmsg = true, | ||
662 | .arg_scnprintf = { [2] = SCA_GETRANDOM_FLAGS, /* flags */ }, }, | ||
1096 | { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, | 663 | { .name = "getrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, |
1097 | { .name = "getxattr", .errmsg = true, | 664 | { .name = "getxattr", .errmsg = true, |
1098 | .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, | 665 | .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, |
@@ -1186,8 +753,7 @@ static struct syscall_fmt { | |||
1186 | [1] = SCA_FILENAME, /* filename */ | 753 | [1] = SCA_FILENAME, /* filename */ |
1187 | [2] = SCA_OPEN_FLAGS, /* flags */ }, }, | 754 | [2] = SCA_OPEN_FLAGS, /* flags */ }, }, |
1188 | { .name = "perf_event_open", .errmsg = true, | 755 | { .name = "perf_event_open", .errmsg = true, |
1189 | .arg_scnprintf = { [1] = SCA_INT, /* pid */ | 756 | .arg_scnprintf = { [2] = SCA_INT, /* cpu */ |
1190 | [2] = SCA_INT, /* cpu */ | ||
1191 | [3] = SCA_FD, /* group_fd */ | 757 | [3] = SCA_FD, /* group_fd */ |
1192 | [4] = SCA_PERF_FLAGS, /* flags */ }, }, | 758 | [4] = SCA_PERF_FLAGS, /* flags */ }, }, |
1193 | { .name = "pipe2", .errmsg = true, | 759 | { .name = "pipe2", .errmsg = true, |
@@ -1234,6 +800,11 @@ static struct syscall_fmt { | |||
1234 | .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, }, | 800 | .arg_scnprintf = { [1] = SCA_SIGNUM, /* sig */ }, }, |
1235 | { .name = "rt_tgsigqueueinfo", .errmsg = true, | 801 | { .name = "rt_tgsigqueueinfo", .errmsg = true, |
1236 | .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, }, | 802 | .arg_scnprintf = { [2] = SCA_SIGNUM, /* sig */ }, }, |
803 | { .name = "sched_setscheduler", .errmsg = true, | ||
804 | .arg_scnprintf = { [1] = SCA_SCHED_POLICY, /* policy */ }, }, | ||
805 | { .name = "seccomp", .errmsg = true, | ||
806 | .arg_scnprintf = { [0] = SCA_SECCOMP_OP, /* op */ | ||
807 | [1] = SCA_SECCOMP_FLAGS, /* flags */ }, }, | ||
1237 | { .name = "select", .errmsg = true, .timeout = true, }, | 808 | { .name = "select", .errmsg = true, .timeout = true, }, |
1238 | { .name = "sendmmsg", .errmsg = true, | 809 | { .name = "sendmmsg", .errmsg = true, |
1239 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ | 810 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ |
@@ -1244,7 +815,9 @@ static struct syscall_fmt { | |||
1244 | { .name = "sendto", .errmsg = true, | 815 | { .name = "sendto", .errmsg = true, |
1245 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ | 816 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ |
1246 | [3] = SCA_MSG_FLAGS, /* flags */ }, }, | 817 | [3] = SCA_MSG_FLAGS, /* flags */ }, }, |
818 | { .name = "set_tid_address", .errpid = true, }, | ||
1247 | { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), }, | 819 | { .name = "setitimer", .errmsg = true, STRARRAY(0, which, itimers), }, |
820 | { .name = "setpgid", .errmsg = true, }, | ||
1248 | { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, | 821 | { .name = "setrlimit", .errmsg = true, STRARRAY(0, resource, rlimit_resources), }, |
1249 | { .name = "setxattr", .errmsg = true, | 822 | { .name = "setxattr", .errmsg = true, |
1250 | .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, | 823 | .arg_scnprintf = { [0] = SCA_FILENAME, /* pathname */ }, }, |
@@ -1287,6 +860,10 @@ static struct syscall_fmt { | |||
1287 | .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, }, | 860 | .arg_scnprintf = { [0] = SCA_FILENAME, /* filename */ }, }, |
1288 | { .name = "vmsplice", .errmsg = true, | 861 | { .name = "vmsplice", .errmsg = true, |
1289 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 862 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
863 | { .name = "wait4", .errpid = true, | ||
864 | .arg_scnprintf = { [2] = SCA_WAITID_OPTIONS, /* options */ }, }, | ||
865 | { .name = "waitid", .errpid = true, | ||
866 | .arg_scnprintf = { [3] = SCA_WAITID_OPTIONS, /* options */ }, }, | ||
1290 | { .name = "write", .errmsg = true, | 867 | { .name = "write", .errmsg = true, |
1291 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, | 868 | .arg_scnprintf = { [0] = SCA_FD, /* fd */ }, }, |
1292 | { .name = "writev", .errmsg = true, | 869 | { .name = "writev", .errmsg = true, |
@@ -1398,59 +975,6 @@ fail: | |||
1398 | 975 | ||
1399 | static const size_t trace__entry_str_size = 2048; | 976 | static const size_t trace__entry_str_size = 2048; |
1400 | 977 | ||
1401 | struct trace { | ||
1402 | struct perf_tool tool; | ||
1403 | struct { | ||
1404 | int machine; | ||
1405 | int open_id; | ||
1406 | } audit; | ||
1407 | struct { | ||
1408 | int max; | ||
1409 | struct syscall *table; | ||
1410 | struct { | ||
1411 | struct perf_evsel *sys_enter, | ||
1412 | *sys_exit; | ||
1413 | } events; | ||
1414 | } syscalls; | ||
1415 | struct record_opts opts; | ||
1416 | struct perf_evlist *evlist; | ||
1417 | struct machine *host; | ||
1418 | struct thread *current; | ||
1419 | u64 base_time; | ||
1420 | FILE *output; | ||
1421 | unsigned long nr_events; | ||
1422 | struct strlist *ev_qualifier; | ||
1423 | struct { | ||
1424 | size_t nr; | ||
1425 | int *entries; | ||
1426 | } ev_qualifier_ids; | ||
1427 | struct intlist *tid_list; | ||
1428 | struct intlist *pid_list; | ||
1429 | struct { | ||
1430 | size_t nr; | ||
1431 | pid_t *entries; | ||
1432 | } filter_pids; | ||
1433 | double duration_filter; | ||
1434 | double runtime_ms; | ||
1435 | struct { | ||
1436 | u64 vfs_getname, | ||
1437 | proc_getname; | ||
1438 | } stats; | ||
1439 | bool not_ev_qualifier; | ||
1440 | bool live; | ||
1441 | bool full_time; | ||
1442 | bool sched; | ||
1443 | bool multiple_threads; | ||
1444 | bool summary; | ||
1445 | bool summary_only; | ||
1446 | bool show_comm; | ||
1447 | bool show_tool_stats; | ||
1448 | bool trace_syscalls; | ||
1449 | bool force; | ||
1450 | bool vfs_getname; | ||
1451 | int trace_pgfaults; | ||
1452 | }; | ||
1453 | |||
1454 | static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname) | 978 | static int trace__set_fd_pathname(struct thread *thread, int fd, const char *pathname) |
1455 | { | 979 | { |
1456 | struct thread_trace *ttrace = thread__priv(thread); | 980 | struct thread_trace *ttrace = thread__priv(thread); |
@@ -1618,6 +1142,7 @@ static int trace__process_event(struct trace *trace, struct machine *machine, | |||
1618 | color_fprintf(trace->output, PERF_COLOR_RED, | 1142 | color_fprintf(trace->output, PERF_COLOR_RED, |
1619 | "LOST %" PRIu64 " events!\n", event->lost.lost); | 1143 | "LOST %" PRIu64 " events!\n", event->lost.lost); |
1620 | ret = machine__process_lost_event(machine, event, sample); | 1144 | ret = machine__process_lost_event(machine, event, sample); |
1145 | break; | ||
1621 | default: | 1146 | default: |
1622 | ret = machine__process_event(machine, event, sample); | 1147 | ret = machine__process_event(machine, event, sample); |
1623 | break; | 1148 | break; |
@@ -1675,6 +1200,10 @@ static int syscall__set_arg_fmts(struct syscall *sc) | |||
1675 | sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx]; | 1200 | sc->arg_scnprintf[idx] = sc->fmt->arg_scnprintf[idx]; |
1676 | else if (field->flags & FIELD_IS_POINTER) | 1201 | else if (field->flags & FIELD_IS_POINTER) |
1677 | sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex; | 1202 | sc->arg_scnprintf[idx] = syscall_arg__scnprintf_hex; |
1203 | else if (strcmp(field->type, "pid_t") == 0) | ||
1204 | sc->arg_scnprintf[idx] = SCA_PID; | ||
1205 | else if (strcmp(field->type, "umode_t") == 0) | ||
1206 | sc->arg_scnprintf[idx] = SCA_MODE_T; | ||
1678 | ++idx; | 1207 | ++idx; |
1679 | } | 1208 | } |
1680 | 1209 | ||
@@ -1685,7 +1214,7 @@ static int trace__read_syscall_info(struct trace *trace, int id) | |||
1685 | { | 1214 | { |
1686 | char tp_name[128]; | 1215 | char tp_name[128]; |
1687 | struct syscall *sc; | 1216 | struct syscall *sc; |
1688 | const char *name = audit_syscall_to_name(id, trace->audit.machine); | 1217 | const char *name = syscalltbl__name(trace->sctbl, id); |
1689 | 1218 | ||
1690 | if (name == NULL) | 1219 | if (name == NULL) |
1691 | return -1; | 1220 | return -1; |
@@ -1760,7 +1289,7 @@ static int trace__validate_ev_qualifier(struct trace *trace) | |||
1760 | 1289 | ||
1761 | strlist__for_each(pos, trace->ev_qualifier) { | 1290 | strlist__for_each(pos, trace->ev_qualifier) { |
1762 | const char *sc = pos->s; | 1291 | const char *sc = pos->s; |
1763 | int id = audit_name_to_syscall(sc, trace->audit.machine); | 1292 | int id = syscalltbl__id(trace->sctbl, sc); |
1764 | 1293 | ||
1765 | if (id < 0) { | 1294 | if (id < 0) { |
1766 | if (err == 0) { | 1295 | if (err == 0) { |
@@ -1846,7 +1375,12 @@ static size_t syscall__scnprintf_args(struct syscall *sc, char *bf, size_t size, | |||
1846 | "%ld", val); | 1375 | "%ld", val); |
1847 | } | 1376 | } |
1848 | } | 1377 | } |
1849 | } else { | 1378 | } else if (IS_ERR(sc->tp_format)) { |
1379 | /* | ||
1380 | * If we managed to read the tracepoint /format file, then we | ||
1381 | * may end up not having any args, like with gettid(), so only | ||
1382 | * print the raw args when we didn't manage to read it. | ||
1383 | */ | ||
1850 | int i = 0; | 1384 | int i = 0; |
1851 | 1385 | ||
1852 | while (i < 6) { | 1386 | while (i < 6) { |
@@ -1987,7 +1521,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, | |||
1987 | goto out_put; | 1521 | goto out_put; |
1988 | } | 1522 | } |
1989 | 1523 | ||
1990 | if (!trace->summary_only) | 1524 | if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) |
1991 | trace__printf_interrupted_entry(trace, sample); | 1525 | trace__printf_interrupted_entry(trace, sample); |
1992 | 1526 | ||
1993 | ttrace->entry_time = sample->time; | 1527 | ttrace->entry_time = sample->time; |
@@ -1998,7 +1532,7 @@ static int trace__sys_enter(struct trace *trace, struct perf_evsel *evsel, | |||
1998 | args, trace, thread); | 1532 | args, trace, thread); |
1999 | 1533 | ||
2000 | if (sc->is_exit) { | 1534 | if (sc->is_exit) { |
2001 | if (!trace->duration_filter && !trace->summary_only) { | 1535 | if (!(trace->duration_filter || trace->summary_only || trace->min_stack)) { |
2002 | trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output); | 1536 | trace__fprintf_entry_head(trace, thread, 1, sample->time, trace->output); |
2003 | fprintf(trace->output, "%-70s\n", ttrace->entry_str); | 1537 | fprintf(trace->output, "%-70s\n", ttrace->entry_str); |
2004 | } | 1538 | } |
@@ -2018,6 +1552,29 @@ out_put: | |||
2018 | return err; | 1552 | return err; |
2019 | } | 1553 | } |
2020 | 1554 | ||
1555 | static int trace__resolve_callchain(struct trace *trace, struct perf_evsel *evsel, | ||
1556 | struct perf_sample *sample, | ||
1557 | struct callchain_cursor *cursor) | ||
1558 | { | ||
1559 | struct addr_location al; | ||
1560 | |||
1561 | if (machine__resolve(trace->host, &al, sample) < 0 || | ||
1562 | thread__resolve_callchain(al.thread, cursor, evsel, sample, NULL, NULL, trace->max_stack)) | ||
1563 | return -1; | ||
1564 | |||
1565 | return 0; | ||
1566 | } | ||
1567 | |||
1568 | static int trace__fprintf_callchain(struct trace *trace, struct perf_sample *sample) | ||
1569 | { | ||
1570 | /* TODO: user-configurable print_opts */ | ||
1571 | const unsigned int print_opts = EVSEL__PRINT_SYM | | ||
1572 | EVSEL__PRINT_DSO | | ||
1573 | EVSEL__PRINT_UNKNOWN_AS_ADDR; | ||
1574 | |||
1575 | return sample__fprintf_callchain(sample, 38, print_opts, &callchain_cursor, trace->output); | ||
1576 | } | ||
1577 | |||
2021 | static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, | 1578 | static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, |
2022 | union perf_event *event __maybe_unused, | 1579 | union perf_event *event __maybe_unused, |
2023 | struct perf_sample *sample) | 1580 | struct perf_sample *sample) |
@@ -2025,7 +1582,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, | |||
2025 | long ret; | 1582 | long ret; |
2026 | u64 duration = 0; | 1583 | u64 duration = 0; |
2027 | struct thread *thread; | 1584 | struct thread *thread; |
2028 | int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1; | 1585 | int id = perf_evsel__sc_tp_uint(evsel, id, sample), err = -1, callchain_ret = 0; |
2029 | struct syscall *sc = trace__syscall_info(trace, evsel, id); | 1586 | struct syscall *sc = trace__syscall_info(trace, evsel, id); |
2030 | struct thread_trace *ttrace; | 1587 | struct thread_trace *ttrace; |
2031 | 1588 | ||
@@ -2042,7 +1599,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, | |||
2042 | 1599 | ||
2043 | ret = perf_evsel__sc_tp_uint(evsel, ret, sample); | 1600 | ret = perf_evsel__sc_tp_uint(evsel, ret, sample); |
2044 | 1601 | ||
2045 | if (id == trace->audit.open_id && ret >= 0 && ttrace->filename.pending_open) { | 1602 | if (id == trace->open_id && ret >= 0 && ttrace->filename.pending_open) { |
2046 | trace__set_fd_pathname(thread, ret, ttrace->filename.name); | 1603 | trace__set_fd_pathname(thread, ret, ttrace->filename.name); |
2047 | ttrace->filename.pending_open = false; | 1604 | ttrace->filename.pending_open = false; |
2048 | ++trace->stats.vfs_getname; | 1605 | ++trace->stats.vfs_getname; |
@@ -2057,6 +1614,15 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, | |||
2057 | } else if (trace->duration_filter) | 1614 | } else if (trace->duration_filter) |
2058 | goto out; | 1615 | goto out; |
2059 | 1616 | ||
1617 | if (sample->callchain) { | ||
1618 | callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor); | ||
1619 | if (callchain_ret == 0) { | ||
1620 | if (callchain_cursor.nr < trace->min_stack) | ||
1621 | goto out; | ||
1622 | callchain_ret = 1; | ||
1623 | } | ||
1624 | } | ||
1625 | |||
2060 | if (trace->summary_only) | 1626 | if (trace->summary_only) |
2061 | goto out; | 1627 | goto out; |
2062 | 1628 | ||
@@ -2073,7 +1639,7 @@ static int trace__sys_exit(struct trace *trace, struct perf_evsel *evsel, | |||
2073 | if (sc->fmt == NULL) { | 1639 | if (sc->fmt == NULL) { |
2074 | signed_print: | 1640 | signed_print: |
2075 | fprintf(trace->output, ") = %ld", ret); | 1641 | fprintf(trace->output, ") = %ld", ret); |
2076 | } else if (ret < 0 && sc->fmt->errmsg) { | 1642 | } else if (ret < 0 && (sc->fmt->errmsg || sc->fmt->errpid)) { |
2077 | char bf[STRERR_BUFSIZE]; | 1643 | char bf[STRERR_BUFSIZE]; |
2078 | const char *emsg = strerror_r(-ret, bf, sizeof(bf)), | 1644 | const char *emsg = strerror_r(-ret, bf, sizeof(bf)), |
2079 | *e = audit_errno_to_name(-ret); | 1645 | *e = audit_errno_to_name(-ret); |
@@ -2083,10 +1649,24 @@ signed_print: | |||
2083 | fprintf(trace->output, ") = 0 Timeout"); | 1649 | fprintf(trace->output, ") = 0 Timeout"); |
2084 | else if (sc->fmt->hexret) | 1650 | else if (sc->fmt->hexret) |
2085 | fprintf(trace->output, ") = %#lx", ret); | 1651 | fprintf(trace->output, ") = %#lx", ret); |
2086 | else | 1652 | else if (sc->fmt->errpid) { |
1653 | struct thread *child = machine__find_thread(trace->host, ret, ret); | ||
1654 | |||
1655 | if (child != NULL) { | ||
1656 | fprintf(trace->output, ") = %ld", ret); | ||
1657 | if (child->comm_set) | ||
1658 | fprintf(trace->output, " (%s)", thread__comm_str(child)); | ||
1659 | thread__put(child); | ||
1660 | } | ||
1661 | } else | ||
2087 | goto signed_print; | 1662 | goto signed_print; |
2088 | 1663 | ||
2089 | fputc('\n', trace->output); | 1664 | fputc('\n', trace->output); |
1665 | |||
1666 | if (callchain_ret > 0) | ||
1667 | trace__fprintf_callchain(trace, sample); | ||
1668 | else if (callchain_ret < 0) | ||
1669 | pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel)); | ||
2090 | out: | 1670 | out: |
2091 | ttrace->entry_pending = false; | 1671 | ttrace->entry_pending = false; |
2092 | err = 0; | 1672 | err = 0; |
@@ -2217,6 +1797,17 @@ static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel, | |||
2217 | union perf_event *event __maybe_unused, | 1797 | union perf_event *event __maybe_unused, |
2218 | struct perf_sample *sample) | 1798 | struct perf_sample *sample) |
2219 | { | 1799 | { |
1800 | int callchain_ret = 0; | ||
1801 | |||
1802 | if (sample->callchain) { | ||
1803 | callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor); | ||
1804 | if (callchain_ret == 0) { | ||
1805 | if (callchain_cursor.nr < trace->min_stack) | ||
1806 | goto out; | ||
1807 | callchain_ret = 1; | ||
1808 | } | ||
1809 | } | ||
1810 | |||
2220 | trace__printf_interrupted_entry(trace, sample); | 1811 | trace__printf_interrupted_entry(trace, sample); |
2221 | trace__fprintf_tstamp(trace, sample->time, trace->output); | 1812 | trace__fprintf_tstamp(trace, sample->time, trace->output); |
2222 | 1813 | ||
@@ -2234,6 +1825,12 @@ static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel, | |||
2234 | } | 1825 | } |
2235 | 1826 | ||
2236 | fprintf(trace->output, ")\n"); | 1827 | fprintf(trace->output, ")\n"); |
1828 | |||
1829 | if (callchain_ret > 0) | ||
1830 | trace__fprintf_callchain(trace, sample); | ||
1831 | else if (callchain_ret < 0) | ||
1832 | pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel)); | ||
1833 | out: | ||
2237 | return 0; | 1834 | return 0; |
2238 | } | 1835 | } |
2239 | 1836 | ||
@@ -2264,8 +1861,19 @@ static int trace__pgfault(struct trace *trace, | |||
2264 | char map_type = 'd'; | 1861 | char map_type = 'd'; |
2265 | struct thread_trace *ttrace; | 1862 | struct thread_trace *ttrace; |
2266 | int err = -1; | 1863 | int err = -1; |
1864 | int callchain_ret = 0; | ||
2267 | 1865 | ||
2268 | thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); | 1866 | thread = machine__findnew_thread(trace->host, sample->pid, sample->tid); |
1867 | |||
1868 | if (sample->callchain) { | ||
1869 | callchain_ret = trace__resolve_callchain(trace, evsel, sample, &callchain_cursor); | ||
1870 | if (callchain_ret == 0) { | ||
1871 | if (callchain_cursor.nr < trace->min_stack) | ||
1872 | goto out_put; | ||
1873 | callchain_ret = 1; | ||
1874 | } | ||
1875 | } | ||
1876 | |||
2269 | ttrace = thread__trace(thread, trace->output); | 1877 | ttrace = thread__trace(thread, trace->output); |
2270 | if (ttrace == NULL) | 1878 | if (ttrace == NULL) |
2271 | goto out_put; | 1879 | goto out_put; |
@@ -2307,6 +1915,11 @@ static int trace__pgfault(struct trace *trace, | |||
2307 | print_location(trace->output, sample, &al, true, false); | 1915 | print_location(trace->output, sample, &al, true, false); |
2308 | 1916 | ||
2309 | fprintf(trace->output, " (%c%c)\n", map_type, al.level); | 1917 | fprintf(trace->output, " (%c%c)\n", map_type, al.level); |
1918 | |||
1919 | if (callchain_ret > 0) | ||
1920 | trace__fprintf_callchain(trace, sample); | ||
1921 | else if (callchain_ret < 0) | ||
1922 | pr_err("Problem processing %s callchain, skipping...\n", perf_evsel__name(evsel)); | ||
2310 | out: | 1923 | out: |
2311 | err = 0; | 1924 | err = 0; |
2312 | out_put: | 1925 | out_put: |
@@ -2326,6 +1939,23 @@ static bool skip_sample(struct trace *trace, struct perf_sample *sample) | |||
2326 | return false; | 1939 | return false; |
2327 | } | 1940 | } |
2328 | 1941 | ||
1942 | static void trace__set_base_time(struct trace *trace, | ||
1943 | struct perf_evsel *evsel, | ||
1944 | struct perf_sample *sample) | ||
1945 | { | ||
1946 | /* | ||
1947 | * BPF events were not setting PERF_SAMPLE_TIME, so be more robust | ||
1948 | * and don't use sample->time unconditionally, we may end up having | ||
1949 | * some other event in the future without PERF_SAMPLE_TIME for good | ||
1950 | * reason, i.e. we may not be interested in its timestamps, just in | ||
1951 | * it taking place, picking some piece of information when it | ||
1952 | * appears in our event stream (vfs_getname comes to mind). | ||
1953 | */ | ||
1954 | if (trace->base_time == 0 && !trace->full_time && | ||
1955 | (evsel->attr.sample_type & PERF_SAMPLE_TIME)) | ||
1956 | trace->base_time = sample->time; | ||
1957 | } | ||
1958 | |||
2329 | static int trace__process_sample(struct perf_tool *tool, | 1959 | static int trace__process_sample(struct perf_tool *tool, |
2330 | union perf_event *event, | 1960 | union perf_event *event, |
2331 | struct perf_sample *sample, | 1961 | struct perf_sample *sample, |
@@ -2340,8 +1970,7 @@ static int trace__process_sample(struct perf_tool *tool, | |||
2340 | if (skip_sample(trace, sample)) | 1970 | if (skip_sample(trace, sample)) |
2341 | return 0; | 1971 | return 0; |
2342 | 1972 | ||
2343 | if (!trace->full_time && trace->base_time == 0) | 1973 | trace__set_base_time(trace, evsel, sample); |
2344 | trace->base_time = sample->time; | ||
2345 | 1974 | ||
2346 | if (handler) { | 1975 | if (handler) { |
2347 | ++trace->nr_events; | 1976 | ++trace->nr_events; |
@@ -2450,8 +2079,7 @@ static bool perf_evlist__add_vfs_getname(struct perf_evlist *evlist) | |||
2450 | return true; | 2079 | return true; |
2451 | } | 2080 | } |
2452 | 2081 | ||
2453 | static int perf_evlist__add_pgfault(struct perf_evlist *evlist, | 2082 | static struct perf_evsel *perf_evsel__new_pgfault(u64 config) |
2454 | u64 config) | ||
2455 | { | 2083 | { |
2456 | struct perf_evsel *evsel; | 2084 | struct perf_evsel *evsel; |
2457 | struct perf_event_attr attr = { | 2085 | struct perf_event_attr attr = { |
@@ -2465,13 +2093,10 @@ static int perf_evlist__add_pgfault(struct perf_evlist *evlist, | |||
2465 | event_attr_init(&attr); | 2093 | event_attr_init(&attr); |
2466 | 2094 | ||
2467 | evsel = perf_evsel__new(&attr); | 2095 | evsel = perf_evsel__new(&attr); |
2468 | if (!evsel) | 2096 | if (evsel) |
2469 | return -ENOMEM; | 2097 | evsel->handler = trace__pgfault; |
2470 | |||
2471 | evsel->handler = trace__pgfault; | ||
2472 | perf_evlist__add(evlist, evsel); | ||
2473 | 2098 | ||
2474 | return 0; | 2099 | return evsel; |
2475 | } | 2100 | } |
2476 | 2101 | ||
2477 | static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample) | 2102 | static void trace__handle_event(struct trace *trace, union perf_event *event, struct perf_sample *sample) |
@@ -2479,9 +2104,6 @@ static void trace__handle_event(struct trace *trace, union perf_event *event, st | |||
2479 | const u32 type = event->header.type; | 2104 | const u32 type = event->header.type; |
2480 | struct perf_evsel *evsel; | 2105 | struct perf_evsel *evsel; |
2481 | 2106 | ||
2482 | if (!trace->full_time && trace->base_time == 0) | ||
2483 | trace->base_time = sample->time; | ||
2484 | |||
2485 | if (type != PERF_RECORD_SAMPLE) { | 2107 | if (type != PERF_RECORD_SAMPLE) { |
2486 | trace__process_event(trace, trace->host, event, sample); | 2108 | trace__process_event(trace, trace->host, event, sample); |
2487 | return; | 2109 | return; |
@@ -2493,6 +2115,8 @@ static void trace__handle_event(struct trace *trace, union perf_event *event, st | |||
2493 | return; | 2115 | return; |
2494 | } | 2116 | } |
2495 | 2117 | ||
2118 | trace__set_base_time(trace, evsel, sample); | ||
2119 | |||
2496 | if (evsel->attr.type == PERF_TYPE_TRACEPOINT && | 2120 | if (evsel->attr.type == PERF_TYPE_TRACEPOINT && |
2497 | sample->raw_data == NULL) { | 2121 | sample->raw_data == NULL) { |
2498 | fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", | 2122 | fprintf(trace->output, "%s sample with no payload for tid: %d, cpu %d, raw_size=%d, skipping...\n", |
@@ -2527,6 +2151,15 @@ static int trace__add_syscall_newtp(struct trace *trace) | |||
2527 | perf_evlist__add(evlist, sys_enter); | 2151 | perf_evlist__add(evlist, sys_enter); |
2528 | perf_evlist__add(evlist, sys_exit); | 2152 | perf_evlist__add(evlist, sys_exit); |
2529 | 2153 | ||
2154 | if (callchain_param.enabled && !trace->kernel_syscallchains) { | ||
2155 | /* | ||
2156 | * We're interested only in the user space callchain | ||
2157 | * leading to the syscall, allow overriding that for | ||
2158 | * debugging reasons using --kernel_syscall_callchains | ||
2159 | */ | ||
2160 | sys_exit->attr.exclude_callchain_kernel = 1; | ||
2161 | } | ||
2162 | |||
2530 | trace->syscalls.events.sys_enter = sys_enter; | 2163 | trace->syscalls.events.sys_enter = sys_enter; |
2531 | trace->syscalls.events.sys_exit = sys_exit; | 2164 | trace->syscalls.events.sys_exit = sys_exit; |
2532 | 2165 | ||
@@ -2565,7 +2198,7 @@ out_enomem: | |||
2565 | static int trace__run(struct trace *trace, int argc, const char **argv) | 2198 | static int trace__run(struct trace *trace, int argc, const char **argv) |
2566 | { | 2199 | { |
2567 | struct perf_evlist *evlist = trace->evlist; | 2200 | struct perf_evlist *evlist = trace->evlist; |
2568 | struct perf_evsel *evsel; | 2201 | struct perf_evsel *evsel, *pgfault_maj = NULL, *pgfault_min = NULL; |
2569 | int err = -1, i; | 2202 | int err = -1, i; |
2570 | unsigned long before; | 2203 | unsigned long before; |
2571 | const bool forks = argc > 0; | 2204 | const bool forks = argc > 0; |
@@ -2579,14 +2212,19 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
2579 | if (trace->trace_syscalls) | 2212 | if (trace->trace_syscalls) |
2580 | trace->vfs_getname = perf_evlist__add_vfs_getname(evlist); | 2213 | trace->vfs_getname = perf_evlist__add_vfs_getname(evlist); |
2581 | 2214 | ||
2582 | if ((trace->trace_pgfaults & TRACE_PFMAJ) && | 2215 | if ((trace->trace_pgfaults & TRACE_PFMAJ)) { |
2583 | perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MAJ)) { | 2216 | pgfault_maj = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MAJ); |
2584 | goto out_error_mem; | 2217 | if (pgfault_maj == NULL) |
2218 | goto out_error_mem; | ||
2219 | perf_evlist__add(evlist, pgfault_maj); | ||
2585 | } | 2220 | } |
2586 | 2221 | ||
2587 | if ((trace->trace_pgfaults & TRACE_PFMIN) && | 2222 | if ((trace->trace_pgfaults & TRACE_PFMIN)) { |
2588 | perf_evlist__add_pgfault(evlist, PERF_COUNT_SW_PAGE_FAULTS_MIN)) | 2223 | pgfault_min = perf_evsel__new_pgfault(PERF_COUNT_SW_PAGE_FAULTS_MIN); |
2589 | goto out_error_mem; | 2224 | if (pgfault_min == NULL) |
2225 | goto out_error_mem; | ||
2226 | perf_evlist__add(evlist, pgfault_min); | ||
2227 | } | ||
2590 | 2228 | ||
2591 | if (trace->sched && | 2229 | if (trace->sched && |
2592 | perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime", | 2230 | perf_evlist__add_newtp(evlist, "sched", "sched_stat_runtime", |
@@ -2605,7 +2243,45 @@ static int trace__run(struct trace *trace, int argc, const char **argv) | |||
2605 | goto out_delete_evlist; | 2243 | goto out_delete_evlist; |
2606 | } | 2244 | } |
2607 | 2245 | ||
2608 | perf_evlist__config(evlist, &trace->opts); | 2246 | perf_evlist__config(evlist, &trace->opts, NULL); |
2247 | |||
2248 | if (callchain_param.enabled) { | ||
2249 | bool use_identifier = false; | ||
2250 | |||
2251 | if (trace->syscalls.events.sys_exit) { | ||
2252 | perf_evsel__config_callchain(trace->syscalls.events.sys_exit, | ||
2253 | &trace->opts, &callchain_param); | ||
2254 | use_identifier = true; | ||
2255 | } | ||
2256 | |||
2257 | if (pgfault_maj) { | ||
2258 | perf_evsel__config_callchain(pgfault_maj, &trace->opts, &callchain_param); | ||
2259 | use_identifier = true; | ||
2260 | } | ||
2261 | |||
2262 | if (pgfault_min) { | ||
2263 | perf_evsel__config_callchain(pgfault_min, &trace->opts, &callchain_param); | ||
2264 | use_identifier = true; | ||
2265 | } | ||
2266 | |||
2267 | if (use_identifier) { | ||
2268 | /* | ||
2269 | * Now we have evsels with different sample_ids, use | ||
2270 | * PERF_SAMPLE_IDENTIFIER to map from sample to evsel | ||
2271 | * from a fixed position in each ring buffer record. | ||
2272 | * | ||
2273 | * As of this the changeset introducing this comment, this | ||
2274 | * isn't strictly needed, as the fields that can come before | ||
2275 | * PERF_SAMPLE_ID are all used, but we'll probably disable | ||
2276 | * some of those for things like copying the payload of | ||
2277 | * pointer syscall arguments, and for vfs_getname we don't | ||
2278 | * need PERF_SAMPLE_ADDR and PERF_SAMPLE_IP, so do this | ||
2279 | * here as a warning we need to use PERF_SAMPLE_IDENTIFIER. | ||
2280 | */ | ||
2281 | perf_evlist__set_sample_bit(evlist, IDENTIFIER); | ||
2282 | perf_evlist__reset_sample_bit(evlist, ID); | ||
2283 | } | ||
2284 | } | ||
2609 | 2285 | ||
2610 | signal(SIGCHLD, sig_handler); | 2286 | signal(SIGCHLD, sig_handler); |
2611 | signal(SIGINT, sig_handler); | 2287 | signal(SIGINT, sig_handler); |
@@ -2883,15 +2559,29 @@ static size_t trace__fprintf_threads_header(FILE *fp) | |||
2883 | return printed; | 2559 | return printed; |
2884 | } | 2560 | } |
2885 | 2561 | ||
2562 | DEFINE_RESORT_RB(syscall_stats, a->msecs > b->msecs, | ||
2563 | struct stats *stats; | ||
2564 | double msecs; | ||
2565 | int syscall; | ||
2566 | ) | ||
2567 | { | ||
2568 | struct int_node *source = rb_entry(nd, struct int_node, rb_node); | ||
2569 | struct stats *stats = source->priv; | ||
2570 | |||
2571 | entry->syscall = source->i; | ||
2572 | entry->stats = stats; | ||
2573 | entry->msecs = stats ? (u64)stats->n * (avg_stats(stats) / NSEC_PER_MSEC) : 0; | ||
2574 | } | ||
2575 | |||
2886 | static size_t thread__dump_stats(struct thread_trace *ttrace, | 2576 | static size_t thread__dump_stats(struct thread_trace *ttrace, |
2887 | struct trace *trace, FILE *fp) | 2577 | struct trace *trace, FILE *fp) |
2888 | { | 2578 | { |
2889 | struct stats *stats; | ||
2890 | size_t printed = 0; | 2579 | size_t printed = 0; |
2891 | struct syscall *sc; | 2580 | struct syscall *sc; |
2892 | struct int_node *inode = intlist__first(ttrace->syscall_stats); | 2581 | struct rb_node *nd; |
2582 | DECLARE_RESORT_RB_INTLIST(syscall_stats, ttrace->syscall_stats); | ||
2893 | 2583 | ||
2894 | if (inode == NULL) | 2584 | if (syscall_stats == NULL) |
2895 | return 0; | 2585 | return 0; |
2896 | 2586 | ||
2897 | printed += fprintf(fp, "\n"); | 2587 | printed += fprintf(fp, "\n"); |
@@ -2900,9 +2590,8 @@ static size_t thread__dump_stats(struct thread_trace *ttrace, | |||
2900 | printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n"); | 2590 | printed += fprintf(fp, " (msec) (msec) (msec) (msec) (%%)\n"); |
2901 | printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n"); | 2591 | printed += fprintf(fp, " --------------- -------- --------- --------- --------- --------- ------\n"); |
2902 | 2592 | ||
2903 | /* each int_node is a syscall */ | 2593 | resort_rb__for_each(nd, syscall_stats) { |
2904 | while (inode) { | 2594 | struct stats *stats = syscall_stats_entry->stats; |
2905 | stats = inode->priv; | ||
2906 | if (stats) { | 2595 | if (stats) { |
2907 | double min = (double)(stats->min) / NSEC_PER_MSEC; | 2596 | double min = (double)(stats->min) / NSEC_PER_MSEC; |
2908 | double max = (double)(stats->max) / NSEC_PER_MSEC; | 2597 | double max = (double)(stats->max) / NSEC_PER_MSEC; |
@@ -2913,34 +2602,23 @@ static size_t thread__dump_stats(struct thread_trace *ttrace, | |||
2913 | pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0; | 2602 | pct = avg ? 100.0 * stddev_stats(stats)/avg : 0.0; |
2914 | avg /= NSEC_PER_MSEC; | 2603 | avg /= NSEC_PER_MSEC; |
2915 | 2604 | ||
2916 | sc = &trace->syscalls.table[inode->i]; | 2605 | sc = &trace->syscalls.table[syscall_stats_entry->syscall]; |
2917 | printed += fprintf(fp, " %-15s", sc->name); | 2606 | printed += fprintf(fp, " %-15s", sc->name); |
2918 | printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f", | 2607 | printed += fprintf(fp, " %8" PRIu64 " %9.3f %9.3f %9.3f", |
2919 | n, avg * n, min, avg); | 2608 | n, syscall_stats_entry->msecs, min, avg); |
2920 | printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct); | 2609 | printed += fprintf(fp, " %9.3f %9.2f%%\n", max, pct); |
2921 | } | 2610 | } |
2922 | |||
2923 | inode = intlist__next(inode); | ||
2924 | } | 2611 | } |
2925 | 2612 | ||
2613 | resort_rb__delete(syscall_stats); | ||
2926 | printed += fprintf(fp, "\n\n"); | 2614 | printed += fprintf(fp, "\n\n"); |
2927 | 2615 | ||
2928 | return printed; | 2616 | return printed; |
2929 | } | 2617 | } |
2930 | 2618 | ||
2931 | /* struct used to pass data to per-thread function */ | 2619 | static size_t trace__fprintf_thread(FILE *fp, struct thread *thread, struct trace *trace) |
2932 | struct summary_data { | ||
2933 | FILE *fp; | ||
2934 | struct trace *trace; | ||
2935 | size_t printed; | ||
2936 | }; | ||
2937 | |||
2938 | static int trace__fprintf_one_thread(struct thread *thread, void *priv) | ||
2939 | { | 2620 | { |
2940 | struct summary_data *data = priv; | 2621 | size_t printed = 0; |
2941 | FILE *fp = data->fp; | ||
2942 | size_t printed = data->printed; | ||
2943 | struct trace *trace = data->trace; | ||
2944 | struct thread_trace *ttrace = thread__priv(thread); | 2622 | struct thread_trace *ttrace = thread__priv(thread); |
2945 | double ratio; | 2623 | double ratio; |
2946 | 2624 | ||
@@ -2956,25 +2634,45 @@ static int trace__fprintf_one_thread(struct thread *thread, void *priv) | |||
2956 | printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj); | 2634 | printed += fprintf(fp, ", %lu majfaults", ttrace->pfmaj); |
2957 | if (ttrace->pfmin) | 2635 | if (ttrace->pfmin) |
2958 | printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin); | 2636 | printed += fprintf(fp, ", %lu minfaults", ttrace->pfmin); |
2959 | printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms); | 2637 | if (trace->sched) |
2638 | printed += fprintf(fp, ", %.3f msec\n", ttrace->runtime_ms); | ||
2639 | else if (fputc('\n', fp) != EOF) | ||
2640 | ++printed; | ||
2641 | |||
2960 | printed += thread__dump_stats(ttrace, trace, fp); | 2642 | printed += thread__dump_stats(ttrace, trace, fp); |
2961 | 2643 | ||
2962 | data->printed += printed; | 2644 | return printed; |
2645 | } | ||
2963 | 2646 | ||
2964 | return 0; | 2647 | static unsigned long thread__nr_events(struct thread_trace *ttrace) |
2648 | { | ||
2649 | return ttrace ? ttrace->nr_events : 0; | ||
2650 | } | ||
2651 | |||
2652 | DEFINE_RESORT_RB(threads, (thread__nr_events(a->thread->priv) < thread__nr_events(b->thread->priv)), | ||
2653 | struct thread *thread; | ||
2654 | ) | ||
2655 | { | ||
2656 | entry->thread = rb_entry(nd, struct thread, rb_node); | ||
2965 | } | 2657 | } |
2966 | 2658 | ||
2967 | static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp) | 2659 | static size_t trace__fprintf_thread_summary(struct trace *trace, FILE *fp) |
2968 | { | 2660 | { |
2969 | struct summary_data data = { | 2661 | DECLARE_RESORT_RB_MACHINE_THREADS(threads, trace->host); |
2970 | .fp = fp, | 2662 | size_t printed = trace__fprintf_threads_header(fp); |
2971 | .trace = trace | 2663 | struct rb_node *nd; |
2972 | }; | 2664 | |
2973 | data.printed = trace__fprintf_threads_header(fp); | 2665 | if (threads == NULL) { |
2666 | fprintf(fp, "%s", "Error sorting output by nr_events!\n"); | ||
2667 | return 0; | ||
2668 | } | ||
2974 | 2669 | ||
2975 | machine__for_each_thread(trace->host, trace__fprintf_one_thread, &data); | 2670 | resort_rb__for_each(nd, threads) |
2671 | printed += trace__fprintf_thread(fp, threads_entry->thread, trace); | ||
2976 | 2672 | ||
2977 | return data.printed; | 2673 | resort_rb__delete(threads); |
2674 | |||
2675 | return printed; | ||
2978 | } | 2676 | } |
2979 | 2677 | ||
2980 | static int trace__set_duration(const struct option *opt, const char *str, | 2678 | static int trace__set_duration(const struct option *opt, const char *str, |
@@ -3070,10 +2768,6 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | |||
3070 | NULL | 2768 | NULL |
3071 | }; | 2769 | }; |
3072 | struct trace trace = { | 2770 | struct trace trace = { |
3073 | .audit = { | ||
3074 | .machine = audit_detect_machine(), | ||
3075 | .open_id = audit_name_to_syscall("open", trace.audit.machine), | ||
3076 | }, | ||
3077 | .syscalls = { | 2771 | .syscalls = { |
3078 | . max = -1, | 2772 | . max = -1, |
3079 | }, | 2773 | }, |
@@ -3091,6 +2785,8 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | |||
3091 | .output = stderr, | 2785 | .output = stderr, |
3092 | .show_comm = true, | 2786 | .show_comm = true, |
3093 | .trace_syscalls = true, | 2787 | .trace_syscalls = true, |
2788 | .kernel_syscallchains = false, | ||
2789 | .max_stack = UINT_MAX, | ||
3094 | }; | 2790 | }; |
3095 | const char *output_name = NULL; | 2791 | const char *output_name = NULL; |
3096 | const char *ev_qualifier_str = NULL; | 2792 | const char *ev_qualifier_str = NULL; |
@@ -3136,10 +2832,24 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | |||
3136 | "Trace pagefaults", parse_pagefaults, "maj"), | 2832 | "Trace pagefaults", parse_pagefaults, "maj"), |
3137 | OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"), | 2833 | OPT_BOOLEAN(0, "syscalls", &trace.trace_syscalls, "Trace syscalls"), |
3138 | OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"), | 2834 | OPT_BOOLEAN('f', "force", &trace.force, "don't complain, do it"), |
2835 | OPT_CALLBACK(0, "call-graph", &trace.opts, | ||
2836 | "record_mode[,record_size]", record_callchain_help, | ||
2837 | &record_parse_callchain_opt), | ||
2838 | OPT_BOOLEAN(0, "kernel-syscall-graph", &trace.kernel_syscallchains, | ||
2839 | "Show the kernel callchains on the syscall exit path"), | ||
2840 | OPT_UINTEGER(0, "min-stack", &trace.min_stack, | ||
2841 | "Set the minimum stack depth when parsing the callchain, " | ||
2842 | "anything below the specified depth will be ignored."), | ||
2843 | OPT_UINTEGER(0, "max-stack", &trace.max_stack, | ||
2844 | "Set the maximum stack depth when parsing the callchain, " | ||
2845 | "anything beyond the specified depth will be ignored. " | ||
2846 | "Default: kernel.perf_event_max_stack or " __stringify(PERF_MAX_STACK_DEPTH)), | ||
3139 | OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout, | 2847 | OPT_UINTEGER(0, "proc-map-timeout", &trace.opts.proc_map_timeout, |
3140 | "per thread proc mmap processing timeout in ms"), | 2848 | "per thread proc mmap processing timeout in ms"), |
3141 | OPT_END() | 2849 | OPT_END() |
3142 | }; | 2850 | }; |
2851 | bool __maybe_unused max_stack_user_set = true; | ||
2852 | bool mmap_pages_user_set = true; | ||
3143 | const char * const trace_subcommands[] = { "record", NULL }; | 2853 | const char * const trace_subcommands[] = { "record", NULL }; |
3144 | int err; | 2854 | int err; |
3145 | char bf[BUFSIZ]; | 2855 | char bf[BUFSIZ]; |
@@ -3148,8 +2858,9 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | |||
3148 | signal(SIGFPE, sighandler_dump_stack); | 2858 | signal(SIGFPE, sighandler_dump_stack); |
3149 | 2859 | ||
3150 | trace.evlist = perf_evlist__new(); | 2860 | trace.evlist = perf_evlist__new(); |
2861 | trace.sctbl = syscalltbl__new(); | ||
3151 | 2862 | ||
3152 | if (trace.evlist == NULL) { | 2863 | if (trace.evlist == NULL || trace.sctbl == NULL) { |
3153 | pr_err("Not enough memory to run!\n"); | 2864 | pr_err("Not enough memory to run!\n"); |
3154 | err = -ENOMEM; | 2865 | err = -ENOMEM; |
3155 | goto out; | 2866 | goto out; |
@@ -3158,11 +2869,40 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | |||
3158 | argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands, | 2869 | argc = parse_options_subcommand(argc, argv, trace_options, trace_subcommands, |
3159 | trace_usage, PARSE_OPT_STOP_AT_NON_OPTION); | 2870 | trace_usage, PARSE_OPT_STOP_AT_NON_OPTION); |
3160 | 2871 | ||
2872 | err = bpf__setup_stdout(trace.evlist); | ||
2873 | if (err) { | ||
2874 | bpf__strerror_setup_stdout(trace.evlist, err, bf, sizeof(bf)); | ||
2875 | pr_err("ERROR: Setup BPF stdout failed: %s\n", bf); | ||
2876 | goto out; | ||
2877 | } | ||
2878 | |||
2879 | err = -1; | ||
2880 | |||
3161 | if (trace.trace_pgfaults) { | 2881 | if (trace.trace_pgfaults) { |
3162 | trace.opts.sample_address = true; | 2882 | trace.opts.sample_address = true; |
3163 | trace.opts.sample_time = true; | 2883 | trace.opts.sample_time = true; |
3164 | } | 2884 | } |
3165 | 2885 | ||
2886 | if (trace.opts.mmap_pages == UINT_MAX) | ||
2887 | mmap_pages_user_set = false; | ||
2888 | |||
2889 | if (trace.max_stack == UINT_MAX) { | ||
2890 | trace.max_stack = sysctl_perf_event_max_stack; | ||
2891 | max_stack_user_set = false; | ||
2892 | } | ||
2893 | |||
2894 | #ifdef HAVE_DWARF_UNWIND_SUPPORT | ||
2895 | if ((trace.min_stack || max_stack_user_set) && !callchain_param.enabled) | ||
2896 | record_opts__parse_callchain(&trace.opts, &callchain_param, "dwarf", false); | ||
2897 | #endif | ||
2898 | |||
2899 | if (callchain_param.enabled) { | ||
2900 | if (!mmap_pages_user_set && geteuid() == 0) | ||
2901 | trace.opts.mmap_pages = perf_event_mlock_kb_in_pages() * 4; | ||
2902 | |||
2903 | symbol_conf.use_callchain = true; | ||
2904 | } | ||
2905 | |||
3166 | if (trace.evlist->nr_entries > 0) | 2906 | if (trace.evlist->nr_entries > 0) |
3167 | evlist__set_evsel_handler(trace.evlist, trace__event_handler); | 2907 | evlist__set_evsel_handler(trace.evlist, trace__event_handler); |
3168 | 2908 | ||
@@ -3179,6 +2919,11 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | |||
3179 | return -1; | 2919 | return -1; |
3180 | } | 2920 | } |
3181 | 2921 | ||
2922 | if (!trace.trace_syscalls && ev_qualifier_str) { | ||
2923 | pr_err("The -e option can't be used with --no-syscalls.\n"); | ||
2924 | goto out; | ||
2925 | } | ||
2926 | |||
3182 | if (output_name != NULL) { | 2927 | if (output_name != NULL) { |
3183 | err = trace__open_output(&trace, output_name); | 2928 | err = trace__open_output(&trace, output_name); |
3184 | if (err < 0) { | 2929 | if (err < 0) { |
@@ -3187,6 +2932,8 @@ int cmd_trace(int argc, const char **argv, const char *prefix __maybe_unused) | |||
3187 | } | 2932 | } |
3188 | } | 2933 | } |
3189 | 2934 | ||
2935 | trace.open_id = syscalltbl__id(trace.sctbl, "open"); | ||
2936 | |||
3190 | if (ev_qualifier_str != NULL) { | 2937 | if (ev_qualifier_str != NULL) { |
3191 | const char *s = ev_qualifier_str; | 2938 | const char *s = ev_qualifier_str; |
3192 | struct strlist_config slist_config = { | 2939 | struct strlist_config slist_config = { |
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile index f7d7f5a1cad5..1e46277286c2 100644 --- a/tools/perf/config/Makefile +++ b/tools/perf/config/Makefile | |||
@@ -27,7 +27,7 @@ NO_PERF_REGS := 1 | |||
27 | ifeq ($(ARCH),x86) | 27 | ifeq ($(ARCH),x86) |
28 | $(call detected,CONFIG_X86) | 28 | $(call detected,CONFIG_X86) |
29 | ifeq (${IS_64_BIT}, 1) | 29 | ifeq (${IS_64_BIT}, 1) |
30 | CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT | 30 | CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT -DHAVE_SYSCALL_TABLE -I$(OUTPUT)arch/x86/include/generated |
31 | ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S | 31 | ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S |
32 | LIBUNWIND_LIBS = -lunwind -lunwind-x86_64 | 32 | LIBUNWIND_LIBS = -lunwind -lunwind-x86_64 |
33 | $(call detected,CONFIG_X86_64) | 33 | $(call detected,CONFIG_X86_64) |
@@ -268,6 +268,12 @@ else | |||
268 | ifneq ($(feature-dwarf), 1) | 268 | ifneq ($(feature-dwarf), 1) |
269 | msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev); | 269 | msg := $(warning No libdw.h found or old libdw.h found or elfutils is older than 0.138, disables dwarf support. Please install new elfutils-devel/libdw-dev); |
270 | NO_DWARF := 1 | 270 | NO_DWARF := 1 |
271 | else | ||
272 | ifneq ($(feature-dwarf_getlocations), 1) | ||
273 | msg := $(warning Old libdw.h, finding variables at given 'perf probe' point will not work, install elfutils-devel/libdw-dev >= 0.157); | ||
274 | else | ||
275 | CFLAGS += -DHAVE_DWARF_GETLOCATIONS | ||
276 | endif # dwarf_getlocations | ||
271 | endif # Dwarf support | 277 | endif # Dwarf support |
272 | endif # libelf support | 278 | endif # libelf support |
273 | endif # NO_LIBELF | 279 | endif # NO_LIBELF |
@@ -289,9 +295,6 @@ ifndef NO_LIBELF | |||
289 | CFLAGS += -DHAVE_ELF_GETPHDRNUM_SUPPORT | 295 | CFLAGS += -DHAVE_ELF_GETPHDRNUM_SUPPORT |
290 | endif | 296 | endif |
291 | 297 | ||
292 | # include ARCH specific config | ||
293 | -include $(src-perf)/arch/$(ARCH)/Makefile | ||
294 | |||
295 | ifndef NO_DWARF | 298 | ifndef NO_DWARF |
296 | ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) | 299 | ifeq ($(origin PERF_HAVE_DWARF_REGS), undefined) |
297 | msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); | 300 | msg := $(warning DWARF register mappings have not been defined for architecture $(ARCH), DWARF support disabled); |
diff --git a/tools/perf/jvmti/jvmti_agent.c b/tools/perf/jvmti/jvmti_agent.c index 6461e02ab940..3573f315f955 100644 --- a/tools/perf/jvmti/jvmti_agent.c +++ b/tools/perf/jvmti/jvmti_agent.c | |||
@@ -92,6 +92,22 @@ error: | |||
92 | return ret; | 92 | return ret; |
93 | } | 93 | } |
94 | 94 | ||
95 | static int use_arch_timestamp; | ||
96 | |||
97 | static inline uint64_t | ||
98 | get_arch_timestamp(void) | ||
99 | { | ||
100 | #if defined(__i386__) || defined(__x86_64__) | ||
101 | unsigned int low, high; | ||
102 | |||
103 | asm volatile("rdtsc" : "=a" (low), "=d" (high)); | ||
104 | |||
105 | return low | ((uint64_t)high) << 32; | ||
106 | #else | ||
107 | return 0; | ||
108 | #endif | ||
109 | } | ||
110 | |||
95 | #define NSEC_PER_SEC 1000000000 | 111 | #define NSEC_PER_SEC 1000000000 |
96 | static int perf_clk_id = CLOCK_MONOTONIC; | 112 | static int perf_clk_id = CLOCK_MONOTONIC; |
97 | 113 | ||
@@ -107,6 +123,9 @@ perf_get_timestamp(void) | |||
107 | struct timespec ts; | 123 | struct timespec ts; |
108 | int ret; | 124 | int ret; |
109 | 125 | ||
126 | if (use_arch_timestamp) | ||
127 | return get_arch_timestamp(); | ||
128 | |||
110 | ret = clock_gettime(perf_clk_id, &ts); | 129 | ret = clock_gettime(perf_clk_id, &ts); |
111 | if (ret) | 130 | if (ret) |
112 | return 0; | 131 | return 0; |
@@ -203,6 +222,17 @@ perf_close_marker_file(void) | |||
203 | munmap(marker_addr, pgsz); | 222 | munmap(marker_addr, pgsz); |
204 | } | 223 | } |
205 | 224 | ||
225 | static void | ||
226 | init_arch_timestamp(void) | ||
227 | { | ||
228 | char *str = getenv("JITDUMP_USE_ARCH_TIMESTAMP"); | ||
229 | |||
230 | if (!str || !*str || !strcmp(str, "0")) | ||
231 | return; | ||
232 | |||
233 | use_arch_timestamp = 1; | ||
234 | } | ||
235 | |||
206 | void *jvmti_open(void) | 236 | void *jvmti_open(void) |
207 | { | 237 | { |
208 | int pad_cnt; | 238 | int pad_cnt; |
@@ -211,11 +241,17 @@ void *jvmti_open(void) | |||
211 | int fd; | 241 | int fd; |
212 | FILE *fp; | 242 | FILE *fp; |
213 | 243 | ||
244 | init_arch_timestamp(); | ||
245 | |||
214 | /* | 246 | /* |
215 | * check if clockid is supported | 247 | * check if clockid is supported |
216 | */ | 248 | */ |
217 | if (!perf_get_timestamp()) | 249 | if (!perf_get_timestamp()) { |
218 | warnx("jvmti: kernel does not support %d clock id", perf_clk_id); | 250 | if (use_arch_timestamp) |
251 | warnx("jvmti: arch timestamp not supported"); | ||
252 | else | ||
253 | warnx("jvmti: kernel does not support %d clock id", perf_clk_id); | ||
254 | } | ||
219 | 255 | ||
220 | memset(&header, 0, sizeof(header)); | 256 | memset(&header, 0, sizeof(header)); |
221 | 257 | ||
@@ -263,6 +299,9 @@ void *jvmti_open(void) | |||
263 | 299 | ||
264 | header.timestamp = perf_get_timestamp(); | 300 | header.timestamp = perf_get_timestamp(); |
265 | 301 | ||
302 | if (use_arch_timestamp) | ||
303 | header.flags |= JITDUMP_FLAGS_ARCH_TIMESTAMP; | ||
304 | |||
266 | if (!fwrite(&header, sizeof(header), 1, fp)) { | 305 | if (!fwrite(&header, sizeof(header), 1, fp)) { |
267 | warn("jvmti: cannot write dumpfile header"); | 306 | warn("jvmti: cannot write dumpfile header"); |
268 | goto error; | 307 | goto error; |
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index aaee0a782747..797000842d40 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <subcmd/parse-options.h> | 17 | #include <subcmd/parse-options.h> |
18 | #include "util/bpf-loader.h" | 18 | #include "util/bpf-loader.h" |
19 | #include "util/debug.h" | 19 | #include "util/debug.h" |
20 | #include <api/fs/fs.h> | ||
20 | #include <api/fs/tracing_path.h> | 21 | #include <api/fs/tracing_path.h> |
21 | #include <pthread.h> | 22 | #include <pthread.h> |
22 | #include <stdlib.h> | 23 | #include <stdlib.h> |
@@ -308,9 +309,11 @@ static int handle_alias(int *argcp, const char ***argv) | |||
308 | if (*argcp > 1) { | 309 | if (*argcp > 1) { |
309 | struct strbuf buf; | 310 | struct strbuf buf; |
310 | 311 | ||
311 | strbuf_init(&buf, PATH_MAX); | 312 | if (strbuf_init(&buf, PATH_MAX) < 0 || |
312 | strbuf_addstr(&buf, alias_string); | 313 | strbuf_addstr(&buf, alias_string) < 0 || |
313 | sq_quote_argv(&buf, (*argv) + 1, PATH_MAX); | 314 | sq_quote_argv(&buf, (*argv) + 1, |
315 | PATH_MAX) < 0) | ||
316 | die("Failed to allocate memory."); | ||
314 | free(alias_string); | 317 | free(alias_string); |
315 | alias_string = buf.buf; | 318 | alias_string = buf.buf; |
316 | } | 319 | } |
@@ -533,6 +536,7 @@ int main(int argc, const char **argv) | |||
533 | { | 536 | { |
534 | const char *cmd; | 537 | const char *cmd; |
535 | char sbuf[STRERR_BUFSIZE]; | 538 | char sbuf[STRERR_BUFSIZE]; |
539 | int value; | ||
536 | 540 | ||
537 | /* libsubcmd init */ | 541 | /* libsubcmd init */ |
538 | exec_cmd_init("perf", PREFIX, PERF_EXEC_PATH, EXEC_PATH_ENVIRONMENT); | 542 | exec_cmd_init("perf", PREFIX, PERF_EXEC_PATH, EXEC_PATH_ENVIRONMENT); |
@@ -542,6 +546,9 @@ int main(int argc, const char **argv) | |||
542 | page_size = sysconf(_SC_PAGE_SIZE); | 546 | page_size = sysconf(_SC_PAGE_SIZE); |
543 | cacheline_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE); | 547 | cacheline_size = sysconf(_SC_LEVEL1_DCACHE_LINESIZE); |
544 | 548 | ||
549 | if (sysctl__read_int("kernel/perf_event_max_stack", &value) == 0) | ||
550 | sysctl_perf_event_max_stack = value; | ||
551 | |||
545 | cmd = extract_argv0_path(argv[0]); | 552 | cmd = extract_argv0_path(argv[0]); |
546 | if (!cmd) | 553 | if (!cmd) |
547 | cmd = "perf-help"; | 554 | cmd = "perf-help"; |
@@ -549,6 +556,7 @@ int main(int argc, const char **argv) | |||
549 | srandom(time(NULL)); | 556 | srandom(time(NULL)); |
550 | 557 | ||
551 | perf_config(perf_default_config, NULL); | 558 | perf_config(perf_default_config, NULL); |
559 | set_buildid_dir(NULL); | ||
552 | 560 | ||
553 | /* get debugfs/tracefs mount point from /proc/mounts */ | 561 | /* get debugfs/tracefs mount point from /proc/mounts */ |
554 | tracing_path_mount(); | 562 | tracing_path_mount(); |
@@ -572,7 +580,6 @@ int main(int argc, const char **argv) | |||
572 | } | 580 | } |
573 | if (!prefixcmp(cmd, "trace")) { | 581 | if (!prefixcmp(cmd, "trace")) { |
574 | #ifdef HAVE_LIBAUDIT_SUPPORT | 582 | #ifdef HAVE_LIBAUDIT_SUPPORT |
575 | set_buildid_dir(NULL); | ||
576 | setup_path(); | 583 | setup_path(); |
577 | argv[0] = "trace"; | 584 | argv[0] = "trace"; |
578 | return cmd_trace(argc, argv, NULL); | 585 | return cmd_trace(argc, argv, NULL); |
@@ -587,7 +594,6 @@ int main(int argc, const char **argv) | |||
587 | argc--; | 594 | argc--; |
588 | handle_options(&argv, &argc, NULL); | 595 | handle_options(&argv, &argc, NULL); |
589 | commit_pager_choice(); | 596 | commit_pager_choice(); |
590 | set_buildid_dir(NULL); | ||
591 | 597 | ||
592 | if (argc > 0) { | 598 | if (argc > 0) { |
593 | if (!prefixcmp(argv[0], "--")) | 599 | if (!prefixcmp(argv[0], "--")) |
diff --git a/tools/perf/perf.h b/tools/perf/perf.h index 5381a01c0610..cd8f1b150f9e 100644 --- a/tools/perf/perf.h +++ b/tools/perf/perf.h | |||
@@ -52,7 +52,6 @@ struct record_opts { | |||
52 | bool sample_weight; | 52 | bool sample_weight; |
53 | bool sample_time; | 53 | bool sample_time; |
54 | bool sample_time_set; | 54 | bool sample_time_set; |
55 | bool callgraph_set; | ||
56 | bool period; | 55 | bool period; |
57 | bool running_time; | 56 | bool running_time; |
58 | bool full_auxtrace; | 57 | bool full_auxtrace; |
diff --git a/tools/perf/scripts/python/export-to-postgresql.py b/tools/perf/scripts/python/export-to-postgresql.py index 1b02cdc0cab6..7656ff8aa066 100644 --- a/tools/perf/scripts/python/export-to-postgresql.py +++ b/tools/perf/scripts/python/export-to-postgresql.py | |||
@@ -34,10 +34,9 @@ import datetime | |||
34 | # | 34 | # |
35 | # ubuntu: | 35 | # ubuntu: |
36 | # | 36 | # |
37 | # $ sudo apt-get install postgresql | 37 | # $ sudo apt-get install postgresql python-pyside.qtsql libqt4-sql-psql |
38 | # $ sudo su - postgres | 38 | # $ sudo su - postgres |
39 | # $ createuser <your user id here> | 39 | # $ createuser -s <your user id here> |
40 | # Shall the new role be a superuser? (y/n) y | ||
41 | # | 40 | # |
42 | # An example of using this script with Intel PT: | 41 | # An example of using this script with Intel PT: |
43 | # | 42 | # |
@@ -224,11 +223,14 @@ sys.path.append(os.environ['PERF_EXEC_PATH'] + \ | |||
224 | 223 | ||
225 | perf_db_export_mode = True | 224 | perf_db_export_mode = True |
226 | perf_db_export_calls = False | 225 | perf_db_export_calls = False |
226 | perf_db_export_callchains = False | ||
227 | |||
227 | 228 | ||
228 | def usage(): | 229 | def usage(): |
229 | print >> sys.stderr, "Usage is: export-to-postgresql.py <database name> [<columns>] [<calls>]" | 230 | print >> sys.stderr, "Usage is: export-to-postgresql.py <database name> [<columns>] [<calls>] [<callchains>]" |
230 | print >> sys.stderr, "where: columns 'all' or 'branches'" | 231 | print >> sys.stderr, "where: columns 'all' or 'branches'" |
231 | print >> sys.stderr, " calls 'calls' => create calls table" | 232 | print >> sys.stderr, " calls 'calls' => create calls and call_paths table" |
233 | print >> sys.stderr, " callchains 'callchains' => create call_paths table" | ||
232 | raise Exception("Too few arguments") | 234 | raise Exception("Too few arguments") |
233 | 235 | ||
234 | if (len(sys.argv) < 2): | 236 | if (len(sys.argv) < 2): |
@@ -246,9 +248,11 @@ if columns not in ("all", "branches"): | |||
246 | 248 | ||
247 | branches = (columns == "branches") | 249 | branches = (columns == "branches") |
248 | 250 | ||
249 | if (len(sys.argv) >= 4): | 251 | for i in range(3,len(sys.argv)): |
250 | if (sys.argv[3] == "calls"): | 252 | if (sys.argv[i] == "calls"): |
251 | perf_db_export_calls = True | 253 | perf_db_export_calls = True |
254 | elif (sys.argv[i] == "callchains"): | ||
255 | perf_db_export_callchains = True | ||
252 | else: | 256 | else: |
253 | usage() | 257 | usage() |
254 | 258 | ||
@@ -359,14 +363,16 @@ else: | |||
359 | 'transaction bigint,' | 363 | 'transaction bigint,' |
360 | 'data_src bigint,' | 364 | 'data_src bigint,' |
361 | 'branch_type integer,' | 365 | 'branch_type integer,' |
362 | 'in_tx boolean)') | 366 | 'in_tx boolean,' |
367 | 'call_path_id bigint)') | ||
363 | 368 | ||
364 | if perf_db_export_calls: | 369 | if perf_db_export_calls or perf_db_export_callchains: |
365 | do_query(query, 'CREATE TABLE call_paths (' | 370 | do_query(query, 'CREATE TABLE call_paths (' |
366 | 'id bigint NOT NULL,' | 371 | 'id bigint NOT NULL,' |
367 | 'parent_id bigint,' | 372 | 'parent_id bigint,' |
368 | 'symbol_id bigint,' | 373 | 'symbol_id bigint,' |
369 | 'ip bigint)') | 374 | 'ip bigint)') |
375 | if perf_db_export_calls: | ||
370 | do_query(query, 'CREATE TABLE calls (' | 376 | do_query(query, 'CREATE TABLE calls (' |
371 | 'id bigint NOT NULL,' | 377 | 'id bigint NOT NULL,' |
372 | 'thread_id bigint,' | 378 | 'thread_id bigint,' |
@@ -428,7 +434,7 @@ do_query(query, 'CREATE VIEW comm_threads_view AS ' | |||
428 | '(SELECT tid FROM threads WHERE id = thread_id) AS tid' | 434 | '(SELECT tid FROM threads WHERE id = thread_id) AS tid' |
429 | ' FROM comm_threads') | 435 | ' FROM comm_threads') |
430 | 436 | ||
431 | if perf_db_export_calls: | 437 | if perf_db_export_calls or perf_db_export_callchains: |
432 | do_query(query, 'CREATE VIEW call_paths_view AS ' | 438 | do_query(query, 'CREATE VIEW call_paths_view AS ' |
433 | 'SELECT ' | 439 | 'SELECT ' |
434 | 'c.id,' | 440 | 'c.id,' |
@@ -444,6 +450,7 @@ if perf_db_export_calls: | |||
444 | '(SELECT dso_id FROM symbols WHERE id = p.symbol_id) AS parent_dso_id,' | 450 | '(SELECT dso_id FROM symbols WHERE id = p.symbol_id) AS parent_dso_id,' |
445 | '(SELECT dso FROM symbols_view WHERE id = p.symbol_id) AS parent_dso_short_name' | 451 | '(SELECT dso FROM symbols_view WHERE id = p.symbol_id) AS parent_dso_short_name' |
446 | ' FROM call_paths c INNER JOIN call_paths p ON p.id = c.parent_id') | 452 | ' FROM call_paths c INNER JOIN call_paths p ON p.id = c.parent_id') |
453 | if perf_db_export_calls: | ||
447 | do_query(query, 'CREATE VIEW calls_view AS ' | 454 | do_query(query, 'CREATE VIEW calls_view AS ' |
448 | 'SELECT ' | 455 | 'SELECT ' |
449 | 'calls.id,' | 456 | 'calls.id,' |
@@ -541,8 +548,9 @@ dso_file = open_output_file("dso_table.bin") | |||
541 | symbol_file = open_output_file("symbol_table.bin") | 548 | symbol_file = open_output_file("symbol_table.bin") |
542 | branch_type_file = open_output_file("branch_type_table.bin") | 549 | branch_type_file = open_output_file("branch_type_table.bin") |
543 | sample_file = open_output_file("sample_table.bin") | 550 | sample_file = open_output_file("sample_table.bin") |
544 | if perf_db_export_calls: | 551 | if perf_db_export_calls or perf_db_export_callchains: |
545 | call_path_file = open_output_file("call_path_table.bin") | 552 | call_path_file = open_output_file("call_path_table.bin") |
553 | if perf_db_export_calls: | ||
546 | call_file = open_output_file("call_table.bin") | 554 | call_file = open_output_file("call_table.bin") |
547 | 555 | ||
548 | def trace_begin(): | 556 | def trace_begin(): |
@@ -554,8 +562,8 @@ def trace_begin(): | |||
554 | comm_table(0, "unknown") | 562 | comm_table(0, "unknown") |
555 | dso_table(0, 0, "unknown", "unknown", "") | 563 | dso_table(0, 0, "unknown", "unknown", "") |
556 | symbol_table(0, 0, 0, 0, 0, "unknown") | 564 | symbol_table(0, 0, 0, 0, 0, "unknown") |
557 | sample_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) | 565 | sample_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) |
558 | if perf_db_export_calls: | 566 | if perf_db_export_calls or perf_db_export_callchains: |
559 | call_path_table(0, 0, 0, 0) | 567 | call_path_table(0, 0, 0, 0) |
560 | 568 | ||
561 | unhandled_count = 0 | 569 | unhandled_count = 0 |
@@ -571,8 +579,9 @@ def trace_end(): | |||
571 | copy_output_file(symbol_file, "symbols") | 579 | copy_output_file(symbol_file, "symbols") |
572 | copy_output_file(branch_type_file, "branch_types") | 580 | copy_output_file(branch_type_file, "branch_types") |
573 | copy_output_file(sample_file, "samples") | 581 | copy_output_file(sample_file, "samples") |
574 | if perf_db_export_calls: | 582 | if perf_db_export_calls or perf_db_export_callchains: |
575 | copy_output_file(call_path_file, "call_paths") | 583 | copy_output_file(call_path_file, "call_paths") |
584 | if perf_db_export_calls: | ||
576 | copy_output_file(call_file, "calls") | 585 | copy_output_file(call_file, "calls") |
577 | 586 | ||
578 | print datetime.datetime.today(), "Removing intermediate files..." | 587 | print datetime.datetime.today(), "Removing intermediate files..." |
@@ -585,8 +594,9 @@ def trace_end(): | |||
585 | remove_output_file(symbol_file) | 594 | remove_output_file(symbol_file) |
586 | remove_output_file(branch_type_file) | 595 | remove_output_file(branch_type_file) |
587 | remove_output_file(sample_file) | 596 | remove_output_file(sample_file) |
588 | if perf_db_export_calls: | 597 | if perf_db_export_calls or perf_db_export_callchains: |
589 | remove_output_file(call_path_file) | 598 | remove_output_file(call_path_file) |
599 | if perf_db_export_calls: | ||
590 | remove_output_file(call_file) | 600 | remove_output_file(call_file) |
591 | os.rmdir(output_dir_name) | 601 | os.rmdir(output_dir_name) |
592 | print datetime.datetime.today(), "Adding primary keys" | 602 | print datetime.datetime.today(), "Adding primary keys" |
@@ -599,8 +609,9 @@ def trace_end(): | |||
599 | do_query(query, 'ALTER TABLE symbols ADD PRIMARY KEY (id)') | 609 | do_query(query, 'ALTER TABLE symbols ADD PRIMARY KEY (id)') |
600 | do_query(query, 'ALTER TABLE branch_types ADD PRIMARY KEY (id)') | 610 | do_query(query, 'ALTER TABLE branch_types ADD PRIMARY KEY (id)') |
601 | do_query(query, 'ALTER TABLE samples ADD PRIMARY KEY (id)') | 611 | do_query(query, 'ALTER TABLE samples ADD PRIMARY KEY (id)') |
602 | if perf_db_export_calls: | 612 | if perf_db_export_calls or perf_db_export_callchains: |
603 | do_query(query, 'ALTER TABLE call_paths ADD PRIMARY KEY (id)') | 613 | do_query(query, 'ALTER TABLE call_paths ADD PRIMARY KEY (id)') |
614 | if perf_db_export_calls: | ||
604 | do_query(query, 'ALTER TABLE calls ADD PRIMARY KEY (id)') | 615 | do_query(query, 'ALTER TABLE calls ADD PRIMARY KEY (id)') |
605 | 616 | ||
606 | print datetime.datetime.today(), "Adding foreign keys" | 617 | print datetime.datetime.today(), "Adding foreign keys" |
@@ -623,10 +634,11 @@ def trace_end(): | |||
623 | 'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id),' | 634 | 'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id),' |
624 | 'ADD CONSTRAINT todsofk FOREIGN KEY (to_dso_id) REFERENCES dsos (id),' | 635 | 'ADD CONSTRAINT todsofk FOREIGN KEY (to_dso_id) REFERENCES dsos (id),' |
625 | 'ADD CONSTRAINT tosymbolfk FOREIGN KEY (to_symbol_id) REFERENCES symbols (id)') | 636 | 'ADD CONSTRAINT tosymbolfk FOREIGN KEY (to_symbol_id) REFERENCES symbols (id)') |
626 | if perf_db_export_calls: | 637 | if perf_db_export_calls or perf_db_export_callchains: |
627 | do_query(query, 'ALTER TABLE call_paths ' | 638 | do_query(query, 'ALTER TABLE call_paths ' |
628 | 'ADD CONSTRAINT parentfk FOREIGN KEY (parent_id) REFERENCES call_paths (id),' | 639 | 'ADD CONSTRAINT parentfk FOREIGN KEY (parent_id) REFERENCES call_paths (id),' |
629 | 'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id)') | 640 | 'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id)') |
641 | if perf_db_export_calls: | ||
630 | do_query(query, 'ALTER TABLE calls ' | 642 | do_query(query, 'ALTER TABLE calls ' |
631 | 'ADD CONSTRAINT threadfk FOREIGN KEY (thread_id) REFERENCES threads (id),' | 643 | 'ADD CONSTRAINT threadfk FOREIGN KEY (thread_id) REFERENCES threads (id),' |
632 | 'ADD CONSTRAINT commfk FOREIGN KEY (comm_id) REFERENCES comms (id),' | 644 | 'ADD CONSTRAINT commfk FOREIGN KEY (comm_id) REFERENCES comms (id),' |
@@ -694,11 +706,11 @@ def branch_type_table(branch_type, name, *x): | |||
694 | value = struct.pack(fmt, 2, 4, branch_type, n, name) | 706 | value = struct.pack(fmt, 2, 4, branch_type, n, name) |
695 | branch_type_file.write(value) | 707 | branch_type_file.write(value) |
696 | 708 | ||
697 | def sample_table(sample_id, evsel_id, machine_id, thread_id, comm_id, dso_id, symbol_id, sym_offset, ip, time, cpu, to_dso_id, to_symbol_id, to_sym_offset, to_ip, period, weight, transaction, data_src, branch_type, in_tx, *x): | 709 | def sample_table(sample_id, evsel_id, machine_id, thread_id, comm_id, dso_id, symbol_id, sym_offset, ip, time, cpu, to_dso_id, to_symbol_id, to_sym_offset, to_ip, period, weight, transaction, data_src, branch_type, in_tx, call_path_id, *x): |
698 | if branches: | 710 | if branches: |
699 | value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiiiB", 17, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 4, branch_type, 1, in_tx) | 711 | value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiiiBiq", 18, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 4, branch_type, 1, in_tx, 8, call_path_id) |
700 | else: | 712 | else: |
701 | value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiqiqiqiqiiiB", 21, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 8, period, 8, weight, 8, transaction, 8, data_src, 4, branch_type, 1, in_tx) | 713 | value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiqiqiqiqiiiBiq", 22, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 8, period, 8, weight, 8, transaction, 8, data_src, 4, branch_type, 1, in_tx, 8, call_path_id) |
702 | sample_file.write(value) | 714 | sample_file.write(value) |
703 | 715 | ||
704 | def call_path_table(cp_id, parent_id, symbol_id, ip, *x): | 716 | def call_path_table(cp_id, parent_id, symbol_id, ip, *x): |
diff --git a/tools/perf/tests/Build b/tools/perf/tests/Build index 1ba628ed049a..66a28982547b 100644 --- a/tools/perf/tests/Build +++ b/tools/perf/tests/Build | |||
@@ -37,6 +37,8 @@ perf-y += topology.o | |||
37 | perf-y += cpumap.o | 37 | perf-y += cpumap.o |
38 | perf-y += stat.o | 38 | perf-y += stat.o |
39 | perf-y += event_update.o | 39 | perf-y += event_update.o |
40 | perf-y += event-times.o | ||
41 | perf-y += backward-ring-buffer.o | ||
40 | 42 | ||
41 | $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build | 43 | $(OUTPUT)tests/llvm-src-base.c: tests/bpf-script-example.c tests/Build |
42 | $(call rule_mkdir) | 44 | $(call rule_mkdir) |
diff --git a/tools/perf/tests/backward-ring-buffer.c b/tools/perf/tests/backward-ring-buffer.c new file mode 100644 index 000000000000..d9ba991a9a30 --- /dev/null +++ b/tools/perf/tests/backward-ring-buffer.c | |||
@@ -0,0 +1,151 @@ | |||
1 | /* | ||
2 | * Test backward bit in event attribute, read ring buffer from end to | ||
3 | * beginning | ||
4 | */ | ||
5 | |||
6 | #include <perf.h> | ||
7 | #include <evlist.h> | ||
8 | #include <sys/prctl.h> | ||
9 | #include "tests.h" | ||
10 | #include "debug.h" | ||
11 | |||
12 | #define NR_ITERS 111 | ||
13 | |||
14 | static void testcase(void) | ||
15 | { | ||
16 | int i; | ||
17 | |||
18 | for (i = 0; i < NR_ITERS; i++) { | ||
19 | char proc_name[10]; | ||
20 | |||
21 | snprintf(proc_name, sizeof(proc_name), "p:%d\n", i); | ||
22 | prctl(PR_SET_NAME, proc_name); | ||
23 | } | ||
24 | } | ||
25 | |||
26 | static int count_samples(struct perf_evlist *evlist, int *sample_count, | ||
27 | int *comm_count) | ||
28 | { | ||
29 | int i; | ||
30 | |||
31 | for (i = 0; i < evlist->nr_mmaps; i++) { | ||
32 | union perf_event *event; | ||
33 | |||
34 | perf_evlist__mmap_read_catchup(evlist, i); | ||
35 | while ((event = perf_evlist__mmap_read_backward(evlist, i)) != NULL) { | ||
36 | const u32 type = event->header.type; | ||
37 | |||
38 | switch (type) { | ||
39 | case PERF_RECORD_SAMPLE: | ||
40 | (*sample_count)++; | ||
41 | break; | ||
42 | case PERF_RECORD_COMM: | ||
43 | (*comm_count)++; | ||
44 | break; | ||
45 | default: | ||
46 | pr_err("Unexpected record of type %d\n", type); | ||
47 | return TEST_FAIL; | ||
48 | } | ||
49 | } | ||
50 | } | ||
51 | return TEST_OK; | ||
52 | } | ||
53 | |||
54 | static int do_test(struct perf_evlist *evlist, int mmap_pages, | ||
55 | int *sample_count, int *comm_count) | ||
56 | { | ||
57 | int err; | ||
58 | char sbuf[STRERR_BUFSIZE]; | ||
59 | |||
60 | err = perf_evlist__mmap(evlist, mmap_pages, true); | ||
61 | if (err < 0) { | ||
62 | pr_debug("perf_evlist__mmap: %s\n", | ||
63 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
64 | return TEST_FAIL; | ||
65 | } | ||
66 | |||
67 | perf_evlist__enable(evlist); | ||
68 | testcase(); | ||
69 | perf_evlist__disable(evlist); | ||
70 | |||
71 | err = count_samples(evlist, sample_count, comm_count); | ||
72 | perf_evlist__munmap(evlist); | ||
73 | return err; | ||
74 | } | ||
75 | |||
76 | |||
77 | int test__backward_ring_buffer(int subtest __maybe_unused) | ||
78 | { | ||
79 | int ret = TEST_SKIP, err, sample_count = 0, comm_count = 0; | ||
80 | char pid[16], sbuf[STRERR_BUFSIZE]; | ||
81 | struct perf_evlist *evlist; | ||
82 | struct perf_evsel *evsel __maybe_unused; | ||
83 | struct parse_events_error parse_error; | ||
84 | struct record_opts opts = { | ||
85 | .target = { | ||
86 | .uid = UINT_MAX, | ||
87 | .uses_mmap = true, | ||
88 | }, | ||
89 | .freq = 0, | ||
90 | .mmap_pages = 256, | ||
91 | .default_interval = 1, | ||
92 | }; | ||
93 | |||
94 | snprintf(pid, sizeof(pid), "%d", getpid()); | ||
95 | pid[sizeof(pid) - 1] = '\0'; | ||
96 | opts.target.tid = opts.target.pid = pid; | ||
97 | |||
98 | evlist = perf_evlist__new(); | ||
99 | if (!evlist) { | ||
100 | pr_debug("No ehough memory to create evlist\n"); | ||
101 | return TEST_FAIL; | ||
102 | } | ||
103 | |||
104 | err = perf_evlist__create_maps(evlist, &opts.target); | ||
105 | if (err < 0) { | ||
106 | pr_debug("Not enough memory to create thread/cpu maps\n"); | ||
107 | goto out_delete_evlist; | ||
108 | } | ||
109 | |||
110 | bzero(&parse_error, sizeof(parse_error)); | ||
111 | err = parse_events(evlist, "syscalls:sys_enter_prctl", &parse_error); | ||
112 | if (err) { | ||
113 | pr_debug("Failed to parse tracepoint event, try use root\n"); | ||
114 | ret = TEST_SKIP; | ||
115 | goto out_delete_evlist; | ||
116 | } | ||
117 | |||
118 | perf_evlist__config(evlist, &opts, NULL); | ||
119 | |||
120 | /* Set backward bit, ring buffer should be writing from end */ | ||
121 | evlist__for_each(evlist, evsel) | ||
122 | evsel->attr.write_backward = 1; | ||
123 | |||
124 | err = perf_evlist__open(evlist); | ||
125 | if (err < 0) { | ||
126 | pr_debug("perf_evlist__open: %s\n", | ||
127 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
128 | goto out_delete_evlist; | ||
129 | } | ||
130 | |||
131 | ret = TEST_FAIL; | ||
132 | err = do_test(evlist, opts.mmap_pages, &sample_count, | ||
133 | &comm_count); | ||
134 | if (err != TEST_OK) | ||
135 | goto out_delete_evlist; | ||
136 | |||
137 | if ((sample_count != NR_ITERS) || (comm_count != NR_ITERS)) { | ||
138 | pr_err("Unexpected counter: sample_count=%d, comm_count=%d\n", | ||
139 | sample_count, comm_count); | ||
140 | goto out_delete_evlist; | ||
141 | } | ||
142 | |||
143 | err = do_test(evlist, 1, &sample_count, &comm_count); | ||
144 | if (err != TEST_OK) | ||
145 | goto out_delete_evlist; | ||
146 | |||
147 | ret = TEST_OK; | ||
148 | out_delete_evlist: | ||
149 | perf_evlist__delete(evlist); | ||
150 | return ret; | ||
151 | } | ||
diff --git a/tools/perf/tests/bpf.c b/tools/perf/tests/bpf.c index 199501c71e27..f31eed31c1a9 100644 --- a/tools/perf/tests/bpf.c +++ b/tools/perf/tests/bpf.c | |||
@@ -138,7 +138,7 @@ static int do_test(struct bpf_object *obj, int (*func)(void), | |||
138 | perf_evlist__splice_list_tail(evlist, &parse_evlist.list); | 138 | perf_evlist__splice_list_tail(evlist, &parse_evlist.list); |
139 | evlist->nr_groups = parse_evlist.nr_groups; | 139 | evlist->nr_groups = parse_evlist.nr_groups; |
140 | 140 | ||
141 | perf_evlist__config(evlist, &opts); | 141 | perf_evlist__config(evlist, &opts, NULL); |
142 | 142 | ||
143 | err = perf_evlist__open(evlist); | 143 | err = perf_evlist__open(evlist); |
144 | if (err < 0) { | 144 | if (err < 0) { |
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c index f2b1dcac45d3..0e95c20ecf6e 100644 --- a/tools/perf/tests/builtin-test.c +++ b/tools/perf/tests/builtin-test.c | |||
@@ -204,6 +204,14 @@ static struct test generic_tests[] = { | |||
204 | .func = test__event_update, | 204 | .func = test__event_update, |
205 | }, | 205 | }, |
206 | { | 206 | { |
207 | .desc = "Test events times", | ||
208 | .func = test__event_times, | ||
209 | }, | ||
210 | { | ||
211 | .desc = "Test backward reading from ring buffer", | ||
212 | .func = test__backward_ring_buffer, | ||
213 | }, | ||
214 | { | ||
207 | .func = NULL, | 215 | .func = NULL, |
208 | }, | 216 | }, |
209 | }; | 217 | }; |
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index abd3f0ec0c0b..68a69a195545 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c | |||
@@ -532,7 +532,7 @@ static int do_test_code_reading(bool try_kcore) | |||
532 | goto out_put; | 532 | goto out_put; |
533 | } | 533 | } |
534 | 534 | ||
535 | perf_evlist__config(evlist, &opts); | 535 | perf_evlist__config(evlist, &opts, NULL); |
536 | 536 | ||
537 | evsel = perf_evlist__first(evlist); | 537 | evsel = perf_evlist__first(evlist); |
538 | 538 | ||
diff --git a/tools/perf/tests/dso-data.c b/tools/perf/tests/dso-data.c index dc673ff7c437..8cf0d9e189a8 100644 --- a/tools/perf/tests/dso-data.c +++ b/tools/perf/tests/dso-data.c | |||
@@ -202,7 +202,7 @@ static int dsos__create(int cnt, int size) | |||
202 | { | 202 | { |
203 | int i; | 203 | int i; |
204 | 204 | ||
205 | dsos = malloc(sizeof(dsos) * cnt); | 205 | dsos = malloc(sizeof(*dsos) * cnt); |
206 | TEST_ASSERT_VAL("failed to alloc dsos array", dsos); | 206 | TEST_ASSERT_VAL("failed to alloc dsos array", dsos); |
207 | 207 | ||
208 | for (i = 0; i < cnt; i++) { | 208 | for (i = 0; i < cnt; i++) { |
diff --git a/tools/perf/tests/event-times.c b/tools/perf/tests/event-times.c new file mode 100644 index 000000000000..95fb744f6628 --- /dev/null +++ b/tools/perf/tests/event-times.c | |||
@@ -0,0 +1,236 @@ | |||
1 | #include <linux/compiler.h> | ||
2 | #include <string.h> | ||
3 | #include "tests.h" | ||
4 | #include "evlist.h" | ||
5 | #include "evsel.h" | ||
6 | #include "util.h" | ||
7 | #include "debug.h" | ||
8 | #include "thread_map.h" | ||
9 | #include "target.h" | ||
10 | |||
11 | static int attach__enable_on_exec(struct perf_evlist *evlist) | ||
12 | { | ||
13 | struct perf_evsel *evsel = perf_evlist__last(evlist); | ||
14 | struct target target = { | ||
15 | .uid = UINT_MAX, | ||
16 | }; | ||
17 | const char *argv[] = { "true", NULL, }; | ||
18 | char sbuf[STRERR_BUFSIZE]; | ||
19 | int err; | ||
20 | |||
21 | pr_debug("attaching to spawned child, enable on exec\n"); | ||
22 | |||
23 | err = perf_evlist__create_maps(evlist, &target); | ||
24 | if (err < 0) { | ||
25 | pr_debug("Not enough memory to create thread/cpu maps\n"); | ||
26 | return err; | ||
27 | } | ||
28 | |||
29 | err = perf_evlist__prepare_workload(evlist, &target, argv, false, NULL); | ||
30 | if (err < 0) { | ||
31 | pr_debug("Couldn't run the workload!\n"); | ||
32 | return err; | ||
33 | } | ||
34 | |||
35 | evsel->attr.enable_on_exec = 1; | ||
36 | |||
37 | err = perf_evlist__open(evlist); | ||
38 | if (err < 0) { | ||
39 | pr_debug("perf_evlist__open: %s\n", | ||
40 | strerror_r(errno, sbuf, sizeof(sbuf))); | ||
41 | return err; | ||
42 | } | ||
43 | |||
44 | return perf_evlist__start_workload(evlist) == 1 ? TEST_OK : TEST_FAIL; | ||
45 | } | ||
46 | |||
47 | static int detach__enable_on_exec(struct perf_evlist *evlist) | ||
48 | { | ||
49 | waitpid(evlist->workload.pid, NULL, 0); | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | static int attach__current_disabled(struct perf_evlist *evlist) | ||
54 | { | ||
55 | struct perf_evsel *evsel = perf_evlist__last(evlist); | ||
56 | struct thread_map *threads; | ||
57 | int err; | ||
58 | |||
59 | pr_debug("attaching to current thread as disabled\n"); | ||
60 | |||
61 | threads = thread_map__new(-1, getpid(), UINT_MAX); | ||
62 | if (threads == NULL) { | ||
63 | pr_debug("thread_map__new\n"); | ||
64 | return -1; | ||
65 | } | ||
66 | |||
67 | evsel->attr.disabled = 1; | ||
68 | |||
69 | err = perf_evsel__open_per_thread(evsel, threads); | ||
70 | if (err) { | ||
71 | pr_debug("Failed to open event cpu-clock:u\n"); | ||
72 | return err; | ||
73 | } | ||
74 | |||
75 | thread_map__put(threads); | ||
76 | return perf_evsel__enable(evsel) == 0 ? TEST_OK : TEST_FAIL; | ||
77 | } | ||
78 | |||
79 | static int attach__current_enabled(struct perf_evlist *evlist) | ||
80 | { | ||
81 | struct perf_evsel *evsel = perf_evlist__last(evlist); | ||
82 | struct thread_map *threads; | ||
83 | int err; | ||
84 | |||
85 | pr_debug("attaching to current thread as enabled\n"); | ||
86 | |||
87 | threads = thread_map__new(-1, getpid(), UINT_MAX); | ||
88 | if (threads == NULL) { | ||
89 | pr_debug("failed to call thread_map__new\n"); | ||
90 | return -1; | ||
91 | } | ||
92 | |||
93 | err = perf_evsel__open_per_thread(evsel, threads); | ||
94 | |||
95 | thread_map__put(threads); | ||
96 | return err == 0 ? TEST_OK : TEST_FAIL; | ||
97 | } | ||
98 | |||
99 | static int detach__disable(struct perf_evlist *evlist) | ||
100 | { | ||
101 | struct perf_evsel *evsel = perf_evlist__last(evlist); | ||
102 | |||
103 | return perf_evsel__enable(evsel); | ||
104 | } | ||
105 | |||
106 | static int attach__cpu_disabled(struct perf_evlist *evlist) | ||
107 | { | ||
108 | struct perf_evsel *evsel = perf_evlist__last(evlist); | ||
109 | struct cpu_map *cpus; | ||
110 | int err; | ||
111 | |||
112 | pr_debug("attaching to CPU 0 as enabled\n"); | ||
113 | |||
114 | cpus = cpu_map__new("0"); | ||
115 | if (cpus == NULL) { | ||
116 | pr_debug("failed to call cpu_map__new\n"); | ||
117 | return -1; | ||
118 | } | ||
119 | |||
120 | evsel->attr.disabled = 1; | ||
121 | |||
122 | err = perf_evsel__open_per_cpu(evsel, cpus); | ||
123 | if (err) { | ||
124 | if (err == -EACCES) | ||
125 | return TEST_SKIP; | ||
126 | |||
127 | pr_debug("Failed to open event cpu-clock:u\n"); | ||
128 | return err; | ||
129 | } | ||
130 | |||
131 | cpu_map__put(cpus); | ||
132 | return perf_evsel__enable(evsel); | ||
133 | } | ||
134 | |||
135 | static int attach__cpu_enabled(struct perf_evlist *evlist) | ||
136 | { | ||
137 | struct perf_evsel *evsel = perf_evlist__last(evlist); | ||
138 | struct cpu_map *cpus; | ||
139 | int err; | ||
140 | |||
141 | pr_debug("attaching to CPU 0 as enabled\n"); | ||
142 | |||
143 | cpus = cpu_map__new("0"); | ||
144 | if (cpus == NULL) { | ||
145 | pr_debug("failed to call cpu_map__new\n"); | ||
146 | return -1; | ||
147 | } | ||
148 | |||
149 | err = perf_evsel__open_per_cpu(evsel, cpus); | ||
150 | if (err == -EACCES) | ||
151 | return TEST_SKIP; | ||
152 | |||
153 | cpu_map__put(cpus); | ||
154 | return err ? TEST_FAIL : TEST_OK; | ||
155 | } | ||
156 | |||
157 | static int test_times(int (attach)(struct perf_evlist *), | ||
158 | int (detach)(struct perf_evlist *)) | ||
159 | { | ||
160 | struct perf_counts_values count; | ||
161 | struct perf_evlist *evlist = NULL; | ||
162 | struct perf_evsel *evsel; | ||
163 | int err = -1, i; | ||
164 | |||
165 | evlist = perf_evlist__new(); | ||
166 | if (!evlist) { | ||
167 | pr_debug("failed to create event list\n"); | ||
168 | goto out_err; | ||
169 | } | ||
170 | |||
171 | err = parse_events(evlist, "cpu-clock:u", NULL); | ||
172 | if (err) { | ||
173 | pr_debug("failed to parse event cpu-clock:u\n"); | ||
174 | goto out_err; | ||
175 | } | ||
176 | |||
177 | evsel = perf_evlist__last(evlist); | ||
178 | evsel->attr.read_format |= | ||
179 | PERF_FORMAT_TOTAL_TIME_ENABLED | | ||
180 | PERF_FORMAT_TOTAL_TIME_RUNNING; | ||
181 | |||
182 | err = attach(evlist); | ||
183 | if (err == TEST_SKIP) { | ||
184 | pr_debug(" SKIP : not enough rights\n"); | ||
185 | return err; | ||
186 | } | ||
187 | |||
188 | TEST_ASSERT_VAL("failed to attach", !err); | ||
189 | |||
190 | for (i = 0; i < 100000000; i++) { } | ||
191 | |||
192 | TEST_ASSERT_VAL("failed to detach", !detach(evlist)); | ||
193 | |||
194 | perf_evsel__read(evsel, 0, 0, &count); | ||
195 | |||
196 | err = !(count.ena == count.run); | ||
197 | |||
198 | pr_debug(" %s: ena %" PRIu64", run %" PRIu64"\n", | ||
199 | !err ? "OK " : "FAILED", | ||
200 | count.ena, count.run); | ||
201 | |||
202 | out_err: | ||
203 | if (evlist) | ||
204 | perf_evlist__delete(evlist); | ||
205 | return !err ? TEST_OK : TEST_FAIL; | ||
206 | } | ||
207 | |||
208 | /* | ||
209 | * This test creates software event 'cpu-clock' | ||
210 | * attaches it in several ways (explained below) | ||
211 | * and checks that enabled and running times | ||
212 | * match. | ||
213 | */ | ||
214 | int test__event_times(int subtest __maybe_unused) | ||
215 | { | ||
216 | int err, ret = 0; | ||
217 | |||
218 | #define _T(attach, detach) \ | ||
219 | err = test_times(attach, detach); \ | ||
220 | if (err && (ret == TEST_OK || ret == TEST_SKIP)) \ | ||
221 | ret = err; | ||
222 | |||
223 | /* attach on newly spawned process after exec */ | ||
224 | _T(attach__enable_on_exec, detach__enable_on_exec) | ||
225 | /* attach on current process as enabled */ | ||
226 | _T(attach__current_enabled, detach__disable) | ||
227 | /* attach on current process as disabled */ | ||
228 | _T(attach__current_disabled, detach__disable) | ||
229 | /* attach on cpu as disabled */ | ||
230 | _T(attach__cpu_disabled, detach__disable) | ||
231 | /* attach on cpu as enabled */ | ||
232 | _T(attach__cpu_enabled, detach__disable) | ||
233 | |||
234 | #undef _T | ||
235 | return ret; | ||
236 | } | ||
diff --git a/tools/perf/tests/event_update.c b/tools/perf/tests/event_update.c index 012eab5d1df1..63ecf21750eb 100644 --- a/tools/perf/tests/event_update.c +++ b/tools/perf/tests/event_update.c | |||
@@ -30,7 +30,7 @@ static int process_event_scale(struct perf_tool *tool __maybe_unused, | |||
30 | 30 | ||
31 | TEST_ASSERT_VAL("wrong id", ev->id == 123); | 31 | TEST_ASSERT_VAL("wrong id", ev->id == 123); |
32 | TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__SCALE); | 32 | TEST_ASSERT_VAL("wrong id", ev->type == PERF_EVENT_UPDATE__SCALE); |
33 | TEST_ASSERT_VAL("wrong scale", ev_data->scale = 0.123); | 33 | TEST_ASSERT_VAL("wrong scale", ev_data->scale == 0.123); |
34 | return 0; | 34 | return 0; |
35 | } | 35 | } |
36 | 36 | ||
diff --git a/tools/perf/tests/hists_common.c b/tools/perf/tests/hists_common.c index f55f4bd47932..6b21746d6eec 100644 --- a/tools/perf/tests/hists_common.c +++ b/tools/perf/tests/hists_common.c | |||
@@ -161,7 +161,7 @@ void print_hists_in(struct hists *hists) | |||
161 | struct rb_root *root; | 161 | struct rb_root *root; |
162 | struct rb_node *node; | 162 | struct rb_node *node; |
163 | 163 | ||
164 | if (sort__need_collapse) | 164 | if (hists__has(hists, need_collapse)) |
165 | root = &hists->entries_collapsed; | 165 | root = &hists->entries_collapsed; |
166 | else | 166 | else |
167 | root = hists->entries_in; | 167 | root = hists->entries_in; |
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c index ed5aa9eaeb6c..a9e3db3afac4 100644 --- a/tools/perf/tests/hists_cumulate.c +++ b/tools/perf/tests/hists_cumulate.c | |||
@@ -101,7 +101,7 @@ static int add_hist_entries(struct hists *hists, struct machine *machine) | |||
101 | if (machine__resolve(machine, &al, &sample) < 0) | 101 | if (machine__resolve(machine, &al, &sample) < 0) |
102 | goto out; | 102 | goto out; |
103 | 103 | ||
104 | if (hist_entry_iter__add(&iter, &al, PERF_MAX_STACK_DEPTH, | 104 | if (hist_entry_iter__add(&iter, &al, sysctl_perf_event_max_stack, |
105 | NULL) < 0) { | 105 | NULL) < 0) { |
106 | addr_location__put(&al); | 106 | addr_location__put(&al); |
107 | goto out; | 107 | goto out; |
@@ -126,7 +126,7 @@ static void del_hist_entries(struct hists *hists) | |||
126 | struct rb_root *root_out; | 126 | struct rb_root *root_out; |
127 | struct rb_node *node; | 127 | struct rb_node *node; |
128 | 128 | ||
129 | if (sort__need_collapse) | 129 | if (hists__has(hists, need_collapse)) |
130 | root_in = &hists->entries_collapsed; | 130 | root_in = &hists->entries_collapsed; |
131 | else | 131 | else |
132 | root_in = hists->entries_in; | 132 | root_in = hists->entries_in; |
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c index b825d24f8186..e846f8c42013 100644 --- a/tools/perf/tests/hists_filter.c +++ b/tools/perf/tests/hists_filter.c | |||
@@ -81,7 +81,7 @@ static int add_hist_entries(struct perf_evlist *evlist, | |||
81 | 81 | ||
82 | al.socket = fake_samples[i].socket; | 82 | al.socket = fake_samples[i].socket; |
83 | if (hist_entry_iter__add(&iter, &al, | 83 | if (hist_entry_iter__add(&iter, &al, |
84 | PERF_MAX_STACK_DEPTH, NULL) < 0) { | 84 | sysctl_perf_event_max_stack, NULL) < 0) { |
85 | addr_location__put(&al); | 85 | addr_location__put(&al); |
86 | goto out; | 86 | goto out; |
87 | } | 87 | } |
diff --git a/tools/perf/tests/hists_link.c b/tools/perf/tests/hists_link.c index 358324e47805..acf5a1301c07 100644 --- a/tools/perf/tests/hists_link.c +++ b/tools/perf/tests/hists_link.c | |||
@@ -145,7 +145,7 @@ static int __validate_match(struct hists *hists) | |||
145 | /* | 145 | /* |
146 | * Only entries from fake_common_samples should have a pair. | 146 | * Only entries from fake_common_samples should have a pair. |
147 | */ | 147 | */ |
148 | if (sort__need_collapse) | 148 | if (hists__has(hists, need_collapse)) |
149 | root = &hists->entries_collapsed; | 149 | root = &hists->entries_collapsed; |
150 | else | 150 | else |
151 | root = hists->entries_in; | 151 | root = hists->entries_in; |
@@ -197,7 +197,7 @@ static int __validate_link(struct hists *hists, int idx) | |||
197 | * and some entries will have no pair. However every entry | 197 | * and some entries will have no pair. However every entry |
198 | * in other hists should have (dummy) pair. | 198 | * in other hists should have (dummy) pair. |
199 | */ | 199 | */ |
200 | if (sort__need_collapse) | 200 | if (hists__has(hists, need_collapse)) |
201 | root = &hists->entries_collapsed; | 201 | root = &hists->entries_collapsed; |
202 | else | 202 | else |
203 | root = hists->entries_in; | 203 | root = hists->entries_in; |
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c index d3556fbe8c5c..63c5efaba1b5 100644 --- a/tools/perf/tests/hists_output.c +++ b/tools/perf/tests/hists_output.c | |||
@@ -67,7 +67,7 @@ static int add_hist_entries(struct hists *hists, struct machine *machine) | |||
67 | if (machine__resolve(machine, &al, &sample) < 0) | 67 | if (machine__resolve(machine, &al, &sample) < 0) |
68 | goto out; | 68 | goto out; |
69 | 69 | ||
70 | if (hist_entry_iter__add(&iter, &al, PERF_MAX_STACK_DEPTH, | 70 | if (hist_entry_iter__add(&iter, &al, sysctl_perf_event_max_stack, |
71 | NULL) < 0) { | 71 | NULL) < 0) { |
72 | addr_location__put(&al); | 72 | addr_location__put(&al); |
73 | goto out; | 73 | goto out; |
@@ -92,7 +92,7 @@ static void del_hist_entries(struct hists *hists) | |||
92 | struct rb_root *root_out; | 92 | struct rb_root *root_out; |
93 | struct rb_node *node; | 93 | struct rb_node *node; |
94 | 94 | ||
95 | if (sort__need_collapse) | 95 | if (hists__has(hists, need_collapse)) |
96 | root_in = &hists->entries_collapsed; | 96 | root_in = &hists->entries_collapsed; |
97 | else | 97 | else |
98 | root_in = hists->entries_in; | 98 | root_in = hists->entries_in; |
diff --git a/tools/perf/tests/keep-tracking.c b/tools/perf/tests/keep-tracking.c index ddb78fae064a..614e45a3c603 100644 --- a/tools/perf/tests/keep-tracking.c +++ b/tools/perf/tests/keep-tracking.c | |||
@@ -80,7 +80,7 @@ int test__keep_tracking(int subtest __maybe_unused) | |||
80 | CHECK__(parse_events(evlist, "dummy:u", NULL)); | 80 | CHECK__(parse_events(evlist, "dummy:u", NULL)); |
81 | CHECK__(parse_events(evlist, "cycles:u", NULL)); | 81 | CHECK__(parse_events(evlist, "cycles:u", NULL)); |
82 | 82 | ||
83 | perf_evlist__config(evlist, &opts); | 83 | perf_evlist__config(evlist, &opts, NULL); |
84 | 84 | ||
85 | evsel = perf_evlist__first(evlist); | 85 | evsel = perf_evlist__first(evlist); |
86 | 86 | ||
diff --git a/tools/perf/tests/openat-syscall-all-cpus.c b/tools/perf/tests/openat-syscall-all-cpus.c index 53c2273e8859..ad1cb63139a7 100644 --- a/tools/perf/tests/openat-syscall-all-cpus.c +++ b/tools/perf/tests/openat-syscall-all-cpus.c | |||
@@ -73,7 +73,7 @@ int test__openat_syscall_event_on_all_cpus(int subtest __maybe_unused) | |||
73 | } | 73 | } |
74 | 74 | ||
75 | /* | 75 | /* |
76 | * Here we need to explicitely preallocate the counts, as if | 76 | * Here we need to explicitly preallocate the counts, as if |
77 | * we use the auto allocation it will allocate just for 1 cpu, | 77 | * we use the auto allocation it will allocate just for 1 cpu, |
78 | * as we start by cpu 0. | 78 | * as we start by cpu 0. |
79 | */ | 79 | */ |
diff --git a/tools/perf/tests/openat-syscall-tp-fields.c b/tools/perf/tests/openat-syscall-tp-fields.c index eb99a105f31c..4344fe482c1d 100644 --- a/tools/perf/tests/openat-syscall-tp-fields.c +++ b/tools/perf/tests/openat-syscall-tp-fields.c | |||
@@ -44,7 +44,7 @@ int test__syscall_openat_tp_fields(int subtest __maybe_unused) | |||
44 | goto out_delete_evlist; | 44 | goto out_delete_evlist; |
45 | } | 45 | } |
46 | 46 | ||
47 | perf_evsel__config(evsel, &opts); | 47 | perf_evsel__config(evsel, &opts, NULL); |
48 | 48 | ||
49 | thread_map__set_pid(evlist->threads, 0, getpid()); | 49 | thread_map__set_pid(evlist->threads, 0, getpid()); |
50 | 50 | ||
diff --git a/tools/perf/tests/perf-record.c b/tools/perf/tests/perf-record.c index 1cc78cefe399..b836ee6a8d9b 100644 --- a/tools/perf/tests/perf-record.c +++ b/tools/perf/tests/perf-record.c | |||
@@ -99,7 +99,7 @@ int test__PERF_RECORD(int subtest __maybe_unused) | |||
99 | perf_evsel__set_sample_bit(evsel, CPU); | 99 | perf_evsel__set_sample_bit(evsel, CPU); |
100 | perf_evsel__set_sample_bit(evsel, TID); | 100 | perf_evsel__set_sample_bit(evsel, TID); |
101 | perf_evsel__set_sample_bit(evsel, TIME); | 101 | perf_evsel__set_sample_bit(evsel, TIME); |
102 | perf_evlist__config(evlist, &opts); | 102 | perf_evlist__config(evlist, &opts, NULL); |
103 | 103 | ||
104 | err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); | 104 | err = sched__get_first_possible_cpu(evlist->workload.pid, &cpu_mask); |
105 | if (err < 0) { | 105 | if (err < 0) { |
diff --git a/tools/perf/tests/switch-tracking.c b/tools/perf/tests/switch-tracking.c index ebd80168d51e..39a689bf7574 100644 --- a/tools/perf/tests/switch-tracking.c +++ b/tools/perf/tests/switch-tracking.c | |||
@@ -417,7 +417,7 @@ int test__switch_tracking(int subtest __maybe_unused) | |||
417 | perf_evsel__set_sample_bit(tracking_evsel, TIME); | 417 | perf_evsel__set_sample_bit(tracking_evsel, TIME); |
418 | 418 | ||
419 | /* Config events */ | 419 | /* Config events */ |
420 | perf_evlist__config(evlist, &opts); | 420 | perf_evlist__config(evlist, &opts, NULL); |
421 | 421 | ||
422 | /* Check moved event is still at the front */ | 422 | /* Check moved event is still at the front */ |
423 | if (cycles_evsel != perf_evlist__first(evlist)) { | 423 | if (cycles_evsel != perf_evlist__first(evlist)) { |
diff --git a/tools/perf/tests/tests.h b/tools/perf/tests/tests.h index 82b2b5e6ba7c..c57e72c826d2 100644 --- a/tools/perf/tests/tests.h +++ b/tools/perf/tests/tests.h | |||
@@ -85,6 +85,8 @@ int test__synthesize_stat_config(int subtest); | |||
85 | int test__synthesize_stat(int subtest); | 85 | int test__synthesize_stat(int subtest); |
86 | int test__synthesize_stat_round(int subtest); | 86 | int test__synthesize_stat_round(int subtest); |
87 | int test__event_update(int subtest); | 87 | int test__event_update(int subtest); |
88 | int test__event_times(int subtest); | ||
89 | int test__backward_ring_buffer(int subtest); | ||
88 | 90 | ||
89 | #if defined(__arm__) || defined(__aarch64__) | 91 | #if defined(__arm__) || defined(__aarch64__) |
90 | #ifdef HAVE_DWARF_UNWIND_SUPPORT | 92 | #ifdef HAVE_DWARF_UNWIND_SUPPORT |
diff --git a/tools/perf/tests/vmlinux-kallsyms.c b/tools/perf/tests/vmlinux-kallsyms.c index 630b0b409b97..e63abab7d5a1 100644 --- a/tools/perf/tests/vmlinux-kallsyms.c +++ b/tools/perf/tests/vmlinux-kallsyms.c | |||
@@ -54,8 +54,14 @@ int test__vmlinux_matches_kallsyms(int subtest __maybe_unused) | |||
54 | * Step 3: | 54 | * Step 3: |
55 | * | 55 | * |
56 | * Load and split /proc/kallsyms into multiple maps, one per module. | 56 | * Load and split /proc/kallsyms into multiple maps, one per module. |
57 | * Do not use kcore, as this test was designed before kcore support | ||
58 | * and has parts that only make sense if using the non-kcore code. | ||
59 | * XXX: extend it to stress the kcorre code as well, hint: the list | ||
60 | * of modules extracted from /proc/kcore, in its current form, can't | ||
61 | * be compacted against the list of modules found in the "vmlinux" | ||
62 | * code and with the one got from /proc/modules from the "kallsyms" code. | ||
57 | */ | 63 | */ |
58 | if (machine__load_kallsyms(&kallsyms, "/proc/kallsyms", type, NULL) <= 0) { | 64 | if (__machine__load_kallsyms(&kallsyms, "/proc/kallsyms", type, true, NULL) <= 0) { |
59 | pr_debug("dso__load_kallsyms "); | 65 | pr_debug("dso__load_kallsyms "); |
60 | goto out; | 66 | goto out; |
61 | } | 67 | } |
@@ -157,6 +163,9 @@ next_pair: | |||
157 | 163 | ||
158 | pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n", | 164 | pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n", |
159 | mem_start, sym->name, pair->name); | 165 | mem_start, sym->name, pair->name); |
166 | } else { | ||
167 | pr_debug("%#" PRIx64 ": diff name v: %s k: %s\n", | ||
168 | mem_start, sym->name, first_pair->name); | ||
160 | } | 169 | } |
161 | } | 170 | } |
162 | } else | 171 | } else |
diff --git a/tools/perf/trace/beauty/eventfd.c b/tools/perf/trace/beauty/eventfd.c new file mode 100644 index 000000000000..d64f4a9128a1 --- /dev/null +++ b/tools/perf/trace/beauty/eventfd.c | |||
@@ -0,0 +1,38 @@ | |||
1 | #include <sys/eventfd.h> | ||
2 | |||
3 | #ifndef EFD_SEMAPHORE | ||
4 | #define EFD_SEMAPHORE 1 | ||
5 | #endif | ||
6 | |||
7 | #ifndef EFD_NONBLOCK | ||
8 | #define EFD_NONBLOCK 00004000 | ||
9 | #endif | ||
10 | |||
11 | #ifndef EFD_CLOEXEC | ||
12 | #define EFD_CLOEXEC 02000000 | ||
13 | #endif | ||
14 | |||
15 | static size_t syscall_arg__scnprintf_eventfd_flags(char *bf, size_t size, struct syscall_arg *arg) | ||
16 | { | ||
17 | int printed = 0, flags = arg->val; | ||
18 | |||
19 | if (flags == 0) | ||
20 | return scnprintf(bf, size, "NONE"); | ||
21 | #define P_FLAG(n) \ | ||
22 | if (flags & EFD_##n) { \ | ||
23 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
24 | flags &= ~EFD_##n; \ | ||
25 | } | ||
26 | |||
27 | P_FLAG(SEMAPHORE); | ||
28 | P_FLAG(CLOEXEC); | ||
29 | P_FLAG(NONBLOCK); | ||
30 | #undef P_FLAG | ||
31 | |||
32 | if (flags) | ||
33 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
34 | |||
35 | return printed; | ||
36 | } | ||
37 | |||
38 | #define SCA_EFD_FLAGS syscall_arg__scnprintf_eventfd_flags | ||
diff --git a/tools/perf/trace/beauty/flock.c b/tools/perf/trace/beauty/flock.c new file mode 100644 index 000000000000..021bb48c6336 --- /dev/null +++ b/tools/perf/trace/beauty/flock.c | |||
@@ -0,0 +1,31 @@ | |||
1 | |||
2 | static size_t syscall_arg__scnprintf_flock(char *bf, size_t size, | ||
3 | struct syscall_arg *arg) | ||
4 | { | ||
5 | int printed = 0, op = arg->val; | ||
6 | |||
7 | if (op == 0) | ||
8 | return scnprintf(bf, size, "NONE"); | ||
9 | #define P_CMD(cmd) \ | ||
10 | if ((op & LOCK_##cmd) == LOCK_##cmd) { \ | ||
11 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #cmd); \ | ||
12 | op &= ~LOCK_##cmd; \ | ||
13 | } | ||
14 | |||
15 | P_CMD(SH); | ||
16 | P_CMD(EX); | ||
17 | P_CMD(NB); | ||
18 | P_CMD(UN); | ||
19 | P_CMD(MAND); | ||
20 | P_CMD(RW); | ||
21 | P_CMD(READ); | ||
22 | P_CMD(WRITE); | ||
23 | #undef P_OP | ||
24 | |||
25 | if (op) | ||
26 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", op); | ||
27 | |||
28 | return printed; | ||
29 | } | ||
30 | |||
31 | #define SCA_FLOCK syscall_arg__scnprintf_flock | ||
diff --git a/tools/perf/trace/beauty/futex_op.c b/tools/perf/trace/beauty/futex_op.c new file mode 100644 index 000000000000..e2476211f22d --- /dev/null +++ b/tools/perf/trace/beauty/futex_op.c | |||
@@ -0,0 +1,44 @@ | |||
1 | #include <linux/futex.h> | ||
2 | |||
3 | static size_t syscall_arg__scnprintf_futex_op(char *bf, size_t size, struct syscall_arg *arg) | ||
4 | { | ||
5 | enum syscall_futex_args { | ||
6 | SCF_UADDR = (1 << 0), | ||
7 | SCF_OP = (1 << 1), | ||
8 | SCF_VAL = (1 << 2), | ||
9 | SCF_TIMEOUT = (1 << 3), | ||
10 | SCF_UADDR2 = (1 << 4), | ||
11 | SCF_VAL3 = (1 << 5), | ||
12 | }; | ||
13 | int op = arg->val; | ||
14 | int cmd = op & FUTEX_CMD_MASK; | ||
15 | size_t printed = 0; | ||
16 | |||
17 | switch (cmd) { | ||
18 | #define P_FUTEX_OP(n) case FUTEX_##n: printed = scnprintf(bf, size, #n); | ||
19 | P_FUTEX_OP(WAIT); arg->mask |= SCF_VAL3|SCF_UADDR2; break; | ||
20 | P_FUTEX_OP(WAKE); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; | ||
21 | P_FUTEX_OP(FD); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; | ||
22 | P_FUTEX_OP(REQUEUE); arg->mask |= SCF_VAL3|SCF_TIMEOUT; break; | ||
23 | P_FUTEX_OP(CMP_REQUEUE); arg->mask |= SCF_TIMEOUT; break; | ||
24 | P_FUTEX_OP(CMP_REQUEUE_PI); arg->mask |= SCF_TIMEOUT; break; | ||
25 | P_FUTEX_OP(WAKE_OP); break; | ||
26 | P_FUTEX_OP(LOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; | ||
27 | P_FUTEX_OP(UNLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2|SCF_TIMEOUT; break; | ||
28 | P_FUTEX_OP(TRYLOCK_PI); arg->mask |= SCF_VAL3|SCF_UADDR2; break; | ||
29 | P_FUTEX_OP(WAIT_BITSET); arg->mask |= SCF_UADDR2; break; | ||
30 | P_FUTEX_OP(WAKE_BITSET); arg->mask |= SCF_UADDR2; break; | ||
31 | P_FUTEX_OP(WAIT_REQUEUE_PI); break; | ||
32 | default: printed = scnprintf(bf, size, "%#x", cmd); break; | ||
33 | } | ||
34 | |||
35 | if (op & FUTEX_PRIVATE_FLAG) | ||
36 | printed += scnprintf(bf + printed, size - printed, "|PRIV"); | ||
37 | |||
38 | if (op & FUTEX_CLOCK_REALTIME) | ||
39 | printed += scnprintf(bf + printed, size - printed, "|CLKRT"); | ||
40 | |||
41 | return printed; | ||
42 | } | ||
43 | |||
44 | #define SCA_FUTEX_OP syscall_arg__scnprintf_futex_op | ||
diff --git a/tools/perf/trace/beauty/mmap.c b/tools/perf/trace/beauty/mmap.c new file mode 100644 index 000000000000..3444a4d5382d --- /dev/null +++ b/tools/perf/trace/beauty/mmap.c | |||
@@ -0,0 +1,158 @@ | |||
1 | #include <sys/mman.h> | ||
2 | |||
3 | static size_t syscall_arg__scnprintf_mmap_prot(char *bf, size_t size, | ||
4 | struct syscall_arg *arg) | ||
5 | { | ||
6 | int printed = 0, prot = arg->val; | ||
7 | |||
8 | if (prot == PROT_NONE) | ||
9 | return scnprintf(bf, size, "NONE"); | ||
10 | #define P_MMAP_PROT(n) \ | ||
11 | if (prot & PROT_##n) { \ | ||
12 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
13 | prot &= ~PROT_##n; \ | ||
14 | } | ||
15 | |||
16 | P_MMAP_PROT(EXEC); | ||
17 | P_MMAP_PROT(READ); | ||
18 | P_MMAP_PROT(WRITE); | ||
19 | #ifdef PROT_SEM | ||
20 | P_MMAP_PROT(SEM); | ||
21 | #endif | ||
22 | P_MMAP_PROT(GROWSDOWN); | ||
23 | P_MMAP_PROT(GROWSUP); | ||
24 | #undef P_MMAP_PROT | ||
25 | |||
26 | if (prot) | ||
27 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", prot); | ||
28 | |||
29 | return printed; | ||
30 | } | ||
31 | |||
32 | #define SCA_MMAP_PROT syscall_arg__scnprintf_mmap_prot | ||
33 | |||
34 | #ifndef MAP_STACK | ||
35 | # define MAP_STACK 0x20000 | ||
36 | #endif | ||
37 | |||
38 | static size_t syscall_arg__scnprintf_mmap_flags(char *bf, size_t size, | ||
39 | struct syscall_arg *arg) | ||
40 | { | ||
41 | int printed = 0, flags = arg->val; | ||
42 | |||
43 | #define P_MMAP_FLAG(n) \ | ||
44 | if (flags & MAP_##n) { \ | ||
45 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
46 | flags &= ~MAP_##n; \ | ||
47 | } | ||
48 | |||
49 | P_MMAP_FLAG(SHARED); | ||
50 | P_MMAP_FLAG(PRIVATE); | ||
51 | #ifdef MAP_32BIT | ||
52 | P_MMAP_FLAG(32BIT); | ||
53 | #endif | ||
54 | P_MMAP_FLAG(ANONYMOUS); | ||
55 | P_MMAP_FLAG(DENYWRITE); | ||
56 | P_MMAP_FLAG(EXECUTABLE); | ||
57 | P_MMAP_FLAG(FILE); | ||
58 | P_MMAP_FLAG(FIXED); | ||
59 | P_MMAP_FLAG(GROWSDOWN); | ||
60 | #ifdef MAP_HUGETLB | ||
61 | P_MMAP_FLAG(HUGETLB); | ||
62 | #endif | ||
63 | P_MMAP_FLAG(LOCKED); | ||
64 | P_MMAP_FLAG(NONBLOCK); | ||
65 | P_MMAP_FLAG(NORESERVE); | ||
66 | P_MMAP_FLAG(POPULATE); | ||
67 | P_MMAP_FLAG(STACK); | ||
68 | #ifdef MAP_UNINITIALIZED | ||
69 | P_MMAP_FLAG(UNINITIALIZED); | ||
70 | #endif | ||
71 | #undef P_MMAP_FLAG | ||
72 | |||
73 | if (flags) | ||
74 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
75 | |||
76 | return printed; | ||
77 | } | ||
78 | |||
79 | #define SCA_MMAP_FLAGS syscall_arg__scnprintf_mmap_flags | ||
80 | |||
81 | static size_t syscall_arg__scnprintf_mremap_flags(char *bf, size_t size, | ||
82 | struct syscall_arg *arg) | ||
83 | { | ||
84 | int printed = 0, flags = arg->val; | ||
85 | |||
86 | #define P_MREMAP_FLAG(n) \ | ||
87 | if (flags & MREMAP_##n) { \ | ||
88 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
89 | flags &= ~MREMAP_##n; \ | ||
90 | } | ||
91 | |||
92 | P_MREMAP_FLAG(MAYMOVE); | ||
93 | #ifdef MREMAP_FIXED | ||
94 | P_MREMAP_FLAG(FIXED); | ||
95 | #endif | ||
96 | #undef P_MREMAP_FLAG | ||
97 | |||
98 | if (flags) | ||
99 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
100 | |||
101 | return printed; | ||
102 | } | ||
103 | |||
104 | #define SCA_MREMAP_FLAGS syscall_arg__scnprintf_mremap_flags | ||
105 | |||
106 | #ifndef MADV_HWPOISON | ||
107 | #define MADV_HWPOISON 100 | ||
108 | #endif | ||
109 | |||
110 | #ifndef MADV_MERGEABLE | ||
111 | #define MADV_MERGEABLE 12 | ||
112 | #endif | ||
113 | |||
114 | #ifndef MADV_UNMERGEABLE | ||
115 | #define MADV_UNMERGEABLE 13 | ||
116 | #endif | ||
117 | |||
118 | static size_t syscall_arg__scnprintf_madvise_behavior(char *bf, size_t size, | ||
119 | struct syscall_arg *arg) | ||
120 | { | ||
121 | int behavior = arg->val; | ||
122 | |||
123 | switch (behavior) { | ||
124 | #define P_MADV_BHV(n) case MADV_##n: return scnprintf(bf, size, #n) | ||
125 | P_MADV_BHV(NORMAL); | ||
126 | P_MADV_BHV(RANDOM); | ||
127 | P_MADV_BHV(SEQUENTIAL); | ||
128 | P_MADV_BHV(WILLNEED); | ||
129 | P_MADV_BHV(DONTNEED); | ||
130 | P_MADV_BHV(REMOVE); | ||
131 | P_MADV_BHV(DONTFORK); | ||
132 | P_MADV_BHV(DOFORK); | ||
133 | P_MADV_BHV(HWPOISON); | ||
134 | #ifdef MADV_SOFT_OFFLINE | ||
135 | P_MADV_BHV(SOFT_OFFLINE); | ||
136 | #endif | ||
137 | P_MADV_BHV(MERGEABLE); | ||
138 | P_MADV_BHV(UNMERGEABLE); | ||
139 | #ifdef MADV_HUGEPAGE | ||
140 | P_MADV_BHV(HUGEPAGE); | ||
141 | #endif | ||
142 | #ifdef MADV_NOHUGEPAGE | ||
143 | P_MADV_BHV(NOHUGEPAGE); | ||
144 | #endif | ||
145 | #ifdef MADV_DONTDUMP | ||
146 | P_MADV_BHV(DONTDUMP); | ||
147 | #endif | ||
148 | #ifdef MADV_DODUMP | ||
149 | P_MADV_BHV(DODUMP); | ||
150 | #endif | ||
151 | #undef P_MADV_PHV | ||
152 | default: break; | ||
153 | } | ||
154 | |||
155 | return scnprintf(bf, size, "%#x", behavior); | ||
156 | } | ||
157 | |||
158 | #define SCA_MADV_BHV syscall_arg__scnprintf_madvise_behavior | ||
diff --git a/tools/perf/trace/beauty/mode_t.c b/tools/perf/trace/beauty/mode_t.c new file mode 100644 index 000000000000..930d8fef2400 --- /dev/null +++ b/tools/perf/trace/beauty/mode_t.c | |||
@@ -0,0 +1,68 @@ | |||
1 | #include <sys/types.h> | ||
2 | #include <sys/stat.h> | ||
3 | #include <unistd.h> | ||
4 | |||
5 | /* From include/linux/stat.h */ | ||
6 | #ifndef S_IRWXUGO | ||
7 | #define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO) | ||
8 | #endif | ||
9 | #ifndef S_IALLUGO | ||
10 | #define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO) | ||
11 | #endif | ||
12 | #ifndef S_IRUGO | ||
13 | #define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH) | ||
14 | #endif | ||
15 | #ifndef S_IWUGO | ||
16 | #define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH) | ||
17 | #endif | ||
18 | #ifndef S_IXUGO | ||
19 | #define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH) | ||
20 | #endif | ||
21 | |||
22 | static size_t syscall_arg__scnprintf_mode_t(char *bf, size_t size, struct syscall_arg *arg) | ||
23 | { | ||
24 | int printed = 0, mode = arg->val; | ||
25 | |||
26 | #define P_MODE(n) \ | ||
27 | if ((mode & S_##n) == S_##n) { \ | ||
28 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
29 | mode &= ~S_##n; \ | ||
30 | } | ||
31 | |||
32 | P_MODE(IALLUGO); | ||
33 | P_MODE(IRWXUGO); | ||
34 | P_MODE(IRUGO); | ||
35 | P_MODE(IWUGO); | ||
36 | P_MODE(IXUGO); | ||
37 | P_MODE(IFMT); | ||
38 | P_MODE(IFSOCK); | ||
39 | P_MODE(IFLNK); | ||
40 | P_MODE(IFREG); | ||
41 | P_MODE(IFBLK); | ||
42 | P_MODE(IFDIR); | ||
43 | P_MODE(IFCHR); | ||
44 | P_MODE(IFIFO); | ||
45 | P_MODE(ISUID); | ||
46 | P_MODE(ISGID); | ||
47 | P_MODE(ISVTX); | ||
48 | P_MODE(IRWXU); | ||
49 | P_MODE(IRUSR); | ||
50 | P_MODE(IWUSR); | ||
51 | P_MODE(IXUSR); | ||
52 | P_MODE(IRWXG); | ||
53 | P_MODE(IRGRP); | ||
54 | P_MODE(IWGRP); | ||
55 | P_MODE(IXGRP); | ||
56 | P_MODE(IRWXO); | ||
57 | P_MODE(IROTH); | ||
58 | P_MODE(IWOTH); | ||
59 | P_MODE(IXOTH); | ||
60 | #undef P_MODE | ||
61 | |||
62 | if (mode) | ||
63 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", mode); | ||
64 | |||
65 | return printed; | ||
66 | } | ||
67 | |||
68 | #define SCA_MODE_T syscall_arg__scnprintf_mode_t | ||
diff --git a/tools/perf/trace/beauty/msg_flags.c b/tools/perf/trace/beauty/msg_flags.c new file mode 100644 index 000000000000..07fa8a0acad6 --- /dev/null +++ b/tools/perf/trace/beauty/msg_flags.c | |||
@@ -0,0 +1,62 @@ | |||
1 | #include <sys/types.h> | ||
2 | #include <sys/socket.h> | ||
3 | |||
4 | #ifndef MSG_PROBE | ||
5 | #define MSG_PROBE 0x10 | ||
6 | #endif | ||
7 | #ifndef MSG_WAITFORONE | ||
8 | #define MSG_WAITFORONE 0x10000 | ||
9 | #endif | ||
10 | #ifndef MSG_SENDPAGE_NOTLAST | ||
11 | #define MSG_SENDPAGE_NOTLAST 0x20000 | ||
12 | #endif | ||
13 | #ifndef MSG_FASTOPEN | ||
14 | #define MSG_FASTOPEN 0x20000000 | ||
15 | #endif | ||
16 | #ifndef MSG_CMSG_CLOEXEC | ||
17 | # define MSG_CMSG_CLOEXEC 0x40000000 | ||
18 | #endif | ||
19 | |||
20 | static size_t syscall_arg__scnprintf_msg_flags(char *bf, size_t size, | ||
21 | struct syscall_arg *arg) | ||
22 | { | ||
23 | int printed = 0, flags = arg->val; | ||
24 | |||
25 | if (flags == 0) | ||
26 | return scnprintf(bf, size, "NONE"); | ||
27 | #define P_MSG_FLAG(n) \ | ||
28 | if (flags & MSG_##n) { \ | ||
29 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
30 | flags &= ~MSG_##n; \ | ||
31 | } | ||
32 | |||
33 | P_MSG_FLAG(OOB); | ||
34 | P_MSG_FLAG(PEEK); | ||
35 | P_MSG_FLAG(DONTROUTE); | ||
36 | P_MSG_FLAG(TRYHARD); | ||
37 | P_MSG_FLAG(CTRUNC); | ||
38 | P_MSG_FLAG(PROBE); | ||
39 | P_MSG_FLAG(TRUNC); | ||
40 | P_MSG_FLAG(DONTWAIT); | ||
41 | P_MSG_FLAG(EOR); | ||
42 | P_MSG_FLAG(WAITALL); | ||
43 | P_MSG_FLAG(FIN); | ||
44 | P_MSG_FLAG(SYN); | ||
45 | P_MSG_FLAG(CONFIRM); | ||
46 | P_MSG_FLAG(RST); | ||
47 | P_MSG_FLAG(ERRQUEUE); | ||
48 | P_MSG_FLAG(NOSIGNAL); | ||
49 | P_MSG_FLAG(MORE); | ||
50 | P_MSG_FLAG(WAITFORONE); | ||
51 | P_MSG_FLAG(SENDPAGE_NOTLAST); | ||
52 | P_MSG_FLAG(FASTOPEN); | ||
53 | P_MSG_FLAG(CMSG_CLOEXEC); | ||
54 | #undef P_MSG_FLAG | ||
55 | |||
56 | if (flags) | ||
57 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
58 | |||
59 | return printed; | ||
60 | } | ||
61 | |||
62 | #define SCA_MSG_FLAGS syscall_arg__scnprintf_msg_flags | ||
diff --git a/tools/perf/trace/beauty/open_flags.c b/tools/perf/trace/beauty/open_flags.c new file mode 100644 index 000000000000..0f3679e0cdcf --- /dev/null +++ b/tools/perf/trace/beauty/open_flags.c | |||
@@ -0,0 +1,56 @@ | |||
1 | |||
2 | static size_t syscall_arg__scnprintf_open_flags(char *bf, size_t size, | ||
3 | struct syscall_arg *arg) | ||
4 | { | ||
5 | int printed = 0, flags = arg->val; | ||
6 | |||
7 | if (!(flags & O_CREAT)) | ||
8 | arg->mask |= 1 << (arg->idx + 1); /* Mask the mode parm */ | ||
9 | |||
10 | if (flags == 0) | ||
11 | return scnprintf(bf, size, "RDONLY"); | ||
12 | #define P_FLAG(n) \ | ||
13 | if (flags & O_##n) { \ | ||
14 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
15 | flags &= ~O_##n; \ | ||
16 | } | ||
17 | |||
18 | P_FLAG(APPEND); | ||
19 | P_FLAG(ASYNC); | ||
20 | P_FLAG(CLOEXEC); | ||
21 | P_FLAG(CREAT); | ||
22 | P_FLAG(DIRECT); | ||
23 | P_FLAG(DIRECTORY); | ||
24 | P_FLAG(EXCL); | ||
25 | P_FLAG(LARGEFILE); | ||
26 | P_FLAG(NOATIME); | ||
27 | P_FLAG(NOCTTY); | ||
28 | #ifdef O_NONBLOCK | ||
29 | P_FLAG(NONBLOCK); | ||
30 | #elif O_NDELAY | ||
31 | P_FLAG(NDELAY); | ||
32 | #endif | ||
33 | #ifdef O_PATH | ||
34 | P_FLAG(PATH); | ||
35 | #endif | ||
36 | P_FLAG(RDWR); | ||
37 | #ifdef O_DSYNC | ||
38 | if ((flags & O_SYNC) == O_SYNC) | ||
39 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", "SYNC"); | ||
40 | else { | ||
41 | P_FLAG(DSYNC); | ||
42 | } | ||
43 | #else | ||
44 | P_FLAG(SYNC); | ||
45 | #endif | ||
46 | P_FLAG(TRUNC); | ||
47 | P_FLAG(WRONLY); | ||
48 | #undef P_FLAG | ||
49 | |||
50 | if (flags) | ||
51 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
52 | |||
53 | return printed; | ||
54 | } | ||
55 | |||
56 | #define SCA_OPEN_FLAGS syscall_arg__scnprintf_open_flags | ||
diff --git a/tools/perf/trace/beauty/perf_event_open.c b/tools/perf/trace/beauty/perf_event_open.c new file mode 100644 index 000000000000..311f09dd718d --- /dev/null +++ b/tools/perf/trace/beauty/perf_event_open.c | |||
@@ -0,0 +1,43 @@ | |||
1 | #ifndef PERF_FLAG_FD_NO_GROUP | ||
2 | # define PERF_FLAG_FD_NO_GROUP (1UL << 0) | ||
3 | #endif | ||
4 | |||
5 | #ifndef PERF_FLAG_FD_OUTPUT | ||
6 | # define PERF_FLAG_FD_OUTPUT (1UL << 1) | ||
7 | #endif | ||
8 | |||
9 | #ifndef PERF_FLAG_PID_CGROUP | ||
10 | # define PERF_FLAG_PID_CGROUP (1UL << 2) /* pid=cgroup id, per-cpu mode only */ | ||
11 | #endif | ||
12 | |||
13 | #ifndef PERF_FLAG_FD_CLOEXEC | ||
14 | # define PERF_FLAG_FD_CLOEXEC (1UL << 3) /* O_CLOEXEC */ | ||
15 | #endif | ||
16 | |||
17 | static size_t syscall_arg__scnprintf_perf_flags(char *bf, size_t size, | ||
18 | struct syscall_arg *arg) | ||
19 | { | ||
20 | int printed = 0, flags = arg->val; | ||
21 | |||
22 | if (flags == 0) | ||
23 | return 0; | ||
24 | |||
25 | #define P_FLAG(n) \ | ||
26 | if (flags & PERF_FLAG_##n) { \ | ||
27 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
28 | flags &= ~PERF_FLAG_##n; \ | ||
29 | } | ||
30 | |||
31 | P_FLAG(FD_NO_GROUP); | ||
32 | P_FLAG(FD_OUTPUT); | ||
33 | P_FLAG(PID_CGROUP); | ||
34 | P_FLAG(FD_CLOEXEC); | ||
35 | #undef P_FLAG | ||
36 | |||
37 | if (flags) | ||
38 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
39 | |||
40 | return printed; | ||
41 | } | ||
42 | |||
43 | #define SCA_PERF_FLAGS syscall_arg__scnprintf_perf_flags | ||
diff --git a/tools/perf/trace/beauty/pid.c b/tools/perf/trace/beauty/pid.c new file mode 100644 index 000000000000..07486ea65ae3 --- /dev/null +++ b/tools/perf/trace/beauty/pid.c | |||
@@ -0,0 +1,21 @@ | |||
1 | static size_t syscall_arg__scnprintf_pid(char *bf, size_t size, struct syscall_arg *arg) | ||
2 | { | ||
3 | int pid = arg->val; | ||
4 | struct trace *trace = arg->trace; | ||
5 | size_t printed = scnprintf(bf, size, "%d", pid); | ||
6 | struct thread *thread = machine__findnew_thread(trace->host, pid, pid); | ||
7 | |||
8 | if (thread != NULL) { | ||
9 | if (!thread->comm_set) | ||
10 | thread__set_comm_from_proc(thread); | ||
11 | |||
12 | if (thread->comm_set) | ||
13 | printed += scnprintf(bf + printed, size - printed, | ||
14 | " (%s)", thread__comm_str(thread)); | ||
15 | thread__put(thread); | ||
16 | } | ||
17 | |||
18 | return printed; | ||
19 | } | ||
20 | |||
21 | #define SCA_PID syscall_arg__scnprintf_pid | ||
diff --git a/tools/perf/trace/beauty/sched_policy.c b/tools/perf/trace/beauty/sched_policy.c new file mode 100644 index 000000000000..c205bc608b3c --- /dev/null +++ b/tools/perf/trace/beauty/sched_policy.c | |||
@@ -0,0 +1,44 @@ | |||
1 | #include <sched.h> | ||
2 | |||
3 | /* | ||
4 | * Not defined anywhere else, probably, just to make sure we | ||
5 | * catch future flags | ||
6 | */ | ||
7 | #define SCHED_POLICY_MASK 0xff | ||
8 | |||
9 | #ifndef SCHED_DEADLINE | ||
10 | #define SCHED_DEADLINE 6 | ||
11 | #endif | ||
12 | |||
13 | static size_t syscall_arg__scnprintf_sched_policy(char *bf, size_t size, | ||
14 | struct syscall_arg *arg) | ||
15 | { | ||
16 | const char *policies[] = { | ||
17 | "NORMAL", "FIFO", "RR", "BATCH", "ISO", "IDLE", "DEADLINE", | ||
18 | }; | ||
19 | size_t printed; | ||
20 | int policy = arg->val, | ||
21 | flags = policy & ~SCHED_POLICY_MASK; | ||
22 | |||
23 | policy &= SCHED_POLICY_MASK; | ||
24 | if (policy <= SCHED_DEADLINE) | ||
25 | printed = scnprintf(bf, size, "%s", policies[policy]); | ||
26 | else | ||
27 | printed = scnprintf(bf, size, "%#x", policy); | ||
28 | |||
29 | #define P_POLICY_FLAG(n) \ | ||
30 | if (flags & SCHED_##n) { \ | ||
31 | printed += scnprintf(bf + printed, size - printed, "|%s", #n); \ | ||
32 | flags &= ~SCHED_##n; \ | ||
33 | } | ||
34 | |||
35 | P_POLICY_FLAG(RESET_ON_FORK); | ||
36 | #undef P_POLICY_FLAG | ||
37 | |||
38 | if (flags) | ||
39 | printed += scnprintf(bf + printed, size - printed, "|%#x", flags); | ||
40 | |||
41 | return printed; | ||
42 | } | ||
43 | |||
44 | #define SCA_SCHED_POLICY syscall_arg__scnprintf_sched_policy | ||
diff --git a/tools/perf/trace/beauty/seccomp.c b/tools/perf/trace/beauty/seccomp.c new file mode 100644 index 000000000000..213c5a7e3e92 --- /dev/null +++ b/tools/perf/trace/beauty/seccomp.c | |||
@@ -0,0 +1,52 @@ | |||
1 | #include <linux/seccomp.h> | ||
2 | |||
3 | #ifndef SECCOMP_SET_MODE_STRICT | ||
4 | #define SECCOMP_SET_MODE_STRICT 0 | ||
5 | #endif | ||
6 | #ifndef SECCOMP_SET_MODE_FILTER | ||
7 | #define SECCOMP_SET_MODE_FILTER 1 | ||
8 | #endif | ||
9 | |||
10 | static size_t syscall_arg__scnprintf_seccomp_op(char *bf, size_t size, struct syscall_arg *arg) | ||
11 | { | ||
12 | int op = arg->val; | ||
13 | size_t printed = 0; | ||
14 | |||
15 | switch (op) { | ||
16 | #define P_SECCOMP_SET_MODE_OP(n) case SECCOMP_SET_MODE_##n: printed = scnprintf(bf, size, #n); break | ||
17 | P_SECCOMP_SET_MODE_OP(STRICT); | ||
18 | P_SECCOMP_SET_MODE_OP(FILTER); | ||
19 | #undef P_SECCOMP_SET_MODE_OP | ||
20 | default: printed = scnprintf(bf, size, "%#x", op); break; | ||
21 | } | ||
22 | |||
23 | return printed; | ||
24 | } | ||
25 | |||
26 | #define SCA_SECCOMP_OP syscall_arg__scnprintf_seccomp_op | ||
27 | |||
28 | #ifndef SECCOMP_FILTER_FLAG_TSYNC | ||
29 | #define SECCOMP_FILTER_FLAG_TSYNC 1 | ||
30 | #endif | ||
31 | |||
32 | static size_t syscall_arg__scnprintf_seccomp_flags(char *bf, size_t size, | ||
33 | struct syscall_arg *arg) | ||
34 | { | ||
35 | int printed = 0, flags = arg->val; | ||
36 | |||
37 | #define P_FLAG(n) \ | ||
38 | if (flags & SECCOMP_FILTER_FLAG_##n) { \ | ||
39 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
40 | flags &= ~SECCOMP_FILTER_FLAG_##n; \ | ||
41 | } | ||
42 | |||
43 | P_FLAG(TSYNC); | ||
44 | #undef P_FLAG | ||
45 | |||
46 | if (flags) | ||
47 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", flags); | ||
48 | |||
49 | return printed; | ||
50 | } | ||
51 | |||
52 | #define SCA_SECCOMP_FLAGS syscall_arg__scnprintf_seccomp_flags | ||
diff --git a/tools/perf/trace/beauty/signum.c b/tools/perf/trace/beauty/signum.c new file mode 100644 index 000000000000..d3b0b1fab077 --- /dev/null +++ b/tools/perf/trace/beauty/signum.c | |||
@@ -0,0 +1,53 @@ | |||
1 | |||
2 | static size_t syscall_arg__scnprintf_signum(char *bf, size_t size, struct syscall_arg *arg) | ||
3 | { | ||
4 | int sig = arg->val; | ||
5 | |||
6 | switch (sig) { | ||
7 | #define P_SIGNUM(n) case SIG##n: return scnprintf(bf, size, #n) | ||
8 | P_SIGNUM(HUP); | ||
9 | P_SIGNUM(INT); | ||
10 | P_SIGNUM(QUIT); | ||
11 | P_SIGNUM(ILL); | ||
12 | P_SIGNUM(TRAP); | ||
13 | P_SIGNUM(ABRT); | ||
14 | P_SIGNUM(BUS); | ||
15 | P_SIGNUM(FPE); | ||
16 | P_SIGNUM(KILL); | ||
17 | P_SIGNUM(USR1); | ||
18 | P_SIGNUM(SEGV); | ||
19 | P_SIGNUM(USR2); | ||
20 | P_SIGNUM(PIPE); | ||
21 | P_SIGNUM(ALRM); | ||
22 | P_SIGNUM(TERM); | ||
23 | P_SIGNUM(CHLD); | ||
24 | P_SIGNUM(CONT); | ||
25 | P_SIGNUM(STOP); | ||
26 | P_SIGNUM(TSTP); | ||
27 | P_SIGNUM(TTIN); | ||
28 | P_SIGNUM(TTOU); | ||
29 | P_SIGNUM(URG); | ||
30 | P_SIGNUM(XCPU); | ||
31 | P_SIGNUM(XFSZ); | ||
32 | P_SIGNUM(VTALRM); | ||
33 | P_SIGNUM(PROF); | ||
34 | P_SIGNUM(WINCH); | ||
35 | P_SIGNUM(IO); | ||
36 | P_SIGNUM(PWR); | ||
37 | P_SIGNUM(SYS); | ||
38 | #ifdef SIGEMT | ||
39 | P_SIGNUM(EMT); | ||
40 | #endif | ||
41 | #ifdef SIGSTKFLT | ||
42 | P_SIGNUM(STKFLT); | ||
43 | #endif | ||
44 | #ifdef SIGSWI | ||
45 | P_SIGNUM(SWI); | ||
46 | #endif | ||
47 | default: break; | ||
48 | } | ||
49 | |||
50 | return scnprintf(bf, size, "%#x", sig); | ||
51 | } | ||
52 | |||
53 | #define SCA_SIGNUM syscall_arg__scnprintf_signum | ||
diff --git a/tools/perf/trace/beauty/socket_type.c b/tools/perf/trace/beauty/socket_type.c new file mode 100644 index 000000000000..0a5ce818131c --- /dev/null +++ b/tools/perf/trace/beauty/socket_type.c | |||
@@ -0,0 +1,60 @@ | |||
1 | #include <sys/types.h> | ||
2 | #include <sys/socket.h> | ||
3 | |||
4 | #ifndef SOCK_DCCP | ||
5 | # define SOCK_DCCP 6 | ||
6 | #endif | ||
7 | |||
8 | #ifndef SOCK_CLOEXEC | ||
9 | # define SOCK_CLOEXEC 02000000 | ||
10 | #endif | ||
11 | |||
12 | #ifndef SOCK_NONBLOCK | ||
13 | # define SOCK_NONBLOCK 00004000 | ||
14 | #endif | ||
15 | |||
16 | #ifndef SOCK_TYPE_MASK | ||
17 | #define SOCK_TYPE_MASK 0xf | ||
18 | #endif | ||
19 | |||
20 | static size_t syscall_arg__scnprintf_socket_type(char *bf, size_t size, struct syscall_arg *arg) | ||
21 | { | ||
22 | size_t printed; | ||
23 | int type = arg->val, | ||
24 | flags = type & ~SOCK_TYPE_MASK; | ||
25 | |||
26 | type &= SOCK_TYPE_MASK; | ||
27 | /* | ||
28 | * Can't use a strarray, MIPS may override for ABI reasons. | ||
29 | */ | ||
30 | switch (type) { | ||
31 | #define P_SK_TYPE(n) case SOCK_##n: printed = scnprintf(bf, size, #n); break; | ||
32 | P_SK_TYPE(STREAM); | ||
33 | P_SK_TYPE(DGRAM); | ||
34 | P_SK_TYPE(RAW); | ||
35 | P_SK_TYPE(RDM); | ||
36 | P_SK_TYPE(SEQPACKET); | ||
37 | P_SK_TYPE(DCCP); | ||
38 | P_SK_TYPE(PACKET); | ||
39 | #undef P_SK_TYPE | ||
40 | default: | ||
41 | printed = scnprintf(bf, size, "%#x", type); | ||
42 | } | ||
43 | |||
44 | #define P_SK_FLAG(n) \ | ||
45 | if (flags & SOCK_##n) { \ | ||
46 | printed += scnprintf(bf + printed, size - printed, "|%s", #n); \ | ||
47 | flags &= ~SOCK_##n; \ | ||
48 | } | ||
49 | |||
50 | P_SK_FLAG(CLOEXEC); | ||
51 | P_SK_FLAG(NONBLOCK); | ||
52 | #undef P_SK_FLAG | ||
53 | |||
54 | if (flags) | ||
55 | printed += scnprintf(bf + printed, size - printed, "|%#x", flags); | ||
56 | |||
57 | return printed; | ||
58 | } | ||
59 | |||
60 | #define SCA_SK_TYPE syscall_arg__scnprintf_socket_type | ||
diff --git a/tools/perf/trace/beauty/waitid_options.c b/tools/perf/trace/beauty/waitid_options.c new file mode 100644 index 000000000000..7942724adec8 --- /dev/null +++ b/tools/perf/trace/beauty/waitid_options.c | |||
@@ -0,0 +1,26 @@ | |||
1 | #include <sys/types.h> | ||
2 | #include <sys/wait.h> | ||
3 | |||
4 | static size_t syscall_arg__scnprintf_waitid_options(char *bf, size_t size, | ||
5 | struct syscall_arg *arg) | ||
6 | { | ||
7 | int printed = 0, options = arg->val; | ||
8 | |||
9 | #define P_OPTION(n) \ | ||
10 | if (options & W##n) { \ | ||
11 | printed += scnprintf(bf + printed, size - printed, "%s%s", printed ? "|" : "", #n); \ | ||
12 | options &= ~W##n; \ | ||
13 | } | ||
14 | |||
15 | P_OPTION(NOHANG); | ||
16 | P_OPTION(UNTRACED); | ||
17 | P_OPTION(CONTINUED); | ||
18 | #undef P_OPTION | ||
19 | |||
20 | if (options) | ||
21 | printed += scnprintf(bf + printed, size - printed, "%s%#x", printed ? "|" : "", options); | ||
22 | |||
23 | return printed; | ||
24 | } | ||
25 | |||
26 | #define SCA_WAITID_OPTIONS syscall_arg__scnprintf_waitid_options | ||
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 2a83414159a6..538bae880bfe 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -1607,9 +1607,8 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows | |||
1607 | 1607 | ||
1608 | ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); | 1608 | ret = fmt->header(fmt, &dummy_hpp, hists_to_evsel(hists)); |
1609 | dummy_hpp.buf[ret] = '\0'; | 1609 | dummy_hpp.buf[ret] = '\0'; |
1610 | rtrim(dummy_hpp.buf); | ||
1611 | 1610 | ||
1612 | start = ltrim(dummy_hpp.buf); | 1611 | start = trim(dummy_hpp.buf); |
1613 | ret = strlen(start); | 1612 | ret = strlen(start); |
1614 | 1613 | ||
1615 | if (start != dummy_hpp.buf) | 1614 | if (start != dummy_hpp.buf) |
@@ -1897,11 +1896,10 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser, | |||
1897 | bool first = true; | 1896 | bool first = true; |
1898 | int ret; | 1897 | int ret; |
1899 | 1898 | ||
1900 | if (symbol_conf.use_callchain) | 1899 | if (symbol_conf.use_callchain) { |
1901 | folded_sign = hist_entry__folded(he); | 1900 | folded_sign = hist_entry__folded(he); |
1902 | |||
1903 | if (symbol_conf.use_callchain) | ||
1904 | printed += fprintf(fp, "%c ", folded_sign); | 1901 | printed += fprintf(fp, "%c ", folded_sign); |
1902 | } | ||
1905 | 1903 | ||
1906 | hists__for_each_format(browser->hists, fmt) { | 1904 | hists__for_each_format(browser->hists, fmt) { |
1907 | if (perf_hpp__should_skip(fmt, he->hists)) | 1905 | if (perf_hpp__should_skip(fmt, he->hists)) |
@@ -2137,7 +2135,7 @@ static int hists__browser_title(struct hists *hists, | |||
2137 | printed += snprintf(bf + printed, size - printed, | 2135 | printed += snprintf(bf + printed, size - printed, |
2138 | ", UID: %s", hists->uid_filter_str); | 2136 | ", UID: %s", hists->uid_filter_str); |
2139 | if (thread) { | 2137 | if (thread) { |
2140 | if (sort__has_thread) { | 2138 | if (hists__has(hists, thread)) { |
2141 | printed += scnprintf(bf + printed, size - printed, | 2139 | printed += scnprintf(bf + printed, size - printed, |
2142 | ", Thread: %s(%d)", | 2140 | ", Thread: %s(%d)", |
2143 | (thread->comm_set ? thread__comm_str(thread) : ""), | 2141 | (thread->comm_set ? thread__comm_str(thread) : ""), |
@@ -2322,7 +2320,8 @@ do_zoom_thread(struct hist_browser *browser, struct popup_action *act) | |||
2322 | { | 2320 | { |
2323 | struct thread *thread = act->thread; | 2321 | struct thread *thread = act->thread; |
2324 | 2322 | ||
2325 | if ((!sort__has_thread && !sort__has_comm) || thread == NULL) | 2323 | if ((!hists__has(browser->hists, thread) && |
2324 | !hists__has(browser->hists, comm)) || thread == NULL) | ||
2326 | return 0; | 2325 | return 0; |
2327 | 2326 | ||
2328 | if (browser->hists->thread_filter) { | 2327 | if (browser->hists->thread_filter) { |
@@ -2331,7 +2330,7 @@ do_zoom_thread(struct hist_browser *browser, struct popup_action *act) | |||
2331 | thread__zput(browser->hists->thread_filter); | 2330 | thread__zput(browser->hists->thread_filter); |
2332 | ui_helpline__pop(); | 2331 | ui_helpline__pop(); |
2333 | } else { | 2332 | } else { |
2334 | if (sort__has_thread) { | 2333 | if (hists__has(browser->hists, thread)) { |
2335 | ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"", | 2334 | ui_helpline__fpush("To zoom out press ESC or ENTER + \"Zoom out of %s(%d) thread\"", |
2336 | thread->comm_set ? thread__comm_str(thread) : "", | 2335 | thread->comm_set ? thread__comm_str(thread) : "", |
2337 | thread->tid); | 2336 | thread->tid); |
@@ -2356,10 +2355,11 @@ add_thread_opt(struct hist_browser *browser, struct popup_action *act, | |||
2356 | { | 2355 | { |
2357 | int ret; | 2356 | int ret; |
2358 | 2357 | ||
2359 | if ((!sort__has_thread && !sort__has_comm) || thread == NULL) | 2358 | if ((!hists__has(browser->hists, thread) && |
2359 | !hists__has(browser->hists, comm)) || thread == NULL) | ||
2360 | return 0; | 2360 | return 0; |
2361 | 2361 | ||
2362 | if (sort__has_thread) { | 2362 | if (hists__has(browser->hists, thread)) { |
2363 | ret = asprintf(optstr, "Zoom %s %s(%d) thread", | 2363 | ret = asprintf(optstr, "Zoom %s %s(%d) thread", |
2364 | browser->hists->thread_filter ? "out of" : "into", | 2364 | browser->hists->thread_filter ? "out of" : "into", |
2365 | thread->comm_set ? thread__comm_str(thread) : "", | 2365 | thread->comm_set ? thread__comm_str(thread) : "", |
@@ -2382,7 +2382,7 @@ do_zoom_dso(struct hist_browser *browser, struct popup_action *act) | |||
2382 | { | 2382 | { |
2383 | struct map *map = act->ms.map; | 2383 | struct map *map = act->ms.map; |
2384 | 2384 | ||
2385 | if (!sort__has_dso || map == NULL) | 2385 | if (!hists__has(browser->hists, dso) || map == NULL) |
2386 | return 0; | 2386 | return 0; |
2387 | 2387 | ||
2388 | if (browser->hists->dso_filter) { | 2388 | if (browser->hists->dso_filter) { |
@@ -2409,7 +2409,7 @@ static int | |||
2409 | add_dso_opt(struct hist_browser *browser, struct popup_action *act, | 2409 | add_dso_opt(struct hist_browser *browser, struct popup_action *act, |
2410 | char **optstr, struct map *map) | 2410 | char **optstr, struct map *map) |
2411 | { | 2411 | { |
2412 | if (!sort__has_dso || map == NULL) | 2412 | if (!hists__has(browser->hists, dso) || map == NULL) |
2413 | return 0; | 2413 | return 0; |
2414 | 2414 | ||
2415 | if (asprintf(optstr, "Zoom %s %s DSO", | 2415 | if (asprintf(optstr, "Zoom %s %s DSO", |
@@ -2431,10 +2431,10 @@ do_browse_map(struct hist_browser *browser __maybe_unused, | |||
2431 | } | 2431 | } |
2432 | 2432 | ||
2433 | static int | 2433 | static int |
2434 | add_map_opt(struct hist_browser *browser __maybe_unused, | 2434 | add_map_opt(struct hist_browser *browser, |
2435 | struct popup_action *act, char **optstr, struct map *map) | 2435 | struct popup_action *act, char **optstr, struct map *map) |
2436 | { | 2436 | { |
2437 | if (!sort__has_dso || map == NULL) | 2437 | if (!hists__has(browser->hists, dso) || map == NULL) |
2438 | return 0; | 2438 | return 0; |
2439 | 2439 | ||
2440 | if (asprintf(optstr, "Browse map details") < 0) | 2440 | if (asprintf(optstr, "Browse map details") < 0) |
@@ -2536,7 +2536,7 @@ add_exit_opt(struct hist_browser *browser __maybe_unused, | |||
2536 | static int | 2536 | static int |
2537 | do_zoom_socket(struct hist_browser *browser, struct popup_action *act) | 2537 | do_zoom_socket(struct hist_browser *browser, struct popup_action *act) |
2538 | { | 2538 | { |
2539 | if (!sort__has_socket || act->socket < 0) | 2539 | if (!hists__has(browser->hists, socket) || act->socket < 0) |
2540 | return 0; | 2540 | return 0; |
2541 | 2541 | ||
2542 | if (browser->hists->socket_filter > -1) { | 2542 | if (browser->hists->socket_filter > -1) { |
@@ -2558,7 +2558,7 @@ static int | |||
2558 | add_socket_opt(struct hist_browser *browser, struct popup_action *act, | 2558 | add_socket_opt(struct hist_browser *browser, struct popup_action *act, |
2559 | char **optstr, int socket_id) | 2559 | char **optstr, int socket_id) |
2560 | { | 2560 | { |
2561 | if (!sort__has_socket || socket_id < 0) | 2561 | if (!hists__has(browser->hists, socket) || socket_id < 0) |
2562 | return 0; | 2562 | return 0; |
2563 | 2563 | ||
2564 | if (asprintf(optstr, "Zoom %s Processor Socket %d", | 2564 | if (asprintf(optstr, "Zoom %s Processor Socket %d", |
@@ -2749,7 +2749,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
2749 | */ | 2749 | */ |
2750 | goto out_free_stack; | 2750 | goto out_free_stack; |
2751 | case 'a': | 2751 | case 'a': |
2752 | if (!sort__has_sym) { | 2752 | if (!hists__has(hists, sym)) { |
2753 | ui_browser__warning(&browser->b, delay_secs * 2, | 2753 | ui_browser__warning(&browser->b, delay_secs * 2, |
2754 | "Annotation is only available for symbolic views, " | 2754 | "Annotation is only available for symbolic views, " |
2755 | "include \"sym*\" in --sort to use it."); | 2755 | "include \"sym*\" in --sort to use it."); |
@@ -2912,7 +2912,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
2912 | continue; | 2912 | continue; |
2913 | } | 2913 | } |
2914 | 2914 | ||
2915 | if (!sort__has_sym || browser->selection == NULL) | 2915 | if (!hists__has(hists, sym) || browser->selection == NULL) |
2916 | goto skip_annotation; | 2916 | goto skip_annotation; |
2917 | 2917 | ||
2918 | if (sort__mode == SORT_MODE__BRANCH) { | 2918 | if (sort__mode == SORT_MODE__BRANCH) { |
@@ -2956,7 +2956,7 @@ skip_annotation: | |||
2956 | goto skip_scripting; | 2956 | goto skip_scripting; |
2957 | 2957 | ||
2958 | if (browser->he_selection) { | 2958 | if (browser->he_selection) { |
2959 | if (sort__has_thread && thread) { | 2959 | if (hists__has(hists, thread) && thread) { |
2960 | nr_options += add_script_opt(browser, | 2960 | nr_options += add_script_opt(browser, |
2961 | &actions[nr_options], | 2961 | &actions[nr_options], |
2962 | &options[nr_options], | 2962 | &options[nr_options], |
@@ -2971,7 +2971,7 @@ skip_annotation: | |||
2971 | * | 2971 | * |
2972 | * See hist_browser__show_entry. | 2972 | * See hist_browser__show_entry. |
2973 | */ | 2973 | */ |
2974 | if (sort__has_sym && browser->selection->sym) { | 2974 | if (hists__has(hists, sym) && browser->selection->sym) { |
2975 | nr_options += add_script_opt(browser, | 2975 | nr_options += add_script_opt(browser, |
2976 | &actions[nr_options], | 2976 | &actions[nr_options], |
2977 | &options[nr_options], | 2977 | &options[nr_options], |
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index 2aa45b606fa4..932adfaa05af 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c | |||
@@ -379,7 +379,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, | |||
379 | gtk_tree_store_set(store, &iter, col_idx++, s, -1); | 379 | gtk_tree_store_set(store, &iter, col_idx++, s, -1); |
380 | } | 380 | } |
381 | 381 | ||
382 | if (symbol_conf.use_callchain && sort__has_sym) { | 382 | if (symbol_conf.use_callchain && hists__has(hists, sym)) { |
383 | if (callchain_param.mode == CHAIN_GRAPH_REL) | 383 | if (callchain_param.mode == CHAIN_GRAPH_REL) |
384 | total = symbol_conf.cumulate_callchain ? | 384 | total = symbol_conf.cumulate_callchain ? |
385 | h->stat_acc->period : h->stat.period; | 385 | h->stat_acc->period : h->stat.period; |
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 3baeaa6e71b5..af07ffb129ca 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c | |||
@@ -635,7 +635,7 @@ unsigned int hists__sort_list_width(struct hists *hists) | |||
635 | ret += fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists)); | 635 | ret += fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists)); |
636 | } | 636 | } |
637 | 637 | ||
638 | if (verbose && sort__has_sym) /* Addr + origin */ | 638 | if (verbose && hists__has(hists, sym)) /* Addr + origin */ |
639 | ret += 3 + BITS_PER_LONG / 4; | 639 | ret += 3 + BITS_PER_LONG / 4; |
640 | 640 | ||
641 | return ret; | 641 | return ret; |
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index 7aff5acf3265..560eb47d56f9 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c | |||
@@ -569,9 +569,8 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp, | |||
569 | first_col = false; | 569 | first_col = false; |
570 | 570 | ||
571 | fmt->header(fmt, hpp, hists_to_evsel(hists)); | 571 | fmt->header(fmt, hpp, hists_to_evsel(hists)); |
572 | rtrim(hpp->buf); | ||
573 | 572 | ||
574 | header_width += fprintf(fp, "%s", ltrim(hpp->buf)); | 573 | header_width += fprintf(fp, "%s", trim(hpp->buf)); |
575 | } | 574 | } |
576 | } | 575 | } |
577 | 576 | ||
diff --git a/tools/perf/util/Build b/tools/perf/util/Build index da48fd843438..8c6c8a0ca642 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build | |||
@@ -8,6 +8,7 @@ libperf-y += env.o | |||
8 | libperf-y += event.o | 8 | libperf-y += event.o |
9 | libperf-y += evlist.o | 9 | libperf-y += evlist.o |
10 | libperf-y += evsel.o | 10 | libperf-y += evsel.o |
11 | libperf-y += evsel_fprintf.o | ||
11 | libperf-y += find_bit.o | 12 | libperf-y += find_bit.o |
12 | libperf-y += kallsyms.o | 13 | libperf-y += kallsyms.o |
13 | libperf-y += levenshtein.o | 14 | libperf-y += levenshtein.o |
@@ -26,9 +27,9 @@ libperf-y += strlist.o | |||
26 | libperf-y += strfilter.o | 27 | libperf-y += strfilter.o |
27 | libperf-y += top.o | 28 | libperf-y += top.o |
28 | libperf-y += usage.o | 29 | libperf-y += usage.o |
29 | libperf-y += wrapper.o | ||
30 | libperf-y += dso.o | 30 | libperf-y += dso.o |
31 | libperf-y += symbol.o | 31 | libperf-y += symbol.o |
32 | libperf-y += symbol_fprintf.o | ||
32 | libperf-y += color.o | 33 | libperf-y += color.o |
33 | libperf-y += header.o | 34 | libperf-y += header.o |
34 | libperf-y += callchain.o | 35 | libperf-y += callchain.o |
@@ -38,6 +39,7 @@ libperf-y += machine.o | |||
38 | libperf-y += map.o | 39 | libperf-y += map.o |
39 | libperf-y += pstack.o | 40 | libperf-y += pstack.o |
40 | libperf-y += session.o | 41 | libperf-y += session.o |
42 | libperf-$(CONFIG_AUDIT) += syscalltbl.o | ||
41 | libperf-y += ordered-events.o | 43 | libperf-y += ordered-events.o |
42 | libperf-y += comm.o | 44 | libperf-y += comm.o |
43 | libperf-y += thread.o | 45 | libperf-y += thread.o |
@@ -69,9 +71,9 @@ libperf-y += stat-shadow.o | |||
69 | libperf-y += record.o | 71 | libperf-y += record.o |
70 | libperf-y += srcline.o | 72 | libperf-y += srcline.o |
71 | libperf-y += data.o | 73 | libperf-y += data.o |
72 | libperf-$(CONFIG_X86) += tsc.o | 74 | libperf-y += tsc.o |
73 | libperf-$(CONFIG_AUXTRACE) += tsc.o | ||
74 | libperf-y += cloexec.o | 75 | libperf-y += cloexec.o |
76 | libperf-y += call-path.o | ||
75 | libperf-y += thread-stack.o | 77 | libperf-y += thread-stack.o |
76 | libperf-$(CONFIG_AUXTRACE) += auxtrace.o | 78 | libperf-$(CONFIG_AUXTRACE) += auxtrace.o |
77 | libperf-$(CONFIG_AUXTRACE) += intel-pt-decoder/ | 79 | libperf-$(CONFIG_AUXTRACE) += intel-pt-decoder/ |
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index b795b6994144..4db73d5a0dbc 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -1138,7 +1138,7 @@ fallback: | |||
1138 | 1138 | ||
1139 | if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && | 1139 | if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS && |
1140 | !dso__is_kcore(dso)) { | 1140 | !dso__is_kcore(dso)) { |
1141 | char bf[BUILD_ID_SIZE * 2 + 16] = " with build id "; | 1141 | char bf[SBUILD_ID_SIZE + 15] = " with build id "; |
1142 | char *build_id_msg = NULL; | 1142 | char *build_id_msg = NULL; |
1143 | 1143 | ||
1144 | if (dso->annotate_warned) | 1144 | if (dso->annotate_warned) |
@@ -1665,5 +1665,5 @@ int hist_entry__annotate(struct hist_entry *he, size_t privsize) | |||
1665 | 1665 | ||
1666 | bool ui__has_annotation(void) | 1666 | bool ui__has_annotation(void) |
1667 | { | 1667 | { |
1668 | return use_browser == 1 && sort__has_sym; | 1668 | return use_browser == 1 && perf_hpp_list.sym; |
1669 | } | 1669 | } |
diff --git a/tools/perf/util/auxtrace.c b/tools/perf/util/auxtrace.c index ec164fe70718..c9169011e55e 100644 --- a/tools/perf/util/auxtrace.c +++ b/tools/perf/util/auxtrace.c | |||
@@ -940,6 +940,7 @@ void itrace_synth_opts__set_default(struct itrace_synth_opts *synth_opts) | |||
940 | synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; | 940 | synth_opts->period = PERF_ITRACE_DEFAULT_PERIOD; |
941 | synth_opts->callchain_sz = PERF_ITRACE_DEFAULT_CALLCHAIN_SZ; | 941 | synth_opts->callchain_sz = PERF_ITRACE_DEFAULT_CALLCHAIN_SZ; |
942 | synth_opts->last_branch_sz = PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ; | 942 | synth_opts->last_branch_sz = PERF_ITRACE_DEFAULT_LAST_BRANCH_SZ; |
943 | synth_opts->initial_skip = 0; | ||
943 | } | 944 | } |
944 | 945 | ||
945 | /* | 946 | /* |
@@ -1064,6 +1065,12 @@ int itrace_parse_synth_opts(const struct option *opt, const char *str, | |||
1064 | synth_opts->last_branch_sz = val; | 1065 | synth_opts->last_branch_sz = val; |
1065 | } | 1066 | } |
1066 | break; | 1067 | break; |
1068 | case 's': | ||
1069 | synth_opts->initial_skip = strtoul(p, &endptr, 10); | ||
1070 | if (p == endptr) | ||
1071 | goto out_err; | ||
1072 | p = endptr; | ||
1073 | break; | ||
1067 | case ' ': | 1074 | case ' ': |
1068 | case ',': | 1075 | case ',': |
1069 | break; | 1076 | break; |
diff --git a/tools/perf/util/auxtrace.h b/tools/perf/util/auxtrace.h index 57ff31ecb8e4..767989e0e312 100644 --- a/tools/perf/util/auxtrace.h +++ b/tools/perf/util/auxtrace.h | |||
@@ -68,6 +68,7 @@ enum itrace_period_type { | |||
68 | * @last_branch_sz: branch context size | 68 | * @last_branch_sz: branch context size |
69 | * @period: 'instructions' events period | 69 | * @period: 'instructions' events period |
70 | * @period_type: 'instructions' events period type | 70 | * @period_type: 'instructions' events period type |
71 | * @initial_skip: skip N events at the beginning. | ||
71 | */ | 72 | */ |
72 | struct itrace_synth_opts { | 73 | struct itrace_synth_opts { |
73 | bool set; | 74 | bool set; |
@@ -86,6 +87,7 @@ struct itrace_synth_opts { | |||
86 | unsigned int last_branch_sz; | 87 | unsigned int last_branch_sz; |
87 | unsigned long long period; | 88 | unsigned long long period; |
88 | enum itrace_period_type period_type; | 89 | enum itrace_period_type period_type; |
90 | unsigned long initial_skip; | ||
89 | }; | 91 | }; |
90 | 92 | ||
91 | /** | 93 | /** |
diff --git a/tools/perf/util/bpf-loader.c b/tools/perf/util/bpf-loader.c index 0967ce601931..493307d1414c 100644 --- a/tools/perf/util/bpf-loader.c +++ b/tools/perf/util/bpf-loader.c | |||
@@ -842,6 +842,58 @@ bpf_map_op__new(struct parse_events_term *term) | |||
842 | return op; | 842 | return op; |
843 | } | 843 | } |
844 | 844 | ||
845 | static struct bpf_map_op * | ||
846 | bpf_map_op__clone(struct bpf_map_op *op) | ||
847 | { | ||
848 | struct bpf_map_op *newop; | ||
849 | |||
850 | newop = memdup(op, sizeof(*op)); | ||
851 | if (!newop) { | ||
852 | pr_debug("Failed to alloc bpf_map_op\n"); | ||
853 | return NULL; | ||
854 | } | ||
855 | |||
856 | INIT_LIST_HEAD(&newop->list); | ||
857 | if (op->key_type == BPF_MAP_KEY_RANGES) { | ||
858 | size_t memsz = op->k.array.nr_ranges * | ||
859 | sizeof(op->k.array.ranges[0]); | ||
860 | |||
861 | newop->k.array.ranges = memdup(op->k.array.ranges, memsz); | ||
862 | if (!newop->k.array.ranges) { | ||
863 | pr_debug("Failed to alloc indices for map\n"); | ||
864 | free(newop); | ||
865 | return NULL; | ||
866 | } | ||
867 | } | ||
868 | |||
869 | return newop; | ||
870 | } | ||
871 | |||
872 | static struct bpf_map_priv * | ||
873 | bpf_map_priv__clone(struct bpf_map_priv *priv) | ||
874 | { | ||
875 | struct bpf_map_priv *newpriv; | ||
876 | struct bpf_map_op *pos, *newop; | ||
877 | |||
878 | newpriv = zalloc(sizeof(*newpriv)); | ||
879 | if (!newpriv) { | ||
880 | pr_debug("No enough memory to alloc map private\n"); | ||
881 | return NULL; | ||
882 | } | ||
883 | INIT_LIST_HEAD(&newpriv->ops_list); | ||
884 | |||
885 | list_for_each_entry(pos, &priv->ops_list, list) { | ||
886 | newop = bpf_map_op__clone(pos); | ||
887 | if (!newop) { | ||
888 | bpf_map_priv__purge(newpriv); | ||
889 | return NULL; | ||
890 | } | ||
891 | list_add_tail(&newop->list, &newpriv->ops_list); | ||
892 | } | ||
893 | |||
894 | return newpriv; | ||
895 | } | ||
896 | |||
845 | static int | 897 | static int |
846 | bpf_map__add_op(struct bpf_map *map, struct bpf_map_op *op) | 898 | bpf_map__add_op(struct bpf_map *map, struct bpf_map_op *op) |
847 | { | 899 | { |
@@ -1417,6 +1469,89 @@ int bpf__apply_obj_config(void) | |||
1417 | return 0; | 1469 | return 0; |
1418 | } | 1470 | } |
1419 | 1471 | ||
1472 | #define bpf__for_each_map(pos, obj, objtmp) \ | ||
1473 | bpf_object__for_each_safe(obj, objtmp) \ | ||
1474 | bpf_map__for_each(pos, obj) | ||
1475 | |||
1476 | #define bpf__for_each_stdout_map(pos, obj, objtmp) \ | ||
1477 | bpf__for_each_map(pos, obj, objtmp) \ | ||
1478 | if (bpf_map__get_name(pos) && \ | ||
1479 | (strcmp("__bpf_stdout__", \ | ||
1480 | bpf_map__get_name(pos)) == 0)) | ||
1481 | |||
1482 | int bpf__setup_stdout(struct perf_evlist *evlist __maybe_unused) | ||
1483 | { | ||
1484 | struct bpf_map_priv *tmpl_priv = NULL; | ||
1485 | struct bpf_object *obj, *tmp; | ||
1486 | struct perf_evsel *evsel = NULL; | ||
1487 | struct bpf_map *map; | ||
1488 | int err; | ||
1489 | bool need_init = false; | ||
1490 | |||
1491 | bpf__for_each_stdout_map(map, obj, tmp) { | ||
1492 | struct bpf_map_priv *priv; | ||
1493 | |||
1494 | err = bpf_map__get_private(map, (void **)&priv); | ||
1495 | if (err) | ||
1496 | return -BPF_LOADER_ERRNO__INTERNAL; | ||
1497 | |||
1498 | /* | ||
1499 | * No need to check map type: type should have been | ||
1500 | * verified by kernel. | ||
1501 | */ | ||
1502 | if (!need_init && !priv) | ||
1503 | need_init = !priv; | ||
1504 | if (!tmpl_priv && priv) | ||
1505 | tmpl_priv = priv; | ||
1506 | } | ||
1507 | |||
1508 | if (!need_init) | ||
1509 | return 0; | ||
1510 | |||
1511 | if (!tmpl_priv) { | ||
1512 | err = parse_events(evlist, "bpf-output/no-inherit=1,name=__bpf_stdout__/", | ||
1513 | NULL); | ||
1514 | if (err) { | ||
1515 | pr_debug("ERROR: failed to create bpf-output event\n"); | ||
1516 | return -err; | ||
1517 | } | ||
1518 | |||
1519 | evsel = perf_evlist__last(evlist); | ||
1520 | } | ||
1521 | |||
1522 | bpf__for_each_stdout_map(map, obj, tmp) { | ||
1523 | struct bpf_map_priv *priv; | ||
1524 | |||
1525 | err = bpf_map__get_private(map, (void **)&priv); | ||
1526 | if (err) | ||
1527 | return -BPF_LOADER_ERRNO__INTERNAL; | ||
1528 | if (priv) | ||
1529 | continue; | ||
1530 | |||
1531 | if (tmpl_priv) { | ||
1532 | priv = bpf_map_priv__clone(tmpl_priv); | ||
1533 | if (!priv) | ||
1534 | return -ENOMEM; | ||
1535 | |||
1536 | err = bpf_map__set_private(map, priv, bpf_map_priv__clear); | ||
1537 | if (err) { | ||
1538 | bpf_map_priv__clear(map, priv); | ||
1539 | return err; | ||
1540 | } | ||
1541 | } else if (evsel) { | ||
1542 | struct bpf_map_op *op; | ||
1543 | |||
1544 | op = bpf_map__add_newop(map, NULL); | ||
1545 | if (IS_ERR(op)) | ||
1546 | return PTR_ERR(op); | ||
1547 | op->op_type = BPF_MAP_OP_SET_EVSEL; | ||
1548 | op->v.evsel = evsel; | ||
1549 | } | ||
1550 | } | ||
1551 | |||
1552 | return 0; | ||
1553 | } | ||
1554 | |||
1420 | #define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START) | 1555 | #define ERRNO_OFFSET(e) ((e) - __BPF_LOADER_ERRNO__START) |
1421 | #define ERRCODE_OFFSET(c) ERRNO_OFFSET(BPF_LOADER_ERRNO__##c) | 1556 | #define ERRCODE_OFFSET(c) ERRNO_OFFSET(BPF_LOADER_ERRNO__##c) |
1422 | #define NR_ERRNO (__BPF_LOADER_ERRNO__END - __BPF_LOADER_ERRNO__START) | 1557 | #define NR_ERRNO (__BPF_LOADER_ERRNO__END - __BPF_LOADER_ERRNO__START) |
@@ -1590,3 +1725,11 @@ int bpf__strerror_apply_obj_config(int err, char *buf, size_t size) | |||
1590 | bpf__strerror_end(buf, size); | 1725 | bpf__strerror_end(buf, size); |
1591 | return 0; | 1726 | return 0; |
1592 | } | 1727 | } |
1728 | |||
1729 | int bpf__strerror_setup_stdout(struct perf_evlist *evlist __maybe_unused, | ||
1730 | int err, char *buf, size_t size) | ||
1731 | { | ||
1732 | bpf__strerror_head(err, buf, size); | ||
1733 | bpf__strerror_end(buf, size); | ||
1734 | return 0; | ||
1735 | } | ||
diff --git a/tools/perf/util/bpf-loader.h b/tools/perf/util/bpf-loader.h index be4311944e3d..941e17275aa7 100644 --- a/tools/perf/util/bpf-loader.h +++ b/tools/perf/util/bpf-loader.h | |||
@@ -79,6 +79,11 @@ int bpf__strerror_config_obj(struct bpf_object *obj, | |||
79 | size_t size); | 79 | size_t size); |
80 | int bpf__apply_obj_config(void); | 80 | int bpf__apply_obj_config(void); |
81 | int bpf__strerror_apply_obj_config(int err, char *buf, size_t size); | 81 | int bpf__strerror_apply_obj_config(int err, char *buf, size_t size); |
82 | |||
83 | int bpf__setup_stdout(struct perf_evlist *evlist); | ||
84 | int bpf__strerror_setup_stdout(struct perf_evlist *evlist, int err, | ||
85 | char *buf, size_t size); | ||
86 | |||
82 | #else | 87 | #else |
83 | static inline struct bpf_object * | 88 | static inline struct bpf_object * |
84 | bpf__prepare_load(const char *filename __maybe_unused, | 89 | bpf__prepare_load(const char *filename __maybe_unused, |
@@ -125,6 +130,12 @@ bpf__apply_obj_config(void) | |||
125 | } | 130 | } |
126 | 131 | ||
127 | static inline int | 132 | static inline int |
133 | bpf__setup_stdout(struct perf_evlist *evlist __maybe_unused) | ||
134 | { | ||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static inline int | ||
128 | __bpf_strerror(char *buf, size_t size) | 139 | __bpf_strerror(char *buf, size_t size) |
129 | { | 140 | { |
130 | if (!size) | 141 | if (!size) |
@@ -177,5 +188,13 @@ bpf__strerror_apply_obj_config(int err __maybe_unused, | |||
177 | { | 188 | { |
178 | return __bpf_strerror(buf, size); | 189 | return __bpf_strerror(buf, size); |
179 | } | 190 | } |
191 | |||
192 | static inline int | ||
193 | bpf__strerror_setup_stdout(struct perf_evlist *evlist __maybe_unused, | ||
194 | int err __maybe_unused, char *buf, | ||
195 | size_t size) | ||
196 | { | ||
197 | return __bpf_strerror(buf, size); | ||
198 | } | ||
180 | #endif | 199 | #endif |
181 | #endif | 200 | #endif |
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c index 0573c2ec861d..bff425e1232c 100644 --- a/tools/perf/util/build-id.c +++ b/tools/perf/util/build-id.c | |||
@@ -261,14 +261,14 @@ static int machine__write_buildid_table(struct machine *machine, int fd) | |||
261 | 261 | ||
262 | if (dso__is_vdso(pos)) { | 262 | if (dso__is_vdso(pos)) { |
263 | name = pos->short_name; | 263 | name = pos->short_name; |
264 | name_len = pos->short_name_len + 1; | 264 | name_len = pos->short_name_len; |
265 | } else if (dso__is_kcore(pos)) { | 265 | } else if (dso__is_kcore(pos)) { |
266 | machine__mmap_name(machine, nm, sizeof(nm)); | 266 | machine__mmap_name(machine, nm, sizeof(nm)); |
267 | name = nm; | 267 | name = nm; |
268 | name_len = strlen(nm) + 1; | 268 | name_len = strlen(nm); |
269 | } else { | 269 | } else { |
270 | name = pos->long_name; | 270 | name = pos->long_name; |
271 | name_len = pos->long_name_len + 1; | 271 | name_len = pos->long_name_len; |
272 | } | 272 | } |
273 | 273 | ||
274 | in_kernel = pos->kernel || | 274 | in_kernel = pos->kernel || |
@@ -365,39 +365,17 @@ static char *build_id_cache__dirname_from_path(const char *name, | |||
365 | int build_id_cache__list_build_ids(const char *pathname, | 365 | int build_id_cache__list_build_ids(const char *pathname, |
366 | struct strlist **result) | 366 | struct strlist **result) |
367 | { | 367 | { |
368 | struct strlist *list; | ||
369 | char *dir_name; | 368 | char *dir_name; |
370 | DIR *dir; | ||
371 | struct dirent *d; | ||
372 | int ret = 0; | 369 | int ret = 0; |
373 | 370 | ||
374 | list = strlist__new(NULL, NULL); | ||
375 | dir_name = build_id_cache__dirname_from_path(pathname, false, false); | 371 | dir_name = build_id_cache__dirname_from_path(pathname, false, false); |
376 | if (!list || !dir_name) { | 372 | if (!dir_name) |
377 | ret = -ENOMEM; | 373 | return -ENOMEM; |
378 | goto out; | ||
379 | } | ||
380 | 374 | ||
381 | /* List up all dirents */ | 375 | *result = lsdir(dir_name, lsdir_no_dot_filter); |
382 | dir = opendir(dir_name); | 376 | if (!*result) |
383 | if (!dir) { | ||
384 | ret = -errno; | 377 | ret = -errno; |
385 | goto out; | ||
386 | } | ||
387 | |||
388 | while ((d = readdir(dir)) != NULL) { | ||
389 | if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) | ||
390 | continue; | ||
391 | strlist__add(list, d->d_name); | ||
392 | } | ||
393 | closedir(dir); | ||
394 | |||
395 | out: | ||
396 | free(dir_name); | 378 | free(dir_name); |
397 | if (ret) | ||
398 | strlist__delete(list); | ||
399 | else | ||
400 | *result = list; | ||
401 | 379 | ||
402 | return ret; | 380 | return ret; |
403 | } | 381 | } |
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h index 1f5a93c2c9a2..0d814bb74661 100644 --- a/tools/perf/util/cache.h +++ b/tools/perf/util/cache.h | |||
@@ -40,25 +40,6 @@ int split_cmdline(char *cmdline, const char ***argv); | |||
40 | 40 | ||
41 | #define alloc_nr(x) (((x)+16)*3/2) | 41 | #define alloc_nr(x) (((x)+16)*3/2) |
42 | 42 | ||
43 | /* | ||
44 | * Realloc the buffer pointed at by variable 'x' so that it can hold | ||
45 | * at least 'nr' entries; the number of entries currently allocated | ||
46 | * is 'alloc', using the standard growing factor alloc_nr() macro. | ||
47 | * | ||
48 | * DO NOT USE any expression with side-effect for 'x' or 'alloc'. | ||
49 | */ | ||
50 | #define ALLOC_GROW(x, nr, alloc) \ | ||
51 | do { \ | ||
52 | if ((nr) > alloc) { \ | ||
53 | if (alloc_nr(alloc) < (nr)) \ | ||
54 | alloc = (nr); \ | ||
55 | else \ | ||
56 | alloc = alloc_nr(alloc); \ | ||
57 | x = xrealloc((x), alloc * sizeof(*(x))); \ | ||
58 | } \ | ||
59 | } while(0) | ||
60 | |||
61 | |||
62 | static inline int is_absolute_path(const char *path) | 43 | static inline int is_absolute_path(const char *path) |
63 | { | 44 | { |
64 | return path[0] == '/'; | 45 | return path[0] == '/'; |
diff --git a/tools/perf/util/call-path.c b/tools/perf/util/call-path.c new file mode 100644 index 000000000000..904a17052e38 --- /dev/null +++ b/tools/perf/util/call-path.c | |||
@@ -0,0 +1,122 @@ | |||
1 | /* | ||
2 | * call-path.h: Manipulate a tree data structure containing function call paths | ||
3 | * Copyright (c) 2014, Intel Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/rbtree.h> | ||
17 | #include <linux/list.h> | ||
18 | |||
19 | #include "util.h" | ||
20 | #include "call-path.h" | ||
21 | |||
22 | static void call_path__init(struct call_path *cp, struct call_path *parent, | ||
23 | struct symbol *sym, u64 ip, bool in_kernel) | ||
24 | { | ||
25 | cp->parent = parent; | ||
26 | cp->sym = sym; | ||
27 | cp->ip = sym ? 0 : ip; | ||
28 | cp->db_id = 0; | ||
29 | cp->in_kernel = in_kernel; | ||
30 | RB_CLEAR_NODE(&cp->rb_node); | ||
31 | cp->children = RB_ROOT; | ||
32 | } | ||
33 | |||
34 | struct call_path_root *call_path_root__new(void) | ||
35 | { | ||
36 | struct call_path_root *cpr; | ||
37 | |||
38 | cpr = zalloc(sizeof(struct call_path_root)); | ||
39 | if (!cpr) | ||
40 | return NULL; | ||
41 | call_path__init(&cpr->call_path, NULL, NULL, 0, false); | ||
42 | INIT_LIST_HEAD(&cpr->blocks); | ||
43 | return cpr; | ||
44 | } | ||
45 | |||
46 | void call_path_root__free(struct call_path_root *cpr) | ||
47 | { | ||
48 | struct call_path_block *pos, *n; | ||
49 | |||
50 | list_for_each_entry_safe(pos, n, &cpr->blocks, node) { | ||
51 | list_del(&pos->node); | ||
52 | free(pos); | ||
53 | } | ||
54 | free(cpr); | ||
55 | } | ||
56 | |||
57 | static struct call_path *call_path__new(struct call_path_root *cpr, | ||
58 | struct call_path *parent, | ||
59 | struct symbol *sym, u64 ip, | ||
60 | bool in_kernel) | ||
61 | { | ||
62 | struct call_path_block *cpb; | ||
63 | struct call_path *cp; | ||
64 | size_t n; | ||
65 | |||
66 | if (cpr->next < cpr->sz) { | ||
67 | cpb = list_last_entry(&cpr->blocks, struct call_path_block, | ||
68 | node); | ||
69 | } else { | ||
70 | cpb = zalloc(sizeof(struct call_path_block)); | ||
71 | if (!cpb) | ||
72 | return NULL; | ||
73 | list_add_tail(&cpb->node, &cpr->blocks); | ||
74 | cpr->sz += CALL_PATH_BLOCK_SIZE; | ||
75 | } | ||
76 | |||
77 | n = cpr->next++ & CALL_PATH_BLOCK_MASK; | ||
78 | cp = &cpb->cp[n]; | ||
79 | |||
80 | call_path__init(cp, parent, sym, ip, in_kernel); | ||
81 | |||
82 | return cp; | ||
83 | } | ||
84 | |||
85 | struct call_path *call_path__findnew(struct call_path_root *cpr, | ||
86 | struct call_path *parent, | ||
87 | struct symbol *sym, u64 ip, u64 ks) | ||
88 | { | ||
89 | struct rb_node **p; | ||
90 | struct rb_node *node_parent = NULL; | ||
91 | struct call_path *cp; | ||
92 | bool in_kernel = ip >= ks; | ||
93 | |||
94 | if (sym) | ||
95 | ip = 0; | ||
96 | |||
97 | if (!parent) | ||
98 | return call_path__new(cpr, parent, sym, ip, in_kernel); | ||
99 | |||
100 | p = &parent->children.rb_node; | ||
101 | while (*p != NULL) { | ||
102 | node_parent = *p; | ||
103 | cp = rb_entry(node_parent, struct call_path, rb_node); | ||
104 | |||
105 | if (cp->sym == sym && cp->ip == ip) | ||
106 | return cp; | ||
107 | |||
108 | if (sym < cp->sym || (sym == cp->sym && ip < cp->ip)) | ||
109 | p = &(*p)->rb_left; | ||
110 | else | ||
111 | p = &(*p)->rb_right; | ||
112 | } | ||
113 | |||
114 | cp = call_path__new(cpr, parent, sym, ip, in_kernel); | ||
115 | if (!cp) | ||
116 | return NULL; | ||
117 | |||
118 | rb_link_node(&cp->rb_node, node_parent, p); | ||
119 | rb_insert_color(&cp->rb_node, &parent->children); | ||
120 | |||
121 | return cp; | ||
122 | } | ||
diff --git a/tools/perf/util/call-path.h b/tools/perf/util/call-path.h new file mode 100644 index 000000000000..477f6d03b659 --- /dev/null +++ b/tools/perf/util/call-path.h | |||
@@ -0,0 +1,77 @@ | |||
1 | /* | ||
2 | * call-path.h: Manipulate a tree data structure containing function call paths | ||
3 | * Copyright (c) 2014, Intel Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #ifndef __PERF_CALL_PATH_H | ||
17 | #define __PERF_CALL_PATH_H | ||
18 | |||
19 | #include <sys/types.h> | ||
20 | |||
21 | #include <linux/types.h> | ||
22 | #include <linux/rbtree.h> | ||
23 | |||
24 | /** | ||
25 | * struct call_path - node in list of calls leading to a function call. | ||
26 | * @parent: call path to the parent function call | ||
27 | * @sym: symbol of function called | ||
28 | * @ip: only if sym is null, the ip of the function | ||
29 | * @db_id: id used for db-export | ||
30 | * @in_kernel: whether function is a in the kernel | ||
31 | * @rb_node: node in parent's tree of called functions | ||
32 | * @children: tree of call paths of functions called | ||
33 | * | ||
34 | * In combination with the call_return structure, the call_path structure | ||
35 | * defines a context-sensitve call-graph. | ||
36 | */ | ||
37 | struct call_path { | ||
38 | struct call_path *parent; | ||
39 | struct symbol *sym; | ||
40 | u64 ip; | ||
41 | u64 db_id; | ||
42 | bool in_kernel; | ||
43 | struct rb_node rb_node; | ||
44 | struct rb_root children; | ||
45 | }; | ||
46 | |||
47 | #define CALL_PATH_BLOCK_SHIFT 8 | ||
48 | #define CALL_PATH_BLOCK_SIZE (1 << CALL_PATH_BLOCK_SHIFT) | ||
49 | #define CALL_PATH_BLOCK_MASK (CALL_PATH_BLOCK_SIZE - 1) | ||
50 | |||
51 | struct call_path_block { | ||
52 | struct call_path cp[CALL_PATH_BLOCK_SIZE]; | ||
53 | struct list_head node; | ||
54 | }; | ||
55 | |||
56 | /** | ||
57 | * struct call_path_root - root of all call paths. | ||
58 | * @call_path: root call path | ||
59 | * @blocks: list of blocks to store call paths | ||
60 | * @next: next free space | ||
61 | * @sz: number of spaces | ||
62 | */ | ||
63 | struct call_path_root { | ||
64 | struct call_path call_path; | ||
65 | struct list_head blocks; | ||
66 | size_t next; | ||
67 | size_t sz; | ||
68 | }; | ||
69 | |||
70 | struct call_path_root *call_path_root__new(void); | ||
71 | void call_path_root__free(struct call_path_root *cpr); | ||
72 | |||
73 | struct call_path *call_path__findnew(struct call_path_root *cpr, | ||
74 | struct call_path *parent, | ||
75 | struct symbol *sym, u64 ip, u64 ks); | ||
76 | |||
77 | #endif | ||
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c index 24b4bd0d7754..07fd30bc2f81 100644 --- a/tools/perf/util/callchain.c +++ b/tools/perf/util/callchain.c | |||
@@ -109,6 +109,7 @@ __parse_callchain_report_opt(const char *arg, bool allow_record_opt) | |||
109 | bool record_opt_set = false; | 109 | bool record_opt_set = false; |
110 | bool try_stack_size = false; | 110 | bool try_stack_size = false; |
111 | 111 | ||
112 | callchain_param.enabled = true; | ||
112 | symbol_conf.use_callchain = true; | 113 | symbol_conf.use_callchain = true; |
113 | 114 | ||
114 | if (!arg) | 115 | if (!arg) |
@@ -117,6 +118,7 @@ __parse_callchain_report_opt(const char *arg, bool allow_record_opt) | |||
117 | while ((tok = strtok((char *)arg, ",")) != NULL) { | 118 | while ((tok = strtok((char *)arg, ",")) != NULL) { |
118 | if (!strncmp(tok, "none", strlen(tok))) { | 119 | if (!strncmp(tok, "none", strlen(tok))) { |
119 | callchain_param.mode = CHAIN_NONE; | 120 | callchain_param.mode = CHAIN_NONE; |
121 | callchain_param.enabled = false; | ||
120 | symbol_conf.use_callchain = false; | 122 | symbol_conf.use_callchain = false; |
121 | return 0; | 123 | return 0; |
122 | } | 124 | } |
@@ -788,7 +790,8 @@ int callchain_cursor_append(struct callchain_cursor *cursor, | |||
788 | return 0; | 790 | return 0; |
789 | } | 791 | } |
790 | 792 | ||
791 | int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent, | 793 | int sample__resolve_callchain(struct perf_sample *sample, |
794 | struct callchain_cursor *cursor, struct symbol **parent, | ||
792 | struct perf_evsel *evsel, struct addr_location *al, | 795 | struct perf_evsel *evsel, struct addr_location *al, |
793 | int max_stack) | 796 | int max_stack) |
794 | { | 797 | { |
@@ -796,8 +799,8 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent | |||
796 | return 0; | 799 | return 0; |
797 | 800 | ||
798 | if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain || | 801 | if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain || |
799 | sort__has_parent) { | 802 | perf_hpp_list.parent) { |
800 | return thread__resolve_callchain(al->thread, evsel, sample, | 803 | return thread__resolve_callchain(al->thread, cursor, evsel, sample, |
801 | parent, al, max_stack); | 804 | parent, al, max_stack); |
802 | } | 805 | } |
803 | return 0; | 806 | return 0; |
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h index d2a9e694810c..65e2a4f7cb4e 100644 --- a/tools/perf/util/callchain.h +++ b/tools/perf/util/callchain.h | |||
@@ -212,7 +212,14 @@ struct hist_entry; | |||
212 | int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); | 212 | int record_parse_callchain_opt(const struct option *opt, const char *arg, int unset); |
213 | int record_callchain_opt(const struct option *opt, const char *arg, int unset); | 213 | int record_callchain_opt(const struct option *opt, const char *arg, int unset); |
214 | 214 | ||
215 | int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent, | 215 | struct record_opts; |
216 | |||
217 | int record_opts__parse_callchain(struct record_opts *record, | ||
218 | struct callchain_param *callchain, | ||
219 | const char *arg, bool unset); | ||
220 | |||
221 | int sample__resolve_callchain(struct perf_sample *sample, | ||
222 | struct callchain_cursor *cursor, struct symbol **parent, | ||
216 | struct perf_evsel *evsel, struct addr_location *al, | 223 | struct perf_evsel *evsel, struct addr_location *al, |
217 | int max_stack); | 224 | int max_stack); |
218 | int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample); | 225 | int hist_entry__append_callchain(struct hist_entry *he, struct perf_sample *sample); |
diff --git a/tools/perf/util/config.c b/tools/perf/util/config.c index 4e727635476e..dad7d8272168 100644 --- a/tools/perf/util/config.c +++ b/tools/perf/util/config.c | |||
@@ -13,6 +13,7 @@ | |||
13 | #include <subcmd/exec-cmd.h> | 13 | #include <subcmd/exec-cmd.h> |
14 | #include "util/hist.h" /* perf_hist_config */ | 14 | #include "util/hist.h" /* perf_hist_config */ |
15 | #include "util/llvm-utils.h" /* perf_llvm_config */ | 15 | #include "util/llvm-utils.h" /* perf_llvm_config */ |
16 | #include "config.h" | ||
16 | 17 | ||
17 | #define MAXNAME (256) | 18 | #define MAXNAME (256) |
18 | 19 | ||
@@ -377,6 +378,21 @@ const char *perf_config_dirname(const char *name, const char *value) | |||
377 | return value; | 378 | return value; |
378 | } | 379 | } |
379 | 380 | ||
381 | static int perf_buildid_config(const char *var, const char *value) | ||
382 | { | ||
383 | /* same dir for all commands */ | ||
384 | if (!strcmp(var, "buildid.dir")) { | ||
385 | const char *dir = perf_config_dirname(var, value); | ||
386 | |||
387 | if (!dir) | ||
388 | return -1; | ||
389 | strncpy(buildid_dir, dir, MAXPATHLEN-1); | ||
390 | buildid_dir[MAXPATHLEN-1] = '\0'; | ||
391 | } | ||
392 | |||
393 | return 0; | ||
394 | } | ||
395 | |||
380 | static int perf_default_core_config(const char *var __maybe_unused, | 396 | static int perf_default_core_config(const char *var __maybe_unused, |
381 | const char *value __maybe_unused) | 397 | const char *value __maybe_unused) |
382 | { | 398 | { |
@@ -412,6 +428,9 @@ int perf_default_config(const char *var, const char *value, | |||
412 | if (!prefixcmp(var, "llvm.")) | 428 | if (!prefixcmp(var, "llvm.")) |
413 | return perf_llvm_config(var, value); | 429 | return perf_llvm_config(var, value); |
414 | 430 | ||
431 | if (!prefixcmp(var, "buildid.")) | ||
432 | return perf_buildid_config(var, value); | ||
433 | |||
415 | /* Add other config variables here. */ | 434 | /* Add other config variables here. */ |
416 | return 0; | 435 | return 0; |
417 | } | 436 | } |
@@ -506,41 +525,185 @@ out: | |||
506 | return ret; | 525 | return ret; |
507 | } | 526 | } |
508 | 527 | ||
509 | /* | 528 | static struct perf_config_section *find_section(struct list_head *sections, |
510 | * Call this to report error for your variable that should not | 529 | const char *section_name) |
511 | * get a boolean value (i.e. "[my] var" means "true"). | ||
512 | */ | ||
513 | int config_error_nonbool(const char *var) | ||
514 | { | 530 | { |
515 | return error("Missing value for '%s'", var); | 531 | struct perf_config_section *section; |
532 | |||
533 | list_for_each_entry(section, sections, node) | ||
534 | if (!strcmp(section->name, section_name)) | ||
535 | return section; | ||
536 | |||
537 | return NULL; | ||
538 | } | ||
539 | |||
540 | static struct perf_config_item *find_config_item(const char *name, | ||
541 | struct perf_config_section *section) | ||
542 | { | ||
543 | struct perf_config_item *item; | ||
544 | |||
545 | list_for_each_entry(item, §ion->items, node) | ||
546 | if (!strcmp(item->name, name)) | ||
547 | return item; | ||
548 | |||
549 | return NULL; | ||
516 | } | 550 | } |
517 | 551 | ||
518 | struct buildid_dir_config { | 552 | static struct perf_config_section *add_section(struct list_head *sections, |
519 | char *dir; | 553 | const char *section_name) |
520 | }; | 554 | { |
555 | struct perf_config_section *section = zalloc(sizeof(*section)); | ||
556 | |||
557 | if (!section) | ||
558 | return NULL; | ||
559 | |||
560 | INIT_LIST_HEAD(§ion->items); | ||
561 | section->name = strdup(section_name); | ||
562 | if (!section->name) { | ||
563 | pr_debug("%s: strdup failed\n", __func__); | ||
564 | free(section); | ||
565 | return NULL; | ||
566 | } | ||
567 | |||
568 | list_add_tail(§ion->node, sections); | ||
569 | return section; | ||
570 | } | ||
521 | 571 | ||
522 | static int buildid_dir_command_config(const char *var, const char *value, | 572 | static struct perf_config_item *add_config_item(struct perf_config_section *section, |
523 | void *data) | 573 | const char *name) |
524 | { | 574 | { |
525 | struct buildid_dir_config *c = data; | 575 | struct perf_config_item *item = zalloc(sizeof(*item)); |
526 | const char *v; | ||
527 | 576 | ||
528 | /* same dir for all commands */ | 577 | if (!item) |
529 | if (!strcmp(var, "buildid.dir")) { | 578 | return NULL; |
530 | v = perf_config_dirname(var, value); | 579 | |
531 | if (!v) | 580 | item->name = strdup(name); |
532 | return -1; | 581 | if (!item->name) { |
533 | strncpy(c->dir, v, MAXPATHLEN-1); | 582 | pr_debug("%s: strdup failed\n", __func__); |
534 | c->dir[MAXPATHLEN-1] = '\0'; | 583 | free(item); |
584 | return NULL; | ||
535 | } | 585 | } |
586 | |||
587 | list_add_tail(&item->node, §ion->items); | ||
588 | return item; | ||
589 | } | ||
590 | |||
591 | static int set_value(struct perf_config_item *item, const char *value) | ||
592 | { | ||
593 | char *val = strdup(value); | ||
594 | |||
595 | if (!val) | ||
596 | return -1; | ||
597 | |||
598 | zfree(&item->value); | ||
599 | item->value = val; | ||
536 | return 0; | 600 | return 0; |
537 | } | 601 | } |
538 | 602 | ||
539 | static void check_buildid_dir_config(void) | 603 | static int collect_config(const char *var, const char *value, |
604 | void *perf_config_set) | ||
540 | { | 605 | { |
541 | struct buildid_dir_config c; | 606 | int ret = -1; |
542 | c.dir = buildid_dir; | 607 | char *ptr, *key; |
543 | perf_config(buildid_dir_command_config, &c); | 608 | char *section_name, *name; |
609 | struct perf_config_section *section = NULL; | ||
610 | struct perf_config_item *item = NULL; | ||
611 | struct perf_config_set *set = perf_config_set; | ||
612 | struct list_head *sections = &set->sections; | ||
613 | |||
614 | key = ptr = strdup(var); | ||
615 | if (!key) { | ||
616 | pr_debug("%s: strdup failed\n", __func__); | ||
617 | return -1; | ||
618 | } | ||
619 | |||
620 | section_name = strsep(&ptr, "."); | ||
621 | name = ptr; | ||
622 | if (name == NULL || value == NULL) | ||
623 | goto out_free; | ||
624 | |||
625 | section = find_section(sections, section_name); | ||
626 | if (!section) { | ||
627 | section = add_section(sections, section_name); | ||
628 | if (!section) | ||
629 | goto out_free; | ||
630 | } | ||
631 | |||
632 | item = find_config_item(name, section); | ||
633 | if (!item) { | ||
634 | item = add_config_item(section, name); | ||
635 | if (!item) | ||
636 | goto out_free; | ||
637 | } | ||
638 | |||
639 | ret = set_value(item, value); | ||
640 | return ret; | ||
641 | |||
642 | out_free: | ||
643 | free(key); | ||
644 | perf_config_set__delete(set); | ||
645 | return -1; | ||
646 | } | ||
647 | |||
648 | struct perf_config_set *perf_config_set__new(void) | ||
649 | { | ||
650 | struct perf_config_set *set = zalloc(sizeof(*set)); | ||
651 | |||
652 | if (set) { | ||
653 | INIT_LIST_HEAD(&set->sections); | ||
654 | perf_config(collect_config, set); | ||
655 | } | ||
656 | |||
657 | return set; | ||
658 | } | ||
659 | |||
660 | static void perf_config_item__delete(struct perf_config_item *item) | ||
661 | { | ||
662 | zfree(&item->name); | ||
663 | zfree(&item->value); | ||
664 | free(item); | ||
665 | } | ||
666 | |||
667 | static void perf_config_section__purge(struct perf_config_section *section) | ||
668 | { | ||
669 | struct perf_config_item *item, *tmp; | ||
670 | |||
671 | list_for_each_entry_safe(item, tmp, §ion->items, node) { | ||
672 | list_del_init(&item->node); | ||
673 | perf_config_item__delete(item); | ||
674 | } | ||
675 | } | ||
676 | |||
677 | static void perf_config_section__delete(struct perf_config_section *section) | ||
678 | { | ||
679 | perf_config_section__purge(section); | ||
680 | zfree(§ion->name); | ||
681 | free(section); | ||
682 | } | ||
683 | |||
684 | static void perf_config_set__purge(struct perf_config_set *set) | ||
685 | { | ||
686 | struct perf_config_section *section, *tmp; | ||
687 | |||
688 | list_for_each_entry_safe(section, tmp, &set->sections, node) { | ||
689 | list_del_init(§ion->node); | ||
690 | perf_config_section__delete(section); | ||
691 | } | ||
692 | } | ||
693 | |||
694 | void perf_config_set__delete(struct perf_config_set *set) | ||
695 | { | ||
696 | perf_config_set__purge(set); | ||
697 | free(set); | ||
698 | } | ||
699 | |||
700 | /* | ||
701 | * Call this to report error for your variable that should not | ||
702 | * get a boolean value (i.e. "[my] var" means "true"). | ||
703 | */ | ||
704 | int config_error_nonbool(const char *var) | ||
705 | { | ||
706 | return error("Missing value for '%s'", var); | ||
544 | } | 707 | } |
545 | 708 | ||
546 | void set_buildid_dir(const char *dir) | 709 | void set_buildid_dir(const char *dir) |
@@ -548,16 +711,13 @@ void set_buildid_dir(const char *dir) | |||
548 | if (dir) | 711 | if (dir) |
549 | scnprintf(buildid_dir, MAXPATHLEN-1, "%s", dir); | 712 | scnprintf(buildid_dir, MAXPATHLEN-1, "%s", dir); |
550 | 713 | ||
551 | /* try config file */ | ||
552 | if (buildid_dir[0] == '\0') | ||
553 | check_buildid_dir_config(); | ||
554 | |||
555 | /* default to $HOME/.debug */ | 714 | /* default to $HOME/.debug */ |
556 | if (buildid_dir[0] == '\0') { | 715 | if (buildid_dir[0] == '\0') { |
557 | char *v = getenv("HOME"); | 716 | char *home = getenv("HOME"); |
558 | if (v) { | 717 | |
718 | if (home) { | ||
559 | snprintf(buildid_dir, MAXPATHLEN-1, "%s/%s", | 719 | snprintf(buildid_dir, MAXPATHLEN-1, "%s/%s", |
560 | v, DEBUG_CACHE_DIR); | 720 | home, DEBUG_CACHE_DIR); |
561 | } else { | 721 | } else { |
562 | strncpy(buildid_dir, DEBUG_CACHE_DIR, MAXPATHLEN-1); | 722 | strncpy(buildid_dir, DEBUG_CACHE_DIR, MAXPATHLEN-1); |
563 | } | 723 | } |
diff --git a/tools/perf/util/config.h b/tools/perf/util/config.h new file mode 100644 index 000000000000..22ec626ac718 --- /dev/null +++ b/tools/perf/util/config.h | |||
@@ -0,0 +1,26 @@ | |||
1 | #ifndef __PERF_CONFIG_H | ||
2 | #define __PERF_CONFIG_H | ||
3 | |||
4 | #include <stdbool.h> | ||
5 | #include <linux/list.h> | ||
6 | |||
7 | struct perf_config_item { | ||
8 | char *name; | ||
9 | char *value; | ||
10 | struct list_head node; | ||
11 | }; | ||
12 | |||
13 | struct perf_config_section { | ||
14 | char *name; | ||
15 | struct list_head items; | ||
16 | struct list_head node; | ||
17 | }; | ||
18 | |||
19 | struct perf_config_set { | ||
20 | struct list_head sections; | ||
21 | }; | ||
22 | |||
23 | struct perf_config_set *perf_config_set__new(void); | ||
24 | void perf_config_set__delete(struct perf_config_set *set); | ||
25 | |||
26 | #endif /* __PERF_CONFIG_H */ | ||
diff --git a/tools/perf/util/cpumap.c b/tools/perf/util/cpumap.c index 9bcf2bed3a6d..02d801670f30 100644 --- a/tools/perf/util/cpumap.c +++ b/tools/perf/util/cpumap.c | |||
@@ -587,3 +587,15 @@ int cpu__setup_cpunode_map(void) | |||
587 | closedir(dir1); | 587 | closedir(dir1); |
588 | return 0; | 588 | return 0; |
589 | } | 589 | } |
590 | |||
591 | bool cpu_map__has(struct cpu_map *cpus, int cpu) | ||
592 | { | ||
593 | int i; | ||
594 | |||
595 | for (i = 0; i < cpus->nr; ++i) { | ||
596 | if (cpus->map[i] == cpu) | ||
597 | return true; | ||
598 | } | ||
599 | |||
600 | return false; | ||
601 | } | ||
diff --git a/tools/perf/util/cpumap.h b/tools/perf/util/cpumap.h index 81a2562aaa2b..1a0a35073ce1 100644 --- a/tools/perf/util/cpumap.h +++ b/tools/perf/util/cpumap.h | |||
@@ -66,4 +66,6 @@ int cpu__get_node(int cpu); | |||
66 | int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, | 66 | int cpu_map__build_map(struct cpu_map *cpus, struct cpu_map **res, |
67 | int (*f)(struct cpu_map *map, int cpu, void *data), | 67 | int (*f)(struct cpu_map *map, int cpu, void *data), |
68 | void *data); | 68 | void *data); |
69 | |||
70 | bool cpu_map__has(struct cpu_map *cpus, int cpu); | ||
69 | #endif /* __PERF_CPUMAP_H */ | 71 | #endif /* __PERF_CPUMAP_H */ |
diff --git a/tools/perf/util/data.c b/tools/perf/util/data.c index 1921942fc2e0..be83516155ee 100644 --- a/tools/perf/util/data.c +++ b/tools/perf/util/data.c | |||
@@ -136,3 +136,44 @@ ssize_t perf_data_file__write(struct perf_data_file *file, | |||
136 | { | 136 | { |
137 | return writen(file->fd, buf, size); | 137 | return writen(file->fd, buf, size); |
138 | } | 138 | } |
139 | |||
140 | int perf_data_file__switch(struct perf_data_file *file, | ||
141 | const char *postfix, | ||
142 | size_t pos, bool at_exit) | ||
143 | { | ||
144 | char *new_filepath; | ||
145 | int ret; | ||
146 | |||
147 | if (check_pipe(file)) | ||
148 | return -EINVAL; | ||
149 | if (perf_data_file__is_read(file)) | ||
150 | return -EINVAL; | ||
151 | |||
152 | if (asprintf(&new_filepath, "%s.%s", file->path, postfix) < 0) | ||
153 | return -ENOMEM; | ||
154 | |||
155 | /* | ||
156 | * Only fire a warning, don't return error, continue fill | ||
157 | * original file. | ||
158 | */ | ||
159 | if (rename(file->path, new_filepath)) | ||
160 | pr_warning("Failed to rename %s to %s\n", file->path, new_filepath); | ||
161 | |||
162 | if (!at_exit) { | ||
163 | close(file->fd); | ||
164 | ret = perf_data_file__open(file); | ||
165 | if (ret < 0) | ||
166 | goto out; | ||
167 | |||
168 | if (lseek(file->fd, pos, SEEK_SET) == (off_t)-1) { | ||
169 | ret = -errno; | ||
170 | pr_debug("Failed to lseek to %zu: %s", | ||
171 | pos, strerror(errno)); | ||
172 | goto out; | ||
173 | } | ||
174 | } | ||
175 | ret = file->fd; | ||
176 | out: | ||
177 | free(new_filepath); | ||
178 | return ret; | ||
179 | } | ||
diff --git a/tools/perf/util/data.h b/tools/perf/util/data.h index 2b15d0c95c7f..ae510ce16cb1 100644 --- a/tools/perf/util/data.h +++ b/tools/perf/util/data.h | |||
@@ -46,5 +46,14 @@ int perf_data_file__open(struct perf_data_file *file); | |||
46 | void perf_data_file__close(struct perf_data_file *file); | 46 | void perf_data_file__close(struct perf_data_file *file); |
47 | ssize_t perf_data_file__write(struct perf_data_file *file, | 47 | ssize_t perf_data_file__write(struct perf_data_file *file, |
48 | void *buf, size_t size); | 48 | void *buf, size_t size); |
49 | 49 | /* | |
50 | * If at_exit is set, only rename current perf.data to | ||
51 | * perf.data.<postfix>, continue write on original file. | ||
52 | * Set at_exit when flushing the last output. | ||
53 | * | ||
54 | * Return value is fd of new output. | ||
55 | */ | ||
56 | int perf_data_file__switch(struct perf_data_file *file, | ||
57 | const char *postfix, | ||
58 | size_t pos, bool at_exit); | ||
50 | #endif /* __PERF_DATA_H */ | 59 | #endif /* __PERF_DATA_H */ |
diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c index 049438d51b9a..8d96c80cc67e 100644 --- a/tools/perf/util/db-export.c +++ b/tools/perf/util/db-export.c | |||
@@ -23,6 +23,8 @@ | |||
23 | #include "event.h" | 23 | #include "event.h" |
24 | #include "util.h" | 24 | #include "util.h" |
25 | #include "thread-stack.h" | 25 | #include "thread-stack.h" |
26 | #include "callchain.h" | ||
27 | #include "call-path.h" | ||
26 | #include "db-export.h" | 28 | #include "db-export.h" |
27 | 29 | ||
28 | struct deferred_export { | 30 | struct deferred_export { |
@@ -258,8 +260,7 @@ static int db_ids_from_al(struct db_export *dbe, struct addr_location *al, | |||
258 | if (!al->sym) { | 260 | if (!al->sym) { |
259 | al->sym = symbol__new(al->addr, 0, 0, "unknown"); | 261 | al->sym = symbol__new(al->addr, 0, 0, "unknown"); |
260 | if (al->sym) | 262 | if (al->sym) |
261 | symbols__insert(&dso->symbols[al->map->type], | 263 | dso__insert_symbol(dso, al->map->type, al->sym); |
262 | al->sym); | ||
263 | } | 264 | } |
264 | 265 | ||
265 | if (al->sym) { | 266 | if (al->sym) { |
@@ -276,6 +277,80 @@ static int db_ids_from_al(struct db_export *dbe, struct addr_location *al, | |||
276 | return 0; | 277 | return 0; |
277 | } | 278 | } |
278 | 279 | ||
280 | static struct call_path *call_path_from_sample(struct db_export *dbe, | ||
281 | struct machine *machine, | ||
282 | struct thread *thread, | ||
283 | struct perf_sample *sample, | ||
284 | struct perf_evsel *evsel) | ||
285 | { | ||
286 | u64 kernel_start = machine__kernel_start(machine); | ||
287 | struct call_path *current = &dbe->cpr->call_path; | ||
288 | enum chain_order saved_order = callchain_param.order; | ||
289 | int err; | ||
290 | |||
291 | if (!symbol_conf.use_callchain || !sample->callchain) | ||
292 | return NULL; | ||
293 | |||
294 | /* | ||
295 | * Since the call path tree must be built starting with the root, we | ||
296 | * must use ORDER_CALL for call chain resolution, in order to process | ||
297 | * the callchain starting with the root node and ending with the leaf. | ||
298 | */ | ||
299 | callchain_param.order = ORDER_CALLER; | ||
300 | err = thread__resolve_callchain(thread, &callchain_cursor, evsel, | ||
301 | sample, NULL, NULL, | ||
302 | sysctl_perf_event_max_stack); | ||
303 | if (err) { | ||
304 | callchain_param.order = saved_order; | ||
305 | return NULL; | ||
306 | } | ||
307 | callchain_cursor_commit(&callchain_cursor); | ||
308 | |||
309 | while (1) { | ||
310 | struct callchain_cursor_node *node; | ||
311 | struct addr_location al; | ||
312 | u64 dso_db_id = 0, sym_db_id = 0, offset = 0; | ||
313 | |||
314 | memset(&al, 0, sizeof(al)); | ||
315 | |||
316 | node = callchain_cursor_current(&callchain_cursor); | ||
317 | if (!node) | ||
318 | break; | ||
319 | /* | ||
320 | * Handle export of symbol and dso for this node by | ||
321 | * constructing an addr_location struct and then passing it to | ||
322 | * db_ids_from_al() to perform the export. | ||
323 | */ | ||
324 | al.sym = node->sym; | ||
325 | al.map = node->map; | ||
326 | al.machine = machine; | ||
327 | al.addr = node->ip; | ||
328 | |||
329 | if (al.map && !al.sym) | ||
330 | al.sym = dso__find_symbol(al.map->dso, MAP__FUNCTION, | ||
331 | al.addr); | ||
332 | |||
333 | db_ids_from_al(dbe, &al, &dso_db_id, &sym_db_id, &offset); | ||
334 | |||
335 | /* add node to the call path tree if it doesn't exist */ | ||
336 | current = call_path__findnew(dbe->cpr, current, | ||
337 | al.sym, node->ip, | ||
338 | kernel_start); | ||
339 | |||
340 | callchain_cursor_advance(&callchain_cursor); | ||
341 | } | ||
342 | |||
343 | /* Reset the callchain order to its prior value. */ | ||
344 | callchain_param.order = saved_order; | ||
345 | |||
346 | if (current == &dbe->cpr->call_path) { | ||
347 | /* Bail because the callchain was empty. */ | ||
348 | return NULL; | ||
349 | } | ||
350 | |||
351 | return current; | ||
352 | } | ||
353 | |||
279 | int db_export__branch_type(struct db_export *dbe, u32 branch_type, | 354 | int db_export__branch_type(struct db_export *dbe, u32 branch_type, |
280 | const char *name) | 355 | const char *name) |
281 | { | 356 | { |
@@ -329,6 +404,16 @@ int db_export__sample(struct db_export *dbe, union perf_event *event, | |||
329 | if (err) | 404 | if (err) |
330 | goto out_put; | 405 | goto out_put; |
331 | 406 | ||
407 | if (dbe->cpr) { | ||
408 | struct call_path *cp = call_path_from_sample(dbe, al->machine, | ||
409 | thread, sample, | ||
410 | evsel); | ||
411 | if (cp) { | ||
412 | db_export__call_path(dbe, cp); | ||
413 | es.call_path_id = cp->db_id; | ||
414 | } | ||
415 | } | ||
416 | |||
332 | if ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && | 417 | if ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) && |
333 | sample_addr_correlates_sym(&evsel->attr)) { | 418 | sample_addr_correlates_sym(&evsel->attr)) { |
334 | struct addr_location addr_al; | 419 | struct addr_location addr_al; |
diff --git a/tools/perf/util/db-export.h b/tools/perf/util/db-export.h index 25e22fd76aca..67bc6b8ad2d6 100644 --- a/tools/perf/util/db-export.h +++ b/tools/perf/util/db-export.h | |||
@@ -27,6 +27,7 @@ struct dso; | |||
27 | struct perf_sample; | 27 | struct perf_sample; |
28 | struct addr_location; | 28 | struct addr_location; |
29 | struct call_return_processor; | 29 | struct call_return_processor; |
30 | struct call_path_root; | ||
30 | struct call_path; | 31 | struct call_path; |
31 | struct call_return; | 32 | struct call_return; |
32 | 33 | ||
@@ -43,6 +44,7 @@ struct export_sample { | |||
43 | u64 addr_dso_db_id; | 44 | u64 addr_dso_db_id; |
44 | u64 addr_sym_db_id; | 45 | u64 addr_sym_db_id; |
45 | u64 addr_offset; /* addr offset from symbol start */ | 46 | u64 addr_offset; /* addr offset from symbol start */ |
47 | u64 call_path_id; | ||
46 | }; | 48 | }; |
47 | 49 | ||
48 | struct db_export { | 50 | struct db_export { |
@@ -64,6 +66,7 @@ struct db_export { | |||
64 | int (*export_call_return)(struct db_export *dbe, | 66 | int (*export_call_return)(struct db_export *dbe, |
65 | struct call_return *cr); | 67 | struct call_return *cr); |
66 | struct call_return_processor *crp; | 68 | struct call_return_processor *crp; |
69 | struct call_path_root *cpr; | ||
67 | u64 evsel_last_db_id; | 70 | u64 evsel_last_db_id; |
68 | u64 machine_last_db_id; | 71 | u64 machine_last_db_id; |
69 | u64 thread_last_db_id; | 72 | u64 thread_last_db_id; |
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index 8e6395439ca0..3357479082ca 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c | |||
@@ -38,7 +38,7 @@ int dso__read_binary_type_filename(const struct dso *dso, | |||
38 | enum dso_binary_type type, | 38 | enum dso_binary_type type, |
39 | char *root_dir, char *filename, size_t size) | 39 | char *root_dir, char *filename, size_t size) |
40 | { | 40 | { |
41 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; | 41 | char build_id_hex[SBUILD_ID_SIZE]; |
42 | int ret = 0; | 42 | int ret = 0; |
43 | size_t len; | 43 | size_t len; |
44 | 44 | ||
@@ -1301,7 +1301,7 @@ size_t __dsos__fprintf(struct list_head *head, FILE *fp) | |||
1301 | 1301 | ||
1302 | size_t dso__fprintf_buildid(struct dso *dso, FILE *fp) | 1302 | size_t dso__fprintf_buildid(struct dso *dso, FILE *fp) |
1303 | { | 1303 | { |
1304 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | 1304 | char sbuild_id[SBUILD_ID_SIZE]; |
1305 | 1305 | ||
1306 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); | 1306 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); |
1307 | return fprintf(fp, "%s", sbuild_id); | 1307 | return fprintf(fp, "%s", sbuild_id); |
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 577e600c8eb1..a347b19c961a 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c | |||
@@ -915,8 +915,7 @@ int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf) | |||
915 | tmp = "*"; | 915 | tmp = "*"; |
916 | else if (tag == DW_TAG_subroutine_type) { | 916 | else if (tag == DW_TAG_subroutine_type) { |
917 | /* Function pointer */ | 917 | /* Function pointer */ |
918 | strbuf_add(buf, "(function_type)", 15); | 918 | return strbuf_add(buf, "(function_type)", 15); |
919 | return 0; | ||
920 | } else { | 919 | } else { |
921 | if (!dwarf_diename(&type)) | 920 | if (!dwarf_diename(&type)) |
922 | return -ENOENT; | 921 | return -ENOENT; |
@@ -927,14 +926,10 @@ int die_get_typename(Dwarf_Die *vr_die, struct strbuf *buf) | |||
927 | else if (tag == DW_TAG_enumeration_type) | 926 | else if (tag == DW_TAG_enumeration_type) |
928 | tmp = "enum "; | 927 | tmp = "enum "; |
929 | /* Write a base name */ | 928 | /* Write a base name */ |
930 | strbuf_addf(buf, "%s%s", tmp, dwarf_diename(&type)); | 929 | return strbuf_addf(buf, "%s%s", tmp, dwarf_diename(&type)); |
931 | return 0; | ||
932 | } | 930 | } |
933 | ret = die_get_typename(&type, buf); | 931 | ret = die_get_typename(&type, buf); |
934 | if (ret == 0) | 932 | return ret ? ret : strbuf_addstr(buf, tmp); |
935 | strbuf_addstr(buf, tmp); | ||
936 | |||
937 | return ret; | ||
938 | } | 933 | } |
939 | 934 | ||
940 | /** | 935 | /** |
@@ -951,14 +946,13 @@ int die_get_varname(Dwarf_Die *vr_die, struct strbuf *buf) | |||
951 | ret = die_get_typename(vr_die, buf); | 946 | ret = die_get_typename(vr_die, buf); |
952 | if (ret < 0) { | 947 | if (ret < 0) { |
953 | pr_debug("Failed to get type, make it unknown.\n"); | 948 | pr_debug("Failed to get type, make it unknown.\n"); |
954 | strbuf_add(buf, " (unknown_type)", 14); | 949 | ret = strbuf_add(buf, " (unknown_type)", 14); |
955 | } | 950 | } |
956 | 951 | ||
957 | strbuf_addf(buf, "\t%s", dwarf_diename(vr_die)); | 952 | return ret < 0 ? ret : strbuf_addf(buf, "\t%s", dwarf_diename(vr_die)); |
958 | |||
959 | return 0; | ||
960 | } | 953 | } |
961 | 954 | ||
955 | #ifdef HAVE_DWARF_GETLOCATIONS | ||
962 | /** | 956 | /** |
963 | * die_get_var_innermost_scope - Get innermost scope range of given variable DIE | 957 | * die_get_var_innermost_scope - Get innermost scope range of given variable DIE |
964 | * @sp_die: a subprogram DIE | 958 | * @sp_die: a subprogram DIE |
@@ -998,22 +992,24 @@ static int die_get_var_innermost_scope(Dwarf_Die *sp_die, Dwarf_Die *vr_die, | |||
998 | } | 992 | } |
999 | 993 | ||
1000 | while ((offset = dwarf_ranges(&scopes[1], offset, &base, | 994 | while ((offset = dwarf_ranges(&scopes[1], offset, &base, |
1001 | &start, &end)) > 0) { | 995 | &start, &end)) > 0) { |
1002 | start -= entry; | 996 | start -= entry; |
1003 | end -= entry; | 997 | end -= entry; |
1004 | 998 | ||
1005 | if (first) { | 999 | if (first) { |
1006 | strbuf_addf(buf, "@<%s+[%" PRIu64 "-%" PRIu64, | 1000 | ret = strbuf_addf(buf, "@<%s+[%" PRIu64 "-%" PRIu64, |
1007 | name, start, end); | 1001 | name, start, end); |
1008 | first = false; | 1002 | first = false; |
1009 | } else { | 1003 | } else { |
1010 | strbuf_addf(buf, ",%" PRIu64 "-%" PRIu64, | 1004 | ret = strbuf_addf(buf, ",%" PRIu64 "-%" PRIu64, |
1011 | start, end); | 1005 | start, end); |
1012 | } | 1006 | } |
1007 | if (ret < 0) | ||
1008 | goto out; | ||
1013 | } | 1009 | } |
1014 | 1010 | ||
1015 | if (!first) | 1011 | if (!first) |
1016 | strbuf_add(buf, "]>", 2); | 1012 | ret = strbuf_add(buf, "]>", 2); |
1017 | 1013 | ||
1018 | out: | 1014 | out: |
1019 | free(scopes); | 1015 | free(scopes); |
@@ -1053,30 +1049,39 @@ int die_get_var_range(Dwarf_Die *sp_die, Dwarf_Die *vr_die, struct strbuf *buf) | |||
1053 | if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) | 1049 | if (dwarf_attr(vr_die, DW_AT_location, &attr) == NULL) |
1054 | return -EINVAL; | 1050 | return -EINVAL; |
1055 | 1051 | ||
1056 | while ((offset = dwarf_getlocations( | 1052 | while ((offset = dwarf_getlocations(&attr, offset, &base, |
1057 | &attr, offset, &base, | 1053 | &start, &end, &op, &nops)) > 0) { |
1058 | &start, &end, &op, &nops)) > 0) { | ||
1059 | if (start == 0) { | 1054 | if (start == 0) { |
1060 | /* Single Location Descriptions */ | 1055 | /* Single Location Descriptions */ |
1061 | ret = die_get_var_innermost_scope(sp_die, vr_die, buf); | 1056 | ret = die_get_var_innermost_scope(sp_die, vr_die, buf); |
1062 | return ret; | 1057 | goto out; |
1063 | } | 1058 | } |
1064 | 1059 | ||
1065 | /* Location Lists */ | 1060 | /* Location Lists */ |
1066 | start -= entry; | 1061 | start -= entry; |
1067 | end -= entry; | 1062 | end -= entry; |
1068 | if (first) { | 1063 | if (first) { |
1069 | strbuf_addf(buf, "@<%s+[%" PRIu64 "-%" PRIu64, | 1064 | ret = strbuf_addf(buf, "@<%s+[%" PRIu64 "-%" PRIu64, |
1070 | name, start, end); | 1065 | name, start, end); |
1071 | first = false; | 1066 | first = false; |
1072 | } else { | 1067 | } else { |
1073 | strbuf_addf(buf, ",%" PRIu64 "-%" PRIu64, | 1068 | ret = strbuf_addf(buf, ",%" PRIu64 "-%" PRIu64, |
1074 | start, end); | 1069 | start, end); |
1075 | } | 1070 | } |
1071 | if (ret < 0) | ||
1072 | goto out; | ||
1076 | } | 1073 | } |
1077 | 1074 | ||
1078 | if (!first) | 1075 | if (!first) |
1079 | strbuf_add(buf, "]>", 2); | 1076 | ret = strbuf_add(buf, "]>", 2); |
1080 | 1077 | out: | |
1081 | return ret; | 1078 | return ret; |
1082 | } | 1079 | } |
1080 | #else | ||
1081 | int die_get_var_range(Dwarf_Die *sp_die __maybe_unused, | ||
1082 | Dwarf_Die *vr_die __maybe_unused, | ||
1083 | struct strbuf *buf __maybe_unused) | ||
1084 | { | ||
1085 | return -ENOTSUP; | ||
1086 | } | ||
1087 | #endif | ||
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index dad55d04ffdd..f6fcc6832949 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -45,6 +45,7 @@ static const char *perf_event__names[] = { | |||
45 | [PERF_RECORD_STAT] = "STAT", | 45 | [PERF_RECORD_STAT] = "STAT", |
46 | [PERF_RECORD_STAT_ROUND] = "STAT_ROUND", | 46 | [PERF_RECORD_STAT_ROUND] = "STAT_ROUND", |
47 | [PERF_RECORD_EVENT_UPDATE] = "EVENT_UPDATE", | 47 | [PERF_RECORD_EVENT_UPDATE] = "EVENT_UPDATE", |
48 | [PERF_RECORD_TIME_CONV] = "TIME_CONV", | ||
48 | }; | 49 | }; |
49 | 50 | ||
50 | const char *perf_event__name(unsigned int id) | 51 | const char *perf_event__name(unsigned int id) |
@@ -433,7 +434,7 @@ static int __event__synthesize_thread(union perf_event *comm_event, | |||
433 | { | 434 | { |
434 | char filename[PATH_MAX]; | 435 | char filename[PATH_MAX]; |
435 | DIR *tasks; | 436 | DIR *tasks; |
436 | struct dirent dirent, *next; | 437 | struct dirent *dirent; |
437 | pid_t tgid, ppid; | 438 | pid_t tgid, ppid; |
438 | int rc = 0; | 439 | int rc = 0; |
439 | 440 | ||
@@ -462,11 +463,11 @@ static int __event__synthesize_thread(union perf_event *comm_event, | |||
462 | return 0; | 463 | return 0; |
463 | } | 464 | } |
464 | 465 | ||
465 | while (!readdir_r(tasks, &dirent, &next) && next) { | 466 | while ((dirent = readdir(tasks)) != NULL) { |
466 | char *end; | 467 | char *end; |
467 | pid_t _pid; | 468 | pid_t _pid; |
468 | 469 | ||
469 | _pid = strtol(dirent.d_name, &end, 10); | 470 | _pid = strtol(dirent->d_name, &end, 10); |
470 | if (*end) | 471 | if (*end) |
471 | continue; | 472 | continue; |
472 | 473 | ||
@@ -575,7 +576,7 @@ int perf_event__synthesize_threads(struct perf_tool *tool, | |||
575 | { | 576 | { |
576 | DIR *proc; | 577 | DIR *proc; |
577 | char proc_path[PATH_MAX]; | 578 | char proc_path[PATH_MAX]; |
578 | struct dirent dirent, *next; | 579 | struct dirent *dirent; |
579 | union perf_event *comm_event, *mmap_event, *fork_event; | 580 | union perf_event *comm_event, *mmap_event, *fork_event; |
580 | int err = -1; | 581 | int err = -1; |
581 | 582 | ||
@@ -600,9 +601,9 @@ int perf_event__synthesize_threads(struct perf_tool *tool, | |||
600 | if (proc == NULL) | 601 | if (proc == NULL) |
601 | goto out_free_fork; | 602 | goto out_free_fork; |
602 | 603 | ||
603 | while (!readdir_r(proc, &dirent, &next) && next) { | 604 | while ((dirent = readdir(proc)) != NULL) { |
604 | char *end; | 605 | char *end; |
605 | pid_t pid = strtol(dirent.d_name, &end, 10); | 606 | pid_t pid = strtol(dirent->d_name, &end, 10); |
606 | 607 | ||
607 | if (*end) /* only interested in proper numerical dirents */ | 608 | if (*end) /* only interested in proper numerical dirents */ |
608 | continue; | 609 | continue; |
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 6bb1c928350d..8d363d5e65a2 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -233,6 +233,7 @@ enum perf_user_event_type { /* above any possible kernel type */ | |||
233 | PERF_RECORD_STAT = 76, | 233 | PERF_RECORD_STAT = 76, |
234 | PERF_RECORD_STAT_ROUND = 77, | 234 | PERF_RECORD_STAT_ROUND = 77, |
235 | PERF_RECORD_EVENT_UPDATE = 78, | 235 | PERF_RECORD_EVENT_UPDATE = 78, |
236 | PERF_RECORD_TIME_CONV = 79, | ||
236 | PERF_RECORD_HEADER_MAX | 237 | PERF_RECORD_HEADER_MAX |
237 | }; | 238 | }; |
238 | 239 | ||
@@ -469,6 +470,13 @@ struct stat_round_event { | |||
469 | u64 time; | 470 | u64 time; |
470 | }; | 471 | }; |
471 | 472 | ||
473 | struct time_conv_event { | ||
474 | struct perf_event_header header; | ||
475 | u64 time_shift; | ||
476 | u64 time_mult; | ||
477 | u64 time_zero; | ||
478 | }; | ||
479 | |||
472 | union perf_event { | 480 | union perf_event { |
473 | struct perf_event_header header; | 481 | struct perf_event_header header; |
474 | struct mmap_event mmap; | 482 | struct mmap_event mmap; |
@@ -497,6 +505,7 @@ union perf_event { | |||
497 | struct stat_config_event stat_config; | 505 | struct stat_config_event stat_config; |
498 | struct stat_event stat; | 506 | struct stat_event stat; |
499 | struct stat_round_event stat_round; | 507 | struct stat_round_event stat_round; |
508 | struct time_conv_event time_conv; | ||
500 | }; | 509 | }; |
501 | 510 | ||
502 | void perf_event__print_totals(void); | 511 | void perf_event__print_totals(void); |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index 86a03836a83f..c4bfe11479a0 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -679,53 +679,52 @@ static struct perf_evsel *perf_evlist__event2evsel(struct perf_evlist *evlist, | |||
679 | return NULL; | 679 | return NULL; |
680 | } | 680 | } |
681 | 681 | ||
682 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) | 682 | /* When check_messup is true, 'end' must points to a good entry */ |
683 | static union perf_event * | ||
684 | perf_mmap__read(struct perf_mmap *md, bool check_messup, u64 start, | ||
685 | u64 end, u64 *prev) | ||
683 | { | 686 | { |
684 | struct perf_mmap *md = &evlist->mmap[idx]; | ||
685 | u64 head; | ||
686 | u64 old = md->prev; | ||
687 | unsigned char *data = md->base + page_size; | 687 | unsigned char *data = md->base + page_size; |
688 | union perf_event *event = NULL; | 688 | union perf_event *event = NULL; |
689 | int diff = end - start; | ||
689 | 690 | ||
690 | /* | 691 | if (check_messup) { |
691 | * Check if event was unmapped due to a POLLHUP/POLLERR. | ||
692 | */ | ||
693 | if (!atomic_read(&md->refcnt)) | ||
694 | return NULL; | ||
695 | |||
696 | head = perf_mmap__read_head(md); | ||
697 | if (evlist->overwrite) { | ||
698 | /* | 692 | /* |
699 | * If we're further behind than half the buffer, there's a chance | 693 | * If we're further behind than half the buffer, there's a chance |
700 | * the writer will bite our tail and mess up the samples under us. | 694 | * the writer will bite our tail and mess up the samples under us. |
701 | * | 695 | * |
702 | * If we somehow ended up ahead of the head, we got messed up. | 696 | * If we somehow ended up ahead of the 'end', we got messed up. |
703 | * | 697 | * |
704 | * In either case, truncate and restart at head. | 698 | * In either case, truncate and restart at 'end'. |
705 | */ | 699 | */ |
706 | int diff = head - old; | ||
707 | if (diff > md->mask / 2 || diff < 0) { | 700 | if (diff > md->mask / 2 || diff < 0) { |
708 | fprintf(stderr, "WARNING: failed to keep up with mmap data.\n"); | 701 | fprintf(stderr, "WARNING: failed to keep up with mmap data.\n"); |
709 | 702 | ||
710 | /* | 703 | /* |
711 | * head points to a known good entry, start there. | 704 | * 'end' points to a known good entry, start there. |
712 | */ | 705 | */ |
713 | old = head; | 706 | start = end; |
707 | diff = 0; | ||
714 | } | 708 | } |
715 | } | 709 | } |
716 | 710 | ||
717 | if (old != head) { | 711 | if (diff >= (int)sizeof(event->header)) { |
718 | size_t size; | 712 | size_t size; |
719 | 713 | ||
720 | event = (union perf_event *)&data[old & md->mask]; | 714 | event = (union perf_event *)&data[start & md->mask]; |
721 | size = event->header.size; | 715 | size = event->header.size; |
722 | 716 | ||
717 | if (size < sizeof(event->header) || diff < (int)size) { | ||
718 | event = NULL; | ||
719 | goto broken_event; | ||
720 | } | ||
721 | |||
723 | /* | 722 | /* |
724 | * Event straddles the mmap boundary -- header should always | 723 | * Event straddles the mmap boundary -- header should always |
725 | * be inside due to u64 alignment of output. | 724 | * be inside due to u64 alignment of output. |
726 | */ | 725 | */ |
727 | if ((old & md->mask) + size != ((old + size) & md->mask)) { | 726 | if ((start & md->mask) + size != ((start + size) & md->mask)) { |
728 | unsigned int offset = old; | 727 | unsigned int offset = start; |
729 | unsigned int len = min(sizeof(*event), size), cpy; | 728 | unsigned int len = min(sizeof(*event), size), cpy; |
730 | void *dst = md->event_copy; | 729 | void *dst = md->event_copy; |
731 | 730 | ||
@@ -740,14 +739,83 @@ union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) | |||
740 | event = (union perf_event *) md->event_copy; | 739 | event = (union perf_event *) md->event_copy; |
741 | } | 740 | } |
742 | 741 | ||
743 | old += size; | 742 | start += size; |
744 | } | 743 | } |
745 | 744 | ||
746 | md->prev = old; | 745 | broken_event: |
746 | if (prev) | ||
747 | *prev = start; | ||
747 | 748 | ||
748 | return event; | 749 | return event; |
749 | } | 750 | } |
750 | 751 | ||
752 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx) | ||
753 | { | ||
754 | struct perf_mmap *md = &evlist->mmap[idx]; | ||
755 | u64 head; | ||
756 | u64 old = md->prev; | ||
757 | |||
758 | /* | ||
759 | * Check if event was unmapped due to a POLLHUP/POLLERR. | ||
760 | */ | ||
761 | if (!atomic_read(&md->refcnt)) | ||
762 | return NULL; | ||
763 | |||
764 | head = perf_mmap__read_head(md); | ||
765 | |||
766 | return perf_mmap__read(md, evlist->overwrite, old, head, &md->prev); | ||
767 | } | ||
768 | |||
769 | union perf_event * | ||
770 | perf_evlist__mmap_read_backward(struct perf_evlist *evlist, int idx) | ||
771 | { | ||
772 | struct perf_mmap *md = &evlist->mmap[idx]; | ||
773 | u64 head, end; | ||
774 | u64 start = md->prev; | ||
775 | |||
776 | /* | ||
777 | * Check if event was unmapped due to a POLLHUP/POLLERR. | ||
778 | */ | ||
779 | if (!atomic_read(&md->refcnt)) | ||
780 | return NULL; | ||
781 | |||
782 | head = perf_mmap__read_head(md); | ||
783 | if (!head) | ||
784 | return NULL; | ||
785 | |||
786 | /* | ||
787 | * 'head' pointer starts from 0. Kernel minus sizeof(record) form | ||
788 | * it each time when kernel writes to it, so in fact 'head' is | ||
789 | * negative. 'end' pointer is made manually by adding the size of | ||
790 | * the ring buffer to 'head' pointer, means the validate data can | ||
791 | * read is the whole ring buffer. If 'end' is positive, the ring | ||
792 | * buffer has not fully filled, so we must adjust 'end' to 0. | ||
793 | * | ||
794 | * However, since both 'head' and 'end' is unsigned, we can't | ||
795 | * simply compare 'end' against 0. Here we compare '-head' and | ||
796 | * the size of the ring buffer, where -head is the number of bytes | ||
797 | * kernel write to the ring buffer. | ||
798 | */ | ||
799 | if (-head < (u64)(md->mask + 1)) | ||
800 | end = 0; | ||
801 | else | ||
802 | end = head + md->mask + 1; | ||
803 | |||
804 | return perf_mmap__read(md, false, start, end, &md->prev); | ||
805 | } | ||
806 | |||
807 | void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx) | ||
808 | { | ||
809 | struct perf_mmap *md = &evlist->mmap[idx]; | ||
810 | u64 head; | ||
811 | |||
812 | if (!atomic_read(&md->refcnt)) | ||
813 | return; | ||
814 | |||
815 | head = perf_mmap__read_head(md); | ||
816 | md->prev = head; | ||
817 | } | ||
818 | |||
751 | static bool perf_mmap__empty(struct perf_mmap *md) | 819 | static bool perf_mmap__empty(struct perf_mmap *md) |
752 | { | 820 | { |
753 | return perf_mmap__read_head(md) == md->prev && !md->auxtrace_mmap.base; | 821 | return perf_mmap__read_head(md) == md->prev && !md->auxtrace_mmap.base; |
@@ -986,26 +1054,34 @@ out_unmap: | |||
986 | return -1; | 1054 | return -1; |
987 | } | 1055 | } |
988 | 1056 | ||
989 | static size_t perf_evlist__mmap_size(unsigned long pages) | 1057 | unsigned long perf_event_mlock_kb_in_pages(void) |
990 | { | 1058 | { |
991 | if (pages == UINT_MAX) { | 1059 | unsigned long pages; |
992 | int max; | 1060 | int max; |
993 | 1061 | ||
994 | if (sysctl__read_int("kernel/perf_event_mlock_kb", &max) < 0) { | 1062 | if (sysctl__read_int("kernel/perf_event_mlock_kb", &max) < 0) { |
995 | /* | 1063 | /* |
996 | * Pick a once upon a time good value, i.e. things look | 1064 | * Pick a once upon a time good value, i.e. things look |
997 | * strange since we can't read a sysctl value, but lets not | 1065 | * strange since we can't read a sysctl value, but lets not |
998 | * die yet... | 1066 | * die yet... |
999 | */ | 1067 | */ |
1000 | max = 512; | 1068 | max = 512; |
1001 | } else { | 1069 | } else { |
1002 | max -= (page_size / 1024); | 1070 | max -= (page_size / 1024); |
1003 | } | 1071 | } |
1004 | 1072 | ||
1005 | pages = (max * 1024) / page_size; | 1073 | pages = (max * 1024) / page_size; |
1006 | if (!is_power_of_2(pages)) | 1074 | if (!is_power_of_2(pages)) |
1007 | pages = rounddown_pow_of_two(pages); | 1075 | pages = rounddown_pow_of_two(pages); |
1008 | } else if (!is_power_of_2(pages)) | 1076 | |
1077 | return pages; | ||
1078 | } | ||
1079 | |||
1080 | static size_t perf_evlist__mmap_size(unsigned long pages) | ||
1081 | { | ||
1082 | if (pages == UINT_MAX) | ||
1083 | pages = perf_event_mlock_kb_in_pages(); | ||
1084 | else if (!is_power_of_2(pages)) | ||
1009 | return 0; | 1085 | return 0; |
1010 | 1086 | ||
1011 | return (pages + 1) * page_size; | 1087 | return (pages + 1) * page_size; |
@@ -1192,6 +1268,24 @@ void perf_evlist__set_maps(struct perf_evlist *evlist, struct cpu_map *cpus, | |||
1192 | perf_evlist__propagate_maps(evlist); | 1268 | perf_evlist__propagate_maps(evlist); |
1193 | } | 1269 | } |
1194 | 1270 | ||
1271 | void __perf_evlist__set_sample_bit(struct perf_evlist *evlist, | ||
1272 | enum perf_event_sample_format bit) | ||
1273 | { | ||
1274 | struct perf_evsel *evsel; | ||
1275 | |||
1276 | evlist__for_each(evlist, evsel) | ||
1277 | __perf_evsel__set_sample_bit(evsel, bit); | ||
1278 | } | ||
1279 | |||
1280 | void __perf_evlist__reset_sample_bit(struct perf_evlist *evlist, | ||
1281 | enum perf_event_sample_format bit) | ||
1282 | { | ||
1283 | struct perf_evsel *evsel; | ||
1284 | |||
1285 | evlist__for_each(evlist, evsel) | ||
1286 | __perf_evsel__reset_sample_bit(evsel, bit); | ||
1287 | } | ||
1288 | |||
1195 | int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **err_evsel) | 1289 | int perf_evlist__apply_filters(struct perf_evlist *evlist, struct perf_evsel **err_evsel) |
1196 | { | 1290 | { |
1197 | struct perf_evsel *evsel; | 1291 | struct perf_evsel *evsel; |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index a0d15221db6e..85d1b59802e8 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -87,6 +87,17 @@ int perf_evlist__add_dummy(struct perf_evlist *evlist); | |||
87 | int perf_evlist__add_newtp(struct perf_evlist *evlist, | 87 | int perf_evlist__add_newtp(struct perf_evlist *evlist, |
88 | const char *sys, const char *name, void *handler); | 88 | const char *sys, const char *name, void *handler); |
89 | 89 | ||
90 | void __perf_evlist__set_sample_bit(struct perf_evlist *evlist, | ||
91 | enum perf_event_sample_format bit); | ||
92 | void __perf_evlist__reset_sample_bit(struct perf_evlist *evlist, | ||
93 | enum perf_event_sample_format bit); | ||
94 | |||
95 | #define perf_evlist__set_sample_bit(evlist, bit) \ | ||
96 | __perf_evlist__set_sample_bit(evlist, PERF_SAMPLE_##bit) | ||
97 | |||
98 | #define perf_evlist__reset_sample_bit(evlist, bit) \ | ||
99 | __perf_evlist__reset_sample_bit(evlist, PERF_SAMPLE_##bit) | ||
100 | |||
90 | int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter); | 101 | int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter); |
91 | int perf_evlist__set_filter_pid(struct perf_evlist *evlist, pid_t pid); | 102 | int perf_evlist__set_filter_pid(struct perf_evlist *evlist, pid_t pid); |
92 | int perf_evlist__set_filter_pids(struct perf_evlist *evlist, size_t npids, pid_t *pids); | 103 | int perf_evlist__set_filter_pids(struct perf_evlist *evlist, size_t npids, pid_t *pids); |
@@ -118,16 +129,23 @@ struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id); | |||
118 | 129 | ||
119 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx); | 130 | union perf_event *perf_evlist__mmap_read(struct perf_evlist *evlist, int idx); |
120 | 131 | ||
132 | union perf_event *perf_evlist__mmap_read_backward(struct perf_evlist *evlist, | ||
133 | int idx); | ||
134 | void perf_evlist__mmap_read_catchup(struct perf_evlist *evlist, int idx); | ||
135 | |||
121 | void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx); | 136 | void perf_evlist__mmap_consume(struct perf_evlist *evlist, int idx); |
122 | 137 | ||
123 | int perf_evlist__open(struct perf_evlist *evlist); | 138 | int perf_evlist__open(struct perf_evlist *evlist); |
124 | void perf_evlist__close(struct perf_evlist *evlist); | 139 | void perf_evlist__close(struct perf_evlist *evlist); |
125 | 140 | ||
141 | struct callchain_param; | ||
142 | |||
126 | void perf_evlist__set_id_pos(struct perf_evlist *evlist); | 143 | void perf_evlist__set_id_pos(struct perf_evlist *evlist); |
127 | bool perf_can_sample_identifier(void); | 144 | bool perf_can_sample_identifier(void); |
128 | bool perf_can_record_switch_events(void); | 145 | bool perf_can_record_switch_events(void); |
129 | bool perf_can_record_cpu_wide(void); | 146 | bool perf_can_record_cpu_wide(void); |
130 | void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts); | 147 | void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, |
148 | struct callchain_param *callchain); | ||
131 | int record_opts__config(struct record_opts *opts); | 149 | int record_opts__config(struct record_opts *opts); |
132 | 150 | ||
133 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, | 151 | int perf_evlist__prepare_workload(struct perf_evlist *evlist, |
@@ -144,6 +162,8 @@ int perf_evlist__parse_mmap_pages(const struct option *opt, | |||
144 | const char *str, | 162 | const char *str, |
145 | int unset); | 163 | int unset); |
146 | 164 | ||
165 | unsigned long perf_event_mlock_kb_in_pages(void); | ||
166 | |||
147 | int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages, | 167 | int perf_evlist__mmap_ex(struct perf_evlist *evlist, unsigned int pages, |
148 | bool overwrite, unsigned int auxtrace_pages, | 168 | bool overwrite, unsigned int auxtrace_pages, |
149 | bool auxtrace_overwrite); | 169 | bool auxtrace_overwrite); |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 738ce226002b..52c7d8884741 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -226,7 +226,8 @@ struct perf_evsel *perf_evsel__new_idx(struct perf_event_attr *attr, int idx) | |||
226 | perf_evsel__init(evsel, attr, idx); | 226 | perf_evsel__init(evsel, attr, idx); |
227 | 227 | ||
228 | if (perf_evsel__is_bpf_output(evsel)) { | 228 | if (perf_evsel__is_bpf_output(evsel)) { |
229 | evsel->attr.sample_type |= PERF_SAMPLE_RAW; | 229 | evsel->attr.sample_type |= (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | |
230 | PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD), | ||
230 | evsel->attr.sample_period = 1; | 231 | evsel->attr.sample_period = 1; |
231 | } | 232 | } |
232 | 233 | ||
@@ -561,10 +562,9 @@ int perf_evsel__group_desc(struct perf_evsel *evsel, char *buf, size_t size) | |||
561 | return ret; | 562 | return ret; |
562 | } | 563 | } |
563 | 564 | ||
564 | static void | 565 | void perf_evsel__config_callchain(struct perf_evsel *evsel, |
565 | perf_evsel__config_callgraph(struct perf_evsel *evsel, | 566 | struct record_opts *opts, |
566 | struct record_opts *opts, | 567 | struct callchain_param *param) |
567 | struct callchain_param *param) | ||
568 | { | 568 | { |
569 | bool function = perf_evsel__is_function_event(evsel); | 569 | bool function = perf_evsel__is_function_event(evsel); |
570 | struct perf_event_attr *attr = &evsel->attr; | 570 | struct perf_event_attr *attr = &evsel->attr; |
@@ -704,7 +704,7 @@ static void apply_config_terms(struct perf_evsel *evsel, | |||
704 | 704 | ||
705 | /* set perf-event callgraph */ | 705 | /* set perf-event callgraph */ |
706 | if (param.enabled) | 706 | if (param.enabled) |
707 | perf_evsel__config_callgraph(evsel, opts, ¶m); | 707 | perf_evsel__config_callchain(evsel, opts, ¶m); |
708 | } | 708 | } |
709 | } | 709 | } |
710 | 710 | ||
@@ -736,7 +736,8 @@ static void apply_config_terms(struct perf_evsel *evsel, | |||
736 | * enable/disable events specifically, as there's no | 736 | * enable/disable events specifically, as there's no |
737 | * initial traced exec call. | 737 | * initial traced exec call. |
738 | */ | 738 | */ |
739 | void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) | 739 | void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts, |
740 | struct callchain_param *callchain) | ||
740 | { | 741 | { |
741 | struct perf_evsel *leader = evsel->leader; | 742 | struct perf_evsel *leader = evsel->leader; |
742 | struct perf_event_attr *attr = &evsel->attr; | 743 | struct perf_event_attr *attr = &evsel->attr; |
@@ -811,8 +812,8 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) | |||
811 | if (perf_evsel__is_function_event(evsel)) | 812 | if (perf_evsel__is_function_event(evsel)) |
812 | evsel->attr.exclude_callchain_user = 1; | 813 | evsel->attr.exclude_callchain_user = 1; |
813 | 814 | ||
814 | if (callchain_param.enabled && !evsel->no_aux_samples) | 815 | if (callchain && callchain->enabled && !evsel->no_aux_samples) |
815 | perf_evsel__config_callgraph(evsel, opts, &callchain_param); | 816 | perf_evsel__config_callchain(evsel, opts, callchain); |
816 | 817 | ||
817 | if (opts->sample_intr_regs) { | 818 | if (opts->sample_intr_regs) { |
818 | attr->sample_regs_intr = opts->sample_intr_regs; | 819 | attr->sample_regs_intr = opts->sample_intr_regs; |
@@ -826,7 +827,7 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts) | |||
826 | perf_evsel__set_sample_bit(evsel, PERIOD); | 827 | perf_evsel__set_sample_bit(evsel, PERIOD); |
827 | 828 | ||
828 | /* | 829 | /* |
829 | * When the user explicitely disabled time don't force it here. | 830 | * When the user explicitly disabled time don't force it here. |
830 | */ | 831 | */ |
831 | if (opts->sample_time && | 832 | if (opts->sample_time && |
832 | (!perf_missing_features.sample_id_all && | 833 | (!perf_missing_features.sample_id_all && |
@@ -1230,6 +1231,21 @@ static void __p_sample_type(char *buf, size_t size, u64 value) | |||
1230 | __p_bits(buf, size, value, bits); | 1231 | __p_bits(buf, size, value, bits); |
1231 | } | 1232 | } |
1232 | 1233 | ||
1234 | static void __p_branch_sample_type(char *buf, size_t size, u64 value) | ||
1235 | { | ||
1236 | #define bit_name(n) { PERF_SAMPLE_BRANCH_##n, #n } | ||
1237 | struct bit_names bits[] = { | ||
1238 | bit_name(USER), bit_name(KERNEL), bit_name(HV), bit_name(ANY), | ||
1239 | bit_name(ANY_CALL), bit_name(ANY_RETURN), bit_name(IND_CALL), | ||
1240 | bit_name(ABORT_TX), bit_name(IN_TX), bit_name(NO_TX), | ||
1241 | bit_name(COND), bit_name(CALL_STACK), bit_name(IND_JUMP), | ||
1242 | bit_name(CALL), bit_name(NO_FLAGS), bit_name(NO_CYCLES), | ||
1243 | { .name = NULL, } | ||
1244 | }; | ||
1245 | #undef bit_name | ||
1246 | __p_bits(buf, size, value, bits); | ||
1247 | } | ||
1248 | |||
1233 | static void __p_read_format(char *buf, size_t size, u64 value) | 1249 | static void __p_read_format(char *buf, size_t size, u64 value) |
1234 | { | 1250 | { |
1235 | #define bit_name(n) { PERF_FORMAT_##n, #n } | 1251 | #define bit_name(n) { PERF_FORMAT_##n, #n } |
@@ -1248,6 +1264,7 @@ static void __p_read_format(char *buf, size_t size, u64 value) | |||
1248 | #define p_unsigned(val) snprintf(buf, BUF_SIZE, "%"PRIu64, (uint64_t)(val)) | 1264 | #define p_unsigned(val) snprintf(buf, BUF_SIZE, "%"PRIu64, (uint64_t)(val)) |
1249 | #define p_signed(val) snprintf(buf, BUF_SIZE, "%"PRId64, (int64_t)(val)) | 1265 | #define p_signed(val) snprintf(buf, BUF_SIZE, "%"PRId64, (int64_t)(val)) |
1250 | #define p_sample_type(val) __p_sample_type(buf, BUF_SIZE, val) | 1266 | #define p_sample_type(val) __p_sample_type(buf, BUF_SIZE, val) |
1267 | #define p_branch_sample_type(val) __p_branch_sample_type(buf, BUF_SIZE, val) | ||
1251 | #define p_read_format(val) __p_read_format(buf, BUF_SIZE, val) | 1268 | #define p_read_format(val) __p_read_format(buf, BUF_SIZE, val) |
1252 | 1269 | ||
1253 | #define PRINT_ATTRn(_n, _f, _p) \ | 1270 | #define PRINT_ATTRn(_n, _f, _p) \ |
@@ -1299,12 +1316,13 @@ int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, | |||
1299 | PRINT_ATTRf(comm_exec, p_unsigned); | 1316 | PRINT_ATTRf(comm_exec, p_unsigned); |
1300 | PRINT_ATTRf(use_clockid, p_unsigned); | 1317 | PRINT_ATTRf(use_clockid, p_unsigned); |
1301 | PRINT_ATTRf(context_switch, p_unsigned); | 1318 | PRINT_ATTRf(context_switch, p_unsigned); |
1319 | PRINT_ATTRf(write_backward, p_unsigned); | ||
1302 | 1320 | ||
1303 | PRINT_ATTRn("{ wakeup_events, wakeup_watermark }", wakeup_events, p_unsigned); | 1321 | PRINT_ATTRn("{ wakeup_events, wakeup_watermark }", wakeup_events, p_unsigned); |
1304 | PRINT_ATTRf(bp_type, p_unsigned); | 1322 | PRINT_ATTRf(bp_type, p_unsigned); |
1305 | PRINT_ATTRn("{ bp_addr, config1 }", bp_addr, p_hex); | 1323 | PRINT_ATTRn("{ bp_addr, config1 }", bp_addr, p_hex); |
1306 | PRINT_ATTRn("{ bp_len, config2 }", bp_len, p_hex); | 1324 | PRINT_ATTRn("{ bp_len, config2 }", bp_len, p_hex); |
1307 | PRINT_ATTRf(branch_sample_type, p_unsigned); | 1325 | PRINT_ATTRf(branch_sample_type, p_branch_sample_type); |
1308 | PRINT_ATTRf(sample_regs_user, p_hex); | 1326 | PRINT_ATTRf(sample_regs_user, p_hex); |
1309 | PRINT_ATTRf(sample_stack_user, p_unsigned); | 1327 | PRINT_ATTRf(sample_stack_user, p_unsigned); |
1310 | PRINT_ATTRf(clockid, p_signed); | 1328 | PRINT_ATTRf(clockid, p_signed); |
@@ -2253,98 +2271,11 @@ u64 perf_evsel__intval(struct perf_evsel *evsel, struct perf_sample *sample, | |||
2253 | return 0; | 2271 | return 0; |
2254 | } | 2272 | } |
2255 | 2273 | ||
2256 | static int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...) | ||
2257 | { | ||
2258 | va_list args; | ||
2259 | int ret = 0; | ||
2260 | |||
2261 | if (!*first) { | ||
2262 | ret += fprintf(fp, ","); | ||
2263 | } else { | ||
2264 | ret += fprintf(fp, ":"); | ||
2265 | *first = false; | ||
2266 | } | ||
2267 | |||
2268 | va_start(args, fmt); | ||
2269 | ret += vfprintf(fp, fmt, args); | ||
2270 | va_end(args); | ||
2271 | return ret; | ||
2272 | } | ||
2273 | |||
2274 | static int __print_attr__fprintf(FILE *fp, const char *name, const char *val, void *priv) | ||
2275 | { | ||
2276 | return comma_fprintf(fp, (bool *)priv, " %s: %s", name, val); | ||
2277 | } | ||
2278 | |||
2279 | int perf_evsel__fprintf(struct perf_evsel *evsel, | ||
2280 | struct perf_attr_details *details, FILE *fp) | ||
2281 | { | ||
2282 | bool first = true; | ||
2283 | int printed = 0; | ||
2284 | |||
2285 | if (details->event_group) { | ||
2286 | struct perf_evsel *pos; | ||
2287 | |||
2288 | if (!perf_evsel__is_group_leader(evsel)) | ||
2289 | return 0; | ||
2290 | |||
2291 | if (evsel->nr_members > 1) | ||
2292 | printed += fprintf(fp, "%s{", evsel->group_name ?: ""); | ||
2293 | |||
2294 | printed += fprintf(fp, "%s", perf_evsel__name(evsel)); | ||
2295 | for_each_group_member(pos, evsel) | ||
2296 | printed += fprintf(fp, ",%s", perf_evsel__name(pos)); | ||
2297 | |||
2298 | if (evsel->nr_members > 1) | ||
2299 | printed += fprintf(fp, "}"); | ||
2300 | goto out; | ||
2301 | } | ||
2302 | |||
2303 | printed += fprintf(fp, "%s", perf_evsel__name(evsel)); | ||
2304 | |||
2305 | if (details->verbose) { | ||
2306 | printed += perf_event_attr__fprintf(fp, &evsel->attr, | ||
2307 | __print_attr__fprintf, &first); | ||
2308 | } else if (details->freq) { | ||
2309 | const char *term = "sample_freq"; | ||
2310 | |||
2311 | if (!evsel->attr.freq) | ||
2312 | term = "sample_period"; | ||
2313 | |||
2314 | printed += comma_fprintf(fp, &first, " %s=%" PRIu64, | ||
2315 | term, (u64)evsel->attr.sample_freq); | ||
2316 | } | ||
2317 | |||
2318 | if (details->trace_fields) { | ||
2319 | struct format_field *field; | ||
2320 | |||
2321 | if (evsel->attr.type != PERF_TYPE_TRACEPOINT) { | ||
2322 | printed += comma_fprintf(fp, &first, " (not a tracepoint)"); | ||
2323 | goto out; | ||
2324 | } | ||
2325 | |||
2326 | field = evsel->tp_format->format.fields; | ||
2327 | if (field == NULL) { | ||
2328 | printed += comma_fprintf(fp, &first, " (no trace field)"); | ||
2329 | goto out; | ||
2330 | } | ||
2331 | |||
2332 | printed += comma_fprintf(fp, &first, " trace_fields: %s", field->name); | ||
2333 | |||
2334 | field = field->next; | ||
2335 | while (field) { | ||
2336 | printed += comma_fprintf(fp, &first, "%s", field->name); | ||
2337 | field = field->next; | ||
2338 | } | ||
2339 | } | ||
2340 | out: | ||
2341 | fputc('\n', fp); | ||
2342 | return ++printed; | ||
2343 | } | ||
2344 | |||
2345 | bool perf_evsel__fallback(struct perf_evsel *evsel, int err, | 2274 | bool perf_evsel__fallback(struct perf_evsel *evsel, int err, |
2346 | char *msg, size_t msgsize) | 2275 | char *msg, size_t msgsize) |
2347 | { | 2276 | { |
2277 | int paranoid; | ||
2278 | |||
2348 | if ((err == ENOENT || err == ENXIO || err == ENODEV) && | 2279 | if ((err == ENOENT || err == ENXIO || err == ENODEV) && |
2349 | evsel->attr.type == PERF_TYPE_HARDWARE && | 2280 | evsel->attr.type == PERF_TYPE_HARDWARE && |
2350 | evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES) { | 2281 | evsel->attr.config == PERF_COUNT_HW_CPU_CYCLES) { |
@@ -2364,6 +2295,22 @@ bool perf_evsel__fallback(struct perf_evsel *evsel, int err, | |||
2364 | 2295 | ||
2365 | zfree(&evsel->name); | 2296 | zfree(&evsel->name); |
2366 | return true; | 2297 | return true; |
2298 | } else if (err == EACCES && !evsel->attr.exclude_kernel && | ||
2299 | (paranoid = perf_event_paranoid()) > 1) { | ||
2300 | const char *name = perf_evsel__name(evsel); | ||
2301 | char *new_name; | ||
2302 | |||
2303 | if (asprintf(&new_name, "%s%su", name, strchr(name, ':') ? "" : ":") < 0) | ||
2304 | return false; | ||
2305 | |||
2306 | if (evsel->name) | ||
2307 | free(evsel->name); | ||
2308 | evsel->name = new_name; | ||
2309 | scnprintf(msg, msgsize, | ||
2310 | "kernel.perf_event_paranoid=%d, trying to fall back to excluding kernel samples", paranoid); | ||
2311 | evsel->attr.exclude_kernel = 1; | ||
2312 | |||
2313 | return true; | ||
2367 | } | 2314 | } |
2368 | 2315 | ||
2369 | return false; | 2316 | return false; |
@@ -2382,12 +2329,13 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, | |||
2382 | "Consider tweaking /proc/sys/kernel/perf_event_paranoid,\n" | 2329 | "Consider tweaking /proc/sys/kernel/perf_event_paranoid,\n" |
2383 | "which controls use of the performance events system by\n" | 2330 | "which controls use of the performance events system by\n" |
2384 | "unprivileged users (without CAP_SYS_ADMIN).\n\n" | 2331 | "unprivileged users (without CAP_SYS_ADMIN).\n\n" |
2385 | "The default value is 1:\n\n" | 2332 | "The current value is %d:\n\n" |
2386 | " -1: Allow use of (almost) all events by all users\n" | 2333 | " -1: Allow use of (almost) all events by all users\n" |
2387 | ">= 0: Disallow raw tracepoint access by users without CAP_IOC_LOCK\n" | 2334 | ">= 0: Disallow raw tracepoint access by users without CAP_IOC_LOCK\n" |
2388 | ">= 1: Disallow CPU event access by users without CAP_SYS_ADMIN\n" | 2335 | ">= 1: Disallow CPU event access by users without CAP_SYS_ADMIN\n" |
2389 | ">= 2: Disallow kernel profiling by users without CAP_SYS_ADMIN", | 2336 | ">= 2: Disallow kernel profiling by users without CAP_SYS_ADMIN", |
2390 | target->system_wide ? "system-wide " : ""); | 2337 | target->system_wide ? "system-wide " : "", |
2338 | perf_event_paranoid()); | ||
2391 | case ENOENT: | 2339 | case ENOENT: |
2392 | return scnprintf(msg, size, "The %s event is not supported.", | 2340 | return scnprintf(msg, size, "The %s event is not supported.", |
2393 | perf_evsel__name(evsel)); | 2341 | perf_evsel__name(evsel)); |
@@ -2397,10 +2345,18 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, | |||
2397 | "Probably the maximum number of open file descriptors has been reached.\n" | 2345 | "Probably the maximum number of open file descriptors has been reached.\n" |
2398 | "Hint: Try again after reducing the number of events.\n" | 2346 | "Hint: Try again after reducing the number of events.\n" |
2399 | "Hint: Try increasing the limit with 'ulimit -n <limit>'"); | 2347 | "Hint: Try increasing the limit with 'ulimit -n <limit>'"); |
2348 | case ENOMEM: | ||
2349 | if ((evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) != 0 && | ||
2350 | access("/proc/sys/kernel/perf_event_max_stack", F_OK) == 0) | ||
2351 | return scnprintf(msg, size, | ||
2352 | "Not enough memory to setup event with callchain.\n" | ||
2353 | "Hint: Try tweaking /proc/sys/kernel/perf_event_max_stack\n" | ||
2354 | "Hint: Current value: %d", sysctl_perf_event_max_stack); | ||
2355 | break; | ||
2400 | case ENODEV: | 2356 | case ENODEV: |
2401 | if (target->cpu_list) | 2357 | if (target->cpu_list) |
2402 | return scnprintf(msg, size, "%s", | 2358 | return scnprintf(msg, size, "%s", |
2403 | "No such device - did you specify an out-of-range profile CPU?\n"); | 2359 | "No such device - did you specify an out-of-range profile CPU?"); |
2404 | break; | 2360 | break; |
2405 | case EOPNOTSUPP: | 2361 | case EOPNOTSUPP: |
2406 | if (evsel->attr.precise_ip) | 2362 | if (evsel->attr.precise_ip) |
@@ -2432,7 +2388,7 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, | |||
2432 | return scnprintf(msg, size, | 2388 | return scnprintf(msg, size, |
2433 | "The sys_perf_event_open() syscall returned with %d (%s) for event (%s).\n" | 2389 | "The sys_perf_event_open() syscall returned with %d (%s) for event (%s).\n" |
2434 | "/bin/dmesg may provide additional information.\n" | 2390 | "/bin/dmesg may provide additional information.\n" |
2435 | "No CONFIG_PERF_EVENTS=y kernel support configured?\n", | 2391 | "No CONFIG_PERF_EVENTS=y kernel support configured?", |
2436 | err, strerror_r(err, sbuf, sizeof(sbuf)), | 2392 | err, strerror_r(err, sbuf, sizeof(sbuf)), |
2437 | perf_evsel__name(evsel)); | 2393 | perf_evsel__name(evsel)); |
2438 | } | 2394 | } |
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index 501ea6e565f1..8a644fef452c 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h | |||
@@ -178,8 +178,14 @@ void perf_evsel__init(struct perf_evsel *evsel, | |||
178 | void perf_evsel__exit(struct perf_evsel *evsel); | 178 | void perf_evsel__exit(struct perf_evsel *evsel); |
179 | void perf_evsel__delete(struct perf_evsel *evsel); | 179 | void perf_evsel__delete(struct perf_evsel *evsel); |
180 | 180 | ||
181 | struct callchain_param; | ||
182 | |||
181 | void perf_evsel__config(struct perf_evsel *evsel, | 183 | void perf_evsel__config(struct perf_evsel *evsel, |
182 | struct record_opts *opts); | 184 | struct record_opts *opts, |
185 | struct callchain_param *callchain); | ||
186 | void perf_evsel__config_callchain(struct perf_evsel *evsel, | ||
187 | struct record_opts *opts, | ||
188 | struct callchain_param *callchain); | ||
183 | 189 | ||
184 | int __perf_evsel__sample_size(u64 sample_type); | 190 | int __perf_evsel__sample_size(u64 sample_type); |
185 | void perf_evsel__calc_id_pos(struct perf_evsel *evsel); | 191 | void perf_evsel__calc_id_pos(struct perf_evsel *evsel); |
@@ -381,6 +387,24 @@ struct perf_attr_details { | |||
381 | int perf_evsel__fprintf(struct perf_evsel *evsel, | 387 | int perf_evsel__fprintf(struct perf_evsel *evsel, |
382 | struct perf_attr_details *details, FILE *fp); | 388 | struct perf_attr_details *details, FILE *fp); |
383 | 389 | ||
390 | #define EVSEL__PRINT_IP (1<<0) | ||
391 | #define EVSEL__PRINT_SYM (1<<1) | ||
392 | #define EVSEL__PRINT_DSO (1<<2) | ||
393 | #define EVSEL__PRINT_SYMOFFSET (1<<3) | ||
394 | #define EVSEL__PRINT_ONELINE (1<<4) | ||
395 | #define EVSEL__PRINT_SRCLINE (1<<5) | ||
396 | #define EVSEL__PRINT_UNKNOWN_AS_ADDR (1<<6) | ||
397 | |||
398 | struct callchain_cursor; | ||
399 | |||
400 | int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment, | ||
401 | unsigned int print_opts, | ||
402 | struct callchain_cursor *cursor, FILE *fp); | ||
403 | |||
404 | int sample__fprintf_sym(struct perf_sample *sample, struct addr_location *al, | ||
405 | int left_alignment, unsigned int print_opts, | ||
406 | struct callchain_cursor *cursor, FILE *fp); | ||
407 | |||
384 | bool perf_evsel__fallback(struct perf_evsel *evsel, int err, | 408 | bool perf_evsel__fallback(struct perf_evsel *evsel, int err, |
385 | char *msg, size_t msgsize); | 409 | char *msg, size_t msgsize); |
386 | int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, | 410 | int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, |
@@ -396,7 +420,7 @@ for ((_evsel) = list_entry((_leader)->node.next, struct perf_evsel, node); \ | |||
396 | (_evsel) && (_evsel)->leader == (_leader); \ | 420 | (_evsel) && (_evsel)->leader == (_leader); \ |
397 | (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node)) | 421 | (_evsel) = list_entry((_evsel)->node.next, struct perf_evsel, node)) |
398 | 422 | ||
399 | static inline bool has_branch_callstack(struct perf_evsel *evsel) | 423 | static inline bool perf_evsel__has_branch_callstack(const struct perf_evsel *evsel) |
400 | { | 424 | { |
401 | return evsel->attr.branch_sample_type & PERF_SAMPLE_BRANCH_CALL_STACK; | 425 | return evsel->attr.branch_sample_type & PERF_SAMPLE_BRANCH_CALL_STACK; |
402 | } | 426 | } |
diff --git a/tools/perf/util/evsel_fprintf.c b/tools/perf/util/evsel_fprintf.c new file mode 100644 index 000000000000..3674e77ad640 --- /dev/null +++ b/tools/perf/util/evsel_fprintf.c | |||
@@ -0,0 +1,212 @@ | |||
1 | #include <stdio.h> | ||
2 | #include <stdbool.h> | ||
3 | #include <traceevent/event-parse.h> | ||
4 | #include "evsel.h" | ||
5 | #include "callchain.h" | ||
6 | #include "map.h" | ||
7 | #include "symbol.h" | ||
8 | |||
9 | static int comma_fprintf(FILE *fp, bool *first, const char *fmt, ...) | ||
10 | { | ||
11 | va_list args; | ||
12 | int ret = 0; | ||
13 | |||
14 | if (!*first) { | ||
15 | ret += fprintf(fp, ","); | ||
16 | } else { | ||
17 | ret += fprintf(fp, ":"); | ||
18 | *first = false; | ||
19 | } | ||
20 | |||
21 | va_start(args, fmt); | ||
22 | ret += vfprintf(fp, fmt, args); | ||
23 | va_end(args); | ||
24 | return ret; | ||
25 | } | ||
26 | |||
27 | static int __print_attr__fprintf(FILE *fp, const char *name, const char *val, void *priv) | ||
28 | { | ||
29 | return comma_fprintf(fp, (bool *)priv, " %s: %s", name, val); | ||
30 | } | ||
31 | |||
32 | int perf_evsel__fprintf(struct perf_evsel *evsel, | ||
33 | struct perf_attr_details *details, FILE *fp) | ||
34 | { | ||
35 | bool first = true; | ||
36 | int printed = 0; | ||
37 | |||
38 | if (details->event_group) { | ||
39 | struct perf_evsel *pos; | ||
40 | |||
41 | if (!perf_evsel__is_group_leader(evsel)) | ||
42 | return 0; | ||
43 | |||
44 | if (evsel->nr_members > 1) | ||
45 | printed += fprintf(fp, "%s{", evsel->group_name ?: ""); | ||
46 | |||
47 | printed += fprintf(fp, "%s", perf_evsel__name(evsel)); | ||
48 | for_each_group_member(pos, evsel) | ||
49 | printed += fprintf(fp, ",%s", perf_evsel__name(pos)); | ||
50 | |||
51 | if (evsel->nr_members > 1) | ||
52 | printed += fprintf(fp, "}"); | ||
53 | goto out; | ||
54 | } | ||
55 | |||
56 | printed += fprintf(fp, "%s", perf_evsel__name(evsel)); | ||
57 | |||
58 | if (details->verbose) { | ||
59 | printed += perf_event_attr__fprintf(fp, &evsel->attr, | ||
60 | __print_attr__fprintf, &first); | ||
61 | } else if (details->freq) { | ||
62 | const char *term = "sample_freq"; | ||
63 | |||
64 | if (!evsel->attr.freq) | ||
65 | term = "sample_period"; | ||
66 | |||
67 | printed += comma_fprintf(fp, &first, " %s=%" PRIu64, | ||
68 | term, (u64)evsel->attr.sample_freq); | ||
69 | } | ||
70 | |||
71 | if (details->trace_fields) { | ||
72 | struct format_field *field; | ||
73 | |||
74 | if (evsel->attr.type != PERF_TYPE_TRACEPOINT) { | ||
75 | printed += comma_fprintf(fp, &first, " (not a tracepoint)"); | ||
76 | goto out; | ||
77 | } | ||
78 | |||
79 | field = evsel->tp_format->format.fields; | ||
80 | if (field == NULL) { | ||
81 | printed += comma_fprintf(fp, &first, " (no trace field)"); | ||
82 | goto out; | ||
83 | } | ||
84 | |||
85 | printed += comma_fprintf(fp, &first, " trace_fields: %s", field->name); | ||
86 | |||
87 | field = field->next; | ||
88 | while (field) { | ||
89 | printed += comma_fprintf(fp, &first, "%s", field->name); | ||
90 | field = field->next; | ||
91 | } | ||
92 | } | ||
93 | out: | ||
94 | fputc('\n', fp); | ||
95 | return ++printed; | ||
96 | } | ||
97 | |||
98 | int sample__fprintf_callchain(struct perf_sample *sample, int left_alignment, | ||
99 | unsigned int print_opts, struct callchain_cursor *cursor, | ||
100 | FILE *fp) | ||
101 | { | ||
102 | int printed = 0; | ||
103 | struct callchain_cursor_node *node; | ||
104 | int print_ip = print_opts & EVSEL__PRINT_IP; | ||
105 | int print_sym = print_opts & EVSEL__PRINT_SYM; | ||
106 | int print_dso = print_opts & EVSEL__PRINT_DSO; | ||
107 | int print_symoffset = print_opts & EVSEL__PRINT_SYMOFFSET; | ||
108 | int print_oneline = print_opts & EVSEL__PRINT_ONELINE; | ||
109 | int print_srcline = print_opts & EVSEL__PRINT_SRCLINE; | ||
110 | int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR; | ||
111 | char s = print_oneline ? ' ' : '\t'; | ||
112 | |||
113 | if (sample->callchain) { | ||
114 | struct addr_location node_al; | ||
115 | |||
116 | callchain_cursor_commit(cursor); | ||
117 | |||
118 | while (1) { | ||
119 | u64 addr = 0; | ||
120 | |||
121 | node = callchain_cursor_current(cursor); | ||
122 | if (!node) | ||
123 | break; | ||
124 | |||
125 | if (node->sym && node->sym->ignore) | ||
126 | goto next; | ||
127 | |||
128 | printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " "); | ||
129 | |||
130 | if (print_ip) | ||
131 | printed += fprintf(fp, "%c%16" PRIx64, s, node->ip); | ||
132 | |||
133 | if (node->map) | ||
134 | addr = node->map->map_ip(node->map, node->ip); | ||
135 | |||
136 | if (print_sym) { | ||
137 | printed += fprintf(fp, " "); | ||
138 | node_al.addr = addr; | ||
139 | node_al.map = node->map; | ||
140 | |||
141 | if (print_symoffset) { | ||
142 | printed += __symbol__fprintf_symname_offs(node->sym, &node_al, | ||
143 | print_unknown_as_addr, fp); | ||
144 | } else { | ||
145 | printed += __symbol__fprintf_symname(node->sym, &node_al, | ||
146 | print_unknown_as_addr, fp); | ||
147 | } | ||
148 | } | ||
149 | |||
150 | if (print_dso) { | ||
151 | printed += fprintf(fp, " ("); | ||
152 | printed += map__fprintf_dsoname(node->map, fp); | ||
153 | printed += fprintf(fp, ")"); | ||
154 | } | ||
155 | |||
156 | if (print_srcline) | ||
157 | printed += map__fprintf_srcline(node->map, addr, "\n ", fp); | ||
158 | |||
159 | if (!print_oneline) | ||
160 | printed += fprintf(fp, "\n"); | ||
161 | next: | ||
162 | callchain_cursor_advance(cursor); | ||
163 | } | ||
164 | } | ||
165 | |||
166 | return printed; | ||
167 | } | ||
168 | |||
169 | int sample__fprintf_sym(struct perf_sample *sample, struct addr_location *al, | ||
170 | int left_alignment, unsigned int print_opts, | ||
171 | struct callchain_cursor *cursor, FILE *fp) | ||
172 | { | ||
173 | int printed = 0; | ||
174 | int print_ip = print_opts & EVSEL__PRINT_IP; | ||
175 | int print_sym = print_opts & EVSEL__PRINT_SYM; | ||
176 | int print_dso = print_opts & EVSEL__PRINT_DSO; | ||
177 | int print_symoffset = print_opts & EVSEL__PRINT_SYMOFFSET; | ||
178 | int print_srcline = print_opts & EVSEL__PRINT_SRCLINE; | ||
179 | int print_unknown_as_addr = print_opts & EVSEL__PRINT_UNKNOWN_AS_ADDR; | ||
180 | |||
181 | if (cursor != NULL) { | ||
182 | printed += sample__fprintf_callchain(sample, left_alignment, | ||
183 | print_opts, cursor, fp); | ||
184 | } else if (!(al->sym && al->sym->ignore)) { | ||
185 | printed += fprintf(fp, "%-*.*s", left_alignment, left_alignment, " "); | ||
186 | |||
187 | if (print_ip) | ||
188 | printed += fprintf(fp, "%16" PRIx64, sample->ip); | ||
189 | |||
190 | if (print_sym) { | ||
191 | printed += fprintf(fp, " "); | ||
192 | if (print_symoffset) { | ||
193 | printed += __symbol__fprintf_symname_offs(al->sym, al, | ||
194 | print_unknown_as_addr, fp); | ||
195 | } else { | ||
196 | printed += __symbol__fprintf_symname(al->sym, al, | ||
197 | print_unknown_as_addr, fp); | ||
198 | } | ||
199 | } | ||
200 | |||
201 | if (print_dso) { | ||
202 | printed += fprintf(fp, " ("); | ||
203 | printed += map__fprintf_dsoname(al->map, fp); | ||
204 | printed += fprintf(fp, ")"); | ||
205 | } | ||
206 | |||
207 | if (print_srcline) | ||
208 | printed += map__fprintf_srcline(al->map, al->addr, "\n ", fp); | ||
209 | } | ||
210 | |||
211 | return printed; | ||
212 | } | ||
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 90680ec9f8b8..08852dde1378 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
@@ -1474,7 +1474,7 @@ static int __event_process_build_id(struct build_id_event *bev, | |||
1474 | 1474 | ||
1475 | dso = machine__findnew_dso(machine, filename); | 1475 | dso = machine__findnew_dso(machine, filename); |
1476 | if (dso != NULL) { | 1476 | if (dso != NULL) { |
1477 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | 1477 | char sbuild_id[SBUILD_ID_SIZE]; |
1478 | 1478 | ||
1479 | dso__set_build_id(dso, &bev->build_id); | 1479 | dso__set_build_id(dso, &bev->build_id); |
1480 | 1480 | ||
@@ -1819,7 +1819,8 @@ static int process_cpu_topology(struct perf_file_section *section, | |||
1819 | 1819 | ||
1820 | ph->env.nr_sibling_cores = nr; | 1820 | ph->env.nr_sibling_cores = nr; |
1821 | size += sizeof(u32); | 1821 | size += sizeof(u32); |
1822 | strbuf_init(&sb, 128); | 1822 | if (strbuf_init(&sb, 128) < 0) |
1823 | goto free_cpu; | ||
1823 | 1824 | ||
1824 | for (i = 0; i < nr; i++) { | 1825 | for (i = 0; i < nr; i++) { |
1825 | str = do_read_string(fd, ph); | 1826 | str = do_read_string(fd, ph); |
@@ -1827,7 +1828,8 @@ static int process_cpu_topology(struct perf_file_section *section, | |||
1827 | goto error; | 1828 | goto error; |
1828 | 1829 | ||
1829 | /* include a NULL character at the end */ | 1830 | /* include a NULL character at the end */ |
1830 | strbuf_add(&sb, str, strlen(str) + 1); | 1831 | if (strbuf_add(&sb, str, strlen(str) + 1) < 0) |
1832 | goto error; | ||
1831 | size += string_size(str); | 1833 | size += string_size(str); |
1832 | free(str); | 1834 | free(str); |
1833 | } | 1835 | } |
@@ -1849,7 +1851,8 @@ static int process_cpu_topology(struct perf_file_section *section, | |||
1849 | goto error; | 1851 | goto error; |
1850 | 1852 | ||
1851 | /* include a NULL character at the end */ | 1853 | /* include a NULL character at the end */ |
1852 | strbuf_add(&sb, str, strlen(str) + 1); | 1854 | if (strbuf_add(&sb, str, strlen(str) + 1) < 0) |
1855 | goto error; | ||
1853 | size += string_size(str); | 1856 | size += string_size(str); |
1854 | free(str); | 1857 | free(str); |
1855 | } | 1858 | } |
@@ -1912,13 +1915,14 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse | |||
1912 | /* nr nodes */ | 1915 | /* nr nodes */ |
1913 | ret = readn(fd, &nr, sizeof(nr)); | 1916 | ret = readn(fd, &nr, sizeof(nr)); |
1914 | if (ret != sizeof(nr)) | 1917 | if (ret != sizeof(nr)) |
1915 | goto error; | 1918 | return -1; |
1916 | 1919 | ||
1917 | if (ph->needs_swap) | 1920 | if (ph->needs_swap) |
1918 | nr = bswap_32(nr); | 1921 | nr = bswap_32(nr); |
1919 | 1922 | ||
1920 | ph->env.nr_numa_nodes = nr; | 1923 | ph->env.nr_numa_nodes = nr; |
1921 | strbuf_init(&sb, 256); | 1924 | if (strbuf_init(&sb, 256) < 0) |
1925 | return -1; | ||
1922 | 1926 | ||
1923 | for (i = 0; i < nr; i++) { | 1927 | for (i = 0; i < nr; i++) { |
1924 | /* node number */ | 1928 | /* node number */ |
@@ -1940,15 +1944,17 @@ static int process_numa_topology(struct perf_file_section *section __maybe_unuse | |||
1940 | mem_free = bswap_64(mem_free); | 1944 | mem_free = bswap_64(mem_free); |
1941 | } | 1945 | } |
1942 | 1946 | ||
1943 | strbuf_addf(&sb, "%u:%"PRIu64":%"PRIu64":", | 1947 | if (strbuf_addf(&sb, "%u:%"PRIu64":%"PRIu64":", |
1944 | node, mem_total, mem_free); | 1948 | node, mem_total, mem_free) < 0) |
1949 | goto error; | ||
1945 | 1950 | ||
1946 | str = do_read_string(fd, ph); | 1951 | str = do_read_string(fd, ph); |
1947 | if (!str) | 1952 | if (!str) |
1948 | goto error; | 1953 | goto error; |
1949 | 1954 | ||
1950 | /* include a NULL character at the end */ | 1955 | /* include a NULL character at the end */ |
1951 | strbuf_add(&sb, str, strlen(str) + 1); | 1956 | if (strbuf_add(&sb, str, strlen(str) + 1) < 0) |
1957 | goto error; | ||
1952 | free(str); | 1958 | free(str); |
1953 | } | 1959 | } |
1954 | ph->env.numa_nodes = strbuf_detach(&sb, NULL); | 1960 | ph->env.numa_nodes = strbuf_detach(&sb, NULL); |
@@ -1982,7 +1988,8 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused | |||
1982 | } | 1988 | } |
1983 | 1989 | ||
1984 | ph->env.nr_pmu_mappings = pmu_num; | 1990 | ph->env.nr_pmu_mappings = pmu_num; |
1985 | strbuf_init(&sb, 128); | 1991 | if (strbuf_init(&sb, 128) < 0) |
1992 | return -1; | ||
1986 | 1993 | ||
1987 | while (pmu_num) { | 1994 | while (pmu_num) { |
1988 | if (readn(fd, &type, sizeof(type)) != sizeof(type)) | 1995 | if (readn(fd, &type, sizeof(type)) != sizeof(type)) |
@@ -1994,9 +2001,11 @@ static int process_pmu_mappings(struct perf_file_section *section __maybe_unused | |||
1994 | if (!name) | 2001 | if (!name) |
1995 | goto error; | 2002 | goto error; |
1996 | 2003 | ||
1997 | strbuf_addf(&sb, "%u:%s", type, name); | 2004 | if (strbuf_addf(&sb, "%u:%s", type, name) < 0) |
2005 | goto error; | ||
1998 | /* include a NULL character at the end */ | 2006 | /* include a NULL character at the end */ |
1999 | strbuf_add(&sb, "", 1); | 2007 | if (strbuf_add(&sb, "", 1) < 0) |
2008 | goto error; | ||
2000 | 2009 | ||
2001 | if (!strcmp(name, "msr")) | 2010 | if (!strcmp(name, "msr")) |
2002 | ph->env.msr_pmu_type = type; | 2011 | ph->env.msr_pmu_type = type; |
diff --git a/tools/perf/util/help-unknown-cmd.c b/tools/perf/util/help-unknown-cmd.c index 43a98a4dc1e1..d62ccaeeadd6 100644 --- a/tools/perf/util/help-unknown-cmd.c +++ b/tools/perf/util/help-unknown-cmd.c | |||
@@ -27,16 +27,27 @@ static int levenshtein_compare(const void *p1, const void *p2) | |||
27 | return l1 != l2 ? l1 - l2 : strcmp(s1, s2); | 27 | return l1 != l2 ? l1 - l2 : strcmp(s1, s2); |
28 | } | 28 | } |
29 | 29 | ||
30 | static void add_cmd_list(struct cmdnames *cmds, struct cmdnames *old) | 30 | static int add_cmd_list(struct cmdnames *cmds, struct cmdnames *old) |
31 | { | 31 | { |
32 | unsigned int i; | 32 | unsigned int i, nr = cmds->cnt + old->cnt; |
33 | 33 | void *tmp; | |
34 | ALLOC_GROW(cmds->names, cmds->cnt + old->cnt, cmds->alloc); | 34 | |
35 | 35 | if (nr > cmds->alloc) { | |
36 | /* Choose bigger one to alloc */ | ||
37 | if (alloc_nr(cmds->alloc) < nr) | ||
38 | cmds->alloc = nr; | ||
39 | else | ||
40 | cmds->alloc = alloc_nr(cmds->alloc); | ||
41 | tmp = realloc(cmds->names, cmds->alloc * sizeof(*cmds->names)); | ||
42 | if (!tmp) | ||
43 | return -1; | ||
44 | cmds->names = tmp; | ||
45 | } | ||
36 | for (i = 0; i < old->cnt; i++) | 46 | for (i = 0; i < old->cnt; i++) |
37 | cmds->names[cmds->cnt++] = old->names[i]; | 47 | cmds->names[cmds->cnt++] = old->names[i]; |
38 | zfree(&old->names); | 48 | zfree(&old->names); |
39 | old->cnt = 0; | 49 | old->cnt = 0; |
50 | return 0; | ||
40 | } | 51 | } |
41 | 52 | ||
42 | const char *help_unknown_cmd(const char *cmd) | 53 | const char *help_unknown_cmd(const char *cmd) |
@@ -52,8 +63,11 @@ const char *help_unknown_cmd(const char *cmd) | |||
52 | 63 | ||
53 | load_command_list("perf-", &main_cmds, &other_cmds); | 64 | load_command_list("perf-", &main_cmds, &other_cmds); |
54 | 65 | ||
55 | add_cmd_list(&main_cmds, &aliases); | 66 | if (add_cmd_list(&main_cmds, &aliases) < 0 || |
56 | add_cmd_list(&main_cmds, &other_cmds); | 67 | add_cmd_list(&main_cmds, &other_cmds) < 0) { |
68 | fprintf(stderr, "ERROR: Failed to allocate command list for unknown command.\n"); | ||
69 | goto end; | ||
70 | } | ||
57 | qsort(main_cmds.names, main_cmds.cnt, | 71 | qsort(main_cmds.names, main_cmds.cnt, |
58 | sizeof(main_cmds.names), cmdname_compare); | 72 | sizeof(main_cmds.names), cmdname_compare); |
59 | uniq(&main_cmds); | 73 | uniq(&main_cmds); |
@@ -99,6 +113,6 @@ const char *help_unknown_cmd(const char *cmd) | |||
99 | for (i = 0; i < n; i++) | 113 | for (i = 0; i < n; i++) |
100 | fprintf(stderr, "\t%s\n", main_cmds.names[i]->name); | 114 | fprintf(stderr, "\t%s\n", main_cmds.names[i]->name); |
101 | } | 115 | } |
102 | 116 | end: | |
103 | exit(1); | 117 | exit(1); |
104 | } | 118 | } |
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 31c4641fe5ff..cfab531437c7 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
@@ -295,7 +295,7 @@ static void hists__delete_entry(struct hists *hists, struct hist_entry *he) | |||
295 | root_in = &he->parent_he->hroot_in; | 295 | root_in = &he->parent_he->hroot_in; |
296 | root_out = &he->parent_he->hroot_out; | 296 | root_out = &he->parent_he->hroot_out; |
297 | } else { | 297 | } else { |
298 | if (sort__need_collapse) | 298 | if (hists__has(hists, need_collapse)) |
299 | root_in = &hists->entries_collapsed; | 299 | root_in = &hists->entries_collapsed; |
300 | else | 300 | else |
301 | root_in = hists->entries_in; | 301 | root_in = hists->entries_in; |
@@ -953,7 +953,7 @@ int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, | |||
953 | { | 953 | { |
954 | int err, err2; | 954 | int err, err2; |
955 | 955 | ||
956 | err = sample__resolve_callchain(iter->sample, &iter->parent, | 956 | err = sample__resolve_callchain(iter->sample, &callchain_cursor, &iter->parent, |
957 | iter->evsel, al, max_stack_depth); | 957 | iter->evsel, al, max_stack_depth); |
958 | if (err) | 958 | if (err) |
959 | return err; | 959 | return err; |
@@ -1295,8 +1295,9 @@ static int hists__hierarchy_insert_entry(struct hists *hists, | |||
1295 | return ret; | 1295 | return ret; |
1296 | } | 1296 | } |
1297 | 1297 | ||
1298 | int hists__collapse_insert_entry(struct hists *hists, struct rb_root *root, | 1298 | static int hists__collapse_insert_entry(struct hists *hists, |
1299 | struct hist_entry *he) | 1299 | struct rb_root *root, |
1300 | struct hist_entry *he) | ||
1300 | { | 1301 | { |
1301 | struct rb_node **p = &root->rb_node; | 1302 | struct rb_node **p = &root->rb_node; |
1302 | struct rb_node *parent = NULL; | 1303 | struct rb_node *parent = NULL; |
@@ -1372,7 +1373,7 @@ int hists__collapse_resort(struct hists *hists, struct ui_progress *prog) | |||
1372 | struct hist_entry *n; | 1373 | struct hist_entry *n; |
1373 | int ret; | 1374 | int ret; |
1374 | 1375 | ||
1375 | if (!sort__need_collapse) | 1376 | if (!hists__has(hists, need_collapse)) |
1376 | return 0; | 1377 | return 0; |
1377 | 1378 | ||
1378 | hists->nr_entries = 0; | 1379 | hists->nr_entries = 0; |
@@ -1631,7 +1632,7 @@ static void output_resort(struct hists *hists, struct ui_progress *prog, | |||
1631 | return; | 1632 | return; |
1632 | } | 1633 | } |
1633 | 1634 | ||
1634 | if (sort__need_collapse) | 1635 | if (hists__has(hists, need_collapse)) |
1635 | root = &hists->entries_collapsed; | 1636 | root = &hists->entries_collapsed; |
1636 | else | 1637 | else |
1637 | root = hists->entries_in; | 1638 | root = hists->entries_in; |
@@ -2035,7 +2036,7 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists, | |||
2035 | struct hist_entry *he; | 2036 | struct hist_entry *he; |
2036 | int64_t cmp; | 2037 | int64_t cmp; |
2037 | 2038 | ||
2038 | if (sort__need_collapse) | 2039 | if (hists__has(hists, need_collapse)) |
2039 | root = &hists->entries_collapsed; | 2040 | root = &hists->entries_collapsed; |
2040 | else | 2041 | else |
2041 | root = hists->entries_in; | 2042 | root = hists->entries_in; |
@@ -2061,6 +2062,8 @@ static struct hist_entry *hists__add_dummy_entry(struct hists *hists, | |||
2061 | if (he) { | 2062 | if (he) { |
2062 | memset(&he->stat, 0, sizeof(he->stat)); | 2063 | memset(&he->stat, 0, sizeof(he->stat)); |
2063 | he->hists = hists; | 2064 | he->hists = hists; |
2065 | if (symbol_conf.cumulate_callchain) | ||
2066 | memset(he->stat_acc, 0, sizeof(he->stat)); | ||
2064 | rb_link_node(&he->rb_node_in, parent, p); | 2067 | rb_link_node(&he->rb_node_in, parent, p); |
2065 | rb_insert_color(&he->rb_node_in, root); | 2068 | rb_insert_color(&he->rb_node_in, root); |
2066 | hists__inc_stats(hists, he); | 2069 | hists__inc_stats(hists, he); |
@@ -2075,7 +2078,7 @@ static struct hist_entry *hists__find_entry(struct hists *hists, | |||
2075 | { | 2078 | { |
2076 | struct rb_node *n; | 2079 | struct rb_node *n; |
2077 | 2080 | ||
2078 | if (sort__need_collapse) | 2081 | if (hists__has(hists, need_collapse)) |
2079 | n = hists->entries_collapsed.rb_node; | 2082 | n = hists->entries_collapsed.rb_node; |
2080 | else | 2083 | else |
2081 | n = hists->entries_in->rb_node; | 2084 | n = hists->entries_in->rb_node; |
@@ -2104,7 +2107,7 @@ void hists__match(struct hists *leader, struct hists *other) | |||
2104 | struct rb_node *nd; | 2107 | struct rb_node *nd; |
2105 | struct hist_entry *pos, *pair; | 2108 | struct hist_entry *pos, *pair; |
2106 | 2109 | ||
2107 | if (sort__need_collapse) | 2110 | if (hists__has(leader, need_collapse)) |
2108 | root = &leader->entries_collapsed; | 2111 | root = &leader->entries_collapsed; |
2109 | else | 2112 | else |
2110 | root = leader->entries_in; | 2113 | root = leader->entries_in; |
@@ -2129,7 +2132,7 @@ int hists__link(struct hists *leader, struct hists *other) | |||
2129 | struct rb_node *nd; | 2132 | struct rb_node *nd; |
2130 | struct hist_entry *pos, *pair; | 2133 | struct hist_entry *pos, *pair; |
2131 | 2134 | ||
2132 | if (sort__need_collapse) | 2135 | if (hists__has(other, need_collapse)) |
2133 | root = &other->entries_collapsed; | 2136 | root = &other->entries_collapsed; |
2134 | else | 2137 | else |
2135 | root = other->entries_in; | 2138 | root = other->entries_in; |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index bec0cd660fbd..0f84bfb42bb1 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -82,6 +82,8 @@ struct hists { | |||
82 | int nr_hpp_node; | 82 | int nr_hpp_node; |
83 | }; | 83 | }; |
84 | 84 | ||
85 | #define hists__has(__h, __f) (__h)->hpp_list->__f | ||
86 | |||
85 | struct hist_entry_iter; | 87 | struct hist_entry_iter; |
86 | 88 | ||
87 | struct hist_iter_ops { | 89 | struct hist_iter_ops { |
@@ -199,8 +201,6 @@ int hists__init(void); | |||
199 | int __hists__init(struct hists *hists, struct perf_hpp_list *hpp_list); | 201 | int __hists__init(struct hists *hists, struct perf_hpp_list *hpp_list); |
200 | 202 | ||
201 | struct rb_root *hists__get_rotate_entries_in(struct hists *hists); | 203 | struct rb_root *hists__get_rotate_entries_in(struct hists *hists); |
202 | int hists__collapse_insert_entry(struct hists *hists, | ||
203 | struct rb_root *root, struct hist_entry *he); | ||
204 | 204 | ||
205 | struct perf_hpp { | 205 | struct perf_hpp { |
206 | char *buf; | 206 | char *buf; |
@@ -240,6 +240,14 @@ struct perf_hpp_fmt { | |||
240 | struct perf_hpp_list { | 240 | struct perf_hpp_list { |
241 | struct list_head fields; | 241 | struct list_head fields; |
242 | struct list_head sorts; | 242 | struct list_head sorts; |
243 | |||
244 | int need_collapse; | ||
245 | int parent; | ||
246 | int sym; | ||
247 | int dso; | ||
248 | int socket; | ||
249 | int thread; | ||
250 | int comm; | ||
243 | }; | 251 | }; |
244 | 252 | ||
245 | extern struct perf_hpp_list perf_hpp_list; | 253 | extern struct perf_hpp_list perf_hpp_list; |
diff --git a/tools/perf/util/intel-bts.c b/tools/perf/util/intel-bts.c index abf1366e2a24..9df996085563 100644 --- a/tools/perf/util/intel-bts.c +++ b/tools/perf/util/intel-bts.c | |||
@@ -66,6 +66,7 @@ struct intel_bts { | |||
66 | u64 branches_id; | 66 | u64 branches_id; |
67 | size_t branches_event_size; | 67 | size_t branches_event_size; |
68 | bool synth_needs_swap; | 68 | bool synth_needs_swap; |
69 | unsigned long num_events; | ||
69 | }; | 70 | }; |
70 | 71 | ||
71 | struct intel_bts_queue { | 72 | struct intel_bts_queue { |
@@ -275,6 +276,10 @@ static int intel_bts_synth_branch_sample(struct intel_bts_queue *btsq, | |||
275 | union perf_event event; | 276 | union perf_event event; |
276 | struct perf_sample sample = { .ip = 0, }; | 277 | struct perf_sample sample = { .ip = 0, }; |
277 | 278 | ||
279 | if (bts->synth_opts.initial_skip && | ||
280 | bts->num_events++ <= bts->synth_opts.initial_skip) | ||
281 | return 0; | ||
282 | |||
278 | event.sample.header.type = PERF_RECORD_SAMPLE; | 283 | event.sample.header.type = PERF_RECORD_SAMPLE; |
279 | event.sample.header.misc = PERF_RECORD_MISC_USER; | 284 | event.sample.header.misc = PERF_RECORD_MISC_USER; |
280 | event.sample.header.size = sizeof(struct perf_event_header); | 285 | event.sample.header.size = sizeof(struct perf_event_header); |
diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c index 9409d014b46c..9c8f15da86ce 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | |||
@@ -356,7 +356,7 @@ static const char *intel_pt_err_msgs[] = { | |||
356 | 356 | ||
357 | int intel_pt__strerror(int code, char *buf, size_t buflen) | 357 | int intel_pt__strerror(int code, char *buf, size_t buflen) |
358 | { | 358 | { |
359 | if (code < 1 || code > INTEL_PT_ERR_MAX) | 359 | if (code < 1 || code >= INTEL_PT_ERR_MAX) |
360 | code = INTEL_PT_ERR_UNK; | 360 | code = INTEL_PT_ERR_UNK; |
361 | strlcpy(buf, intel_pt_err_msgs[code], buflen); | 361 | strlcpy(buf, intel_pt_err_msgs[code], buflen); |
362 | return 0; | 362 | return 0; |
diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 407f11b97c8d..137196990012 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c | |||
@@ -100,6 +100,8 @@ struct intel_pt { | |||
100 | u64 cyc_bit; | 100 | u64 cyc_bit; |
101 | u64 noretcomp_bit; | 101 | u64 noretcomp_bit; |
102 | unsigned max_non_turbo_ratio; | 102 | unsigned max_non_turbo_ratio; |
103 | |||
104 | unsigned long num_events; | ||
103 | }; | 105 | }; |
104 | 106 | ||
105 | enum switch_state { | 107 | enum switch_state { |
@@ -972,6 +974,10 @@ static int intel_pt_synth_branch_sample(struct intel_pt_queue *ptq) | |||
972 | if (pt->branches_filter && !(pt->branches_filter & ptq->flags)) | 974 | if (pt->branches_filter && !(pt->branches_filter & ptq->flags)) |
973 | return 0; | 975 | return 0; |
974 | 976 | ||
977 | if (pt->synth_opts.initial_skip && | ||
978 | pt->num_events++ < pt->synth_opts.initial_skip) | ||
979 | return 0; | ||
980 | |||
975 | event->sample.header.type = PERF_RECORD_SAMPLE; | 981 | event->sample.header.type = PERF_RECORD_SAMPLE; |
976 | event->sample.header.misc = PERF_RECORD_MISC_USER; | 982 | event->sample.header.misc = PERF_RECORD_MISC_USER; |
977 | event->sample.header.size = sizeof(struct perf_event_header); | 983 | event->sample.header.size = sizeof(struct perf_event_header); |
@@ -1029,6 +1035,10 @@ static int intel_pt_synth_instruction_sample(struct intel_pt_queue *ptq) | |||
1029 | union perf_event *event = ptq->event_buf; | 1035 | union perf_event *event = ptq->event_buf; |
1030 | struct perf_sample sample = { .ip = 0, }; | 1036 | struct perf_sample sample = { .ip = 0, }; |
1031 | 1037 | ||
1038 | if (pt->synth_opts.initial_skip && | ||
1039 | pt->num_events++ < pt->synth_opts.initial_skip) | ||
1040 | return 0; | ||
1041 | |||
1032 | event->sample.header.type = PERF_RECORD_SAMPLE; | 1042 | event->sample.header.type = PERF_RECORD_SAMPLE; |
1033 | event->sample.header.misc = PERF_RECORD_MISC_USER; | 1043 | event->sample.header.misc = PERF_RECORD_MISC_USER; |
1034 | event->sample.header.size = sizeof(struct perf_event_header); | 1044 | event->sample.header.size = sizeof(struct perf_event_header); |
@@ -1087,6 +1097,10 @@ static int intel_pt_synth_transaction_sample(struct intel_pt_queue *ptq) | |||
1087 | union perf_event *event = ptq->event_buf; | 1097 | union perf_event *event = ptq->event_buf; |
1088 | struct perf_sample sample = { .ip = 0, }; | 1098 | struct perf_sample sample = { .ip = 0, }; |
1089 | 1099 | ||
1100 | if (pt->synth_opts.initial_skip && | ||
1101 | pt->num_events++ < pt->synth_opts.initial_skip) | ||
1102 | return 0; | ||
1103 | |||
1090 | event->sample.header.type = PERF_RECORD_SAMPLE; | 1104 | event->sample.header.type = PERF_RECORD_SAMPLE; |
1091 | event->sample.header.misc = PERF_RECORD_MISC_USER; | 1105 | event->sample.header.misc = PERF_RECORD_MISC_USER; |
1092 | event->sample.header.size = sizeof(struct perf_event_header); | 1106 | event->sample.header.size = sizeof(struct perf_event_header); |
@@ -1130,7 +1144,7 @@ static int intel_pt_synth_transaction_sample(struct intel_pt_queue *ptq) | |||
1130 | pr_err("Intel Processor Trace: failed to deliver transaction event, error %d\n", | 1144 | pr_err("Intel Processor Trace: failed to deliver transaction event, error %d\n", |
1131 | ret); | 1145 | ret); |
1132 | 1146 | ||
1133 | if (pt->synth_opts.callchain) | 1147 | if (pt->synth_opts.last_branch) |
1134 | intel_pt_reset_last_branch_rb(ptq); | 1148 | intel_pt_reset_last_branch_rb(ptq); |
1135 | 1149 | ||
1136 | return ret; | 1150 | return ret; |
@@ -1199,14 +1213,18 @@ static int intel_pt_sample(struct intel_pt_queue *ptq) | |||
1199 | ptq->have_sample = false; | 1213 | ptq->have_sample = false; |
1200 | 1214 | ||
1201 | if (pt->sample_instructions && | 1215 | if (pt->sample_instructions && |
1202 | (state->type & INTEL_PT_INSTRUCTION)) { | 1216 | (state->type & INTEL_PT_INSTRUCTION) && |
1217 | (!pt->synth_opts.initial_skip || | ||
1218 | pt->num_events++ >= pt->synth_opts.initial_skip)) { | ||
1203 | err = intel_pt_synth_instruction_sample(ptq); | 1219 | err = intel_pt_synth_instruction_sample(ptq); |
1204 | if (err) | 1220 | if (err) |
1205 | return err; | 1221 | return err; |
1206 | } | 1222 | } |
1207 | 1223 | ||
1208 | if (pt->sample_transactions && | 1224 | if (pt->sample_transactions && |
1209 | (state->type & INTEL_PT_TRANSACTION)) { | 1225 | (state->type & INTEL_PT_TRANSACTION) && |
1226 | (!pt->synth_opts.initial_skip || | ||
1227 | pt->num_events++ >= pt->synth_opts.initial_skip)) { | ||
1210 | err = intel_pt_synth_transaction_sample(ptq); | 1228 | err = intel_pt_synth_transaction_sample(ptq); |
1211 | if (err) | 1229 | if (err) |
1212 | return err; | 1230 | return err; |
diff --git a/tools/perf/util/jitdump.c b/tools/perf/util/jitdump.c index ad0c0bb1fbc7..86afe9618bb0 100644 --- a/tools/perf/util/jitdump.c +++ b/tools/perf/util/jitdump.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include "strlist.h" | 17 | #include "strlist.h" |
18 | #include <elf.h> | 18 | #include <elf.h> |
19 | 19 | ||
20 | #include "tsc.h" | ||
20 | #include "session.h" | 21 | #include "session.h" |
21 | #include "jit.h" | 22 | #include "jit.h" |
22 | #include "jitdump.h" | 23 | #include "jitdump.h" |
@@ -33,6 +34,7 @@ struct jit_buf_desc { | |||
33 | size_t bufsize; | 34 | size_t bufsize; |
34 | FILE *in; | 35 | FILE *in; |
35 | bool needs_bswap; /* handles cross-endianess */ | 36 | bool needs_bswap; /* handles cross-endianess */ |
37 | bool use_arch_timestamp; | ||
36 | void *debug_data; | 38 | void *debug_data; |
37 | size_t nr_debug_entries; | 39 | size_t nr_debug_entries; |
38 | uint32_t code_load_count; | 40 | uint32_t code_load_count; |
@@ -158,13 +160,16 @@ jit_open(struct jit_buf_desc *jd, const char *name) | |||
158 | header.flags = bswap_64(header.flags); | 160 | header.flags = bswap_64(header.flags); |
159 | } | 161 | } |
160 | 162 | ||
163 | jd->use_arch_timestamp = header.flags & JITDUMP_FLAGS_ARCH_TIMESTAMP; | ||
164 | |||
161 | if (verbose > 2) | 165 | if (verbose > 2) |
162 | pr_debug("version=%u\nhdr.size=%u\nts=0x%llx\npid=%d\nelf_mach=%d\n", | 166 | pr_debug("version=%u\nhdr.size=%u\nts=0x%llx\npid=%d\nelf_mach=%d\nuse_arch_timestamp=%d\n", |
163 | header.version, | 167 | header.version, |
164 | header.total_size, | 168 | header.total_size, |
165 | (unsigned long long)header.timestamp, | 169 | (unsigned long long)header.timestamp, |
166 | header.pid, | 170 | header.pid, |
167 | header.elf_mach); | 171 | header.elf_mach, |
172 | jd->use_arch_timestamp); | ||
168 | 173 | ||
169 | if (header.flags & JITDUMP_FLAGS_RESERVED) { | 174 | if (header.flags & JITDUMP_FLAGS_RESERVED) { |
170 | pr_err("jitdump file contains invalid or unsupported flags 0x%llx\n", | 175 | pr_err("jitdump file contains invalid or unsupported flags 0x%llx\n", |
@@ -172,10 +177,15 @@ jit_open(struct jit_buf_desc *jd, const char *name) | |||
172 | goto error; | 177 | goto error; |
173 | } | 178 | } |
174 | 179 | ||
180 | if (jd->use_arch_timestamp && !jd->session->time_conv.time_mult) { | ||
181 | pr_err("jitdump file uses arch timestamps but there is no timestamp conversion\n"); | ||
182 | goto error; | ||
183 | } | ||
184 | |||
175 | /* | 185 | /* |
176 | * validate event is using the correct clockid | 186 | * validate event is using the correct clockid |
177 | */ | 187 | */ |
178 | if (jit_validate_events(jd->session)) { | 188 | if (!jd->use_arch_timestamp && jit_validate_events(jd->session)) { |
179 | pr_err("error, jitted code must be sampled with perf record -k 1\n"); | 189 | pr_err("error, jitted code must be sampled with perf record -k 1\n"); |
180 | goto error; | 190 | goto error; |
181 | } | 191 | } |
@@ -329,6 +339,23 @@ jit_inject_event(struct jit_buf_desc *jd, union perf_event *event) | |||
329 | return 0; | 339 | return 0; |
330 | } | 340 | } |
331 | 341 | ||
342 | static uint64_t convert_timestamp(struct jit_buf_desc *jd, uint64_t timestamp) | ||
343 | { | ||
344 | struct perf_tsc_conversion tc; | ||
345 | |||
346 | if (!jd->use_arch_timestamp) | ||
347 | return timestamp; | ||
348 | |||
349 | tc.time_shift = jd->session->time_conv.time_shift; | ||
350 | tc.time_mult = jd->session->time_conv.time_mult; | ||
351 | tc.time_zero = jd->session->time_conv.time_zero; | ||
352 | |||
353 | if (!tc.time_mult) | ||
354 | return 0; | ||
355 | |||
356 | return tsc_to_perf_time(timestamp, &tc); | ||
357 | } | ||
358 | |||
332 | static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr) | 359 | static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr) |
333 | { | 360 | { |
334 | struct perf_sample sample; | 361 | struct perf_sample sample; |
@@ -385,7 +412,7 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr) | |||
385 | return -1; | 412 | return -1; |
386 | } | 413 | } |
387 | if (stat(filename, &st)) | 414 | if (stat(filename, &st)) |
388 | memset(&st, 0, sizeof(stat)); | 415 | memset(&st, 0, sizeof(st)); |
389 | 416 | ||
390 | event->mmap2.header.type = PERF_RECORD_MMAP2; | 417 | event->mmap2.header.type = PERF_RECORD_MMAP2; |
391 | event->mmap2.header.misc = PERF_RECORD_MISC_USER; | 418 | event->mmap2.header.misc = PERF_RECORD_MISC_USER; |
@@ -410,7 +437,7 @@ static int jit_repipe_code_load(struct jit_buf_desc *jd, union jr_entry *jr) | |||
410 | id->tid = tid; | 437 | id->tid = tid; |
411 | } | 438 | } |
412 | if (jd->sample_type & PERF_SAMPLE_TIME) | 439 | if (jd->sample_type & PERF_SAMPLE_TIME) |
413 | id->time = jr->load.p.timestamp; | 440 | id->time = convert_timestamp(jd, jr->load.p.timestamp); |
414 | 441 | ||
415 | /* | 442 | /* |
416 | * create pseudo sample to induce dso hit increment | 443 | * create pseudo sample to induce dso hit increment |
@@ -473,7 +500,7 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr) | |||
473 | size++; /* for \0 */ | 500 | size++; /* for \0 */ |
474 | 501 | ||
475 | if (stat(filename, &st)) | 502 | if (stat(filename, &st)) |
476 | memset(&st, 0, sizeof(stat)); | 503 | memset(&st, 0, sizeof(st)); |
477 | 504 | ||
478 | size = PERF_ALIGN(size, sizeof(u64)); | 505 | size = PERF_ALIGN(size, sizeof(u64)); |
479 | 506 | ||
@@ -499,7 +526,7 @@ static int jit_repipe_code_move(struct jit_buf_desc *jd, union jr_entry *jr) | |||
499 | id->tid = tid; | 526 | id->tid = tid; |
500 | } | 527 | } |
501 | if (jd->sample_type & PERF_SAMPLE_TIME) | 528 | if (jd->sample_type & PERF_SAMPLE_TIME) |
502 | id->time = jr->load.p.timestamp; | 529 | id->time = convert_timestamp(jd, jr->load.p.timestamp); |
503 | 530 | ||
504 | /* | 531 | /* |
505 | * create pseudo sample to induce dso hit increment | 532 | * create pseudo sample to induce dso hit increment |
diff --git a/tools/perf/util/jitdump.h b/tools/perf/util/jitdump.h index b66c1f503d9e..bcacd20d0c1c 100644 --- a/tools/perf/util/jitdump.h +++ b/tools/perf/util/jitdump.h | |||
@@ -23,9 +23,12 @@ | |||
23 | #define JITHEADER_VERSION 1 | 23 | #define JITHEADER_VERSION 1 |
24 | 24 | ||
25 | enum jitdump_flags_bits { | 25 | enum jitdump_flags_bits { |
26 | JITDUMP_FLAGS_ARCH_TIMESTAMP_BIT, | ||
26 | JITDUMP_FLAGS_MAX_BIT, | 27 | JITDUMP_FLAGS_MAX_BIT, |
27 | }; | 28 | }; |
28 | 29 | ||
30 | #define JITDUMP_FLAGS_ARCH_TIMESTAMP (1ULL << JITDUMP_FLAGS_ARCH_TIMESTAMP_BIT) | ||
31 | |||
29 | #define JITDUMP_FLAGS_RESERVED (JITDUMP_FLAGS_MAX_BIT < 64 ? \ | 32 | #define JITDUMP_FLAGS_RESERVED (JITDUMP_FLAGS_MAX_BIT < 64 ? \ |
30 | (~((1ULL << JITDUMP_FLAGS_MAX_BIT) - 1)) : 0) | 33 | (~((1ULL << JITDUMP_FLAGS_MAX_BIT) - 1)) : 0) |
31 | 34 | ||
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c index 80b9b6a87990..f9644f79686c 100644 --- a/tools/perf/util/machine.c +++ b/tools/perf/util/machine.c | |||
@@ -32,6 +32,7 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid) | |||
32 | 32 | ||
33 | machine->threads = RB_ROOT; | 33 | machine->threads = RB_ROOT; |
34 | pthread_rwlock_init(&machine->threads_lock, NULL); | 34 | pthread_rwlock_init(&machine->threads_lock, NULL); |
35 | machine->nr_threads = 0; | ||
35 | INIT_LIST_HEAD(&machine->dead_threads); | 36 | INIT_LIST_HEAD(&machine->dead_threads); |
36 | machine->last_match = NULL; | 37 | machine->last_match = NULL; |
37 | 38 | ||
@@ -361,7 +362,7 @@ out_err: | |||
361 | } | 362 | } |
362 | 363 | ||
363 | /* | 364 | /* |
364 | * Caller must eventually drop thread->refcnt returned with a successfull | 365 | * Caller must eventually drop thread->refcnt returned with a successful |
365 | * lookup/new thread inserted. | 366 | * lookup/new thread inserted. |
366 | */ | 367 | */ |
367 | static struct thread *____machine__findnew_thread(struct machine *machine, | 368 | static struct thread *____machine__findnew_thread(struct machine *machine, |
@@ -430,6 +431,7 @@ static struct thread *____machine__findnew_thread(struct machine *machine, | |||
430 | */ | 431 | */ |
431 | thread__get(th); | 432 | thread__get(th); |
432 | machine->last_match = th; | 433 | machine->last_match = th; |
434 | ++machine->nr_threads; | ||
433 | } | 435 | } |
434 | 436 | ||
435 | return th; | 437 | return th; |
@@ -681,11 +683,13 @@ size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp) | |||
681 | 683 | ||
682 | size_t machine__fprintf(struct machine *machine, FILE *fp) | 684 | size_t machine__fprintf(struct machine *machine, FILE *fp) |
683 | { | 685 | { |
684 | size_t ret = 0; | 686 | size_t ret; |
685 | struct rb_node *nd; | 687 | struct rb_node *nd; |
686 | 688 | ||
687 | pthread_rwlock_rdlock(&machine->threads_lock); | 689 | pthread_rwlock_rdlock(&machine->threads_lock); |
688 | 690 | ||
691 | ret = fprintf(fp, "Threads: %u\n", machine->nr_threads); | ||
692 | |||
689 | for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) { | 693 | for (nd = rb_first(&machine->threads); nd; nd = rb_next(nd)) { |
690 | struct thread *pos = rb_entry(nd, struct thread, rb_node); | 694 | struct thread *pos = rb_entry(nd, struct thread, rb_node); |
691 | 695 | ||
@@ -908,11 +912,11 @@ int machines__create_kernel_maps(struct machines *machines, pid_t pid) | |||
908 | return machine__create_kernel_maps(machine); | 912 | return machine__create_kernel_maps(machine); |
909 | } | 913 | } |
910 | 914 | ||
911 | int machine__load_kallsyms(struct machine *machine, const char *filename, | 915 | int __machine__load_kallsyms(struct machine *machine, const char *filename, |
912 | enum map_type type, symbol_filter_t filter) | 916 | enum map_type type, bool no_kcore, symbol_filter_t filter) |
913 | { | 917 | { |
914 | struct map *map = machine__kernel_map(machine); | 918 | struct map *map = machine__kernel_map(machine); |
915 | int ret = dso__load_kallsyms(map->dso, filename, map, filter); | 919 | int ret = __dso__load_kallsyms(map->dso, filename, map, no_kcore, filter); |
916 | 920 | ||
917 | if (ret > 0) { | 921 | if (ret > 0) { |
918 | dso__set_loaded(map->dso, type); | 922 | dso__set_loaded(map->dso, type); |
@@ -927,6 +931,12 @@ int machine__load_kallsyms(struct machine *machine, const char *filename, | |||
927 | return ret; | 931 | return ret; |
928 | } | 932 | } |
929 | 933 | ||
934 | int machine__load_kallsyms(struct machine *machine, const char *filename, | ||
935 | enum map_type type, symbol_filter_t filter) | ||
936 | { | ||
937 | return __machine__load_kallsyms(machine, filename, type, false, filter); | ||
938 | } | ||
939 | |||
930 | int machine__load_vmlinux_path(struct machine *machine, enum map_type type, | 940 | int machine__load_vmlinux_path(struct machine *machine, enum map_type type, |
931 | symbol_filter_t filter) | 941 | symbol_filter_t filter) |
932 | { | 942 | { |
@@ -1413,6 +1423,7 @@ static void __machine__remove_thread(struct machine *machine, struct thread *th, | |||
1413 | pthread_rwlock_wrlock(&machine->threads_lock); | 1423 | pthread_rwlock_wrlock(&machine->threads_lock); |
1414 | rb_erase_init(&th->rb_node, &machine->threads); | 1424 | rb_erase_init(&th->rb_node, &machine->threads); |
1415 | RB_CLEAR_NODE(&th->rb_node); | 1425 | RB_CLEAR_NODE(&th->rb_node); |
1426 | --machine->nr_threads; | ||
1416 | /* | 1427 | /* |
1417 | * Move it first to the dead_threads list, then drop the reference, | 1428 | * Move it first to the dead_threads list, then drop the reference, |
1418 | * if this is the last reference, then the thread__delete destructor | 1429 | * if this is the last reference, then the thread__delete destructor |
@@ -1599,6 +1610,7 @@ struct mem_info *sample__resolve_mem(struct perf_sample *sample, | |||
1599 | } | 1610 | } |
1600 | 1611 | ||
1601 | static int add_callchain_ip(struct thread *thread, | 1612 | static int add_callchain_ip(struct thread *thread, |
1613 | struct callchain_cursor *cursor, | ||
1602 | struct symbol **parent, | 1614 | struct symbol **parent, |
1603 | struct addr_location *root_al, | 1615 | struct addr_location *root_al, |
1604 | u8 *cpumode, | 1616 | u8 *cpumode, |
@@ -1630,7 +1642,7 @@ static int add_callchain_ip(struct thread *thread, | |||
1630 | * It seems the callchain is corrupted. | 1642 | * It seems the callchain is corrupted. |
1631 | * Discard all. | 1643 | * Discard all. |
1632 | */ | 1644 | */ |
1633 | callchain_cursor_reset(&callchain_cursor); | 1645 | callchain_cursor_reset(cursor); |
1634 | return 1; | 1646 | return 1; |
1635 | } | 1647 | } |
1636 | return 0; | 1648 | return 0; |
@@ -1640,7 +1652,7 @@ static int add_callchain_ip(struct thread *thread, | |||
1640 | } | 1652 | } |
1641 | 1653 | ||
1642 | if (al.sym != NULL) { | 1654 | if (al.sym != NULL) { |
1643 | if (sort__has_parent && !*parent && | 1655 | if (perf_hpp_list.parent && !*parent && |
1644 | symbol__match_regex(al.sym, &parent_regex)) | 1656 | symbol__match_regex(al.sym, &parent_regex)) |
1645 | *parent = al.sym; | 1657 | *parent = al.sym; |
1646 | else if (have_ignore_callees && root_al && | 1658 | else if (have_ignore_callees && root_al && |
@@ -1648,13 +1660,13 @@ static int add_callchain_ip(struct thread *thread, | |||
1648 | /* Treat this symbol as the root, | 1660 | /* Treat this symbol as the root, |
1649 | forgetting its callees. */ | 1661 | forgetting its callees. */ |
1650 | *root_al = al; | 1662 | *root_al = al; |
1651 | callchain_cursor_reset(&callchain_cursor); | 1663 | callchain_cursor_reset(cursor); |
1652 | } | 1664 | } |
1653 | } | 1665 | } |
1654 | 1666 | ||
1655 | if (symbol_conf.hide_unresolved && al.sym == NULL) | 1667 | if (symbol_conf.hide_unresolved && al.sym == NULL) |
1656 | return 0; | 1668 | return 0; |
1657 | return callchain_cursor_append(&callchain_cursor, al.addr, al.map, al.sym); | 1669 | return callchain_cursor_append(cursor, al.addr, al.map, al.sym); |
1658 | } | 1670 | } |
1659 | 1671 | ||
1660 | struct branch_info *sample__resolve_bstack(struct perf_sample *sample, | 1672 | struct branch_info *sample__resolve_bstack(struct perf_sample *sample, |
@@ -1724,6 +1736,7 @@ static int remove_loops(struct branch_entry *l, int nr) | |||
1724 | * negative error code on other errors. | 1736 | * negative error code on other errors. |
1725 | */ | 1737 | */ |
1726 | static int resolve_lbr_callchain_sample(struct thread *thread, | 1738 | static int resolve_lbr_callchain_sample(struct thread *thread, |
1739 | struct callchain_cursor *cursor, | ||
1727 | struct perf_sample *sample, | 1740 | struct perf_sample *sample, |
1728 | struct symbol **parent, | 1741 | struct symbol **parent, |
1729 | struct addr_location *root_al, | 1742 | struct addr_location *root_al, |
@@ -1756,7 +1769,7 @@ static int resolve_lbr_callchain_sample(struct thread *thread, | |||
1756 | */ | 1769 | */ |
1757 | int mix_chain_nr = i + 1 + lbr_nr + 1; | 1770 | int mix_chain_nr = i + 1 + lbr_nr + 1; |
1758 | 1771 | ||
1759 | if (mix_chain_nr > PERF_MAX_STACK_DEPTH + PERF_MAX_BRANCH_DEPTH) { | 1772 | if (mix_chain_nr > (int)sysctl_perf_event_max_stack + PERF_MAX_BRANCH_DEPTH) { |
1760 | pr_warning("corrupted callchain. skipping...\n"); | 1773 | pr_warning("corrupted callchain. skipping...\n"); |
1761 | return 0; | 1774 | return 0; |
1762 | } | 1775 | } |
@@ -1778,7 +1791,7 @@ static int resolve_lbr_callchain_sample(struct thread *thread, | |||
1778 | ip = lbr_stack->entries[0].to; | 1791 | ip = lbr_stack->entries[0].to; |
1779 | } | 1792 | } |
1780 | 1793 | ||
1781 | err = add_callchain_ip(thread, parent, root_al, &cpumode, ip); | 1794 | err = add_callchain_ip(thread, cursor, parent, root_al, &cpumode, ip); |
1782 | if (err) | 1795 | if (err) |
1783 | return (err < 0) ? err : 0; | 1796 | return (err < 0) ? err : 0; |
1784 | } | 1797 | } |
@@ -1789,6 +1802,7 @@ static int resolve_lbr_callchain_sample(struct thread *thread, | |||
1789 | } | 1802 | } |
1790 | 1803 | ||
1791 | static int thread__resolve_callchain_sample(struct thread *thread, | 1804 | static int thread__resolve_callchain_sample(struct thread *thread, |
1805 | struct callchain_cursor *cursor, | ||
1792 | struct perf_evsel *evsel, | 1806 | struct perf_evsel *evsel, |
1793 | struct perf_sample *sample, | 1807 | struct perf_sample *sample, |
1794 | struct symbol **parent, | 1808 | struct symbol **parent, |
@@ -1803,10 +1817,8 @@ static int thread__resolve_callchain_sample(struct thread *thread, | |||
1803 | int skip_idx = -1; | 1817 | int skip_idx = -1; |
1804 | int first_call = 0; | 1818 | int first_call = 0; |
1805 | 1819 | ||
1806 | callchain_cursor_reset(&callchain_cursor); | 1820 | if (perf_evsel__has_branch_callstack(evsel)) { |
1807 | 1821 | err = resolve_lbr_callchain_sample(thread, cursor, sample, parent, | |
1808 | if (has_branch_callstack(evsel)) { | ||
1809 | err = resolve_lbr_callchain_sample(thread, sample, parent, | ||
1810 | root_al, max_stack); | 1822 | root_al, max_stack); |
1811 | if (err) | 1823 | if (err) |
1812 | return (err < 0) ? err : 0; | 1824 | return (err < 0) ? err : 0; |
@@ -1816,7 +1828,7 @@ static int thread__resolve_callchain_sample(struct thread *thread, | |||
1816 | * Based on DWARF debug information, some architectures skip | 1828 | * Based on DWARF debug information, some architectures skip |
1817 | * a callchain entry saved by the kernel. | 1829 | * a callchain entry saved by the kernel. |
1818 | */ | 1830 | */ |
1819 | if (chain->nr < PERF_MAX_STACK_DEPTH) | 1831 | if (chain->nr < sysctl_perf_event_max_stack) |
1820 | skip_idx = arch_skip_callchain_idx(thread, chain); | 1832 | skip_idx = arch_skip_callchain_idx(thread, chain); |
1821 | 1833 | ||
1822 | /* | 1834 | /* |
@@ -1863,10 +1875,10 @@ static int thread__resolve_callchain_sample(struct thread *thread, | |||
1863 | nr = remove_loops(be, nr); | 1875 | nr = remove_loops(be, nr); |
1864 | 1876 | ||
1865 | for (i = 0; i < nr; i++) { | 1877 | for (i = 0; i < nr; i++) { |
1866 | err = add_callchain_ip(thread, parent, root_al, | 1878 | err = add_callchain_ip(thread, cursor, parent, root_al, |
1867 | NULL, be[i].to); | 1879 | NULL, be[i].to); |
1868 | if (!err) | 1880 | if (!err) |
1869 | err = add_callchain_ip(thread, parent, root_al, | 1881 | err = add_callchain_ip(thread, cursor, parent, root_al, |
1870 | NULL, be[i].from); | 1882 | NULL, be[i].from); |
1871 | if (err == -EINVAL) | 1883 | if (err == -EINVAL) |
1872 | break; | 1884 | break; |
@@ -1877,7 +1889,7 @@ static int thread__resolve_callchain_sample(struct thread *thread, | |||
1877 | } | 1889 | } |
1878 | 1890 | ||
1879 | check_calls: | 1891 | check_calls: |
1880 | if (chain->nr > PERF_MAX_STACK_DEPTH && (int)chain->nr > max_stack) { | 1892 | if (chain->nr > sysctl_perf_event_max_stack && (int)chain->nr > max_stack) { |
1881 | pr_warning("corrupted callchain. skipping...\n"); | 1893 | pr_warning("corrupted callchain. skipping...\n"); |
1882 | return 0; | 1894 | return 0; |
1883 | } | 1895 | } |
@@ -1896,7 +1908,7 @@ check_calls: | |||
1896 | #endif | 1908 | #endif |
1897 | ip = chain->ips[j]; | 1909 | ip = chain->ips[j]; |
1898 | 1910 | ||
1899 | err = add_callchain_ip(thread, parent, root_al, &cpumode, ip); | 1911 | err = add_callchain_ip(thread, cursor, parent, root_al, &cpumode, ip); |
1900 | 1912 | ||
1901 | if (err) | 1913 | if (err) |
1902 | return (err < 0) ? err : 0; | 1914 | return (err < 0) ? err : 0; |
@@ -1915,19 +1927,12 @@ static int unwind_entry(struct unwind_entry *entry, void *arg) | |||
1915 | entry->map, entry->sym); | 1927 | entry->map, entry->sym); |
1916 | } | 1928 | } |
1917 | 1929 | ||
1918 | int thread__resolve_callchain(struct thread *thread, | 1930 | static int thread__resolve_callchain_unwind(struct thread *thread, |
1919 | struct perf_evsel *evsel, | 1931 | struct callchain_cursor *cursor, |
1920 | struct perf_sample *sample, | 1932 | struct perf_evsel *evsel, |
1921 | struct symbol **parent, | 1933 | struct perf_sample *sample, |
1922 | struct addr_location *root_al, | 1934 | int max_stack) |
1923 | int max_stack) | ||
1924 | { | 1935 | { |
1925 | int ret = thread__resolve_callchain_sample(thread, evsel, | ||
1926 | sample, parent, | ||
1927 | root_al, max_stack); | ||
1928 | if (ret) | ||
1929 | return ret; | ||
1930 | |||
1931 | /* Can we do dwarf post unwind? */ | 1936 | /* Can we do dwarf post unwind? */ |
1932 | if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) && | 1937 | if (!((evsel->attr.sample_type & PERF_SAMPLE_REGS_USER) && |
1933 | (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER))) | 1938 | (evsel->attr.sample_type & PERF_SAMPLE_STACK_USER))) |
@@ -1938,9 +1943,45 @@ int thread__resolve_callchain(struct thread *thread, | |||
1938 | (!sample->user_stack.size)) | 1943 | (!sample->user_stack.size)) |
1939 | return 0; | 1944 | return 0; |
1940 | 1945 | ||
1941 | return unwind__get_entries(unwind_entry, &callchain_cursor, | 1946 | return unwind__get_entries(unwind_entry, cursor, |
1942 | thread, sample, max_stack); | 1947 | thread, sample, max_stack); |
1948 | } | ||
1949 | |||
1950 | int thread__resolve_callchain(struct thread *thread, | ||
1951 | struct callchain_cursor *cursor, | ||
1952 | struct perf_evsel *evsel, | ||
1953 | struct perf_sample *sample, | ||
1954 | struct symbol **parent, | ||
1955 | struct addr_location *root_al, | ||
1956 | int max_stack) | ||
1957 | { | ||
1958 | int ret = 0; | ||
1959 | |||
1960 | callchain_cursor_reset(&callchain_cursor); | ||
1943 | 1961 | ||
1962 | if (callchain_param.order == ORDER_CALLEE) { | ||
1963 | ret = thread__resolve_callchain_sample(thread, cursor, | ||
1964 | evsel, sample, | ||
1965 | parent, root_al, | ||
1966 | max_stack); | ||
1967 | if (ret) | ||
1968 | return ret; | ||
1969 | ret = thread__resolve_callchain_unwind(thread, cursor, | ||
1970 | evsel, sample, | ||
1971 | max_stack); | ||
1972 | } else { | ||
1973 | ret = thread__resolve_callchain_unwind(thread, cursor, | ||
1974 | evsel, sample, | ||
1975 | max_stack); | ||
1976 | if (ret) | ||
1977 | return ret; | ||
1978 | ret = thread__resolve_callchain_sample(thread, cursor, | ||
1979 | evsel, sample, | ||
1980 | parent, root_al, | ||
1981 | max_stack); | ||
1982 | } | ||
1983 | |||
1984 | return ret; | ||
1944 | } | 1985 | } |
1945 | 1986 | ||
1946 | int machine__for_each_thread(struct machine *machine, | 1987 | int machine__for_each_thread(struct machine *machine, |
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h index 8499db281158..83f46790c52f 100644 --- a/tools/perf/util/machine.h +++ b/tools/perf/util/machine.h | |||
@@ -31,6 +31,7 @@ struct machine { | |||
31 | char *root_dir; | 31 | char *root_dir; |
32 | struct rb_root threads; | 32 | struct rb_root threads; |
33 | pthread_rwlock_t threads_lock; | 33 | pthread_rwlock_t threads_lock; |
34 | unsigned int nr_threads; | ||
34 | struct list_head dead_threads; | 35 | struct list_head dead_threads; |
35 | struct thread *last_match; | 36 | struct thread *last_match; |
36 | struct vdso_info *vdso_info; | 37 | struct vdso_info *vdso_info; |
@@ -141,7 +142,11 @@ struct branch_info *sample__resolve_bstack(struct perf_sample *sample, | |||
141 | struct addr_location *al); | 142 | struct addr_location *al); |
142 | struct mem_info *sample__resolve_mem(struct perf_sample *sample, | 143 | struct mem_info *sample__resolve_mem(struct perf_sample *sample, |
143 | struct addr_location *al); | 144 | struct addr_location *al); |
145 | |||
146 | struct callchain_cursor; | ||
147 | |||
144 | int thread__resolve_callchain(struct thread *thread, | 148 | int thread__resolve_callchain(struct thread *thread, |
149 | struct callchain_cursor *cursor, | ||
145 | struct perf_evsel *evsel, | 150 | struct perf_evsel *evsel, |
146 | struct perf_sample *sample, | 151 | struct perf_sample *sample, |
147 | struct symbol **parent, | 152 | struct symbol **parent, |
@@ -211,6 +216,8 @@ struct symbol *machine__find_kernel_function_by_name(struct machine *machine, | |||
211 | struct map *machine__findnew_module_map(struct machine *machine, u64 start, | 216 | struct map *machine__findnew_module_map(struct machine *machine, u64 start, |
212 | const char *filename); | 217 | const char *filename); |
213 | 218 | ||
219 | int __machine__load_kallsyms(struct machine *machine, const char *filename, | ||
220 | enum map_type type, bool no_kcore, symbol_filter_t filter); | ||
214 | int machine__load_kallsyms(struct machine *machine, const char *filename, | 221 | int machine__load_kallsyms(struct machine *machine, const char *filename, |
215 | enum map_type type, symbol_filter_t filter); | 222 | enum map_type type, symbol_filter_t filter); |
216 | int machine__load_vmlinux_path(struct machine *machine, enum map_type type, | 223 | int machine__load_vmlinux_path(struct machine *machine, enum map_type type, |
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 171b6d10a04b..b19bcd3b7128 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
@@ -289,7 +289,7 @@ int map__load(struct map *map, symbol_filter_t filter) | |||
289 | nr = dso__load(map->dso, map, filter); | 289 | nr = dso__load(map->dso, map, filter); |
290 | if (nr < 0) { | 290 | if (nr < 0) { |
291 | if (map->dso->has_build_id) { | 291 | if (map->dso->has_build_id) { |
292 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | 292 | char sbuild_id[SBUILD_ID_SIZE]; |
293 | 293 | ||
294 | build_id__sprintf(map->dso->build_id, | 294 | build_id__sprintf(map->dso->build_id, |
295 | sizeof(map->dso->build_id), | 295 | sizeof(map->dso->build_id), |
@@ -431,6 +431,13 @@ u64 map__rip_2objdump(struct map *map, u64 rip) | |||
431 | if (map->dso->rel) | 431 | if (map->dso->rel) |
432 | return rip - map->pgoff; | 432 | return rip - map->pgoff; |
433 | 433 | ||
434 | /* | ||
435 | * kernel modules also have DSO_TYPE_USER in dso->kernel, | ||
436 | * but all kernel modules are ET_REL, so won't get here. | ||
437 | */ | ||
438 | if (map->dso->kernel == DSO_TYPE_USER) | ||
439 | return rip + map->dso->text_offset; | ||
440 | |||
434 | return map->unmap_ip(map, rip) - map->reloc; | 441 | return map->unmap_ip(map, rip) - map->reloc; |
435 | } | 442 | } |
436 | 443 | ||
@@ -454,6 +461,13 @@ u64 map__objdump_2mem(struct map *map, u64 ip) | |||
454 | if (map->dso->rel) | 461 | if (map->dso->rel) |
455 | return map->unmap_ip(map, ip + map->pgoff); | 462 | return map->unmap_ip(map, ip + map->pgoff); |
456 | 463 | ||
464 | /* | ||
465 | * kernel modules also have DSO_TYPE_USER in dso->kernel, | ||
466 | * but all kernel modules are ET_REL, so won't get here. | ||
467 | */ | ||
468 | if (map->dso->kernel == DSO_TYPE_USER) | ||
469 | return map->unmap_ip(map, ip - map->dso->text_offset); | ||
470 | |||
457 | return ip + map->reloc; | 471 | return ip + map->reloc; |
458 | } | 472 | } |
459 | 473 | ||
diff --git a/tools/perf/util/ordered-events.c b/tools/perf/util/ordered-events.c index b1b9e2385f4b..fe84df1875aa 100644 --- a/tools/perf/util/ordered-events.c +++ b/tools/perf/util/ordered-events.c | |||
@@ -308,3 +308,12 @@ void ordered_events__free(struct ordered_events *oe) | |||
308 | free(event); | 308 | free(event); |
309 | } | 309 | } |
310 | } | 310 | } |
311 | |||
312 | void ordered_events__reinit(struct ordered_events *oe) | ||
313 | { | ||
314 | ordered_events__deliver_t old_deliver = oe->deliver; | ||
315 | |||
316 | ordered_events__free(oe); | ||
317 | memset(oe, '\0', sizeof(*oe)); | ||
318 | ordered_events__init(oe, old_deliver); | ||
319 | } | ||
diff --git a/tools/perf/util/ordered-events.h b/tools/perf/util/ordered-events.h index f403991e3bfd..e11468a9a6e4 100644 --- a/tools/perf/util/ordered-events.h +++ b/tools/perf/util/ordered-events.h | |||
@@ -49,6 +49,7 @@ void ordered_events__delete(struct ordered_events *oe, struct ordered_event *eve | |||
49 | int ordered_events__flush(struct ordered_events *oe, enum oe_flush how); | 49 | int ordered_events__flush(struct ordered_events *oe, enum oe_flush how); |
50 | void ordered_events__init(struct ordered_events *oe, ordered_events__deliver_t deliver); | 50 | void ordered_events__init(struct ordered_events *oe, ordered_events__deliver_t deliver); |
51 | void ordered_events__free(struct ordered_events *oe); | 51 | void ordered_events__free(struct ordered_events *oe); |
52 | void ordered_events__reinit(struct ordered_events *oe); | ||
52 | 53 | ||
53 | static inline | 54 | static inline |
54 | void ordered_events__set_alloc_size(struct ordered_events *oe, u64 size) | 55 | void ordered_events__set_alloc_size(struct ordered_events *oe, u64 size) |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 4c19d5e79d8c..c6fd0479f4cd 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
@@ -138,11 +138,11 @@ struct event_symbol event_symbols_sw[PERF_COUNT_SW_MAX] = { | |||
138 | #define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE) | 138 | #define PERF_EVENT_TYPE(config) __PERF_EVENT_FIELD(config, TYPE) |
139 | #define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT) | 139 | #define PERF_EVENT_ID(config) __PERF_EVENT_FIELD(config, EVENT) |
140 | 140 | ||
141 | #define for_each_subsystem(sys_dir, sys_dirent, sys_next) \ | 141 | #define for_each_subsystem(sys_dir, sys_dirent) \ |
142 | while (!readdir_r(sys_dir, &sys_dirent, &sys_next) && sys_next) \ | 142 | while ((sys_dirent = readdir(sys_dir)) != NULL) \ |
143 | if (sys_dirent.d_type == DT_DIR && \ | 143 | if (sys_dirent->d_type == DT_DIR && \ |
144 | (strcmp(sys_dirent.d_name, ".")) && \ | 144 | (strcmp(sys_dirent->d_name, ".")) && \ |
145 | (strcmp(sys_dirent.d_name, ".."))) | 145 | (strcmp(sys_dirent->d_name, ".."))) |
146 | 146 | ||
147 | static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir) | 147 | static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir) |
148 | { | 148 | { |
@@ -159,12 +159,12 @@ static int tp_event_has_id(struct dirent *sys_dir, struct dirent *evt_dir) | |||
159 | return 0; | 159 | return 0; |
160 | } | 160 | } |
161 | 161 | ||
162 | #define for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) \ | 162 | #define for_each_event(sys_dirent, evt_dir, evt_dirent) \ |
163 | while (!readdir_r(evt_dir, &evt_dirent, &evt_next) && evt_next) \ | 163 | while ((evt_dirent = readdir(evt_dir)) != NULL) \ |
164 | if (evt_dirent.d_type == DT_DIR && \ | 164 | if (evt_dirent->d_type == DT_DIR && \ |
165 | (strcmp(evt_dirent.d_name, ".")) && \ | 165 | (strcmp(evt_dirent->d_name, ".")) && \ |
166 | (strcmp(evt_dirent.d_name, "..")) && \ | 166 | (strcmp(evt_dirent->d_name, "..")) && \ |
167 | (!tp_event_has_id(&sys_dirent, &evt_dirent))) | 167 | (!tp_event_has_id(sys_dirent, evt_dirent))) |
168 | 168 | ||
169 | #define MAX_EVENT_LENGTH 512 | 169 | #define MAX_EVENT_LENGTH 512 |
170 | 170 | ||
@@ -173,7 +173,7 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) | |||
173 | { | 173 | { |
174 | struct tracepoint_path *path = NULL; | 174 | struct tracepoint_path *path = NULL; |
175 | DIR *sys_dir, *evt_dir; | 175 | DIR *sys_dir, *evt_dir; |
176 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; | 176 | struct dirent *sys_dirent, *evt_dirent; |
177 | char id_buf[24]; | 177 | char id_buf[24]; |
178 | int fd; | 178 | int fd; |
179 | u64 id; | 179 | u64 id; |
@@ -184,18 +184,18 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) | |||
184 | if (!sys_dir) | 184 | if (!sys_dir) |
185 | return NULL; | 185 | return NULL; |
186 | 186 | ||
187 | for_each_subsystem(sys_dir, sys_dirent, sys_next) { | 187 | for_each_subsystem(sys_dir, sys_dirent) { |
188 | 188 | ||
189 | snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, | 189 | snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, |
190 | sys_dirent.d_name); | 190 | sys_dirent->d_name); |
191 | evt_dir = opendir(dir_path); | 191 | evt_dir = opendir(dir_path); |
192 | if (!evt_dir) | 192 | if (!evt_dir) |
193 | continue; | 193 | continue; |
194 | 194 | ||
195 | for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { | 195 | for_each_event(sys_dirent, evt_dir, evt_dirent) { |
196 | 196 | ||
197 | snprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, | 197 | snprintf(evt_path, MAXPATHLEN, "%s/%s/id", dir_path, |
198 | evt_dirent.d_name); | 198 | evt_dirent->d_name); |
199 | fd = open(evt_path, O_RDONLY); | 199 | fd = open(evt_path, O_RDONLY); |
200 | if (fd < 0) | 200 | if (fd < 0) |
201 | continue; | 201 | continue; |
@@ -220,9 +220,9 @@ struct tracepoint_path *tracepoint_id_to_path(u64 config) | |||
220 | free(path); | 220 | free(path); |
221 | return NULL; | 221 | return NULL; |
222 | } | 222 | } |
223 | strncpy(path->system, sys_dirent.d_name, | 223 | strncpy(path->system, sys_dirent->d_name, |
224 | MAX_EVENT_LENGTH); | 224 | MAX_EVENT_LENGTH); |
225 | strncpy(path->name, evt_dirent.d_name, | 225 | strncpy(path->name, evt_dirent->d_name, |
226 | MAX_EVENT_LENGTH); | 226 | MAX_EVENT_LENGTH); |
227 | return path; | 227 | return path; |
228 | } | 228 | } |
@@ -1649,7 +1649,7 @@ static void parse_events_print_error(struct parse_events_error *err, | |||
1649 | 1649 | ||
1650 | buf = _buf; | 1650 | buf = _buf; |
1651 | 1651 | ||
1652 | /* We're cutting from the beggining. */ | 1652 | /* We're cutting from the beginning. */ |
1653 | if (err->idx > max_err_idx) | 1653 | if (err->idx > max_err_idx) |
1654 | cut = err->idx - max_err_idx; | 1654 | cut = err->idx - max_err_idx; |
1655 | 1655 | ||
@@ -1812,7 +1812,7 @@ void print_tracepoint_events(const char *subsys_glob, const char *event_glob, | |||
1812 | bool name_only) | 1812 | bool name_only) |
1813 | { | 1813 | { |
1814 | DIR *sys_dir, *evt_dir; | 1814 | DIR *sys_dir, *evt_dir; |
1815 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; | 1815 | struct dirent *sys_dirent, *evt_dirent; |
1816 | char evt_path[MAXPATHLEN]; | 1816 | char evt_path[MAXPATHLEN]; |
1817 | char dir_path[MAXPATHLEN]; | 1817 | char dir_path[MAXPATHLEN]; |
1818 | char **evt_list = NULL; | 1818 | char **evt_list = NULL; |
@@ -1830,20 +1830,20 @@ restart: | |||
1830 | goto out_close_sys_dir; | 1830 | goto out_close_sys_dir; |
1831 | } | 1831 | } |
1832 | 1832 | ||
1833 | for_each_subsystem(sys_dir, sys_dirent, sys_next) { | 1833 | for_each_subsystem(sys_dir, sys_dirent) { |
1834 | if (subsys_glob != NULL && | 1834 | if (subsys_glob != NULL && |
1835 | !strglobmatch(sys_dirent.d_name, subsys_glob)) | 1835 | !strglobmatch(sys_dirent->d_name, subsys_glob)) |
1836 | continue; | 1836 | continue; |
1837 | 1837 | ||
1838 | snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, | 1838 | snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, |
1839 | sys_dirent.d_name); | 1839 | sys_dirent->d_name); |
1840 | evt_dir = opendir(dir_path); | 1840 | evt_dir = opendir(dir_path); |
1841 | if (!evt_dir) | 1841 | if (!evt_dir) |
1842 | continue; | 1842 | continue; |
1843 | 1843 | ||
1844 | for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { | 1844 | for_each_event(sys_dirent, evt_dir, evt_dirent) { |
1845 | if (event_glob != NULL && | 1845 | if (event_glob != NULL && |
1846 | !strglobmatch(evt_dirent.d_name, event_glob)) | 1846 | !strglobmatch(evt_dirent->d_name, event_glob)) |
1847 | continue; | 1847 | continue; |
1848 | 1848 | ||
1849 | if (!evt_num_known) { | 1849 | if (!evt_num_known) { |
@@ -1852,7 +1852,7 @@ restart: | |||
1852 | } | 1852 | } |
1853 | 1853 | ||
1854 | snprintf(evt_path, MAXPATHLEN, "%s:%s", | 1854 | snprintf(evt_path, MAXPATHLEN, "%s:%s", |
1855 | sys_dirent.d_name, evt_dirent.d_name); | 1855 | sys_dirent->d_name, evt_dirent->d_name); |
1856 | 1856 | ||
1857 | evt_list[evt_i] = strdup(evt_path); | 1857 | evt_list[evt_i] = strdup(evt_path); |
1858 | if (evt_list[evt_i] == NULL) | 1858 | if (evt_list[evt_i] == NULL) |
@@ -1905,7 +1905,7 @@ out_close_sys_dir: | |||
1905 | int is_valid_tracepoint(const char *event_string) | 1905 | int is_valid_tracepoint(const char *event_string) |
1906 | { | 1906 | { |
1907 | DIR *sys_dir, *evt_dir; | 1907 | DIR *sys_dir, *evt_dir; |
1908 | struct dirent *sys_next, *evt_next, sys_dirent, evt_dirent; | 1908 | struct dirent *sys_dirent, *evt_dirent; |
1909 | char evt_path[MAXPATHLEN]; | 1909 | char evt_path[MAXPATHLEN]; |
1910 | char dir_path[MAXPATHLEN]; | 1910 | char dir_path[MAXPATHLEN]; |
1911 | 1911 | ||
@@ -1913,17 +1913,17 @@ int is_valid_tracepoint(const char *event_string) | |||
1913 | if (!sys_dir) | 1913 | if (!sys_dir) |
1914 | return 0; | 1914 | return 0; |
1915 | 1915 | ||
1916 | for_each_subsystem(sys_dir, sys_dirent, sys_next) { | 1916 | for_each_subsystem(sys_dir, sys_dirent) { |
1917 | 1917 | ||
1918 | snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, | 1918 | snprintf(dir_path, MAXPATHLEN, "%s/%s", tracing_events_path, |
1919 | sys_dirent.d_name); | 1919 | sys_dirent->d_name); |
1920 | evt_dir = opendir(dir_path); | 1920 | evt_dir = opendir(dir_path); |
1921 | if (!evt_dir) | 1921 | if (!evt_dir) |
1922 | continue; | 1922 | continue; |
1923 | 1923 | ||
1924 | for_each_event(sys_dirent, evt_dir, evt_dirent, evt_next) { | 1924 | for_each_event(sys_dirent, evt_dir, evt_dirent) { |
1925 | snprintf(evt_path, MAXPATHLEN, "%s:%s", | 1925 | snprintf(evt_path, MAXPATHLEN, "%s:%s", |
1926 | sys_dirent.d_name, evt_dirent.d_name); | 1926 | sys_dirent->d_name, evt_dirent->d_name); |
1927 | if (!strcmp(evt_path, event_string)) { | 1927 | if (!strcmp(evt_path, event_string)) { |
1928 | closedir(evt_dir); | 1928 | closedir(evt_dir); |
1929 | closedir(sys_dir); | 1929 | closedir(sys_dir); |
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index adef23b1352e..ddb0261b2577 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c | |||
@@ -602,14 +602,13 @@ static void pmu_format_value(unsigned long *format, __u64 value, __u64 *v, | |||
602 | 602 | ||
603 | static __u64 pmu_format_max_value(const unsigned long *format) | 603 | static __u64 pmu_format_max_value(const unsigned long *format) |
604 | { | 604 | { |
605 | int w; | 605 | __u64 w = 0; |
606 | int fbit; | ||
606 | 607 | ||
607 | w = bitmap_weight(format, PERF_PMU_FORMAT_BITS); | 608 | for_each_set_bit(fbit, format, PERF_PMU_FORMAT_BITS) |
608 | if (!w) | 609 | w |= (1ULL << fbit); |
609 | return 0; | 610 | |
610 | if (w < 64) | 611 | return w; |
611 | return (1ULL << w) - 1; | ||
612 | return -1; | ||
613 | } | 612 | } |
614 | 613 | ||
615 | /* | 614 | /* |
@@ -644,20 +643,20 @@ static int pmu_resolve_param_term(struct parse_events_term *term, | |||
644 | static char *pmu_formats_string(struct list_head *formats) | 643 | static char *pmu_formats_string(struct list_head *formats) |
645 | { | 644 | { |
646 | struct perf_pmu_format *format; | 645 | struct perf_pmu_format *format; |
647 | char *str; | 646 | char *str = NULL; |
648 | struct strbuf buf; | 647 | struct strbuf buf = STRBUF_INIT; |
649 | unsigned i = 0; | 648 | unsigned i = 0; |
650 | 649 | ||
651 | if (!formats) | 650 | if (!formats) |
652 | return NULL; | 651 | return NULL; |
653 | 652 | ||
654 | strbuf_init(&buf, 0); | ||
655 | /* sysfs exported terms */ | 653 | /* sysfs exported terms */ |
656 | list_for_each_entry(format, formats, list) | 654 | list_for_each_entry(format, formats, list) |
657 | strbuf_addf(&buf, i++ ? ",%s" : "%s", | 655 | if (strbuf_addf(&buf, i++ ? ",%s" : "%s", format->name) < 0) |
658 | format->name); | 656 | goto error; |
659 | 657 | ||
660 | str = strbuf_detach(&buf, NULL); | 658 | str = strbuf_detach(&buf, NULL); |
659 | error: | ||
661 | strbuf_release(&buf); | 660 | strbuf_release(&buf); |
662 | 661 | ||
663 | return str; | 662 | return str; |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 8319fbb08636..74401a20106d 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -265,6 +265,65 @@ static bool kprobe_warn_out_range(const char *symbol, unsigned long address) | |||
265 | return true; | 265 | return true; |
266 | } | 266 | } |
267 | 267 | ||
268 | /* | ||
269 | * NOTE: | ||
270 | * '.gnu.linkonce.this_module' section of kernel module elf directly | ||
271 | * maps to 'struct module' from linux/module.h. This section contains | ||
272 | * actual module name which will be used by kernel after loading it. | ||
273 | * But, we cannot use 'struct module' here since linux/module.h is not | ||
274 | * exposed to user-space. Offset of 'name' has remained same from long | ||
275 | * time, so hardcoding it here. | ||
276 | */ | ||
277 | #ifdef __LP64__ | ||
278 | #define MOD_NAME_OFFSET 24 | ||
279 | #else | ||
280 | #define MOD_NAME_OFFSET 12 | ||
281 | #endif | ||
282 | |||
283 | /* | ||
284 | * @module can be module name of module file path. In case of path, | ||
285 | * inspect elf and find out what is actual module name. | ||
286 | * Caller has to free mod_name after using it. | ||
287 | */ | ||
288 | static char *find_module_name(const char *module) | ||
289 | { | ||
290 | int fd; | ||
291 | Elf *elf; | ||
292 | GElf_Ehdr ehdr; | ||
293 | GElf_Shdr shdr; | ||
294 | Elf_Data *data; | ||
295 | Elf_Scn *sec; | ||
296 | char *mod_name = NULL; | ||
297 | |||
298 | fd = open(module, O_RDONLY); | ||
299 | if (fd < 0) | ||
300 | return NULL; | ||
301 | |||
302 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | ||
303 | if (elf == NULL) | ||
304 | goto elf_err; | ||
305 | |||
306 | if (gelf_getehdr(elf, &ehdr) == NULL) | ||
307 | goto ret_err; | ||
308 | |||
309 | sec = elf_section_by_name(elf, &ehdr, &shdr, | ||
310 | ".gnu.linkonce.this_module", NULL); | ||
311 | if (!sec) | ||
312 | goto ret_err; | ||
313 | |||
314 | data = elf_getdata(sec, NULL); | ||
315 | if (!data || !data->d_buf) | ||
316 | goto ret_err; | ||
317 | |||
318 | mod_name = strdup((char *)data->d_buf + MOD_NAME_OFFSET); | ||
319 | |||
320 | ret_err: | ||
321 | elf_end(elf); | ||
322 | elf_err: | ||
323 | close(fd); | ||
324 | return mod_name; | ||
325 | } | ||
326 | |||
268 | #ifdef HAVE_DWARF_SUPPORT | 327 | #ifdef HAVE_DWARF_SUPPORT |
269 | 328 | ||
270 | static int kernel_get_module_dso(const char *module, struct dso **pdso) | 329 | static int kernel_get_module_dso(const char *module, struct dso **pdso) |
@@ -486,8 +545,10 @@ static int get_text_start_address(const char *exec, unsigned long *address) | |||
486 | return -errno; | 545 | return -errno; |
487 | 546 | ||
488 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | 547 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); |
489 | if (elf == NULL) | 548 | if (elf == NULL) { |
490 | return -EINVAL; | 549 | ret = -EINVAL; |
550 | goto out_close; | ||
551 | } | ||
491 | 552 | ||
492 | if (gelf_getehdr(elf, &ehdr) == NULL) | 553 | if (gelf_getehdr(elf, &ehdr) == NULL) |
493 | goto out; | 554 | goto out; |
@@ -499,6 +560,9 @@ static int get_text_start_address(const char *exec, unsigned long *address) | |||
499 | ret = 0; | 560 | ret = 0; |
500 | out: | 561 | out: |
501 | elf_end(elf); | 562 | elf_end(elf); |
563 | out_close: | ||
564 | close(fd); | ||
565 | |||
502 | return ret; | 566 | return ret; |
503 | } | 567 | } |
504 | 568 | ||
@@ -583,32 +647,23 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, | |||
583 | int ntevs, const char *module) | 647 | int ntevs, const char *module) |
584 | { | 648 | { |
585 | int i, ret = 0; | 649 | int i, ret = 0; |
586 | char *tmp; | 650 | char *mod_name = NULL; |
587 | 651 | ||
588 | if (!module) | 652 | if (!module) |
589 | return 0; | 653 | return 0; |
590 | 654 | ||
591 | tmp = strrchr(module, '/'); | 655 | mod_name = find_module_name(module); |
592 | if (tmp) { | ||
593 | /* This is a module path -- get the module name */ | ||
594 | module = strdup(tmp + 1); | ||
595 | if (!module) | ||
596 | return -ENOMEM; | ||
597 | tmp = strchr(module, '.'); | ||
598 | if (tmp) | ||
599 | *tmp = '\0'; | ||
600 | tmp = (char *)module; /* For free() */ | ||
601 | } | ||
602 | 656 | ||
603 | for (i = 0; i < ntevs; i++) { | 657 | for (i = 0; i < ntevs; i++) { |
604 | tevs[i].point.module = strdup(module); | 658 | tevs[i].point.module = |
659 | strdup(mod_name ? mod_name : module); | ||
605 | if (!tevs[i].point.module) { | 660 | if (!tevs[i].point.module) { |
606 | ret = -ENOMEM; | 661 | ret = -ENOMEM; |
607 | break; | 662 | break; |
608 | } | 663 | } |
609 | } | 664 | } |
610 | 665 | ||
611 | free(tmp); | 666 | free(mod_name); |
612 | return ret; | 667 | return ret; |
613 | } | 668 | } |
614 | 669 | ||
@@ -1618,69 +1673,65 @@ out: | |||
1618 | } | 1673 | } |
1619 | 1674 | ||
1620 | /* Compose only probe arg */ | 1675 | /* Compose only probe arg */ |
1621 | int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len) | 1676 | char *synthesize_perf_probe_arg(struct perf_probe_arg *pa) |
1622 | { | 1677 | { |
1623 | struct perf_probe_arg_field *field = pa->field; | 1678 | struct perf_probe_arg_field *field = pa->field; |
1624 | int ret; | 1679 | struct strbuf buf; |
1625 | char *tmp = buf; | 1680 | char *ret = NULL; |
1681 | int err; | ||
1682 | |||
1683 | if (strbuf_init(&buf, 64) < 0) | ||
1684 | return NULL; | ||
1626 | 1685 | ||
1627 | if (pa->name && pa->var) | 1686 | if (pa->name && pa->var) |
1628 | ret = e_snprintf(tmp, len, "%s=%s", pa->name, pa->var); | 1687 | err = strbuf_addf(&buf, "%s=%s", pa->name, pa->var); |
1629 | else | 1688 | else |
1630 | ret = e_snprintf(tmp, len, "%s", pa->name ? pa->name : pa->var); | 1689 | err = strbuf_addstr(&buf, pa->name ?: pa->var); |
1631 | if (ret <= 0) | 1690 | if (err) |
1632 | goto error; | 1691 | goto out; |
1633 | tmp += ret; | ||
1634 | len -= ret; | ||
1635 | 1692 | ||
1636 | while (field) { | 1693 | while (field) { |
1637 | if (field->name[0] == '[') | 1694 | if (field->name[0] == '[') |
1638 | ret = e_snprintf(tmp, len, "%s", field->name); | 1695 | err = strbuf_addstr(&buf, field->name); |
1639 | else | 1696 | else |
1640 | ret = e_snprintf(tmp, len, "%s%s", | 1697 | err = strbuf_addf(&buf, "%s%s", field->ref ? "->" : ".", |
1641 | field->ref ? "->" : ".", field->name); | 1698 | field->name); |
1642 | if (ret <= 0) | ||
1643 | goto error; | ||
1644 | tmp += ret; | ||
1645 | len -= ret; | ||
1646 | field = field->next; | 1699 | field = field->next; |
1700 | if (err) | ||
1701 | goto out; | ||
1647 | } | 1702 | } |
1648 | 1703 | ||
1649 | if (pa->type) { | 1704 | if (pa->type) |
1650 | ret = e_snprintf(tmp, len, ":%s", pa->type); | 1705 | if (strbuf_addf(&buf, ":%s", pa->type) < 0) |
1651 | if (ret <= 0) | 1706 | goto out; |
1652 | goto error; | ||
1653 | tmp += ret; | ||
1654 | len -= ret; | ||
1655 | } | ||
1656 | 1707 | ||
1657 | return tmp - buf; | 1708 | ret = strbuf_detach(&buf, NULL); |
1658 | error: | 1709 | out: |
1659 | pr_debug("Failed to synthesize perf probe argument: %d\n", ret); | 1710 | strbuf_release(&buf); |
1660 | return ret; | 1711 | return ret; |
1661 | } | 1712 | } |
1662 | 1713 | ||
1663 | /* Compose only probe point (not argument) */ | 1714 | /* Compose only probe point (not argument) */ |
1664 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp) | 1715 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp) |
1665 | { | 1716 | { |
1666 | char *buf, *tmp; | 1717 | struct strbuf buf; |
1667 | char offs[32] = "", line[32] = "", file[32] = ""; | 1718 | char *tmp, *ret = NULL; |
1668 | int ret, len; | 1719 | int len, err = 0; |
1669 | 1720 | ||
1670 | buf = zalloc(MAX_CMDLEN); | 1721 | if (strbuf_init(&buf, 64) < 0) |
1671 | if (buf == NULL) { | 1722 | return NULL; |
1672 | ret = -ENOMEM; | 1723 | |
1673 | goto error; | 1724 | if (pp->function) { |
1674 | } | 1725 | if (strbuf_addstr(&buf, pp->function) < 0) |
1675 | if (pp->offset) { | 1726 | goto out; |
1676 | ret = e_snprintf(offs, 32, "+%lu", pp->offset); | 1727 | if (pp->offset) |
1677 | if (ret <= 0) | 1728 | err = strbuf_addf(&buf, "+%lu", pp->offset); |
1678 | goto error; | 1729 | else if (pp->line) |
1679 | } | 1730 | err = strbuf_addf(&buf, ":%d", pp->line); |
1680 | if (pp->line) { | 1731 | else if (pp->retprobe) |
1681 | ret = e_snprintf(line, 32, ":%d", pp->line); | 1732 | err = strbuf_addstr(&buf, "%return"); |
1682 | if (ret <= 0) | 1733 | if (err) |
1683 | goto error; | 1734 | goto out; |
1684 | } | 1735 | } |
1685 | if (pp->file) { | 1736 | if (pp->file) { |
1686 | tmp = pp->file; | 1737 | tmp = pp->file; |
@@ -1689,25 +1740,15 @@ static char *synthesize_perf_probe_point(struct perf_probe_point *pp) | |||
1689 | tmp = strchr(pp->file + len - 30, '/'); | 1740 | tmp = strchr(pp->file + len - 30, '/'); |
1690 | tmp = tmp ? tmp + 1 : pp->file + len - 30; | 1741 | tmp = tmp ? tmp + 1 : pp->file + len - 30; |
1691 | } | 1742 | } |
1692 | ret = e_snprintf(file, 32, "@%s", tmp); | 1743 | err = strbuf_addf(&buf, "@%s", tmp); |
1693 | if (ret <= 0) | 1744 | if (!err && !pp->function && pp->line) |
1694 | goto error; | 1745 | err = strbuf_addf(&buf, ":%d", pp->line); |
1695 | } | 1746 | } |
1696 | 1747 | if (!err) | |
1697 | if (pp->function) | 1748 | ret = strbuf_detach(&buf, NULL); |
1698 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s%s%s%s", pp->function, | 1749 | out: |
1699 | offs, pp->retprobe ? "%return" : "", line, | 1750 | strbuf_release(&buf); |
1700 | file); | 1751 | return ret; |
1701 | else | ||
1702 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", file, line); | ||
1703 | if (ret <= 0) | ||
1704 | goto error; | ||
1705 | |||
1706 | return buf; | ||
1707 | error: | ||
1708 | pr_debug("Failed to synthesize perf probe point: %d\n", ret); | ||
1709 | free(buf); | ||
1710 | return NULL; | ||
1711 | } | 1752 | } |
1712 | 1753 | ||
1713 | #if 0 | 1754 | #if 0 |
@@ -1736,45 +1777,32 @@ char *synthesize_perf_probe_command(struct perf_probe_event *pev) | |||
1736 | #endif | 1777 | #endif |
1737 | 1778 | ||
1738 | static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref, | 1779 | static int __synthesize_probe_trace_arg_ref(struct probe_trace_arg_ref *ref, |
1739 | char **buf, size_t *buflen, | 1780 | struct strbuf *buf, int depth) |
1740 | int depth) | ||
1741 | { | 1781 | { |
1742 | int ret; | 1782 | int err; |
1743 | if (ref->next) { | 1783 | if (ref->next) { |
1744 | depth = __synthesize_probe_trace_arg_ref(ref->next, buf, | 1784 | depth = __synthesize_probe_trace_arg_ref(ref->next, buf, |
1745 | buflen, depth + 1); | 1785 | depth + 1); |
1746 | if (depth < 0) | 1786 | if (depth < 0) |
1747 | goto out; | 1787 | return depth; |
1748 | } | ||
1749 | |||
1750 | ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset); | ||
1751 | if (ret < 0) | ||
1752 | depth = ret; | ||
1753 | else { | ||
1754 | *buf += ret; | ||
1755 | *buflen -= ret; | ||
1756 | } | 1788 | } |
1757 | out: | 1789 | err = strbuf_addf(buf, "%+ld(", ref->offset); |
1758 | return depth; | 1790 | return (err < 0) ? err : depth; |
1759 | |||
1760 | } | 1791 | } |
1761 | 1792 | ||
1762 | static int synthesize_probe_trace_arg(struct probe_trace_arg *arg, | 1793 | static int synthesize_probe_trace_arg(struct probe_trace_arg *arg, |
1763 | char *buf, size_t buflen) | 1794 | struct strbuf *buf) |
1764 | { | 1795 | { |
1765 | struct probe_trace_arg_ref *ref = arg->ref; | 1796 | struct probe_trace_arg_ref *ref = arg->ref; |
1766 | int ret, depth = 0; | 1797 | int depth = 0, err; |
1767 | char *tmp = buf; | ||
1768 | 1798 | ||
1769 | /* Argument name or separator */ | 1799 | /* Argument name or separator */ |
1770 | if (arg->name) | 1800 | if (arg->name) |
1771 | ret = e_snprintf(buf, buflen, " %s=", arg->name); | 1801 | err = strbuf_addf(buf, " %s=", arg->name); |
1772 | else | 1802 | else |
1773 | ret = e_snprintf(buf, buflen, " "); | 1803 | err = strbuf_addch(buf, ' '); |
1774 | if (ret < 0) | 1804 | if (err) |
1775 | return ret; | 1805 | return err; |
1776 | buf += ret; | ||
1777 | buflen -= ret; | ||
1778 | 1806 | ||
1779 | /* Special case: @XXX */ | 1807 | /* Special case: @XXX */ |
1780 | if (arg->value[0] == '@' && arg->ref) | 1808 | if (arg->value[0] == '@' && arg->ref) |
@@ -1782,59 +1810,44 @@ static int synthesize_probe_trace_arg(struct probe_trace_arg *arg, | |||
1782 | 1810 | ||
1783 | /* Dereferencing arguments */ | 1811 | /* Dereferencing arguments */ |
1784 | if (ref) { | 1812 | if (ref) { |
1785 | depth = __synthesize_probe_trace_arg_ref(ref, &buf, | 1813 | depth = __synthesize_probe_trace_arg_ref(ref, buf, 1); |
1786 | &buflen, 1); | ||
1787 | if (depth < 0) | 1814 | if (depth < 0) |
1788 | return depth; | 1815 | return depth; |
1789 | } | 1816 | } |
1790 | 1817 | ||
1791 | /* Print argument value */ | 1818 | /* Print argument value */ |
1792 | if (arg->value[0] == '@' && arg->ref) | 1819 | if (arg->value[0] == '@' && arg->ref) |
1793 | ret = e_snprintf(buf, buflen, "%s%+ld", arg->value, | 1820 | err = strbuf_addf(buf, "%s%+ld", arg->value, arg->ref->offset); |
1794 | arg->ref->offset); | ||
1795 | else | 1821 | else |
1796 | ret = e_snprintf(buf, buflen, "%s", arg->value); | 1822 | err = strbuf_addstr(buf, arg->value); |
1797 | if (ret < 0) | ||
1798 | return ret; | ||
1799 | buf += ret; | ||
1800 | buflen -= ret; | ||
1801 | 1823 | ||
1802 | /* Closing */ | 1824 | /* Closing */ |
1803 | while (depth--) { | 1825 | while (!err && depth--) |
1804 | ret = e_snprintf(buf, buflen, ")"); | 1826 | err = strbuf_addch(buf, ')'); |
1805 | if (ret < 0) | 1827 | |
1806 | return ret; | ||
1807 | buf += ret; | ||
1808 | buflen -= ret; | ||
1809 | } | ||
1810 | /* Print argument type */ | 1828 | /* Print argument type */ |
1811 | if (arg->type) { | 1829 | if (!err && arg->type) |
1812 | ret = e_snprintf(buf, buflen, ":%s", arg->type); | 1830 | err = strbuf_addf(buf, ":%s", arg->type); |
1813 | if (ret <= 0) | ||
1814 | return ret; | ||
1815 | buf += ret; | ||
1816 | } | ||
1817 | 1831 | ||
1818 | return buf - tmp; | 1832 | return err; |
1819 | } | 1833 | } |
1820 | 1834 | ||
1821 | char *synthesize_probe_trace_command(struct probe_trace_event *tev) | 1835 | char *synthesize_probe_trace_command(struct probe_trace_event *tev) |
1822 | { | 1836 | { |
1823 | struct probe_trace_point *tp = &tev->point; | 1837 | struct probe_trace_point *tp = &tev->point; |
1824 | char *buf; | 1838 | struct strbuf buf; |
1825 | int i, len, ret; | 1839 | char *ret = NULL; |
1840 | int i, err; | ||
1826 | 1841 | ||
1827 | buf = zalloc(MAX_CMDLEN); | 1842 | /* Uprobes must have tp->module */ |
1828 | if (buf == NULL) | 1843 | if (tev->uprobes && !tp->module) |
1829 | return NULL; | 1844 | return NULL; |
1830 | 1845 | ||
1831 | len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s ", tp->retprobe ? 'r' : 'p', | 1846 | if (strbuf_init(&buf, 32) < 0) |
1832 | tev->group, tev->event); | 1847 | return NULL; |
1833 | if (len <= 0) | ||
1834 | goto error; | ||
1835 | 1848 | ||
1836 | /* Uprobes must have tp->module */ | 1849 | if (strbuf_addf(&buf, "%c:%s/%s ", tp->retprobe ? 'r' : 'p', |
1837 | if (tev->uprobes && !tp->module) | 1850 | tev->group, tev->event) < 0) |
1838 | goto error; | 1851 | goto error; |
1839 | /* | 1852 | /* |
1840 | * If tp->address == 0, then this point must be a | 1853 | * If tp->address == 0, then this point must be a |
@@ -1849,34 +1862,25 @@ char *synthesize_probe_trace_command(struct probe_trace_event *tev) | |||
1849 | 1862 | ||
1850 | /* Use the tp->address for uprobes */ | 1863 | /* Use the tp->address for uprobes */ |
1851 | if (tev->uprobes) | 1864 | if (tev->uprobes) |
1852 | ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s:0x%lx", | 1865 | err = strbuf_addf(&buf, "%s:0x%lx", tp->module, tp->address); |
1853 | tp->module, tp->address); | ||
1854 | else if (!strncmp(tp->symbol, "0x", 2)) | 1866 | else if (!strncmp(tp->symbol, "0x", 2)) |
1855 | /* Absolute address. See try_to_find_absolute_address() */ | 1867 | /* Absolute address. See try_to_find_absolute_address() */ |
1856 | ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s%s0x%lx", | 1868 | err = strbuf_addf(&buf, "%s%s0x%lx", tp->module ?: "", |
1857 | tp->module ?: "", tp->module ? ":" : "", | 1869 | tp->module ? ":" : "", tp->address); |
1858 | tp->address); | ||
1859 | else | 1870 | else |
1860 | ret = e_snprintf(buf + len, MAX_CMDLEN - len, "%s%s%s+%lu", | 1871 | err = strbuf_addf(&buf, "%s%s%s+%lu", tp->module ?: "", |
1861 | tp->module ?: "", tp->module ? ":" : "", | 1872 | tp->module ? ":" : "", tp->symbol, tp->offset); |
1862 | tp->symbol, tp->offset); | 1873 | if (err) |
1863 | |||
1864 | if (ret <= 0) | ||
1865 | goto error; | 1874 | goto error; |
1866 | len += ret; | ||
1867 | 1875 | ||
1868 | for (i = 0; i < tev->nargs; i++) { | 1876 | for (i = 0; i < tev->nargs; i++) |
1869 | ret = synthesize_probe_trace_arg(&tev->args[i], buf + len, | 1877 | if (synthesize_probe_trace_arg(&tev->args[i], &buf) < 0) |
1870 | MAX_CMDLEN - len); | ||
1871 | if (ret <= 0) | ||
1872 | goto error; | 1878 | goto error; |
1873 | len += ret; | ||
1874 | } | ||
1875 | 1879 | ||
1876 | return buf; | 1880 | ret = strbuf_detach(&buf, NULL); |
1877 | error: | 1881 | error: |
1878 | free(buf); | 1882 | strbuf_release(&buf); |
1879 | return NULL; | 1883 | return ret; |
1880 | } | 1884 | } |
1881 | 1885 | ||
1882 | static int find_perf_probe_point_from_map(struct probe_trace_point *tp, | 1886 | static int find_perf_probe_point_from_map(struct probe_trace_point *tp, |
@@ -1958,7 +1962,7 @@ static int convert_to_perf_probe_point(struct probe_trace_point *tp, | |||
1958 | static int convert_to_perf_probe_event(struct probe_trace_event *tev, | 1962 | static int convert_to_perf_probe_event(struct probe_trace_event *tev, |
1959 | struct perf_probe_event *pev, bool is_kprobe) | 1963 | struct perf_probe_event *pev, bool is_kprobe) |
1960 | { | 1964 | { |
1961 | char buf[64] = ""; | 1965 | struct strbuf buf = STRBUF_INIT; |
1962 | int i, ret; | 1966 | int i, ret; |
1963 | 1967 | ||
1964 | /* Convert event/group name */ | 1968 | /* Convert event/group name */ |
@@ -1981,14 +1985,15 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev, | |||
1981 | if (tev->args[i].name) | 1985 | if (tev->args[i].name) |
1982 | pev->args[i].name = strdup(tev->args[i].name); | 1986 | pev->args[i].name = strdup(tev->args[i].name); |
1983 | else { | 1987 | else { |
1984 | ret = synthesize_probe_trace_arg(&tev->args[i], | 1988 | if ((ret = strbuf_init(&buf, 32)) < 0) |
1985 | buf, 64); | 1989 | goto error; |
1986 | pev->args[i].name = strdup(buf); | 1990 | ret = synthesize_probe_trace_arg(&tev->args[i], &buf); |
1991 | pev->args[i].name = strbuf_detach(&buf, NULL); | ||
1987 | } | 1992 | } |
1988 | if (pev->args[i].name == NULL && ret >= 0) | 1993 | if (pev->args[i].name == NULL && ret >= 0) |
1989 | ret = -ENOMEM; | 1994 | ret = -ENOMEM; |
1990 | } | 1995 | } |
1991 | 1996 | error: | |
1992 | if (ret < 0) | 1997 | if (ret < 0) |
1993 | clear_perf_probe_event(pev); | 1998 | clear_perf_probe_event(pev); |
1994 | 1999 | ||
@@ -2162,35 +2167,38 @@ static int perf_probe_event__sprintf(const char *group, const char *event, | |||
2162 | struct strbuf *result) | 2167 | struct strbuf *result) |
2163 | { | 2168 | { |
2164 | int i, ret; | 2169 | int i, ret; |
2165 | char buf[128]; | 2170 | char *buf; |
2166 | char *place; | ||
2167 | 2171 | ||
2168 | /* Synthesize only event probe point */ | 2172 | if (asprintf(&buf, "%s:%s", group, event) < 0) |
2169 | place = synthesize_perf_probe_point(&pev->point); | 2173 | return -errno; |
2170 | if (!place) | 2174 | ret = strbuf_addf(result, " %-20s (on ", buf); |
2171 | return -EINVAL; | 2175 | free(buf); |
2176 | if (ret) | ||
2177 | return ret; | ||
2172 | 2178 | ||
2173 | ret = e_snprintf(buf, 128, "%s:%s", group, event); | 2179 | /* Synthesize only event probe point */ |
2174 | if (ret < 0) | 2180 | buf = synthesize_perf_probe_point(&pev->point); |
2175 | goto out; | 2181 | if (!buf) |
2182 | return -ENOMEM; | ||
2183 | ret = strbuf_addstr(result, buf); | ||
2184 | free(buf); | ||
2176 | 2185 | ||
2177 | strbuf_addf(result, " %-20s (on %s", buf, place); | 2186 | if (!ret && module) |
2178 | if (module) | 2187 | ret = strbuf_addf(result, " in %s", module); |
2179 | strbuf_addf(result, " in %s", module); | ||
2180 | 2188 | ||
2181 | if (pev->nargs > 0) { | 2189 | if (!ret && pev->nargs > 0) { |
2182 | strbuf_add(result, " with", 5); | 2190 | ret = strbuf_add(result, " with", 5); |
2183 | for (i = 0; i < pev->nargs; i++) { | 2191 | for (i = 0; !ret && i < pev->nargs; i++) { |
2184 | ret = synthesize_perf_probe_arg(&pev->args[i], | 2192 | buf = synthesize_perf_probe_arg(&pev->args[i]); |
2185 | buf, 128); | 2193 | if (!buf) |
2186 | if (ret < 0) | 2194 | return -ENOMEM; |
2187 | goto out; | 2195 | ret = strbuf_addf(result, " %s", buf); |
2188 | strbuf_addf(result, " %s", buf); | 2196 | free(buf); |
2189 | } | 2197 | } |
2190 | } | 2198 | } |
2191 | strbuf_addch(result, ')'); | 2199 | if (!ret) |
2192 | out: | 2200 | ret = strbuf_addch(result, ')'); |
2193 | free(place); | 2201 | |
2194 | return ret; | 2202 | return ret; |
2195 | } | 2203 | } |
2196 | 2204 | ||
@@ -2498,7 +2506,8 @@ static int find_probe_functions(struct map *map, char *name, | |||
2498 | 2506 | ||
2499 | void __weak arch__fix_tev_from_maps(struct perf_probe_event *pev __maybe_unused, | 2507 | void __weak arch__fix_tev_from_maps(struct perf_probe_event *pev __maybe_unused, |
2500 | struct probe_trace_event *tev __maybe_unused, | 2508 | struct probe_trace_event *tev __maybe_unused, |
2501 | struct map *map __maybe_unused) { } | 2509 | struct map *map __maybe_unused, |
2510 | struct symbol *sym __maybe_unused) { } | ||
2502 | 2511 | ||
2503 | /* | 2512 | /* |
2504 | * Find probe function addresses from map. | 2513 | * Find probe function addresses from map. |
@@ -2516,6 +2525,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, | |||
2516 | struct probe_trace_point *tp; | 2525 | struct probe_trace_point *tp; |
2517 | int num_matched_functions; | 2526 | int num_matched_functions; |
2518 | int ret, i, j, skipped = 0; | 2527 | int ret, i, j, skipped = 0; |
2528 | char *mod_name; | ||
2519 | 2529 | ||
2520 | map = get_target_map(pev->target, pev->uprobes); | 2530 | map = get_target_map(pev->target, pev->uprobes); |
2521 | if (!map) { | 2531 | if (!map) { |
@@ -2600,9 +2610,19 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, | |||
2600 | tp->realname = strdup_or_goto(sym->name, nomem_out); | 2610 | tp->realname = strdup_or_goto(sym->name, nomem_out); |
2601 | 2611 | ||
2602 | tp->retprobe = pp->retprobe; | 2612 | tp->retprobe = pp->retprobe; |
2603 | if (pev->target) | 2613 | if (pev->target) { |
2604 | tev->point.module = strdup_or_goto(pev->target, | 2614 | if (pev->uprobes) { |
2605 | nomem_out); | 2615 | tev->point.module = strdup_or_goto(pev->target, |
2616 | nomem_out); | ||
2617 | } else { | ||
2618 | mod_name = find_module_name(pev->target); | ||
2619 | tev->point.module = | ||
2620 | strdup(mod_name ? mod_name : pev->target); | ||
2621 | free(mod_name); | ||
2622 | if (!tev->point.module) | ||
2623 | goto nomem_out; | ||
2624 | } | ||
2625 | } | ||
2606 | tev->uprobes = pev->uprobes; | 2626 | tev->uprobes = pev->uprobes; |
2607 | tev->nargs = pev->nargs; | 2627 | tev->nargs = pev->nargs; |
2608 | if (tev->nargs) { | 2628 | if (tev->nargs) { |
@@ -2624,7 +2644,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, | |||
2624 | strdup_or_goto(pev->args[i].type, | 2644 | strdup_or_goto(pev->args[i].type, |
2625 | nomem_out); | 2645 | nomem_out); |
2626 | } | 2646 | } |
2627 | arch__fix_tev_from_maps(pev, tev, map); | 2647 | arch__fix_tev_from_maps(pev, tev, map, sym); |
2628 | } | 2648 | } |
2629 | if (ret == skipped) { | 2649 | if (ret == skipped) { |
2630 | ret = -ENOENT; | 2650 | ret = -ENOENT; |
@@ -2743,9 +2763,13 @@ static int convert_to_probe_trace_events(struct perf_probe_event *pev, | |||
2743 | { | 2763 | { |
2744 | int ret; | 2764 | int ret; |
2745 | 2765 | ||
2746 | if (pev->uprobes && !pev->group) { | 2766 | if (!pev->group) { |
2747 | /* Replace group name if not given */ | 2767 | /* Set group name if not given */ |
2748 | ret = convert_exec_to_group(pev->target, &pev->group); | 2768 | if (!pev->uprobes) { |
2769 | pev->group = strdup(PERFPROBE_GROUP); | ||
2770 | ret = pev->group ? 0 : -ENOMEM; | ||
2771 | } else | ||
2772 | ret = convert_exec_to_group(pev->target, &pev->group); | ||
2749 | if (ret != 0) { | 2773 | if (ret != 0) { |
2750 | pr_warning("Failed to make a group name.\n"); | 2774 | pr_warning("Failed to make a group name.\n"); |
2751 | return ret; | 2775 | return ret; |
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index e54e7b011577..5a27eb4fad05 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h | |||
@@ -120,7 +120,7 @@ int parse_probe_trace_command(const char *cmd, struct probe_trace_event *tev); | |||
120 | /* Events to command string */ | 120 | /* Events to command string */ |
121 | char *synthesize_perf_probe_command(struct perf_probe_event *pev); | 121 | char *synthesize_perf_probe_command(struct perf_probe_event *pev); |
122 | char *synthesize_probe_trace_command(struct probe_trace_event *tev); | 122 | char *synthesize_probe_trace_command(struct probe_trace_event *tev); |
123 | int synthesize_perf_probe_arg(struct perf_probe_arg *pa, char *buf, size_t len); | 123 | char *synthesize_perf_probe_arg(struct perf_probe_arg *pa); |
124 | 124 | ||
125 | /* Check the perf_probe_event needs debuginfo */ | 125 | /* Check the perf_probe_event needs debuginfo */ |
126 | bool perf_probe_event_need_dwarf(struct perf_probe_event *pev); | 126 | bool perf_probe_event_need_dwarf(struct perf_probe_event *pev); |
@@ -154,7 +154,8 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs, | |||
154 | int show_available_funcs(const char *module, struct strfilter *filter, bool user); | 154 | int show_available_funcs(const char *module, struct strfilter *filter, bool user); |
155 | bool arch__prefers_symtab(void); | 155 | bool arch__prefers_symtab(void); |
156 | void arch__fix_tev_from_maps(struct perf_probe_event *pev, | 156 | void arch__fix_tev_from_maps(struct perf_probe_event *pev, |
157 | struct probe_trace_event *tev, struct map *map); | 157 | struct probe_trace_event *tev, struct map *map, |
158 | struct symbol *sym); | ||
158 | 159 | ||
159 | /* If there is no space to write, returns -E2BIG. */ | 160 | /* If there is no space to write, returns -E2BIG. */ |
160 | int e_snprintf(char *str, size_t size, const char *format, ...) | 161 | int e_snprintf(char *str, size_t size, const char *format, ...) |
diff --git a/tools/perf/util/probe-file.c b/tools/perf/util/probe-file.c index e3b3b92e4458..3fe6214970e6 100644 --- a/tools/perf/util/probe-file.c +++ b/tools/perf/util/probe-file.c | |||
@@ -220,8 +220,7 @@ int probe_file__add_event(int fd, struct probe_trace_event *tev) | |||
220 | 220 | ||
221 | pr_debug("Writing event: %s\n", buf); | 221 | pr_debug("Writing event: %s\n", buf); |
222 | if (!probe_event_dry_run) { | 222 | if (!probe_event_dry_run) { |
223 | ret = write(fd, buf, strlen(buf)); | 223 | if (write(fd, buf, strlen(buf)) < (int)strlen(buf)) { |
224 | if (ret <= 0) { | ||
225 | ret = -errno; | 224 | ret = -errno; |
226 | pr_warning("Failed to write event: %s\n", | 225 | pr_warning("Failed to write event: %s\n", |
227 | strerror_r(errno, sbuf, sizeof(sbuf))); | 226 | strerror_r(errno, sbuf, sizeof(sbuf))); |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index b3bd0fba0237..1259839dbf6d 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -553,7 +553,7 @@ static int convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) | |||
553 | static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) | 553 | static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) |
554 | { | 554 | { |
555 | Dwarf_Die vr_die; | 555 | Dwarf_Die vr_die; |
556 | char buf[32], *ptr; | 556 | char *buf, *ptr; |
557 | int ret = 0; | 557 | int ret = 0; |
558 | 558 | ||
559 | /* Copy raw parameters */ | 559 | /* Copy raw parameters */ |
@@ -563,13 +563,13 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) | |||
563 | if (pf->pvar->name) | 563 | if (pf->pvar->name) |
564 | pf->tvar->name = strdup(pf->pvar->name); | 564 | pf->tvar->name = strdup(pf->pvar->name); |
565 | else { | 565 | else { |
566 | ret = synthesize_perf_probe_arg(pf->pvar, buf, 32); | 566 | buf = synthesize_perf_probe_arg(pf->pvar); |
567 | if (ret < 0) | 567 | if (!buf) |
568 | return ret; | 568 | return -ENOMEM; |
569 | ptr = strchr(buf, ':'); /* Change type separator to _ */ | 569 | ptr = strchr(buf, ':'); /* Change type separator to _ */ |
570 | if (ptr) | 570 | if (ptr) |
571 | *ptr = '_'; | 571 | *ptr = '_'; |
572 | pf->tvar->name = strdup(buf); | 572 | pf->tvar->name = buf; |
573 | } | 573 | } |
574 | if (pf->tvar->name == NULL) | 574 | if (pf->tvar->name == NULL) |
575 | return -ENOMEM; | 575 | return -ENOMEM; |
@@ -1294,6 +1294,7 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data) | |||
1294 | { | 1294 | { |
1295 | struct available_var_finder *af = data; | 1295 | struct available_var_finder *af = data; |
1296 | struct variable_list *vl; | 1296 | struct variable_list *vl; |
1297 | struct strbuf buf = STRBUF_INIT; | ||
1297 | int tag, ret; | 1298 | int tag, ret; |
1298 | 1299 | ||
1299 | vl = &af->vls[af->nvls - 1]; | 1300 | vl = &af->vls[af->nvls - 1]; |
@@ -1307,25 +1308,26 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data) | |||
1307 | if (ret == 0 || ret == -ERANGE) { | 1308 | if (ret == 0 || ret == -ERANGE) { |
1308 | int ret2; | 1309 | int ret2; |
1309 | bool externs = !af->child; | 1310 | bool externs = !af->child; |
1310 | struct strbuf buf; | ||
1311 | 1311 | ||
1312 | strbuf_init(&buf, 64); | 1312 | if (strbuf_init(&buf, 64) < 0) |
1313 | goto error; | ||
1313 | 1314 | ||
1314 | if (probe_conf.show_location_range) { | 1315 | if (probe_conf.show_location_range) { |
1315 | if (!externs) { | 1316 | if (!externs) |
1316 | if (ret) | 1317 | ret2 = strbuf_add(&buf, |
1317 | strbuf_add(&buf, "[INV]\t", 6); | 1318 | ret ? "[INV]\t" : "[VAL]\t", 6); |
1318 | else | 1319 | else |
1319 | strbuf_add(&buf, "[VAL]\t", 6); | 1320 | ret2 = strbuf_add(&buf, "[EXT]\t", 6); |
1320 | } else | 1321 | if (ret2) |
1321 | strbuf_add(&buf, "[EXT]\t", 6); | 1322 | goto error; |
1322 | } | 1323 | } |
1323 | 1324 | ||
1324 | ret2 = die_get_varname(die_mem, &buf); | 1325 | ret2 = die_get_varname(die_mem, &buf); |
1325 | 1326 | ||
1326 | if (!ret2 && probe_conf.show_location_range && | 1327 | if (!ret2 && probe_conf.show_location_range && |
1327 | !externs) { | 1328 | !externs) { |
1328 | strbuf_addch(&buf, '\t'); | 1329 | if (strbuf_addch(&buf, '\t') < 0) |
1330 | goto error; | ||
1329 | ret2 = die_get_var_range(&af->pf.sp_die, | 1331 | ret2 = die_get_var_range(&af->pf.sp_die, |
1330 | die_mem, &buf); | 1332 | die_mem, &buf); |
1331 | } | 1333 | } |
@@ -1343,6 +1345,10 @@ static int collect_variables_cb(Dwarf_Die *die_mem, void *data) | |||
1343 | return DIE_FIND_CB_CONTINUE; | 1345 | return DIE_FIND_CB_CONTINUE; |
1344 | else | 1346 | else |
1345 | return DIE_FIND_CB_SIBLING; | 1347 | return DIE_FIND_CB_SIBLING; |
1348 | error: | ||
1349 | strbuf_release(&buf); | ||
1350 | pr_debug("Error in strbuf\n"); | ||
1351 | return DIE_FIND_CB_END; | ||
1346 | } | 1352 | } |
1347 | 1353 | ||
1348 | /* Add a found vars into available variables list */ | 1354 | /* Add a found vars into available variables list */ |
diff --git a/tools/perf/util/python-ext-sources b/tools/perf/util/python-ext-sources index 8162ba0e2e57..36c6862119e3 100644 --- a/tools/perf/util/python-ext-sources +++ b/tools/perf/util/python-ext-sources | |||
@@ -23,3 +23,4 @@ util/strlist.c | |||
23 | util/trace-event.c | 23 | util/trace-event.c |
24 | ../lib/rbtree.c | 24 | ../lib/rbtree.c |
25 | util/string.c | 25 | util/string.c |
26 | util/symbol_fprintf.c | ||
diff --git a/tools/perf/util/quote.c b/tools/perf/util/quote.c index 01f03242b86a..c6d4ee2de752 100644 --- a/tools/perf/util/quote.c +++ b/tools/perf/util/quote.c | |||
@@ -17,38 +17,42 @@ static inline int need_bs_quote(char c) | |||
17 | return (c == '\'' || c == '!'); | 17 | return (c == '\'' || c == '!'); |
18 | } | 18 | } |
19 | 19 | ||
20 | static void sq_quote_buf(struct strbuf *dst, const char *src) | 20 | static int sq_quote_buf(struct strbuf *dst, const char *src) |
21 | { | 21 | { |
22 | char *to_free = NULL; | 22 | char *to_free = NULL; |
23 | int ret; | ||
23 | 24 | ||
24 | if (dst->buf == src) | 25 | if (dst->buf == src) |
25 | to_free = strbuf_detach(dst, NULL); | 26 | to_free = strbuf_detach(dst, NULL); |
26 | 27 | ||
27 | strbuf_addch(dst, '\''); | 28 | ret = strbuf_addch(dst, '\''); |
28 | while (*src) { | 29 | while (!ret && *src) { |
29 | size_t len = strcspn(src, "'!"); | 30 | size_t len = strcspn(src, "'!"); |
30 | strbuf_add(dst, src, len); | 31 | ret = strbuf_add(dst, src, len); |
31 | src += len; | 32 | src += len; |
32 | while (need_bs_quote(*src)) { | 33 | while (!ret && need_bs_quote(*src)) |
33 | strbuf_addstr(dst, "'\\"); | 34 | ret = strbuf_addf(dst, "'\\%c\'", *src++); |
34 | strbuf_addch(dst, *src++); | ||
35 | strbuf_addch(dst, '\''); | ||
36 | } | ||
37 | } | 35 | } |
38 | strbuf_addch(dst, '\''); | 36 | if (!ret) |
37 | ret = strbuf_addch(dst, '\''); | ||
39 | free(to_free); | 38 | free(to_free); |
39 | |||
40 | return ret; | ||
40 | } | 41 | } |
41 | 42 | ||
42 | void sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen) | 43 | int sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen) |
43 | { | 44 | { |
44 | int i; | 45 | int i, ret; |
45 | 46 | ||
46 | /* Copy into destination buffer. */ | 47 | /* Copy into destination buffer. */ |
47 | strbuf_grow(dst, 255); | 48 | ret = strbuf_grow(dst, 255); |
48 | for (i = 0; argv[i]; ++i) { | 49 | for (i = 0; !ret && argv[i]; ++i) { |
49 | strbuf_addch(dst, ' '); | 50 | ret = strbuf_addch(dst, ' '); |
50 | sq_quote_buf(dst, argv[i]); | 51 | if (ret) |
52 | break; | ||
53 | ret = sq_quote_buf(dst, argv[i]); | ||
51 | if (maxlen && dst->len > maxlen) | 54 | if (maxlen && dst->len > maxlen) |
52 | die("Too many or long arguments"); | 55 | die("Too many or long arguments"); |
53 | } | 56 | } |
57 | return ret; | ||
54 | } | 58 | } |
diff --git a/tools/perf/util/quote.h b/tools/perf/util/quote.h index 3340c9c4a6ca..e1ec19146fb0 100644 --- a/tools/perf/util/quote.h +++ b/tools/perf/util/quote.h | |||
@@ -24,6 +24,6 @@ | |||
24 | * sq_quote() in a real application. | 24 | * sq_quote() in a real application. |
25 | */ | 25 | */ |
26 | 26 | ||
27 | void sq_quote_argv(struct strbuf *, const char **argv, size_t maxlen); | 27 | int sq_quote_argv(struct strbuf *, const char **argv, size_t maxlen); |
28 | 28 | ||
29 | #endif /* __PERF_QUOTE_H */ | 29 | #endif /* __PERF_QUOTE_H */ |
diff --git a/tools/perf/util/rb_resort.h b/tools/perf/util/rb_resort.h new file mode 100644 index 000000000000..abc76e3d3098 --- /dev/null +++ b/tools/perf/util/rb_resort.h | |||
@@ -0,0 +1,149 @@ | |||
1 | #ifndef _PERF_RESORT_RB_H_ | ||
2 | #define _PERF_RESORT_RB_H_ | ||
3 | /* | ||
4 | * Template for creating a class to resort an existing rb_tree according to | ||
5 | * a new sort criteria, that must be present in the entries of the source | ||
6 | * rb_tree. | ||
7 | * | ||
8 | * (c) 2016 Arnaldo Carvalho de Melo <acme@redhat.com> | ||
9 | * | ||
10 | * Quick example, resorting threads by its shortname: | ||
11 | * | ||
12 | * First define the prefix (threads) to be used for the functions and data | ||
13 | * structures created, and provide an expression for the sorting, then the | ||
14 | * fields to be present in each of the entries in the new, sorted, rb_tree. | ||
15 | * | ||
16 | * The body of the init function should collect the fields, maybe | ||
17 | * pre-calculating them from multiple entries in the original 'entry' from | ||
18 | * the rb_tree used as a source for the entries to be sorted: | ||
19 | |||
20 | DEFINE_RB_RESORT_RB(threads, strcmp(a->thread->shortname, | ||
21 | b->thread->shortname) < 0, | ||
22 | struct thread *thread; | ||
23 | ) | ||
24 | { | ||
25 | entry->thread = rb_entry(nd, struct thread, rb_node); | ||
26 | } | ||
27 | |||
28 | * After this it is just a matter of instantiating it and iterating it, | ||
29 | * for a few data structures with existing rb_trees, such as 'struct machine', | ||
30 | * helpers are available to get the rb_root and the nr_entries: | ||
31 | |||
32 | DECLARE_RESORT_RB_MACHINE_THREADS(threads, machine_ptr); | ||
33 | |||
34 | * This will instantiate the new rb_tree and a cursor for it, that can be used as: | ||
35 | |||
36 | struct rb_node *nd; | ||
37 | |||
38 | resort_rb__for_each(nd, threads) { | ||
39 | struct thread *t = threads_entry; | ||
40 | printf("%s: %d\n", t->shortname, t->tid); | ||
41 | } | ||
42 | |||
43 | * Then delete it: | ||
44 | |||
45 | resort_rb__delete(threads); | ||
46 | |||
47 | * The name of the data structures and functions will have a _sorted suffix | ||
48 | * right before the method names, i.e. will look like: | ||
49 | * | ||
50 | * struct threads_sorted_entry {} | ||
51 | * threads_sorted__insert() | ||
52 | */ | ||
53 | |||
54 | #define DEFINE_RESORT_RB(__name, __comp, ...) \ | ||
55 | struct __name##_sorted_entry { \ | ||
56 | struct rb_node rb_node; \ | ||
57 | __VA_ARGS__ \ | ||
58 | }; \ | ||
59 | static void __name##_sorted__init_entry(struct rb_node *nd, \ | ||
60 | struct __name##_sorted_entry *entry); \ | ||
61 | \ | ||
62 | static int __name##_sorted__cmp(struct rb_node *nda, struct rb_node *ndb) \ | ||
63 | { \ | ||
64 | struct __name##_sorted_entry *a, *b; \ | ||
65 | a = rb_entry(nda, struct __name##_sorted_entry, rb_node); \ | ||
66 | b = rb_entry(ndb, struct __name##_sorted_entry, rb_node); \ | ||
67 | return __comp; \ | ||
68 | } \ | ||
69 | \ | ||
70 | struct __name##_sorted { \ | ||
71 | struct rb_root entries; \ | ||
72 | struct __name##_sorted_entry nd[0]; \ | ||
73 | }; \ | ||
74 | \ | ||
75 | static void __name##_sorted__insert(struct __name##_sorted *sorted, \ | ||
76 | struct rb_node *sorted_nd) \ | ||
77 | { \ | ||
78 | struct rb_node **p = &sorted->entries.rb_node, *parent = NULL; \ | ||
79 | while (*p != NULL) { \ | ||
80 | parent = *p; \ | ||
81 | if (__name##_sorted__cmp(sorted_nd, parent)) \ | ||
82 | p = &(*p)->rb_left; \ | ||
83 | else \ | ||
84 | p = &(*p)->rb_right; \ | ||
85 | } \ | ||
86 | rb_link_node(sorted_nd, parent, p); \ | ||
87 | rb_insert_color(sorted_nd, &sorted->entries); \ | ||
88 | } \ | ||
89 | \ | ||
90 | static void __name##_sorted__sort(struct __name##_sorted *sorted, \ | ||
91 | struct rb_root *entries) \ | ||
92 | { \ | ||
93 | struct rb_node *nd; \ | ||
94 | unsigned int i = 0; \ | ||
95 | for (nd = rb_first(entries); nd; nd = rb_next(nd)) { \ | ||
96 | struct __name##_sorted_entry *snd = &sorted->nd[i++]; \ | ||
97 | __name##_sorted__init_entry(nd, snd); \ | ||
98 | __name##_sorted__insert(sorted, &snd->rb_node); \ | ||
99 | } \ | ||
100 | } \ | ||
101 | \ | ||
102 | static struct __name##_sorted *__name##_sorted__new(struct rb_root *entries, \ | ||
103 | int nr_entries) \ | ||
104 | { \ | ||
105 | struct __name##_sorted *sorted; \ | ||
106 | sorted = malloc(sizeof(*sorted) + sizeof(sorted->nd[0]) * nr_entries); \ | ||
107 | if (sorted) { \ | ||
108 | sorted->entries = RB_ROOT; \ | ||
109 | __name##_sorted__sort(sorted, entries); \ | ||
110 | } \ | ||
111 | return sorted; \ | ||
112 | } \ | ||
113 | \ | ||
114 | static void __name##_sorted__delete(struct __name##_sorted *sorted) \ | ||
115 | { \ | ||
116 | free(sorted); \ | ||
117 | } \ | ||
118 | \ | ||
119 | static void __name##_sorted__init_entry(struct rb_node *nd, \ | ||
120 | struct __name##_sorted_entry *entry) | ||
121 | |||
122 | #define DECLARE_RESORT_RB(__name) \ | ||
123 | struct __name##_sorted_entry *__name##_entry; \ | ||
124 | struct __name##_sorted *__name = __name##_sorted__new | ||
125 | |||
126 | #define resort_rb__for_each(__nd, __name) \ | ||
127 | for (__nd = rb_first(&__name->entries); \ | ||
128 | __name##_entry = rb_entry(__nd, struct __name##_sorted_entry, \ | ||
129 | rb_node), __nd; \ | ||
130 | __nd = rb_next(__nd)) | ||
131 | |||
132 | #define resort_rb__delete(__name) \ | ||
133 | __name##_sorted__delete(__name), __name = NULL | ||
134 | |||
135 | /* | ||
136 | * Helpers for other classes that contains both an rbtree and the | ||
137 | * number of entries in it: | ||
138 | */ | ||
139 | |||
140 | /* For 'struct intlist' */ | ||
141 | #define DECLARE_RESORT_RB_INTLIST(__name, __ilist) \ | ||
142 | DECLARE_RESORT_RB(__name)(&__ilist->rblist.entries, \ | ||
143 | __ilist->rblist.nr_entries) | ||
144 | |||
145 | /* For 'struct machine->threads' */ | ||
146 | #define DECLARE_RESORT_RB_MACHINE_THREADS(__name, __machine) \ | ||
147 | DECLARE_RESORT_RB(__name)(&__machine->threads, __machine->nr_threads) | ||
148 | |||
149 | #endif /* _PERF_RESORT_RB_H_ */ | ||
diff --git a/tools/perf/util/record.c b/tools/perf/util/record.c index 0467367dc315..481792c7484b 100644 --- a/tools/perf/util/record.c +++ b/tools/perf/util/record.c | |||
@@ -129,7 +129,8 @@ bool perf_can_record_cpu_wide(void) | |||
129 | return true; | 129 | return true; |
130 | } | 130 | } |
131 | 131 | ||
132 | void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts) | 132 | void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, |
133 | struct callchain_param *callchain) | ||
133 | { | 134 | { |
134 | struct perf_evsel *evsel; | 135 | struct perf_evsel *evsel; |
135 | bool use_sample_identifier = false; | 136 | bool use_sample_identifier = false; |
@@ -148,7 +149,7 @@ void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts) | |||
148 | use_comm_exec = perf_can_comm_exec(); | 149 | use_comm_exec = perf_can_comm_exec(); |
149 | 150 | ||
150 | evlist__for_each(evlist, evsel) { | 151 | evlist__for_each(evlist, evsel) { |
151 | perf_evsel__config(evsel, opts); | 152 | perf_evsel__config(evsel, opts, callchain); |
152 | if (evsel->tracking && use_comm_exec) | 153 | if (evsel->tracking && use_comm_exec) |
153 | evsel->attr.comm_exec = 1; | 154 | evsel->attr.comm_exec = 1; |
154 | } | 155 | } |
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c index b3aabc0d4eb0..62c7f6988e0e 100644 --- a/tools/perf/util/scripting-engines/trace-event-perl.c +++ b/tools/perf/util/scripting-engines/trace-event-perl.c | |||
@@ -31,6 +31,8 @@ | |||
31 | #include <perl.h> | 31 | #include <perl.h> |
32 | 32 | ||
33 | #include "../../perf.h" | 33 | #include "../../perf.h" |
34 | #include "../callchain.h" | ||
35 | #include "../machine.h" | ||
34 | #include "../thread.h" | 36 | #include "../thread.h" |
35 | #include "../event.h" | 37 | #include "../event.h" |
36 | #include "../trace-event.h" | 38 | #include "../trace-event.h" |
@@ -248,10 +250,90 @@ static void define_event_symbols(struct event_format *event, | |||
248 | define_event_symbols(event, ev_name, args->next); | 250 | define_event_symbols(event, ev_name, args->next); |
249 | } | 251 | } |
250 | 252 | ||
253 | static SV *perl_process_callchain(struct perf_sample *sample, | ||
254 | struct perf_evsel *evsel, | ||
255 | struct addr_location *al) | ||
256 | { | ||
257 | AV *list; | ||
258 | |||
259 | list = newAV(); | ||
260 | if (!list) | ||
261 | goto exit; | ||
262 | |||
263 | if (!symbol_conf.use_callchain || !sample->callchain) | ||
264 | goto exit; | ||
265 | |||
266 | if (thread__resolve_callchain(al->thread, &callchain_cursor, evsel, | ||
267 | sample, NULL, NULL, | ||
268 | sysctl_perf_event_max_stack) != 0) { | ||
269 | pr_err("Failed to resolve callchain. Skipping\n"); | ||
270 | goto exit; | ||
271 | } | ||
272 | callchain_cursor_commit(&callchain_cursor); | ||
273 | |||
274 | |||
275 | while (1) { | ||
276 | HV *elem; | ||
277 | struct callchain_cursor_node *node; | ||
278 | node = callchain_cursor_current(&callchain_cursor); | ||
279 | if (!node) | ||
280 | break; | ||
281 | |||
282 | elem = newHV(); | ||
283 | if (!elem) | ||
284 | goto exit; | ||
285 | |||
286 | if (!hv_stores(elem, "ip", newSVuv(node->ip))) { | ||
287 | hv_undef(elem); | ||
288 | goto exit; | ||
289 | } | ||
290 | |||
291 | if (node->sym) { | ||
292 | HV *sym = newHV(); | ||
293 | if (!sym) { | ||
294 | hv_undef(elem); | ||
295 | goto exit; | ||
296 | } | ||
297 | if (!hv_stores(sym, "start", newSVuv(node->sym->start)) || | ||
298 | !hv_stores(sym, "end", newSVuv(node->sym->end)) || | ||
299 | !hv_stores(sym, "binding", newSVuv(node->sym->binding)) || | ||
300 | !hv_stores(sym, "name", newSVpvn(node->sym->name, | ||
301 | node->sym->namelen)) || | ||
302 | !hv_stores(elem, "sym", newRV_noinc((SV*)sym))) { | ||
303 | hv_undef(sym); | ||
304 | hv_undef(elem); | ||
305 | goto exit; | ||
306 | } | ||
307 | } | ||
308 | |||
309 | if (node->map) { | ||
310 | struct map *map = node->map; | ||
311 | const char *dsoname = "[unknown]"; | ||
312 | if (map && map->dso && (map->dso->name || map->dso->long_name)) { | ||
313 | if (symbol_conf.show_kernel_path && map->dso->long_name) | ||
314 | dsoname = map->dso->long_name; | ||
315 | else if (map->dso->name) | ||
316 | dsoname = map->dso->name; | ||
317 | } | ||
318 | if (!hv_stores(elem, "dso", newSVpv(dsoname,0))) { | ||
319 | hv_undef(elem); | ||
320 | goto exit; | ||
321 | } | ||
322 | } | ||
323 | |||
324 | callchain_cursor_advance(&callchain_cursor); | ||
325 | av_push(list, newRV_noinc((SV*)elem)); | ||
326 | } | ||
327 | |||
328 | exit: | ||
329 | return newRV_noinc((SV*)list); | ||
330 | } | ||
331 | |||
251 | static void perl_process_tracepoint(struct perf_sample *sample, | 332 | static void perl_process_tracepoint(struct perf_sample *sample, |
252 | struct perf_evsel *evsel, | 333 | struct perf_evsel *evsel, |
253 | struct thread *thread) | 334 | struct addr_location *al) |
254 | { | 335 | { |
336 | struct thread *thread = al->thread; | ||
255 | struct event_format *event = evsel->tp_format; | 337 | struct event_format *event = evsel->tp_format; |
256 | struct format_field *field; | 338 | struct format_field *field; |
257 | static char handler[256]; | 339 | static char handler[256]; |
@@ -295,6 +377,7 @@ static void perl_process_tracepoint(struct perf_sample *sample, | |||
295 | XPUSHs(sv_2mortal(newSVuv(ns))); | 377 | XPUSHs(sv_2mortal(newSVuv(ns))); |
296 | XPUSHs(sv_2mortal(newSViv(pid))); | 378 | XPUSHs(sv_2mortal(newSViv(pid))); |
297 | XPUSHs(sv_2mortal(newSVpv(comm, 0))); | 379 | XPUSHs(sv_2mortal(newSVpv(comm, 0))); |
380 | XPUSHs(sv_2mortal(perl_process_callchain(sample, evsel, al))); | ||
298 | 381 | ||
299 | /* common fields other than pid can be accessed via xsub fns */ | 382 | /* common fields other than pid can be accessed via xsub fns */ |
300 | 383 | ||
@@ -329,6 +412,7 @@ static void perl_process_tracepoint(struct perf_sample *sample, | |||
329 | XPUSHs(sv_2mortal(newSVuv(nsecs))); | 412 | XPUSHs(sv_2mortal(newSVuv(nsecs))); |
330 | XPUSHs(sv_2mortal(newSViv(pid))); | 413 | XPUSHs(sv_2mortal(newSViv(pid))); |
331 | XPUSHs(sv_2mortal(newSVpv(comm, 0))); | 414 | XPUSHs(sv_2mortal(newSVpv(comm, 0))); |
415 | XPUSHs(sv_2mortal(perl_process_callchain(sample, evsel, al))); | ||
332 | call_pv("main::trace_unhandled", G_SCALAR); | 416 | call_pv("main::trace_unhandled", G_SCALAR); |
333 | } | 417 | } |
334 | SPAGAIN; | 418 | SPAGAIN; |
@@ -366,7 +450,7 @@ static void perl_process_event(union perf_event *event, | |||
366 | struct perf_evsel *evsel, | 450 | struct perf_evsel *evsel, |
367 | struct addr_location *al) | 451 | struct addr_location *al) |
368 | { | 452 | { |
369 | perl_process_tracepoint(sample, evsel, al->thread); | 453 | perl_process_tracepoint(sample, evsel, al); |
370 | perl_process_event_generic(event, sample, evsel); | 454 | perl_process_event_generic(event, sample, evsel); |
371 | } | 455 | } |
372 | 456 | ||
@@ -490,7 +574,27 @@ static int perl_generate_script(struct pevent *pevent, const char *outfile) | |||
490 | fprintf(ofp, "use Perf::Trace::Util;\n\n"); | 574 | fprintf(ofp, "use Perf::Trace::Util;\n\n"); |
491 | 575 | ||
492 | fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n"); | 576 | fprintf(ofp, "sub trace_begin\n{\n\t# optional\n}\n\n"); |
493 | fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n\n"); | 577 | fprintf(ofp, "sub trace_end\n{\n\t# optional\n}\n"); |
578 | |||
579 | |||
580 | fprintf(ofp, "\n\ | ||
581 | sub print_backtrace\n\ | ||
582 | {\n\ | ||
583 | my $callchain = shift;\n\ | ||
584 | for my $node (@$callchain)\n\ | ||
585 | {\n\ | ||
586 | if(exists $node->{sym})\n\ | ||
587 | {\n\ | ||
588 | printf( \"\\t[\\%%x] \\%%s\\n\", $node->{ip}, $node->{sym}{name});\n\ | ||
589 | }\n\ | ||
590 | else\n\ | ||
591 | {\n\ | ||
592 | printf( \"\\t[\\%%x]\\n\", $node{ip});\n\ | ||
593 | }\n\ | ||
594 | }\n\ | ||
595 | }\n\n\ | ||
596 | "); | ||
597 | |||
494 | 598 | ||
495 | while ((event = trace_find_next_event(pevent, event))) { | 599 | while ((event = trace_find_next_event(pevent, event))) { |
496 | fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name); | 600 | fprintf(ofp, "sub %s::%s\n{\n", event->system, event->name); |
@@ -502,7 +606,8 @@ static int perl_generate_script(struct pevent *pevent, const char *outfile) | |||
502 | fprintf(ofp, "$common_secs, "); | 606 | fprintf(ofp, "$common_secs, "); |
503 | fprintf(ofp, "$common_nsecs,\n"); | 607 | fprintf(ofp, "$common_nsecs,\n"); |
504 | fprintf(ofp, "\t $common_pid, "); | 608 | fprintf(ofp, "\t $common_pid, "); |
505 | fprintf(ofp, "$common_comm,\n\t "); | 609 | fprintf(ofp, "$common_comm, "); |
610 | fprintf(ofp, "$common_callchain,\n\t "); | ||
506 | 611 | ||
507 | not_first = 0; | 612 | not_first = 0; |
508 | count = 0; | 613 | count = 0; |
@@ -519,7 +624,7 @@ static int perl_generate_script(struct pevent *pevent, const char *outfile) | |||
519 | 624 | ||
520 | fprintf(ofp, "\tprint_header($event_name, $common_cpu, " | 625 | fprintf(ofp, "\tprint_header($event_name, $common_cpu, " |
521 | "$common_secs, $common_nsecs,\n\t " | 626 | "$common_secs, $common_nsecs,\n\t " |
522 | "$common_pid, $common_comm);\n\n"); | 627 | "$common_pid, $common_comm, $common_callchain);\n\n"); |
523 | 628 | ||
524 | fprintf(ofp, "\tprintf(\""); | 629 | fprintf(ofp, "\tprintf(\""); |
525 | 630 | ||
@@ -581,17 +686,22 @@ static int perl_generate_script(struct pevent *pevent, const char *outfile) | |||
581 | fprintf(ofp, "$%s", f->name); | 686 | fprintf(ofp, "$%s", f->name); |
582 | } | 687 | } |
583 | 688 | ||
584 | fprintf(ofp, ");\n"); | 689 | fprintf(ofp, ");\n\n"); |
690 | |||
691 | fprintf(ofp, "\tprint_backtrace($common_callchain);\n"); | ||
692 | |||
585 | fprintf(ofp, "}\n\n"); | 693 | fprintf(ofp, "}\n\n"); |
586 | } | 694 | } |
587 | 695 | ||
588 | fprintf(ofp, "sub trace_unhandled\n{\n\tmy ($event_name, $context, " | 696 | fprintf(ofp, "sub trace_unhandled\n{\n\tmy ($event_name, $context, " |
589 | "$common_cpu, $common_secs, $common_nsecs,\n\t " | 697 | "$common_cpu, $common_secs, $common_nsecs,\n\t " |
590 | "$common_pid, $common_comm) = @_;\n\n"); | 698 | "$common_pid, $common_comm, $common_callchain) = @_;\n\n"); |
591 | 699 | ||
592 | fprintf(ofp, "\tprint_header($event_name, $common_cpu, " | 700 | fprintf(ofp, "\tprint_header($event_name, $common_cpu, " |
593 | "$common_secs, $common_nsecs,\n\t $common_pid, " | 701 | "$common_secs, $common_nsecs,\n\t $common_pid, " |
594 | "$common_comm);\n}\n\n"); | 702 | "$common_comm, $common_callchain);\n"); |
703 | fprintf(ofp, "\tprint_backtrace($common_callchain);\n"); | ||
704 | fprintf(ofp, "}\n\n"); | ||
595 | 705 | ||
596 | fprintf(ofp, "sub print_header\n{\n" | 706 | fprintf(ofp, "sub print_header\n{\n" |
597 | "\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n" | 707 | "\tmy ($event_name, $cpu, $secs, $nsecs, $pid, $comm) = @_;\n\n" |
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index fbd05242b4e5..ff134700bf30 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c | |||
@@ -41,6 +41,7 @@ | |||
41 | #include "../thread-stack.h" | 41 | #include "../thread-stack.h" |
42 | #include "../trace-event.h" | 42 | #include "../trace-event.h" |
43 | #include "../machine.h" | 43 | #include "../machine.h" |
44 | #include "../call-path.h" | ||
44 | #include "thread_map.h" | 45 | #include "thread_map.h" |
45 | #include "cpumap.h" | 46 | #include "cpumap.h" |
46 | #include "stat.h" | 47 | #include "stat.h" |
@@ -323,7 +324,7 @@ static PyObject *python_process_callchain(struct perf_sample *sample, | |||
323 | if (!symbol_conf.use_callchain || !sample->callchain) | 324 | if (!symbol_conf.use_callchain || !sample->callchain) |
324 | goto exit; | 325 | goto exit; |
325 | 326 | ||
326 | if (thread__resolve_callchain(al->thread, evsel, | 327 | if (thread__resolve_callchain(al->thread, &callchain_cursor, evsel, |
327 | sample, NULL, NULL, | 328 | sample, NULL, NULL, |
328 | scripting_max_stack) != 0) { | 329 | scripting_max_stack) != 0) { |
329 | pr_err("Failed to resolve callchain. Skipping\n"); | 330 | pr_err("Failed to resolve callchain. Skipping\n"); |
@@ -407,8 +408,11 @@ static void python_process_tracepoint(struct perf_sample *sample, | |||
407 | if (!t) | 408 | if (!t) |
408 | Py_FatalError("couldn't create Python tuple"); | 409 | Py_FatalError("couldn't create Python tuple"); |
409 | 410 | ||
410 | if (!event) | 411 | if (!event) { |
411 | die("ug! no event found for type %d", (int)evsel->attr.config); | 412 | snprintf(handler_name, sizeof(handler_name), |
413 | "ug! no event found for type %" PRIu64, (u64)evsel->attr.config); | ||
414 | Py_FatalError(handler_name); | ||
415 | } | ||
412 | 416 | ||
413 | pid = raw_field_value(event, "common_pid", data); | 417 | pid = raw_field_value(event, "common_pid", data); |
414 | 418 | ||
@@ -614,7 +618,7 @@ static int python_export_dso(struct db_export *dbe, struct dso *dso, | |||
614 | struct machine *machine) | 618 | struct machine *machine) |
615 | { | 619 | { |
616 | struct tables *tables = container_of(dbe, struct tables, dbe); | 620 | struct tables *tables = container_of(dbe, struct tables, dbe); |
617 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | 621 | char sbuild_id[SBUILD_ID_SIZE]; |
618 | PyObject *t; | 622 | PyObject *t; |
619 | 623 | ||
620 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); | 624 | build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id); |
@@ -681,7 +685,7 @@ static int python_export_sample(struct db_export *dbe, | |||
681 | struct tables *tables = container_of(dbe, struct tables, dbe); | 685 | struct tables *tables = container_of(dbe, struct tables, dbe); |
682 | PyObject *t; | 686 | PyObject *t; |
683 | 687 | ||
684 | t = tuple_new(21); | 688 | t = tuple_new(22); |
685 | 689 | ||
686 | tuple_set_u64(t, 0, es->db_id); | 690 | tuple_set_u64(t, 0, es->db_id); |
687 | tuple_set_u64(t, 1, es->evsel->db_id); | 691 | tuple_set_u64(t, 1, es->evsel->db_id); |
@@ -704,6 +708,7 @@ static int python_export_sample(struct db_export *dbe, | |||
704 | tuple_set_u64(t, 18, es->sample->data_src); | 708 | tuple_set_u64(t, 18, es->sample->data_src); |
705 | tuple_set_s32(t, 19, es->sample->flags & PERF_BRANCH_MASK); | 709 | tuple_set_s32(t, 19, es->sample->flags & PERF_BRANCH_MASK); |
706 | tuple_set_s32(t, 20, !!(es->sample->flags & PERF_IP_FLAG_IN_TX)); | 710 | tuple_set_s32(t, 20, !!(es->sample->flags & PERF_IP_FLAG_IN_TX)); |
711 | tuple_set_u64(t, 21, es->call_path_id); | ||
707 | 712 | ||
708 | call_object(tables->sample_handler, t, "sample_table"); | 713 | call_object(tables->sample_handler, t, "sample_table"); |
709 | 714 | ||
@@ -998,8 +1003,10 @@ static void set_table_handlers(struct tables *tables) | |||
998 | { | 1003 | { |
999 | const char *perf_db_export_mode = "perf_db_export_mode"; | 1004 | const char *perf_db_export_mode = "perf_db_export_mode"; |
1000 | const char *perf_db_export_calls = "perf_db_export_calls"; | 1005 | const char *perf_db_export_calls = "perf_db_export_calls"; |
1001 | PyObject *db_export_mode, *db_export_calls; | 1006 | const char *perf_db_export_callchains = "perf_db_export_callchains"; |
1007 | PyObject *db_export_mode, *db_export_calls, *db_export_callchains; | ||
1002 | bool export_calls = false; | 1008 | bool export_calls = false; |
1009 | bool export_callchains = false; | ||
1003 | int ret; | 1010 | int ret; |
1004 | 1011 | ||
1005 | memset(tables, 0, sizeof(struct tables)); | 1012 | memset(tables, 0, sizeof(struct tables)); |
@@ -1016,6 +1023,7 @@ static void set_table_handlers(struct tables *tables) | |||
1016 | if (!ret) | 1023 | if (!ret) |
1017 | return; | 1024 | return; |
1018 | 1025 | ||
1026 | /* handle export calls */ | ||
1019 | tables->dbe.crp = NULL; | 1027 | tables->dbe.crp = NULL; |
1020 | db_export_calls = PyDict_GetItemString(main_dict, perf_db_export_calls); | 1028 | db_export_calls = PyDict_GetItemString(main_dict, perf_db_export_calls); |
1021 | if (db_export_calls) { | 1029 | if (db_export_calls) { |
@@ -1033,6 +1041,33 @@ static void set_table_handlers(struct tables *tables) | |||
1033 | Py_FatalError("failed to create calls processor"); | 1041 | Py_FatalError("failed to create calls processor"); |
1034 | } | 1042 | } |
1035 | 1043 | ||
1044 | /* handle export callchains */ | ||
1045 | tables->dbe.cpr = NULL; | ||
1046 | db_export_callchains = PyDict_GetItemString(main_dict, | ||
1047 | perf_db_export_callchains); | ||
1048 | if (db_export_callchains) { | ||
1049 | ret = PyObject_IsTrue(db_export_callchains); | ||
1050 | if (ret == -1) | ||
1051 | handler_call_die(perf_db_export_callchains); | ||
1052 | export_callchains = !!ret; | ||
1053 | } | ||
1054 | |||
1055 | if (export_callchains) { | ||
1056 | /* | ||
1057 | * Attempt to use the call path root from the call return | ||
1058 | * processor, if the call return processor is in use. Otherwise, | ||
1059 | * we allocate a new call path root. This prevents exporting | ||
1060 | * duplicate call path ids when both are in use simultaniously. | ||
1061 | */ | ||
1062 | if (tables->dbe.crp) | ||
1063 | tables->dbe.cpr = tables->dbe.crp->cpr; | ||
1064 | else | ||
1065 | tables->dbe.cpr = call_path_root__new(); | ||
1066 | |||
1067 | if (!tables->dbe.cpr) | ||
1068 | Py_FatalError("failed to create call path root"); | ||
1069 | } | ||
1070 | |||
1036 | tables->db_export_mode = true; | 1071 | tables->db_export_mode = true; |
1037 | /* | 1072 | /* |
1038 | * Reserve per symbol space for symbol->db_id via symbol__priv() | 1073 | * Reserve per symbol space for symbol->db_id via symbol__priv() |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 4abd85c6346d..5214974e841a 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
@@ -409,6 +409,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool) | |||
409 | tool->stat = process_stat_stub; | 409 | tool->stat = process_stat_stub; |
410 | if (tool->stat_round == NULL) | 410 | if (tool->stat_round == NULL) |
411 | tool->stat_round = process_stat_round_stub; | 411 | tool->stat_round = process_stat_round_stub; |
412 | if (tool->time_conv == NULL) | ||
413 | tool->time_conv = process_event_op2_stub; | ||
412 | } | 414 | } |
413 | 415 | ||
414 | static void swap_sample_id_all(union perf_event *event, void *data) | 416 | static void swap_sample_id_all(union perf_event *event, void *data) |
@@ -555,7 +557,7 @@ static u8 revbyte(u8 b) | |||
555 | 557 | ||
556 | /* | 558 | /* |
557 | * XXX this is hack in attempt to carry flags bitfield | 559 | * XXX this is hack in attempt to carry flags bitfield |
558 | * throught endian village. ABI says: | 560 | * through endian village. ABI says: |
559 | * | 561 | * |
560 | * Bit-fields are allocated from right to left (least to most significant) | 562 | * Bit-fields are allocated from right to left (least to most significant) |
561 | * on little-endian implementations and from left to right (most to least | 563 | * on little-endian implementations and from left to right (most to least |
@@ -794,6 +796,7 @@ static perf_event__swap_op perf_event__swap_ops[] = { | |||
794 | [PERF_RECORD_STAT] = perf_event__stat_swap, | 796 | [PERF_RECORD_STAT] = perf_event__stat_swap, |
795 | [PERF_RECORD_STAT_ROUND] = perf_event__stat_round_swap, | 797 | [PERF_RECORD_STAT_ROUND] = perf_event__stat_round_swap, |
796 | [PERF_RECORD_EVENT_UPDATE] = perf_event__event_update_swap, | 798 | [PERF_RECORD_EVENT_UPDATE] = perf_event__event_update_swap, |
799 | [PERF_RECORD_TIME_CONV] = perf_event__all64_swap, | ||
797 | [PERF_RECORD_HEADER_MAX] = NULL, | 800 | [PERF_RECORD_HEADER_MAX] = NULL, |
798 | }; | 801 | }; |
799 | 802 | ||
@@ -904,7 +907,7 @@ static void callchain__printf(struct perf_evsel *evsel, | |||
904 | unsigned int i; | 907 | unsigned int i; |
905 | struct ip_callchain *callchain = sample->callchain; | 908 | struct ip_callchain *callchain = sample->callchain; |
906 | 909 | ||
907 | if (has_branch_callstack(evsel)) | 910 | if (perf_evsel__has_branch_callstack(evsel)) |
908 | callchain__lbr_callstack_printf(sample); | 911 | callchain__lbr_callstack_printf(sample); |
909 | 912 | ||
910 | printf("... FP chain: nr:%" PRIu64 "\n", callchain->nr); | 913 | printf("... FP chain: nr:%" PRIu64 "\n", callchain->nr); |
@@ -1078,7 +1081,7 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event, | |||
1078 | if (sample_type & PERF_SAMPLE_CALLCHAIN) | 1081 | if (sample_type & PERF_SAMPLE_CALLCHAIN) |
1079 | callchain__printf(evsel, sample); | 1082 | callchain__printf(evsel, sample); |
1080 | 1083 | ||
1081 | if ((sample_type & PERF_SAMPLE_BRANCH_STACK) && !has_branch_callstack(evsel)) | 1084 | if ((sample_type & PERF_SAMPLE_BRANCH_STACK) && !perf_evsel__has_branch_callstack(evsel)) |
1082 | branch_stack__printf(sample); | 1085 | branch_stack__printf(sample); |
1083 | 1086 | ||
1084 | if (sample_type & PERF_SAMPLE_REGS_USER) | 1087 | if (sample_type & PERF_SAMPLE_REGS_USER) |
@@ -1341,6 +1344,9 @@ static s64 perf_session__process_user_event(struct perf_session *session, | |||
1341 | return tool->stat(tool, event, session); | 1344 | return tool->stat(tool, event, session); |
1342 | case PERF_RECORD_STAT_ROUND: | 1345 | case PERF_RECORD_STAT_ROUND: |
1343 | return tool->stat_round(tool, event, session); | 1346 | return tool->stat_round(tool, event, session); |
1347 | case PERF_RECORD_TIME_CONV: | ||
1348 | session->time_conv = event->time_conv; | ||
1349 | return tool->time_conv(tool, event, session); | ||
1344 | default: | 1350 | default: |
1345 | return -EINVAL; | 1351 | return -EINVAL; |
1346 | } | 1352 | } |
@@ -1830,7 +1836,11 @@ out: | |||
1830 | out_err: | 1836 | out_err: |
1831 | ui_progress__finish(); | 1837 | ui_progress__finish(); |
1832 | perf_session__warn_about_errors(session); | 1838 | perf_session__warn_about_errors(session); |
1833 | ordered_events__free(&session->ordered_events); | 1839 | /* |
1840 | * We may switching perf.data output, make ordered_events | ||
1841 | * reusable. | ||
1842 | */ | ||
1843 | ordered_events__reinit(&session->ordered_events); | ||
1834 | auxtrace__free_events(session); | 1844 | auxtrace__free_events(session); |
1835 | session->one_mmap = false; | 1845 | session->one_mmap = false; |
1836 | return err; | 1846 | return err; |
@@ -1947,105 +1957,6 @@ struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | |||
1947 | return NULL; | 1957 | return NULL; |
1948 | } | 1958 | } |
1949 | 1959 | ||
1950 | void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, | ||
1951 | struct addr_location *al, | ||
1952 | unsigned int print_opts, unsigned int stack_depth) | ||
1953 | { | ||
1954 | struct callchain_cursor_node *node; | ||
1955 | int print_ip = print_opts & PRINT_IP_OPT_IP; | ||
1956 | int print_sym = print_opts & PRINT_IP_OPT_SYM; | ||
1957 | int print_dso = print_opts & PRINT_IP_OPT_DSO; | ||
1958 | int print_symoffset = print_opts & PRINT_IP_OPT_SYMOFFSET; | ||
1959 | int print_oneline = print_opts & PRINT_IP_OPT_ONELINE; | ||
1960 | int print_srcline = print_opts & PRINT_IP_OPT_SRCLINE; | ||
1961 | char s = print_oneline ? ' ' : '\t'; | ||
1962 | |||
1963 | if (symbol_conf.use_callchain && sample->callchain) { | ||
1964 | struct addr_location node_al; | ||
1965 | |||
1966 | if (thread__resolve_callchain(al->thread, evsel, | ||
1967 | sample, NULL, NULL, | ||
1968 | stack_depth) != 0) { | ||
1969 | if (verbose) | ||
1970 | error("Failed to resolve callchain. Skipping\n"); | ||
1971 | return; | ||
1972 | } | ||
1973 | callchain_cursor_commit(&callchain_cursor); | ||
1974 | |||
1975 | if (print_symoffset) | ||
1976 | node_al = *al; | ||
1977 | |||
1978 | while (stack_depth) { | ||
1979 | u64 addr = 0; | ||
1980 | |||
1981 | node = callchain_cursor_current(&callchain_cursor); | ||
1982 | if (!node) | ||
1983 | break; | ||
1984 | |||
1985 | if (node->sym && node->sym->ignore) | ||
1986 | goto next; | ||
1987 | |||
1988 | if (print_ip) | ||
1989 | printf("%c%16" PRIx64, s, node->ip); | ||
1990 | |||
1991 | if (node->map) | ||
1992 | addr = node->map->map_ip(node->map, node->ip); | ||
1993 | |||
1994 | if (print_sym) { | ||
1995 | printf(" "); | ||
1996 | if (print_symoffset) { | ||
1997 | node_al.addr = addr; | ||
1998 | node_al.map = node->map; | ||
1999 | symbol__fprintf_symname_offs(node->sym, &node_al, stdout); | ||
2000 | } else | ||
2001 | symbol__fprintf_symname(node->sym, stdout); | ||
2002 | } | ||
2003 | |||
2004 | if (print_dso) { | ||
2005 | printf(" ("); | ||
2006 | map__fprintf_dsoname(node->map, stdout); | ||
2007 | printf(")"); | ||
2008 | } | ||
2009 | |||
2010 | if (print_srcline) | ||
2011 | map__fprintf_srcline(node->map, addr, "\n ", | ||
2012 | stdout); | ||
2013 | |||
2014 | if (!print_oneline) | ||
2015 | printf("\n"); | ||
2016 | |||
2017 | stack_depth--; | ||
2018 | next: | ||
2019 | callchain_cursor_advance(&callchain_cursor); | ||
2020 | } | ||
2021 | |||
2022 | } else { | ||
2023 | if (al->sym && al->sym->ignore) | ||
2024 | return; | ||
2025 | |||
2026 | if (print_ip) | ||
2027 | printf("%16" PRIx64, sample->ip); | ||
2028 | |||
2029 | if (print_sym) { | ||
2030 | printf(" "); | ||
2031 | if (print_symoffset) | ||
2032 | symbol__fprintf_symname_offs(al->sym, al, | ||
2033 | stdout); | ||
2034 | else | ||
2035 | symbol__fprintf_symname(al->sym, stdout); | ||
2036 | } | ||
2037 | |||
2038 | if (print_dso) { | ||
2039 | printf(" ("); | ||
2040 | map__fprintf_dsoname(al->map, stdout); | ||
2041 | printf(")"); | ||
2042 | } | ||
2043 | |||
2044 | if (print_srcline) | ||
2045 | map__fprintf_srcline(al->map, al->addr, "\n ", stdout); | ||
2046 | } | ||
2047 | } | ||
2048 | |||
2049 | int perf_session__cpu_bitmap(struct perf_session *session, | 1960 | int perf_session__cpu_bitmap(struct perf_session *session, |
2050 | const char *cpu_list, unsigned long *cpu_bitmap) | 1961 | const char *cpu_list, unsigned long *cpu_bitmap) |
2051 | { | 1962 | { |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 5f792e35d4c1..4bd758553450 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -26,6 +26,7 @@ struct perf_session { | |||
26 | struct itrace_synth_opts *itrace_synth_opts; | 26 | struct itrace_synth_opts *itrace_synth_opts; |
27 | struct list_head auxtrace_index; | 27 | struct list_head auxtrace_index; |
28 | struct trace_event tevent; | 28 | struct trace_event tevent; |
29 | struct time_conv_event time_conv; | ||
29 | bool repipe; | 30 | bool repipe; |
30 | bool one_mmap; | 31 | bool one_mmap; |
31 | void *one_mmap_addr; | 32 | void *one_mmap_addr; |
@@ -35,13 +36,6 @@ struct perf_session { | |||
35 | struct perf_tool *tool; | 36 | struct perf_tool *tool; |
36 | }; | 37 | }; |
37 | 38 | ||
38 | #define PRINT_IP_OPT_IP (1<<0) | ||
39 | #define PRINT_IP_OPT_SYM (1<<1) | ||
40 | #define PRINT_IP_OPT_DSO (1<<2) | ||
41 | #define PRINT_IP_OPT_SYMOFFSET (1<<3) | ||
42 | #define PRINT_IP_OPT_ONELINE (1<<4) | ||
43 | #define PRINT_IP_OPT_SRCLINE (1<<5) | ||
44 | |||
45 | struct perf_tool; | 39 | struct perf_tool; |
46 | 40 | ||
47 | struct perf_session *perf_session__new(struct perf_data_file *file, | 41 | struct perf_session *perf_session__new(struct perf_data_file *file, |
@@ -103,10 +97,6 @@ size_t perf_session__fprintf_nr_events(struct perf_session *session, FILE *fp); | |||
103 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | 97 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, |
104 | unsigned int type); | 98 | unsigned int type); |
105 | 99 | ||
106 | void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample, | ||
107 | struct addr_location *al, | ||
108 | unsigned int print_opts, unsigned int stack_depth); | ||
109 | |||
110 | int perf_session__cpu_bitmap(struct perf_session *session, | 100 | int perf_session__cpu_bitmap(struct perf_session *session, |
111 | const char *cpu_list, unsigned long *cpu_bitmap); | 101 | const char *cpu_list, unsigned long *cpu_bitmap); |
112 | 102 | ||
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 47966a1618c7..20e69edd5006 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -21,13 +21,6 @@ const char *sort_order; | |||
21 | const char *field_order; | 21 | const char *field_order; |
22 | regex_t ignore_callees_regex; | 22 | regex_t ignore_callees_regex; |
23 | int have_ignore_callees = 0; | 23 | int have_ignore_callees = 0; |
24 | int sort__need_collapse = 0; | ||
25 | int sort__has_parent = 0; | ||
26 | int sort__has_sym = 0; | ||
27 | int sort__has_dso = 0; | ||
28 | int sort__has_socket = 0; | ||
29 | int sort__has_thread = 0; | ||
30 | int sort__has_comm = 0; | ||
31 | enum sort_mode sort__mode = SORT_MODE__NORMAL; | 24 | enum sort_mode sort__mode = SORT_MODE__NORMAL; |
32 | 25 | ||
33 | /* | 26 | /* |
@@ -244,7 +237,7 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) | |||
244 | * comparing symbol address alone is not enough since it's a | 237 | * comparing symbol address alone is not enough since it's a |
245 | * relative address within a dso. | 238 | * relative address within a dso. |
246 | */ | 239 | */ |
247 | if (!sort__has_dso) { | 240 | if (!hists__has(left->hists, dso) || hists__has(right->hists, dso)) { |
248 | ret = sort__dso_cmp(left, right); | 241 | ret = sort__dso_cmp(left, right); |
249 | if (ret != 0) | 242 | if (ret != 0) |
250 | return ret; | 243 | return ret; |
@@ -2163,7 +2156,7 @@ static int __sort_dimension__add(struct sort_dimension *sd, | |||
2163 | return -1; | 2156 | return -1; |
2164 | 2157 | ||
2165 | if (sd->entry->se_collapse) | 2158 | if (sd->entry->se_collapse) |
2166 | sort__need_collapse = 1; | 2159 | list->need_collapse = 1; |
2167 | 2160 | ||
2168 | sd->taken = 1; | 2161 | sd->taken = 1; |
2169 | 2162 | ||
@@ -2245,9 +2238,9 @@ static int sort_dimension__add(struct perf_hpp_list *list, const char *tok, | |||
2245 | pr_err("Invalid regex: %s\n%s", parent_pattern, err); | 2238 | pr_err("Invalid regex: %s\n%s", parent_pattern, err); |
2246 | return -EINVAL; | 2239 | return -EINVAL; |
2247 | } | 2240 | } |
2248 | sort__has_parent = 1; | 2241 | list->parent = 1; |
2249 | } else if (sd->entry == &sort_sym) { | 2242 | } else if (sd->entry == &sort_sym) { |
2250 | sort__has_sym = 1; | 2243 | list->sym = 1; |
2251 | /* | 2244 | /* |
2252 | * perf diff displays the performance difference amongst | 2245 | * perf diff displays the performance difference amongst |
2253 | * two or more perf.data files. Those files could come | 2246 | * two or more perf.data files. Those files could come |
@@ -2258,13 +2251,13 @@ static int sort_dimension__add(struct perf_hpp_list *list, const char *tok, | |||
2258 | sd->entry->se_collapse = sort__sym_sort; | 2251 | sd->entry->se_collapse = sort__sym_sort; |
2259 | 2252 | ||
2260 | } else if (sd->entry == &sort_dso) { | 2253 | } else if (sd->entry == &sort_dso) { |
2261 | sort__has_dso = 1; | 2254 | list->dso = 1; |
2262 | } else if (sd->entry == &sort_socket) { | 2255 | } else if (sd->entry == &sort_socket) { |
2263 | sort__has_socket = 1; | 2256 | list->socket = 1; |
2264 | } else if (sd->entry == &sort_thread) { | 2257 | } else if (sd->entry == &sort_thread) { |
2265 | sort__has_thread = 1; | 2258 | list->thread = 1; |
2266 | } else if (sd->entry == &sort_comm) { | 2259 | } else if (sd->entry == &sort_comm) { |
2267 | sort__has_comm = 1; | 2260 | list->comm = 1; |
2268 | } | 2261 | } |
2269 | 2262 | ||
2270 | return __sort_dimension__add(sd, list, level); | 2263 | return __sort_dimension__add(sd, list, level); |
@@ -2289,7 +2282,7 @@ static int sort_dimension__add(struct perf_hpp_list *list, const char *tok, | |||
2289 | return -EINVAL; | 2282 | return -EINVAL; |
2290 | 2283 | ||
2291 | if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to) | 2284 | if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to) |
2292 | sort__has_sym = 1; | 2285 | list->sym = 1; |
2293 | 2286 | ||
2294 | __sort_dimension__add(sd, list, level); | 2287 | __sort_dimension__add(sd, list, level); |
2295 | return 0; | 2288 | return 0; |
@@ -2305,7 +2298,7 @@ static int sort_dimension__add(struct perf_hpp_list *list, const char *tok, | |||
2305 | return -EINVAL; | 2298 | return -EINVAL; |
2306 | 2299 | ||
2307 | if (sd->entry == &sort_mem_daddr_sym) | 2300 | if (sd->entry == &sort_mem_daddr_sym) |
2308 | sort__has_sym = 1; | 2301 | list->sym = 1; |
2309 | 2302 | ||
2310 | __sort_dimension__add(sd, list, level); | 2303 | __sort_dimension__add(sd, list, level); |
2311 | return 0; | 2304 | return 0; |
@@ -2445,6 +2438,9 @@ static char *prefix_if_not_in(const char *pre, char *str) | |||
2445 | 2438 | ||
2446 | static char *setup_overhead(char *keys) | 2439 | static char *setup_overhead(char *keys) |
2447 | { | 2440 | { |
2441 | if (sort__mode == SORT_MODE__DIFF) | ||
2442 | return keys; | ||
2443 | |||
2448 | keys = prefix_if_not_in("overhead", keys); | 2444 | keys = prefix_if_not_in("overhead", keys); |
2449 | 2445 | ||
2450 | if (symbol_conf.cumulate_callchain) | 2446 | if (symbol_conf.cumulate_callchain) |
@@ -2746,10 +2742,10 @@ int setup_sorting(struct perf_evlist *evlist) | |||
2746 | 2742 | ||
2747 | void reset_output_field(void) | 2743 | void reset_output_field(void) |
2748 | { | 2744 | { |
2749 | sort__need_collapse = 0; | 2745 | perf_hpp_list.need_collapse = 0; |
2750 | sort__has_parent = 0; | 2746 | perf_hpp_list.parent = 0; |
2751 | sort__has_sym = 0; | 2747 | perf_hpp_list.sym = 0; |
2752 | sort__has_dso = 0; | 2748 | perf_hpp_list.dso = 0; |
2753 | 2749 | ||
2754 | field_order = NULL; | 2750 | field_order = NULL; |
2755 | sort_order = NULL; | 2751 | sort_order = NULL; |
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 3f4e35998119..42927f448bcb 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h | |||
@@ -31,13 +31,6 @@ extern const char *parent_pattern; | |||
31 | extern const char default_sort_order[]; | 31 | extern const char default_sort_order[]; |
32 | extern regex_t ignore_callees_regex; | 32 | extern regex_t ignore_callees_regex; |
33 | extern int have_ignore_callees; | 33 | extern int have_ignore_callees; |
34 | extern int sort__need_collapse; | ||
35 | extern int sort__has_dso; | ||
36 | extern int sort__has_parent; | ||
37 | extern int sort__has_sym; | ||
38 | extern int sort__has_socket; | ||
39 | extern int sort__has_thread; | ||
40 | extern int sort__has_comm; | ||
41 | extern enum sort_mode sort__mode; | 34 | extern enum sort_mode sort__mode; |
42 | extern struct sort_entry sort_comm; | 35 | extern struct sort_entry sort_comm; |
43 | extern struct sort_entry sort_dso; | 36 | extern struct sort_entry sort_dso; |
diff --git a/tools/perf/util/stat.c b/tools/perf/util/stat.c index 4d9b481cf3b6..ffa1d0653861 100644 --- a/tools/perf/util/stat.c +++ b/tools/perf/util/stat.c | |||
@@ -307,6 +307,7 @@ int perf_stat_process_counter(struct perf_stat_config *config, | |||
307 | struct perf_counts_values *aggr = &counter->counts->aggr; | 307 | struct perf_counts_values *aggr = &counter->counts->aggr; |
308 | struct perf_stat_evsel *ps = counter->priv; | 308 | struct perf_stat_evsel *ps = counter->priv; |
309 | u64 *count = counter->counts->aggr.values; | 309 | u64 *count = counter->counts->aggr.values; |
310 | u64 val; | ||
310 | int i, ret; | 311 | int i, ret; |
311 | 312 | ||
312 | aggr->val = aggr->ena = aggr->run = 0; | 313 | aggr->val = aggr->ena = aggr->run = 0; |
@@ -346,7 +347,8 @@ int perf_stat_process_counter(struct perf_stat_config *config, | |||
346 | /* | 347 | /* |
347 | * Save the full runtime - to allow normalization during printout: | 348 | * Save the full runtime - to allow normalization during printout: |
348 | */ | 349 | */ |
349 | perf_stat__update_shadow_stats(counter, count, 0); | 350 | val = counter->scale * *count; |
351 | perf_stat__update_shadow_stats(counter, &val, 0); | ||
350 | 352 | ||
351 | return 0; | 353 | return 0; |
352 | } | 354 | } |
diff --git a/tools/perf/util/strbuf.c b/tools/perf/util/strbuf.c index 8fb73295ec34..f95f682aa2b2 100644 --- a/tools/perf/util/strbuf.c +++ b/tools/perf/util/strbuf.c | |||
@@ -1,3 +1,4 @@ | |||
1 | #include "debug.h" | ||
1 | #include "cache.h" | 2 | #include "cache.h" |
2 | #include <linux/kernel.h> | 3 | #include <linux/kernel.h> |
3 | 4 | ||
@@ -17,12 +18,13 @@ int prefixcmp(const char *str, const char *prefix) | |||
17 | */ | 18 | */ |
18 | char strbuf_slopbuf[1]; | 19 | char strbuf_slopbuf[1]; |
19 | 20 | ||
20 | void strbuf_init(struct strbuf *sb, ssize_t hint) | 21 | int strbuf_init(struct strbuf *sb, ssize_t hint) |
21 | { | 22 | { |
22 | sb->alloc = sb->len = 0; | 23 | sb->alloc = sb->len = 0; |
23 | sb->buf = strbuf_slopbuf; | 24 | sb->buf = strbuf_slopbuf; |
24 | if (hint) | 25 | if (hint) |
25 | strbuf_grow(sb, hint); | 26 | return strbuf_grow(sb, hint); |
27 | return 0; | ||
26 | } | 28 | } |
27 | 29 | ||
28 | void strbuf_release(struct strbuf *sb) | 30 | void strbuf_release(struct strbuf *sb) |
@@ -42,67 +44,104 @@ char *strbuf_detach(struct strbuf *sb, size_t *sz) | |||
42 | return res; | 44 | return res; |
43 | } | 45 | } |
44 | 46 | ||
45 | void strbuf_grow(struct strbuf *sb, size_t extra) | 47 | int strbuf_grow(struct strbuf *sb, size_t extra) |
46 | { | 48 | { |
47 | if (sb->len + extra + 1 <= sb->len) | 49 | char *buf; |
48 | die("you want to use way too much memory"); | 50 | size_t nr = sb->len + extra + 1; |
49 | if (!sb->alloc) | 51 | |
50 | sb->buf = NULL; | 52 | if (nr < sb->alloc) |
51 | ALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc); | 53 | return 0; |
54 | |||
55 | if (nr <= sb->len) | ||
56 | return -E2BIG; | ||
57 | |||
58 | if (alloc_nr(sb->alloc) > nr) | ||
59 | nr = alloc_nr(sb->alloc); | ||
60 | |||
61 | /* | ||
62 | * Note that sb->buf == strbuf_slopbuf if sb->alloc == 0, and it is | ||
63 | * a static variable. Thus we have to avoid passing it to realloc. | ||
64 | */ | ||
65 | buf = realloc(sb->alloc ? sb->buf : NULL, nr * sizeof(*buf)); | ||
66 | if (!buf) | ||
67 | return -ENOMEM; | ||
68 | |||
69 | sb->buf = buf; | ||
70 | sb->alloc = nr; | ||
71 | return 0; | ||
52 | } | 72 | } |
53 | 73 | ||
54 | void strbuf_addch(struct strbuf *sb, int c) | 74 | int strbuf_addch(struct strbuf *sb, int c) |
55 | { | 75 | { |
56 | strbuf_grow(sb, 1); | 76 | int ret = strbuf_grow(sb, 1); |
77 | if (ret) | ||
78 | return ret; | ||
79 | |||
57 | sb->buf[sb->len++] = c; | 80 | sb->buf[sb->len++] = c; |
58 | sb->buf[sb->len] = '\0'; | 81 | sb->buf[sb->len] = '\0'; |
82 | return 0; | ||
59 | } | 83 | } |
60 | 84 | ||
61 | void strbuf_add(struct strbuf *sb, const void *data, size_t len) | 85 | int strbuf_add(struct strbuf *sb, const void *data, size_t len) |
62 | { | 86 | { |
63 | strbuf_grow(sb, len); | 87 | int ret = strbuf_grow(sb, len); |
88 | if (ret) | ||
89 | return ret; | ||
90 | |||
64 | memcpy(sb->buf + sb->len, data, len); | 91 | memcpy(sb->buf + sb->len, data, len); |
65 | strbuf_setlen(sb, sb->len + len); | 92 | return strbuf_setlen(sb, sb->len + len); |
66 | } | 93 | } |
67 | 94 | ||
68 | static void strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap) | 95 | static int strbuf_addv(struct strbuf *sb, const char *fmt, va_list ap) |
69 | { | 96 | { |
70 | int len; | 97 | int len, ret; |
71 | va_list ap_saved; | 98 | va_list ap_saved; |
72 | 99 | ||
73 | if (!strbuf_avail(sb)) | 100 | if (!strbuf_avail(sb)) { |
74 | strbuf_grow(sb, 64); | 101 | ret = strbuf_grow(sb, 64); |
102 | if (ret) | ||
103 | return ret; | ||
104 | } | ||
75 | 105 | ||
76 | va_copy(ap_saved, ap); | 106 | va_copy(ap_saved, ap); |
77 | len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); | 107 | len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap); |
78 | if (len < 0) | 108 | if (len < 0) |
79 | die("your vsnprintf is broken"); | 109 | return len; |
80 | if (len > strbuf_avail(sb)) { | 110 | if (len > strbuf_avail(sb)) { |
81 | strbuf_grow(sb, len); | 111 | ret = strbuf_grow(sb, len); |
112 | if (ret) | ||
113 | return ret; | ||
82 | len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap_saved); | 114 | len = vsnprintf(sb->buf + sb->len, sb->alloc - sb->len, fmt, ap_saved); |
83 | va_end(ap_saved); | 115 | va_end(ap_saved); |
84 | if (len > strbuf_avail(sb)) { | 116 | if (len > strbuf_avail(sb)) { |
85 | die("this should not happen, your vsnprintf is broken"); | 117 | pr_debug("this should not happen, your vsnprintf is broken"); |
118 | return -EINVAL; | ||
86 | } | 119 | } |
87 | } | 120 | } |
88 | strbuf_setlen(sb, sb->len + len); | 121 | return strbuf_setlen(sb, sb->len + len); |
89 | } | 122 | } |
90 | 123 | ||
91 | void strbuf_addf(struct strbuf *sb, const char *fmt, ...) | 124 | int strbuf_addf(struct strbuf *sb, const char *fmt, ...) |
92 | { | 125 | { |
93 | va_list ap; | 126 | va_list ap; |
127 | int ret; | ||
94 | 128 | ||
95 | va_start(ap, fmt); | 129 | va_start(ap, fmt); |
96 | strbuf_addv(sb, fmt, ap); | 130 | ret = strbuf_addv(sb, fmt, ap); |
97 | va_end(ap); | 131 | va_end(ap); |
132 | return ret; | ||
98 | } | 133 | } |
99 | 134 | ||
100 | ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint) | 135 | ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint) |
101 | { | 136 | { |
102 | size_t oldlen = sb->len; | 137 | size_t oldlen = sb->len; |
103 | size_t oldalloc = sb->alloc; | 138 | size_t oldalloc = sb->alloc; |
139 | int ret; | ||
140 | |||
141 | ret = strbuf_grow(sb, hint ? hint : 8192); | ||
142 | if (ret) | ||
143 | return ret; | ||
104 | 144 | ||
105 | strbuf_grow(sb, hint ? hint : 8192); | ||
106 | for (;;) { | 145 | for (;;) { |
107 | ssize_t cnt; | 146 | ssize_t cnt; |
108 | 147 | ||
@@ -112,12 +151,14 @@ ssize_t strbuf_read(struct strbuf *sb, int fd, ssize_t hint) | |||
112 | strbuf_release(sb); | 151 | strbuf_release(sb); |
113 | else | 152 | else |
114 | strbuf_setlen(sb, oldlen); | 153 | strbuf_setlen(sb, oldlen); |
115 | return -1; | 154 | return cnt; |
116 | } | 155 | } |
117 | if (!cnt) | 156 | if (!cnt) |
118 | break; | 157 | break; |
119 | sb->len += cnt; | 158 | sb->len += cnt; |
120 | strbuf_grow(sb, 8192); | 159 | ret = strbuf_grow(sb, 8192); |
160 | if (ret) | ||
161 | return ret; | ||
121 | } | 162 | } |
122 | 163 | ||
123 | sb->buf[sb->len] = '\0'; | 164 | sb->buf[sb->len] = '\0'; |
diff --git a/tools/perf/util/strbuf.h b/tools/perf/util/strbuf.h index ab9be0fbbd40..54b409297d4a 100644 --- a/tools/perf/util/strbuf.h +++ b/tools/perf/util/strbuf.h | |||
@@ -51,7 +51,7 @@ struct strbuf { | |||
51 | #define STRBUF_INIT { 0, 0, strbuf_slopbuf } | 51 | #define STRBUF_INIT { 0, 0, strbuf_slopbuf } |
52 | 52 | ||
53 | /*----- strbuf life cycle -----*/ | 53 | /*----- strbuf life cycle -----*/ |
54 | void strbuf_init(struct strbuf *buf, ssize_t hint); | 54 | int strbuf_init(struct strbuf *buf, ssize_t hint); |
55 | void strbuf_release(struct strbuf *buf); | 55 | void strbuf_release(struct strbuf *buf); |
56 | char *strbuf_detach(struct strbuf *buf, size_t *); | 56 | char *strbuf_detach(struct strbuf *buf, size_t *); |
57 | 57 | ||
@@ -60,26 +60,31 @@ static inline ssize_t strbuf_avail(const struct strbuf *sb) { | |||
60 | return sb->alloc ? sb->alloc - sb->len - 1 : 0; | 60 | return sb->alloc ? sb->alloc - sb->len - 1 : 0; |
61 | } | 61 | } |
62 | 62 | ||
63 | void strbuf_grow(struct strbuf *buf, size_t); | 63 | int strbuf_grow(struct strbuf *buf, size_t); |
64 | 64 | ||
65 | static inline void strbuf_setlen(struct strbuf *sb, size_t len) { | 65 | static inline int strbuf_setlen(struct strbuf *sb, size_t len) { |
66 | if (!sb->alloc) | 66 | int ret; |
67 | strbuf_grow(sb, 0); | 67 | if (!sb->alloc) { |
68 | ret = strbuf_grow(sb, 0); | ||
69 | if (ret) | ||
70 | return ret; | ||
71 | } | ||
68 | assert(len < sb->alloc); | 72 | assert(len < sb->alloc); |
69 | sb->len = len; | 73 | sb->len = len; |
70 | sb->buf[len] = '\0'; | 74 | sb->buf[len] = '\0'; |
75 | return 0; | ||
71 | } | 76 | } |
72 | 77 | ||
73 | /*----- add data in your buffer -----*/ | 78 | /*----- add data in your buffer -----*/ |
74 | void strbuf_addch(struct strbuf *sb, int c); | 79 | int strbuf_addch(struct strbuf *sb, int c); |
75 | 80 | ||
76 | void strbuf_add(struct strbuf *buf, const void *, size_t); | 81 | int strbuf_add(struct strbuf *buf, const void *, size_t); |
77 | static inline void strbuf_addstr(struct strbuf *sb, const char *s) { | 82 | static inline int strbuf_addstr(struct strbuf *sb, const char *s) { |
78 | strbuf_add(sb, s, strlen(s)); | 83 | return strbuf_add(sb, s, strlen(s)); |
79 | } | 84 | } |
80 | 85 | ||
81 | __attribute__((format(printf,2,3))) | 86 | __attribute__((format(printf,2,3))) |
82 | void strbuf_addf(struct strbuf *sb, const char *fmt, ...); | 87 | int strbuf_addf(struct strbuf *sb, const char *fmt, ...); |
83 | 88 | ||
84 | /* XXX: if read fails, any partial read is undone */ | 89 | /* XXX: if read fails, any partial read is undone */ |
85 | ssize_t strbuf_read(struct strbuf *, int fd, ssize_t hint); | 90 | ssize_t strbuf_read(struct strbuf *, int fd, ssize_t hint); |
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index bc229a74c6a9..87a297dd8901 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c | |||
@@ -709,17 +709,10 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name, | |||
709 | if (ss->opdshdr.sh_type != SHT_PROGBITS) | 709 | if (ss->opdshdr.sh_type != SHT_PROGBITS) |
710 | ss->opdsec = NULL; | 710 | ss->opdsec = NULL; |
711 | 711 | ||
712 | if (dso->kernel == DSO_TYPE_USER) { | 712 | if (dso->kernel == DSO_TYPE_USER) |
713 | GElf_Shdr shdr; | 713 | ss->adjust_symbols = true; |
714 | ss->adjust_symbols = (ehdr.e_type == ET_EXEC || | 714 | else |
715 | ehdr.e_type == ET_REL || | ||
716 | dso__is_vdso(dso) || | ||
717 | elf_section_by_name(elf, &ehdr, &shdr, | ||
718 | ".gnu.prelink_undo", | ||
719 | NULL) != NULL); | ||
720 | } else { | ||
721 | ss->adjust_symbols = elf__needs_adjust_symbols(ehdr); | 715 | ss->adjust_symbols = elf__needs_adjust_symbols(ehdr); |
722 | } | ||
723 | 716 | ||
724 | ss->name = strdup(name); | 717 | ss->name = strdup(name); |
725 | if (!ss->name) { | 718 | if (!ss->name) { |
@@ -777,7 +770,8 @@ static bool want_demangle(bool is_kernel_sym) | |||
777 | return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle; | 770 | return is_kernel_sym ? symbol_conf.demangle_kernel : symbol_conf.demangle; |
778 | } | 771 | } |
779 | 772 | ||
780 | void __weak arch__elf_sym_adjust(GElf_Sym *sym __maybe_unused) { } | 773 | void __weak arch__sym_update(struct symbol *s __maybe_unused, |
774 | GElf_Sym *sym __maybe_unused) { } | ||
781 | 775 | ||
782 | int dso__load_sym(struct dso *dso, struct map *map, | 776 | int dso__load_sym(struct dso *dso, struct map *map, |
783 | struct symsrc *syms_ss, struct symsrc *runtime_ss, | 777 | struct symsrc *syms_ss, struct symsrc *runtime_ss, |
@@ -954,8 +948,6 @@ int dso__load_sym(struct dso *dso, struct map *map, | |||
954 | (sym.st_value & 1)) | 948 | (sym.st_value & 1)) |
955 | --sym.st_value; | 949 | --sym.st_value; |
956 | 950 | ||
957 | arch__elf_sym_adjust(&sym); | ||
958 | |||
959 | if (dso->kernel || kmodule) { | 951 | if (dso->kernel || kmodule) { |
960 | char dso_name[PATH_MAX]; | 952 | char dso_name[PATH_MAX]; |
961 | 953 | ||
@@ -1089,6 +1081,8 @@ new_symbol: | |||
1089 | if (!f) | 1081 | if (!f) |
1090 | goto out_elf_end; | 1082 | goto out_elf_end; |
1091 | 1083 | ||
1084 | arch__sym_update(f, &sym); | ||
1085 | |||
1092 | if (filter && filter(curr_map, f)) | 1086 | if (filter && filter(curr_map, f)) |
1093 | symbol__delete(f); | 1087 | symbol__delete(f); |
1094 | else { | 1088 | else { |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e7588dc91518..7fb33304fb4e 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -255,40 +255,6 @@ void symbol__delete(struct symbol *sym) | |||
255 | free(((void *)sym) - symbol_conf.priv_size); | 255 | free(((void *)sym) - symbol_conf.priv_size); |
256 | } | 256 | } |
257 | 257 | ||
258 | size_t symbol__fprintf(struct symbol *sym, FILE *fp) | ||
259 | { | ||
260 | return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n", | ||
261 | sym->start, sym->end, | ||
262 | sym->binding == STB_GLOBAL ? 'g' : | ||
263 | sym->binding == STB_LOCAL ? 'l' : 'w', | ||
264 | sym->name); | ||
265 | } | ||
266 | |||
267 | size_t symbol__fprintf_symname_offs(const struct symbol *sym, | ||
268 | const struct addr_location *al, FILE *fp) | ||
269 | { | ||
270 | unsigned long offset; | ||
271 | size_t length; | ||
272 | |||
273 | if (sym && sym->name) { | ||
274 | length = fprintf(fp, "%s", sym->name); | ||
275 | if (al) { | ||
276 | if (al->addr < sym->end) | ||
277 | offset = al->addr - sym->start; | ||
278 | else | ||
279 | offset = al->addr - al->map->start - sym->start; | ||
280 | length += fprintf(fp, "+0x%lx", offset); | ||
281 | } | ||
282 | return length; | ||
283 | } else | ||
284 | return fprintf(fp, "[unknown]"); | ||
285 | } | ||
286 | |||
287 | size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp) | ||
288 | { | ||
289 | return symbol__fprintf_symname_offs(sym, NULL, fp); | ||
290 | } | ||
291 | |||
292 | void symbols__delete(struct rb_root *symbols) | 258 | void symbols__delete(struct rb_root *symbols) |
293 | { | 259 | { |
294 | struct symbol *pos; | 260 | struct symbol *pos; |
@@ -335,7 +301,7 @@ static struct symbol *symbols__find(struct rb_root *symbols, u64 ip) | |||
335 | 301 | ||
336 | if (ip < s->start) | 302 | if (ip < s->start) |
337 | n = n->rb_left; | 303 | n = n->rb_left; |
338 | else if (ip >= s->end) | 304 | else if (ip > s->end || (ip == s->end && ip != s->start)) |
339 | n = n->rb_right; | 305 | n = n->rb_right; |
340 | else | 306 | else |
341 | return s; | 307 | return s; |
@@ -364,11 +330,6 @@ static struct symbol *symbols__next(struct symbol *sym) | |||
364 | return NULL; | 330 | return NULL; |
365 | } | 331 | } |
366 | 332 | ||
367 | struct symbol_name_rb_node { | ||
368 | struct rb_node rb_node; | ||
369 | struct symbol sym; | ||
370 | }; | ||
371 | |||
372 | static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym) | 333 | static void symbols__insert_by_name(struct rb_root *symbols, struct symbol *sym) |
373 | { | 334 | { |
374 | struct rb_node **p = &symbols->rb_node; | 335 | struct rb_node **p = &symbols->rb_node; |
@@ -452,6 +413,18 @@ void dso__reset_find_symbol_cache(struct dso *dso) | |||
452 | } | 413 | } |
453 | } | 414 | } |
454 | 415 | ||
416 | void dso__insert_symbol(struct dso *dso, enum map_type type, struct symbol *sym) | ||
417 | { | ||
418 | symbols__insert(&dso->symbols[type], sym); | ||
419 | |||
420 | /* update the symbol cache if necessary */ | ||
421 | if (dso->last_find_result[type].addr >= sym->start && | ||
422 | (dso->last_find_result[type].addr < sym->end || | ||
423 | sym->start == sym->end)) { | ||
424 | dso->last_find_result[type].symbol = sym; | ||
425 | } | ||
426 | } | ||
427 | |||
455 | struct symbol *dso__find_symbol(struct dso *dso, | 428 | struct symbol *dso__find_symbol(struct dso *dso, |
456 | enum map_type type, u64 addr) | 429 | enum map_type type, u64 addr) |
457 | { | 430 | { |
@@ -497,21 +470,6 @@ void dso__sort_by_name(struct dso *dso, enum map_type type) | |||
497 | &dso->symbols[type]); | 470 | &dso->symbols[type]); |
498 | } | 471 | } |
499 | 472 | ||
500 | size_t dso__fprintf_symbols_by_name(struct dso *dso, | ||
501 | enum map_type type, FILE *fp) | ||
502 | { | ||
503 | size_t ret = 0; | ||
504 | struct rb_node *nd; | ||
505 | struct symbol_name_rb_node *pos; | ||
506 | |||
507 | for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) { | ||
508 | pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); | ||
509 | fprintf(fp, "%s\n", pos->sym.name); | ||
510 | } | ||
511 | |||
512 | return ret; | ||
513 | } | ||
514 | |||
515 | int modules__parse(const char *filename, void *arg, | 473 | int modules__parse(const char *filename, void *arg, |
516 | int (*process_module)(void *arg, const char *name, | 474 | int (*process_module)(void *arg, const char *name, |
517 | u64 start)) | 475 | u64 start)) |
@@ -1262,8 +1220,8 @@ static int kallsyms__delta(struct map *map, const char *filename, u64 *delta) | |||
1262 | return 0; | 1220 | return 0; |
1263 | } | 1221 | } |
1264 | 1222 | ||
1265 | int dso__load_kallsyms(struct dso *dso, const char *filename, | 1223 | int __dso__load_kallsyms(struct dso *dso, const char *filename, |
1266 | struct map *map, symbol_filter_t filter) | 1224 | struct map *map, bool no_kcore, symbol_filter_t filter) |
1267 | { | 1225 | { |
1268 | u64 delta = 0; | 1226 | u64 delta = 0; |
1269 | 1227 | ||
@@ -1284,12 +1242,18 @@ int dso__load_kallsyms(struct dso *dso, const char *filename, | |||
1284 | else | 1242 | else |
1285 | dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS; | 1243 | dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS; |
1286 | 1244 | ||
1287 | if (!dso__load_kcore(dso, map, filename)) | 1245 | if (!no_kcore && !dso__load_kcore(dso, map, filename)) |
1288 | return dso__split_kallsyms_for_kcore(dso, map, filter); | 1246 | return dso__split_kallsyms_for_kcore(dso, map, filter); |
1289 | else | 1247 | else |
1290 | return dso__split_kallsyms(dso, map, delta, filter); | 1248 | return dso__split_kallsyms(dso, map, delta, filter); |
1291 | } | 1249 | } |
1292 | 1250 | ||
1251 | int dso__load_kallsyms(struct dso *dso, const char *filename, | ||
1252 | struct map *map, symbol_filter_t filter) | ||
1253 | { | ||
1254 | return __dso__load_kallsyms(dso, filename, map, false, filter); | ||
1255 | } | ||
1256 | |||
1293 | static int dso__load_perf_map(struct dso *dso, struct map *map, | 1257 | static int dso__load_perf_map(struct dso *dso, struct map *map, |
1294 | symbol_filter_t filter) | 1258 | symbol_filter_t filter) |
1295 | { | 1259 | { |
@@ -1644,25 +1608,27 @@ out: | |||
1644 | return err; | 1608 | return err; |
1645 | } | 1609 | } |
1646 | 1610 | ||
1611 | static bool visible_dir_filter(const char *name, struct dirent *d) | ||
1612 | { | ||
1613 | if (d->d_type != DT_DIR) | ||
1614 | return false; | ||
1615 | return lsdir_no_dot_filter(name, d); | ||
1616 | } | ||
1617 | |||
1647 | static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) | 1618 | static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) |
1648 | { | 1619 | { |
1649 | char kallsyms_filename[PATH_MAX]; | 1620 | char kallsyms_filename[PATH_MAX]; |
1650 | struct dirent *dent; | ||
1651 | int ret = -1; | 1621 | int ret = -1; |
1652 | DIR *d; | 1622 | struct strlist *dirs; |
1623 | struct str_node *nd; | ||
1653 | 1624 | ||
1654 | d = opendir(dir); | 1625 | dirs = lsdir(dir, visible_dir_filter); |
1655 | if (!d) | 1626 | if (!dirs) |
1656 | return -1; | 1627 | return -1; |
1657 | 1628 | ||
1658 | while (1) { | 1629 | strlist__for_each(nd, dirs) { |
1659 | dent = readdir(d); | ||
1660 | if (!dent) | ||
1661 | break; | ||
1662 | if (dent->d_type != DT_DIR) | ||
1663 | continue; | ||
1664 | scnprintf(kallsyms_filename, sizeof(kallsyms_filename), | 1630 | scnprintf(kallsyms_filename, sizeof(kallsyms_filename), |
1665 | "%s/%s/kallsyms", dir, dent->d_name); | 1631 | "%s/%s/kallsyms", dir, nd->s); |
1666 | if (!validate_kcore_addresses(kallsyms_filename, map)) { | 1632 | if (!validate_kcore_addresses(kallsyms_filename, map)) { |
1667 | strlcpy(dir, kallsyms_filename, dir_sz); | 1633 | strlcpy(dir, kallsyms_filename, dir_sz); |
1668 | ret = 0; | 1634 | ret = 0; |
@@ -1670,7 +1636,7 @@ static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) | |||
1670 | } | 1636 | } |
1671 | } | 1637 | } |
1672 | 1638 | ||
1673 | closedir(d); | 1639 | strlist__delete(dirs); |
1674 | 1640 | ||
1675 | return ret; | 1641 | return ret; |
1676 | } | 1642 | } |
@@ -1678,7 +1644,7 @@ static int find_matching_kcore(struct map *map, char *dir, size_t dir_sz) | |||
1678 | static char *dso__find_kallsyms(struct dso *dso, struct map *map) | 1644 | static char *dso__find_kallsyms(struct dso *dso, struct map *map) |
1679 | { | 1645 | { |
1680 | u8 host_build_id[BUILD_ID_SIZE]; | 1646 | u8 host_build_id[BUILD_ID_SIZE]; |
1681 | char sbuild_id[BUILD_ID_SIZE * 2 + 1]; | 1647 | char sbuild_id[SBUILD_ID_SIZE]; |
1682 | bool is_host = false; | 1648 | bool is_host = false; |
1683 | char path[PATH_MAX]; | 1649 | char path[PATH_MAX]; |
1684 | 1650 | ||
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index c8b7544d9267..2b5e4ed76fcb 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -55,6 +55,7 @@ struct symbol { | |||
55 | u16 namelen; | 55 | u16 namelen; |
56 | u8 binding; | 56 | u8 binding; |
57 | bool ignore; | 57 | bool ignore; |
58 | u8 arch_sym; | ||
58 | char name[0]; | 59 | char name[0]; |
59 | }; | 60 | }; |
60 | 61 | ||
@@ -140,6 +141,11 @@ struct symbol_conf { | |||
140 | 141 | ||
141 | extern struct symbol_conf symbol_conf; | 142 | extern struct symbol_conf symbol_conf; |
142 | 143 | ||
144 | struct symbol_name_rb_node { | ||
145 | struct rb_node rb_node; | ||
146 | struct symbol sym; | ||
147 | }; | ||
148 | |||
143 | static inline int __symbol__join_symfs(char *bf, size_t size, const char *path) | 149 | static inline int __symbol__join_symfs(char *bf, size_t size, const char *path) |
144 | { | 150 | { |
145 | return path__join(bf, size, symbol_conf.symfs, path); | 151 | return path__join(bf, size, symbol_conf.symfs, path); |
@@ -235,9 +241,14 @@ int dso__load_vmlinux(struct dso *dso, struct map *map, | |||
235 | symbol_filter_t filter); | 241 | symbol_filter_t filter); |
236 | int dso__load_vmlinux_path(struct dso *dso, struct map *map, | 242 | int dso__load_vmlinux_path(struct dso *dso, struct map *map, |
237 | symbol_filter_t filter); | 243 | symbol_filter_t filter); |
244 | int __dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, | ||
245 | bool no_kcore, symbol_filter_t filter); | ||
238 | int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, | 246 | int dso__load_kallsyms(struct dso *dso, const char *filename, struct map *map, |
239 | symbol_filter_t filter); | 247 | symbol_filter_t filter); |
240 | 248 | ||
249 | void dso__insert_symbol(struct dso *dso, enum map_type type, | ||
250 | struct symbol *sym); | ||
251 | |||
241 | struct symbol *dso__find_symbol(struct dso *dso, enum map_type type, | 252 | struct symbol *dso__find_symbol(struct dso *dso, enum map_type type, |
242 | u64 addr); | 253 | u64 addr); |
243 | struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, | 254 | struct symbol *dso__find_symbol_by_name(struct dso *dso, enum map_type type, |
@@ -262,8 +273,14 @@ int symbol__init(struct perf_env *env); | |||
262 | void symbol__exit(void); | 273 | void symbol__exit(void); |
263 | void symbol__elf_init(void); | 274 | void symbol__elf_init(void); |
264 | struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name); | 275 | struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name); |
276 | size_t __symbol__fprintf_symname_offs(const struct symbol *sym, | ||
277 | const struct addr_location *al, | ||
278 | bool unknown_as_addr, FILE *fp); | ||
265 | size_t symbol__fprintf_symname_offs(const struct symbol *sym, | 279 | size_t symbol__fprintf_symname_offs(const struct symbol *sym, |
266 | const struct addr_location *al, FILE *fp); | 280 | const struct addr_location *al, FILE *fp); |
281 | size_t __symbol__fprintf_symname(const struct symbol *sym, | ||
282 | const struct addr_location *al, | ||
283 | bool unknown_as_addr, FILE *fp); | ||
267 | size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp); | 284 | size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp); |
268 | size_t symbol__fprintf(struct symbol *sym, FILE *fp); | 285 | size_t symbol__fprintf(struct symbol *sym, FILE *fp); |
269 | bool symbol_type__is_a(char symbol_type, enum map_type map_type); | 286 | bool symbol_type__is_a(char symbol_type, enum map_type map_type); |
@@ -310,7 +327,7 @@ int setup_intlist(struct intlist **list, const char *list_str, | |||
310 | 327 | ||
311 | #ifdef HAVE_LIBELF_SUPPORT | 328 | #ifdef HAVE_LIBELF_SUPPORT |
312 | bool elf__needs_adjust_symbols(GElf_Ehdr ehdr); | 329 | bool elf__needs_adjust_symbols(GElf_Ehdr ehdr); |
313 | void arch__elf_sym_adjust(GElf_Sym *sym); | 330 | void arch__sym_update(struct symbol *s, GElf_Sym *sym); |
314 | #endif | 331 | #endif |
315 | 332 | ||
316 | #define SYMBOL_A 0 | 333 | #define SYMBOL_A 0 |
diff --git a/tools/perf/util/symbol_fprintf.c b/tools/perf/util/symbol_fprintf.c new file mode 100644 index 000000000000..a680bdaa65dc --- /dev/null +++ b/tools/perf/util/symbol_fprintf.c | |||
@@ -0,0 +1,71 @@ | |||
1 | #include <elf.h> | ||
2 | #include <inttypes.h> | ||
3 | #include <stdio.h> | ||
4 | |||
5 | #include "symbol.h" | ||
6 | |||
7 | size_t symbol__fprintf(struct symbol *sym, FILE *fp) | ||
8 | { | ||
9 | return fprintf(fp, " %" PRIx64 "-%" PRIx64 " %c %s\n", | ||
10 | sym->start, sym->end, | ||
11 | sym->binding == STB_GLOBAL ? 'g' : | ||
12 | sym->binding == STB_LOCAL ? 'l' : 'w', | ||
13 | sym->name); | ||
14 | } | ||
15 | |||
16 | size_t __symbol__fprintf_symname_offs(const struct symbol *sym, | ||
17 | const struct addr_location *al, | ||
18 | bool unknown_as_addr, FILE *fp) | ||
19 | { | ||
20 | unsigned long offset; | ||
21 | size_t length; | ||
22 | |||
23 | if (sym && sym->name) { | ||
24 | length = fprintf(fp, "%s", sym->name); | ||
25 | if (al) { | ||
26 | if (al->addr < sym->end) | ||
27 | offset = al->addr - sym->start; | ||
28 | else | ||
29 | offset = al->addr - al->map->start - sym->start; | ||
30 | length += fprintf(fp, "+0x%lx", offset); | ||
31 | } | ||
32 | return length; | ||
33 | } else if (al && unknown_as_addr) | ||
34 | return fprintf(fp, "[%#" PRIx64 "]", al->addr); | ||
35 | else | ||
36 | return fprintf(fp, "[unknown]"); | ||
37 | } | ||
38 | |||
39 | size_t symbol__fprintf_symname_offs(const struct symbol *sym, | ||
40 | const struct addr_location *al, | ||
41 | FILE *fp) | ||
42 | { | ||
43 | return __symbol__fprintf_symname_offs(sym, al, false, fp); | ||
44 | } | ||
45 | |||
46 | size_t __symbol__fprintf_symname(const struct symbol *sym, | ||
47 | const struct addr_location *al, | ||
48 | bool unknown_as_addr, FILE *fp) | ||
49 | { | ||
50 | return __symbol__fprintf_symname_offs(sym, al, unknown_as_addr, fp); | ||
51 | } | ||
52 | |||
53 | size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp) | ||
54 | { | ||
55 | return __symbol__fprintf_symname_offs(sym, NULL, false, fp); | ||
56 | } | ||
57 | |||
58 | size_t dso__fprintf_symbols_by_name(struct dso *dso, | ||
59 | enum map_type type, FILE *fp) | ||
60 | { | ||
61 | size_t ret = 0; | ||
62 | struct rb_node *nd; | ||
63 | struct symbol_name_rb_node *pos; | ||
64 | |||
65 | for (nd = rb_first(&dso->symbol_names[type]); nd; nd = rb_next(nd)) { | ||
66 | pos = rb_entry(nd, struct symbol_name_rb_node, rb_node); | ||
67 | fprintf(fp, "%s\n", pos->sym.name); | ||
68 | } | ||
69 | |||
70 | return ret; | ||
71 | } | ||
diff --git a/tools/perf/util/syscalltbl.c b/tools/perf/util/syscalltbl.c new file mode 100644 index 000000000000..bbb4c1957578 --- /dev/null +++ b/tools/perf/util/syscalltbl.c | |||
@@ -0,0 +1,134 @@ | |||
1 | /* | ||
2 | * System call table mapper | ||
3 | * | ||
4 | * (C) 2016 Arnaldo Carvalho de Melo <acme@redhat.com> | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify it | ||
7 | * under the terms and conditions of the GNU General Public License, | ||
8 | * version 2, as published by the Free Software Foundation. | ||
9 | * | ||
10 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
12 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
13 | * more details. | ||
14 | */ | ||
15 | |||
16 | #include "syscalltbl.h" | ||
17 | #include <stdlib.h> | ||
18 | |||
19 | #ifdef HAVE_SYSCALL_TABLE | ||
20 | #include <linux/compiler.h> | ||
21 | #include <string.h> | ||
22 | #include "util.h" | ||
23 | |||
24 | #if defined(__x86_64__) | ||
25 | #include <asm/syscalls_64.c> | ||
26 | const int syscalltbl_native_max_id = SYSCALLTBL_x86_64_MAX_ID; | ||
27 | static const char **syscalltbl_native = syscalltbl_x86_64; | ||
28 | #endif | ||
29 | |||
30 | struct syscall { | ||
31 | int id; | ||
32 | const char *name; | ||
33 | }; | ||
34 | |||
35 | static int syscallcmpname(const void *vkey, const void *ventry) | ||
36 | { | ||
37 | const char *key = vkey; | ||
38 | const struct syscall *entry = ventry; | ||
39 | |||
40 | return strcmp(key, entry->name); | ||
41 | } | ||
42 | |||
43 | static int syscallcmp(const void *va, const void *vb) | ||
44 | { | ||
45 | const struct syscall *a = va, *b = vb; | ||
46 | |||
47 | return strcmp(a->name, b->name); | ||
48 | } | ||
49 | |||
50 | static int syscalltbl__init_native(struct syscalltbl *tbl) | ||
51 | { | ||
52 | int nr_entries = 0, i, j; | ||
53 | struct syscall *entries; | ||
54 | |||
55 | for (i = 0; i <= syscalltbl_native_max_id; ++i) | ||
56 | if (syscalltbl_native[i]) | ||
57 | ++nr_entries; | ||
58 | |||
59 | entries = tbl->syscalls.entries = malloc(sizeof(struct syscall) * nr_entries); | ||
60 | if (tbl->syscalls.entries == NULL) | ||
61 | return -1; | ||
62 | |||
63 | for (i = 0, j = 0; i <= syscalltbl_native_max_id; ++i) { | ||
64 | if (syscalltbl_native[i]) { | ||
65 | entries[j].name = syscalltbl_native[i]; | ||
66 | entries[j].id = i; | ||
67 | ++j; | ||
68 | } | ||
69 | } | ||
70 | |||
71 | qsort(tbl->syscalls.entries, nr_entries, sizeof(struct syscall), syscallcmp); | ||
72 | tbl->syscalls.nr_entries = nr_entries; | ||
73 | return 0; | ||
74 | } | ||
75 | |||
76 | struct syscalltbl *syscalltbl__new(void) | ||
77 | { | ||
78 | struct syscalltbl *tbl = malloc(sizeof(*tbl)); | ||
79 | if (tbl) { | ||
80 | if (syscalltbl__init_native(tbl)) { | ||
81 | free(tbl); | ||
82 | return NULL; | ||
83 | } | ||
84 | } | ||
85 | return tbl; | ||
86 | } | ||
87 | |||
88 | void syscalltbl__delete(struct syscalltbl *tbl) | ||
89 | { | ||
90 | zfree(&tbl->syscalls.entries); | ||
91 | free(tbl); | ||
92 | } | ||
93 | |||
94 | const char *syscalltbl__name(const struct syscalltbl *tbl __maybe_unused, int id) | ||
95 | { | ||
96 | return id <= syscalltbl_native_max_id ? syscalltbl_native[id]: NULL; | ||
97 | } | ||
98 | |||
99 | int syscalltbl__id(struct syscalltbl *tbl, const char *name) | ||
100 | { | ||
101 | struct syscall *sc = bsearch(name, tbl->syscalls.entries, | ||
102 | tbl->syscalls.nr_entries, sizeof(*sc), | ||
103 | syscallcmpname); | ||
104 | |||
105 | return sc ? sc->id : -1; | ||
106 | } | ||
107 | |||
108 | #else /* HAVE_SYSCALL_TABLE */ | ||
109 | |||
110 | #include <libaudit.h> | ||
111 | |||
112 | struct syscalltbl *syscalltbl__new(void) | ||
113 | { | ||
114 | struct syscalltbl *tbl = malloc(sizeof(*tbl)); | ||
115 | if (tbl) | ||
116 | tbl->audit_machine = audit_detect_machine(); | ||
117 | return tbl; | ||
118 | } | ||
119 | |||
120 | void syscalltbl__delete(struct syscalltbl *tbl) | ||
121 | { | ||
122 | free(tbl); | ||
123 | } | ||
124 | |||
125 | const char *syscalltbl__name(const struct syscalltbl *tbl, int id) | ||
126 | { | ||
127 | return audit_syscall_to_name(id, tbl->audit_machine); | ||
128 | } | ||
129 | |||
130 | int syscalltbl__id(struct syscalltbl *tbl, const char *name) | ||
131 | { | ||
132 | return audit_name_to_syscall(name, tbl->audit_machine); | ||
133 | } | ||
134 | #endif /* HAVE_SYSCALL_TABLE */ | ||
diff --git a/tools/perf/util/syscalltbl.h b/tools/perf/util/syscalltbl.h new file mode 100644 index 000000000000..e2951510484f --- /dev/null +++ b/tools/perf/util/syscalltbl.h | |||
@@ -0,0 +1,20 @@ | |||
1 | #ifndef __PERF_SYSCALLTBL_H | ||
2 | #define __PERF_SYSCALLTBL_H | ||
3 | |||
4 | struct syscalltbl { | ||
5 | union { | ||
6 | int audit_machine; | ||
7 | struct { | ||
8 | int nr_entries; | ||
9 | void *entries; | ||
10 | } syscalls; | ||
11 | }; | ||
12 | }; | ||
13 | |||
14 | struct syscalltbl *syscalltbl__new(void); | ||
15 | void syscalltbl__delete(struct syscalltbl *tbl); | ||
16 | |||
17 | const char *syscalltbl__name(const struct syscalltbl *tbl, int id); | ||
18 | int syscalltbl__id(struct syscalltbl *tbl, const char *name); | ||
19 | |||
20 | #endif /* __PERF_SYSCALLTBL_H */ | ||
diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c index 679688e70ae7..825086aa9a08 100644 --- a/tools/perf/util/thread-stack.c +++ b/tools/perf/util/thread-stack.c | |||
@@ -22,44 +22,9 @@ | |||
22 | #include "debug.h" | 22 | #include "debug.h" |
23 | #include "symbol.h" | 23 | #include "symbol.h" |
24 | #include "comm.h" | 24 | #include "comm.h" |
25 | #include "call-path.h" | ||
25 | #include "thread-stack.h" | 26 | #include "thread-stack.h" |
26 | 27 | ||
27 | #define CALL_PATH_BLOCK_SHIFT 8 | ||
28 | #define CALL_PATH_BLOCK_SIZE (1 << CALL_PATH_BLOCK_SHIFT) | ||
29 | #define CALL_PATH_BLOCK_MASK (CALL_PATH_BLOCK_SIZE - 1) | ||
30 | |||
31 | struct call_path_block { | ||
32 | struct call_path cp[CALL_PATH_BLOCK_SIZE]; | ||
33 | struct list_head node; | ||
34 | }; | ||
35 | |||
36 | /** | ||
37 | * struct call_path_root - root of all call paths. | ||
38 | * @call_path: root call path | ||
39 | * @blocks: list of blocks to store call paths | ||
40 | * @next: next free space | ||
41 | * @sz: number of spaces | ||
42 | */ | ||
43 | struct call_path_root { | ||
44 | struct call_path call_path; | ||
45 | struct list_head blocks; | ||
46 | size_t next; | ||
47 | size_t sz; | ||
48 | }; | ||
49 | |||
50 | /** | ||
51 | * struct call_return_processor - provides a call-back to consume call-return | ||
52 | * information. | ||
53 | * @cpr: call path root | ||
54 | * @process: call-back that accepts call/return information | ||
55 | * @data: anonymous data for call-back | ||
56 | */ | ||
57 | struct call_return_processor { | ||
58 | struct call_path_root *cpr; | ||
59 | int (*process)(struct call_return *cr, void *data); | ||
60 | void *data; | ||
61 | }; | ||
62 | |||
63 | #define STACK_GROWTH 2048 | 28 | #define STACK_GROWTH 2048 |
64 | 29 | ||
65 | /** | 30 | /** |
@@ -335,108 +300,6 @@ void thread_stack__sample(struct thread *thread, struct ip_callchain *chain, | |||
335 | chain->ips[i] = thread->ts->stack[thread->ts->cnt - i].ret_addr; | 300 | chain->ips[i] = thread->ts->stack[thread->ts->cnt - i].ret_addr; |
336 | } | 301 | } |
337 | 302 | ||
338 | static void call_path__init(struct call_path *cp, struct call_path *parent, | ||
339 | struct symbol *sym, u64 ip, bool in_kernel) | ||
340 | { | ||
341 | cp->parent = parent; | ||
342 | cp->sym = sym; | ||
343 | cp->ip = sym ? 0 : ip; | ||
344 | cp->db_id = 0; | ||
345 | cp->in_kernel = in_kernel; | ||
346 | RB_CLEAR_NODE(&cp->rb_node); | ||
347 | cp->children = RB_ROOT; | ||
348 | } | ||
349 | |||
350 | static struct call_path_root *call_path_root__new(void) | ||
351 | { | ||
352 | struct call_path_root *cpr; | ||
353 | |||
354 | cpr = zalloc(sizeof(struct call_path_root)); | ||
355 | if (!cpr) | ||
356 | return NULL; | ||
357 | call_path__init(&cpr->call_path, NULL, NULL, 0, false); | ||
358 | INIT_LIST_HEAD(&cpr->blocks); | ||
359 | return cpr; | ||
360 | } | ||
361 | |||
362 | static void call_path_root__free(struct call_path_root *cpr) | ||
363 | { | ||
364 | struct call_path_block *pos, *n; | ||
365 | |||
366 | list_for_each_entry_safe(pos, n, &cpr->blocks, node) { | ||
367 | list_del(&pos->node); | ||
368 | free(pos); | ||
369 | } | ||
370 | free(cpr); | ||
371 | } | ||
372 | |||
373 | static struct call_path *call_path__new(struct call_path_root *cpr, | ||
374 | struct call_path *parent, | ||
375 | struct symbol *sym, u64 ip, | ||
376 | bool in_kernel) | ||
377 | { | ||
378 | struct call_path_block *cpb; | ||
379 | struct call_path *cp; | ||
380 | size_t n; | ||
381 | |||
382 | if (cpr->next < cpr->sz) { | ||
383 | cpb = list_last_entry(&cpr->blocks, struct call_path_block, | ||
384 | node); | ||
385 | } else { | ||
386 | cpb = zalloc(sizeof(struct call_path_block)); | ||
387 | if (!cpb) | ||
388 | return NULL; | ||
389 | list_add_tail(&cpb->node, &cpr->blocks); | ||
390 | cpr->sz += CALL_PATH_BLOCK_SIZE; | ||
391 | } | ||
392 | |||
393 | n = cpr->next++ & CALL_PATH_BLOCK_MASK; | ||
394 | cp = &cpb->cp[n]; | ||
395 | |||
396 | call_path__init(cp, parent, sym, ip, in_kernel); | ||
397 | |||
398 | return cp; | ||
399 | } | ||
400 | |||
401 | static struct call_path *call_path__findnew(struct call_path_root *cpr, | ||
402 | struct call_path *parent, | ||
403 | struct symbol *sym, u64 ip, u64 ks) | ||
404 | { | ||
405 | struct rb_node **p; | ||
406 | struct rb_node *node_parent = NULL; | ||
407 | struct call_path *cp; | ||
408 | bool in_kernel = ip >= ks; | ||
409 | |||
410 | if (sym) | ||
411 | ip = 0; | ||
412 | |||
413 | if (!parent) | ||
414 | return call_path__new(cpr, parent, sym, ip, in_kernel); | ||
415 | |||
416 | p = &parent->children.rb_node; | ||
417 | while (*p != NULL) { | ||
418 | node_parent = *p; | ||
419 | cp = rb_entry(node_parent, struct call_path, rb_node); | ||
420 | |||
421 | if (cp->sym == sym && cp->ip == ip) | ||
422 | return cp; | ||
423 | |||
424 | if (sym < cp->sym || (sym == cp->sym && ip < cp->ip)) | ||
425 | p = &(*p)->rb_left; | ||
426 | else | ||
427 | p = &(*p)->rb_right; | ||
428 | } | ||
429 | |||
430 | cp = call_path__new(cpr, parent, sym, ip, in_kernel); | ||
431 | if (!cp) | ||
432 | return NULL; | ||
433 | |||
434 | rb_link_node(&cp->rb_node, node_parent, p); | ||
435 | rb_insert_color(&cp->rb_node, &parent->children); | ||
436 | |||
437 | return cp; | ||
438 | } | ||
439 | |||
440 | struct call_return_processor * | 303 | struct call_return_processor * |
441 | call_return_processor__new(int (*process)(struct call_return *cr, void *data), | 304 | call_return_processor__new(int (*process)(struct call_return *cr, void *data), |
442 | void *data) | 305 | void *data) |
diff --git a/tools/perf/util/thread-stack.h b/tools/perf/util/thread-stack.h index e1528f1374c3..ad44c7944b8e 100644 --- a/tools/perf/util/thread-stack.h +++ b/tools/perf/util/thread-stack.h | |||
@@ -19,17 +19,16 @@ | |||
19 | #include <sys/types.h> | 19 | #include <sys/types.h> |
20 | 20 | ||
21 | #include <linux/types.h> | 21 | #include <linux/types.h> |
22 | #include <linux/rbtree.h> | ||
23 | 22 | ||
24 | struct thread; | 23 | struct thread; |
25 | struct comm; | 24 | struct comm; |
26 | struct ip_callchain; | 25 | struct ip_callchain; |
27 | struct symbol; | 26 | struct symbol; |
28 | struct dso; | 27 | struct dso; |
29 | struct call_return_processor; | ||
30 | struct comm; | 28 | struct comm; |
31 | struct perf_sample; | 29 | struct perf_sample; |
32 | struct addr_location; | 30 | struct addr_location; |
31 | struct call_path; | ||
33 | 32 | ||
34 | /* | 33 | /* |
35 | * Call/Return flags. | 34 | * Call/Return flags. |
@@ -69,26 +68,16 @@ struct call_return { | |||
69 | }; | 68 | }; |
70 | 69 | ||
71 | /** | 70 | /** |
72 | * struct call_path - node in list of calls leading to a function call. | 71 | * struct call_return_processor - provides a call-back to consume call-return |
73 | * @parent: call path to the parent function call | 72 | * information. |
74 | * @sym: symbol of function called | 73 | * @cpr: call path root |
75 | * @ip: only if sym is null, the ip of the function | 74 | * @process: call-back that accepts call/return information |
76 | * @db_id: id used for db-export | 75 | * @data: anonymous data for call-back |
77 | * @in_kernel: whether function is a in the kernel | ||
78 | * @rb_node: node in parent's tree of called functions | ||
79 | * @children: tree of call paths of functions called | ||
80 | * | ||
81 | * In combination with the call_return structure, the call_path structure | ||
82 | * defines a context-sensitve call-graph. | ||
83 | */ | 76 | */ |
84 | struct call_path { | 77 | struct call_return_processor { |
85 | struct call_path *parent; | 78 | struct call_path_root *cpr; |
86 | struct symbol *sym; | 79 | int (*process)(struct call_return *cr, void *data); |
87 | u64 ip; | 80 | void *data; |
88 | u64 db_id; | ||
89 | bool in_kernel; | ||
90 | struct rb_node rb_node; | ||
91 | struct rb_root children; | ||
92 | }; | 81 | }; |
93 | 82 | ||
94 | int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip, | 83 | int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip, |
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index dfd00c6dad6e..45fcb715a36b 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c | |||
@@ -10,6 +10,8 @@ | |||
10 | #include "comm.h" | 10 | #include "comm.h" |
11 | #include "unwind.h" | 11 | #include "unwind.h" |
12 | 12 | ||
13 | #include <api/fs/fs.h> | ||
14 | |||
13 | int thread__init_map_groups(struct thread *thread, struct machine *machine) | 15 | int thread__init_map_groups(struct thread *thread, struct machine *machine) |
14 | { | 16 | { |
15 | struct thread *leader; | 17 | struct thread *leader; |
@@ -153,6 +155,23 @@ int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp, | |||
153 | return 0; | 155 | return 0; |
154 | } | 156 | } |
155 | 157 | ||
158 | int thread__set_comm_from_proc(struct thread *thread) | ||
159 | { | ||
160 | char path[64]; | ||
161 | char *comm = NULL; | ||
162 | size_t sz; | ||
163 | int err = -1; | ||
164 | |||
165 | if (!(snprintf(path, sizeof(path), "%d/task/%d/comm", | ||
166 | thread->pid_, thread->tid) >= (int)sizeof(path)) && | ||
167 | procfs__read_str(path, &comm, &sz) == 0) { | ||
168 | comm[sz - 1] = '\0'; | ||
169 | err = thread__set_comm(thread, comm, 0); | ||
170 | } | ||
171 | |||
172 | return err; | ||
173 | } | ||
174 | |||
156 | const char *thread__comm_str(const struct thread *thread) | 175 | const char *thread__comm_str(const struct thread *thread) |
157 | { | 176 | { |
158 | const struct comm *comm = thread__comm(thread); | 177 | const struct comm *comm = thread__comm(thread); |
@@ -233,7 +252,7 @@ void thread__find_cpumode_addr_location(struct thread *thread, | |||
233 | struct addr_location *al) | 252 | struct addr_location *al) |
234 | { | 253 | { |
235 | size_t i; | 254 | size_t i; |
236 | const u8 const cpumodes[] = { | 255 | const u8 cpumodes[] = { |
237 | PERF_RECORD_MISC_USER, | 256 | PERF_RECORD_MISC_USER, |
238 | PERF_RECORD_MISC_KERNEL, | 257 | PERF_RECORD_MISC_KERNEL, |
239 | PERF_RECORD_MISC_GUEST_USER, | 258 | PERF_RECORD_MISC_GUEST_USER, |
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h index a0ac0317affb..45fba13c800b 100644 --- a/tools/perf/util/thread.h +++ b/tools/perf/util/thread.h | |||
@@ -9,6 +9,9 @@ | |||
9 | #include "symbol.h" | 9 | #include "symbol.h" |
10 | #include <strlist.h> | 10 | #include <strlist.h> |
11 | #include <intlist.h> | 11 | #include <intlist.h> |
12 | #ifdef HAVE_LIBUNWIND_SUPPORT | ||
13 | #include <libunwind.h> | ||
14 | #endif | ||
12 | 15 | ||
13 | struct thread_stack; | 16 | struct thread_stack; |
14 | 17 | ||
@@ -32,6 +35,9 @@ struct thread { | |||
32 | 35 | ||
33 | void *priv; | 36 | void *priv; |
34 | struct thread_stack *ts; | 37 | struct thread_stack *ts; |
38 | #ifdef HAVE_LIBUNWIND_SUPPORT | ||
39 | unw_addr_space_t addr_space; | ||
40 | #endif | ||
35 | }; | 41 | }; |
36 | 42 | ||
37 | struct machine; | 43 | struct machine; |
@@ -65,6 +71,8 @@ static inline int thread__set_comm(struct thread *thread, const char *comm, | |||
65 | return __thread__set_comm(thread, comm, timestamp, false); | 71 | return __thread__set_comm(thread, comm, timestamp, false); |
66 | } | 72 | } |
67 | 73 | ||
74 | int thread__set_comm_from_proc(struct thread *thread); | ||
75 | |||
68 | int thread__comm_len(struct thread *thread); | 76 | int thread__comm_len(struct thread *thread); |
69 | struct comm *thread__comm(const struct thread *thread); | 77 | struct comm *thread__comm(const struct thread *thread); |
70 | struct comm *thread__exec_comm(const struct thread *thread); | 78 | struct comm *thread__exec_comm(const struct thread *thread); |
diff --git a/tools/perf/util/thread_map.c b/tools/perf/util/thread_map.c index 08afc6909953..5654fe15e036 100644 --- a/tools/perf/util/thread_map.c +++ b/tools/perf/util/thread_map.c | |||
@@ -94,7 +94,7 @@ struct thread_map *thread_map__new_by_uid(uid_t uid) | |||
94 | DIR *proc; | 94 | DIR *proc; |
95 | int max_threads = 32, items, i; | 95 | int max_threads = 32, items, i; |
96 | char path[256]; | 96 | char path[256]; |
97 | struct dirent dirent, *next, **namelist = NULL; | 97 | struct dirent *dirent, **namelist = NULL; |
98 | struct thread_map *threads = thread_map__alloc(max_threads); | 98 | struct thread_map *threads = thread_map__alloc(max_threads); |
99 | 99 | ||
100 | if (threads == NULL) | 100 | if (threads == NULL) |
@@ -107,16 +107,16 @@ struct thread_map *thread_map__new_by_uid(uid_t uid) | |||
107 | threads->nr = 0; | 107 | threads->nr = 0; |
108 | atomic_set(&threads->refcnt, 1); | 108 | atomic_set(&threads->refcnt, 1); |
109 | 109 | ||
110 | while (!readdir_r(proc, &dirent, &next) && next) { | 110 | while ((dirent = readdir(proc)) != NULL) { |
111 | char *end; | 111 | char *end; |
112 | bool grow = false; | 112 | bool grow = false; |
113 | struct stat st; | 113 | struct stat st; |
114 | pid_t pid = strtol(dirent.d_name, &end, 10); | 114 | pid_t pid = strtol(dirent->d_name, &end, 10); |
115 | 115 | ||
116 | if (*end) /* only interested in proper numerical dirents */ | 116 | if (*end) /* only interested in proper numerical dirents */ |
117 | continue; | 117 | continue; |
118 | 118 | ||
119 | snprintf(path, sizeof(path), "/proc/%s", dirent.d_name); | 119 | snprintf(path, sizeof(path), "/proc/%s", dirent->d_name); |
120 | 120 | ||
121 | if (stat(path, &st) != 0) | 121 | if (stat(path, &st) != 0) |
122 | continue; | 122 | continue; |
@@ -260,7 +260,7 @@ struct thread_map *thread_map__new_dummy(void) | |||
260 | return threads; | 260 | return threads; |
261 | } | 261 | } |
262 | 262 | ||
263 | static struct thread_map *thread_map__new_by_tid_str(const char *tid_str) | 263 | struct thread_map *thread_map__new_by_tid_str(const char *tid_str) |
264 | { | 264 | { |
265 | struct thread_map *threads = NULL, *nt; | 265 | struct thread_map *threads = NULL, *nt; |
266 | int ntasks = 0; | 266 | int ntasks = 0; |
@@ -436,3 +436,15 @@ struct thread_map *thread_map__new_event(struct thread_map_event *event) | |||
436 | 436 | ||
437 | return threads; | 437 | return threads; |
438 | } | 438 | } |
439 | |||
440 | bool thread_map__has(struct thread_map *threads, pid_t pid) | ||
441 | { | ||
442 | int i; | ||
443 | |||
444 | for (i = 0; i < threads->nr; ++i) { | ||
445 | if (threads->map[i].pid == pid) | ||
446 | return true; | ||
447 | } | ||
448 | |||
449 | return false; | ||
450 | } | ||
diff --git a/tools/perf/util/thread_map.h b/tools/perf/util/thread_map.h index 85e4c7c4fbde..bd3b971588da 100644 --- a/tools/perf/util/thread_map.h +++ b/tools/perf/util/thread_map.h | |||
@@ -31,6 +31,8 @@ void thread_map__put(struct thread_map *map); | |||
31 | struct thread_map *thread_map__new_str(const char *pid, | 31 | struct thread_map *thread_map__new_str(const char *pid, |
32 | const char *tid, uid_t uid); | 32 | const char *tid, uid_t uid); |
33 | 33 | ||
34 | struct thread_map *thread_map__new_by_tid_str(const char *tid_str); | ||
35 | |||
34 | size_t thread_map__fprintf(struct thread_map *threads, FILE *fp); | 36 | size_t thread_map__fprintf(struct thread_map *threads, FILE *fp); |
35 | 37 | ||
36 | static inline int thread_map__nr(struct thread_map *threads) | 38 | static inline int thread_map__nr(struct thread_map *threads) |
@@ -55,4 +57,5 @@ static inline char *thread_map__comm(struct thread_map *map, int thread) | |||
55 | } | 57 | } |
56 | 58 | ||
57 | void thread_map__read_comms(struct thread_map *threads); | 59 | void thread_map__read_comms(struct thread_map *threads); |
60 | bool thread_map__has(struct thread_map *threads, pid_t pid); | ||
58 | #endif /* __PERF_THREAD_MAP_H */ | 61 | #endif /* __PERF_THREAD_MAP_H */ |
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h index 55de4cffcd4e..ac2590a3de2d 100644 --- a/tools/perf/util/tool.h +++ b/tools/perf/util/tool.h | |||
@@ -57,6 +57,7 @@ struct perf_tool { | |||
57 | id_index, | 57 | id_index, |
58 | auxtrace_info, | 58 | auxtrace_info, |
59 | auxtrace_error, | 59 | auxtrace_error, |
60 | time_conv, | ||
60 | thread_map, | 61 | thread_map, |
61 | cpu_map, | 62 | cpu_map, |
62 | stat_config, | 63 | stat_config, |
diff --git a/tools/perf/util/trigger.h b/tools/perf/util/trigger.h new file mode 100644 index 000000000000..e97d7016d771 --- /dev/null +++ b/tools/perf/util/trigger.h | |||
@@ -0,0 +1,94 @@ | |||
1 | #ifndef __TRIGGER_H_ | ||
2 | #define __TRIGGER_H_ 1 | ||
3 | |||
4 | #include "util/debug.h" | ||
5 | #include "asm/bug.h" | ||
6 | |||
7 | /* | ||
8 | * Use trigger to model operations which need to be executed when | ||
9 | * an event (a signal, for example) is observed. | ||
10 | * | ||
11 | * States and transits: | ||
12 | * | ||
13 | * | ||
14 | * OFF--(on)--> READY --(hit)--> HIT | ||
15 | * ^ | | ||
16 | * | (ready) | ||
17 | * | | | ||
18 | * \_____________/ | ||
19 | * | ||
20 | * is_hit and is_ready are two key functions to query the state of | ||
21 | * a trigger. is_hit means the event already happen; is_ready means the | ||
22 | * trigger is waiting for the event. | ||
23 | */ | ||
24 | |||
25 | struct trigger { | ||
26 | volatile enum { | ||
27 | TRIGGER_ERROR = -2, | ||
28 | TRIGGER_OFF = -1, | ||
29 | TRIGGER_READY = 0, | ||
30 | TRIGGER_HIT = 1, | ||
31 | } state; | ||
32 | const char *name; | ||
33 | }; | ||
34 | |||
35 | #define TRIGGER_WARN_ONCE(t, exp) \ | ||
36 | WARN_ONCE(t->state != exp, "trigger '%s' state transist error: %d in %s()\n", \ | ||
37 | t->name, t->state, __func__) | ||
38 | |||
39 | static inline bool trigger_is_available(struct trigger *t) | ||
40 | { | ||
41 | return t->state >= 0; | ||
42 | } | ||
43 | |||
44 | static inline bool trigger_is_error(struct trigger *t) | ||
45 | { | ||
46 | return t->state <= TRIGGER_ERROR; | ||
47 | } | ||
48 | |||
49 | static inline void trigger_on(struct trigger *t) | ||
50 | { | ||
51 | TRIGGER_WARN_ONCE(t, TRIGGER_OFF); | ||
52 | t->state = TRIGGER_READY; | ||
53 | } | ||
54 | |||
55 | static inline void trigger_ready(struct trigger *t) | ||
56 | { | ||
57 | if (!trigger_is_available(t)) | ||
58 | return; | ||
59 | t->state = TRIGGER_READY; | ||
60 | } | ||
61 | |||
62 | static inline void trigger_hit(struct trigger *t) | ||
63 | { | ||
64 | if (!trigger_is_available(t)) | ||
65 | return; | ||
66 | TRIGGER_WARN_ONCE(t, TRIGGER_READY); | ||
67 | t->state = TRIGGER_HIT; | ||
68 | } | ||
69 | |||
70 | static inline void trigger_off(struct trigger *t) | ||
71 | { | ||
72 | if (!trigger_is_available(t)) | ||
73 | return; | ||
74 | t->state = TRIGGER_OFF; | ||
75 | } | ||
76 | |||
77 | static inline void trigger_error(struct trigger *t) | ||
78 | { | ||
79 | t->state = TRIGGER_ERROR; | ||
80 | } | ||
81 | |||
82 | static inline bool trigger_is_ready(struct trigger *t) | ||
83 | { | ||
84 | return t->state == TRIGGER_READY; | ||
85 | } | ||
86 | |||
87 | static inline bool trigger_is_hit(struct trigger *t) | ||
88 | { | ||
89 | return t->state == TRIGGER_HIT; | ||
90 | } | ||
91 | |||
92 | #define DEFINE_TRIGGER(n) \ | ||
93 | struct trigger n = {.state = TRIGGER_OFF, .name = #n} | ||
94 | #endif | ||
diff --git a/tools/perf/util/tsc.h b/tools/perf/util/tsc.h index a8b78f1b3243..d5b11e2b85e0 100644 --- a/tools/perf/util/tsc.h +++ b/tools/perf/util/tsc.h | |||
@@ -3,10 +3,29 @@ | |||
3 | 3 | ||
4 | #include <linux/types.h> | 4 | #include <linux/types.h> |
5 | 5 | ||
6 | #include "../arch/x86/util/tsc.h" | 6 | #include "event.h" |
7 | |||
8 | struct perf_tsc_conversion { | ||
9 | u16 time_shift; | ||
10 | u32 time_mult; | ||
11 | u64 time_zero; | ||
12 | }; | ||
13 | struct perf_event_mmap_page; | ||
14 | |||
15 | int perf_read_tsc_conversion(const struct perf_event_mmap_page *pc, | ||
16 | struct perf_tsc_conversion *tc); | ||
7 | 17 | ||
8 | u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc); | 18 | u64 perf_time_to_tsc(u64 ns, struct perf_tsc_conversion *tc); |
9 | u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc); | 19 | u64 tsc_to_perf_time(u64 cyc, struct perf_tsc_conversion *tc); |
10 | u64 rdtsc(void); | 20 | u64 rdtsc(void); |
11 | 21 | ||
22 | struct perf_event_mmap_page; | ||
23 | struct perf_tool; | ||
24 | struct machine; | ||
25 | |||
26 | int perf_event__synth_time_conv(const struct perf_event_mmap_page *pc, | ||
27 | struct perf_tool *tool, | ||
28 | perf_event__handler_t process, | ||
29 | struct machine *machine); | ||
30 | |||
12 | #endif | 31 | #endif |
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c index ee7e372297e5..63687d3a344e 100644 --- a/tools/perf/util/unwind-libunwind.c +++ b/tools/perf/util/unwind-libunwind.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include "symbol.h" | 32 | #include "symbol.h" |
33 | #include "util.h" | 33 | #include "util.h" |
34 | #include "debug.h" | 34 | #include "debug.h" |
35 | #include "asm/bug.h" | ||
35 | 36 | ||
36 | extern int | 37 | extern int |
37 | UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, | 38 | UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as, |
@@ -580,43 +581,33 @@ static unw_accessors_t accessors = { | |||
580 | 581 | ||
581 | int unwind__prepare_access(struct thread *thread) | 582 | int unwind__prepare_access(struct thread *thread) |
582 | { | 583 | { |
583 | unw_addr_space_t addr_space; | ||
584 | |||
585 | if (callchain_param.record_mode != CALLCHAIN_DWARF) | 584 | if (callchain_param.record_mode != CALLCHAIN_DWARF) |
586 | return 0; | 585 | return 0; |
587 | 586 | ||
588 | addr_space = unw_create_addr_space(&accessors, 0); | 587 | thread->addr_space = unw_create_addr_space(&accessors, 0); |
589 | if (!addr_space) { | 588 | if (!thread->addr_space) { |
590 | pr_err("unwind: Can't create unwind address space.\n"); | 589 | pr_err("unwind: Can't create unwind address space.\n"); |
591 | return -ENOMEM; | 590 | return -ENOMEM; |
592 | } | 591 | } |
593 | 592 | ||
594 | unw_set_caching_policy(addr_space, UNW_CACHE_GLOBAL); | 593 | unw_set_caching_policy(thread->addr_space, UNW_CACHE_GLOBAL); |
595 | thread__set_priv(thread, addr_space); | ||
596 | |||
597 | return 0; | 594 | return 0; |
598 | } | 595 | } |
599 | 596 | ||
600 | void unwind__flush_access(struct thread *thread) | 597 | void unwind__flush_access(struct thread *thread) |
601 | { | 598 | { |
602 | unw_addr_space_t addr_space; | ||
603 | |||
604 | if (callchain_param.record_mode != CALLCHAIN_DWARF) | 599 | if (callchain_param.record_mode != CALLCHAIN_DWARF) |
605 | return; | 600 | return; |
606 | 601 | ||
607 | addr_space = thread__priv(thread); | 602 | unw_flush_cache(thread->addr_space, 0, 0); |
608 | unw_flush_cache(addr_space, 0, 0); | ||
609 | } | 603 | } |
610 | 604 | ||
611 | void unwind__finish_access(struct thread *thread) | 605 | void unwind__finish_access(struct thread *thread) |
612 | { | 606 | { |
613 | unw_addr_space_t addr_space; | ||
614 | |||
615 | if (callchain_param.record_mode != CALLCHAIN_DWARF) | 607 | if (callchain_param.record_mode != CALLCHAIN_DWARF) |
616 | return; | 608 | return; |
617 | 609 | ||
618 | addr_space = thread__priv(thread); | 610 | unw_destroy_addr_space(thread->addr_space); |
619 | unw_destroy_addr_space(addr_space); | ||
620 | } | 611 | } |
621 | 612 | ||
622 | static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, | 613 | static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, |
@@ -639,7 +630,9 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb, | |||
639 | * unwind itself. | 630 | * unwind itself. |
640 | */ | 631 | */ |
641 | if (max_stack - 1 > 0) { | 632 | if (max_stack - 1 > 0) { |
642 | addr_space = thread__priv(ui->thread); | 633 | WARN_ONCE(!ui->thread, "WARNING: ui->thread is NULL"); |
634 | addr_space = ui->thread->addr_space; | ||
635 | |||
643 | if (addr_space == NULL) | 636 | if (addr_space == NULL) |
644 | return -1; | 637 | return -1; |
645 | 638 | ||
diff --git a/tools/perf/util/util.c b/tools/perf/util/util.c index b7766c577b01..eab077ad6ca9 100644 --- a/tools/perf/util/util.c +++ b/tools/perf/util/util.c | |||
@@ -33,6 +33,8 @@ struct callchain_param callchain_param = { | |||
33 | unsigned int page_size; | 33 | unsigned int page_size; |
34 | int cacheline_size; | 34 | int cacheline_size; |
35 | 35 | ||
36 | unsigned int sysctl_perf_event_max_stack = PERF_MAX_STACK_DEPTH; | ||
37 | |||
36 | bool test_attr__enabled; | 38 | bool test_attr__enabled; |
37 | 39 | ||
38 | bool perf_host = true; | 40 | bool perf_host = true; |
@@ -117,6 +119,40 @@ int rm_rf(char *path) | |||
117 | return rmdir(path); | 119 | return rmdir(path); |
118 | } | 120 | } |
119 | 121 | ||
122 | /* A filter which removes dot files */ | ||
123 | bool lsdir_no_dot_filter(const char *name __maybe_unused, struct dirent *d) | ||
124 | { | ||
125 | return d->d_name[0] != '.'; | ||
126 | } | ||
127 | |||
128 | /* lsdir reads a directory and store it in strlist */ | ||
129 | struct strlist *lsdir(const char *name, | ||
130 | bool (*filter)(const char *, struct dirent *)) | ||
131 | { | ||
132 | struct strlist *list = NULL; | ||
133 | DIR *dir; | ||
134 | struct dirent *d; | ||
135 | |||
136 | dir = opendir(name); | ||
137 | if (!dir) | ||
138 | return NULL; | ||
139 | |||
140 | list = strlist__new(NULL, NULL); | ||
141 | if (!list) { | ||
142 | errno = ENOMEM; | ||
143 | goto out; | ||
144 | } | ||
145 | |||
146 | while ((d = readdir(dir)) != NULL) { | ||
147 | if (!filter || filter(name, d)) | ||
148 | strlist__add(list, d->d_name); | ||
149 | } | ||
150 | |||
151 | out: | ||
152 | closedir(dir); | ||
153 | return list; | ||
154 | } | ||
155 | |||
120 | static int slow_copyfile(const char *from, const char *to) | 156 | static int slow_copyfile(const char *from, const char *to) |
121 | { | 157 | { |
122 | int err = -1; | 158 | int err = -1; |
@@ -471,7 +507,6 @@ int parse_callchain_record(const char *arg, struct callchain_param *param) | |||
471 | "needed for --call-graph fp\n"); | 507 | "needed for --call-graph fp\n"); |
472 | break; | 508 | break; |
473 | 509 | ||
474 | #ifdef HAVE_DWARF_UNWIND_SUPPORT | ||
475 | /* Dwarf style */ | 510 | /* Dwarf style */ |
476 | } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { | 511 | } else if (!strncmp(name, "dwarf", sizeof("dwarf"))) { |
477 | const unsigned long default_stack_dump_size = 8192; | 512 | const unsigned long default_stack_dump_size = 8192; |
@@ -487,7 +522,6 @@ int parse_callchain_record(const char *arg, struct callchain_param *param) | |||
487 | ret = get_stack_size(tok, &size); | 522 | ret = get_stack_size(tok, &size); |
488 | param->dump_size = size; | 523 | param->dump_size = size; |
489 | } | 524 | } |
490 | #endif /* HAVE_DWARF_UNWIND_SUPPORT */ | ||
491 | } else if (!strncmp(name, "lbr", sizeof("lbr"))) { | 525 | } else if (!strncmp(name, "lbr", sizeof("lbr"))) { |
492 | if (!strtok_r(NULL, ",", &saveptr)) { | 526 | if (!strtok_r(NULL, ",", &saveptr)) { |
493 | param->record_mode = CALLCHAIN_LBR; | 527 | param->record_mode = CALLCHAIN_LBR; |
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h index 8298d607c738..7651633a8dc7 100644 --- a/tools/perf/util/util.h +++ b/tools/perf/util/util.h | |||
@@ -79,6 +79,7 @@ | |||
79 | #include <termios.h> | 79 | #include <termios.h> |
80 | #include <linux/bitops.h> | 80 | #include <linux/bitops.h> |
81 | #include <termios.h> | 81 | #include <termios.h> |
82 | #include "strlist.h" | ||
82 | 83 | ||
83 | extern const char *graph_line; | 84 | extern const char *graph_line; |
84 | extern const char *graph_dotted_line; | 85 | extern const char *graph_dotted_line; |
@@ -159,12 +160,6 @@ static inline char *gitstrchrnul(const char *s, int c) | |||
159 | } | 160 | } |
160 | #endif | 161 | #endif |
161 | 162 | ||
162 | /* | ||
163 | * Wrappers: | ||
164 | */ | ||
165 | void *xrealloc(void *ptr, size_t size) __attribute__((weak)); | ||
166 | |||
167 | |||
168 | static inline void *zalloc(size_t size) | 163 | static inline void *zalloc(size_t size) |
169 | { | 164 | { |
170 | return calloc(1, size); | 165 | return calloc(1, size); |
@@ -222,6 +217,8 @@ static inline int sane_case(int x, int high) | |||
222 | 217 | ||
223 | int mkdir_p(char *path, mode_t mode); | 218 | int mkdir_p(char *path, mode_t mode); |
224 | int rm_rf(char *path); | 219 | int rm_rf(char *path); |
220 | struct strlist *lsdir(const char *name, bool (*filter)(const char *, struct dirent *)); | ||
221 | bool lsdir_no_dot_filter(const char *name, struct dirent *d); | ||
225 | int copyfile(const char *from, const char *to); | 222 | int copyfile(const char *from, const char *to); |
226 | int copyfile_mode(const char *from, const char *to, mode_t mode); | 223 | int copyfile_mode(const char *from, const char *to, mode_t mode); |
227 | int copyfile_offset(int fromfd, loff_t from_ofs, int tofd, loff_t to_ofs, u64 size); | 224 | int copyfile_offset(int fromfd, loff_t from_ofs, int tofd, loff_t to_ofs, u64 size); |
@@ -254,11 +251,17 @@ int hex2u64(const char *ptr, u64 *val); | |||
254 | char *ltrim(char *s); | 251 | char *ltrim(char *s); |
255 | char *rtrim(char *s); | 252 | char *rtrim(char *s); |
256 | 253 | ||
254 | static inline char *trim(char *s) | ||
255 | { | ||
256 | return ltrim(rtrim(s)); | ||
257 | } | ||
258 | |||
257 | void dump_stack(void); | 259 | void dump_stack(void); |
258 | void sighandler_dump_stack(int sig); | 260 | void sighandler_dump_stack(int sig); |
259 | 261 | ||
260 | extern unsigned int page_size; | 262 | extern unsigned int page_size; |
261 | extern int cacheline_size; | 263 | extern int cacheline_size; |
264 | extern unsigned int sysctl_perf_event_max_stack; | ||
262 | 265 | ||
263 | struct parse_tag { | 266 | struct parse_tag { |
264 | char tag; | 267 | char tag; |
diff --git a/tools/perf/util/wrapper.c b/tools/perf/util/wrapper.c deleted file mode 100644 index 5f1a07c4b87b..000000000000 --- a/tools/perf/util/wrapper.c +++ /dev/null | |||
@@ -1,29 +0,0 @@ | |||
1 | /* | ||
2 | * Various trivial helper wrappers around standard functions | ||
3 | */ | ||
4 | #include "cache.h" | ||
5 | |||
6 | /* | ||
7 | * There's no pack memory to release - but stay close to the Git | ||
8 | * version so wrap this away: | ||
9 | */ | ||
10 | static inline void release_pack_memory(size_t size __maybe_unused, | ||
11 | int flag __maybe_unused) | ||
12 | { | ||
13 | } | ||
14 | |||
15 | void *xrealloc(void *ptr, size_t size) | ||
16 | { | ||
17 | void *ret = realloc(ptr, size); | ||
18 | if (!ret && !size) | ||
19 | ret = realloc(ptr, 1); | ||
20 | if (!ret) { | ||
21 | release_pack_memory(size, -1); | ||
22 | ret = realloc(ptr, size); | ||
23 | if (!ret && !size) | ||
24 | ret = realloc(ptr, 1); | ||
25 | if (!ret) | ||
26 | die("Out of memory, realloc failed"); | ||
27 | } | ||
28 | return ret; | ||
29 | } | ||
diff --git a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c index d0e6b857d8d1..546cf4a503b7 100644 --- a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c +++ b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c | |||
@@ -91,7 +91,7 @@ osl_get_customized_table(char *pathname, | |||
91 | char *signature, | 91 | char *signature, |
92 | u32 instance, | 92 | u32 instance, |
93 | struct acpi_table_header **table, | 93 | struct acpi_table_header **table, |
94 | acpi_physical_address * address); | 94 | acpi_physical_address *address); |
95 | 95 | ||
96 | static acpi_status osl_list_bios_tables(void); | 96 | static acpi_status osl_list_bios_tables(void); |
97 | 97 | ||
@@ -99,7 +99,7 @@ static acpi_status | |||
99 | osl_get_bios_table(char *signature, | 99 | osl_get_bios_table(char *signature, |
100 | u32 instance, | 100 | u32 instance, |
101 | struct acpi_table_header **table, | 101 | struct acpi_table_header **table, |
102 | acpi_physical_address * address); | 102 | acpi_physical_address *address); |
103 | 103 | ||
104 | static acpi_status osl_get_last_status(acpi_status default_status); | 104 | static acpi_status osl_get_last_status(acpi_status default_status); |
105 | 105 | ||
@@ -187,7 +187,7 @@ static acpi_status osl_get_last_status(acpi_status default_status) | |||
187 | 187 | ||
188 | acpi_status | 188 | acpi_status |
189 | acpi_os_get_table_by_address(acpi_physical_address address, | 189 | acpi_os_get_table_by_address(acpi_physical_address address, |
190 | struct acpi_table_header ** table) | 190 | struct acpi_table_header **table) |
191 | { | 191 | { |
192 | u32 table_length; | 192 | u32 table_length; |
193 | struct acpi_table_header *mapped_table; | 193 | struct acpi_table_header *mapped_table; |
@@ -252,8 +252,8 @@ exit: | |||
252 | acpi_status | 252 | acpi_status |
253 | acpi_os_get_table_by_name(char *signature, | 253 | acpi_os_get_table_by_name(char *signature, |
254 | u32 instance, | 254 | u32 instance, |
255 | struct acpi_table_header ** table, | 255 | struct acpi_table_header **table, |
256 | acpi_physical_address * address) | 256 | acpi_physical_address *address) |
257 | { | 257 | { |
258 | acpi_status status; | 258 | acpi_status status; |
259 | 259 | ||
@@ -380,8 +380,8 @@ static acpi_status osl_add_table_to_list(char *signature, u32 instance) | |||
380 | 380 | ||
381 | acpi_status | 381 | acpi_status |
382 | acpi_os_get_table_by_index(u32 index, | 382 | acpi_os_get_table_by_index(u32 index, |
383 | struct acpi_table_header ** table, | 383 | struct acpi_table_header **table, |
384 | u32 *instance, acpi_physical_address * address) | 384 | u32 *instance, acpi_physical_address *address) |
385 | { | 385 | { |
386 | struct osl_table_info *info; | 386 | struct osl_table_info *info; |
387 | acpi_status status; | 387 | acpi_status status; |
@@ -447,7 +447,7 @@ osl_find_rsdp_via_efi_by_keyword(FILE * file, const char *keyword) | |||
447 | } | 447 | } |
448 | } | 448 | } |
449 | 449 | ||
450 | return ((acpi_physical_address) (address)); | 450 | return ((acpi_physical_address)(address)); |
451 | } | 451 | } |
452 | 452 | ||
453 | /****************************************************************************** | 453 | /****************************************************************************** |
@@ -751,10 +751,10 @@ static acpi_status osl_list_bios_tables(void) | |||
751 | for (i = 0; i < number_of_tables; ++i, table_data += item_size) { | 751 | for (i = 0; i < number_of_tables; ++i, table_data += item_size) { |
752 | if (osl_can_use_xsdt()) { | 752 | if (osl_can_use_xsdt()) { |
753 | table_address = | 753 | table_address = |
754 | (acpi_physical_address) (*ACPI_CAST64(table_data)); | 754 | (acpi_physical_address)(*ACPI_CAST64(table_data)); |
755 | } else { | 755 | } else { |
756 | table_address = | 756 | table_address = |
757 | (acpi_physical_address) (*ACPI_CAST32(table_data)); | 757 | (acpi_physical_address)(*ACPI_CAST32(table_data)); |
758 | } | 758 | } |
759 | 759 | ||
760 | /* Skip NULL entries in RSDT/XSDT */ | 760 | /* Skip NULL entries in RSDT/XSDT */ |
@@ -800,7 +800,7 @@ static acpi_status | |||
800 | osl_get_bios_table(char *signature, | 800 | osl_get_bios_table(char *signature, |
801 | u32 instance, | 801 | u32 instance, |
802 | struct acpi_table_header **table, | 802 | struct acpi_table_header **table, |
803 | acpi_physical_address * address) | 803 | acpi_physical_address *address) |
804 | { | 804 | { |
805 | struct acpi_table_header *local_table = NULL; | 805 | struct acpi_table_header *local_table = NULL; |
806 | struct acpi_table_header *mapped_table = NULL; | 806 | struct acpi_table_header *mapped_table = NULL; |
@@ -833,38 +833,37 @@ osl_get_bios_table(char *signature, | |||
833 | if ((gbl_fadt->header.length >= MIN_FADT_FOR_XDSDT) && | 833 | if ((gbl_fadt->header.length >= MIN_FADT_FOR_XDSDT) && |
834 | gbl_fadt->Xdsdt) { | 834 | gbl_fadt->Xdsdt) { |
835 | table_address = | 835 | table_address = |
836 | (acpi_physical_address) gbl_fadt->Xdsdt; | 836 | (acpi_physical_address)gbl_fadt->Xdsdt; |
837 | } else | 837 | } else |
838 | if ((gbl_fadt->header.length >= MIN_FADT_FOR_DSDT) | 838 | if ((gbl_fadt->header.length >= MIN_FADT_FOR_DSDT) |
839 | && gbl_fadt->dsdt) { | 839 | && gbl_fadt->dsdt) { |
840 | table_address = | 840 | table_address = |
841 | (acpi_physical_address) gbl_fadt->dsdt; | 841 | (acpi_physical_address)gbl_fadt->dsdt; |
842 | } | 842 | } |
843 | } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) { | 843 | } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) { |
844 | if ((gbl_fadt->header.length >= MIN_FADT_FOR_XFACS) && | 844 | if ((gbl_fadt->header.length >= MIN_FADT_FOR_XFACS) && |
845 | gbl_fadt->Xfacs) { | 845 | gbl_fadt->Xfacs) { |
846 | table_address = | 846 | table_address = |
847 | (acpi_physical_address) gbl_fadt->Xfacs; | 847 | (acpi_physical_address)gbl_fadt->Xfacs; |
848 | } else | 848 | } else |
849 | if ((gbl_fadt->header.length >= MIN_FADT_FOR_FACS) | 849 | if ((gbl_fadt->header.length >= MIN_FADT_FOR_FACS) |
850 | && gbl_fadt->facs) { | 850 | && gbl_fadt->facs) { |
851 | table_address = | 851 | table_address = |
852 | (acpi_physical_address) gbl_fadt->facs; | 852 | (acpi_physical_address)gbl_fadt->facs; |
853 | } | 853 | } |
854 | } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT)) { | 854 | } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT)) { |
855 | if (!gbl_revision) { | 855 | if (!gbl_revision) { |
856 | return (AE_BAD_SIGNATURE); | 856 | return (AE_BAD_SIGNATURE); |
857 | } | 857 | } |
858 | table_address = | 858 | table_address = |
859 | (acpi_physical_address) gbl_rsdp. | 859 | (acpi_physical_address)gbl_rsdp. |
860 | xsdt_physical_address; | 860 | xsdt_physical_address; |
861 | } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT)) { | 861 | } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT)) { |
862 | table_address = | 862 | table_address = |
863 | (acpi_physical_address) gbl_rsdp. | 863 | (acpi_physical_address)gbl_rsdp. |
864 | rsdt_physical_address; | 864 | rsdt_physical_address; |
865 | } else { | 865 | } else { |
866 | table_address = | 866 | table_address = (acpi_physical_address)gbl_rsdp_address; |
867 | (acpi_physical_address) gbl_rsdp_address; | ||
868 | signature = ACPI_SIG_RSDP; | 867 | signature = ACPI_SIG_RSDP; |
869 | } | 868 | } |
870 | 869 | ||
@@ -904,12 +903,12 @@ osl_get_bios_table(char *signature, | |||
904 | for (i = 0; i < number_of_tables; ++i, table_data += item_size) { | 903 | for (i = 0; i < number_of_tables; ++i, table_data += item_size) { |
905 | if (osl_can_use_xsdt()) { | 904 | if (osl_can_use_xsdt()) { |
906 | table_address = | 905 | table_address = |
907 | (acpi_physical_address) (*ACPI_CAST64 | 906 | (acpi_physical_address)(*ACPI_CAST64 |
908 | (table_data)); | 907 | (table_data)); |
909 | } else { | 908 | } else { |
910 | table_address = | 909 | table_address = |
911 | (acpi_physical_address) (*ACPI_CAST32 | 910 | (acpi_physical_address)(*ACPI_CAST32 |
912 | (table_data)); | 911 | (table_data)); |
913 | } | 912 | } |
914 | 913 | ||
915 | /* Skip NULL entries in RSDT/XSDT */ | 914 | /* Skip NULL entries in RSDT/XSDT */ |
@@ -1301,7 +1300,7 @@ osl_get_customized_table(char *pathname, | |||
1301 | char *signature, | 1300 | char *signature, |
1302 | u32 instance, | 1301 | u32 instance, |
1303 | struct acpi_table_header **table, | 1302 | struct acpi_table_header **table, |
1304 | acpi_physical_address * address) | 1303 | acpi_physical_address *address) |
1305 | { | 1304 | { |
1306 | void *table_dir; | 1305 | void *table_dir; |
1307 | u32 current_instance = 0; | 1306 | u32 current_instance = 0; |
diff --git a/tools/power/acpi/os_specific/service_layers/osunixmap.c b/tools/power/acpi/os_specific/service_layers/osunixmap.c index 3818fd07e50f..cbfbce18783d 100644 --- a/tools/power/acpi/os_specific/service_layers/osunixmap.c +++ b/tools/power/acpi/os_specific/service_layers/osunixmap.c | |||
@@ -54,7 +54,7 @@ ACPI_MODULE_NAME("osunixmap") | |||
54 | #ifndef O_BINARY | 54 | #ifndef O_BINARY |
55 | #define O_BINARY 0 | 55 | #define O_BINARY 0 |
56 | #endif | 56 | #endif |
57 | #if defined(_dragon_fly) || defined(_free_BSD) | 57 | #if defined(_dragon_fly) || defined(_free_BSD) || defined(_QNX) |
58 | #define MMAP_FLAGS MAP_SHARED | 58 | #define MMAP_FLAGS MAP_SHARED |
59 | #else | 59 | #else |
60 | #define MMAP_FLAGS MAP_PRIVATE | 60 | #define MMAP_FLAGS MAP_PRIVATE |
diff --git a/tools/power/acpi/os_specific/service_layers/osunixxf.c b/tools/power/acpi/os_specific/service_layers/osunixxf.c index 08cb8b2035f2..88aa66ef4ad5 100644 --- a/tools/power/acpi/os_specific/service_layers/osunixxf.c +++ b/tools/power/acpi/os_specific/service_layers/osunixxf.c | |||
@@ -246,8 +246,8 @@ acpi_physical_address acpi_os_get_root_pointer(void) | |||
246 | *****************************************************************************/ | 246 | *****************************************************************************/ |
247 | 247 | ||
248 | acpi_status | 248 | acpi_status |
249 | acpi_os_predefined_override(const struct acpi_predefined_names * init_val, | 249 | acpi_os_predefined_override(const struct acpi_predefined_names *init_val, |
250 | acpi_string * new_val) | 250 | acpi_string *new_val) |
251 | { | 251 | { |
252 | 252 | ||
253 | if (!init_val || !new_val) { | 253 | if (!init_val || !new_val) { |
@@ -274,8 +274,8 @@ acpi_os_predefined_override(const struct acpi_predefined_names * init_val, | |||
274 | *****************************************************************************/ | 274 | *****************************************************************************/ |
275 | 275 | ||
276 | acpi_status | 276 | acpi_status |
277 | acpi_os_table_override(struct acpi_table_header * existing_table, | 277 | acpi_os_table_override(struct acpi_table_header *existing_table, |
278 | struct acpi_table_header ** new_table) | 278 | struct acpi_table_header **new_table) |
279 | { | 279 | { |
280 | 280 | ||
281 | if (!existing_table || !new_table) { | 281 | if (!existing_table || !new_table) { |
@@ -311,8 +311,8 @@ acpi_os_table_override(struct acpi_table_header * existing_table, | |||
311 | *****************************************************************************/ | 311 | *****************************************************************************/ |
312 | 312 | ||
313 | acpi_status | 313 | acpi_status |
314 | acpi_os_physical_table_override(struct acpi_table_header * existing_table, | 314 | acpi_os_physical_table_override(struct acpi_table_header *existing_table, |
315 | acpi_physical_address * new_address, | 315 | acpi_physical_address *new_address, |
316 | u32 *new_table_length) | 316 | u32 *new_table_length) |
317 | { | 317 | { |
318 | 318 | ||
@@ -506,7 +506,7 @@ acpi_status acpi_os_get_line(char *buffer, u32 buffer_length, u32 *bytes_read) | |||
506 | void *acpi_os_map_memory(acpi_physical_address where, acpi_size length) | 506 | void *acpi_os_map_memory(acpi_physical_address where, acpi_size length) |
507 | { | 507 | { |
508 | 508 | ||
509 | return (ACPI_TO_POINTER((acpi_size) where)); | 509 | return (ACPI_TO_POINTER((acpi_size)where)); |
510 | } | 510 | } |
511 | 511 | ||
512 | /****************************************************************************** | 512 | /****************************************************************************** |
@@ -603,9 +603,9 @@ void acpi_os_free(void *mem) | |||
603 | 603 | ||
604 | acpi_status | 604 | acpi_status |
605 | acpi_os_create_semaphore(u32 max_units, | 605 | acpi_os_create_semaphore(u32 max_units, |
606 | u32 initial_units, acpi_handle * out_handle) | 606 | u32 initial_units, acpi_handle *out_handle) |
607 | { | 607 | { |
608 | *out_handle = (acpi_handle) 1; | 608 | *out_handle = (acpi_handle)1; |
609 | return (AE_OK); | 609 | return (AE_OK); |
610 | } | 610 | } |
611 | 611 | ||
@@ -640,7 +640,7 @@ acpi_status acpi_os_signal_semaphore(acpi_handle handle, u32 units) | |||
640 | 640 | ||
641 | acpi_status | 641 | acpi_status |
642 | acpi_os_create_semaphore(u32 max_units, | 642 | acpi_os_create_semaphore(u32 max_units, |
643 | u32 initial_units, acpi_handle * out_handle) | 643 | u32 initial_units, acpi_handle *out_handle) |
644 | { | 644 | { |
645 | sem_t *sem; | 645 | sem_t *sem; |
646 | 646 | ||
@@ -672,7 +672,7 @@ acpi_os_create_semaphore(u32 max_units, | |||
672 | } | 672 | } |
673 | #endif | 673 | #endif |
674 | 674 | ||
675 | *out_handle = (acpi_handle) sem; | 675 | *out_handle = (acpi_handle)sem; |
676 | return (AE_OK); | 676 | return (AE_OK); |
677 | } | 677 | } |
678 | 678 | ||
@@ -1035,7 +1035,7 @@ acpi_os_read_pci_configuration(struct acpi_pci_id *pci_id, | |||
1035 | *****************************************************************************/ | 1035 | *****************************************************************************/ |
1036 | 1036 | ||
1037 | acpi_status | 1037 | acpi_status |
1038 | acpi_os_write_pci_configuration(struct acpi_pci_id * pci_id, | 1038 | acpi_os_write_pci_configuration(struct acpi_pci_id *pci_id, |
1039 | u32 pci_register, u64 value, u32 width) | 1039 | u32 pci_register, u64 value, u32 width) |
1040 | { | 1040 | { |
1041 | 1041 | ||
diff --git a/tools/power/acpi/tools/acpidbg/acpidbg.c b/tools/power/acpi/tools/acpidbg/acpidbg.c index d070fccdba6d..a88ac45b7756 100644 --- a/tools/power/acpi/tools/acpidbg/acpidbg.c +++ b/tools/power/acpi/tools/acpidbg/acpidbg.c | |||
@@ -375,7 +375,7 @@ void usage(FILE *file, char *progname) | |||
375 | 375 | ||
376 | int main(int argc, char **argv) | 376 | int main(int argc, char **argv) |
377 | { | 377 | { |
378 | int fd = 0; | 378 | int fd = -1; |
379 | int ch; | 379 | int ch; |
380 | int len; | 380 | int len; |
381 | int ret = EXIT_SUCCESS; | 381 | int ret = EXIT_SUCCESS; |
@@ -430,7 +430,7 @@ int main(int argc, char **argv) | |||
430 | acpi_aml_loop(fd); | 430 | acpi_aml_loop(fd); |
431 | 431 | ||
432 | exit: | 432 | exit: |
433 | if (fd < 0) | 433 | if (fd >= 0) |
434 | close(fd); | 434 | close(fd); |
435 | if (acpi_aml_batch_cmd) | 435 | if (acpi_aml_batch_cmd) |
436 | free(acpi_aml_batch_cmd); | 436 | free(acpi_aml_batch_cmd); |
diff --git a/tools/power/acpi/tools/acpidump/Makefile b/tools/power/acpi/tools/acpidump/Makefile index 8d761576e91b..2942cdced2ad 100644 --- a/tools/power/acpi/tools/acpidump/Makefile +++ b/tools/power/acpi/tools/acpidump/Makefile | |||
@@ -31,6 +31,7 @@ TOOL_OBJS = \ | |||
31 | osunixxf.o\ | 31 | osunixxf.o\ |
32 | tbprint.o\ | 32 | tbprint.o\ |
33 | tbxfroot.o\ | 33 | tbxfroot.o\ |
34 | utascii.o\ | ||
34 | utbuffer.o\ | 35 | utbuffer.o\ |
35 | utdebug.o\ | 36 | utdebug.o\ |
36 | utexcep.o\ | 37 | utexcep.o\ |
diff --git a/tools/power/acpi/tools/acpidump/apdump.c b/tools/power/acpi/tools/acpidump/apdump.c index da44458d3b6c..fb8f1d9e3b1b 100644 --- a/tools/power/acpi/tools/acpidump/apdump.c +++ b/tools/power/acpi/tools/acpidump/apdump.c | |||
@@ -68,7 +68,7 @@ u8 ap_is_valid_header(struct acpi_table_header *table) | |||
68 | 68 | ||
69 | /* Make sure signature is all ASCII and a valid ACPI name */ | 69 | /* Make sure signature is all ASCII and a valid ACPI name */ |
70 | 70 | ||
71 | if (!acpi_ut_valid_acpi_name(table->signature)) { | 71 | if (!acpi_ut_valid_nameseg(table->signature)) { |
72 | acpi_log_error("Table signature (0x%8.8X) is invalid\n", | 72 | acpi_log_error("Table signature (0x%8.8X) is invalid\n", |
73 | *(u32 *)table->signature); | 73 | *(u32 *)table->signature); |
74 | return (FALSE); | 74 | return (FALSE); |
@@ -286,14 +286,15 @@ int ap_dump_table_by_address(char *ascii_address) | |||
286 | 286 | ||
287 | /* Convert argument to an integer physical address */ | 287 | /* Convert argument to an integer physical address */ |
288 | 288 | ||
289 | status = acpi_ut_strtoul64(ascii_address, 0, &long_address); | 289 | status = acpi_ut_strtoul64(ascii_address, ACPI_ANY_BASE, |
290 | ACPI_MAX64_BYTE_WIDTH, &long_address); | ||
290 | if (ACPI_FAILURE(status)) { | 291 | if (ACPI_FAILURE(status)) { |
291 | acpi_log_error("%s: Could not convert to a physical address\n", | 292 | acpi_log_error("%s: Could not convert to a physical address\n", |
292 | ascii_address); | 293 | ascii_address); |
293 | return (-1); | 294 | return (-1); |
294 | } | 295 | } |
295 | 296 | ||
296 | address = (acpi_physical_address) long_address; | 297 | address = (acpi_physical_address)long_address; |
297 | status = acpi_os_get_table_by_address(address, &table); | 298 | status = acpi_os_get_table_by_address(address, &table); |
298 | if (ACPI_FAILURE(status)) { | 299 | if (ACPI_FAILURE(status)) { |
299 | acpi_log_error("Could not get table at 0x%8.8X%8.8X, %s\n", | 300 | acpi_log_error("Could not get table at 0x%8.8X%8.8X, %s\n", |
@@ -406,6 +407,12 @@ int ap_dump_table_from_file(char *pathname) | |||
406 | return (-1); | 407 | return (-1); |
407 | } | 408 | } |
408 | 409 | ||
410 | if (!acpi_ut_valid_nameseg(table->signature)) { | ||
411 | acpi_log_error | ||
412 | ("No valid ACPI signature was found in input file %s\n", | ||
413 | pathname); | ||
414 | } | ||
415 | |||
409 | /* File must be at least as long as the table length */ | 416 | /* File must be at least as long as the table length */ |
410 | 417 | ||
411 | if (table->length > file_size) { | 418 | if (table->length > file_size) { |
diff --git a/tools/power/acpi/tools/acpidump/apmain.c b/tools/power/acpi/tools/acpidump/apmain.c index c3c09152fac6..7692e6b887e1 100644 --- a/tools/power/acpi/tools/acpidump/apmain.c +++ b/tools/power/acpi/tools/acpidump/apmain.c | |||
@@ -209,7 +209,8 @@ static int ap_do_options(int argc, char **argv) | |||
209 | case 'r': /* Dump tables from specified RSDP */ | 209 | case 'r': /* Dump tables from specified RSDP */ |
210 | 210 | ||
211 | status = | 211 | status = |
212 | acpi_ut_strtoul64(acpi_gbl_optarg, 0, | 212 | acpi_ut_strtoul64(acpi_gbl_optarg, ACPI_ANY_BASE, |
213 | ACPI_MAX64_BYTE_WIDTH, | ||
213 | &gbl_rsdp_base); | 214 | &gbl_rsdp_base); |
214 | if (ACPI_FAILURE(status)) { | 215 | if (ACPI_FAILURE(status)) { |
215 | acpi_log_error | 216 | acpi_log_error |
diff --git a/tools/power/cpupower/Makefile b/tools/power/cpupower/Makefile index 0adaf0c7c03a..8358863259c5 100644 --- a/tools/power/cpupower/Makefile +++ b/tools/power/cpupower/Makefile | |||
@@ -63,7 +63,7 @@ DESTDIR ?= | |||
63 | # and _should_ modify the PACKAGE_BUGREPORT definition | 63 | # and _should_ modify the PACKAGE_BUGREPORT definition |
64 | 64 | ||
65 | VERSION= $(shell ./utils/version-gen.sh) | 65 | VERSION= $(shell ./utils/version-gen.sh) |
66 | LIB_MAJ= 0.0.0 | 66 | LIB_MAJ= 0.0.1 |
67 | LIB_MIN= 0 | 67 | LIB_MIN= 0 |
68 | 68 | ||
69 | PACKAGE = cpupower | 69 | PACKAGE = cpupower |
@@ -129,7 +129,7 @@ WARNINGS += -Wshadow | |||
129 | CFLAGS += -DVERSION=\"$(VERSION)\" -DPACKAGE=\"$(PACKAGE)\" \ | 129 | CFLAGS += -DVERSION=\"$(VERSION)\" -DPACKAGE=\"$(PACKAGE)\" \ |
130 | -DPACKAGE_BUGREPORT=\"$(PACKAGE_BUGREPORT)\" -D_GNU_SOURCE | 130 | -DPACKAGE_BUGREPORT=\"$(PACKAGE_BUGREPORT)\" -D_GNU_SOURCE |
131 | 131 | ||
132 | UTIL_OBJS = utils/helpers/amd.o utils/helpers/topology.o utils/helpers/msr.o \ | 132 | UTIL_OBJS = utils/helpers/amd.o utils/helpers/msr.o \ |
133 | utils/helpers/sysfs.o utils/helpers/misc.o utils/helpers/cpuid.o \ | 133 | utils/helpers/sysfs.o utils/helpers/misc.o utils/helpers/cpuid.o \ |
134 | utils/helpers/pci.o utils/helpers/bitmask.o \ | 134 | utils/helpers/pci.o utils/helpers/bitmask.o \ |
135 | utils/idle_monitor/nhm_idle.o utils/idle_monitor/snb_idle.o \ | 135 | utils/idle_monitor/nhm_idle.o utils/idle_monitor/snb_idle.o \ |
@@ -148,9 +148,9 @@ UTIL_HEADERS = utils/helpers/helpers.h utils/idle_monitor/cpupower-monitor.h \ | |||
148 | utils/helpers/bitmask.h \ | 148 | utils/helpers/bitmask.h \ |
149 | utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def | 149 | utils/idle_monitor/idle_monitors.h utils/idle_monitor/idle_monitors.def |
150 | 150 | ||
151 | LIB_HEADERS = lib/cpufreq.h lib/sysfs.h | 151 | LIB_HEADERS = lib/cpufreq.h lib/cpupower.h lib/cpuidle.h |
152 | LIB_SRC = lib/cpufreq.c lib/sysfs.c | 152 | LIB_SRC = lib/cpufreq.c lib/cpupower.c lib/cpuidle.c |
153 | LIB_OBJS = lib/cpufreq.o lib/sysfs.o | 153 | LIB_OBJS = lib/cpufreq.o lib/cpupower.o lib/cpuidle.o |
154 | LIB_OBJS := $(addprefix $(OUTPUT),$(LIB_OBJS)) | 154 | LIB_OBJS := $(addprefix $(OUTPUT),$(LIB_OBJS)) |
155 | 155 | ||
156 | CFLAGS += -pipe | 156 | CFLAGS += -pipe |
@@ -280,6 +280,7 @@ install-lib: | |||
280 | $(CP) $(OUTPUT)libcpupower.so* $(DESTDIR)${libdir}/ | 280 | $(CP) $(OUTPUT)libcpupower.so* $(DESTDIR)${libdir}/ |
281 | $(INSTALL) -d $(DESTDIR)${includedir} | 281 | $(INSTALL) -d $(DESTDIR)${includedir} |
282 | $(INSTALL_DATA) lib/cpufreq.h $(DESTDIR)${includedir}/cpufreq.h | 282 | $(INSTALL_DATA) lib/cpufreq.h $(DESTDIR)${includedir}/cpufreq.h |
283 | $(INSTALL_DATA) lib/cpuidle.h $(DESTDIR)${includedir}/cpuidle.h | ||
283 | 284 | ||
284 | install-tools: | 285 | install-tools: |
285 | $(INSTALL) -d $(DESTDIR)${bindir} | 286 | $(INSTALL) -d $(DESTDIR)${bindir} |
@@ -315,6 +316,7 @@ endif | |||
315 | uninstall: | 316 | uninstall: |
316 | - rm -f $(DESTDIR)${libdir}/libcpupower.* | 317 | - rm -f $(DESTDIR)${libdir}/libcpupower.* |
317 | - rm -f $(DESTDIR)${includedir}/cpufreq.h | 318 | - rm -f $(DESTDIR)${includedir}/cpufreq.h |
319 | - rm -f $(DESTDIR)${includedir}/cpuidle.h | ||
318 | - rm -f $(DESTDIR)${bindir}/utils/cpupower | 320 | - rm -f $(DESTDIR)${bindir}/utils/cpupower |
319 | - rm -f $(DESTDIR)${mandir}/man1/cpupower.1 | 321 | - rm -f $(DESTDIR)${mandir}/man1/cpupower.1 |
320 | - rm -f $(DESTDIR)${mandir}/man1/cpupower-frequency-set.1 | 322 | - rm -f $(DESTDIR)${mandir}/man1/cpupower-frequency-set.1 |
diff --git a/tools/power/cpupower/bench/Makefile b/tools/power/cpupower/bench/Makefile index d0f879b223fc..3e59f1aa3947 100644 --- a/tools/power/cpupower/bench/Makefile +++ b/tools/power/cpupower/bench/Makefile | |||
@@ -22,7 +22,7 @@ $(OUTPUT)%.o : %.c | |||
22 | 22 | ||
23 | $(OUTPUT)cpufreq-bench: $(OBJS) | 23 | $(OUTPUT)cpufreq-bench: $(OBJS) |
24 | $(ECHO) " CC " $@ | 24 | $(ECHO) " CC " $@ |
25 | $(QUIET) $(CC) -o $@ $(CFLAGS) $(OBJS) $(LIBS) | 25 | $(QUIET) $(CC) -o $@ $(CFLAGS) $(LDFLAGS) $(OBJS) $(LIBS) |
26 | 26 | ||
27 | all: $(OUTPUT)cpufreq-bench | 27 | all: $(OUTPUT)cpufreq-bench |
28 | 28 | ||
diff --git a/tools/power/cpupower/bench/README-BENCH b/tools/power/cpupower/bench/README-BENCH index 8093ec738170..97727aed61cc 100644 --- a/tools/power/cpupower/bench/README-BENCH +++ b/tools/power/cpupower/bench/README-BENCH | |||
@@ -113,7 +113,7 @@ cpufreq-bench Command Usage | |||
113 | -c, --cpu=<unsigned int> CPU Number to use, starting at 0 | 113 | -c, --cpu=<unsigned int> CPU Number to use, starting at 0 |
114 | -p, --prio=<priority> scheduler priority, HIGH, LOW or DEFAULT | 114 | -p, --prio=<priority> scheduler priority, HIGH, LOW or DEFAULT |
115 | -g, --governor=<governor> cpufreq governor to test | 115 | -g, --governor=<governor> cpufreq governor to test |
116 | -n, --cycles=<int> load/sleep cycles to get an avarage value to compare | 116 | -n, --cycles=<int> load/sleep cycles to get an average value to compare |
117 | -r, --rounds<int> load/sleep rounds | 117 | -r, --rounds<int> load/sleep rounds |
118 | -f, --file=<configfile> config file to use | 118 | -f, --file=<configfile> config file to use |
119 | -o, --output=<dir> output dir, must exist | 119 | -o, --output=<dir> output dir, must exist |
diff --git a/tools/power/cpupower/bench/benchmark.c b/tools/power/cpupower/bench/benchmark.c index 81b1c48607d9..429d51ab8031 100644 --- a/tools/power/cpupower/bench/benchmark.c +++ b/tools/power/cpupower/bench/benchmark.c | |||
@@ -130,7 +130,7 @@ void start_benchmark(struct config *config) | |||
130 | _round, load_time, sleep_time); | 130 | _round, load_time, sleep_time); |
131 | 131 | ||
132 | if (config->verbose) | 132 | if (config->verbose) |
133 | printf("avarage: %lius, rps:%li\n", | 133 | printf("average: %lius, rps:%li\n", |
134 | load_time / calculations, | 134 | load_time / calculations, |
135 | 1000000 * calculations / load_time); | 135 | 1000000 * calculations / load_time); |
136 | 136 | ||
@@ -177,7 +177,7 @@ void start_benchmark(struct config *config) | |||
177 | 177 | ||
178 | progress_time += sleep_time + load_time; | 178 | progress_time += sleep_time + load_time; |
179 | 179 | ||
180 | /* compare the avarage sleep/load cycles */ | 180 | /* compare the average sleep/load cycles */ |
181 | fprintf(config->output, "%li ", | 181 | fprintf(config->output, "%li ", |
182 | powersave_time / config->cycles); | 182 | powersave_time / config->cycles); |
183 | fprintf(config->output, "%.3f\n", | 183 | fprintf(config->output, "%.3f\n", |
diff --git a/tools/power/cpupower/bench/parse.c b/tools/power/cpupower/bench/parse.c index f503fb53824e..9b65f052081f 100644 --- a/tools/power/cpupower/bench/parse.c +++ b/tools/power/cpupower/bench/parse.c | |||
@@ -65,7 +65,7 @@ FILE *prepare_output(const char *dirname) | |||
65 | { | 65 | { |
66 | FILE *output = NULL; | 66 | FILE *output = NULL; |
67 | int len; | 67 | int len; |
68 | char *filename; | 68 | char *filename, *filename_tmp; |
69 | struct utsname sysdata; | 69 | struct utsname sysdata; |
70 | DIR *dir; | 70 | DIR *dir; |
71 | 71 | ||
@@ -81,16 +81,22 @@ FILE *prepare_output(const char *dirname) | |||
81 | 81 | ||
82 | len = strlen(dirname) + 30; | 82 | len = strlen(dirname) + 30; |
83 | filename = malloc(sizeof(char) * len); | 83 | filename = malloc(sizeof(char) * len); |
84 | if (!filename) { | ||
85 | perror("malloc"); | ||
86 | goto out_dir; | ||
87 | } | ||
84 | 88 | ||
85 | if (uname(&sysdata) == 0) { | 89 | if (uname(&sysdata) == 0) { |
86 | len += strlen(sysdata.nodename) + strlen(sysdata.release); | 90 | len += strlen(sysdata.nodename) + strlen(sysdata.release); |
87 | filename = realloc(filename, sizeof(char) * len); | 91 | filename_tmp = realloc(filename, sizeof(*filename) * len); |
88 | 92 | ||
89 | if (filename == NULL) { | 93 | if (filename_tmp == NULL) { |
94 | free(filename); | ||
90 | perror("realloc"); | 95 | perror("realloc"); |
91 | return NULL; | 96 | goto out_dir; |
92 | } | 97 | } |
93 | 98 | ||
99 | filename = filename_tmp; | ||
94 | snprintf(filename, len - 1, "%s/benchmark_%s_%s_%li.log", | 100 | snprintf(filename, len - 1, "%s/benchmark_%s_%s_%li.log", |
95 | dirname, sysdata.nodename, sysdata.release, time(NULL)); | 101 | dirname, sysdata.nodename, sysdata.release, time(NULL)); |
96 | } else { | 102 | } else { |
@@ -104,12 +110,16 @@ FILE *prepare_output(const char *dirname) | |||
104 | if (output == NULL) { | 110 | if (output == NULL) { |
105 | perror("fopen"); | 111 | perror("fopen"); |
106 | fprintf(stderr, "error: unable to open logfile\n"); | 112 | fprintf(stderr, "error: unable to open logfile\n"); |
113 | goto out; | ||
107 | } | 114 | } |
108 | 115 | ||
109 | fprintf(stdout, "Logfile: %s\n", filename); | 116 | fprintf(stdout, "Logfile: %s\n", filename); |
110 | 117 | ||
111 | free(filename); | ||
112 | fprintf(output, "#round load sleep performance powersave percentage\n"); | 118 | fprintf(output, "#round load sleep performance powersave percentage\n"); |
119 | out: | ||
120 | free(filename); | ||
121 | out_dir: | ||
122 | closedir(dir); | ||
113 | return output; | 123 | return output; |
114 | } | 124 | } |
115 | 125 | ||
diff --git a/tools/power/cpupower/bench/system.c b/tools/power/cpupower/bench/system.c index f01e3f4be84c..c25a74ae51ba 100644 --- a/tools/power/cpupower/bench/system.c +++ b/tools/power/cpupower/bench/system.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <sched.h> | 26 | #include <sched.h> |
27 | 27 | ||
28 | #include <cpufreq.h> | 28 | #include <cpufreq.h> |
29 | #include <cpupower.h> | ||
29 | 30 | ||
30 | #include "config.h" | 31 | #include "config.h" |
31 | #include "system.h" | 32 | #include "system.h" |
@@ -60,7 +61,7 @@ int set_cpufreq_governor(char *governor, unsigned int cpu) | |||
60 | 61 | ||
61 | dprintf("set %s as cpufreq governor\n", governor); | 62 | dprintf("set %s as cpufreq governor\n", governor); |
62 | 63 | ||
63 | if (cpufreq_cpu_exists(cpu) != 0) { | 64 | if (cpupower_is_cpu_online(cpu) != 0) { |
64 | perror("cpufreq_cpu_exists"); | 65 | perror("cpufreq_cpu_exists"); |
65 | fprintf(stderr, "error: cpu %u does not exist\n", cpu); | 66 | fprintf(stderr, "error: cpu %u does not exist\n", cpu); |
66 | return -1; | 67 | return -1; |
diff --git a/tools/power/cpupower/lib/cpufreq.c b/tools/power/cpupower/lib/cpufreq.c index d961101d1cea..1b993fe1ce23 100644 --- a/tools/power/cpupower/lib/cpufreq.c +++ b/tools/power/cpupower/lib/cpufreq.c | |||
@@ -9,28 +9,190 @@ | |||
9 | #include <errno.h> | 9 | #include <errno.h> |
10 | #include <stdlib.h> | 10 | #include <stdlib.h> |
11 | #include <string.h> | 11 | #include <string.h> |
12 | #include <sys/types.h> | ||
13 | #include <sys/stat.h> | ||
14 | #include <fcntl.h> | ||
15 | #include <unistd.h> | ||
12 | 16 | ||
13 | #include "cpufreq.h" | 17 | #include "cpufreq.h" |
14 | #include "sysfs.h" | 18 | #include "cpupower_intern.h" |
15 | 19 | ||
16 | int cpufreq_cpu_exists(unsigned int cpu) | 20 | /* CPUFREQ sysfs access **************************************************/ |
21 | |||
22 | /* helper function to read file from /sys into given buffer */ | ||
23 | /* fname is a relative path under "cpuX/cpufreq" dir */ | ||
24 | static unsigned int sysfs_cpufreq_read_file(unsigned int cpu, const char *fname, | ||
25 | char *buf, size_t buflen) | ||
17 | { | 26 | { |
18 | return sysfs_cpu_exists(cpu); | 27 | char path[SYSFS_PATH_MAX]; |
28 | |||
29 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s", | ||
30 | cpu, fname); | ||
31 | return sysfs_read_file(path, buf, buflen); | ||
19 | } | 32 | } |
20 | 33 | ||
34 | /* helper function to write a new value to a /sys file */ | ||
35 | /* fname is a relative path under "cpuX/cpufreq" dir */ | ||
36 | static unsigned int sysfs_cpufreq_write_file(unsigned int cpu, | ||
37 | const char *fname, | ||
38 | const char *value, size_t len) | ||
39 | { | ||
40 | char path[SYSFS_PATH_MAX]; | ||
41 | int fd; | ||
42 | ssize_t numwrite; | ||
43 | |||
44 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s", | ||
45 | cpu, fname); | ||
46 | |||
47 | fd = open(path, O_WRONLY); | ||
48 | if (fd == -1) | ||
49 | return 0; | ||
50 | |||
51 | numwrite = write(fd, value, len); | ||
52 | if (numwrite < 1) { | ||
53 | close(fd); | ||
54 | return 0; | ||
55 | } | ||
56 | |||
57 | close(fd); | ||
58 | |||
59 | return (unsigned int) numwrite; | ||
60 | } | ||
61 | |||
62 | /* read access to files which contain one numeric value */ | ||
63 | |||
64 | enum cpufreq_value { | ||
65 | CPUINFO_CUR_FREQ, | ||
66 | CPUINFO_MIN_FREQ, | ||
67 | CPUINFO_MAX_FREQ, | ||
68 | CPUINFO_LATENCY, | ||
69 | SCALING_CUR_FREQ, | ||
70 | SCALING_MIN_FREQ, | ||
71 | SCALING_MAX_FREQ, | ||
72 | STATS_NUM_TRANSITIONS, | ||
73 | MAX_CPUFREQ_VALUE_READ_FILES | ||
74 | }; | ||
75 | |||
76 | static const char *cpufreq_value_files[MAX_CPUFREQ_VALUE_READ_FILES] = { | ||
77 | [CPUINFO_CUR_FREQ] = "cpuinfo_cur_freq", | ||
78 | [CPUINFO_MIN_FREQ] = "cpuinfo_min_freq", | ||
79 | [CPUINFO_MAX_FREQ] = "cpuinfo_max_freq", | ||
80 | [CPUINFO_LATENCY] = "cpuinfo_transition_latency", | ||
81 | [SCALING_CUR_FREQ] = "scaling_cur_freq", | ||
82 | [SCALING_MIN_FREQ] = "scaling_min_freq", | ||
83 | [SCALING_MAX_FREQ] = "scaling_max_freq", | ||
84 | [STATS_NUM_TRANSITIONS] = "stats/total_trans" | ||
85 | }; | ||
86 | |||
87 | |||
88 | static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu, | ||
89 | enum cpufreq_value which) | ||
90 | { | ||
91 | unsigned long value; | ||
92 | unsigned int len; | ||
93 | char linebuf[MAX_LINE_LEN]; | ||
94 | char *endp; | ||
95 | |||
96 | if (which >= MAX_CPUFREQ_VALUE_READ_FILES) | ||
97 | return 0; | ||
98 | |||
99 | len = sysfs_cpufreq_read_file(cpu, cpufreq_value_files[which], | ||
100 | linebuf, sizeof(linebuf)); | ||
101 | |||
102 | if (len == 0) | ||
103 | return 0; | ||
104 | |||
105 | value = strtoul(linebuf, &endp, 0); | ||
106 | |||
107 | if (endp == linebuf || errno == ERANGE) | ||
108 | return 0; | ||
109 | |||
110 | return value; | ||
111 | } | ||
112 | |||
113 | /* read access to files which contain one string */ | ||
114 | |||
115 | enum cpufreq_string { | ||
116 | SCALING_DRIVER, | ||
117 | SCALING_GOVERNOR, | ||
118 | MAX_CPUFREQ_STRING_FILES | ||
119 | }; | ||
120 | |||
121 | static const char *cpufreq_string_files[MAX_CPUFREQ_STRING_FILES] = { | ||
122 | [SCALING_DRIVER] = "scaling_driver", | ||
123 | [SCALING_GOVERNOR] = "scaling_governor", | ||
124 | }; | ||
125 | |||
126 | |||
127 | static char *sysfs_cpufreq_get_one_string(unsigned int cpu, | ||
128 | enum cpufreq_string which) | ||
129 | { | ||
130 | char linebuf[MAX_LINE_LEN]; | ||
131 | char *result; | ||
132 | unsigned int len; | ||
133 | |||
134 | if (which >= MAX_CPUFREQ_STRING_FILES) | ||
135 | return NULL; | ||
136 | |||
137 | len = sysfs_cpufreq_read_file(cpu, cpufreq_string_files[which], | ||
138 | linebuf, sizeof(linebuf)); | ||
139 | if (len == 0) | ||
140 | return NULL; | ||
141 | |||
142 | result = strdup(linebuf); | ||
143 | if (result == NULL) | ||
144 | return NULL; | ||
145 | |||
146 | if (result[strlen(result) - 1] == '\n') | ||
147 | result[strlen(result) - 1] = '\0'; | ||
148 | |||
149 | return result; | ||
150 | } | ||
151 | |||
152 | /* write access */ | ||
153 | |||
154 | enum cpufreq_write { | ||
155 | WRITE_SCALING_MIN_FREQ, | ||
156 | WRITE_SCALING_MAX_FREQ, | ||
157 | WRITE_SCALING_GOVERNOR, | ||
158 | WRITE_SCALING_SET_SPEED, | ||
159 | MAX_CPUFREQ_WRITE_FILES | ||
160 | }; | ||
161 | |||
162 | static const char *cpufreq_write_files[MAX_CPUFREQ_WRITE_FILES] = { | ||
163 | [WRITE_SCALING_MIN_FREQ] = "scaling_min_freq", | ||
164 | [WRITE_SCALING_MAX_FREQ] = "scaling_max_freq", | ||
165 | [WRITE_SCALING_GOVERNOR] = "scaling_governor", | ||
166 | [WRITE_SCALING_SET_SPEED] = "scaling_setspeed", | ||
167 | }; | ||
168 | |||
169 | static int sysfs_cpufreq_write_one_value(unsigned int cpu, | ||
170 | enum cpufreq_write which, | ||
171 | const char *new_value, size_t len) | ||
172 | { | ||
173 | if (which >= MAX_CPUFREQ_WRITE_FILES) | ||
174 | return 0; | ||
175 | |||
176 | if (sysfs_cpufreq_write_file(cpu, cpufreq_write_files[which], | ||
177 | new_value, len) != len) | ||
178 | return -ENODEV; | ||
179 | |||
180 | return 0; | ||
181 | }; | ||
182 | |||
21 | unsigned long cpufreq_get_freq_kernel(unsigned int cpu) | 183 | unsigned long cpufreq_get_freq_kernel(unsigned int cpu) |
22 | { | 184 | { |
23 | return sysfs_get_freq_kernel(cpu); | 185 | return sysfs_cpufreq_get_one_value(cpu, SCALING_CUR_FREQ); |
24 | } | 186 | } |
25 | 187 | ||
26 | unsigned long cpufreq_get_freq_hardware(unsigned int cpu) | 188 | unsigned long cpufreq_get_freq_hardware(unsigned int cpu) |
27 | { | 189 | { |
28 | return sysfs_get_freq_hardware(cpu); | 190 | return sysfs_cpufreq_get_one_value(cpu, CPUINFO_CUR_FREQ); |
29 | } | 191 | } |
30 | 192 | ||
31 | unsigned long cpufreq_get_transition_latency(unsigned int cpu) | 193 | unsigned long cpufreq_get_transition_latency(unsigned int cpu) |
32 | { | 194 | { |
33 | return sysfs_get_freq_transition_latency(cpu); | 195 | return sysfs_cpufreq_get_one_value(cpu, CPUINFO_LATENCY); |
34 | } | 196 | } |
35 | 197 | ||
36 | int cpufreq_get_hardware_limits(unsigned int cpu, | 198 | int cpufreq_get_hardware_limits(unsigned int cpu, |
@@ -39,12 +201,21 @@ int cpufreq_get_hardware_limits(unsigned int cpu, | |||
39 | { | 201 | { |
40 | if ((!min) || (!max)) | 202 | if ((!min) || (!max)) |
41 | return -EINVAL; | 203 | return -EINVAL; |
42 | return sysfs_get_freq_hardware_limits(cpu, min, max); | 204 | |
205 | *min = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MIN_FREQ); | ||
206 | if (!*min) | ||
207 | return -ENODEV; | ||
208 | |||
209 | *max = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MAX_FREQ); | ||
210 | if (!*max) | ||
211 | return -ENODEV; | ||
212 | |||
213 | return 0; | ||
43 | } | 214 | } |
44 | 215 | ||
45 | char *cpufreq_get_driver(unsigned int cpu) | 216 | char *cpufreq_get_driver(unsigned int cpu) |
46 | { | 217 | { |
47 | return sysfs_get_freq_driver(cpu); | 218 | return sysfs_cpufreq_get_one_string(cpu, SCALING_DRIVER); |
48 | } | 219 | } |
49 | 220 | ||
50 | void cpufreq_put_driver(char *ptr) | 221 | void cpufreq_put_driver(char *ptr) |
@@ -56,7 +227,26 @@ void cpufreq_put_driver(char *ptr) | |||
56 | 227 | ||
57 | struct cpufreq_policy *cpufreq_get_policy(unsigned int cpu) | 228 | struct cpufreq_policy *cpufreq_get_policy(unsigned int cpu) |
58 | { | 229 | { |
59 | return sysfs_get_freq_policy(cpu); | 230 | struct cpufreq_policy *policy; |
231 | |||
232 | policy = malloc(sizeof(struct cpufreq_policy)); | ||
233 | if (!policy) | ||
234 | return NULL; | ||
235 | |||
236 | policy->governor = sysfs_cpufreq_get_one_string(cpu, SCALING_GOVERNOR); | ||
237 | if (!policy->governor) { | ||
238 | free(policy); | ||
239 | return NULL; | ||
240 | } | ||
241 | policy->min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ); | ||
242 | policy->max = sysfs_cpufreq_get_one_value(cpu, SCALING_MAX_FREQ); | ||
243 | if ((!policy->min) || (!policy->max)) { | ||
244 | free(policy->governor); | ||
245 | free(policy); | ||
246 | return NULL; | ||
247 | } | ||
248 | |||
249 | return policy; | ||
60 | } | 250 | } |
61 | 251 | ||
62 | void cpufreq_put_policy(struct cpufreq_policy *policy) | 252 | void cpufreq_put_policy(struct cpufreq_policy *policy) |
@@ -72,7 +262,57 @@ void cpufreq_put_policy(struct cpufreq_policy *policy) | |||
72 | struct cpufreq_available_governors *cpufreq_get_available_governors(unsigned | 262 | struct cpufreq_available_governors *cpufreq_get_available_governors(unsigned |
73 | int cpu) | 263 | int cpu) |
74 | { | 264 | { |
75 | return sysfs_get_freq_available_governors(cpu); | 265 | struct cpufreq_available_governors *first = NULL; |
266 | struct cpufreq_available_governors *current = NULL; | ||
267 | char linebuf[MAX_LINE_LEN]; | ||
268 | unsigned int pos, i; | ||
269 | unsigned int len; | ||
270 | |||
271 | len = sysfs_cpufreq_read_file(cpu, "scaling_available_governors", | ||
272 | linebuf, sizeof(linebuf)); | ||
273 | if (len == 0) | ||
274 | return NULL; | ||
275 | |||
276 | pos = 0; | ||
277 | for (i = 0; i < len; i++) { | ||
278 | if (linebuf[i] == ' ' || linebuf[i] == '\n') { | ||
279 | if (i - pos < 2) | ||
280 | continue; | ||
281 | if (current) { | ||
282 | current->next = malloc(sizeof(*current)); | ||
283 | if (!current->next) | ||
284 | goto error_out; | ||
285 | current = current->next; | ||
286 | } else { | ||
287 | first = malloc(sizeof(*first)); | ||
288 | if (!first) | ||
289 | goto error_out; | ||
290 | current = first; | ||
291 | } | ||
292 | current->first = first; | ||
293 | current->next = NULL; | ||
294 | |||
295 | current->governor = malloc(i - pos + 1); | ||
296 | if (!current->governor) | ||
297 | goto error_out; | ||
298 | |||
299 | memcpy(current->governor, linebuf + pos, i - pos); | ||
300 | current->governor[i - pos] = '\0'; | ||
301 | pos = i + 1; | ||
302 | } | ||
303 | } | ||
304 | |||
305 | return first; | ||
306 | |||
307 | error_out: | ||
308 | while (first) { | ||
309 | current = first->next; | ||
310 | if (first->governor) | ||
311 | free(first->governor); | ||
312 | free(first); | ||
313 | first = current; | ||
314 | } | ||
315 | return NULL; | ||
76 | } | 316 | } |
77 | 317 | ||
78 | void cpufreq_put_available_governors(struct cpufreq_available_governors *any) | 318 | void cpufreq_put_available_governors(struct cpufreq_available_governors *any) |
@@ -96,7 +336,57 @@ void cpufreq_put_available_governors(struct cpufreq_available_governors *any) | |||
96 | struct cpufreq_available_frequencies | 336 | struct cpufreq_available_frequencies |
97 | *cpufreq_get_available_frequencies(unsigned int cpu) | 337 | *cpufreq_get_available_frequencies(unsigned int cpu) |
98 | { | 338 | { |
99 | return sysfs_get_available_frequencies(cpu); | 339 | struct cpufreq_available_frequencies *first = NULL; |
340 | struct cpufreq_available_frequencies *current = NULL; | ||
341 | char one_value[SYSFS_PATH_MAX]; | ||
342 | char linebuf[MAX_LINE_LEN]; | ||
343 | unsigned int pos, i; | ||
344 | unsigned int len; | ||
345 | |||
346 | len = sysfs_cpufreq_read_file(cpu, "scaling_available_frequencies", | ||
347 | linebuf, sizeof(linebuf)); | ||
348 | if (len == 0) | ||
349 | return NULL; | ||
350 | |||
351 | pos = 0; | ||
352 | for (i = 0; i < len; i++) { | ||
353 | if (linebuf[i] == ' ' || linebuf[i] == '\n') { | ||
354 | if (i - pos < 2) | ||
355 | continue; | ||
356 | if (i - pos >= SYSFS_PATH_MAX) | ||
357 | goto error_out; | ||
358 | if (current) { | ||
359 | current->next = malloc(sizeof(*current)); | ||
360 | if (!current->next) | ||
361 | goto error_out; | ||
362 | current = current->next; | ||
363 | } else { | ||
364 | first = malloc(sizeof(*first)); | ||
365 | if (!first) | ||
366 | goto error_out; | ||
367 | current = first; | ||
368 | } | ||
369 | current->first = first; | ||
370 | current->next = NULL; | ||
371 | |||
372 | memcpy(one_value, linebuf + pos, i - pos); | ||
373 | one_value[i - pos] = '\0'; | ||
374 | if (sscanf(one_value, "%lu", ¤t->frequency) != 1) | ||
375 | goto error_out; | ||
376 | |||
377 | pos = i + 1; | ||
378 | } | ||
379 | } | ||
380 | |||
381 | return first; | ||
382 | |||
383 | error_out: | ||
384 | while (first) { | ||
385 | current = first->next; | ||
386 | free(first); | ||
387 | first = current; | ||
388 | } | ||
389 | return NULL; | ||
100 | } | 390 | } |
101 | 391 | ||
102 | void cpufreq_put_available_frequencies(struct cpufreq_available_frequencies | 392 | void cpufreq_put_available_frequencies(struct cpufreq_available_frequencies |
@@ -114,10 +404,65 @@ void cpufreq_put_available_frequencies(struct cpufreq_available_frequencies | |||
114 | } | 404 | } |
115 | } | 405 | } |
116 | 406 | ||
407 | static struct cpufreq_affected_cpus *sysfs_get_cpu_list(unsigned int cpu, | ||
408 | const char *file) | ||
409 | { | ||
410 | struct cpufreq_affected_cpus *first = NULL; | ||
411 | struct cpufreq_affected_cpus *current = NULL; | ||
412 | char one_value[SYSFS_PATH_MAX]; | ||
413 | char linebuf[MAX_LINE_LEN]; | ||
414 | unsigned int pos, i; | ||
415 | unsigned int len; | ||
416 | |||
417 | len = sysfs_cpufreq_read_file(cpu, file, linebuf, sizeof(linebuf)); | ||
418 | if (len == 0) | ||
419 | return NULL; | ||
420 | |||
421 | pos = 0; | ||
422 | for (i = 0; i < len; i++) { | ||
423 | if (i == len || linebuf[i] == ' ' || linebuf[i] == '\n') { | ||
424 | if (i - pos < 1) | ||
425 | continue; | ||
426 | if (i - pos >= SYSFS_PATH_MAX) | ||
427 | goto error_out; | ||
428 | if (current) { | ||
429 | current->next = malloc(sizeof(*current)); | ||
430 | if (!current->next) | ||
431 | goto error_out; | ||
432 | current = current->next; | ||
433 | } else { | ||
434 | first = malloc(sizeof(*first)); | ||
435 | if (!first) | ||
436 | goto error_out; | ||
437 | current = first; | ||
438 | } | ||
439 | current->first = first; | ||
440 | current->next = NULL; | ||
441 | |||
442 | memcpy(one_value, linebuf + pos, i - pos); | ||
443 | one_value[i - pos] = '\0'; | ||
444 | |||
445 | if (sscanf(one_value, "%u", ¤t->cpu) != 1) | ||
446 | goto error_out; | ||
447 | |||
448 | pos = i + 1; | ||
449 | } | ||
450 | } | ||
451 | |||
452 | return first; | ||
453 | |||
454 | error_out: | ||
455 | while (first) { | ||
456 | current = first->next; | ||
457 | free(first); | ||
458 | first = current; | ||
459 | } | ||
460 | return NULL; | ||
461 | } | ||
117 | 462 | ||
118 | struct cpufreq_affected_cpus *cpufreq_get_affected_cpus(unsigned int cpu) | 463 | struct cpufreq_affected_cpus *cpufreq_get_affected_cpus(unsigned int cpu) |
119 | { | 464 | { |
120 | return sysfs_get_freq_affected_cpus(cpu); | 465 | return sysfs_get_cpu_list(cpu, "affected_cpus"); |
121 | } | 466 | } |
122 | 467 | ||
123 | void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *any) | 468 | void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *any) |
@@ -138,7 +483,7 @@ void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *any) | |||
138 | 483 | ||
139 | struct cpufreq_affected_cpus *cpufreq_get_related_cpus(unsigned int cpu) | 484 | struct cpufreq_affected_cpus *cpufreq_get_related_cpus(unsigned int cpu) |
140 | { | 485 | { |
141 | return sysfs_get_freq_related_cpus(cpu); | 486 | return sysfs_get_cpu_list(cpu, "related_cpus"); |
142 | } | 487 | } |
143 | 488 | ||
144 | void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *any) | 489 | void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *any) |
@@ -146,45 +491,208 @@ void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *any) | |||
146 | cpufreq_put_affected_cpus(any); | 491 | cpufreq_put_affected_cpus(any); |
147 | } | 492 | } |
148 | 493 | ||
494 | static int verify_gov(char *new_gov, char *passed_gov) | ||
495 | { | ||
496 | unsigned int i, j = 0; | ||
497 | |||
498 | if (!passed_gov || (strlen(passed_gov) > 19)) | ||
499 | return -EINVAL; | ||
500 | |||
501 | strncpy(new_gov, passed_gov, 20); | ||
502 | for (i = 0; i < 20; i++) { | ||
503 | if (j) { | ||
504 | new_gov[i] = '\0'; | ||
505 | continue; | ||
506 | } | ||
507 | if ((new_gov[i] >= 'a') && (new_gov[i] <= 'z')) | ||
508 | continue; | ||
509 | |||
510 | if ((new_gov[i] >= 'A') && (new_gov[i] <= 'Z')) | ||
511 | continue; | ||
512 | |||
513 | if (new_gov[i] == '-') | ||
514 | continue; | ||
515 | |||
516 | if (new_gov[i] == '_') | ||
517 | continue; | ||
518 | |||
519 | if (new_gov[i] == '\0') { | ||
520 | j = 1; | ||
521 | continue; | ||
522 | } | ||
523 | return -EINVAL; | ||
524 | } | ||
525 | new_gov[19] = '\0'; | ||
526 | return 0; | ||
527 | } | ||
149 | 528 | ||
150 | int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy) | 529 | int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy) |
151 | { | 530 | { |
531 | char min[SYSFS_PATH_MAX]; | ||
532 | char max[SYSFS_PATH_MAX]; | ||
533 | char gov[SYSFS_PATH_MAX]; | ||
534 | int ret; | ||
535 | unsigned long old_min; | ||
536 | int write_max_first; | ||
537 | |||
152 | if (!policy || !(policy->governor)) | 538 | if (!policy || !(policy->governor)) |
153 | return -EINVAL; | 539 | return -EINVAL; |
154 | 540 | ||
155 | return sysfs_set_freq_policy(cpu, policy); | 541 | if (policy->max < policy->min) |
542 | return -EINVAL; | ||
543 | |||
544 | if (verify_gov(gov, policy->governor)) | ||
545 | return -EINVAL; | ||
546 | |||
547 | snprintf(min, SYSFS_PATH_MAX, "%lu", policy->min); | ||
548 | snprintf(max, SYSFS_PATH_MAX, "%lu", policy->max); | ||
549 | |||
550 | old_min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ); | ||
551 | write_max_first = (old_min && (policy->max < old_min) ? 0 : 1); | ||
552 | |||
553 | if (write_max_first) { | ||
554 | ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, | ||
555 | max, strlen(max)); | ||
556 | if (ret) | ||
557 | return ret; | ||
558 | } | ||
559 | |||
560 | ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, min, | ||
561 | strlen(min)); | ||
562 | if (ret) | ||
563 | return ret; | ||
564 | |||
565 | if (!write_max_first) { | ||
566 | ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, | ||
567 | max, strlen(max)); | ||
568 | if (ret) | ||
569 | return ret; | ||
570 | } | ||
571 | |||
572 | return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR, | ||
573 | gov, strlen(gov)); | ||
156 | } | 574 | } |
157 | 575 | ||
158 | 576 | ||
159 | int cpufreq_modify_policy_min(unsigned int cpu, unsigned long min_freq) | 577 | int cpufreq_modify_policy_min(unsigned int cpu, unsigned long min_freq) |
160 | { | 578 | { |
161 | return sysfs_modify_freq_policy_min(cpu, min_freq); | 579 | char value[SYSFS_PATH_MAX]; |
580 | |||
581 | snprintf(value, SYSFS_PATH_MAX, "%lu", min_freq); | ||
582 | |||
583 | return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, | ||
584 | value, strlen(value)); | ||
162 | } | 585 | } |
163 | 586 | ||
164 | 587 | ||
165 | int cpufreq_modify_policy_max(unsigned int cpu, unsigned long max_freq) | 588 | int cpufreq_modify_policy_max(unsigned int cpu, unsigned long max_freq) |
166 | { | 589 | { |
167 | return sysfs_modify_freq_policy_max(cpu, max_freq); | 590 | char value[SYSFS_PATH_MAX]; |
168 | } | 591 | |
592 | snprintf(value, SYSFS_PATH_MAX, "%lu", max_freq); | ||
169 | 593 | ||
594 | return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, | ||
595 | value, strlen(value)); | ||
596 | } | ||
170 | 597 | ||
171 | int cpufreq_modify_policy_governor(unsigned int cpu, char *governor) | 598 | int cpufreq_modify_policy_governor(unsigned int cpu, char *governor) |
172 | { | 599 | { |
600 | char new_gov[SYSFS_PATH_MAX]; | ||
601 | |||
173 | if ((!governor) || (strlen(governor) > 19)) | 602 | if ((!governor) || (strlen(governor) > 19)) |
174 | return -EINVAL; | 603 | return -EINVAL; |
175 | 604 | ||
176 | return sysfs_modify_freq_policy_governor(cpu, governor); | 605 | if (verify_gov(new_gov, governor)) |
606 | return -EINVAL; | ||
607 | |||
608 | return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR, | ||
609 | new_gov, strlen(new_gov)); | ||
177 | } | 610 | } |
178 | 611 | ||
179 | int cpufreq_set_frequency(unsigned int cpu, unsigned long target_frequency) | 612 | int cpufreq_set_frequency(unsigned int cpu, unsigned long target_frequency) |
180 | { | 613 | { |
181 | return sysfs_set_frequency(cpu, target_frequency); | 614 | struct cpufreq_policy *pol = cpufreq_get_policy(cpu); |
615 | char userspace_gov[] = "userspace"; | ||
616 | char freq[SYSFS_PATH_MAX]; | ||
617 | int ret; | ||
618 | |||
619 | if (!pol) | ||
620 | return -ENODEV; | ||
621 | |||
622 | if (strncmp(pol->governor, userspace_gov, 9) != 0) { | ||
623 | ret = cpufreq_modify_policy_governor(cpu, userspace_gov); | ||
624 | if (ret) { | ||
625 | cpufreq_put_policy(pol); | ||
626 | return ret; | ||
627 | } | ||
628 | } | ||
629 | |||
630 | cpufreq_put_policy(pol); | ||
631 | |||
632 | snprintf(freq, SYSFS_PATH_MAX, "%lu", target_frequency); | ||
633 | |||
634 | return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_SET_SPEED, | ||
635 | freq, strlen(freq)); | ||
182 | } | 636 | } |
183 | 637 | ||
184 | struct cpufreq_stats *cpufreq_get_stats(unsigned int cpu, | 638 | struct cpufreq_stats *cpufreq_get_stats(unsigned int cpu, |
185 | unsigned long long *total_time) | 639 | unsigned long long *total_time) |
186 | { | 640 | { |
187 | return sysfs_get_freq_stats(cpu, total_time); | 641 | struct cpufreq_stats *first = NULL; |
642 | struct cpufreq_stats *current = NULL; | ||
643 | char one_value[SYSFS_PATH_MAX]; | ||
644 | char linebuf[MAX_LINE_LEN]; | ||
645 | unsigned int pos, i; | ||
646 | unsigned int len; | ||
647 | |||
648 | len = sysfs_cpufreq_read_file(cpu, "stats/time_in_state", | ||
649 | linebuf, sizeof(linebuf)); | ||
650 | if (len == 0) | ||
651 | return NULL; | ||
652 | |||
653 | *total_time = 0; | ||
654 | pos = 0; | ||
655 | for (i = 0; i < len; i++) { | ||
656 | if (i == strlen(linebuf) || linebuf[i] == '\n') { | ||
657 | if (i - pos < 2) | ||
658 | continue; | ||
659 | if ((i - pos) >= SYSFS_PATH_MAX) | ||
660 | goto error_out; | ||
661 | if (current) { | ||
662 | current->next = malloc(sizeof(*current)); | ||
663 | if (!current->next) | ||
664 | goto error_out; | ||
665 | current = current->next; | ||
666 | } else { | ||
667 | first = malloc(sizeof(*first)); | ||
668 | if (!first) | ||
669 | goto error_out; | ||
670 | current = first; | ||
671 | } | ||
672 | current->first = first; | ||
673 | current->next = NULL; | ||
674 | |||
675 | memcpy(one_value, linebuf + pos, i - pos); | ||
676 | one_value[i - pos] = '\0'; | ||
677 | if (sscanf(one_value, "%lu %llu", | ||
678 | ¤t->frequency, | ||
679 | ¤t->time_in_state) != 2) | ||
680 | goto error_out; | ||
681 | |||
682 | *total_time = *total_time + current->time_in_state; | ||
683 | pos = i + 1; | ||
684 | } | ||
685 | } | ||
686 | |||
687 | return first; | ||
688 | |||
689 | error_out: | ||
690 | while (first) { | ||
691 | current = first->next; | ||
692 | free(first); | ||
693 | first = current; | ||
694 | } | ||
695 | return NULL; | ||
188 | } | 696 | } |
189 | 697 | ||
190 | void cpufreq_put_stats(struct cpufreq_stats *any) | 698 | void cpufreq_put_stats(struct cpufreq_stats *any) |
@@ -204,5 +712,5 @@ void cpufreq_put_stats(struct cpufreq_stats *any) | |||
204 | 712 | ||
205 | unsigned long cpufreq_get_transitions(unsigned int cpu) | 713 | unsigned long cpufreq_get_transitions(unsigned int cpu) |
206 | { | 714 | { |
207 | return sysfs_get_freq_transitions(cpu); | 715 | return sysfs_cpufreq_get_one_value(cpu, STATS_NUM_TRANSITIONS); |
208 | } | 716 | } |
diff --git a/tools/power/cpupower/lib/cpufreq.h b/tools/power/cpupower/lib/cpufreq.h index 3aae8e7a0839..3b005c39f068 100644 --- a/tools/power/cpupower/lib/cpufreq.h +++ b/tools/power/cpupower/lib/cpufreq.h | |||
@@ -17,8 +17,8 @@ | |||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
18 | */ | 18 | */ |
19 | 19 | ||
20 | #ifndef _CPUFREQ_H | 20 | #ifndef __CPUPOWER_CPUFREQ_H__ |
21 | #define _CPUFREQ_H 1 | 21 | #define __CPUPOWER_CPUFREQ_H__ |
22 | 22 | ||
23 | struct cpufreq_policy { | 23 | struct cpufreq_policy { |
24 | unsigned long min; | 24 | unsigned long min; |
@@ -58,13 +58,6 @@ struct cpufreq_stats { | |||
58 | extern "C" { | 58 | extern "C" { |
59 | #endif | 59 | #endif |
60 | 60 | ||
61 | /* | ||
62 | * returns 0 if the specified CPU is present (it doesn't say | ||
63 | * whether it is online!), and an error value if not. | ||
64 | */ | ||
65 | |||
66 | extern int cpufreq_cpu_exists(unsigned int cpu); | ||
67 | |||
68 | /* determine current CPU frequency | 61 | /* determine current CPU frequency |
69 | * - _kernel variant means kernel's opinion of CPU frequency | 62 | * - _kernel variant means kernel's opinion of CPU frequency |
70 | * - _hardware variant means actual hardware CPU frequency, | 63 | * - _hardware variant means actual hardware CPU frequency, |
@@ -73,9 +66,9 @@ extern int cpufreq_cpu_exists(unsigned int cpu); | |||
73 | * returns 0 on failure, else frequency in kHz. | 66 | * returns 0 on failure, else frequency in kHz. |
74 | */ | 67 | */ |
75 | 68 | ||
76 | extern unsigned long cpufreq_get_freq_kernel(unsigned int cpu); | 69 | unsigned long cpufreq_get_freq_kernel(unsigned int cpu); |
77 | 70 | ||
78 | extern unsigned long cpufreq_get_freq_hardware(unsigned int cpu); | 71 | unsigned long cpufreq_get_freq_hardware(unsigned int cpu); |
79 | 72 | ||
80 | #define cpufreq_get(cpu) cpufreq_get_freq_kernel(cpu); | 73 | #define cpufreq_get(cpu) cpufreq_get_freq_kernel(cpu); |
81 | 74 | ||
@@ -84,7 +77,7 @@ extern unsigned long cpufreq_get_freq_hardware(unsigned int cpu); | |||
84 | * | 77 | * |
85 | * returns 0 on failure, else transition latency in 10^(-9) s = nanoseconds | 78 | * returns 0 on failure, else transition latency in 10^(-9) s = nanoseconds |
86 | */ | 79 | */ |
87 | extern unsigned long cpufreq_get_transition_latency(unsigned int cpu); | 80 | unsigned long cpufreq_get_transition_latency(unsigned int cpu); |
88 | 81 | ||
89 | 82 | ||
90 | /* determine hardware CPU frequency limits | 83 | /* determine hardware CPU frequency limits |
@@ -93,7 +86,7 @@ extern unsigned long cpufreq_get_transition_latency(unsigned int cpu); | |||
93 | * considerations by cpufreq policy notifiers in the kernel. | 86 | * considerations by cpufreq policy notifiers in the kernel. |
94 | */ | 87 | */ |
95 | 88 | ||
96 | extern int cpufreq_get_hardware_limits(unsigned int cpu, | 89 | int cpufreq_get_hardware_limits(unsigned int cpu, |
97 | unsigned long *min, | 90 | unsigned long *min, |
98 | unsigned long *max); | 91 | unsigned long *max); |
99 | 92 | ||
@@ -104,9 +97,9 @@ extern int cpufreq_get_hardware_limits(unsigned int cpu, | |||
104 | * to avoid memory leakage, please. | 97 | * to avoid memory leakage, please. |
105 | */ | 98 | */ |
106 | 99 | ||
107 | extern char *cpufreq_get_driver(unsigned int cpu); | 100 | char *cpufreq_get_driver(unsigned int cpu); |
108 | 101 | ||
109 | extern void cpufreq_put_driver(char *ptr); | 102 | void cpufreq_put_driver(char *ptr); |
110 | 103 | ||
111 | 104 | ||
112 | /* determine CPUfreq policy currently used | 105 | /* determine CPUfreq policy currently used |
@@ -116,9 +109,9 @@ extern void cpufreq_put_driver(char *ptr); | |||
116 | */ | 109 | */ |
117 | 110 | ||
118 | 111 | ||
119 | extern struct cpufreq_policy *cpufreq_get_policy(unsigned int cpu); | 112 | struct cpufreq_policy *cpufreq_get_policy(unsigned int cpu); |
120 | 113 | ||
121 | extern void cpufreq_put_policy(struct cpufreq_policy *policy); | 114 | void cpufreq_put_policy(struct cpufreq_policy *policy); |
122 | 115 | ||
123 | 116 | ||
124 | /* determine CPUfreq governors currently available | 117 | /* determine CPUfreq governors currently available |
@@ -129,10 +122,10 @@ extern void cpufreq_put_policy(struct cpufreq_policy *policy); | |||
129 | */ | 122 | */ |
130 | 123 | ||
131 | 124 | ||
132 | extern struct cpufreq_available_governors | 125 | struct cpufreq_available_governors |
133 | *cpufreq_get_available_governors(unsigned int cpu); | 126 | *cpufreq_get_available_governors(unsigned int cpu); |
134 | 127 | ||
135 | extern void cpufreq_put_available_governors( | 128 | void cpufreq_put_available_governors( |
136 | struct cpufreq_available_governors *first); | 129 | struct cpufreq_available_governors *first); |
137 | 130 | ||
138 | 131 | ||
@@ -143,10 +136,10 @@ extern void cpufreq_put_available_governors( | |||
143 | * cpufreq_put_available_frequencies after use. | 136 | * cpufreq_put_available_frequencies after use. |
144 | */ | 137 | */ |
145 | 138 | ||
146 | extern struct cpufreq_available_frequencies | 139 | struct cpufreq_available_frequencies |
147 | *cpufreq_get_available_frequencies(unsigned int cpu); | 140 | *cpufreq_get_available_frequencies(unsigned int cpu); |
148 | 141 | ||
149 | extern void cpufreq_put_available_frequencies( | 142 | void cpufreq_put_available_frequencies( |
150 | struct cpufreq_available_frequencies *first); | 143 | struct cpufreq_available_frequencies *first); |
151 | 144 | ||
152 | 145 | ||
@@ -156,10 +149,10 @@ extern void cpufreq_put_available_frequencies( | |||
156 | * to avoid memory leakage, please. | 149 | * to avoid memory leakage, please. |
157 | */ | 150 | */ |
158 | 151 | ||
159 | extern struct cpufreq_affected_cpus *cpufreq_get_affected_cpus(unsigned | 152 | struct cpufreq_affected_cpus *cpufreq_get_affected_cpus(unsigned |
160 | int cpu); | 153 | int cpu); |
161 | 154 | ||
162 | extern void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *first); | 155 | void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *first); |
163 | 156 | ||
164 | 157 | ||
165 | /* determine related CPUs | 158 | /* determine related CPUs |
@@ -168,10 +161,10 @@ extern void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *first); | |||
168 | * to avoid memory leakage, please. | 161 | * to avoid memory leakage, please. |
169 | */ | 162 | */ |
170 | 163 | ||
171 | extern struct cpufreq_affected_cpus *cpufreq_get_related_cpus(unsigned | 164 | struct cpufreq_affected_cpus *cpufreq_get_related_cpus(unsigned |
172 | int cpu); | 165 | int cpu); |
173 | 166 | ||
174 | extern void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *first); | 167 | void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *first); |
175 | 168 | ||
176 | 169 | ||
177 | /* determine stats for cpufreq subsystem | 170 | /* determine stats for cpufreq subsystem |
@@ -179,12 +172,12 @@ extern void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *first); | |||
179 | * This is not available in all kernel versions or configurations. | 172 | * This is not available in all kernel versions or configurations. |
180 | */ | 173 | */ |
181 | 174 | ||
182 | extern struct cpufreq_stats *cpufreq_get_stats(unsigned int cpu, | 175 | struct cpufreq_stats *cpufreq_get_stats(unsigned int cpu, |
183 | unsigned long long *total_time); | 176 | unsigned long long *total_time); |
184 | 177 | ||
185 | extern void cpufreq_put_stats(struct cpufreq_stats *stats); | 178 | void cpufreq_put_stats(struct cpufreq_stats *stats); |
186 | 179 | ||
187 | extern unsigned long cpufreq_get_transitions(unsigned int cpu); | 180 | unsigned long cpufreq_get_transitions(unsigned int cpu); |
188 | 181 | ||
189 | 182 | ||
190 | /* set new cpufreq policy | 183 | /* set new cpufreq policy |
@@ -193,7 +186,7 @@ extern unsigned long cpufreq_get_transitions(unsigned int cpu); | |||
193 | * but results may differ depending e.g. on governors being available. | 186 | * but results may differ depending e.g. on governors being available. |
194 | */ | 187 | */ |
195 | 188 | ||
196 | extern int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy); | 189 | int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy); |
197 | 190 | ||
198 | 191 | ||
199 | /* modify a policy by only changing min/max freq or governor | 192 | /* modify a policy by only changing min/max freq or governor |
@@ -201,9 +194,9 @@ extern int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy); | |||
201 | * Does not check whether result is what was intended. | 194 | * Does not check whether result is what was intended. |
202 | */ | 195 | */ |
203 | 196 | ||
204 | extern int cpufreq_modify_policy_min(unsigned int cpu, unsigned long min_freq); | 197 | int cpufreq_modify_policy_min(unsigned int cpu, unsigned long min_freq); |
205 | extern int cpufreq_modify_policy_max(unsigned int cpu, unsigned long max_freq); | 198 | int cpufreq_modify_policy_max(unsigned int cpu, unsigned long max_freq); |
206 | extern int cpufreq_modify_policy_governor(unsigned int cpu, char *governor); | 199 | int cpufreq_modify_policy_governor(unsigned int cpu, char *governor); |
207 | 200 | ||
208 | 201 | ||
209 | /* set a specific frequency | 202 | /* set a specific frequency |
@@ -213,7 +206,7 @@ extern int cpufreq_modify_policy_governor(unsigned int cpu, char *governor); | |||
213 | * occurs. Also does not work on ->range() cpufreq drivers. | 206 | * occurs. Also does not work on ->range() cpufreq drivers. |
214 | */ | 207 | */ |
215 | 208 | ||
216 | extern int cpufreq_set_frequency(unsigned int cpu, | 209 | int cpufreq_set_frequency(unsigned int cpu, |
217 | unsigned long target_frequency); | 210 | unsigned long target_frequency); |
218 | 211 | ||
219 | #ifdef __cplusplus | 212 | #ifdef __cplusplus |
diff --git a/tools/power/cpupower/lib/cpuidle.c b/tools/power/cpupower/lib/cpuidle.c new file mode 100644 index 000000000000..9bd4c7655fdb --- /dev/null +++ b/tools/power/cpupower/lib/cpuidle.c | |||
@@ -0,0 +1,380 @@ | |||
1 | /* | ||
2 | * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de> | ||
3 | * (C) 2011 Thomas Renninger <trenn@novell.com> Novell Inc. | ||
4 | * | ||
5 | * Licensed under the terms of the GNU GPL License version 2. | ||
6 | */ | ||
7 | |||
8 | #include <stdio.h> | ||
9 | #include <errno.h> | ||
10 | #include <stdlib.h> | ||
11 | #include <string.h> | ||
12 | #include <sys/types.h> | ||
13 | #include <sys/stat.h> | ||
14 | #include <fcntl.h> | ||
15 | #include <unistd.h> | ||
16 | |||
17 | #include "cpuidle.h" | ||
18 | #include "cpupower_intern.h" | ||
19 | |||
20 | /* | ||
21 | * helper function to check whether a file under "../cpuX/cpuidle/stateX/" dir | ||
22 | * exists. | ||
23 | * For example the functionality to disable c-states was introduced in later | ||
24 | * kernel versions, this function can be used to explicitly check for this | ||
25 | * feature. | ||
26 | * | ||
27 | * returns 1 if the file exists, 0 otherwise. | ||
28 | */ | ||
29 | static | ||
30 | unsigned int cpuidle_state_file_exists(unsigned int cpu, | ||
31 | unsigned int idlestate, | ||
32 | const char *fname) | ||
33 | { | ||
34 | char path[SYSFS_PATH_MAX]; | ||
35 | struct stat statbuf; | ||
36 | |||
37 | |||
38 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s", | ||
39 | cpu, idlestate, fname); | ||
40 | if (stat(path, &statbuf) != 0) | ||
41 | return 0; | ||
42 | return 1; | ||
43 | } | ||
44 | |||
45 | /* | ||
46 | * helper function to read file from /sys into given buffer | ||
47 | * fname is a relative path under "cpuX/cpuidle/stateX/" dir | ||
48 | * cstates starting with 0, C0 is not counted as cstate. | ||
49 | * This means if you want C1 info, pass 0 as idlestate param | ||
50 | */ | ||
51 | static | ||
52 | unsigned int cpuidle_state_read_file(unsigned int cpu, | ||
53 | unsigned int idlestate, | ||
54 | const char *fname, char *buf, | ||
55 | size_t buflen) | ||
56 | { | ||
57 | char path[SYSFS_PATH_MAX]; | ||
58 | int fd; | ||
59 | ssize_t numread; | ||
60 | |||
61 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s", | ||
62 | cpu, idlestate, fname); | ||
63 | |||
64 | fd = open(path, O_RDONLY); | ||
65 | if (fd == -1) | ||
66 | return 0; | ||
67 | |||
68 | numread = read(fd, buf, buflen - 1); | ||
69 | if (numread < 1) { | ||
70 | close(fd); | ||
71 | return 0; | ||
72 | } | ||
73 | |||
74 | buf[numread] = '\0'; | ||
75 | close(fd); | ||
76 | |||
77 | return (unsigned int) numread; | ||
78 | } | ||
79 | |||
80 | /* | ||
81 | * helper function to write a new value to a /sys file | ||
82 | * fname is a relative path under "../cpuX/cpuidle/cstateY/" dir | ||
83 | * | ||
84 | * Returns the number of bytes written or 0 on error | ||
85 | */ | ||
86 | static | ||
87 | unsigned int cpuidle_state_write_file(unsigned int cpu, | ||
88 | unsigned int idlestate, | ||
89 | const char *fname, | ||
90 | const char *value, size_t len) | ||
91 | { | ||
92 | char path[SYSFS_PATH_MAX]; | ||
93 | int fd; | ||
94 | ssize_t numwrite; | ||
95 | |||
96 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s", | ||
97 | cpu, idlestate, fname); | ||
98 | |||
99 | fd = open(path, O_WRONLY); | ||
100 | if (fd == -1) | ||
101 | return 0; | ||
102 | |||
103 | numwrite = write(fd, value, len); | ||
104 | if (numwrite < 1) { | ||
105 | close(fd); | ||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | close(fd); | ||
110 | |||
111 | return (unsigned int) numwrite; | ||
112 | } | ||
113 | |||
114 | /* read access to files which contain one numeric value */ | ||
115 | |||
116 | enum idlestate_value { | ||
117 | IDLESTATE_USAGE, | ||
118 | IDLESTATE_POWER, | ||
119 | IDLESTATE_LATENCY, | ||
120 | IDLESTATE_TIME, | ||
121 | IDLESTATE_DISABLE, | ||
122 | MAX_IDLESTATE_VALUE_FILES | ||
123 | }; | ||
124 | |||
125 | static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = { | ||
126 | [IDLESTATE_USAGE] = "usage", | ||
127 | [IDLESTATE_POWER] = "power", | ||
128 | [IDLESTATE_LATENCY] = "latency", | ||
129 | [IDLESTATE_TIME] = "time", | ||
130 | [IDLESTATE_DISABLE] = "disable", | ||
131 | }; | ||
132 | |||
133 | static | ||
134 | unsigned long long cpuidle_state_get_one_value(unsigned int cpu, | ||
135 | unsigned int idlestate, | ||
136 | enum idlestate_value which) | ||
137 | { | ||
138 | unsigned long long value; | ||
139 | unsigned int len; | ||
140 | char linebuf[MAX_LINE_LEN]; | ||
141 | char *endp; | ||
142 | |||
143 | if (which >= MAX_IDLESTATE_VALUE_FILES) | ||
144 | return 0; | ||
145 | |||
146 | len = cpuidle_state_read_file(cpu, idlestate, | ||
147 | idlestate_value_files[which], | ||
148 | linebuf, sizeof(linebuf)); | ||
149 | if (len == 0) | ||
150 | return 0; | ||
151 | |||
152 | value = strtoull(linebuf, &endp, 0); | ||
153 | |||
154 | if (endp == linebuf || errno == ERANGE) | ||
155 | return 0; | ||
156 | |||
157 | return value; | ||
158 | } | ||
159 | |||
160 | /* read access to files which contain one string */ | ||
161 | |||
162 | enum idlestate_string { | ||
163 | IDLESTATE_DESC, | ||
164 | IDLESTATE_NAME, | ||
165 | MAX_IDLESTATE_STRING_FILES | ||
166 | }; | ||
167 | |||
168 | static const char *idlestate_string_files[MAX_IDLESTATE_STRING_FILES] = { | ||
169 | [IDLESTATE_DESC] = "desc", | ||
170 | [IDLESTATE_NAME] = "name", | ||
171 | }; | ||
172 | |||
173 | |||
174 | static char *cpuidle_state_get_one_string(unsigned int cpu, | ||
175 | unsigned int idlestate, | ||
176 | enum idlestate_string which) | ||
177 | { | ||
178 | char linebuf[MAX_LINE_LEN]; | ||
179 | char *result; | ||
180 | unsigned int len; | ||
181 | |||
182 | if (which >= MAX_IDLESTATE_STRING_FILES) | ||
183 | return NULL; | ||
184 | |||
185 | len = cpuidle_state_read_file(cpu, idlestate, | ||
186 | idlestate_string_files[which], | ||
187 | linebuf, sizeof(linebuf)); | ||
188 | if (len == 0) | ||
189 | return NULL; | ||
190 | |||
191 | result = strdup(linebuf); | ||
192 | if (result == NULL) | ||
193 | return NULL; | ||
194 | |||
195 | if (result[strlen(result) - 1] == '\n') | ||
196 | result[strlen(result) - 1] = '\0'; | ||
197 | |||
198 | return result; | ||
199 | } | ||
200 | |||
201 | /* | ||
202 | * Returns: | ||
203 | * 1 if disabled | ||
204 | * 0 if enabled | ||
205 | * -1 if idlestate is not available | ||
206 | * -2 if disabling is not supported by the kernel | ||
207 | */ | ||
208 | int cpuidle_is_state_disabled(unsigned int cpu, | ||
209 | unsigned int idlestate) | ||
210 | { | ||
211 | if (cpuidle_state_count(cpu) <= idlestate) | ||
212 | return -1; | ||
213 | |||
214 | if (!cpuidle_state_file_exists(cpu, idlestate, | ||
215 | idlestate_value_files[IDLESTATE_DISABLE])) | ||
216 | return -2; | ||
217 | return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_DISABLE); | ||
218 | } | ||
219 | |||
220 | /* | ||
221 | * Pass 1 as last argument to disable or 0 to enable the state | ||
222 | * Returns: | ||
223 | * 0 on success | ||
224 | * negative values on error, for example: | ||
225 | * -1 if idlestate is not available | ||
226 | * -2 if disabling is not supported by the kernel | ||
227 | * -3 No write access to disable/enable C-states | ||
228 | */ | ||
229 | int cpuidle_state_disable(unsigned int cpu, | ||
230 | unsigned int idlestate, | ||
231 | unsigned int disable) | ||
232 | { | ||
233 | char value[SYSFS_PATH_MAX]; | ||
234 | int bytes_written; | ||
235 | |||
236 | if (cpuidle_state_count(cpu) <= idlestate) | ||
237 | return -1; | ||
238 | |||
239 | if (!cpuidle_state_file_exists(cpu, idlestate, | ||
240 | idlestate_value_files[IDLESTATE_DISABLE])) | ||
241 | return -2; | ||
242 | |||
243 | snprintf(value, SYSFS_PATH_MAX, "%u", disable); | ||
244 | |||
245 | bytes_written = cpuidle_state_write_file(cpu, idlestate, "disable", | ||
246 | value, sizeof(disable)); | ||
247 | if (bytes_written) | ||
248 | return 0; | ||
249 | return -3; | ||
250 | } | ||
251 | |||
252 | unsigned long cpuidle_state_latency(unsigned int cpu, | ||
253 | unsigned int idlestate) | ||
254 | { | ||
255 | return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_LATENCY); | ||
256 | } | ||
257 | |||
258 | unsigned long cpuidle_state_usage(unsigned int cpu, | ||
259 | unsigned int idlestate) | ||
260 | { | ||
261 | return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_USAGE); | ||
262 | } | ||
263 | |||
264 | unsigned long long cpuidle_state_time(unsigned int cpu, | ||
265 | unsigned int idlestate) | ||
266 | { | ||
267 | return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_TIME); | ||
268 | } | ||
269 | |||
270 | char *cpuidle_state_name(unsigned int cpu, unsigned int idlestate) | ||
271 | { | ||
272 | return cpuidle_state_get_one_string(cpu, idlestate, IDLESTATE_NAME); | ||
273 | } | ||
274 | |||
275 | char *cpuidle_state_desc(unsigned int cpu, unsigned int idlestate) | ||
276 | { | ||
277 | return cpuidle_state_get_one_string(cpu, idlestate, IDLESTATE_DESC); | ||
278 | } | ||
279 | |||
280 | /* | ||
281 | * Returns number of supported C-states of CPU core cpu | ||
282 | * Negativ in error case | ||
283 | * Zero if cpuidle does not export any C-states | ||
284 | */ | ||
285 | unsigned int cpuidle_state_count(unsigned int cpu) | ||
286 | { | ||
287 | char file[SYSFS_PATH_MAX]; | ||
288 | struct stat statbuf; | ||
289 | int idlestates = 1; | ||
290 | |||
291 | |||
292 | snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpuidle"); | ||
293 | if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) | ||
294 | return 0; | ||
295 | |||
296 | snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/cpuidle/state0", cpu); | ||
297 | if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) | ||
298 | return 0; | ||
299 | |||
300 | while (stat(file, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) { | ||
301 | snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU | ||
302 | "cpu%u/cpuidle/state%d", cpu, idlestates); | ||
303 | idlestates++; | ||
304 | } | ||
305 | idlestates--; | ||
306 | return idlestates; | ||
307 | } | ||
308 | |||
309 | /* CPUidle general /sys/devices/system/cpu/cpuidle/ sysfs access ********/ | ||
310 | |||
311 | /* | ||
312 | * helper function to read file from /sys into given buffer | ||
313 | * fname is a relative path under "cpu/cpuidle/" dir | ||
314 | */ | ||
315 | static unsigned int sysfs_cpuidle_read_file(const char *fname, char *buf, | ||
316 | size_t buflen) | ||
317 | { | ||
318 | char path[SYSFS_PATH_MAX]; | ||
319 | |||
320 | snprintf(path, sizeof(path), PATH_TO_CPU "cpuidle/%s", fname); | ||
321 | |||
322 | return sysfs_read_file(path, buf, buflen); | ||
323 | } | ||
324 | |||
325 | |||
326 | |||
327 | /* read access to files which contain one string */ | ||
328 | |||
329 | enum cpuidle_string { | ||
330 | CPUIDLE_GOVERNOR, | ||
331 | CPUIDLE_GOVERNOR_RO, | ||
332 | CPUIDLE_DRIVER, | ||
333 | MAX_CPUIDLE_STRING_FILES | ||
334 | }; | ||
335 | |||
336 | static const char *cpuidle_string_files[MAX_CPUIDLE_STRING_FILES] = { | ||
337 | [CPUIDLE_GOVERNOR] = "current_governor", | ||
338 | [CPUIDLE_GOVERNOR_RO] = "current_governor_ro", | ||
339 | [CPUIDLE_DRIVER] = "current_driver", | ||
340 | }; | ||
341 | |||
342 | |||
343 | static char *sysfs_cpuidle_get_one_string(enum cpuidle_string which) | ||
344 | { | ||
345 | char linebuf[MAX_LINE_LEN]; | ||
346 | char *result; | ||
347 | unsigned int len; | ||
348 | |||
349 | if (which >= MAX_CPUIDLE_STRING_FILES) | ||
350 | return NULL; | ||
351 | |||
352 | len = sysfs_cpuidle_read_file(cpuidle_string_files[which], | ||
353 | linebuf, sizeof(linebuf)); | ||
354 | if (len == 0) | ||
355 | return NULL; | ||
356 | |||
357 | result = strdup(linebuf); | ||
358 | if (result == NULL) | ||
359 | return NULL; | ||
360 | |||
361 | if (result[strlen(result) - 1] == '\n') | ||
362 | result[strlen(result) - 1] = '\0'; | ||
363 | |||
364 | return result; | ||
365 | } | ||
366 | |||
367 | char *cpuidle_get_governor(void) | ||
368 | { | ||
369 | char *tmp = sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR_RO); | ||
370 | if (!tmp) | ||
371 | return sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR); | ||
372 | else | ||
373 | return tmp; | ||
374 | } | ||
375 | |||
376 | char *cpuidle_get_driver(void) | ||
377 | { | ||
378 | return sysfs_cpuidle_get_one_string(CPUIDLE_DRIVER); | ||
379 | } | ||
380 | /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */ | ||
diff --git a/tools/power/cpupower/lib/cpuidle.h b/tools/power/cpupower/lib/cpuidle.h new file mode 100644 index 000000000000..04eb3cfa6e42 --- /dev/null +++ b/tools/power/cpupower/lib/cpuidle.h | |||
@@ -0,0 +1,23 @@ | |||
1 | #ifndef __CPUPOWER_CPUIDLE_H__ | ||
2 | #define __CPUPOWER_CPUIDLE_H__ | ||
3 | |||
4 | int cpuidle_is_state_disabled(unsigned int cpu, | ||
5 | unsigned int idlestate); | ||
6 | int cpuidle_state_disable(unsigned int cpu, unsigned int idlestate, | ||
7 | unsigned int disable); | ||
8 | unsigned long cpuidle_state_latency(unsigned int cpu, | ||
9 | unsigned int idlestate); | ||
10 | unsigned long cpuidle_state_usage(unsigned int cpu, | ||
11 | unsigned int idlestate); | ||
12 | unsigned long long cpuidle_state_time(unsigned int cpu, | ||
13 | unsigned int idlestate); | ||
14 | char *cpuidle_state_name(unsigned int cpu, | ||
15 | unsigned int idlestate); | ||
16 | char *cpuidle_state_desc(unsigned int cpu, | ||
17 | unsigned int idlestate); | ||
18 | unsigned int cpuidle_state_count(unsigned int cpu); | ||
19 | |||
20 | char *cpuidle_get_governor(void); | ||
21 | char *cpuidle_get_driver(void); | ||
22 | |||
23 | #endif /* __CPUPOWER_HELPERS_SYSFS_H__ */ | ||
diff --git a/tools/power/cpupower/lib/cpupower.c b/tools/power/cpupower/lib/cpupower.c new file mode 100644 index 000000000000..9c395ec924de --- /dev/null +++ b/tools/power/cpupower/lib/cpupower.c | |||
@@ -0,0 +1,192 @@ | |||
1 | /* | ||
2 | * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de> | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | */ | ||
6 | |||
7 | #include <sys/types.h> | ||
8 | #include <sys/stat.h> | ||
9 | #include <fcntl.h> | ||
10 | #include <unistd.h> | ||
11 | #include <stdio.h> | ||
12 | #include <errno.h> | ||
13 | #include <stdlib.h> | ||
14 | |||
15 | #include "cpupower.h" | ||
16 | #include "cpupower_intern.h" | ||
17 | |||
18 | unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen) | ||
19 | { | ||
20 | int fd; | ||
21 | ssize_t numread; | ||
22 | |||
23 | fd = open(path, O_RDONLY); | ||
24 | if (fd == -1) | ||
25 | return 0; | ||
26 | |||
27 | numread = read(fd, buf, buflen - 1); | ||
28 | if (numread < 1) { | ||
29 | close(fd); | ||
30 | return 0; | ||
31 | } | ||
32 | |||
33 | buf[numread] = '\0'; | ||
34 | close(fd); | ||
35 | |||
36 | return (unsigned int) numread; | ||
37 | } | ||
38 | |||
39 | /* | ||
40 | * Detect whether a CPU is online | ||
41 | * | ||
42 | * Returns: | ||
43 | * 1 -> if CPU is online | ||
44 | * 0 -> if CPU is offline | ||
45 | * negative errno values in error case | ||
46 | */ | ||
47 | int cpupower_is_cpu_online(unsigned int cpu) | ||
48 | { | ||
49 | char path[SYSFS_PATH_MAX]; | ||
50 | int fd; | ||
51 | ssize_t numread; | ||
52 | unsigned long long value; | ||
53 | char linebuf[MAX_LINE_LEN]; | ||
54 | char *endp; | ||
55 | struct stat statbuf; | ||
56 | |||
57 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u", cpu); | ||
58 | |||
59 | if (stat(path, &statbuf) != 0) | ||
60 | return 0; | ||
61 | |||
62 | /* | ||
63 | * kernel without CONFIG_HOTPLUG_CPU | ||
64 | * -> cpuX directory exists, but not cpuX/online file | ||
65 | */ | ||
66 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/online", cpu); | ||
67 | if (stat(path, &statbuf) != 0) | ||
68 | return 1; | ||
69 | |||
70 | fd = open(path, O_RDONLY); | ||
71 | if (fd == -1) | ||
72 | return -errno; | ||
73 | |||
74 | numread = read(fd, linebuf, MAX_LINE_LEN - 1); | ||
75 | if (numread < 1) { | ||
76 | close(fd); | ||
77 | return -EIO; | ||
78 | } | ||
79 | linebuf[numread] = '\0'; | ||
80 | close(fd); | ||
81 | |||
82 | value = strtoull(linebuf, &endp, 0); | ||
83 | if (value > 1) | ||
84 | return -EINVAL; | ||
85 | |||
86 | return value; | ||
87 | } | ||
88 | |||
89 | /* returns -1 on failure, 0 on success */ | ||
90 | static int sysfs_topology_read_file(unsigned int cpu, const char *fname, int *result) | ||
91 | { | ||
92 | char linebuf[MAX_LINE_LEN]; | ||
93 | char *endp; | ||
94 | char path[SYSFS_PATH_MAX]; | ||
95 | |||
96 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/topology/%s", | ||
97 | cpu, fname); | ||
98 | if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0) | ||
99 | return -1; | ||
100 | *result = strtol(linebuf, &endp, 0); | ||
101 | if (endp == linebuf || errno == ERANGE) | ||
102 | return -1; | ||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static int __compare(const void *t1, const void *t2) | ||
107 | { | ||
108 | struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1; | ||
109 | struct cpuid_core_info *top2 = (struct cpuid_core_info *)t2; | ||
110 | if (top1->pkg < top2->pkg) | ||
111 | return -1; | ||
112 | else if (top1->pkg > top2->pkg) | ||
113 | return 1; | ||
114 | else if (top1->core < top2->core) | ||
115 | return -1; | ||
116 | else if (top1->core > top2->core) | ||
117 | return 1; | ||
118 | else if (top1->cpu < top2->cpu) | ||
119 | return -1; | ||
120 | else if (top1->cpu > top2->cpu) | ||
121 | return 1; | ||
122 | else | ||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | /* | ||
127 | * Returns amount of cpus, negative on error, cpu_top must be | ||
128 | * passed to cpu_topology_release to free resources | ||
129 | * | ||
130 | * Array is sorted after ->pkg, ->core, then ->cpu | ||
131 | */ | ||
132 | int get_cpu_topology(struct cpupower_topology *cpu_top) | ||
133 | { | ||
134 | int cpu, last_pkg, cpus = sysconf(_SC_NPROCESSORS_CONF); | ||
135 | |||
136 | cpu_top->core_info = malloc(sizeof(struct cpuid_core_info) * cpus); | ||
137 | if (cpu_top->core_info == NULL) | ||
138 | return -ENOMEM; | ||
139 | cpu_top->pkgs = cpu_top->cores = 0; | ||
140 | for (cpu = 0; cpu < cpus; cpu++) { | ||
141 | cpu_top->core_info[cpu].cpu = cpu; | ||
142 | cpu_top->core_info[cpu].is_online = cpupower_is_cpu_online(cpu); | ||
143 | if(sysfs_topology_read_file( | ||
144 | cpu, | ||
145 | "physical_package_id", | ||
146 | &(cpu_top->core_info[cpu].pkg)) < 0) { | ||
147 | cpu_top->core_info[cpu].pkg = -1; | ||
148 | cpu_top->core_info[cpu].core = -1; | ||
149 | continue; | ||
150 | } | ||
151 | if(sysfs_topology_read_file( | ||
152 | cpu, | ||
153 | "core_id", | ||
154 | &(cpu_top->core_info[cpu].core)) < 0) { | ||
155 | cpu_top->core_info[cpu].pkg = -1; | ||
156 | cpu_top->core_info[cpu].core = -1; | ||
157 | continue; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info), | ||
162 | __compare); | ||
163 | |||
164 | /* Count the number of distinct pkgs values. This works | ||
165 | because the primary sort of the core_info struct was just | ||
166 | done by pkg value. */ | ||
167 | last_pkg = cpu_top->core_info[0].pkg; | ||
168 | for(cpu = 1; cpu < cpus; cpu++) { | ||
169 | if (cpu_top->core_info[cpu].pkg != last_pkg && | ||
170 | cpu_top->core_info[cpu].pkg != -1) { | ||
171 | |||
172 | last_pkg = cpu_top->core_info[cpu].pkg; | ||
173 | cpu_top->pkgs++; | ||
174 | } | ||
175 | } | ||
176 | if (!(cpu_top->core_info[0].pkg == -1)) | ||
177 | cpu_top->pkgs++; | ||
178 | |||
179 | /* Intel's cores count is not consecutively numbered, there may | ||
180 | * be a core_id of 3, but none of 2. Assume there always is 0 | ||
181 | * Get amount of cores by counting duplicates in a package | ||
182 | for (cpu = 0; cpu_top->core_info[cpu].pkg = 0 && cpu < cpus; cpu++) { | ||
183 | if (cpu_top->core_info[cpu].core == 0) | ||
184 | cpu_top->cores++; | ||
185 | */ | ||
186 | return cpus; | ||
187 | } | ||
188 | |||
189 | void cpu_topology_release(struct cpupower_topology cpu_top) | ||
190 | { | ||
191 | free(cpu_top.core_info); | ||
192 | } | ||
diff --git a/tools/power/cpupower/lib/cpupower.h b/tools/power/cpupower/lib/cpupower.h new file mode 100644 index 000000000000..fa031fcc7710 --- /dev/null +++ b/tools/power/cpupower/lib/cpupower.h | |||
@@ -0,0 +1,35 @@ | |||
1 | #ifndef __CPUPOWER_CPUPOWER_H__ | ||
2 | #define __CPUPOWER_CPUPOWER_H__ | ||
3 | |||
4 | struct cpupower_topology { | ||
5 | /* Amount of CPU cores, packages and threads per core in the system */ | ||
6 | unsigned int cores; | ||
7 | unsigned int pkgs; | ||
8 | unsigned int threads; /* per core */ | ||
9 | |||
10 | /* Array gets mallocated with cores entries, holding per core info */ | ||
11 | struct cpuid_core_info *core_info; | ||
12 | }; | ||
13 | |||
14 | struct cpuid_core_info { | ||
15 | int pkg; | ||
16 | int core; | ||
17 | int cpu; | ||
18 | |||
19 | /* flags */ | ||
20 | unsigned int is_online:1; | ||
21 | }; | ||
22 | |||
23 | #ifdef __cplusplus | ||
24 | extern "C" { | ||
25 | #endif | ||
26 | |||
27 | int get_cpu_topology(struct cpupower_topology *cpu_top); | ||
28 | void cpu_topology_release(struct cpupower_topology cpu_top); | ||
29 | int cpupower_is_cpu_online(unsigned int cpu); | ||
30 | |||
31 | #ifdef __cplusplus | ||
32 | } | ||
33 | #endif | ||
34 | |||
35 | #endif | ||
diff --git a/tools/power/cpupower/lib/cpupower_intern.h b/tools/power/cpupower/lib/cpupower_intern.h new file mode 100644 index 000000000000..f8ec4009621c --- /dev/null +++ b/tools/power/cpupower/lib/cpupower_intern.h | |||
@@ -0,0 +1,5 @@ | |||
1 | #define PATH_TO_CPU "/sys/devices/system/cpu/" | ||
2 | #define MAX_LINE_LEN 4096 | ||
3 | #define SYSFS_PATH_MAX 255 | ||
4 | |||
5 | unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen); | ||
diff --git a/tools/power/cpupower/lib/sysfs.c b/tools/power/cpupower/lib/sysfs.c deleted file mode 100644 index 870713a75a81..000000000000 --- a/tools/power/cpupower/lib/sysfs.c +++ /dev/null | |||
@@ -1,672 +0,0 @@ | |||
1 | /* | ||
2 | * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de> | ||
3 | * | ||
4 | * Licensed under the terms of the GNU GPL License version 2. | ||
5 | */ | ||
6 | |||
7 | #include <stdio.h> | ||
8 | #include <errno.h> | ||
9 | #include <stdlib.h> | ||
10 | #include <string.h> | ||
11 | #include <limits.h> | ||
12 | #include <sys/types.h> | ||
13 | #include <sys/stat.h> | ||
14 | #include <fcntl.h> | ||
15 | #include <unistd.h> | ||
16 | |||
17 | #include "cpufreq.h" | ||
18 | |||
19 | #define PATH_TO_CPU "/sys/devices/system/cpu/" | ||
20 | #define MAX_LINE_LEN 4096 | ||
21 | #define SYSFS_PATH_MAX 255 | ||
22 | |||
23 | |||
24 | static unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen) | ||
25 | { | ||
26 | int fd; | ||
27 | ssize_t numread; | ||
28 | |||
29 | fd = open(path, O_RDONLY); | ||
30 | if (fd == -1) | ||
31 | return 0; | ||
32 | |||
33 | numread = read(fd, buf, buflen - 1); | ||
34 | if (numread < 1) { | ||
35 | close(fd); | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | buf[numread] = '\0'; | ||
40 | close(fd); | ||
41 | |||
42 | return (unsigned int) numread; | ||
43 | } | ||
44 | |||
45 | |||
46 | /* CPUFREQ sysfs access **************************************************/ | ||
47 | |||
48 | /* helper function to read file from /sys into given buffer */ | ||
49 | /* fname is a relative path under "cpuX/cpufreq" dir */ | ||
50 | static unsigned int sysfs_cpufreq_read_file(unsigned int cpu, const char *fname, | ||
51 | char *buf, size_t buflen) | ||
52 | { | ||
53 | char path[SYSFS_PATH_MAX]; | ||
54 | |||
55 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s", | ||
56 | cpu, fname); | ||
57 | return sysfs_read_file(path, buf, buflen); | ||
58 | } | ||
59 | |||
60 | /* helper function to write a new value to a /sys file */ | ||
61 | /* fname is a relative path under "cpuX/cpufreq" dir */ | ||
62 | static unsigned int sysfs_cpufreq_write_file(unsigned int cpu, | ||
63 | const char *fname, | ||
64 | const char *value, size_t len) | ||
65 | { | ||
66 | char path[SYSFS_PATH_MAX]; | ||
67 | int fd; | ||
68 | ssize_t numwrite; | ||
69 | |||
70 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s", | ||
71 | cpu, fname); | ||
72 | |||
73 | fd = open(path, O_WRONLY); | ||
74 | if (fd == -1) | ||
75 | return 0; | ||
76 | |||
77 | numwrite = write(fd, value, len); | ||
78 | if (numwrite < 1) { | ||
79 | close(fd); | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | close(fd); | ||
84 | |||
85 | return (unsigned int) numwrite; | ||
86 | } | ||
87 | |||
88 | /* read access to files which contain one numeric value */ | ||
89 | |||
90 | enum cpufreq_value { | ||
91 | CPUINFO_CUR_FREQ, | ||
92 | CPUINFO_MIN_FREQ, | ||
93 | CPUINFO_MAX_FREQ, | ||
94 | CPUINFO_LATENCY, | ||
95 | SCALING_CUR_FREQ, | ||
96 | SCALING_MIN_FREQ, | ||
97 | SCALING_MAX_FREQ, | ||
98 | STATS_NUM_TRANSITIONS, | ||
99 | MAX_CPUFREQ_VALUE_READ_FILES | ||
100 | }; | ||
101 | |||
102 | static const char *cpufreq_value_files[MAX_CPUFREQ_VALUE_READ_FILES] = { | ||
103 | [CPUINFO_CUR_FREQ] = "cpuinfo_cur_freq", | ||
104 | [CPUINFO_MIN_FREQ] = "cpuinfo_min_freq", | ||
105 | [CPUINFO_MAX_FREQ] = "cpuinfo_max_freq", | ||
106 | [CPUINFO_LATENCY] = "cpuinfo_transition_latency", | ||
107 | [SCALING_CUR_FREQ] = "scaling_cur_freq", | ||
108 | [SCALING_MIN_FREQ] = "scaling_min_freq", | ||
109 | [SCALING_MAX_FREQ] = "scaling_max_freq", | ||
110 | [STATS_NUM_TRANSITIONS] = "stats/total_trans" | ||
111 | }; | ||
112 | |||
113 | |||
114 | static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu, | ||
115 | enum cpufreq_value which) | ||
116 | { | ||
117 | unsigned long value; | ||
118 | unsigned int len; | ||
119 | char linebuf[MAX_LINE_LEN]; | ||
120 | char *endp; | ||
121 | |||
122 | if (which >= MAX_CPUFREQ_VALUE_READ_FILES) | ||
123 | return 0; | ||
124 | |||
125 | len = sysfs_cpufreq_read_file(cpu, cpufreq_value_files[which], | ||
126 | linebuf, sizeof(linebuf)); | ||
127 | |||
128 | if (len == 0) | ||
129 | return 0; | ||
130 | |||
131 | value = strtoul(linebuf, &endp, 0); | ||
132 | |||
133 | if (endp == linebuf || errno == ERANGE) | ||
134 | return 0; | ||
135 | |||
136 | return value; | ||
137 | } | ||
138 | |||
139 | /* read access to files which contain one string */ | ||
140 | |||
141 | enum cpufreq_string { | ||
142 | SCALING_DRIVER, | ||
143 | SCALING_GOVERNOR, | ||
144 | MAX_CPUFREQ_STRING_FILES | ||
145 | }; | ||
146 | |||
147 | static const char *cpufreq_string_files[MAX_CPUFREQ_STRING_FILES] = { | ||
148 | [SCALING_DRIVER] = "scaling_driver", | ||
149 | [SCALING_GOVERNOR] = "scaling_governor", | ||
150 | }; | ||
151 | |||
152 | |||
153 | static char *sysfs_cpufreq_get_one_string(unsigned int cpu, | ||
154 | enum cpufreq_string which) | ||
155 | { | ||
156 | char linebuf[MAX_LINE_LEN]; | ||
157 | char *result; | ||
158 | unsigned int len; | ||
159 | |||
160 | if (which >= MAX_CPUFREQ_STRING_FILES) | ||
161 | return NULL; | ||
162 | |||
163 | len = sysfs_cpufreq_read_file(cpu, cpufreq_string_files[which], | ||
164 | linebuf, sizeof(linebuf)); | ||
165 | if (len == 0) | ||
166 | return NULL; | ||
167 | |||
168 | result = strdup(linebuf); | ||
169 | if (result == NULL) | ||
170 | return NULL; | ||
171 | |||
172 | if (result[strlen(result) - 1] == '\n') | ||
173 | result[strlen(result) - 1] = '\0'; | ||
174 | |||
175 | return result; | ||
176 | } | ||
177 | |||
178 | /* write access */ | ||
179 | |||
180 | enum cpufreq_write { | ||
181 | WRITE_SCALING_MIN_FREQ, | ||
182 | WRITE_SCALING_MAX_FREQ, | ||
183 | WRITE_SCALING_GOVERNOR, | ||
184 | WRITE_SCALING_SET_SPEED, | ||
185 | MAX_CPUFREQ_WRITE_FILES | ||
186 | }; | ||
187 | |||
188 | static const char *cpufreq_write_files[MAX_CPUFREQ_WRITE_FILES] = { | ||
189 | [WRITE_SCALING_MIN_FREQ] = "scaling_min_freq", | ||
190 | [WRITE_SCALING_MAX_FREQ] = "scaling_max_freq", | ||
191 | [WRITE_SCALING_GOVERNOR] = "scaling_governor", | ||
192 | [WRITE_SCALING_SET_SPEED] = "scaling_setspeed", | ||
193 | }; | ||
194 | |||
195 | static int sysfs_cpufreq_write_one_value(unsigned int cpu, | ||
196 | enum cpufreq_write which, | ||
197 | const char *new_value, size_t len) | ||
198 | { | ||
199 | if (which >= MAX_CPUFREQ_WRITE_FILES) | ||
200 | return 0; | ||
201 | |||
202 | if (sysfs_cpufreq_write_file(cpu, cpufreq_write_files[which], | ||
203 | new_value, len) != len) | ||
204 | return -ENODEV; | ||
205 | |||
206 | return 0; | ||
207 | }; | ||
208 | |||
209 | unsigned long sysfs_get_freq_kernel(unsigned int cpu) | ||
210 | { | ||
211 | return sysfs_cpufreq_get_one_value(cpu, SCALING_CUR_FREQ); | ||
212 | } | ||
213 | |||
214 | unsigned long sysfs_get_freq_hardware(unsigned int cpu) | ||
215 | { | ||
216 | return sysfs_cpufreq_get_one_value(cpu, CPUINFO_CUR_FREQ); | ||
217 | } | ||
218 | |||
219 | unsigned long sysfs_get_freq_transition_latency(unsigned int cpu) | ||
220 | { | ||
221 | return sysfs_cpufreq_get_one_value(cpu, CPUINFO_LATENCY); | ||
222 | } | ||
223 | |||
224 | int sysfs_get_freq_hardware_limits(unsigned int cpu, | ||
225 | unsigned long *min, | ||
226 | unsigned long *max) | ||
227 | { | ||
228 | if ((!min) || (!max)) | ||
229 | return -EINVAL; | ||
230 | |||
231 | *min = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MIN_FREQ); | ||
232 | if (!*min) | ||
233 | return -ENODEV; | ||
234 | |||
235 | *max = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MAX_FREQ); | ||
236 | if (!*max) | ||
237 | return -ENODEV; | ||
238 | |||
239 | return 0; | ||
240 | } | ||
241 | |||
242 | char *sysfs_get_freq_driver(unsigned int cpu) | ||
243 | { | ||
244 | return sysfs_cpufreq_get_one_string(cpu, SCALING_DRIVER); | ||
245 | } | ||
246 | |||
247 | struct cpufreq_policy *sysfs_get_freq_policy(unsigned int cpu) | ||
248 | { | ||
249 | struct cpufreq_policy *policy; | ||
250 | |||
251 | policy = malloc(sizeof(struct cpufreq_policy)); | ||
252 | if (!policy) | ||
253 | return NULL; | ||
254 | |||
255 | policy->governor = sysfs_cpufreq_get_one_string(cpu, SCALING_GOVERNOR); | ||
256 | if (!policy->governor) { | ||
257 | free(policy); | ||
258 | return NULL; | ||
259 | } | ||
260 | policy->min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ); | ||
261 | policy->max = sysfs_cpufreq_get_one_value(cpu, SCALING_MAX_FREQ); | ||
262 | if ((!policy->min) || (!policy->max)) { | ||
263 | free(policy->governor); | ||
264 | free(policy); | ||
265 | return NULL; | ||
266 | } | ||
267 | |||
268 | return policy; | ||
269 | } | ||
270 | |||
271 | struct cpufreq_available_governors * | ||
272 | sysfs_get_freq_available_governors(unsigned int cpu) { | ||
273 | struct cpufreq_available_governors *first = NULL; | ||
274 | struct cpufreq_available_governors *current = NULL; | ||
275 | char linebuf[MAX_LINE_LEN]; | ||
276 | unsigned int pos, i; | ||
277 | unsigned int len; | ||
278 | |||
279 | len = sysfs_cpufreq_read_file(cpu, "scaling_available_governors", | ||
280 | linebuf, sizeof(linebuf)); | ||
281 | if (len == 0) | ||
282 | return NULL; | ||
283 | |||
284 | pos = 0; | ||
285 | for (i = 0; i < len; i++) { | ||
286 | if (linebuf[i] == ' ' || linebuf[i] == '\n') { | ||
287 | if (i - pos < 2) | ||
288 | continue; | ||
289 | if (current) { | ||
290 | current->next = malloc(sizeof(*current)); | ||
291 | if (!current->next) | ||
292 | goto error_out; | ||
293 | current = current->next; | ||
294 | } else { | ||
295 | first = malloc(sizeof(*first)); | ||
296 | if (!first) | ||
297 | goto error_out; | ||
298 | current = first; | ||
299 | } | ||
300 | current->first = first; | ||
301 | current->next = NULL; | ||
302 | |||
303 | current->governor = malloc(i - pos + 1); | ||
304 | if (!current->governor) | ||
305 | goto error_out; | ||
306 | |||
307 | memcpy(current->governor, linebuf + pos, i - pos); | ||
308 | current->governor[i - pos] = '\0'; | ||
309 | pos = i + 1; | ||
310 | } | ||
311 | } | ||
312 | |||
313 | return first; | ||
314 | |||
315 | error_out: | ||
316 | while (first) { | ||
317 | current = first->next; | ||
318 | if (first->governor) | ||
319 | free(first->governor); | ||
320 | free(first); | ||
321 | first = current; | ||
322 | } | ||
323 | return NULL; | ||
324 | } | ||
325 | |||
326 | |||
327 | struct cpufreq_available_frequencies * | ||
328 | sysfs_get_available_frequencies(unsigned int cpu) { | ||
329 | struct cpufreq_available_frequencies *first = NULL; | ||
330 | struct cpufreq_available_frequencies *current = NULL; | ||
331 | char one_value[SYSFS_PATH_MAX]; | ||
332 | char linebuf[MAX_LINE_LEN]; | ||
333 | unsigned int pos, i; | ||
334 | unsigned int len; | ||
335 | |||
336 | len = sysfs_cpufreq_read_file(cpu, "scaling_available_frequencies", | ||
337 | linebuf, sizeof(linebuf)); | ||
338 | if (len == 0) | ||
339 | return NULL; | ||
340 | |||
341 | pos = 0; | ||
342 | for (i = 0; i < len; i++) { | ||
343 | if (linebuf[i] == ' ' || linebuf[i] == '\n') { | ||
344 | if (i - pos < 2) | ||
345 | continue; | ||
346 | if (i - pos >= SYSFS_PATH_MAX) | ||
347 | goto error_out; | ||
348 | if (current) { | ||
349 | current->next = malloc(sizeof(*current)); | ||
350 | if (!current->next) | ||
351 | goto error_out; | ||
352 | current = current->next; | ||
353 | } else { | ||
354 | first = malloc(sizeof(*first)); | ||
355 | if (!first) | ||
356 | goto error_out; | ||
357 | current = first; | ||
358 | } | ||
359 | current->first = first; | ||
360 | current->next = NULL; | ||
361 | |||
362 | memcpy(one_value, linebuf + pos, i - pos); | ||
363 | one_value[i - pos] = '\0'; | ||
364 | if (sscanf(one_value, "%lu", ¤t->frequency) != 1) | ||
365 | goto error_out; | ||
366 | |||
367 | pos = i + 1; | ||
368 | } | ||
369 | } | ||
370 | |||
371 | return first; | ||
372 | |||
373 | error_out: | ||
374 | while (first) { | ||
375 | current = first->next; | ||
376 | free(first); | ||
377 | first = current; | ||
378 | } | ||
379 | return NULL; | ||
380 | } | ||
381 | |||
382 | static struct cpufreq_affected_cpus *sysfs_get_cpu_list(unsigned int cpu, | ||
383 | const char *file) | ||
384 | { | ||
385 | struct cpufreq_affected_cpus *first = NULL; | ||
386 | struct cpufreq_affected_cpus *current = NULL; | ||
387 | char one_value[SYSFS_PATH_MAX]; | ||
388 | char linebuf[MAX_LINE_LEN]; | ||
389 | unsigned int pos, i; | ||
390 | unsigned int len; | ||
391 | |||
392 | len = sysfs_cpufreq_read_file(cpu, file, linebuf, sizeof(linebuf)); | ||
393 | if (len == 0) | ||
394 | return NULL; | ||
395 | |||
396 | pos = 0; | ||
397 | for (i = 0; i < len; i++) { | ||
398 | if (i == len || linebuf[i] == ' ' || linebuf[i] == '\n') { | ||
399 | if (i - pos < 1) | ||
400 | continue; | ||
401 | if (i - pos >= SYSFS_PATH_MAX) | ||
402 | goto error_out; | ||
403 | if (current) { | ||
404 | current->next = malloc(sizeof(*current)); | ||
405 | if (!current->next) | ||
406 | goto error_out; | ||
407 | current = current->next; | ||
408 | } else { | ||
409 | first = malloc(sizeof(*first)); | ||
410 | if (!first) | ||
411 | goto error_out; | ||
412 | current = first; | ||
413 | } | ||
414 | current->first = first; | ||
415 | current->next = NULL; | ||
416 | |||
417 | memcpy(one_value, linebuf + pos, i - pos); | ||
418 | one_value[i - pos] = '\0'; | ||
419 | |||
420 | if (sscanf(one_value, "%u", ¤t->cpu) != 1) | ||
421 | goto error_out; | ||
422 | |||
423 | pos = i + 1; | ||
424 | } | ||
425 | } | ||
426 | |||
427 | return first; | ||
428 | |||
429 | error_out: | ||
430 | while (first) { | ||
431 | current = first->next; | ||
432 | free(first); | ||
433 | first = current; | ||
434 | } | ||
435 | return NULL; | ||
436 | } | ||
437 | |||
438 | struct cpufreq_affected_cpus *sysfs_get_freq_affected_cpus(unsigned int cpu) | ||
439 | { | ||
440 | return sysfs_get_cpu_list(cpu, "affected_cpus"); | ||
441 | } | ||
442 | |||
443 | struct cpufreq_affected_cpus *sysfs_get_freq_related_cpus(unsigned int cpu) | ||
444 | { | ||
445 | return sysfs_get_cpu_list(cpu, "related_cpus"); | ||
446 | } | ||
447 | |||
448 | struct cpufreq_stats *sysfs_get_freq_stats(unsigned int cpu, | ||
449 | unsigned long long *total_time) { | ||
450 | struct cpufreq_stats *first = NULL; | ||
451 | struct cpufreq_stats *current = NULL; | ||
452 | char one_value[SYSFS_PATH_MAX]; | ||
453 | char linebuf[MAX_LINE_LEN]; | ||
454 | unsigned int pos, i; | ||
455 | unsigned int len; | ||
456 | |||
457 | len = sysfs_cpufreq_read_file(cpu, "stats/time_in_state", | ||
458 | linebuf, sizeof(linebuf)); | ||
459 | if (len == 0) | ||
460 | return NULL; | ||
461 | |||
462 | *total_time = 0; | ||
463 | pos = 0; | ||
464 | for (i = 0; i < len; i++) { | ||
465 | if (i == strlen(linebuf) || linebuf[i] == '\n') { | ||
466 | if (i - pos < 2) | ||
467 | continue; | ||
468 | if ((i - pos) >= SYSFS_PATH_MAX) | ||
469 | goto error_out; | ||
470 | if (current) { | ||
471 | current->next = malloc(sizeof(*current)); | ||
472 | if (!current->next) | ||
473 | goto error_out; | ||
474 | current = current->next; | ||
475 | } else { | ||
476 | first = malloc(sizeof(*first)); | ||
477 | if (!first) | ||
478 | goto error_out; | ||
479 | current = first; | ||
480 | } | ||
481 | current->first = first; | ||
482 | current->next = NULL; | ||
483 | |||
484 | memcpy(one_value, linebuf + pos, i - pos); | ||
485 | one_value[i - pos] = '\0'; | ||
486 | if (sscanf(one_value, "%lu %llu", | ||
487 | ¤t->frequency, | ||
488 | ¤t->time_in_state) != 2) | ||
489 | goto error_out; | ||
490 | |||
491 | *total_time = *total_time + current->time_in_state; | ||
492 | pos = i + 1; | ||
493 | } | ||
494 | } | ||
495 | |||
496 | return first; | ||
497 | |||
498 | error_out: | ||
499 | while (first) { | ||
500 | current = first->next; | ||
501 | free(first); | ||
502 | first = current; | ||
503 | } | ||
504 | return NULL; | ||
505 | } | ||
506 | |||
507 | unsigned long sysfs_get_freq_transitions(unsigned int cpu) | ||
508 | { | ||
509 | return sysfs_cpufreq_get_one_value(cpu, STATS_NUM_TRANSITIONS); | ||
510 | } | ||
511 | |||
512 | static int verify_gov(char *new_gov, char *passed_gov) | ||
513 | { | ||
514 | unsigned int i, j = 0; | ||
515 | |||
516 | if (!passed_gov || (strlen(passed_gov) > 19)) | ||
517 | return -EINVAL; | ||
518 | |||
519 | strncpy(new_gov, passed_gov, 20); | ||
520 | for (i = 0; i < 20; i++) { | ||
521 | if (j) { | ||
522 | new_gov[i] = '\0'; | ||
523 | continue; | ||
524 | } | ||
525 | if ((new_gov[i] >= 'a') && (new_gov[i] <= 'z')) | ||
526 | continue; | ||
527 | |||
528 | if ((new_gov[i] >= 'A') && (new_gov[i] <= 'Z')) | ||
529 | continue; | ||
530 | |||
531 | if (new_gov[i] == '-') | ||
532 | continue; | ||
533 | |||
534 | if (new_gov[i] == '_') | ||
535 | continue; | ||
536 | |||
537 | if (new_gov[i] == '\0') { | ||
538 | j = 1; | ||
539 | continue; | ||
540 | } | ||
541 | return -EINVAL; | ||
542 | } | ||
543 | new_gov[19] = '\0'; | ||
544 | return 0; | ||
545 | } | ||
546 | |||
547 | int sysfs_modify_freq_policy_governor(unsigned int cpu, char *governor) | ||
548 | { | ||
549 | char new_gov[SYSFS_PATH_MAX]; | ||
550 | |||
551 | if (!governor) | ||
552 | return -EINVAL; | ||
553 | |||
554 | if (verify_gov(new_gov, governor)) | ||
555 | return -EINVAL; | ||
556 | |||
557 | return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR, | ||
558 | new_gov, strlen(new_gov)); | ||
559 | }; | ||
560 | |||
561 | int sysfs_modify_freq_policy_max(unsigned int cpu, unsigned long max_freq) | ||
562 | { | ||
563 | char value[SYSFS_PATH_MAX]; | ||
564 | |||
565 | snprintf(value, SYSFS_PATH_MAX, "%lu", max_freq); | ||
566 | |||
567 | return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, | ||
568 | value, strlen(value)); | ||
569 | }; | ||
570 | |||
571 | |||
572 | int sysfs_modify_freq_policy_min(unsigned int cpu, unsigned long min_freq) | ||
573 | { | ||
574 | char value[SYSFS_PATH_MAX]; | ||
575 | |||
576 | snprintf(value, SYSFS_PATH_MAX, "%lu", min_freq); | ||
577 | |||
578 | return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, | ||
579 | value, strlen(value)); | ||
580 | }; | ||
581 | |||
582 | |||
583 | int sysfs_set_freq_policy(unsigned int cpu, struct cpufreq_policy *policy) | ||
584 | { | ||
585 | char min[SYSFS_PATH_MAX]; | ||
586 | char max[SYSFS_PATH_MAX]; | ||
587 | char gov[SYSFS_PATH_MAX]; | ||
588 | int ret; | ||
589 | unsigned long old_min; | ||
590 | int write_max_first; | ||
591 | |||
592 | if (!policy || !(policy->governor)) | ||
593 | return -EINVAL; | ||
594 | |||
595 | if (policy->max < policy->min) | ||
596 | return -EINVAL; | ||
597 | |||
598 | if (verify_gov(gov, policy->governor)) | ||
599 | return -EINVAL; | ||
600 | |||
601 | snprintf(min, SYSFS_PATH_MAX, "%lu", policy->min); | ||
602 | snprintf(max, SYSFS_PATH_MAX, "%lu", policy->max); | ||
603 | |||
604 | old_min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ); | ||
605 | write_max_first = (old_min && (policy->max < old_min) ? 0 : 1); | ||
606 | |||
607 | if (write_max_first) { | ||
608 | ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, | ||
609 | max, strlen(max)); | ||
610 | if (ret) | ||
611 | return ret; | ||
612 | } | ||
613 | |||
614 | ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, min, | ||
615 | strlen(min)); | ||
616 | if (ret) | ||
617 | return ret; | ||
618 | |||
619 | if (!write_max_first) { | ||
620 | ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, | ||
621 | max, strlen(max)); | ||
622 | if (ret) | ||
623 | return ret; | ||
624 | } | ||
625 | |||
626 | return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR, | ||
627 | gov, strlen(gov)); | ||
628 | } | ||
629 | |||
630 | int sysfs_set_frequency(unsigned int cpu, unsigned long target_frequency) | ||
631 | { | ||
632 | struct cpufreq_policy *pol = sysfs_get_freq_policy(cpu); | ||
633 | char userspace_gov[] = "userspace"; | ||
634 | char freq[SYSFS_PATH_MAX]; | ||
635 | int ret; | ||
636 | |||
637 | if (!pol) | ||
638 | return -ENODEV; | ||
639 | |||
640 | if (strncmp(pol->governor, userspace_gov, 9) != 0) { | ||
641 | ret = sysfs_modify_freq_policy_governor(cpu, userspace_gov); | ||
642 | if (ret) { | ||
643 | cpufreq_put_policy(pol); | ||
644 | return ret; | ||
645 | } | ||
646 | } | ||
647 | |||
648 | cpufreq_put_policy(pol); | ||
649 | |||
650 | snprintf(freq, SYSFS_PATH_MAX, "%lu", target_frequency); | ||
651 | |||
652 | return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_SET_SPEED, | ||
653 | freq, strlen(freq)); | ||
654 | } | ||
655 | |||
656 | /* CPUFREQ sysfs access **************************************************/ | ||
657 | |||
658 | /* General sysfs access **************************************************/ | ||
659 | int sysfs_cpu_exists(unsigned int cpu) | ||
660 | { | ||
661 | char file[SYSFS_PATH_MAX]; | ||
662 | struct stat statbuf; | ||
663 | |||
664 | snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/", cpu); | ||
665 | |||
666 | if (stat(file, &statbuf) != 0) | ||
667 | return -ENOSYS; | ||
668 | |||
669 | return S_ISDIR(statbuf.st_mode) ? 0 : -ENOSYS; | ||
670 | } | ||
671 | |||
672 | /* General sysfs access **************************************************/ | ||
diff --git a/tools/power/cpupower/lib/sysfs.h b/tools/power/cpupower/lib/sysfs.h deleted file mode 100644 index c76a5e0af501..000000000000 --- a/tools/power/cpupower/lib/sysfs.h +++ /dev/null | |||
@@ -1,31 +0,0 @@ | |||
1 | /* General */ | ||
2 | extern unsigned int sysfs_cpu_exists(unsigned int cpu); | ||
3 | |||
4 | /* CPUfreq */ | ||
5 | extern unsigned long sysfs_get_freq_kernel(unsigned int cpu); | ||
6 | extern unsigned long sysfs_get_freq_hardware(unsigned int cpu); | ||
7 | extern unsigned long sysfs_get_freq_transition_latency(unsigned int cpu); | ||
8 | extern int sysfs_get_freq_hardware_limits(unsigned int cpu, | ||
9 | unsigned long *min, unsigned long *max); | ||
10 | extern char *sysfs_get_freq_driver(unsigned int cpu); | ||
11 | extern struct cpufreq_policy *sysfs_get_freq_policy(unsigned int cpu); | ||
12 | extern struct cpufreq_available_governors *sysfs_get_freq_available_governors( | ||
13 | unsigned int cpu); | ||
14 | extern struct cpufreq_available_frequencies *sysfs_get_available_frequencies( | ||
15 | unsigned int cpu); | ||
16 | extern struct cpufreq_affected_cpus *sysfs_get_freq_affected_cpus( | ||
17 | unsigned int cpu); | ||
18 | extern struct cpufreq_affected_cpus *sysfs_get_freq_related_cpus( | ||
19 | unsigned int cpu); | ||
20 | extern struct cpufreq_stats *sysfs_get_freq_stats(unsigned int cpu, | ||
21 | unsigned long long *total_time); | ||
22 | extern unsigned long sysfs_get_freq_transitions(unsigned int cpu); | ||
23 | extern int sysfs_set_freq_policy(unsigned int cpu, | ||
24 | struct cpufreq_policy *policy); | ||
25 | extern int sysfs_modify_freq_policy_min(unsigned int cpu, | ||
26 | unsigned long min_freq); | ||
27 | extern int sysfs_modify_freq_policy_max(unsigned int cpu, | ||
28 | unsigned long max_freq); | ||
29 | extern int sysfs_modify_freq_policy_governor(unsigned int cpu, char *governor); | ||
30 | extern int sysfs_set_frequency(unsigned int cpu, | ||
31 | unsigned long target_frequency); | ||
diff --git a/tools/power/cpupower/man/cpupower-frequency-info.1 b/tools/power/cpupower/man/cpupower-frequency-info.1 index 9c85a382e355..6aa8d239dff9 100644 --- a/tools/power/cpupower/man/cpupower-frequency-info.1 +++ b/tools/power/cpupower/man/cpupower-frequency-info.1 | |||
@@ -1,7 +1,7 @@ | |||
1 | .TH "CPUPOWER\-FREQUENCY\-INFO" "1" "0.1" "" "cpupower Manual" | 1 | .TH "CPUPOWER\-FREQUENCY\-INFO" "1" "0.1" "" "cpupower Manual" |
2 | .SH "NAME" | 2 | .SH "NAME" |
3 | .LP | 3 | .LP |
4 | cpupower frequency\-info \- Utility to retrieve cpufreq kernel information | 4 | cpupower\-frequency\-info \- Utility to retrieve cpufreq kernel information |
5 | .SH "SYNTAX" | 5 | .SH "SYNTAX" |
6 | .LP | 6 | .LP |
7 | cpupower [ \-c cpulist ] frequency\-info [\fIoptions\fP] | 7 | cpupower [ \-c cpulist ] frequency\-info [\fIoptions\fP] |
diff --git a/tools/power/cpupower/man/cpupower-frequency-set.1 b/tools/power/cpupower/man/cpupower-frequency-set.1 index 3eacc8d03d1a..b50570221a5b 100644 --- a/tools/power/cpupower/man/cpupower-frequency-set.1 +++ b/tools/power/cpupower/man/cpupower-frequency-set.1 | |||
@@ -1,7 +1,7 @@ | |||
1 | .TH "CPUPOWER\-FREQUENCY\-SET" "1" "0.1" "" "cpupower Manual" | 1 | .TH "CPUPOWER\-FREQUENCY\-SET" "1" "0.1" "" "cpupower Manual" |
2 | .SH "NAME" | 2 | .SH "NAME" |
3 | .LP | 3 | .LP |
4 | cpupower frequency\-set \- A small tool which allows to modify cpufreq settings. | 4 | cpupower\-frequency\-set \- A small tool which allows to modify cpufreq settings. |
5 | .SH "SYNTAX" | 5 | .SH "SYNTAX" |
6 | .LP | 6 | .LP |
7 | cpupower [ \-c cpu ] frequency\-set [\fIoptions\fP] | 7 | cpupower [ \-c cpu ] frequency\-set [\fIoptions\fP] |
diff --git a/tools/power/cpupower/man/cpupower-idle-info.1 b/tools/power/cpupower/man/cpupower-idle-info.1 index 7b3646adb92f..80a1311fa747 100644 --- a/tools/power/cpupower/man/cpupower-idle-info.1 +++ b/tools/power/cpupower/man/cpupower-idle-info.1 | |||
@@ -1,7 +1,7 @@ | |||
1 | .TH "CPUPOWER-IDLE-INFO" "1" "0.1" "" "cpupower Manual" | 1 | .TH "CPUPOWER-IDLE-INFO" "1" "0.1" "" "cpupower Manual" |
2 | .SH "NAME" | 2 | .SH "NAME" |
3 | .LP | 3 | .LP |
4 | cpupower idle\-info \- Utility to retrieve cpu idle kernel information | 4 | cpupower\-idle\-info \- Utility to retrieve cpu idle kernel information |
5 | .SH "SYNTAX" | 5 | .SH "SYNTAX" |
6 | .LP | 6 | .LP |
7 | cpupower [ \-c cpulist ] idle\-info [\fIoptions\fP] | 7 | cpupower [ \-c cpulist ] idle\-info [\fIoptions\fP] |
diff --git a/tools/power/cpupower/man/cpupower-idle-set.1 b/tools/power/cpupower/man/cpupower-idle-set.1 index 580c4e3ea92a..21916cff7516 100644 --- a/tools/power/cpupower/man/cpupower-idle-set.1 +++ b/tools/power/cpupower/man/cpupower-idle-set.1 | |||
@@ -1,7 +1,7 @@ | |||
1 | .TH "CPUPOWER-IDLE-SET" "1" "0.1" "" "cpupower Manual" | 1 | .TH "CPUPOWER-IDLE-SET" "1" "0.1" "" "cpupower Manual" |
2 | .SH "NAME" | 2 | .SH "NAME" |
3 | .LP | 3 | .LP |
4 | cpupower idle\-set \- Utility to set cpu idle state specific kernel options | 4 | cpupower\-idle\-set \- Utility to set cpu idle state specific kernel options |
5 | .SH "SYNTAX" | 5 | .SH "SYNTAX" |
6 | .LP | 6 | .LP |
7 | cpupower [ \-c cpulist ] idle\-info [\fIoptions\fP] | 7 | cpupower [ \-c cpulist ] idle\-info [\fIoptions\fP] |
diff --git a/tools/power/cpupower/utils/cpufreq-set.c b/tools/power/cpupower/utils/cpufreq-set.c index 0fbd1a22c0a9..b4bf76971dc9 100644 --- a/tools/power/cpupower/utils/cpufreq-set.c +++ b/tools/power/cpupower/utils/cpufreq-set.c | |||
@@ -16,8 +16,8 @@ | |||
16 | #include <getopt.h> | 16 | #include <getopt.h> |
17 | 17 | ||
18 | #include "cpufreq.h" | 18 | #include "cpufreq.h" |
19 | #include "cpuidle.h" | ||
19 | #include "helpers/helpers.h" | 20 | #include "helpers/helpers.h" |
20 | #include "helpers/sysfs.h" | ||
21 | 21 | ||
22 | #define NORM_FREQ_LEN 32 | 22 | #define NORM_FREQ_LEN 32 |
23 | 23 | ||
@@ -296,7 +296,7 @@ int cmd_freq_set(int argc, char **argv) | |||
296 | struct cpufreq_affected_cpus *cpus; | 296 | struct cpufreq_affected_cpus *cpus; |
297 | 297 | ||
298 | if (!bitmask_isbitset(cpus_chosen, cpu) || | 298 | if (!bitmask_isbitset(cpus_chosen, cpu) || |
299 | cpufreq_cpu_exists(cpu)) | 299 | cpupower_is_cpu_online(cpu)) |
300 | continue; | 300 | continue; |
301 | 301 | ||
302 | cpus = cpufreq_get_related_cpus(cpu); | 302 | cpus = cpufreq_get_related_cpus(cpu); |
@@ -316,10 +316,10 @@ int cmd_freq_set(int argc, char **argv) | |||
316 | cpu <= bitmask_last(cpus_chosen); cpu++) { | 316 | cpu <= bitmask_last(cpus_chosen); cpu++) { |
317 | 317 | ||
318 | if (!bitmask_isbitset(cpus_chosen, cpu) || | 318 | if (!bitmask_isbitset(cpus_chosen, cpu) || |
319 | cpufreq_cpu_exists(cpu)) | 319 | cpupower_is_cpu_online(cpu)) |
320 | continue; | 320 | continue; |
321 | 321 | ||
322 | if (sysfs_is_cpu_online(cpu) != 1) | 322 | if (cpupower_is_cpu_online(cpu) != 1) |
323 | continue; | 323 | continue; |
324 | 324 | ||
325 | printf(_("Setting cpu: %d\n"), cpu); | 325 | printf(_("Setting cpu: %d\n"), cpu); |
diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c index 8bf8ab5ffa25..b59c85defa05 100644 --- a/tools/power/cpupower/utils/cpuidle-info.c +++ b/tools/power/cpupower/utils/cpuidle-info.c | |||
@@ -13,8 +13,10 @@ | |||
13 | #include <string.h> | 13 | #include <string.h> |
14 | #include <getopt.h> | 14 | #include <getopt.h> |
15 | 15 | ||
16 | #include "helpers/helpers.h" | 16 | #include <cpuidle.h> |
17 | |||
17 | #include "helpers/sysfs.h" | 18 | #include "helpers/sysfs.h" |
19 | #include "helpers/helpers.h" | ||
18 | #include "helpers/bitmask.h" | 20 | #include "helpers/bitmask.h" |
19 | 21 | ||
20 | #define LINE_LEN 10 | 22 | #define LINE_LEN 10 |
@@ -24,7 +26,7 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose) | |||
24 | unsigned int idlestates, idlestate; | 26 | unsigned int idlestates, idlestate; |
25 | char *tmp; | 27 | char *tmp; |
26 | 28 | ||
27 | idlestates = sysfs_get_idlestate_count(cpu); | 29 | idlestates = cpuidle_state_count(cpu); |
28 | if (idlestates == 0) { | 30 | if (idlestates == 0) { |
29 | printf(_("CPU %u: No idle states\n"), cpu); | 31 | printf(_("CPU %u: No idle states\n"), cpu); |
30 | return; | 32 | return; |
@@ -33,7 +35,7 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose) | |||
33 | printf(_("Number of idle states: %d\n"), idlestates); | 35 | printf(_("Number of idle states: %d\n"), idlestates); |
34 | printf(_("Available idle states:")); | 36 | printf(_("Available idle states:")); |
35 | for (idlestate = 0; idlestate < idlestates; idlestate++) { | 37 | for (idlestate = 0; idlestate < idlestates; idlestate++) { |
36 | tmp = sysfs_get_idlestate_name(cpu, idlestate); | 38 | tmp = cpuidle_state_name(cpu, idlestate); |
37 | if (!tmp) | 39 | if (!tmp) |
38 | continue; | 40 | continue; |
39 | printf(" %s", tmp); | 41 | printf(" %s", tmp); |
@@ -45,28 +47,28 @@ static void cpuidle_cpu_output(unsigned int cpu, int verbose) | |||
45 | return; | 47 | return; |
46 | 48 | ||
47 | for (idlestate = 0; idlestate < idlestates; idlestate++) { | 49 | for (idlestate = 0; idlestate < idlestates; idlestate++) { |
48 | int disabled = sysfs_is_idlestate_disabled(cpu, idlestate); | 50 | int disabled = cpuidle_is_state_disabled(cpu, idlestate); |
49 | /* Disabled interface not supported on older kernels */ | 51 | /* Disabled interface not supported on older kernels */ |
50 | if (disabled < 0) | 52 | if (disabled < 0) |
51 | disabled = 0; | 53 | disabled = 0; |
52 | tmp = sysfs_get_idlestate_name(cpu, idlestate); | 54 | tmp = cpuidle_state_name(cpu, idlestate); |
53 | if (!tmp) | 55 | if (!tmp) |
54 | continue; | 56 | continue; |
55 | printf("%s%s:\n", tmp, (disabled) ? " (DISABLED) " : ""); | 57 | printf("%s%s:\n", tmp, (disabled) ? " (DISABLED) " : ""); |
56 | free(tmp); | 58 | free(tmp); |
57 | 59 | ||
58 | tmp = sysfs_get_idlestate_desc(cpu, idlestate); | 60 | tmp = cpuidle_state_desc(cpu, idlestate); |
59 | if (!tmp) | 61 | if (!tmp) |
60 | continue; | 62 | continue; |
61 | printf(_("Flags/Description: %s\n"), tmp); | 63 | printf(_("Flags/Description: %s\n"), tmp); |
62 | free(tmp); | 64 | free(tmp); |
63 | 65 | ||
64 | printf(_("Latency: %lu\n"), | 66 | printf(_("Latency: %lu\n"), |
65 | sysfs_get_idlestate_latency(cpu, idlestate)); | 67 | cpuidle_state_latency(cpu, idlestate)); |
66 | printf(_("Usage: %lu\n"), | 68 | printf(_("Usage: %lu\n"), |
67 | sysfs_get_idlestate_usage(cpu, idlestate)); | 69 | cpuidle_state_usage(cpu, idlestate)); |
68 | printf(_("Duration: %llu\n"), | 70 | printf(_("Duration: %llu\n"), |
69 | sysfs_get_idlestate_time(cpu, idlestate)); | 71 | cpuidle_state_time(cpu, idlestate)); |
70 | } | 72 | } |
71 | } | 73 | } |
72 | 74 | ||
@@ -74,7 +76,7 @@ static void cpuidle_general_output(void) | |||
74 | { | 76 | { |
75 | char *tmp; | 77 | char *tmp; |
76 | 78 | ||
77 | tmp = sysfs_get_cpuidle_driver(); | 79 | tmp = cpuidle_get_driver(); |
78 | if (!tmp) { | 80 | if (!tmp) { |
79 | printf(_("Could not determine cpuidle driver\n")); | 81 | printf(_("Could not determine cpuidle driver\n")); |
80 | return; | 82 | return; |
@@ -83,7 +85,7 @@ static void cpuidle_general_output(void) | |||
83 | printf(_("CPUidle driver: %s\n"), tmp); | 85 | printf(_("CPUidle driver: %s\n"), tmp); |
84 | free(tmp); | 86 | free(tmp); |
85 | 87 | ||
86 | tmp = sysfs_get_cpuidle_governor(); | 88 | tmp = cpuidle_get_governor(); |
87 | if (!tmp) { | 89 | if (!tmp) { |
88 | printf(_("Could not determine cpuidle governor\n")); | 90 | printf(_("Could not determine cpuidle governor\n")); |
89 | return; | 91 | return; |
@@ -98,7 +100,7 @@ static void proc_cpuidle_cpu_output(unsigned int cpu) | |||
98 | long max_allowed_cstate = 2000000000; | 100 | long max_allowed_cstate = 2000000000; |
99 | unsigned int cstate, cstates; | 101 | unsigned int cstate, cstates; |
100 | 102 | ||
101 | cstates = sysfs_get_idlestate_count(cpu); | 103 | cstates = cpuidle_state_count(cpu); |
102 | if (cstates == 0) { | 104 | if (cstates == 0) { |
103 | printf(_("CPU %u: No C-states info\n"), cpu); | 105 | printf(_("CPU %u: No C-states info\n"), cpu); |
104 | return; | 106 | return; |
@@ -113,11 +115,11 @@ static void proc_cpuidle_cpu_output(unsigned int cpu) | |||
113 | "type[C%d] "), cstate, cstate); | 115 | "type[C%d] "), cstate, cstate); |
114 | printf(_("promotion[--] demotion[--] ")); | 116 | printf(_("promotion[--] demotion[--] ")); |
115 | printf(_("latency[%03lu] "), | 117 | printf(_("latency[%03lu] "), |
116 | sysfs_get_idlestate_latency(cpu, cstate)); | 118 | cpuidle_state_latency(cpu, cstate)); |
117 | printf(_("usage[%08lu] "), | 119 | printf(_("usage[%08lu] "), |
118 | sysfs_get_idlestate_usage(cpu, cstate)); | 120 | cpuidle_state_usage(cpu, cstate)); |
119 | printf(_("duration[%020Lu] \n"), | 121 | printf(_("duration[%020Lu] \n"), |
120 | sysfs_get_idlestate_time(cpu, cstate)); | 122 | cpuidle_state_time(cpu, cstate)); |
121 | } | 123 | } |
122 | } | 124 | } |
123 | 125 | ||
diff --git a/tools/power/cpupower/utils/cpuidle-set.c b/tools/power/cpupower/utils/cpuidle-set.c index d6b6ae44b8c2..691c24d50ef4 100644 --- a/tools/power/cpupower/utils/cpuidle-set.c +++ b/tools/power/cpupower/utils/cpuidle-set.c | |||
@@ -5,12 +5,12 @@ | |||
5 | #include <limits.h> | 5 | #include <limits.h> |
6 | #include <string.h> | 6 | #include <string.h> |
7 | #include <ctype.h> | 7 | #include <ctype.h> |
8 | |||
9 | #include <getopt.h> | 8 | #include <getopt.h> |
10 | 9 | ||
11 | #include "cpufreq.h" | 10 | #include <cpufreq.h> |
11 | #include <cpuidle.h> | ||
12 | |||
12 | #include "helpers/helpers.h" | 13 | #include "helpers/helpers.h" |
13 | #include "helpers/sysfs.h" | ||
14 | 14 | ||
15 | static struct option info_opts[] = { | 15 | static struct option info_opts[] = { |
16 | {"disable", required_argument, NULL, 'd'}, | 16 | {"disable", required_argument, NULL, 'd'}, |
@@ -104,16 +104,16 @@ int cmd_idle_set(int argc, char **argv) | |||
104 | if (!bitmask_isbitset(cpus_chosen, cpu)) | 104 | if (!bitmask_isbitset(cpus_chosen, cpu)) |
105 | continue; | 105 | continue; |
106 | 106 | ||
107 | if (sysfs_is_cpu_online(cpu) != 1) | 107 | if (cpupower_is_cpu_online(cpu) != 1) |
108 | continue; | 108 | continue; |
109 | 109 | ||
110 | idlestates = sysfs_get_idlestate_count(cpu); | 110 | idlestates = cpuidle_state_count(cpu); |
111 | if (idlestates <= 0) | 111 | if (idlestates <= 0) |
112 | continue; | 112 | continue; |
113 | 113 | ||
114 | switch (param) { | 114 | switch (param) { |
115 | case 'd': | 115 | case 'd': |
116 | ret = sysfs_idlestate_disable(cpu, idlestate, 1); | 116 | ret = cpuidle_state_disable(cpu, idlestate, 1); |
117 | if (ret == 0) | 117 | if (ret == 0) |
118 | printf(_("Idlestate %u disabled on CPU %u\n"), idlestate, cpu); | 118 | printf(_("Idlestate %u disabled on CPU %u\n"), idlestate, cpu); |
119 | else if (ret == -1) | 119 | else if (ret == -1) |
@@ -126,7 +126,7 @@ int cmd_idle_set(int argc, char **argv) | |||
126 | idlestate, cpu); | 126 | idlestate, cpu); |
127 | break; | 127 | break; |
128 | case 'e': | 128 | case 'e': |
129 | ret = sysfs_idlestate_disable(cpu, idlestate, 0); | 129 | ret = cpuidle_state_disable(cpu, idlestate, 0); |
130 | if (ret == 0) | 130 | if (ret == 0) |
131 | printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu); | 131 | printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu); |
132 | else if (ret == -1) | 132 | else if (ret == -1) |
@@ -140,13 +140,13 @@ int cmd_idle_set(int argc, char **argv) | |||
140 | break; | 140 | break; |
141 | case 'D': | 141 | case 'D': |
142 | for (idlestate = 0; idlestate < idlestates; idlestate++) { | 142 | for (idlestate = 0; idlestate < idlestates; idlestate++) { |
143 | disabled = sysfs_is_idlestate_disabled | 143 | disabled = cpuidle_is_state_disabled |
144 | (cpu, idlestate); | 144 | (cpu, idlestate); |
145 | state_latency = sysfs_get_idlestate_latency | 145 | state_latency = cpuidle_state_latency |
146 | (cpu, idlestate); | 146 | (cpu, idlestate); |
147 | if (disabled == 1) { | 147 | if (disabled == 1) { |
148 | if (latency > state_latency){ | 148 | if (latency > state_latency){ |
149 | ret = sysfs_idlestate_disable | 149 | ret = cpuidle_state_disable |
150 | (cpu, idlestate, 0); | 150 | (cpu, idlestate, 0); |
151 | if (ret == 0) | 151 | if (ret == 0) |
152 | printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu); | 152 | printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu); |
@@ -154,7 +154,7 @@ int cmd_idle_set(int argc, char **argv) | |||
154 | continue; | 154 | continue; |
155 | } | 155 | } |
156 | if (latency <= state_latency){ | 156 | if (latency <= state_latency){ |
157 | ret = sysfs_idlestate_disable | 157 | ret = cpuidle_state_disable |
158 | (cpu, idlestate, 1); | 158 | (cpu, idlestate, 1); |
159 | if (ret == 0) | 159 | if (ret == 0) |
160 | printf(_("Idlestate %u disabled on CPU %u\n"), idlestate, cpu); | 160 | printf(_("Idlestate %u disabled on CPU %u\n"), idlestate, cpu); |
@@ -163,10 +163,10 @@ int cmd_idle_set(int argc, char **argv) | |||
163 | break; | 163 | break; |
164 | case 'E': | 164 | case 'E': |
165 | for (idlestate = 0; idlestate < idlestates; idlestate++) { | 165 | for (idlestate = 0; idlestate < idlestates; idlestate++) { |
166 | disabled = sysfs_is_idlestate_disabled | 166 | disabled = cpuidle_is_state_disabled |
167 | (cpu, idlestate); | 167 | (cpu, idlestate); |
168 | if (disabled == 1) { | 168 | if (disabled == 1) { |
169 | ret = sysfs_idlestate_disable | 169 | ret = cpuidle_state_disable |
170 | (cpu, idlestate, 0); | 170 | (cpu, idlestate, 0); |
171 | if (ret == 0) | 171 | if (ret == 0) |
172 | printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu); | 172 | printf(_("Idlestate %u enabled on CPU %u\n"), idlestate, cpu); |
diff --git a/tools/power/cpupower/utils/helpers/helpers.h b/tools/power/cpupower/utils/helpers/helpers.h index aa9e95486a2d..afb66f80554e 100644 --- a/tools/power/cpupower/utils/helpers/helpers.h +++ b/tools/power/cpupower/utils/helpers/helpers.h | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <locale.h> | 14 | #include <locale.h> |
15 | 15 | ||
16 | #include "helpers/bitmask.h" | 16 | #include "helpers/bitmask.h" |
17 | #include <cpupower.h> | ||
17 | 18 | ||
18 | /* Internationalization ****************************/ | 19 | /* Internationalization ****************************/ |
19 | #ifdef NLS | 20 | #ifdef NLS |
@@ -92,31 +93,6 @@ extern int get_cpu_info(unsigned int cpu, struct cpupower_cpu_info *cpu_info); | |||
92 | extern struct cpupower_cpu_info cpupower_cpu_info; | 93 | extern struct cpupower_cpu_info cpupower_cpu_info; |
93 | /* cpuid and cpuinfo helpers **************************/ | 94 | /* cpuid and cpuinfo helpers **************************/ |
94 | 95 | ||
95 | struct cpuid_core_info { | ||
96 | int pkg; | ||
97 | int core; | ||
98 | int cpu; | ||
99 | |||
100 | /* flags */ | ||
101 | unsigned int is_online:1; | ||
102 | }; | ||
103 | |||
104 | /* CPU topology/hierarchy parsing ******************/ | ||
105 | struct cpupower_topology { | ||
106 | /* Amount of CPU cores, packages and threads per core in the system */ | ||
107 | unsigned int cores; | ||
108 | unsigned int pkgs; | ||
109 | unsigned int threads; /* per core */ | ||
110 | |||
111 | /* Array gets mallocated with cores entries, holding per core info */ | ||
112 | struct cpuid_core_info *core_info; | ||
113 | }; | ||
114 | |||
115 | extern int get_cpu_topology(struct cpupower_topology *cpu_top); | ||
116 | extern void cpu_topology_release(struct cpupower_topology cpu_top); | ||
117 | |||
118 | /* CPU topology/hierarchy parsing ******************/ | ||
119 | |||
120 | /* X86 ONLY ****************************************/ | 96 | /* X86 ONLY ****************************************/ |
121 | #if defined(__i386__) || defined(__x86_64__) | 97 | #if defined(__i386__) || defined(__x86_64__) |
122 | 98 | ||
diff --git a/tools/power/cpupower/utils/helpers/topology.c b/tools/power/cpupower/utils/helpers/topology.c index 5f9c908f4557..a1a6c6041a1e 100644 --- a/tools/power/cpupower/utils/helpers/topology.c +++ b/tools/power/cpupower/utils/helpers/topology.c | |||
@@ -16,110 +16,7 @@ | |||
16 | #include <errno.h> | 16 | #include <errno.h> |
17 | #include <fcntl.h> | 17 | #include <fcntl.h> |
18 | 18 | ||
19 | #include <helpers/helpers.h> | 19 | #include <cpuidle.h> |
20 | #include <helpers/sysfs.h> | ||
21 | 20 | ||
22 | /* returns -1 on failure, 0 on success */ | 21 | /* CPU topology/hierarchy parsing ******************/ |
23 | static int sysfs_topology_read_file(unsigned int cpu, const char *fname, int *result) | ||
24 | { | ||
25 | char linebuf[MAX_LINE_LEN]; | ||
26 | char *endp; | ||
27 | char path[SYSFS_PATH_MAX]; | ||
28 | 22 | ||
29 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/topology/%s", | ||
30 | cpu, fname); | ||
31 | if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0) | ||
32 | return -1; | ||
33 | *result = strtol(linebuf, &endp, 0); | ||
34 | if (endp == linebuf || errno == ERANGE) | ||
35 | return -1; | ||
36 | return 0; | ||
37 | } | ||
38 | |||
39 | static int __compare(const void *t1, const void *t2) | ||
40 | { | ||
41 | struct cpuid_core_info *top1 = (struct cpuid_core_info *)t1; | ||
42 | struct cpuid_core_info *top2 = (struct cpuid_core_info *)t2; | ||
43 | if (top1->pkg < top2->pkg) | ||
44 | return -1; | ||
45 | else if (top1->pkg > top2->pkg) | ||
46 | return 1; | ||
47 | else if (top1->core < top2->core) | ||
48 | return -1; | ||
49 | else if (top1->core > top2->core) | ||
50 | return 1; | ||
51 | else if (top1->cpu < top2->cpu) | ||
52 | return -1; | ||
53 | else if (top1->cpu > top2->cpu) | ||
54 | return 1; | ||
55 | else | ||
56 | return 0; | ||
57 | } | ||
58 | |||
59 | /* | ||
60 | * Returns amount of cpus, negative on error, cpu_top must be | ||
61 | * passed to cpu_topology_release to free resources | ||
62 | * | ||
63 | * Array is sorted after ->pkg, ->core, then ->cpu | ||
64 | */ | ||
65 | int get_cpu_topology(struct cpupower_topology *cpu_top) | ||
66 | { | ||
67 | int cpu, last_pkg, cpus = sysconf(_SC_NPROCESSORS_CONF); | ||
68 | |||
69 | cpu_top->core_info = malloc(sizeof(struct cpuid_core_info) * cpus); | ||
70 | if (cpu_top->core_info == NULL) | ||
71 | return -ENOMEM; | ||
72 | cpu_top->pkgs = cpu_top->cores = 0; | ||
73 | for (cpu = 0; cpu < cpus; cpu++) { | ||
74 | cpu_top->core_info[cpu].cpu = cpu; | ||
75 | cpu_top->core_info[cpu].is_online = sysfs_is_cpu_online(cpu); | ||
76 | if(sysfs_topology_read_file( | ||
77 | cpu, | ||
78 | "physical_package_id", | ||
79 | &(cpu_top->core_info[cpu].pkg)) < 0) { | ||
80 | cpu_top->core_info[cpu].pkg = -1; | ||
81 | cpu_top->core_info[cpu].core = -1; | ||
82 | continue; | ||
83 | } | ||
84 | if(sysfs_topology_read_file( | ||
85 | cpu, | ||
86 | "core_id", | ||
87 | &(cpu_top->core_info[cpu].core)) < 0) { | ||
88 | cpu_top->core_info[cpu].pkg = -1; | ||
89 | cpu_top->core_info[cpu].core = -1; | ||
90 | continue; | ||
91 | } | ||
92 | } | ||
93 | |||
94 | qsort(cpu_top->core_info, cpus, sizeof(struct cpuid_core_info), | ||
95 | __compare); | ||
96 | |||
97 | /* Count the number of distinct pkgs values. This works | ||
98 | because the primary sort of the core_info struct was just | ||
99 | done by pkg value. */ | ||
100 | last_pkg = cpu_top->core_info[0].pkg; | ||
101 | for(cpu = 1; cpu < cpus; cpu++) { | ||
102 | if (cpu_top->core_info[cpu].pkg != last_pkg && | ||
103 | cpu_top->core_info[cpu].pkg != -1) { | ||
104 | |||
105 | last_pkg = cpu_top->core_info[cpu].pkg; | ||
106 | cpu_top->pkgs++; | ||
107 | } | ||
108 | } | ||
109 | if (!(cpu_top->core_info[0].pkg == -1)) | ||
110 | cpu_top->pkgs++; | ||
111 | |||
112 | /* Intel's cores count is not consecutively numbered, there may | ||
113 | * be a core_id of 3, but none of 2. Assume there always is 0 | ||
114 | * Get amount of cores by counting duplicates in a package | ||
115 | for (cpu = 0; cpu_top->core_info[cpu].pkg = 0 && cpu < cpus; cpu++) { | ||
116 | if (cpu_top->core_info[cpu].core == 0) | ||
117 | cpu_top->cores++; | ||
118 | */ | ||
119 | return cpus; | ||
120 | } | ||
121 | |||
122 | void cpu_topology_release(struct cpupower_topology cpu_top) | ||
123 | { | ||
124 | free(cpu_top.core_info); | ||
125 | } | ||
diff --git a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c index bcd22a1a3970..1b5da0066ebf 100644 --- a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c +++ b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c | |||
@@ -10,8 +10,8 @@ | |||
10 | #include <stdint.h> | 10 | #include <stdint.h> |
11 | #include <string.h> | 11 | #include <string.h> |
12 | #include <limits.h> | 12 | #include <limits.h> |
13 | #include <cpuidle.h> | ||
13 | 14 | ||
14 | #include "helpers/sysfs.h" | ||
15 | #include "helpers/helpers.h" | 15 | #include "helpers/helpers.h" |
16 | #include "idle_monitor/cpupower-monitor.h" | 16 | #include "idle_monitor/cpupower-monitor.h" |
17 | 17 | ||
@@ -51,7 +51,7 @@ static int cpuidle_start(void) | |||
51 | for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num; | 51 | for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num; |
52 | state++) { | 52 | state++) { |
53 | previous_count[cpu][state] = | 53 | previous_count[cpu][state] = |
54 | sysfs_get_idlestate_time(cpu, state); | 54 | cpuidle_state_time(cpu, state); |
55 | dprint("CPU %d - State: %d - Val: %llu\n", | 55 | dprint("CPU %d - State: %d - Val: %llu\n", |
56 | cpu, state, previous_count[cpu][state]); | 56 | cpu, state, previous_count[cpu][state]); |
57 | } | 57 | } |
@@ -70,7 +70,7 @@ static int cpuidle_stop(void) | |||
70 | for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num; | 70 | for (state = 0; state < cpuidle_sysfs_monitor.hw_states_num; |
71 | state++) { | 71 | state++) { |
72 | current_count[cpu][state] = | 72 | current_count[cpu][state] = |
73 | sysfs_get_idlestate_time(cpu, state); | 73 | cpuidle_state_time(cpu, state); |
74 | dprint("CPU %d - State: %d - Val: %llu\n", | 74 | dprint("CPU %d - State: %d - Val: %llu\n", |
75 | cpu, state, previous_count[cpu][state]); | 75 | cpu, state, previous_count[cpu][state]); |
76 | } | 76 | } |
@@ -132,13 +132,13 @@ static struct cpuidle_monitor *cpuidle_register(void) | |||
132 | char *tmp; | 132 | char *tmp; |
133 | 133 | ||
134 | /* Assume idle state count is the same for all CPUs */ | 134 | /* Assume idle state count is the same for all CPUs */ |
135 | cpuidle_sysfs_monitor.hw_states_num = sysfs_get_idlestate_count(0); | 135 | cpuidle_sysfs_monitor.hw_states_num = cpuidle_state_count(0); |
136 | 136 | ||
137 | if (cpuidle_sysfs_monitor.hw_states_num <= 0) | 137 | if (cpuidle_sysfs_monitor.hw_states_num <= 0) |
138 | return NULL; | 138 | return NULL; |
139 | 139 | ||
140 | for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) { | 140 | for (num = 0; num < cpuidle_sysfs_monitor.hw_states_num; num++) { |
141 | tmp = sysfs_get_idlestate_name(0, num); | 141 | tmp = cpuidle_state_name(0, num); |
142 | if (tmp == NULL) | 142 | if (tmp == NULL) |
143 | continue; | 143 | continue; |
144 | 144 | ||
@@ -146,7 +146,7 @@ static struct cpuidle_monitor *cpuidle_register(void) | |||
146 | strncpy(cpuidle_cstates[num].name, tmp, CSTATE_NAME_LEN - 1); | 146 | strncpy(cpuidle_cstates[num].name, tmp, CSTATE_NAME_LEN - 1); |
147 | free(tmp); | 147 | free(tmp); |
148 | 148 | ||
149 | tmp = sysfs_get_idlestate_desc(0, num); | 149 | tmp = cpuidle_state_desc(0, num); |
150 | if (tmp == NULL) | 150 | if (tmp == NULL) |
151 | continue; | 151 | continue; |
152 | strncpy(cpuidle_cstates[num].desc, tmp, CSTATE_DESC_LEN - 1); | 152 | strncpy(cpuidle_cstates[num].desc, tmp, CSTATE_DESC_LEN - 1); |
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index b04afc3295df..ff9e5f20a5a7 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile | |||
@@ -19,6 +19,7 @@ TARGETS += powerpc | |||
19 | TARGETS += pstore | 19 | TARGETS += pstore |
20 | TARGETS += ptrace | 20 | TARGETS += ptrace |
21 | TARGETS += seccomp | 21 | TARGETS += seccomp |
22 | TARGETS += sigaltstack | ||
22 | TARGETS += size | 23 | TARGETS += size |
23 | TARGETS += static_keys | 24 | TARGETS += static_keys |
24 | TARGETS += sysctl | 25 | TARGETS += sysctl |
diff --git a/tools/testing/selftests/net/.gitignore b/tools/testing/selftests/net/.gitignore index 69bb3fc38fb2..0840684deb7d 100644 --- a/tools/testing/selftests/net/.gitignore +++ b/tools/testing/selftests/net/.gitignore | |||
@@ -3,3 +3,4 @@ psock_fanout | |||
3 | psock_tpacket | 3 | psock_tpacket |
4 | reuseport_bpf | 4 | reuseport_bpf |
5 | reuseport_bpf_cpu | 5 | reuseport_bpf_cpu |
6 | reuseport_dualstack | ||
diff --git a/tools/testing/selftests/net/Makefile b/tools/testing/selftests/net/Makefile index c658792d47b4..0e5340742620 100644 --- a/tools/testing/selftests/net/Makefile +++ b/tools/testing/selftests/net/Makefile | |||
@@ -4,7 +4,7 @@ CFLAGS = -Wall -O2 -g | |||
4 | 4 | ||
5 | CFLAGS += -I../../../../usr/include/ | 5 | CFLAGS += -I../../../../usr/include/ |
6 | 6 | ||
7 | NET_PROGS = socket psock_fanout psock_tpacket reuseport_bpf reuseport_bpf_cpu | 7 | NET_PROGS = socket psock_fanout psock_tpacket reuseport_bpf reuseport_bpf_cpu reuseport_dualstack |
8 | 8 | ||
9 | all: $(NET_PROGS) | 9 | all: $(NET_PROGS) |
10 | %: %.c | 10 | %: %.c |
diff --git a/tools/testing/selftests/net/reuseport_dualstack.c b/tools/testing/selftests/net/reuseport_dualstack.c new file mode 100644 index 000000000000..90958aaaafb9 --- /dev/null +++ b/tools/testing/selftests/net/reuseport_dualstack.c | |||
@@ -0,0 +1,208 @@ | |||
1 | /* | ||
2 | * It is possible to use SO_REUSEPORT to open multiple sockets bound to | ||
3 | * equivalent local addresses using AF_INET and AF_INET6 at the same time. If | ||
4 | * the AF_INET6 socket has IPV6_V6ONLY set, it's clear which socket should | ||
5 | * receive a given incoming packet. However, when it is not set, incoming v4 | ||
6 | * packets should prefer the AF_INET socket(s). This behavior was defined with | ||
7 | * the original SO_REUSEPORT implementation, but broke with | ||
8 | * e32ea7e74727 ("soreuseport: fast reuseport UDP socket selection") | ||
9 | * This test creates these mixed AF_INET/AF_INET6 sockets and asserts the | ||
10 | * AF_INET preference for v4 packets. | ||
11 | */ | ||
12 | |||
13 | #define _GNU_SOURCE | ||
14 | |||
15 | #include <arpa/inet.h> | ||
16 | #include <errno.h> | ||
17 | #include <error.h> | ||
18 | #include <linux/in.h> | ||
19 | #include <linux/unistd.h> | ||
20 | #include <stdio.h> | ||
21 | #include <stdlib.h> | ||
22 | #include <string.h> | ||
23 | #include <sys/epoll.h> | ||
24 | #include <sys/types.h> | ||
25 | #include <sys/socket.h> | ||
26 | #include <unistd.h> | ||
27 | |||
28 | static const int PORT = 8888; | ||
29 | |||
30 | static void build_rcv_fd(int family, int proto, int *rcv_fds, int count) | ||
31 | { | ||
32 | struct sockaddr_storage addr; | ||
33 | struct sockaddr_in *addr4; | ||
34 | struct sockaddr_in6 *addr6; | ||
35 | int opt, i; | ||
36 | |||
37 | switch (family) { | ||
38 | case AF_INET: | ||
39 | addr4 = (struct sockaddr_in *)&addr; | ||
40 | addr4->sin_family = AF_INET; | ||
41 | addr4->sin_addr.s_addr = htonl(INADDR_ANY); | ||
42 | addr4->sin_port = htons(PORT); | ||
43 | break; | ||
44 | case AF_INET6: | ||
45 | addr6 = (struct sockaddr_in6 *)&addr; | ||
46 | addr6->sin6_family = AF_INET6; | ||
47 | addr6->sin6_addr = in6addr_any; | ||
48 | addr6->sin6_port = htons(PORT); | ||
49 | break; | ||
50 | default: | ||
51 | error(1, 0, "Unsupported family %d", family); | ||
52 | } | ||
53 | |||
54 | for (i = 0; i < count; ++i) { | ||
55 | rcv_fds[i] = socket(family, proto, 0); | ||
56 | if (rcv_fds[i] < 0) | ||
57 | error(1, errno, "failed to create receive socket"); | ||
58 | |||
59 | opt = 1; | ||
60 | if (setsockopt(rcv_fds[i], SOL_SOCKET, SO_REUSEPORT, &opt, | ||
61 | sizeof(opt))) | ||
62 | error(1, errno, "failed to set SO_REUSEPORT"); | ||
63 | |||
64 | if (bind(rcv_fds[i], (struct sockaddr *)&addr, sizeof(addr))) | ||
65 | error(1, errno, "failed to bind receive socket"); | ||
66 | |||
67 | if (proto == SOCK_STREAM && listen(rcv_fds[i], 10)) | ||
68 | error(1, errno, "failed to listen on receive port"); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | static void send_from_v4(int proto) | ||
73 | { | ||
74 | struct sockaddr_in saddr, daddr; | ||
75 | int fd; | ||
76 | |||
77 | saddr.sin_family = AF_INET; | ||
78 | saddr.sin_addr.s_addr = htonl(INADDR_ANY); | ||
79 | saddr.sin_port = 0; | ||
80 | |||
81 | daddr.sin_family = AF_INET; | ||
82 | daddr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); | ||
83 | daddr.sin_port = htons(PORT); | ||
84 | |||
85 | fd = socket(AF_INET, proto, 0); | ||
86 | if (fd < 0) | ||
87 | error(1, errno, "failed to create send socket"); | ||
88 | |||
89 | if (bind(fd, (struct sockaddr *)&saddr, sizeof(saddr))) | ||
90 | error(1, errno, "failed to bind send socket"); | ||
91 | |||
92 | if (connect(fd, (struct sockaddr *)&daddr, sizeof(daddr))) | ||
93 | error(1, errno, "failed to connect send socket"); | ||
94 | |||
95 | if (send(fd, "a", 1, 0) < 0) | ||
96 | error(1, errno, "failed to send message"); | ||
97 | |||
98 | close(fd); | ||
99 | } | ||
100 | |||
101 | static int receive_once(int epfd, int proto) | ||
102 | { | ||
103 | struct epoll_event ev; | ||
104 | int i, fd; | ||
105 | char buf[8]; | ||
106 | |||
107 | i = epoll_wait(epfd, &ev, 1, -1); | ||
108 | if (i < 0) | ||
109 | error(1, errno, "epoll_wait failed"); | ||
110 | |||
111 | if (proto == SOCK_STREAM) { | ||
112 | fd = accept(ev.data.fd, NULL, NULL); | ||
113 | if (fd < 0) | ||
114 | error(1, errno, "failed to accept"); | ||
115 | i = recv(fd, buf, sizeof(buf), 0); | ||
116 | close(fd); | ||
117 | } else { | ||
118 | i = recv(ev.data.fd, buf, sizeof(buf), 0); | ||
119 | } | ||
120 | |||
121 | if (i < 0) | ||
122 | error(1, errno, "failed to recv"); | ||
123 | |||
124 | return ev.data.fd; | ||
125 | } | ||
126 | |||
127 | static void test(int *rcv_fds, int count, int proto) | ||
128 | { | ||
129 | struct epoll_event ev; | ||
130 | int epfd, i, test_fd; | ||
131 | uint16_t test_family; | ||
132 | socklen_t len; | ||
133 | |||
134 | epfd = epoll_create(1); | ||
135 | if (epfd < 0) | ||
136 | error(1, errno, "failed to create epoll"); | ||
137 | |||
138 | ev.events = EPOLLIN; | ||
139 | for (i = 0; i < count; ++i) { | ||
140 | ev.data.fd = rcv_fds[i]; | ||
141 | if (epoll_ctl(epfd, EPOLL_CTL_ADD, rcv_fds[i], &ev)) | ||
142 | error(1, errno, "failed to register sock epoll"); | ||
143 | } | ||
144 | |||
145 | send_from_v4(proto); | ||
146 | |||
147 | test_fd = receive_once(epfd, proto); | ||
148 | if (getsockopt(test_fd, SOL_SOCKET, SO_DOMAIN, &test_family, &len)) | ||
149 | error(1, errno, "failed to read socket domain"); | ||
150 | if (test_family != AF_INET) | ||
151 | error(1, 0, "expected to receive on v4 socket but got v6 (%d)", | ||
152 | test_family); | ||
153 | |||
154 | close(epfd); | ||
155 | } | ||
156 | |||
157 | int main(void) | ||
158 | { | ||
159 | int rcv_fds[32], i; | ||
160 | |||
161 | fprintf(stderr, "---- UDP IPv4 created before IPv6 ----\n"); | ||
162 | build_rcv_fd(AF_INET, SOCK_DGRAM, rcv_fds, 5); | ||
163 | build_rcv_fd(AF_INET6, SOCK_DGRAM, &(rcv_fds[5]), 5); | ||
164 | test(rcv_fds, 10, SOCK_DGRAM); | ||
165 | for (i = 0; i < 10; ++i) | ||
166 | close(rcv_fds[i]); | ||
167 | |||
168 | fprintf(stderr, "---- UDP IPv6 created before IPv4 ----\n"); | ||
169 | build_rcv_fd(AF_INET6, SOCK_DGRAM, rcv_fds, 5); | ||
170 | build_rcv_fd(AF_INET, SOCK_DGRAM, &(rcv_fds[5]), 5); | ||
171 | test(rcv_fds, 10, SOCK_DGRAM); | ||
172 | for (i = 0; i < 10; ++i) | ||
173 | close(rcv_fds[i]); | ||
174 | |||
175 | /* NOTE: UDP socket lookups traverse a different code path when there | ||
176 | * are > 10 sockets in a group. | ||
177 | */ | ||
178 | fprintf(stderr, "---- UDP IPv4 created before IPv6 (large) ----\n"); | ||
179 | build_rcv_fd(AF_INET, SOCK_DGRAM, rcv_fds, 16); | ||
180 | build_rcv_fd(AF_INET6, SOCK_DGRAM, &(rcv_fds[16]), 16); | ||
181 | test(rcv_fds, 32, SOCK_DGRAM); | ||
182 | for (i = 0; i < 32; ++i) | ||
183 | close(rcv_fds[i]); | ||
184 | |||
185 | fprintf(stderr, "---- UDP IPv6 created before IPv4 (large) ----\n"); | ||
186 | build_rcv_fd(AF_INET6, SOCK_DGRAM, rcv_fds, 16); | ||
187 | build_rcv_fd(AF_INET, SOCK_DGRAM, &(rcv_fds[16]), 16); | ||
188 | test(rcv_fds, 32, SOCK_DGRAM); | ||
189 | for (i = 0; i < 32; ++i) | ||
190 | close(rcv_fds[i]); | ||
191 | |||
192 | fprintf(stderr, "---- TCP IPv4 created before IPv6 ----\n"); | ||
193 | build_rcv_fd(AF_INET, SOCK_STREAM, rcv_fds, 5); | ||
194 | build_rcv_fd(AF_INET6, SOCK_STREAM, &(rcv_fds[5]), 5); | ||
195 | test(rcv_fds, 10, SOCK_STREAM); | ||
196 | for (i = 0; i < 10; ++i) | ||
197 | close(rcv_fds[i]); | ||
198 | |||
199 | fprintf(stderr, "---- TCP IPv6 created before IPv4 ----\n"); | ||
200 | build_rcv_fd(AF_INET6, SOCK_STREAM, rcv_fds, 5); | ||
201 | build_rcv_fd(AF_INET, SOCK_STREAM, &(rcv_fds[5]), 5); | ||
202 | test(rcv_fds, 10, SOCK_STREAM); | ||
203 | for (i = 0; i < 10; ++i) | ||
204 | close(rcv_fds[i]); | ||
205 | |||
206 | fprintf(stderr, "SUCCESS\n"); | ||
207 | return 0; | ||
208 | } | ||
diff --git a/tools/testing/selftests/rcutorture/bin/jitter.sh b/tools/testing/selftests/rcutorture/bin/jitter.sh new file mode 100755 index 000000000000..3633828375e3 --- /dev/null +++ b/tools/testing/selftests/rcutorture/bin/jitter.sh | |||
@@ -0,0 +1,90 @@ | |||
1 | #!/bin/bash | ||
2 | # | ||
3 | # Alternate sleeping and spinning on randomly selected CPUs. The purpose | ||
4 | # of this script is to inflict random OS jitter on a concurrently running | ||
5 | # test. | ||
6 | # | ||
7 | # Usage: jitter.sh me duration [ sleepmax [ spinmax ] ] | ||
8 | # | ||
9 | # me: Random-number-generator seed salt. | ||
10 | # duration: Time to run in seconds. | ||
11 | # sleepmax: Maximum microseconds to sleep, defaults to one second. | ||
12 | # spinmax: Maximum microseconds to spin, defaults to one millisecond. | ||
13 | # | ||
14 | # This program is free software; you can redistribute it and/or modify | ||
15 | # it under the terms of the GNU General Public License as published by | ||
16 | # the Free Software Foundation; either version 2 of the License, or | ||
17 | # (at your option) any later version. | ||
18 | # | ||
19 | # This program is distributed in the hope that it will be useful, | ||
20 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
21 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
22 | # GNU General Public License for more details. | ||
23 | # | ||
24 | # You should have received a copy of the GNU General Public License | ||
25 | # along with this program; if not, you can access it online at | ||
26 | # http://www.gnu.org/licenses/gpl-2.0.html. | ||
27 | # | ||
28 | # Copyright (C) IBM Corporation, 2016 | ||
29 | # | ||
30 | # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> | ||
31 | |||
32 | me=$(($1 * 1000)) | ||
33 | duration=$2 | ||
34 | sleepmax=${3-1000000} | ||
35 | spinmax=${4-1000} | ||
36 | |||
37 | n=1 | ||
38 | |||
39 | starttime=`awk 'BEGIN { print systime(); }' < /dev/null` | ||
40 | |||
41 | while : | ||
42 | do | ||
43 | # Check for done. | ||
44 | t=`awk -v s=$starttime 'BEGIN { print systime() - s; }' < /dev/null` | ||
45 | if test "$t" -gt "$duration" | ||
46 | then | ||
47 | exit 0; | ||
48 | fi | ||
49 | |||
50 | # Set affinity to randomly selected CPU | ||
51 | cpus=`ls /sys/devices/system/cpu/*/online | | ||
52 | sed -e 's,/[^/]*$,,' -e 's/^[^0-9]*//' | | ||
53 | grep -v '^0*$'` | ||
54 | cpumask=`awk -v cpus="$cpus" -v me=$me -v n=$n 'BEGIN { | ||
55 | srand(n + me + systime()); | ||
56 | ncpus = split(cpus, ca); | ||
57 | curcpu = ca[int(rand() * ncpus + 1)]; | ||
58 | mask = lshift(1, curcpu); | ||
59 | if (mask + 0 <= 0) | ||
60 | mask = 1; | ||
61 | printf("%#x\n", mask); | ||
62 | }' < /dev/null` | ||
63 | n=$(($n+1)) | ||
64 | if ! taskset -p $cpumask $$ > /dev/null 2>&1 | ||
65 | then | ||
66 | echo taskset failure: '"taskset -p ' $cpumask $$ '"' | ||
67 | exit 1 | ||
68 | fi | ||
69 | |||
70 | # Sleep a random duration | ||
71 | sleeptime=`awk -v me=$me -v n=$n -v sleepmax=$sleepmax 'BEGIN { | ||
72 | srand(n + me + systime()); | ||
73 | printf("%06d", int(rand() * sleepmax)); | ||
74 | }' < /dev/null` | ||
75 | n=$(($n+1)) | ||
76 | sleep .$sleeptime | ||
77 | |||
78 | # Spin a random duration | ||
79 | limit=`awk -v me=$me -v n=$n -v spinmax=$spinmax 'BEGIN { | ||
80 | srand(n + me + systime()); | ||
81 | printf("%06d", int(rand() * spinmax)); | ||
82 | }' < /dev/null` | ||
83 | n=$(($n+1)) | ||
84 | for i in {1..$limit} | ||
85 | do | ||
86 | echo > /dev/null | ||
87 | done | ||
88 | done | ||
89 | |||
90 | exit 1 | ||
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh new file mode 100755 index 000000000000..f79b0e9e84fc --- /dev/null +++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf-ftrace.sh | |||
@@ -0,0 +1,121 @@ | |||
1 | #!/bin/bash | ||
2 | # | ||
3 | # Analyze a given results directory for rcuperf performance measurements, | ||
4 | # looking for ftrace data. Exits with 0 if data was found, analyzed, and | ||
5 | # printed. Intended to be invoked from kvm-recheck-rcuperf.sh after | ||
6 | # argument checking. | ||
7 | # | ||
8 | # Usage: kvm-recheck-rcuperf-ftrace.sh resdir | ||
9 | # | ||
10 | # This program is free software; you can redistribute it and/or modify | ||
11 | # it under the terms of the GNU General Public License as published by | ||
12 | # the Free Software Foundation; either version 2 of the License, or | ||
13 | # (at your option) any later version. | ||
14 | # | ||
15 | # This program is distributed in the hope that it will be useful, | ||
16 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
17 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
18 | # GNU General Public License for more details. | ||
19 | # | ||
20 | # You should have received a copy of the GNU General Public License | ||
21 | # along with this program; if not, you can access it online at | ||
22 | # http://www.gnu.org/licenses/gpl-2.0.html. | ||
23 | # | ||
24 | # Copyright (C) IBM Corporation, 2016 | ||
25 | # | ||
26 | # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> | ||
27 | |||
28 | i="$1" | ||
29 | . tools/testing/selftests/rcutorture/bin/functions.sh | ||
30 | |||
31 | if test "`grep -c 'rcu_exp_grace_period.*start' < $i/console.log`" -lt 100 | ||
32 | then | ||
33 | exit 10 | ||
34 | fi | ||
35 | |||
36 | sed -e 's/^\[[^]]*]//' < $i/console.log | | ||
37 | grep 'us : rcu_exp_grace_period' | | ||
38 | sed -e 's/us : / : /' | | ||
39 | tr -d '\015' | | ||
40 | awk ' | ||
41 | $8 == "start" { | ||
42 | if (starttask != "") | ||
43 | nlost++; | ||
44 | starttask = $1; | ||
45 | starttime = $3; | ||
46 | startseq = $7; | ||
47 | } | ||
48 | |||
49 | $8 == "end" { | ||
50 | if (starttask == $1 && startseq == $7) { | ||
51 | curgpdur = $3 - starttime; | ||
52 | gptimes[++n] = curgpdur; | ||
53 | gptaskcnt[starttask]++; | ||
54 | sum += curgpdur; | ||
55 | if (curgpdur > 1000) | ||
56 | print "Long GP " starttime "us to " $3 "us (" curgpdur "us)"; | ||
57 | starttask = ""; | ||
58 | } else { | ||
59 | # Lost a message or some such, reset. | ||
60 | starttask = ""; | ||
61 | nlost++; | ||
62 | } | ||
63 | } | ||
64 | |||
65 | $8 == "done" { | ||
66 | piggybackcnt[$1]++; | ||
67 | } | ||
68 | |||
69 | END { | ||
70 | newNR = asort(gptimes); | ||
71 | if (newNR <= 0) { | ||
72 | print "No ftrace records found???" | ||
73 | exit 10; | ||
74 | } | ||
75 | pct50 = int(newNR * 50 / 100); | ||
76 | if (pct50 < 1) | ||
77 | pct50 = 1; | ||
78 | pct90 = int(newNR * 90 / 100); | ||
79 | if (pct90 < 1) | ||
80 | pct90 = 1; | ||
81 | pct99 = int(newNR * 99 / 100); | ||
82 | if (pct99 < 1) | ||
83 | pct99 = 1; | ||
84 | div = 10 ** int(log(gptimes[pct90]) / log(10) + .5) / 100; | ||
85 | print "Histogram bucket size: " div; | ||
86 | last = gptimes[1] - 10; | ||
87 | count = 0; | ||
88 | for (i = 1; i <= newNR; i++) { | ||
89 | current = div * int(gptimes[i] / div); | ||
90 | if (last == current) { | ||
91 | count++; | ||
92 | } else { | ||
93 | if (count > 0) | ||
94 | print last, count; | ||
95 | count = 1; | ||
96 | last = current; | ||
97 | } | ||
98 | } | ||
99 | if (count > 0) | ||
100 | print last, count; | ||
101 | print "Distribution of grace periods across tasks:"; | ||
102 | for (i in gptaskcnt) { | ||
103 | print "\t" i, gptaskcnt[i]; | ||
104 | nbatches += gptaskcnt[i]; | ||
105 | } | ||
106 | ngps = nbatches; | ||
107 | print "Distribution of piggybacking across tasks:"; | ||
108 | for (i in piggybackcnt) { | ||
109 | print "\t" i, piggybackcnt[i]; | ||
110 | ngps += piggybackcnt[i]; | ||
111 | } | ||
112 | print "Average grace-period duration: " sum / newNR " microseconds"; | ||
113 | print "Minimum grace-period duration: " gptimes[1]; | ||
114 | print "50th percentile grace-period duration: " gptimes[pct50]; | ||
115 | print "90th percentile grace-period duration: " gptimes[pct90]; | ||
116 | print "99th percentile grace-period duration: " gptimes[pct99]; | ||
117 | print "Maximum grace-period duration: " gptimes[newNR]; | ||
118 | print "Grace periods: " ngps + 0 " Batches: " nbatches + 0 " Ratio: " ngps / nbatches " Lost: " nlost + 0; | ||
119 | print "Computed from ftrace data."; | ||
120 | }' | ||
121 | exit 0 | ||
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf.sh new file mode 100755 index 000000000000..8f3121afc716 --- /dev/null +++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck-rcuperf.sh | |||
@@ -0,0 +1,96 @@ | |||
1 | #!/bin/bash | ||
2 | # | ||
3 | # Analyze a given results directory for rcuperf performance measurements. | ||
4 | # | ||
5 | # Usage: kvm-recheck-rcuperf.sh resdir | ||
6 | # | ||
7 | # This program is free software; you can redistribute it and/or modify | ||
8 | # it under the terms of the GNU General Public License as published by | ||
9 | # the Free Software Foundation; either version 2 of the License, or | ||
10 | # (at your option) any later version. | ||
11 | # | ||
12 | # This program is distributed in the hope that it will be useful, | ||
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
15 | # GNU General Public License for more details. | ||
16 | # | ||
17 | # You should have received a copy of the GNU General Public License | ||
18 | # along with this program; if not, you can access it online at | ||
19 | # http://www.gnu.org/licenses/gpl-2.0.html. | ||
20 | # | ||
21 | # Copyright (C) IBM Corporation, 2016 | ||
22 | # | ||
23 | # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> | ||
24 | |||
25 | i="$1" | ||
26 | if test -d $i | ||
27 | then | ||
28 | : | ||
29 | else | ||
30 | echo Unreadable results directory: $i | ||
31 | exit 1 | ||
32 | fi | ||
33 | PATH=`pwd`/tools/testing/selftests/rcutorture/bin:$PATH; export PATH | ||
34 | . tools/testing/selftests/rcutorture/bin/functions.sh | ||
35 | |||
36 | if kvm-recheck-rcuperf-ftrace.sh $i | ||
37 | then | ||
38 | # ftrace data was successfully analyzed, call it good! | ||
39 | exit 0 | ||
40 | fi | ||
41 | |||
42 | configfile=`echo $i | sed -e 's/^.*\///'` | ||
43 | |||
44 | sed -e 's/^\[[^]]*]//' < $i/console.log | | ||
45 | awk ' | ||
46 | /-perf: .* gps: .* batches:/ { | ||
47 | ngps = $9; | ||
48 | nbatches = $11; | ||
49 | } | ||
50 | |||
51 | /-perf: .*writer-duration/ { | ||
52 | gptimes[++n] = $5 / 1000.; | ||
53 | sum += $5 / 1000.; | ||
54 | } | ||
55 | |||
56 | END { | ||
57 | newNR = asort(gptimes); | ||
58 | if (newNR <= 0) { | ||
59 | print "No rcuperf records found???" | ||
60 | exit; | ||
61 | } | ||
62 | pct50 = int(newNR * 50 / 100); | ||
63 | if (pct50 < 1) | ||
64 | pct50 = 1; | ||
65 | pct90 = int(newNR * 90 / 100); | ||
66 | if (pct90 < 1) | ||
67 | pct90 = 1; | ||
68 | pct99 = int(newNR * 99 / 100); | ||
69 | if (pct99 < 1) | ||
70 | pct99 = 1; | ||
71 | div = 10 ** int(log(gptimes[pct90]) / log(10) + .5) / 100; | ||
72 | print "Histogram bucket size: " div; | ||
73 | last = gptimes[1] - 10; | ||
74 | count = 0; | ||
75 | for (i = 1; i <= newNR; i++) { | ||
76 | current = div * int(gptimes[i] / div); | ||
77 | if (last == current) { | ||
78 | count++; | ||
79 | } else { | ||
80 | if (count > 0) | ||
81 | print last, count; | ||
82 | count = 1; | ||
83 | last = current; | ||
84 | } | ||
85 | } | ||
86 | if (count > 0) | ||
87 | print last, count; | ||
88 | print "Average grace-period duration: " sum / newNR " microseconds"; | ||
89 | print "Minimum grace-period duration: " gptimes[1]; | ||
90 | print "50th percentile grace-period duration: " gptimes[pct50]; | ||
91 | print "90th percentile grace-period duration: " gptimes[pct90]; | ||
92 | print "99th percentile grace-period duration: " gptimes[pct99]; | ||
93 | print "Maximum grace-period duration: " gptimes[newNR]; | ||
94 | print "Grace periods: " ngps + 0 " Batches: " nbatches + 0 " Ratio: " ngps / nbatches; | ||
95 | print "Computed from rcuperf printk output."; | ||
96 | }' | ||
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh index d86bdd6b6cc2..f659346d3358 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-recheck.sh | |||
@@ -48,7 +48,10 @@ do | |||
48 | cat $i/Make.oldconfig.err | 48 | cat $i/Make.oldconfig.err |
49 | fi | 49 | fi |
50 | parse-build.sh $i/Make.out $configfile | 50 | parse-build.sh $i/Make.out $configfile |
51 | parse-torture.sh $i/console.log $configfile | 51 | if test "$TORTURE_SUITE" != rcuperf |
52 | then | ||
53 | parse-torture.sh $i/console.log $configfile | ||
54 | fi | ||
52 | parse-console.sh $i/console.log $configfile | 55 | parse-console.sh $i/console.log $configfile |
53 | if test -r $i/Warnings | 56 | if test -r $i/Warnings |
54 | then | 57 | then |
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh index 0f80eefb0bfd..4109f306d855 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh | |||
@@ -6,7 +6,7 @@ | |||
6 | # Execute this in the source tree. Do not run it as a background task | 6 | # Execute this in the source tree. Do not run it as a background task |
7 | # because qemu does not seem to like that much. | 7 | # because qemu does not seem to like that much. |
8 | # | 8 | # |
9 | # Usage: kvm-test-1-run.sh config builddir resdir minutes qemu-args boot_args | 9 | # Usage: kvm-test-1-run.sh config builddir resdir seconds qemu-args boot_args |
10 | # | 10 | # |
11 | # qemu-args defaults to "-enable-kvm -soundhw pcspk -nographic", along with | 11 | # qemu-args defaults to "-enable-kvm -soundhw pcspk -nographic", along with |
12 | # arguments specifying the number of CPUs and other | 12 | # arguments specifying the number of CPUs and other |
@@ -91,25 +91,33 @@ fi | |||
91 | # CONFIG_PCMCIA=n | 91 | # CONFIG_PCMCIA=n |
92 | # CONFIG_CARDBUS=n | 92 | # CONFIG_CARDBUS=n |
93 | # CONFIG_YENTA=n | 93 | # CONFIG_YENTA=n |
94 | if kvm-build.sh $config_template $builddir $T | 94 | base_resdir=`echo $resdir | sed -e 's/\.[0-9]\+$//'` |
95 | if test "$base_resdir" != "$resdir" -a -f $base_resdir/bzImage -a -f $base_resdir/vmlinux | ||
95 | then | 96 | then |
97 | # Rerunning previous test, so use that test's kernel. | ||
98 | QEMU="`identify_qemu $base_resdir/vmlinux`" | ||
99 | KERNEL=$base_resdir/bzImage | ||
100 | ln -s $base_resdir/Make*.out $resdir # for kvm-recheck.sh | ||
101 | ln -s $base_resdir/.config $resdir # for kvm-recheck.sh | ||
102 | elif kvm-build.sh $config_template $builddir $T | ||
103 | then | ||
104 | # Had to build a kernel for this test. | ||
96 | QEMU="`identify_qemu $builddir/vmlinux`" | 105 | QEMU="`identify_qemu $builddir/vmlinux`" |
97 | BOOT_IMAGE="`identify_boot_image $QEMU`" | 106 | BOOT_IMAGE="`identify_boot_image $QEMU`" |
98 | cp $builddir/Make*.out $resdir | 107 | cp $builddir/Make*.out $resdir |
108 | cp $builddir/vmlinux $resdir | ||
99 | cp $builddir/.config $resdir | 109 | cp $builddir/.config $resdir |
100 | if test -n "$BOOT_IMAGE" | 110 | if test -n "$BOOT_IMAGE" |
101 | then | 111 | then |
102 | cp $builddir/$BOOT_IMAGE $resdir | 112 | cp $builddir/$BOOT_IMAGE $resdir |
113 | KERNEL=$resdir/bzImage | ||
103 | else | 114 | else |
104 | echo No identifiable boot image, not running KVM, see $resdir. | 115 | echo No identifiable boot image, not running KVM, see $resdir. |
105 | echo Do the torture scripts know about your architecture? | 116 | echo Do the torture scripts know about your architecture? |
106 | fi | 117 | fi |
107 | parse-build.sh $resdir/Make.out $title | 118 | parse-build.sh $resdir/Make.out $title |
108 | if test -f $builddir.wait | ||
109 | then | ||
110 | mv $builddir.wait $builddir.ready | ||
111 | fi | ||
112 | else | 119 | else |
120 | # Build failed. | ||
113 | cp $builddir/Make*.out $resdir | 121 | cp $builddir/Make*.out $resdir |
114 | cp $builddir/.config $resdir || : | 122 | cp $builddir/.config $resdir || : |
115 | echo Build failed, not running KVM, see $resdir. | 123 | echo Build failed, not running KVM, see $resdir. |
@@ -119,12 +127,15 @@ else | |||
119 | fi | 127 | fi |
120 | exit 1 | 128 | exit 1 |
121 | fi | 129 | fi |
130 | if test -f $builddir.wait | ||
131 | then | ||
132 | mv $builddir.wait $builddir.ready | ||
133 | fi | ||
122 | while test -f $builddir.ready | 134 | while test -f $builddir.ready |
123 | do | 135 | do |
124 | sleep 1 | 136 | sleep 1 |
125 | done | 137 | done |
126 | minutes=$4 | 138 | seconds=$4 |
127 | seconds=$(($minutes * 60)) | ||
128 | qemu_args=$5 | 139 | qemu_args=$5 |
129 | boot_args=$6 | 140 | boot_args=$6 |
130 | 141 | ||
@@ -167,15 +178,26 @@ then | |||
167 | exit 0 | 178 | exit 0 |
168 | fi | 179 | fi |
169 | echo "NOTE: $QEMU either did not run or was interactive" > $resdir/console.log | 180 | echo "NOTE: $QEMU either did not run or was interactive" > $resdir/console.log |
170 | echo $QEMU $qemu_args -m 512 -kernel $resdir/bzImage -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd | 181 | echo $QEMU $qemu_args -m 512 -kernel $KERNEL -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd |
171 | ( $QEMU $qemu_args -m 512 -kernel $resdir/bzImage -append "$qemu_append $boot_args"; echo $? > $resdir/qemu-retval ) & | 182 | ( $QEMU $qemu_args -m 512 -kernel $KERNEL -append "$qemu_append $boot_args"& echo $! > $resdir/qemu_pid; wait `cat $resdir/qemu_pid`; echo $? > $resdir/qemu-retval ) & |
172 | qemu_pid=$! | ||
173 | commandcompleted=0 | 183 | commandcompleted=0 |
174 | echo Monitoring qemu job at pid $qemu_pid | 184 | sleep 10 # Give qemu's pid a chance to reach the file |
185 | if test -s "$resdir/qemu_pid" | ||
186 | then | ||
187 | qemu_pid=`cat "$resdir/qemu_pid"` | ||
188 | echo Monitoring qemu job at pid $qemu_pid | ||
189 | else | ||
190 | qemu_pid="" | ||
191 | echo Monitoring qemu job at yet-as-unknown pid | ||
192 | fi | ||
175 | while : | 193 | while : |
176 | do | 194 | do |
195 | if test -z "$qemu_pid" -a -s "$resdir/qemu_pid" | ||
196 | then | ||
197 | qemu_pid=`cat "$resdir/qemu_pid"` | ||
198 | fi | ||
177 | kruntime=`awk 'BEGIN { print systime() - '"$kstarttime"' }' < /dev/null` | 199 | kruntime=`awk 'BEGIN { print systime() - '"$kstarttime"' }' < /dev/null` |
178 | if kill -0 $qemu_pid > /dev/null 2>&1 | 200 | if test -z "$qemu_pid" || kill -0 "$qemu_pid" > /dev/null 2>&1 |
179 | then | 201 | then |
180 | if test $kruntime -ge $seconds | 202 | if test $kruntime -ge $seconds |
181 | then | 203 | then |
@@ -195,12 +217,16 @@ do | |||
195 | ps -fp $killpid >> $resdir/Warnings 2>&1 | 217 | ps -fp $killpid >> $resdir/Warnings 2>&1 |
196 | fi | 218 | fi |
197 | else | 219 | else |
198 | echo ' ---' `date`: Kernel done | 220 | echo ' ---' `date`: "Kernel done" |
199 | fi | 221 | fi |
200 | break | 222 | break |
201 | fi | 223 | fi |
202 | done | 224 | done |
203 | if test $commandcompleted -eq 0 | 225 | if test -z "$qemu_pid" -a -s "$resdir/qemu_pid" |
226 | then | ||
227 | qemu_pid=`cat "$resdir/qemu_pid"` | ||
228 | fi | ||
229 | if test $commandcompleted -eq 0 -a -n "$qemu_pid" | ||
204 | then | 230 | then |
205 | echo Grace period for qemu job at pid $qemu_pid | 231 | echo Grace period for qemu job at pid $qemu_pid |
206 | while : | 232 | while : |
@@ -220,6 +246,9 @@ then | |||
220 | fi | 246 | fi |
221 | sleep 1 | 247 | sleep 1 |
222 | done | 248 | done |
249 | elif test -z "$qemu_pid" | ||
250 | then | ||
251 | echo Unknown PID, cannot kill qemu command | ||
223 | fi | 252 | fi |
224 | 253 | ||
225 | parse-torture.sh $resdir/console.log $title | 254 | parse-torture.sh $resdir/console.log $title |
diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh index 4a431767f77a..0d598145873e 100755 --- a/tools/testing/selftests/rcutorture/bin/kvm.sh +++ b/tools/testing/selftests/rcutorture/bin/kvm.sh | |||
@@ -34,7 +34,7 @@ T=/tmp/kvm.sh.$$ | |||
34 | trap 'rm -rf $T' 0 | 34 | trap 'rm -rf $T' 0 |
35 | mkdir $T | 35 | mkdir $T |
36 | 36 | ||
37 | dur=30 | 37 | dur=$((30*60)) |
38 | dryrun="" | 38 | dryrun="" |
39 | KVM="`pwd`/tools/testing/selftests/rcutorture"; export KVM | 39 | KVM="`pwd`/tools/testing/selftests/rcutorture"; export KVM |
40 | PATH=${KVM}/bin:$PATH; export PATH | 40 | PATH=${KVM}/bin:$PATH; export PATH |
@@ -48,6 +48,7 @@ resdir="" | |||
48 | configs="" | 48 | configs="" |
49 | cpus=0 | 49 | cpus=0 |
50 | ds=`date +%Y.%m.%d-%H:%M:%S` | 50 | ds=`date +%Y.%m.%d-%H:%M:%S` |
51 | jitter=0 | ||
51 | 52 | ||
52 | . functions.sh | 53 | . functions.sh |
53 | 54 | ||
@@ -63,6 +64,7 @@ usage () { | |||
63 | echo " --dryrun sched|script" | 64 | echo " --dryrun sched|script" |
64 | echo " --duration minutes" | 65 | echo " --duration minutes" |
65 | echo " --interactive" | 66 | echo " --interactive" |
67 | echo " --jitter N [ maxsleep (us) [ maxspin (us) ] ]" | ||
66 | echo " --kmake-arg kernel-make-arguments" | 68 | echo " --kmake-arg kernel-make-arguments" |
67 | echo " --mac nn:nn:nn:nn:nn:nn" | 69 | echo " --mac nn:nn:nn:nn:nn:nn" |
68 | echo " --no-initrd" | 70 | echo " --no-initrd" |
@@ -116,12 +118,17 @@ do | |||
116 | ;; | 118 | ;; |
117 | --duration) | 119 | --duration) |
118 | checkarg --duration "(minutes)" $# "$2" '^[0-9]*$' '^error' | 120 | checkarg --duration "(minutes)" $# "$2" '^[0-9]*$' '^error' |
119 | dur=$2 | 121 | dur=$(($2*60)) |
120 | shift | 122 | shift |
121 | ;; | 123 | ;; |
122 | --interactive) | 124 | --interactive) |
123 | TORTURE_QEMU_INTERACTIVE=1; export TORTURE_QEMU_INTERACTIVE | 125 | TORTURE_QEMU_INTERACTIVE=1; export TORTURE_QEMU_INTERACTIVE |
124 | ;; | 126 | ;; |
127 | --jitter) | ||
128 | checkarg --jitter "(# threads [ sleep [ spin ] ])" $# "$2" '^-\{,1\}[0-9]\+\( \+[0-9]\+\)\{,2\} *$' '^error$' | ||
129 | jitter="$2" | ||
130 | shift | ||
131 | ;; | ||
125 | --kmake-arg) | 132 | --kmake-arg) |
126 | checkarg --kmake-arg "(kernel make arguments)" $# "$2" '.*' '^error$' | 133 | checkarg --kmake-arg "(kernel make arguments)" $# "$2" '.*' '^error$' |
127 | TORTURE_KMAKE_ARG="$2" | 134 | TORTURE_KMAKE_ARG="$2" |
@@ -156,7 +163,7 @@ do | |||
156 | shift | 163 | shift |
157 | ;; | 164 | ;; |
158 | --torture) | 165 | --torture) |
159 | checkarg --torture "(suite name)" "$#" "$2" '^\(lock\|rcu\)$' '^--' | 166 | checkarg --torture "(suite name)" "$#" "$2" '^\(lock\|rcu\|rcuperf\)$' '^--' |
160 | TORTURE_SUITE=$2 | 167 | TORTURE_SUITE=$2 |
161 | shift | 168 | shift |
162 | ;; | 169 | ;; |
@@ -299,6 +306,7 @@ awk < $T/cfgcpu.pack \ | |||
299 | -v CONFIGDIR="$CONFIGFRAG/" \ | 306 | -v CONFIGDIR="$CONFIGFRAG/" \ |
300 | -v KVM="$KVM" \ | 307 | -v KVM="$KVM" \ |
301 | -v ncpus=$cpus \ | 308 | -v ncpus=$cpus \ |
309 | -v jitter="$jitter" \ | ||
302 | -v rd=$resdir/$ds/ \ | 310 | -v rd=$resdir/$ds/ \ |
303 | -v dur=$dur \ | 311 | -v dur=$dur \ |
304 | -v TORTURE_QEMU_ARG="$TORTURE_QEMU_ARG" \ | 312 | -v TORTURE_QEMU_ARG="$TORTURE_QEMU_ARG" \ |
@@ -359,6 +367,16 @@ function dump(first, pastlast, batchnum) | |||
359 | print "\techo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date` >> " rd "/log"; | 367 | print "\techo ----", cfr[j], cpusr[j] ovf ": Starting kernel. `date` >> " rd "/log"; |
360 | print "fi" | 368 | print "fi" |
361 | } | 369 | } |
370 | njitter = 0; | ||
371 | split(jitter, ja); | ||
372 | if (ja[1] == -1 && ncpus == 0) | ||
373 | njitter = 1; | ||
374 | else if (ja[1] == -1) | ||
375 | njitter = ncpus; | ||
376 | else | ||
377 | njitter = ja[1]; | ||
378 | for (j = 0; j < njitter; j++) | ||
379 | print "jitter.sh " j " " dur " " ja[2] " " ja[3] "&" | ||
362 | print "wait" | 380 | print "wait" |
363 | print "if test -z \"$TORTURE_BUILDONLY\"" | 381 | print "if test -z \"$TORTURE_BUILDONLY\"" |
364 | print "then" | 382 | print "then" |
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE04 b/tools/testing/selftests/rcutorture/configs/rcu/TREE04 index 39a2c6d7d7ec..17cbe098b115 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE04 +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE04 | |||
@@ -14,7 +14,7 @@ CONFIG_HOTPLUG_CPU=n | |||
14 | CONFIG_SUSPEND=n | 14 | CONFIG_SUSPEND=n |
15 | CONFIG_HIBERNATION=n | 15 | CONFIG_HIBERNATION=n |
16 | CONFIG_RCU_FANOUT=4 | 16 | CONFIG_RCU_FANOUT=4 |
17 | CONFIG_RCU_FANOUT_LEAF=4 | 17 | CONFIG_RCU_FANOUT_LEAF=3 |
18 | CONFIG_RCU_NOCB_CPU=n | 18 | CONFIG_RCU_NOCB_CPU=n |
19 | CONFIG_DEBUG_LOCK_ALLOC=n | 19 | CONFIG_DEBUG_LOCK_ALLOC=n |
20 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | 20 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n |
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot index 0fc8a3428938..e34c33430447 100644 --- a/tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot +++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE04.boot | |||
@@ -1 +1 @@ | |||
rcutorture.torture_type=rcu_bh | rcutorture.torture_type=rcu_bh rcutree.rcu_fanout_leaf=4 | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcuperf/CFLIST b/tools/testing/selftests/rcutorture/configs/rcuperf/CFLIST new file mode 100644 index 000000000000..c9f56cf20775 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/rcuperf/CFLIST | |||
@@ -0,0 +1 @@ | |||
TREE | |||
diff --git a/tools/testing/selftests/rcutorture/configs/rcuperf/CFcommon b/tools/testing/selftests/rcutorture/configs/rcuperf/CFcommon new file mode 100644 index 000000000000..a09816b8c0f3 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/rcuperf/CFcommon | |||
@@ -0,0 +1,2 @@ | |||
1 | CONFIG_RCU_PERF_TEST=y | ||
2 | CONFIG_PRINTK_TIME=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcuperf/TREE b/tools/testing/selftests/rcutorture/configs/rcuperf/TREE new file mode 100644 index 000000000000..a312f671a29a --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/rcuperf/TREE | |||
@@ -0,0 +1,20 @@ | |||
1 | CONFIG_SMP=y | ||
2 | CONFIG_PREEMPT_NONE=n | ||
3 | CONFIG_PREEMPT_VOLUNTARY=n | ||
4 | CONFIG_PREEMPT=y | ||
5 | #CHECK#CONFIG_PREEMPT_RCU=y | ||
6 | CONFIG_HZ_PERIODIC=n | ||
7 | CONFIG_NO_HZ_IDLE=y | ||
8 | CONFIG_NO_HZ_FULL=n | ||
9 | CONFIG_RCU_FAST_NO_HZ=n | ||
10 | CONFIG_RCU_TRACE=n | ||
11 | CONFIG_HOTPLUG_CPU=n | ||
12 | CONFIG_SUSPEND=n | ||
13 | CONFIG_HIBERNATION=n | ||
14 | CONFIG_RCU_NOCB_CPU=n | ||
15 | CONFIG_DEBUG_LOCK_ALLOC=n | ||
16 | CONFIG_PROVE_LOCKING=n | ||
17 | CONFIG_RCU_BOOST=n | ||
18 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | ||
19 | CONFIG_RCU_EXPERT=y | ||
20 | CONFIG_RCU_TRACE=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcuperf/TREE54 b/tools/testing/selftests/rcutorture/configs/rcuperf/TREE54 new file mode 100644 index 000000000000..985fb170d13c --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/rcuperf/TREE54 | |||
@@ -0,0 +1,23 @@ | |||
1 | CONFIG_SMP=y | ||
2 | CONFIG_NR_CPUS=54 | ||
3 | CONFIG_PREEMPT_NONE=n | ||
4 | CONFIG_PREEMPT_VOLUNTARY=n | ||
5 | CONFIG_PREEMPT=y | ||
6 | #CHECK#CONFIG_PREEMPT_RCU=y | ||
7 | CONFIG_HZ_PERIODIC=n | ||
8 | CONFIG_NO_HZ_IDLE=y | ||
9 | CONFIG_NO_HZ_FULL=n | ||
10 | CONFIG_RCU_FAST_NO_HZ=n | ||
11 | CONFIG_RCU_TRACE=n | ||
12 | CONFIG_HOTPLUG_CPU=n | ||
13 | CONFIG_SUSPEND=n | ||
14 | CONFIG_HIBERNATION=n | ||
15 | CONFIG_RCU_FANOUT=3 | ||
16 | CONFIG_RCU_FANOUT_LEAF=2 | ||
17 | CONFIG_RCU_NOCB_CPU=n | ||
18 | CONFIG_DEBUG_LOCK_ALLOC=n | ||
19 | CONFIG_PROVE_LOCKING=n | ||
20 | CONFIG_RCU_BOOST=n | ||
21 | CONFIG_DEBUG_OBJECTS_RCU_HEAD=n | ||
22 | CONFIG_RCU_EXPERT=y | ||
23 | CONFIG_RCU_TRACE=y | ||
diff --git a/tools/testing/selftests/rcutorture/configs/rcuperf/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/rcuperf/ver_functions.sh new file mode 100644 index 000000000000..34f2a1b35ee5 --- /dev/null +++ b/tools/testing/selftests/rcutorture/configs/rcuperf/ver_functions.sh | |||
@@ -0,0 +1,52 @@ | |||
1 | #!/bin/bash | ||
2 | # | ||
3 | # Torture-suite-dependent shell functions for the rest of the scripts. | ||
4 | # | ||
5 | # This program is free software; you can redistribute it and/or modify | ||
6 | # it under the terms of the GNU General Public License as published by | ||
7 | # the Free Software Foundation; either version 2 of the License, or | ||
8 | # (at your option) any later version. | ||
9 | # | ||
10 | # This program is distributed in the hope that it will be useful, | ||
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | # GNU General Public License for more details. | ||
14 | # | ||
15 | # You should have received a copy of the GNU General Public License | ||
16 | # along with this program; if not, you can access it online at | ||
17 | # http://www.gnu.org/licenses/gpl-2.0.html. | ||
18 | # | ||
19 | # Copyright (C) IBM Corporation, 2015 | ||
20 | # | ||
21 | # Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com> | ||
22 | |||
23 | # rcuperf_param_nreaders bootparam-string | ||
24 | # | ||
25 | # Adds nreaders rcuperf module parameter if not already specified. | ||
26 | rcuperf_param_nreaders () { | ||
27 | if ! echo "$1" | grep -q "rcuperf.nreaders" | ||
28 | then | ||
29 | echo rcuperf.nreaders=-1 | ||
30 | fi | ||
31 | } | ||
32 | |||
33 | # rcuperf_param_nwriters bootparam-string | ||
34 | # | ||
35 | # Adds nwriters rcuperf module parameter if not already specified. | ||
36 | rcuperf_param_nwriters () { | ||
37 | if ! echo "$1" | grep -q "rcuperf.nwriters" | ||
38 | then | ||
39 | echo rcuperf.nwriters=-1 | ||
40 | fi | ||
41 | } | ||
42 | |||
43 | # per_version_boot_params bootparam-string config-file seconds | ||
44 | # | ||
45 | # Adds per-version torture-module parameters to kernels supporting them. | ||
46 | per_version_boot_params () { | ||
47 | echo $1 `rcuperf_param_nreaders "$1"` \ | ||
48 | `rcuperf_param_nwriters "$1"` \ | ||
49 | rcuperf.perf_runnable=1 \ | ||
50 | rcuperf.shutdown=1 \ | ||
51 | rcuperf.verbose=1 | ||
52 | } | ||
diff --git a/tools/testing/selftests/sigaltstack/Makefile b/tools/testing/selftests/sigaltstack/Makefile new file mode 100644 index 000000000000..56af56eda6fa --- /dev/null +++ b/tools/testing/selftests/sigaltstack/Makefile | |||
@@ -0,0 +1,8 @@ | |||
1 | CFLAGS = -Wall | ||
2 | BINARIES = sas | ||
3 | all: $(BINARIES) | ||
4 | |||
5 | include ../lib.mk | ||
6 | |||
7 | clean: | ||
8 | rm -rf $(BINARIES) | ||
diff --git a/tools/testing/selftests/sigaltstack/sas.c b/tools/testing/selftests/sigaltstack/sas.c new file mode 100644 index 000000000000..1bb01258e559 --- /dev/null +++ b/tools/testing/selftests/sigaltstack/sas.c | |||
@@ -0,0 +1,176 @@ | |||
1 | /* | ||
2 | * Stas Sergeev <stsp@users.sourceforge.net> | ||
3 | * | ||
4 | * test sigaltstack(SS_ONSTACK | SS_AUTODISARM) | ||
5 | * If that succeeds, then swapcontext() can be used inside sighandler safely. | ||
6 | * | ||
7 | */ | ||
8 | |||
9 | #define _GNU_SOURCE | ||
10 | #include <signal.h> | ||
11 | #include <stdio.h> | ||
12 | #include <stdlib.h> | ||
13 | #include <sys/mman.h> | ||
14 | #include <ucontext.h> | ||
15 | #include <alloca.h> | ||
16 | #include <string.h> | ||
17 | #include <assert.h> | ||
18 | #include <errno.h> | ||
19 | |||
20 | #ifndef SS_AUTODISARM | ||
21 | #define SS_AUTODISARM (1U << 31) | ||
22 | #endif | ||
23 | |||
24 | static void *sstack, *ustack; | ||
25 | static ucontext_t uc, sc; | ||
26 | static const char *msg = "[OK]\tStack preserved"; | ||
27 | static const char *msg2 = "[FAIL]\tStack corrupted"; | ||
28 | struct stk_data { | ||
29 | char msg[128]; | ||
30 | int flag; | ||
31 | }; | ||
32 | |||
33 | void my_usr1(int sig, siginfo_t *si, void *u) | ||
34 | { | ||
35 | char *aa; | ||
36 | int err; | ||
37 | stack_t stk; | ||
38 | struct stk_data *p; | ||
39 | |||
40 | register unsigned long sp asm("sp"); | ||
41 | |||
42 | if (sp < (unsigned long)sstack || | ||
43 | sp >= (unsigned long)sstack + SIGSTKSZ) { | ||
44 | printf("[FAIL]\tSP is not on sigaltstack\n"); | ||
45 | exit(EXIT_FAILURE); | ||
46 | } | ||
47 | /* put some data on stack. other sighandler will try to overwrite it */ | ||
48 | aa = alloca(1024); | ||
49 | assert(aa); | ||
50 | p = (struct stk_data *)(aa + 512); | ||
51 | strcpy(p->msg, msg); | ||
52 | p->flag = 1; | ||
53 | printf("[RUN]\tsignal USR1\n"); | ||
54 | err = sigaltstack(NULL, &stk); | ||
55 | if (err) { | ||
56 | perror("[FAIL]\tsigaltstack()"); | ||
57 | exit(EXIT_FAILURE); | ||
58 | } | ||
59 | if (stk.ss_flags != SS_DISABLE) | ||
60 | printf("[FAIL]\tss_flags=%i, should be SS_DISABLE\n", | ||
61 | stk.ss_flags); | ||
62 | else | ||
63 | printf("[OK]\tsigaltstack is disabled in sighandler\n"); | ||
64 | swapcontext(&sc, &uc); | ||
65 | printf("%s\n", p->msg); | ||
66 | if (!p->flag) { | ||
67 | printf("[RUN]\tAborting\n"); | ||
68 | exit(EXIT_FAILURE); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | void my_usr2(int sig, siginfo_t *si, void *u) | ||
73 | { | ||
74 | char *aa; | ||
75 | struct stk_data *p; | ||
76 | |||
77 | printf("[RUN]\tsignal USR2\n"); | ||
78 | aa = alloca(1024); | ||
79 | /* dont run valgrind on this */ | ||
80 | /* try to find the data stored by previous sighandler */ | ||
81 | p = memmem(aa, 1024, msg, strlen(msg)); | ||
82 | if (p) { | ||
83 | printf("[FAIL]\tsigaltstack re-used\n"); | ||
84 | /* corrupt the data */ | ||
85 | strcpy(p->msg, msg2); | ||
86 | /* tell other sighandler that his data is corrupted */ | ||
87 | p->flag = 0; | ||
88 | } | ||
89 | } | ||
90 | |||
91 | static void switch_fn(void) | ||
92 | { | ||
93 | printf("[RUN]\tswitched to user ctx\n"); | ||
94 | raise(SIGUSR2); | ||
95 | setcontext(&sc); | ||
96 | } | ||
97 | |||
98 | int main(void) | ||
99 | { | ||
100 | struct sigaction act; | ||
101 | stack_t stk; | ||
102 | int err; | ||
103 | |||
104 | sigemptyset(&act.sa_mask); | ||
105 | act.sa_flags = SA_ONSTACK | SA_SIGINFO; | ||
106 | act.sa_sigaction = my_usr1; | ||
107 | sigaction(SIGUSR1, &act, NULL); | ||
108 | act.sa_sigaction = my_usr2; | ||
109 | sigaction(SIGUSR2, &act, NULL); | ||
110 | sstack = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE, | ||
111 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); | ||
112 | if (sstack == MAP_FAILED) { | ||
113 | perror("mmap()"); | ||
114 | return EXIT_FAILURE; | ||
115 | } | ||
116 | |||
117 | err = sigaltstack(NULL, &stk); | ||
118 | if (err) { | ||
119 | perror("[FAIL]\tsigaltstack()"); | ||
120 | exit(EXIT_FAILURE); | ||
121 | } | ||
122 | if (stk.ss_flags == SS_DISABLE) { | ||
123 | printf("[OK]\tInitial sigaltstack state was SS_DISABLE\n"); | ||
124 | } else { | ||
125 | printf("[FAIL]\tInitial sigaltstack state was %i; should have been SS_DISABLE\n", stk.ss_flags); | ||
126 | return EXIT_FAILURE; | ||
127 | } | ||
128 | |||
129 | stk.ss_sp = sstack; | ||
130 | stk.ss_size = SIGSTKSZ; | ||
131 | stk.ss_flags = SS_ONSTACK | SS_AUTODISARM; | ||
132 | err = sigaltstack(&stk, NULL); | ||
133 | if (err) { | ||
134 | if (errno == EINVAL) { | ||
135 | printf("[NOTE]\tThe running kernel doesn't support SS_AUTODISARM\n"); | ||
136 | /* | ||
137 | * If test cases for the !SS_AUTODISARM variant were | ||
138 | * added, we could still run them. We don't have any | ||
139 | * test cases like that yet, so just exit and report | ||
140 | * success. | ||
141 | */ | ||
142 | return 0; | ||
143 | } else { | ||
144 | perror("[FAIL]\tsigaltstack(SS_ONSTACK | SS_AUTODISARM)"); | ||
145 | return EXIT_FAILURE; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | ustack = mmap(NULL, SIGSTKSZ, PROT_READ | PROT_WRITE, | ||
150 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0); | ||
151 | if (ustack == MAP_FAILED) { | ||
152 | perror("mmap()"); | ||
153 | return EXIT_FAILURE; | ||
154 | } | ||
155 | getcontext(&uc); | ||
156 | uc.uc_link = NULL; | ||
157 | uc.uc_stack.ss_sp = ustack; | ||
158 | uc.uc_stack.ss_size = SIGSTKSZ; | ||
159 | makecontext(&uc, switch_fn, 0); | ||
160 | raise(SIGUSR1); | ||
161 | |||
162 | err = sigaltstack(NULL, &stk); | ||
163 | if (err) { | ||
164 | perror("[FAIL]\tsigaltstack()"); | ||
165 | exit(EXIT_FAILURE); | ||
166 | } | ||
167 | if (stk.ss_flags != SS_AUTODISARM) { | ||
168 | printf("[FAIL]\tss_flags=%i, should be SS_AUTODISARM\n", | ||
169 | stk.ss_flags); | ||
170 | exit(EXIT_FAILURE); | ||
171 | } | ||
172 | printf("[OK]\tsigaltstack is still SS_AUTODISARM after signal\n"); | ||
173 | |||
174 | printf("[OK]\tTest passed\n"); | ||
175 | return 0; | ||
176 | } | ||
diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile index b47ebd170690..c73425de3cfe 100644 --- a/tools/testing/selftests/x86/Makefile +++ b/tools/testing/selftests/x86/Makefile | |||
@@ -9,6 +9,7 @@ TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_sysc | |||
9 | TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \ | 9 | TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \ |
10 | test_FCMOV test_FCOMI test_FISTTP \ | 10 | test_FCMOV test_FCOMI test_FISTTP \ |
11 | vdso_restorer | 11 | vdso_restorer |
12 | TARGETS_C_64BIT_ONLY := fsgsbase | ||
12 | 13 | ||
13 | TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY) | 14 | TARGETS_C_32BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_32BIT_ONLY) |
14 | TARGETS_C_64BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_64BIT_ONLY) | 15 | TARGETS_C_64BIT_ALL := $(TARGETS_C_BOTHBITS) $(TARGETS_C_64BIT_ONLY) |
diff --git a/tools/testing/selftests/x86/fsgsbase.c b/tools/testing/selftests/x86/fsgsbase.c new file mode 100644 index 000000000000..5b2b4b3c634c --- /dev/null +++ b/tools/testing/selftests/x86/fsgsbase.c | |||
@@ -0,0 +1,398 @@ | |||
1 | /* | ||
2 | * fsgsbase.c, an fsgsbase test | ||
3 | * Copyright (c) 2014-2016 Andy Lutomirski | ||
4 | * GPL v2 | ||
5 | */ | ||
6 | |||
7 | #define _GNU_SOURCE | ||
8 | #include <stdio.h> | ||
9 | #include <stdlib.h> | ||
10 | #include <stdbool.h> | ||
11 | #include <string.h> | ||
12 | #include <sys/syscall.h> | ||
13 | #include <unistd.h> | ||
14 | #include <err.h> | ||
15 | #include <sys/user.h> | ||
16 | #include <asm/prctl.h> | ||
17 | #include <sys/prctl.h> | ||
18 | #include <signal.h> | ||
19 | #include <limits.h> | ||
20 | #include <sys/ucontext.h> | ||
21 | #include <sched.h> | ||
22 | #include <linux/futex.h> | ||
23 | #include <pthread.h> | ||
24 | #include <asm/ldt.h> | ||
25 | #include <sys/mman.h> | ||
26 | |||
27 | #ifndef __x86_64__ | ||
28 | # error This test is 64-bit only | ||
29 | #endif | ||
30 | |||
31 | static volatile sig_atomic_t want_segv; | ||
32 | static volatile unsigned long segv_addr; | ||
33 | |||
34 | static int nerrs; | ||
35 | |||
36 | static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), | ||
37 | int flags) | ||
38 | { | ||
39 | struct sigaction sa; | ||
40 | memset(&sa, 0, sizeof(sa)); | ||
41 | sa.sa_sigaction = handler; | ||
42 | sa.sa_flags = SA_SIGINFO | flags; | ||
43 | sigemptyset(&sa.sa_mask); | ||
44 | if (sigaction(sig, &sa, 0)) | ||
45 | err(1, "sigaction"); | ||
46 | } | ||
47 | |||
48 | static void clearhandler(int sig) | ||
49 | { | ||
50 | struct sigaction sa; | ||
51 | memset(&sa, 0, sizeof(sa)); | ||
52 | sa.sa_handler = SIG_DFL; | ||
53 | sigemptyset(&sa.sa_mask); | ||
54 | if (sigaction(sig, &sa, 0)) | ||
55 | err(1, "sigaction"); | ||
56 | } | ||
57 | |||
58 | static void sigsegv(int sig, siginfo_t *si, void *ctx_void) | ||
59 | { | ||
60 | ucontext_t *ctx = (ucontext_t*)ctx_void; | ||
61 | |||
62 | if (!want_segv) { | ||
63 | clearhandler(SIGSEGV); | ||
64 | return; /* Crash cleanly. */ | ||
65 | } | ||
66 | |||
67 | want_segv = false; | ||
68 | segv_addr = (unsigned long)si->si_addr; | ||
69 | |||
70 | ctx->uc_mcontext.gregs[REG_RIP] += 4; /* Skip the faulting mov */ | ||
71 | |||
72 | } | ||
73 | |||
74 | enum which_base { FS, GS }; | ||
75 | |||
76 | static unsigned long read_base(enum which_base which) | ||
77 | { | ||
78 | unsigned long offset; | ||
79 | /* | ||
80 | * Unless we have FSGSBASE, there's no direct way to do this from | ||
81 | * user mode. We can get at it indirectly using signals, though. | ||
82 | */ | ||
83 | |||
84 | want_segv = true; | ||
85 | |||
86 | offset = 0; | ||
87 | if (which == FS) { | ||
88 | /* Use a constant-length instruction here. */ | ||
89 | asm volatile ("mov %%fs:(%%rcx), %%rax" : : "c" (offset) : "rax"); | ||
90 | } else { | ||
91 | asm volatile ("mov %%gs:(%%rcx), %%rax" : : "c" (offset) : "rax"); | ||
92 | } | ||
93 | if (!want_segv) | ||
94 | return segv_addr + offset; | ||
95 | |||
96 | /* | ||
97 | * If that didn't segfault, try the other end of the address space. | ||
98 | * Unless we get really unlucky and run into the vsyscall page, this | ||
99 | * is guaranteed to segfault. | ||
100 | */ | ||
101 | |||
102 | offset = (ULONG_MAX >> 1) + 1; | ||
103 | if (which == FS) { | ||
104 | asm volatile ("mov %%fs:(%%rcx), %%rax" | ||
105 | : : "c" (offset) : "rax"); | ||
106 | } else { | ||
107 | asm volatile ("mov %%gs:(%%rcx), %%rax" | ||
108 | : : "c" (offset) : "rax"); | ||
109 | } | ||
110 | if (!want_segv) | ||
111 | return segv_addr + offset; | ||
112 | |||
113 | abort(); | ||
114 | } | ||
115 | |||
116 | static void check_gs_value(unsigned long value) | ||
117 | { | ||
118 | unsigned long base; | ||
119 | unsigned short sel; | ||
120 | |||
121 | printf("[RUN]\tARCH_SET_GS to 0x%lx\n", value); | ||
122 | if (syscall(SYS_arch_prctl, ARCH_SET_GS, value) != 0) | ||
123 | err(1, "ARCH_SET_GS"); | ||
124 | |||
125 | asm volatile ("mov %%gs, %0" : "=rm" (sel)); | ||
126 | base = read_base(GS); | ||
127 | if (base == value) { | ||
128 | printf("[OK]\tGSBASE was set as expected (selector 0x%hx)\n", | ||
129 | sel); | ||
130 | } else { | ||
131 | nerrs++; | ||
132 | printf("[FAIL]\tGSBASE was not as expected: got 0x%lx (selector 0x%hx)\n", | ||
133 | base, sel); | ||
134 | } | ||
135 | |||
136 | if (syscall(SYS_arch_prctl, ARCH_GET_GS, &base) != 0) | ||
137 | err(1, "ARCH_GET_GS"); | ||
138 | if (base == value) { | ||
139 | printf("[OK]\tARCH_GET_GS worked as expected (selector 0x%hx)\n", | ||
140 | sel); | ||
141 | } else { | ||
142 | nerrs++; | ||
143 | printf("[FAIL]\tARCH_GET_GS was not as expected: got 0x%lx (selector 0x%hx)\n", | ||
144 | base, sel); | ||
145 | } | ||
146 | } | ||
147 | |||
148 | static void mov_0_gs(unsigned long initial_base, bool schedule) | ||
149 | { | ||
150 | unsigned long base, arch_base; | ||
151 | |||
152 | printf("[RUN]\tARCH_SET_GS to 0x%lx then mov 0 to %%gs%s\n", initial_base, schedule ? " and schedule " : ""); | ||
153 | if (syscall(SYS_arch_prctl, ARCH_SET_GS, initial_base) != 0) | ||
154 | err(1, "ARCH_SET_GS"); | ||
155 | |||
156 | if (schedule) | ||
157 | usleep(10); | ||
158 | |||
159 | asm volatile ("mov %0, %%gs" : : "rm" (0)); | ||
160 | base = read_base(GS); | ||
161 | if (syscall(SYS_arch_prctl, ARCH_GET_GS, &arch_base) != 0) | ||
162 | err(1, "ARCH_GET_GS"); | ||
163 | if (base == arch_base) { | ||
164 | printf("[OK]\tGSBASE is 0x%lx\n", base); | ||
165 | } else { | ||
166 | nerrs++; | ||
167 | printf("[FAIL]\tGSBASE changed to 0x%lx but kernel reports 0x%lx\n", base, arch_base); | ||
168 | } | ||
169 | } | ||
170 | |||
171 | static volatile unsigned long remote_base; | ||
172 | static volatile bool remote_hard_zero; | ||
173 | static volatile unsigned int ftx; | ||
174 | |||
175 | /* | ||
176 | * ARCH_SET_FS/GS(0) may or may not program a selector of zero. HARD_ZERO | ||
177 | * means to force the selector to zero to improve test coverage. | ||
178 | */ | ||
179 | #define HARD_ZERO 0xa1fa5f343cb85fa4 | ||
180 | |||
181 | static void do_remote_base() | ||
182 | { | ||
183 | unsigned long to_set = remote_base; | ||
184 | bool hard_zero = false; | ||
185 | if (to_set == HARD_ZERO) { | ||
186 | to_set = 0; | ||
187 | hard_zero = true; | ||
188 | } | ||
189 | |||
190 | if (syscall(SYS_arch_prctl, ARCH_SET_GS, to_set) != 0) | ||
191 | err(1, "ARCH_SET_GS"); | ||
192 | |||
193 | if (hard_zero) | ||
194 | asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0)); | ||
195 | |||
196 | unsigned short sel; | ||
197 | asm volatile ("mov %%gs, %0" : "=rm" (sel)); | ||
198 | printf("\tother thread: ARCH_SET_GS(0x%lx)%s -- sel is 0x%hx\n", | ||
199 | to_set, hard_zero ? " and clear gs" : "", sel); | ||
200 | } | ||
201 | |||
202 | void do_unexpected_base(void) | ||
203 | { | ||
204 | /* | ||
205 | * The goal here is to try to arrange for GS == 0, GSBASE != | ||
206 | * 0, and for the the kernel the think that GSBASE == 0. | ||
207 | * | ||
208 | * To make the test as reliable as possible, this uses | ||
209 | * explicit descriptorss. (This is not the only way. This | ||
210 | * could use ARCH_SET_GS with a low, nonzero base, but the | ||
211 | * relevant side effect of ARCH_SET_GS could change.) | ||
212 | */ | ||
213 | |||
214 | /* Step 1: tell the kernel that we have GSBASE == 0. */ | ||
215 | if (syscall(SYS_arch_prctl, ARCH_SET_GS, 0) != 0) | ||
216 | err(1, "ARCH_SET_GS"); | ||
217 | |||
218 | /* Step 2: change GSBASE without telling the kernel. */ | ||
219 | struct user_desc desc = { | ||
220 | .entry_number = 0, | ||
221 | .base_addr = 0xBAADF00D, | ||
222 | .limit = 0xfffff, | ||
223 | .seg_32bit = 1, | ||
224 | .contents = 0, /* Data, grow-up */ | ||
225 | .read_exec_only = 0, | ||
226 | .limit_in_pages = 1, | ||
227 | .seg_not_present = 0, | ||
228 | .useable = 0 | ||
229 | }; | ||
230 | if (syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)) == 0) { | ||
231 | printf("\tother thread: using LDT slot 0\n"); | ||
232 | asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0x7)); | ||
233 | } else { | ||
234 | /* No modify_ldt for us (configured out, perhaps) */ | ||
235 | |||
236 | struct user_desc *low_desc = mmap( | ||
237 | NULL, sizeof(desc), | ||
238 | PROT_READ | PROT_WRITE, | ||
239 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0); | ||
240 | memcpy(low_desc, &desc, sizeof(desc)); | ||
241 | |||
242 | low_desc->entry_number = -1; | ||
243 | |||
244 | /* 32-bit set_thread_area */ | ||
245 | long ret; | ||
246 | asm volatile ("int $0x80" | ||
247 | : "=a" (ret) : "a" (243), "b" (low_desc) | ||
248 | : "flags"); | ||
249 | memcpy(&desc, low_desc, sizeof(desc)); | ||
250 | munmap(low_desc, sizeof(desc)); | ||
251 | |||
252 | if (ret != 0) { | ||
253 | printf("[NOTE]\tcould not create a segment -- test won't do anything\n"); | ||
254 | return; | ||
255 | } | ||
256 | printf("\tother thread: using GDT slot %d\n", desc.entry_number); | ||
257 | asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)((desc.entry_number << 3) | 0x3))); | ||
258 | } | ||
259 | |||
260 | /* | ||
261 | * Step 3: set the selector back to zero. On AMD chips, this will | ||
262 | * preserve GSBASE. | ||
263 | */ | ||
264 | |||
265 | asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0)); | ||
266 | } | ||
267 | |||
268 | static void *threadproc(void *ctx) | ||
269 | { | ||
270 | while (1) { | ||
271 | while (ftx == 0) | ||
272 | syscall(SYS_futex, &ftx, FUTEX_WAIT, 0, NULL, NULL, 0); | ||
273 | if (ftx == 3) | ||
274 | return NULL; | ||
275 | |||
276 | if (ftx == 1) | ||
277 | do_remote_base(); | ||
278 | else if (ftx == 2) | ||
279 | do_unexpected_base(); | ||
280 | else | ||
281 | errx(1, "helper thread got bad command"); | ||
282 | |||
283 | ftx = 0; | ||
284 | syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0); | ||
285 | } | ||
286 | } | ||
287 | |||
288 | static void set_gs_and_switch_to(unsigned long local, unsigned long remote) | ||
289 | { | ||
290 | unsigned long base; | ||
291 | |||
292 | bool hard_zero = false; | ||
293 | if (local == HARD_ZERO) { | ||
294 | hard_zero = true; | ||
295 | local = 0; | ||
296 | } | ||
297 | |||
298 | printf("[RUN]\tARCH_SET_GS(0x%lx)%s, then schedule to 0x%lx\n", | ||
299 | local, hard_zero ? " and clear gs" : "", remote); | ||
300 | if (syscall(SYS_arch_prctl, ARCH_SET_GS, local) != 0) | ||
301 | err(1, "ARCH_SET_GS"); | ||
302 | if (hard_zero) | ||
303 | asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0)); | ||
304 | |||
305 | if (read_base(GS) != local) { | ||
306 | nerrs++; | ||
307 | printf("[FAIL]\tGSBASE wasn't set as expected\n"); | ||
308 | } | ||
309 | |||
310 | remote_base = remote; | ||
311 | ftx = 1; | ||
312 | syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0); | ||
313 | while (ftx != 0) | ||
314 | syscall(SYS_futex, &ftx, FUTEX_WAIT, 1, NULL, NULL, 0); | ||
315 | |||
316 | base = read_base(GS); | ||
317 | if (base == local) { | ||
318 | printf("[OK]\tGSBASE remained 0x%lx\n", local); | ||
319 | } else { | ||
320 | nerrs++; | ||
321 | printf("[FAIL]\tGSBASE changed to 0x%lx\n", base); | ||
322 | } | ||
323 | } | ||
324 | |||
325 | static void test_unexpected_base(void) | ||
326 | { | ||
327 | unsigned long base; | ||
328 | |||
329 | printf("[RUN]\tARCH_SET_GS(0), clear gs, then manipulate GSBASE in a different thread\n"); | ||
330 | if (syscall(SYS_arch_prctl, ARCH_SET_GS, 0) != 0) | ||
331 | err(1, "ARCH_SET_GS"); | ||
332 | asm volatile ("mov %0, %%gs" : : "rm" ((unsigned short)0)); | ||
333 | |||
334 | ftx = 2; | ||
335 | syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0); | ||
336 | while (ftx != 0) | ||
337 | syscall(SYS_futex, &ftx, FUTEX_WAIT, 1, NULL, NULL, 0); | ||
338 | |||
339 | base = read_base(GS); | ||
340 | if (base == 0) { | ||
341 | printf("[OK]\tGSBASE remained 0\n"); | ||
342 | } else { | ||
343 | nerrs++; | ||
344 | printf("[FAIL]\tGSBASE changed to 0x%lx\n", base); | ||
345 | } | ||
346 | } | ||
347 | |||
348 | int main() | ||
349 | { | ||
350 | pthread_t thread; | ||
351 | |||
352 | sethandler(SIGSEGV, sigsegv, 0); | ||
353 | |||
354 | check_gs_value(0); | ||
355 | check_gs_value(1); | ||
356 | check_gs_value(0x200000000); | ||
357 | check_gs_value(0); | ||
358 | check_gs_value(0x200000000); | ||
359 | check_gs_value(1); | ||
360 | |||
361 | for (int sched = 0; sched < 2; sched++) { | ||
362 | mov_0_gs(0, !!sched); | ||
363 | mov_0_gs(1, !!sched); | ||
364 | mov_0_gs(0x200000000, !!sched); | ||
365 | } | ||
366 | |||
367 | /* Set up for multithreading. */ | ||
368 | |||
369 | cpu_set_t cpuset; | ||
370 | CPU_ZERO(&cpuset); | ||
371 | CPU_SET(0, &cpuset); | ||
372 | if (sched_setaffinity(0, sizeof(cpuset), &cpuset) != 0) | ||
373 | err(1, "sched_setaffinity to CPU 0"); /* should never fail */ | ||
374 | |||
375 | if (pthread_create(&thread, 0, threadproc, 0) != 0) | ||
376 | err(1, "pthread_create"); | ||
377 | |||
378 | static unsigned long bases_with_hard_zero[] = { | ||
379 | 0, HARD_ZERO, 1, 0x200000000, | ||
380 | }; | ||
381 | |||
382 | for (int local = 0; local < 4; local++) { | ||
383 | for (int remote = 0; remote < 4; remote++) { | ||
384 | set_gs_and_switch_to(bases_with_hard_zero[local], | ||
385 | bases_with_hard_zero[remote]); | ||
386 | } | ||
387 | } | ||
388 | |||
389 | test_unexpected_base(); | ||
390 | |||
391 | ftx = 3; /* Kill the thread. */ | ||
392 | syscall(SYS_futex, &ftx, FUTEX_WAKE, 0, NULL, NULL, 0); | ||
393 | |||
394 | if (pthread_join(thread, NULL) != 0) | ||
395 | err(1, "pthread_join"); | ||
396 | |||
397 | return nerrs == 0 ? 0 : 1; | ||
398 | } | ||
diff --git a/tools/testing/selftests/x86/ldt_gdt.c b/tools/testing/selftests/x86/ldt_gdt.c index 31a3035cd4eb..4af47079cf04 100644 --- a/tools/testing/selftests/x86/ldt_gdt.c +++ b/tools/testing/selftests/x86/ldt_gdt.c | |||
@@ -21,6 +21,9 @@ | |||
21 | #include <pthread.h> | 21 | #include <pthread.h> |
22 | #include <sched.h> | 22 | #include <sched.h> |
23 | #include <linux/futex.h> | 23 | #include <linux/futex.h> |
24 | #include <sys/mman.h> | ||
25 | #include <asm/prctl.h> | ||
26 | #include <sys/prctl.h> | ||
24 | 27 | ||
25 | #define AR_ACCESSED (1<<8) | 28 | #define AR_ACCESSED (1<<8) |
26 | 29 | ||
@@ -44,6 +47,12 @@ | |||
44 | 47 | ||
45 | static int nerrs; | 48 | static int nerrs; |
46 | 49 | ||
50 | /* Points to an array of 1024 ints, each holding its own index. */ | ||
51 | static const unsigned int *counter_page; | ||
52 | static struct user_desc *low_user_desc; | ||
53 | static struct user_desc *low_user_desc_clear; /* Use to delete GDT entry */ | ||
54 | static int gdt_entry_num; | ||
55 | |||
47 | static void check_invalid_segment(uint16_t index, int ldt) | 56 | static void check_invalid_segment(uint16_t index, int ldt) |
48 | { | 57 | { |
49 | uint32_t has_limit = 0, has_ar = 0, limit, ar; | 58 | uint32_t has_limit = 0, has_ar = 0, limit, ar; |
@@ -561,16 +570,257 @@ static void do_exec_test(void) | |||
561 | } | 570 | } |
562 | } | 571 | } |
563 | 572 | ||
573 | static void setup_counter_page(void) | ||
574 | { | ||
575 | unsigned int *page = mmap(NULL, 4096, PROT_READ | PROT_WRITE, | ||
576 | MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT, -1, 0); | ||
577 | if (page == MAP_FAILED) | ||
578 | err(1, "mmap"); | ||
579 | |||
580 | for (int i = 0; i < 1024; i++) | ||
581 | page[i] = i; | ||
582 | counter_page = page; | ||
583 | } | ||
584 | |||
585 | static int invoke_set_thread_area(void) | ||
586 | { | ||
587 | int ret; | ||
588 | asm volatile ("int $0x80" | ||
589 | : "=a" (ret), "+m" (low_user_desc) : | ||
590 | "a" (243), "b" (low_user_desc) | ||
591 | : "flags"); | ||
592 | return ret; | ||
593 | } | ||
594 | |||
595 | static void setup_low_user_desc(void) | ||
596 | { | ||
597 | low_user_desc = mmap(NULL, 2 * sizeof(struct user_desc), | ||
598 | PROT_READ | PROT_WRITE, | ||
599 | MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT, -1, 0); | ||
600 | if (low_user_desc == MAP_FAILED) | ||
601 | err(1, "mmap"); | ||
602 | |||
603 | low_user_desc->entry_number = -1; | ||
604 | low_user_desc->base_addr = (unsigned long)&counter_page[1]; | ||
605 | low_user_desc->limit = 0xfffff; | ||
606 | low_user_desc->seg_32bit = 1; | ||
607 | low_user_desc->contents = 0; /* Data, grow-up*/ | ||
608 | low_user_desc->read_exec_only = 0; | ||
609 | low_user_desc->limit_in_pages = 1; | ||
610 | low_user_desc->seg_not_present = 0; | ||
611 | low_user_desc->useable = 0; | ||
612 | |||
613 | if (invoke_set_thread_area() == 0) { | ||
614 | gdt_entry_num = low_user_desc->entry_number; | ||
615 | printf("[NOTE]\tset_thread_area is available; will use GDT index %d\n", gdt_entry_num); | ||
616 | } else { | ||
617 | printf("[NOTE]\tset_thread_area is unavailable\n"); | ||
618 | } | ||
619 | |||
620 | low_user_desc_clear = low_user_desc + 1; | ||
621 | low_user_desc_clear->entry_number = gdt_entry_num; | ||
622 | low_user_desc_clear->read_exec_only = 1; | ||
623 | low_user_desc_clear->seg_not_present = 1; | ||
624 | } | ||
625 | |||
626 | static void test_gdt_invalidation(void) | ||
627 | { | ||
628 | if (!gdt_entry_num) | ||
629 | return; /* 64-bit only system -- we can't use set_thread_area */ | ||
630 | |||
631 | unsigned short prev_sel; | ||
632 | unsigned short sel; | ||
633 | unsigned int eax; | ||
634 | const char *result; | ||
635 | #ifdef __x86_64__ | ||
636 | unsigned long saved_base; | ||
637 | unsigned long new_base; | ||
638 | #endif | ||
639 | |||
640 | /* Test DS */ | ||
641 | invoke_set_thread_area(); | ||
642 | eax = 243; | ||
643 | sel = (gdt_entry_num << 3) | 3; | ||
644 | asm volatile ("movw %%ds, %[prev_sel]\n\t" | ||
645 | "movw %[sel], %%ds\n\t" | ||
646 | #ifdef __i386__ | ||
647 | "pushl %%ebx\n\t" | ||
648 | #endif | ||
649 | "movl %[arg1], %%ebx\n\t" | ||
650 | "int $0x80\n\t" /* Should invalidate ds */ | ||
651 | #ifdef __i386__ | ||
652 | "popl %%ebx\n\t" | ||
653 | #endif | ||
654 | "movw %%ds, %[sel]\n\t" | ||
655 | "movw %[prev_sel], %%ds" | ||
656 | : [prev_sel] "=&r" (prev_sel), [sel] "+r" (sel), | ||
657 | "+a" (eax) | ||
658 | : "m" (low_user_desc_clear), | ||
659 | [arg1] "r" ((unsigned int)(unsigned long)low_user_desc_clear) | ||
660 | : "flags"); | ||
661 | |||
662 | if (sel != 0) { | ||
663 | result = "FAIL"; | ||
664 | nerrs++; | ||
665 | } else { | ||
666 | result = "OK"; | ||
667 | } | ||
668 | printf("[%s]\tInvalidate DS with set_thread_area: new DS = 0x%hx\n", | ||
669 | result, sel); | ||
670 | |||
671 | /* Test ES */ | ||
672 | invoke_set_thread_area(); | ||
673 | eax = 243; | ||
674 | sel = (gdt_entry_num << 3) | 3; | ||
675 | asm volatile ("movw %%es, %[prev_sel]\n\t" | ||
676 | "movw %[sel], %%es\n\t" | ||
677 | #ifdef __i386__ | ||
678 | "pushl %%ebx\n\t" | ||
679 | #endif | ||
680 | "movl %[arg1], %%ebx\n\t" | ||
681 | "int $0x80\n\t" /* Should invalidate es */ | ||
682 | #ifdef __i386__ | ||
683 | "popl %%ebx\n\t" | ||
684 | #endif | ||
685 | "movw %%es, %[sel]\n\t" | ||
686 | "movw %[prev_sel], %%es" | ||
687 | : [prev_sel] "=&r" (prev_sel), [sel] "+r" (sel), | ||
688 | "+a" (eax) | ||
689 | : "m" (low_user_desc_clear), | ||
690 | [arg1] "r" ((unsigned int)(unsigned long)low_user_desc_clear) | ||
691 | : "flags"); | ||
692 | |||
693 | if (sel != 0) { | ||
694 | result = "FAIL"; | ||
695 | nerrs++; | ||
696 | } else { | ||
697 | result = "OK"; | ||
698 | } | ||
699 | printf("[%s]\tInvalidate ES with set_thread_area: new ES = 0x%hx\n", | ||
700 | result, sel); | ||
701 | |||
702 | /* Test FS */ | ||
703 | invoke_set_thread_area(); | ||
704 | eax = 243; | ||
705 | sel = (gdt_entry_num << 3) | 3; | ||
706 | #ifdef __x86_64__ | ||
707 | syscall(SYS_arch_prctl, ARCH_GET_FS, &saved_base); | ||
708 | #endif | ||
709 | asm volatile ("movw %%fs, %[prev_sel]\n\t" | ||
710 | "movw %[sel], %%fs\n\t" | ||
711 | #ifdef __i386__ | ||
712 | "pushl %%ebx\n\t" | ||
713 | #endif | ||
714 | "movl %[arg1], %%ebx\n\t" | ||
715 | "int $0x80\n\t" /* Should invalidate fs */ | ||
716 | #ifdef __i386__ | ||
717 | "popl %%ebx\n\t" | ||
718 | #endif | ||
719 | "movw %%fs, %[sel]\n\t" | ||
720 | : [prev_sel] "=&r" (prev_sel), [sel] "+r" (sel), | ||
721 | "+a" (eax) | ||
722 | : "m" (low_user_desc_clear), | ||
723 | [arg1] "r" ((unsigned int)(unsigned long)low_user_desc_clear) | ||
724 | : "flags"); | ||
725 | |||
726 | #ifdef __x86_64__ | ||
727 | syscall(SYS_arch_prctl, ARCH_GET_FS, &new_base); | ||
728 | #endif | ||
729 | |||
730 | /* Restore FS/BASE for glibc */ | ||
731 | asm volatile ("movw %[prev_sel], %%fs" : : [prev_sel] "rm" (prev_sel)); | ||
732 | #ifdef __x86_64__ | ||
733 | if (saved_base) | ||
734 | syscall(SYS_arch_prctl, ARCH_SET_FS, saved_base); | ||
735 | #endif | ||
736 | |||
737 | if (sel != 0) { | ||
738 | result = "FAIL"; | ||
739 | nerrs++; | ||
740 | } else { | ||
741 | result = "OK"; | ||
742 | } | ||
743 | printf("[%s]\tInvalidate FS with set_thread_area: new FS = 0x%hx\n", | ||
744 | result, sel); | ||
745 | |||
746 | #ifdef __x86_64__ | ||
747 | if (sel == 0 && new_base != 0) { | ||
748 | nerrs++; | ||
749 | printf("[FAIL]\tNew FSBASE was 0x%lx\n", new_base); | ||
750 | } else { | ||
751 | printf("[OK]\tNew FSBASE was zero\n"); | ||
752 | } | ||
753 | #endif | ||
754 | |||
755 | /* Test GS */ | ||
756 | invoke_set_thread_area(); | ||
757 | eax = 243; | ||
758 | sel = (gdt_entry_num << 3) | 3; | ||
759 | #ifdef __x86_64__ | ||
760 | syscall(SYS_arch_prctl, ARCH_GET_GS, &saved_base); | ||
761 | #endif | ||
762 | asm volatile ("movw %%gs, %[prev_sel]\n\t" | ||
763 | "movw %[sel], %%gs\n\t" | ||
764 | #ifdef __i386__ | ||
765 | "pushl %%ebx\n\t" | ||
766 | #endif | ||
767 | "movl %[arg1], %%ebx\n\t" | ||
768 | "int $0x80\n\t" /* Should invalidate gs */ | ||
769 | #ifdef __i386__ | ||
770 | "popl %%ebx\n\t" | ||
771 | #endif | ||
772 | "movw %%gs, %[sel]\n\t" | ||
773 | : [prev_sel] "=&r" (prev_sel), [sel] "+r" (sel), | ||
774 | "+a" (eax) | ||
775 | : "m" (low_user_desc_clear), | ||
776 | [arg1] "r" ((unsigned int)(unsigned long)low_user_desc_clear) | ||
777 | : "flags"); | ||
778 | |||
779 | #ifdef __x86_64__ | ||
780 | syscall(SYS_arch_prctl, ARCH_GET_GS, &new_base); | ||
781 | #endif | ||
782 | |||
783 | /* Restore GS/BASE for glibc */ | ||
784 | asm volatile ("movw %[prev_sel], %%gs" : : [prev_sel] "rm" (prev_sel)); | ||
785 | #ifdef __x86_64__ | ||
786 | if (saved_base) | ||
787 | syscall(SYS_arch_prctl, ARCH_SET_GS, saved_base); | ||
788 | #endif | ||
789 | |||
790 | if (sel != 0) { | ||
791 | result = "FAIL"; | ||
792 | nerrs++; | ||
793 | } else { | ||
794 | result = "OK"; | ||
795 | } | ||
796 | printf("[%s]\tInvalidate GS with set_thread_area: new GS = 0x%hx\n", | ||
797 | result, sel); | ||
798 | |||
799 | #ifdef __x86_64__ | ||
800 | if (sel == 0 && new_base != 0) { | ||
801 | nerrs++; | ||
802 | printf("[FAIL]\tNew GSBASE was 0x%lx\n", new_base); | ||
803 | } else { | ||
804 | printf("[OK]\tNew GSBASE was zero\n"); | ||
805 | } | ||
806 | #endif | ||
807 | } | ||
808 | |||
564 | int main(int argc, char **argv) | 809 | int main(int argc, char **argv) |
565 | { | 810 | { |
566 | if (argc == 1 && !strcmp(argv[0], "ldt_gdt_test_exec")) | 811 | if (argc == 1 && !strcmp(argv[0], "ldt_gdt_test_exec")) |
567 | return finish_exec_test(); | 812 | return finish_exec_test(); |
568 | 813 | ||
814 | setup_counter_page(); | ||
815 | setup_low_user_desc(); | ||
816 | |||
569 | do_simple_tests(); | 817 | do_simple_tests(); |
570 | 818 | ||
571 | do_multicpu_tests(); | 819 | do_multicpu_tests(); |
572 | 820 | ||
573 | do_exec_test(); | 821 | do_exec_test(); |
574 | 822 | ||
823 | test_gdt_invalidation(); | ||
824 | |||
575 | return nerrs ? 1 : 0; | 825 | return nerrs ? 1 : 0; |
576 | } | 826 | } |