From 9fd0c40451468754754271ba0cbb63b6927911df Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Thu, 3 May 2018 10:09:10 +0100 Subject: cpupower: fix spelling mistake: "logilename" -> "logfilename" Trivial fix to spelling mistake in dprintf message Signed-off-by: Colin Ian King Signed-off-by: Shuah Khan (Samsung OSG) --- tools/power/cpupower/bench/parse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/power/cpupower/bench/parse.c b/tools/power/cpupower/bench/parse.c index 9b65f052081f..9ba8a44ad2a7 100644 --- a/tools/power/cpupower/bench/parse.c +++ b/tools/power/cpupower/bench/parse.c @@ -104,7 +104,7 @@ FILE *prepare_output(const char *dirname) dirname, time(NULL)); } - dprintf("logilename: %s\n", filename); + dprintf("logfilename: %s\n", filename); output = fopen(filename, "w+"); if (output == NULL) { -- cgit From 71b52d2c746b2915d615e29f5873e1ee5f3c5f52 Mon Sep 17 00:00:00 2001 From: Martin Kelly Date: Thu, 17 May 2018 17:14:45 -0700 Subject: tools: iio: iio_generic_buffer: fix types to match Several types are mismatched and causing implicit conversions. Fix them up so the types match. Signed-off-by: Martin Kelly Signed-off-by: Jonathan Cameron --- tools/iio/iio_generic_buffer.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/iio/iio_generic_buffer.c b/tools/iio/iio_generic_buffer.c index f0c6f54a8b2f..aa765c11992b 100644 --- a/tools/iio/iio_generic_buffer.c +++ b/tools/iio/iio_generic_buffer.c @@ -334,7 +334,10 @@ int main(int argc, char **argv) unsigned long timedelay = 1000000; unsigned long buf_len = 128; - int ret, c, i, j, toread; + ssize_t i; + unsigned long j; + unsigned long toread; + int ret, c; int fp = -1; int num_channels = 0; -- cgit From 55dda0abcf9d36bf5c3e21c8423b7c00a1125e27 Mon Sep 17 00:00:00 2001 From: Martin Kelly Date: Thu, 17 May 2018 17:14:46 -0700 Subject: tools: iio: iio_generic_buffer: allow continuous looping Sometimes it's useful to stream samples forever, such as when stress-testing a driver overnight to check for memory leaks or other issues. When the program receives a signal, it will gracefully cleanup, so it is still safe to terminate at any time. Add support for specifying a negative -c option, meaning that we should loop forever. To do so, we need to use a long long (instead of just long) for num_loops so that current code specifying num_loops greater than UNSIGNED_LONG_MAX doesn't break. Signed-off-by: Martin Kelly Signed-off-by: Jonathan Cameron --- tools/iio/iio_generic_buffer.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'tools') diff --git a/tools/iio/iio_generic_buffer.c b/tools/iio/iio_generic_buffer.c index aa765c11992b..3040830d7797 100644 --- a/tools/iio/iio_generic_buffer.c +++ b/tools/iio/iio_generic_buffer.c @@ -248,7 +248,7 @@ void print_usage(void) "Capture, convert and output data from IIO device buffer\n" " -a Auto-activate all available channels\n" " -A Force-activate ALL channels\n" - " -c Do n conversions\n" + " -c Do n conversions, or loop forever if n < 0\n" " -e Disable wait for event (new data)\n" " -g Use trigger-less mode\n" " -l Set buffer length to n samples\n" @@ -330,12 +330,12 @@ static const struct option longopts[] = { int main(int argc, char **argv) { - unsigned long num_loops = 2; + unsigned long long num_loops = 2; unsigned long timedelay = 1000000; unsigned long buf_len = 128; ssize_t i; - unsigned long j; + unsigned long long j; unsigned long toread; int ret, c; int fp = -1; @@ -369,7 +369,7 @@ int main(int argc, char **argv) break; case 'c': errno = 0; - num_loops = strtoul(optarg, &dummy, 10); + num_loops = strtoll(optarg, &dummy, 10); if (errno) { ret = -errno; goto error; @@ -637,7 +637,7 @@ int main(int argc, char **argv) goto error; } - for (j = 0; j < num_loops; j++) { + for (j = 0; j < num_loops || num_loops < 0; j++) { if (!noevents) { struct pollfd pfd = { .fd = fp, -- cgit From 5d8beee20d89e34ff1dcb0da84adf7607858c59d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Tue, 1 May 2018 06:49:45 -0700 Subject: x86, nfit_test: Add unit test for memcpy_mcsafe() Given the fact that the ACPI "EINJ" (error injection) facility is not universally available, implement software infrastructure to validate the memcpy_mcsafe() exception handling implementation. For each potential read exception point in memcpy_mcsafe(), inject a emulated exception point at the address identified by 'mcsafe_inject' variable. With this infrastructure implement a test to validate that the 'bytes remaining' calculation is correct for a range of various source buffer alignments. This code is compiled out by default. The CONFIG_MCSAFE_DEBUG configuration symbol needs to be manually enabled by editing Kconfig.debug. I.e. this functionality can not be accidentally enabled by a user / distro, it's only for development. Cc: Cc: Ingo Molnar Cc: Borislav Petkov Cc: Tony Luck Cc: Al Viro Cc: Thomas Gleixner Cc: Andy Lutomirski Cc: Peter Zijlstra Cc: Andrew Morton Cc: Linus Torvalds Reported-by: Tony Luck Signed-off-by: Dan Williams --- arch/x86/Kconfig.debug | 3 ++ arch/x86/include/asm/mcsafe_test.h | 75 ++++++++++++++++++++++++++ arch/x86/lib/memcpy_64.S | 10 ++++ tools/testing/nvdimm/test/nfit.c | 104 +++++++++++++++++++++++++++++++++++++ 4 files changed, 192 insertions(+) create mode 100644 arch/x86/include/asm/mcsafe_test.h (limited to 'tools') diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug index 192e4d2f9efc..c6dd1d980081 100644 --- a/arch/x86/Kconfig.debug +++ b/arch/x86/Kconfig.debug @@ -72,6 +72,9 @@ config EARLY_PRINTK_USB_XDBC You should normally say N here, unless you want to debug early crashes or need a very simple printk logging facility. +config MCSAFE_TEST + def_bool n + config X86_PTDUMP_CORE def_bool n diff --git a/arch/x86/include/asm/mcsafe_test.h b/arch/x86/include/asm/mcsafe_test.h new file mode 100644 index 000000000000..eb59804b6201 --- /dev/null +++ b/arch/x86/include/asm/mcsafe_test.h @@ -0,0 +1,75 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _MCSAFE_TEST_H_ +#define _MCSAFE_TEST_H_ + +#ifndef __ASSEMBLY__ +#ifdef CONFIG_MCSAFE_TEST +extern unsigned long mcsafe_test_src; +extern unsigned long mcsafe_test_dst; + +static inline void mcsafe_inject_src(void *addr) +{ + if (addr) + mcsafe_test_src = (unsigned long) addr; + else + mcsafe_test_src = ~0UL; +} + +static inline void mcsafe_inject_dst(void *addr) +{ + if (addr) + mcsafe_test_dst = (unsigned long) addr; + else + mcsafe_test_dst = ~0UL; +} +#else /* CONFIG_MCSAFE_TEST */ +static inline void mcsafe_inject_src(void *addr) +{ +} + +static inline void mcsafe_inject_dst(void *addr) +{ +} +#endif /* CONFIG_MCSAFE_TEST */ + +#else /* __ASSEMBLY__ */ +#include + +#ifdef CONFIG_MCSAFE_TEST +.macro MCSAFE_TEST_CTL + .pushsection .data + .align 8 + .globl mcsafe_test_src + mcsafe_test_src: + .quad 0 + EXPORT_SYMBOL_GPL(mcsafe_test_src) + .globl mcsafe_test_dst + mcsafe_test_dst: + .quad 0 + EXPORT_SYMBOL_GPL(mcsafe_test_dst) + .popsection +.endm + +.macro MCSAFE_TEST_SRC reg count target + leaq \count(\reg), %r9 + cmp mcsafe_test_src, %r9 + ja \target +.endm + +.macro MCSAFE_TEST_DST reg count target + leaq \count(\reg), %r9 + cmp mcsafe_test_dst, %r9 + ja \target +.endm +#else +.macro MCSAFE_TEST_CTL +.endm + +.macro MCSAFE_TEST_SRC reg count target +.endm + +.macro MCSAFE_TEST_DST reg count target +.endm +#endif /* CONFIG_MCSAFE_TEST */ +#endif /* __ASSEMBLY__ */ +#endif /* _MCSAFE_TEST_H_ */ diff --git a/arch/x86/lib/memcpy_64.S b/arch/x86/lib/memcpy_64.S index c3b527a9f95d..298ef1479240 100644 --- a/arch/x86/lib/memcpy_64.S +++ b/arch/x86/lib/memcpy_64.S @@ -3,6 +3,7 @@ #include #include #include +#include #include #include @@ -183,6 +184,9 @@ ENTRY(memcpy_orig) ENDPROC(memcpy_orig) #ifndef CONFIG_UML + +MCSAFE_TEST_CTL + /* * __memcpy_mcsafe - memory copy with machine check exception handling * Note that we only catch machine checks when reading the source addresses. @@ -206,6 +210,8 @@ ENTRY(__memcpy_mcsafe) subl %ecx, %edx .L_read_leading_bytes: movb (%rsi), %al + MCSAFE_TEST_SRC %rsi 1 .E_leading_bytes + MCSAFE_TEST_DST %rdi 1 .E_leading_bytes .L_write_leading_bytes: movb %al, (%rdi) incq %rsi @@ -221,6 +227,8 @@ ENTRY(__memcpy_mcsafe) .L_read_words: movq (%rsi), %r8 + MCSAFE_TEST_SRC %rsi 8 .E_read_words + MCSAFE_TEST_DST %rdi 8 .E_write_words .L_write_words: movq %r8, (%rdi) addq $8, %rsi @@ -237,6 +245,8 @@ ENTRY(__memcpy_mcsafe) movl %edx, %ecx .L_read_trailing_bytes: movb (%rsi), %al + MCSAFE_TEST_SRC %rsi 1 .E_trailing_bytes + MCSAFE_TEST_DST %rdi 1 .E_trailing_bytes .L_write_trailing_bytes: movb %al, (%rdi) incq %rsi diff --git a/tools/testing/nvdimm/test/nfit.c b/tools/testing/nvdimm/test/nfit.c index 4ea385be528f..a8fb63edcf89 100644 --- a/tools/testing/nvdimm/test/nfit.c +++ b/tools/testing/nvdimm/test/nfit.c @@ -29,6 +29,8 @@ #include "nfit_test.h" #include "../watermark.h" +#include + /* * Generate an NFIT table to describe the following topology: * @@ -2681,6 +2683,107 @@ static struct platform_driver nfit_test_driver = { .id_table = nfit_test_id, }; +static char mcsafe_buf[PAGE_SIZE] __attribute__((__aligned__(PAGE_SIZE))); + +enum INJECT { + INJECT_NONE, + INJECT_SRC, + INJECT_DST, +}; + +static void mcsafe_test_init(char *dst, char *src, size_t size) +{ + size_t i; + + memset(dst, 0xff, size); + for (i = 0; i < size; i++) + src[i] = (char) i; +} + +static bool mcsafe_test_validate(unsigned char *dst, unsigned char *src, + size_t size, unsigned long rem) +{ + size_t i; + + for (i = 0; i < size - rem; i++) + if (dst[i] != (unsigned char) i) { + pr_info_once("%s:%d: offset: %zd got: %#x expect: %#x\n", + __func__, __LINE__, i, dst[i], + (unsigned char) i); + return false; + } + for (i = size - rem; i < size; i++) + if (dst[i] != 0xffU) { + pr_info_once("%s:%d: offset: %zd got: %#x expect: 0xff\n", + __func__, __LINE__, i, dst[i]); + return false; + } + return true; +} + +void mcsafe_test(void) +{ + char *inject_desc[] = { "none", "source", "destination" }; + enum INJECT inj; + + if (IS_ENABLED(CONFIG_MCSAFE_TEST)) { + pr_info("%s: run...\n", __func__); + } else { + pr_info("%s: disabled, skip.\n", __func__); + return; + } + + for (inj = INJECT_NONE; inj <= INJECT_DST; inj++) { + int i; + + pr_info("%s: inject: %s\n", __func__, inject_desc[inj]); + for (i = 0; i < 512; i++) { + unsigned long expect, rem; + void *src, *dst; + bool valid; + + switch (inj) { + case INJECT_NONE: + mcsafe_inject_src(NULL); + mcsafe_inject_dst(NULL); + dst = &mcsafe_buf[2048]; + src = &mcsafe_buf[1024 - i]; + expect = 0; + break; + case INJECT_SRC: + mcsafe_inject_src(&mcsafe_buf[1024]); + mcsafe_inject_dst(NULL); + dst = &mcsafe_buf[2048]; + src = &mcsafe_buf[1024 - i]; + expect = 512 - i; + break; + case INJECT_DST: + mcsafe_inject_src(NULL); + mcsafe_inject_dst(&mcsafe_buf[2048]); + dst = &mcsafe_buf[2048 - i]; + src = &mcsafe_buf[1024]; + expect = 512 - i; + break; + } + + mcsafe_test_init(dst, src, 512); + rem = __memcpy_mcsafe(dst, src, 512); + valid = mcsafe_test_validate(dst, src, 512, expect); + if (rem == expect && valid) + continue; + pr_info("%s: copy(%#lx, %#lx, %d) off: %d rem: %ld %s expect: %ld\n", + __func__, + ((unsigned long) dst) & ~PAGE_MASK, + ((unsigned long ) src) & ~PAGE_MASK, + 512, i, rem, valid ? "valid" : "bad", + expect); + } + } + + mcsafe_inject_src(NULL); + mcsafe_inject_dst(NULL); +} + static __init int nfit_test_init(void) { int rc, i; @@ -2689,6 +2792,7 @@ static __init int nfit_test_init(void) libnvdimm_test(); acpi_nfit_test(); device_dax_test(); + mcsafe_test(); nfit_test_setup(nfit_test_lookup, nfit_test_evaluate_dsm); -- cgit From f9652d5cae04eb5e85303c087f5842d320499c65 Mon Sep 17 00:00:00 2001 From: Abhishek Goel Date: Mon, 28 May 2018 06:03:03 -0500 Subject: cpupower : Fix header name to read idle state name The names of the idle states in the output of cpupower monitor command are truncated to 4 characters. On POWER9, this creates ambiguity as the states are named "stop0", "stop1", etc. root:~# cpupower monitor |Idle_Stats PKG |CORE|CPU | snoo | stop | stop | stop | stop | stop | stop 0| 0| 0| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 1.90 0| 0| 1| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00 0| 0| 2| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00 0| 0| 3| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00 This patch modifies the output to print the state name that results in a legible output. The names will be printed with atmost 1 padding in left. root:~# cpupower monitor | Idle_Stats PKG|CORE| CPU|snooze|stop0L| stop0|stop1L| stop1|stop2L| stop2 0| 0| 0| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.72 0| 0| 1| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00 0| 0| 2| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00 0| 0| 3| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00| 0.00 This patch does not affect the output for intel. Output for intel before applying the patch: root:~# cpupower monitor |Idle_Stats CPU | POLL | C1-S | C1E- | C3-S | C6-S | C7s- | C8-S | C9-S | C10- 0| 0.00| 0.14| 0.39| 0.35| 7.41| 0.00| 17.67| 1.01| 70.03 2| 0.00| 0.19| 0.47| 0.10| 6.50| 0.00| 29.66| 2.17| 58.07 1| 0.00| 0.11| 0.50| 1.50| 9.11| 0.18| 18.19| 0.40| 66.63 3| 0.00| 0.67| 0.42| 0.03| 5.84| 0.00| 12.58| 0.77| 77.14 Output for intel after applying the patch: root:~# cpupower monitor | Idle_Stats CPU| POLL | C1-S | C1E- | C3-S | C6-S | C7s- | C8-S | C9-S | C10- 0| 0.03| 0.33| 1.01| 0.27| 3.03| 0.00| 19.18| 0.00| 71.24 2| 0.00| 1.58| 0.58| 0.42| 8.55| 0.09| 21.11| 0.99| 63.32 1| 0.00| 1.26| 0.88| 0.43| 9.00| 0.02| 7.78| 4.65| 71.91 3| 0.00| 0.30| 0.42| 0.06| 13.62| 0.21| 30.29| 0.00| 52.45 Signed-off-by: Abhishek Goel Signed-off-by: Shuah Khan (Samsung OSG) --- .../cpupower/utils/idle_monitor/cpuidle_sysfs.c | 15 ++++++++++ .../cpupower/utils/idle_monitor/cpupower-monitor.c | 35 ++++++++++++---------- .../cpupower/utils/idle_monitor/cpupower-monitor.h | 9 ++++++ 3 files changed, 44 insertions(+), 15 deletions(-) (limited to 'tools') diff --git a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c index 5b3205f16217..5b8c4956ff9a 100644 --- a/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c +++ b/tools/power/cpupower/utils/idle_monitor/cpuidle_sysfs.c @@ -126,6 +126,20 @@ void fix_up_intel_idle_driver_name(char *tmp, int num) } } +#ifdef __powerpc__ +void map_power_idle_state_name(char *tmp) +{ + if (!strncmp(tmp, "stop0_lite", CSTATE_NAME_LEN)) + strcpy(tmp, "stop0L"); + else if (!strncmp(tmp, "stop1_lite", CSTATE_NAME_LEN)) + strcpy(tmp, "stop1L"); + else if (!strncmp(tmp, "stop2_lite", CSTATE_NAME_LEN)) + strcpy(tmp, "stop2L"); +} +#else +void map_power_idle_state_name(char *tmp) { } +#endif + static struct cpuidle_monitor *cpuidle_register(void) { int num; @@ -145,6 +159,7 @@ static struct cpuidle_monitor *cpuidle_register(void) if (tmp == NULL) continue; + map_power_idle_state_name(tmp); fix_up_intel_idle_driver_name(tmp, num); strncpy(cpuidle_cstates[num].name, tmp, CSTATE_NAME_LEN - 1); free(tmp); diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c index 05f953f0f0a0..051da0a7c454 100644 --- a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c +++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.c @@ -70,36 +70,43 @@ void print_n_spaces(int n) printf(" "); } -/* size of s must be at least n + 1 */ +/*s is filled with left and right spaces + *to make its length atleast n+1 + */ int fill_string_with_spaces(char *s, int n) { + char *temp; int len = strlen(s); - if (len > n) + + if (len >= n) return -1; + + temp = malloc(sizeof(char) * (n+1)); for (; len < n; len++) s[len] = ' '; s[len] = '\0'; + snprintf(temp, n+1, " %s", s); + strcpy(s, temp); + free(temp); return 0; } +#define MAX_COL_WIDTH 6 void print_header(int topology_depth) { int unsigned mon; int state, need_len; cstate_t s; char buf[128] = ""; - int percent_width = 4; fill_string_with_spaces(buf, topology_depth * 5 - 1); printf("%s|", buf); for (mon = 0; mon < avail_monitors; mon++) { - need_len = monitors[mon]->hw_states_num * (percent_width + 3) + need_len = monitors[mon]->hw_states_num * (MAX_COL_WIDTH + 1) - 1; - if (mon != 0) { - printf("|| "); - need_len--; - } + if (mon != 0) + printf("||"); sprintf(buf, "%s", monitors[mon]->name); fill_string_with_spaces(buf, need_len); printf("%s", buf); @@ -107,23 +114,21 @@ void print_header(int topology_depth) printf("\n"); if (topology_depth > 2) - printf("PKG |"); + printf(" PKG|"); if (topology_depth > 1) printf("CORE|"); if (topology_depth > 0) - printf("CPU |"); + printf(" CPU|"); for (mon = 0; mon < avail_monitors; mon++) { if (mon != 0) - printf("|| "); - else - printf(" "); + printf("||"); for (state = 0; state < monitors[mon]->hw_states_num; state++) { if (state != 0) - printf(" | "); + printf("|"); s = monitors[mon]->hw_states[state]; sprintf(buf, "%s", s.name); - fill_string_with_spaces(buf, percent_width); + fill_string_with_spaces(buf, MAX_COL_WIDTH); printf("%s", buf); } printf(" "); diff --git a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h index 9e43f3371fbc..2ae50b499e0a 100644 --- a/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h +++ b/tools/power/cpupower/utils/idle_monitor/cpupower-monitor.h @@ -15,7 +15,16 @@ #define MONITORS_MAX 20 #define MONITOR_NAME_LEN 20 + +/* CSTATE_NAME_LEN is limited by header field width defined + * in cpupower-monitor.c. Header field width is defined to be + * sum of percent width and two spaces for padding. + */ +#ifdef __powerpc__ +#define CSTATE_NAME_LEN 7 +#else #define CSTATE_NAME_LEN 5 +#endif #define CSTATE_DESC_LEN 60 int cpu_count; -- cgit From 4f5aeecd0d1233cbd0ccd60f4d6701404884471a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 24 May 2018 10:49:25 -0300 Subject: perf tools: Remove dead quote.[ch] code In c68677014bac ("perf tools: Remove support for command aliases") we removed the only remaining use of a function provided by these files, so ditch it. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-mgnzqbi46gucs48d7bzfwr55@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/perf.c | 1 - tools/perf/util/Build | 1 - tools/perf/util/quote.c | 62 ------------------------------------------------- tools/perf/util/quote.h | 31 ------------------------- 4 files changed, 95 deletions(-) delete mode 100644 tools/perf/util/quote.c delete mode 100644 tools/perf/util/quote.h (limited to 'tools') diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 51c81509a315..a11cb006f968 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c @@ -12,7 +12,6 @@ #include "util/env.h" #include #include "util/config.h" -#include "util/quote.h" #include #include "util/parse-events.h" #include diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 5d4c45b76895..b604ef334dc9 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -24,7 +24,6 @@ libperf-y += libstring.o libperf-y += bitmap.o libperf-y += hweight.o libperf-y += smt.o -libperf-y += quote.o libperf-y += strbuf.o libperf-y += string.o libperf-y += strlist.o diff --git a/tools/perf/util/quote.c b/tools/perf/util/quote.c deleted file mode 100644 index 22eaa201aa27..000000000000 --- a/tools/perf/util/quote.c +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#include -#include -#include "strbuf.h" -#include "quote.h" -#include "util.h" - -/* Help to copy the thing properly quoted for the shell safety. - * any single quote is replaced with '\'', any exclamation point - * is replaced with '\!', and the whole thing is enclosed in a - * - * E.g. - * original sq_quote result - * name ==> name ==> 'name' - * a b ==> a b ==> 'a b' - * a'b ==> a'\''b ==> 'a'\''b' - * a!b ==> a'\!'b ==> 'a'\!'b' - */ -static inline int need_bs_quote(char c) -{ - return (c == '\'' || c == '!'); -} - -static int sq_quote_buf(struct strbuf *dst, const char *src) -{ - char *to_free = NULL; - int ret; - - if (dst->buf == src) - to_free = strbuf_detach(dst, NULL); - - ret = strbuf_addch(dst, '\''); - while (!ret && *src) { - size_t len = strcspn(src, "'!"); - ret = strbuf_add(dst, src, len); - src += len; - while (!ret && need_bs_quote(*src)) - ret = strbuf_addf(dst, "'\\%c\'", *src++); - } - if (!ret) - ret = strbuf_addch(dst, '\''); - free(to_free); - - return ret; -} - -int sq_quote_argv(struct strbuf *dst, const char** argv, size_t maxlen) -{ - int i, ret; - - /* Copy into destination buffer. */ - ret = strbuf_grow(dst, 255); - for (i = 0; !ret && argv[i]; ++i) { - ret = strbuf_addch(dst, ' '); - if (ret) - break; - ret = sq_quote_buf(dst, argv[i]); - if (maxlen && dst->len > maxlen) - return -ENOSPC; - } - return ret; -} diff --git a/tools/perf/util/quote.h b/tools/perf/util/quote.h deleted file mode 100644 index 274bf26d3511..000000000000 --- a/tools/perf/util/quote.h +++ /dev/null @@ -1,31 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0 */ -#ifndef __PERF_QUOTE_H -#define __PERF_QUOTE_H - -#include - -/* Help to copy the thing properly quoted for the shell safety. - * any single quote is replaced with '\'', any exclamation point - * is replaced with '\!', and the whole thing is enclosed in a - * single quote pair. - * - * For example, if you are passing the result to system() as an - * argument: - * - * sprintf(cmd, "foobar %s %s", sq_quote(arg0), sq_quote(arg1)) - * - * would be appropriate. If the system() is going to call ssh to - * run the command on the other side: - * - * sprintf(cmd, "git-diff-tree %s %s", sq_quote(arg0), sq_quote(arg1)); - * sprintf(rcmd, "ssh %s %s", sq_util/quote.host), sq_quote(cmd)); - * - * Note that the above examples leak memory! Remember to free result from - * sq_quote() in a real application. - */ - -struct strbuf; - -int sq_quote_argv(struct strbuf *, const char **argv, size_t maxlen); - -#endif /* __PERF_QUOTE_H */ -- cgit From f622df5ed768ce7c049af99196c1b7b0a2c0d385 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 24 May 2018 11:17:34 -0300 Subject: perf probe: Use return of map__get() to make code more compact The __get() idiom returns a reference count for the object passed, i.e. all functions of this type return the object passed, so take advantage of that to make the code more compact. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Masami Hiramatsu Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-ds6vdm7clh070512rpydidsc@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/probe-event.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index 3094f11e7d81..f119eb628dbb 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -165,8 +165,7 @@ static struct map *kernel_get_module_map(const char *module) if (strncmp(pos->dso->short_name + 1, module, pos->dso->short_name_len - 2) == 0 && module[pos->dso->short_name_len - 2] == '\0') { - map__get(pos); - return pos; + return map__get(pos); } } return NULL; -- cgit From 5dbe23e8772299f227f1ac974752bc853e9814bb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 24 May 2018 11:29:07 -0300 Subject: perf cgroup: Make evlist__find_cgroup() more compact By taking advantage that __get() routines return the pointer to the object for which a reference count is being get. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Stephane Eranian Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-xnvd07rdxliy04oi062samik@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/cgroup.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/cgroup.c b/tools/perf/util/cgroup.c index decb91f9da82..ccd02634a616 100644 --- a/tools/perf/util/cgroup.c +++ b/tools/perf/util/cgroup.c @@ -93,20 +93,17 @@ static int open_cgroup(const char *name) static struct cgroup *evlist__find_cgroup(struct perf_evlist *evlist, const char *str) { struct perf_evsel *counter; - struct cgroup *cgrp = NULL; /* * check if cgrp is already defined, if so we reuse it */ evlist__for_each_entry(evlist, counter) { if (!counter->cgrp) continue; - if (!strcmp(counter->cgrp->name, str)) { - cgrp = cgroup__get(counter->cgrp); - break; - } + if (!strcmp(counter->cgrp->name, str)) + return cgroup__get(counter->cgrp); } - return cgrp; + return NULL; } static struct cgroup *cgroup__new(const char *name) -- cgit From 362379aad56fdc627a49e30d12c3ece900221898 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 24 May 2018 11:20:39 -0300 Subject: perf tools: No need to check if the argument to __get() function is NULL Those functions always check if the argument is NULL before trying to grab a reference count, and also will return the received object, so, to make code more compact, no need to check for NULL. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Krister Johansen Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-i9wycjdxh0fwhryu55lmafks@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-probe.c | 3 +-- tools/perf/util/hist.c | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index c0065923a525..99de91698de1 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c @@ -81,8 +81,7 @@ static int parse_probe_event(const char *str) params.target_used = true; } - if (params.nsi) - pev->nsi = nsinfo__get(params.nsi); + pev->nsi = nsinfo__get(params.nsi); /* Parse a perf-probe command into event */ ret = parse_perf_probe_command(str, pev); diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 4d602fba40b2..95333b068109 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -1039,7 +1039,7 @@ int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al, int err, err2; struct map *alm = NULL; - if (al && al->map) + if (al) alm = map__get(al->map); err = sample__resolve_callchain(iter->sample, &callchain_cursor, &iter->parent, -- cgit From e345f3bd9b2f4a768a216f629a1ae750eb609aee Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 24 May 2018 12:05:39 -0300 Subject: perf annotate: Pass perf_evsel instead of just evsel->idx The code gets shorter and we'll be able to use evsel->evlist in a followup patch. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-t0s7vy19wq5kak74kavm8swf@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 6 +++--- tools/perf/builtin-report.c | 17 ++++++++--------- tools/perf/builtin-top.c | 6 +++--- tools/perf/util/annotate.c | 12 ++++++------ tools/perf/util/annotate.h | 4 ++-- 5 files changed, 22 insertions(+), 23 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index da5704240239..2b21bbcd70ea 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -162,12 +162,12 @@ static int hist_iter__branch_callback(struct hist_entry_iter *iter, hist__account_cycles(sample->branch_stack, al, sample, false); bi = he->branch_info; - err = addr_map_symbol__inc_samples(&bi->from, sample, evsel->idx); + err = addr_map_symbol__inc_samples(&bi->from, sample, evsel); if (err) goto out; - err = addr_map_symbol__inc_samples(&bi->to, sample, evsel->idx); + err = addr_map_symbol__inc_samples(&bi->to, sample, evsel); out: return err; @@ -249,7 +249,7 @@ static int perf_evsel__add_sample(struct perf_evsel *evsel, if (he == NULL) return -ENOMEM; - ret = hist_entry__inc_addr_samples(he, sample, evsel->idx, al->addr); + ret = hist_entry__inc_addr_samples(he, sample, evsel, al->addr); hists__inc_nr_samples(hists, true); return ret; } diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index ad978e3ee2b8..7a689c933f04 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -136,26 +136,25 @@ static int hist_iter__report_callback(struct hist_entry_iter *iter, if (sort__mode == SORT_MODE__BRANCH) { bi = he->branch_info; - err = addr_map_symbol__inc_samples(&bi->from, sample, evsel->idx); + err = addr_map_symbol__inc_samples(&bi->from, sample, evsel); if (err) goto out; - err = addr_map_symbol__inc_samples(&bi->to, sample, evsel->idx); + err = addr_map_symbol__inc_samples(&bi->to, sample, evsel); } else if (rep->mem_mode) { mi = he->mem_info; - err = addr_map_symbol__inc_samples(&mi->daddr, sample, evsel->idx); + err = addr_map_symbol__inc_samples(&mi->daddr, sample, evsel); if (err) goto out; - err = hist_entry__inc_addr_samples(he, sample, evsel->idx, al->addr); + err = hist_entry__inc_addr_samples(he, sample, evsel, al->addr); } else if (symbol_conf.cumulate_callchain) { if (single) - err = hist_entry__inc_addr_samples(he, sample, evsel->idx, - al->addr); + err = hist_entry__inc_addr_samples(he, sample, evsel, al->addr); } else { - err = hist_entry__inc_addr_samples(he, sample, evsel->idx, al->addr); + err = hist_entry__inc_addr_samples(he, sample, evsel, al->addr); } out: @@ -181,11 +180,11 @@ static int hist_iter__branch_callback(struct hist_entry_iter *iter, rep->nonany_branch_mode); bi = he->branch_info; - err = addr_map_symbol__inc_samples(&bi->from, sample, evsel->idx); + err = addr_map_symbol__inc_samples(&bi->from, sample, evsel); if (err) goto out; - err = addr_map_symbol__inc_samples(&bi->to, sample, evsel->idx); + err = addr_map_symbol__inc_samples(&bi->to, sample, evsel); branch_type_count(&rep->brtype_stat, &bi->flags, bi->from.addr, bi->to.addr); diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 7a349fcd3864..bc71e899096d 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -188,7 +188,7 @@ static void ui__warn_map_erange(struct map *map, struct symbol *sym, u64 ip) static void perf_top__record_precise_ip(struct perf_top *top, struct hist_entry *he, struct perf_sample *sample, - int counter, u64 ip) + struct perf_evsel *evsel, u64 ip) { struct annotation *notes; struct symbol *sym = he->ms.sym; @@ -204,7 +204,7 @@ static void perf_top__record_precise_ip(struct perf_top *top, if (pthread_mutex_trylock(¬es->lock)) return; - err = hist_entry__inc_addr_samples(he, sample, counter, ip); + err = hist_entry__inc_addr_samples(he, sample, evsel, ip); pthread_mutex_unlock(¬es->lock); @@ -691,7 +691,7 @@ static int hist_iter__top_callback(struct hist_entry_iter *iter, struct perf_evsel *evsel = iter->evsel; if (perf_hpp_list.sym && single) - perf_top__record_precise_ip(top, he, iter->sample, evsel->idx, al->addr); + perf_top__record_precise_ip(top, he, iter->sample, evsel, al->addr); hist__account_cycles(iter->sample->branch_stack, al, iter->sample, !(top->record_opts.branch_stack & PERF_SAMPLE_BRANCH_ANY)); diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 71897689dacf..0f5ed6091e00 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -836,7 +836,7 @@ static struct annotation *symbol__get_annotation(struct symbol *sym, bool cycles } static int symbol__inc_addr_samples(struct symbol *sym, struct map *map, - int evidx, u64 addr, + struct perf_evsel *evsel, u64 addr, struct perf_sample *sample) { struct annotation *notes; @@ -846,7 +846,7 @@ static int symbol__inc_addr_samples(struct symbol *sym, struct map *map, notes = symbol__get_annotation(sym, false); if (notes == NULL) return -ENOMEM; - return __symbol__inc_addr_samples(sym, map, notes, evidx, addr, sample); + return __symbol__inc_addr_samples(sym, map, notes, evsel->idx, addr, sample); } static int symbol__account_cycles(u64 addr, u64 start, @@ -974,15 +974,15 @@ void annotation__compute_ipc(struct annotation *notes, size_t size) } int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample, - int evidx) + struct perf_evsel *evsel) { - return symbol__inc_addr_samples(ams->sym, ams->map, evidx, ams->al_addr, sample); + return symbol__inc_addr_samples(ams->sym, ams->map, evsel, ams->al_addr, sample); } int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample, - int evidx, u64 ip) + struct perf_evsel *evsel, u64 ip) { - return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip, sample); + return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evsel, ip, sample); } static void disasm_line__init_ins(struct disasm_line *dl, struct arch *arch, struct map_symbol *ms) diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 5080b6dd98b8..aef9eae4f125 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -279,14 +279,14 @@ static inline struct annotation *symbol__annotation(struct symbol *sym) } int addr_map_symbol__inc_samples(struct addr_map_symbol *ams, struct perf_sample *sample, - int evidx); + struct perf_evsel *evsel); int addr_map_symbol__account_cycles(struct addr_map_symbol *ams, struct addr_map_symbol *start, unsigned cycles); int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample, - int evidx, u64 addr); + struct perf_evsel *evsel, u64 addr); int symbol__alloc_hist(struct symbol *sym); void symbol__annotate_zero_histograms(struct symbol *sym); -- cgit From f40dd6d1b4b29208a7232693746575f7ae6365a5 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 24 May 2018 15:20:18 -0300 Subject: perf annotate: __symbol__acount_cycles doesn't need notes It only operates on the notes->src->cyc_hist, just pass that to it. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-zd1cu4zwmu21k0cxlr83y6vr@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 0f5ed6091e00..a7221f9fa504 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -741,14 +741,11 @@ void symbol__annotate_zero_histograms(struct symbol *sym) pthread_mutex_unlock(¬es->lock); } -static int __symbol__account_cycles(struct annotation *notes, +static int __symbol__account_cycles(struct cyc_hist *ch, u64 start, unsigned offset, unsigned cycles, unsigned have_start) { - struct cyc_hist *ch; - - ch = notes->src->cycles_hist; /* * For now we can only account one basic block per * final jump. But multiple could be overlapping. @@ -870,7 +867,7 @@ static int symbol__account_cycles(u64 addr, u64 start, start = 0; } offset = addr - sym->start; - return __symbol__account_cycles(notes, + return __symbol__account_cycles(notes->src->cycles_hist, start ? start - sym->start : 0, offset, cycles, !!start); -- cgit From 116c626b9aca10ee7619b06185c22a5b2da19e30 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 24 May 2018 15:31:40 -0300 Subject: perf annotate: Split allocation of annotated_source struct So that we can allocate just the notes->src->cyc_hist, that, unlike notes->src->histograms, is not per event, and in paths where we need to lazily allocate notes->src->cyc_hist we don't have the number of events handy to also allocate ->histograms. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-tsx7dhxzpi0criyx0sio3pz3@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 10 +++++++--- tools/perf/util/annotate.h | 6 +++--- 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index a7221f9fa504..f0c6941bca6c 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -701,13 +701,17 @@ int symbol__alloc_hist(struct symbol *sym) sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(struct sym_hist_entry)); /* Check for overflow in zalloc argument */ - if (sizeof_sym_hist > (SIZE_MAX - sizeof(*notes->src)) - / symbol_conf.nr_events) + if (sizeof_sym_hist > SIZE_MAX / symbol_conf.nr_events) return -1; - notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist); + notes->src = zalloc(sizeof(*notes->src)); if (notes->src == NULL) return -1; + notes->src->histograms = calloc(symbol_conf.nr_events, sizeof_sym_hist); + if (notes->src->histograms == NULL) { + zfree(¬es->src); + return -1; + } notes->src->sizeof_sym_hist = sizeof_sym_hist; notes->src->nr_histograms = symbol_conf.nr_events; INIT_LIST_HEAD(¬es->src->source); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index aef9eae4f125..94b60e34c3a7 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -201,7 +201,7 @@ struct cyc_hist { /** struct annotated_source - symbols with hits have this attached as in sannotation * - * @histogram: Array of addr hit histograms per event being monitored + * @histograms: Array of addr hit histograms per event being monitored * @lines: If 'print_lines' is specified, per source code line percentages * @source: source parsed from a disassembler like objdump -dS * @cyc_hist: Average cycles per basic block @@ -217,7 +217,7 @@ struct annotated_source { int nr_histograms; size_t sizeof_sym_hist; struct cyc_hist *cycles_hist; - struct sym_hist histograms[0]; + struct sym_hist *histograms; }; struct annotation { @@ -269,7 +269,7 @@ void annotation__init_column_widths(struct annotation *notes, struct symbol *sym static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx) { - return (((void *)¬es->src->histograms) + + return (((void *)notes->src->histograms) + (notes->src->sizeof_sym_hist * idx)); } -- cgit From ca39650309a7ce471ed6077267a27a0ac1f28941 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 24 May 2018 16:01:31 -0300 Subject: perf annotate: Introduce constructor/destructor for annotated_source More stuff will go in there, all the parts that are not needed when a symbol had no samples and that were mistakenly added to 'struct annotation'. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-u4761kyzhixw9ydk6kib3f0o@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 25 ++++++++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index f0c6941bca6c..f6c9bb29ac84 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -678,6 +678,25 @@ static struct arch *arch__find(const char *name) return bsearch(name, architectures, nmemb, sizeof(struct arch), arch__key_cmp); } +static struct annotated_source *annotated_source__new(void) +{ + struct annotated_source *src = zalloc(sizeof(*src)); + + if (src != NULL) + INIT_LIST_HEAD(&src->source); + + return src; +} + +static void annotated_source__delete(struct annotated_source *src) +{ + if (src == NULL) + return; + zfree(&src->histograms); + zfree(&src->cycles_hist); + free(src); +} + int symbol__alloc_hist(struct symbol *sym) { struct annotation *notes = symbol__annotation(sym); @@ -704,17 +723,17 @@ int symbol__alloc_hist(struct symbol *sym) if (sizeof_sym_hist > SIZE_MAX / symbol_conf.nr_events) return -1; - notes->src = zalloc(sizeof(*notes->src)); + notes->src = annotated_source__new(); if (notes->src == NULL) return -1; notes->src->histograms = calloc(symbol_conf.nr_events, sizeof_sym_hist); if (notes->src->histograms == NULL) { - zfree(¬es->src); + annotated_source__delete(notes->src); + notes->src = NULL; return -1; } notes->src->sizeof_sym_hist = sizeof_sym_hist; notes->src->nr_histograms = symbol_conf.nr_events; - INIT_LIST_HEAD(¬es->src->source); return 0; } -- cgit From be3e26d99c3abf4b17728da7bc606dd05419611e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 24 May 2018 16:23:08 -0300 Subject: perf annotate: Introduce annotated_source__alloc_histograms So that we can call it independently, in contexts were we know we already have notes->src allocated. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-f5fn7tr1asey6g013wavpn4c@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index f6c9bb29ac84..a6fa49bf879b 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -697,10 +697,9 @@ static void annotated_source__delete(struct annotated_source *src) free(src); } -int symbol__alloc_hist(struct symbol *sym) +static int annotated_source__alloc_histograms(struct annotated_source *src, + size_t size, int nr_hists) { - struct annotation *notes = symbol__annotation(sym); - size_t size = symbol__size(sym); size_t sizeof_sym_hist; /* @@ -720,20 +719,29 @@ int symbol__alloc_hist(struct symbol *sym) sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(struct sym_hist_entry)); /* Check for overflow in zalloc argument */ - if (sizeof_sym_hist > SIZE_MAX / symbol_conf.nr_events) + if (sizeof_sym_hist > SIZE_MAX / nr_hists) return -1; + src->sizeof_sym_hist = sizeof_sym_hist; + src->nr_histograms = nr_hists; + src->histograms = calloc(nr_hists, sizeof_sym_hist) ; + return src->histograms ? 0 : -1; +} + +int symbol__alloc_hist(struct symbol *sym) +{ + size_t size = symbol__size(sym); + struct annotation *notes = symbol__annotation(sym); + notes->src = annotated_source__new(); if (notes->src == NULL) return -1; - notes->src->histograms = calloc(symbol_conf.nr_events, sizeof_sym_hist); - if (notes->src->histograms == NULL) { + + if (annotated_source__alloc_histograms(notes->src, size, symbol_conf.nr_events) < 0) { annotated_source__delete(notes->src); notes->src = NULL; return -1; } - notes->src->sizeof_sym_hist = sizeof_sym_hist; - notes->src->nr_histograms = symbol_conf.nr_events; return 0; } -- cgit From e1a91a834d6e1b6616b76b0ba22e7e11d5592c3b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 24 May 2018 16:28:29 -0300 Subject: perf annotate: __symbol__inc_addr_samples() needs just annotated_source It only operates on the histograms, so no need for the encompassing 'struct annotation'. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-2se2v7rrjil0kwqywks04ey2@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 6 +++--- tools/perf/util/annotate.h | 8 ++++++-- 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index a6fa49bf879b..a5a6d686004e 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -819,7 +819,7 @@ static int __symbol__account_cycles(struct cyc_hist *ch, } static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map, - struct annotation *notes, int evidx, u64 addr, + struct annotated_source *src, int evidx, u64 addr, struct perf_sample *sample) { unsigned offset; @@ -835,7 +835,7 @@ static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map, } offset = addr - sym->start; - h = annotation__histogram(notes, evidx); + h = annotated_source__histogram(src, evidx); h->nr_samples++; h->addr[offset].nr_samples++; h->period += sample->period; @@ -874,7 +874,7 @@ static int symbol__inc_addr_samples(struct symbol *sym, struct map *map, notes = symbol__get_annotation(sym, false); if (notes == NULL) return -ENOMEM; - return __symbol__inc_addr_samples(sym, map, notes, evsel->idx, addr, sample); + return __symbol__inc_addr_samples(sym, map, notes->src, evsel->idx, addr, sample); } static int symbol__account_cycles(u64 addr, u64 start, diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 94b60e34c3a7..2a73f9084930 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -267,10 +267,14 @@ void annotation__mark_jump_targets(struct annotation *notes, struct symbol *sym) void annotation__update_column_widths(struct annotation *notes); void annotation__init_column_widths(struct annotation *notes, struct symbol *sym); +static inline struct sym_hist *annotated_source__histogram(struct annotated_source *src, int idx) +{ + return ((void *)src->histograms) + (src->sizeof_sym_hist * idx); +} + static inline struct sym_hist *annotation__histogram(struct annotation *notes, int idx) { - return (((void *)notes->src->histograms) + - (notes->src->sizeof_sym_hist * idx)); + return annotated_source__histogram(notes->src, idx); } static inline struct annotation *symbol__annotation(struct symbol *sym) -- cgit From e8ea922a7e077b491c6363755e3ac94d350ea253 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 24 May 2018 16:37:53 -0300 Subject: perf annotate: Introduce symbol__hists() In this case we're wanting just notes->src->histograms, allocating it if needed. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-4iatualjskia7sojmdb65cmm@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index a5a6d686004e..467bae0279ce 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -863,18 +863,38 @@ static struct annotation *symbol__get_annotation(struct symbol *sym, bool cycles return notes; } +static struct annotated_source *symbol__hists(struct symbol *sym) +{ + struct annotation *notes = symbol__annotation(sym); + + if (notes->src == NULL) { + notes->src = annotated_source__new(); + if (notes->src == NULL) + return NULL; + goto alloc_histograms; + } + + if (notes->src->histograms == NULL) { +alloc_histograms: + annotated_source__alloc_histograms(notes->src, symbol__size(sym), + symbol_conf.nr_events); + } + + return notes->src; +} + static int symbol__inc_addr_samples(struct symbol *sym, struct map *map, struct perf_evsel *evsel, u64 addr, struct perf_sample *sample) { - struct annotation *notes; + struct annotated_source *src; if (sym == NULL) return 0; - notes = symbol__get_annotation(sym, false); - if (notes == NULL) + src = symbol__hists(sym); + if (src == NULL) return -ENOMEM; - return __symbol__inc_addr_samples(sym, map, notes->src, evsel->idx, addr, sample); + return __symbol__inc_addr_samples(sym, map, src, evsel->idx, addr, sample); } static int symbol__account_cycles(u64 addr, u64 start, -- cgit From c6b635eece599ae13ffce081bac1fde94912df33 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 24 May 2018 17:17:05 -0300 Subject: perf annotate: Introduce symbol__cycle_hists() In this case we're wanting just notes->src->cycles_hist, allocating it if needed. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-pqj81aneunhftlntm66tmhz0@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 467bae0279ce..f11199f0be27 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -848,19 +848,23 @@ static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map, return 0; } -static struct annotation *symbol__get_annotation(struct symbol *sym, bool cycles) +static struct cyc_hist *symbol__cycles_hist(struct symbol *sym) { struct annotation *notes = symbol__annotation(sym); if (notes->src == NULL) { - if (symbol__alloc_hist(sym) < 0) + notes->src = annotated_source__new(); + if (notes->src == NULL) return NULL; + goto alloc_cycles_hist; } - if (!notes->src->cycles_hist && cycles) { - if (symbol__alloc_hist_cycles(sym) < 0) - return NULL; + + if (!notes->src->cycles_hist) { +alloc_cycles_hist: + symbol__alloc_hist_cycles(sym); } - return notes; + + return notes->src->cycles_hist; } static struct annotated_source *symbol__hists(struct symbol *sym) @@ -900,13 +904,13 @@ static int symbol__inc_addr_samples(struct symbol *sym, struct map *map, static int symbol__account_cycles(u64 addr, u64 start, struct symbol *sym, unsigned cycles) { - struct annotation *notes; + struct cyc_hist *cycles_hist; unsigned offset; if (sym == NULL) return 0; - notes = symbol__get_annotation(sym, true); - if (notes == NULL) + cycles_hist = symbol__cycles_hist(sym); + if (cycles_hist == NULL) return -ENOMEM; if (addr < sym->start || addr >= sym->end) return -ERANGE; @@ -918,7 +922,7 @@ static int symbol__account_cycles(u64 addr, u64 start, start = 0; } offset = addr - sym->start; - return __symbol__account_cycles(notes->src->cycles_hist, + return __symbol__account_cycles(cycles_hist, start ? start - sym->start : 0, offset, cycles, !!start); -- cgit From 0693f7588a2f2e016e0774102c52ab2494938348 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 24 May 2018 17:20:53 -0300 Subject: perf annotate: Stop using symbol_conf.nr_events global in symbol__hists() Since now we have evsel->evlist->nr_entries in the single place calling this function, use it. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-9mgosbqa977h39j4i9ys8t75@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index f11199f0be27..7c194b04a2da 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -21,6 +21,7 @@ #include "debug.h" #include "annotate.h" #include "evsel.h" +#include "evlist.h" #include "block-range.h" #include "string2.h" #include "arch/common.h" @@ -867,7 +868,7 @@ alloc_cycles_hist: return notes->src->cycles_hist; } -static struct annotated_source *symbol__hists(struct symbol *sym) +static struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists) { struct annotation *notes = symbol__annotation(sym); @@ -881,7 +882,7 @@ static struct annotated_source *symbol__hists(struct symbol *sym) if (notes->src->histograms == NULL) { alloc_histograms: annotated_source__alloc_histograms(notes->src, symbol__size(sym), - symbol_conf.nr_events); + nr_hists); } return notes->src; @@ -895,7 +896,7 @@ static int symbol__inc_addr_samples(struct symbol *sym, struct map *map, if (sym == NULL) return 0; - src = symbol__hists(sym); + src = symbol__hists(sym, evsel->evlist->nr_entries); if (src == NULL) return -ENOMEM; return __symbol__inc_addr_samples(sym, map, src, evsel->idx, addr, sample); -- cgit From 14c8dde170cc1ba6754a1275ff378092ab36b257 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 24 May 2018 17:33:18 -0300 Subject: perf annotate: Replace symbol__alloc_hists() with symbol__hists() Its a bit shorter, so ditch the old symbol__alloc_hists() function. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-m7tienxk7dijh5ln62yln1m9@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 8 +------- tools/perf/ui/browsers/annotate.c | 2 +- tools/perf/util/annotate.c | 21 ++------------------- tools/perf/util/annotate.h | 2 +- 4 files changed, 5 insertions(+), 28 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index bc71e899096d..04fe04885e99 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -123,14 +123,9 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) } notes = symbol__annotation(sym); - if (notes->src != NULL) { - pthread_mutex_lock(¬es->lock); - goto out_assign; - } - pthread_mutex_lock(¬es->lock); - if (symbol__alloc_hist(sym) < 0) { + if (!symbol__hists(sym, top->evlist->nr_entries)) { pthread_mutex_unlock(¬es->lock); pr_err("Not enough memory for annotating '%s' symbol!\n", sym->name); @@ -140,7 +135,6 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) err = symbol__annotate(sym, map, evsel, 0, NULL); if (err == 0) { -out_assign: top->sym_filter_entry = he; } else { char msg[BUFSIZ]; diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 8be40fa903aa..3bfe17e176fe 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -410,7 +410,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser, notes = symbol__annotation(dl->ops.target.sym); pthread_mutex_lock(¬es->lock); - if (notes->src == NULL && symbol__alloc_hist(dl->ops.target.sym) < 0) { + if (!symbol__hists(dl->ops.target.sym, evsel->evlist->nr_entries)) { pthread_mutex_unlock(¬es->lock); ui__warning("Not enough memory for annotating '%s' symbol!\n", dl->ops.target.sym->name); diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 7c194b04a2da..bcd5d3e17b85 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -689,7 +689,7 @@ static struct annotated_source *annotated_source__new(void) return src; } -static void annotated_source__delete(struct annotated_source *src) +static __maybe_unused void annotated_source__delete(struct annotated_source *src) { if (src == NULL) return; @@ -729,23 +729,6 @@ static int annotated_source__alloc_histograms(struct annotated_source *src, return src->histograms ? 0 : -1; } -int symbol__alloc_hist(struct symbol *sym) -{ - size_t size = symbol__size(sym); - struct annotation *notes = symbol__annotation(sym); - - notes->src = annotated_source__new(); - if (notes->src == NULL) - return -1; - - if (annotated_source__alloc_histograms(notes->src, size, symbol_conf.nr_events) < 0) { - annotated_source__delete(notes->src); - notes->src = NULL; - return -1; - } - return 0; -} - /* The cycles histogram is lazily allocated. */ static int symbol__alloc_hist_cycles(struct symbol *sym) { @@ -868,7 +851,7 @@ alloc_cycles_hist: return notes->src->cycles_hist; } -static struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists) +struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists) { struct annotation *notes = symbol__annotation(sym); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 2a73f9084930..7ad503fbff74 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -292,7 +292,7 @@ int addr_map_symbol__account_cycles(struct addr_map_symbol *ams, int hist_entry__inc_addr_samples(struct hist_entry *he, struct perf_sample *sample, struct perf_evsel *evsel, u64 addr); -int symbol__alloc_hist(struct symbol *sym); +struct annotated_source *symbol__hists(struct symbol *sym, int nr_hists); void symbol__annotate_zero_histograms(struct symbol *sym); int symbol__annotate(struct symbol *sym, struct map *map, -- cgit From 9fd5578a3cdd6cb59603b04a9282199d08f85607 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 24 May 2018 17:38:51 -0300 Subject: perf tools: Ditch the symbol_conf.nr_events global Since over time the places where we need to pass this got reduced because we can obtain it from evsel->evlist->nr_entries, no need to have this global anymore. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-ovhikrfj8pzdv93yq3gt6sei@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-kvm.c | 2 -- tools/perf/builtin-top.c | 2 -- tools/perf/util/header.c | 4 ---- tools/perf/util/symbol.h | 1 - 4 files changed, 9 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c index 72e2ca096bf5..2b1ef704169f 100644 --- a/tools/perf/builtin-kvm.c +++ b/tools/perf/builtin-kvm.c @@ -1438,8 +1438,6 @@ static int kvm_events_live(struct perf_kvm_stat *kvm, goto out; } - symbol_conf.nr_events = kvm->evlist->nr_entries; - if (perf_evlist__create_maps(kvm->evlist, &kvm->opts.target) < 0) usage_with_options(live_usage, live_options); diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 04fe04885e99..4284840022a3 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1462,8 +1462,6 @@ int cmd_top(int argc, const char **argv) goto out_delete_evlist; } - symbol_conf.nr_events = top.evlist->nr_entries; - if (top.delay_secs < 1) top.delay_secs = 1; diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index a8bff2178fbc..2625cc38a0d6 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -3312,8 +3312,6 @@ int perf_session__read_header(struct perf_session *session) lseek(fd, tmp, SEEK_SET); } - symbol_conf.nr_events = nr_attrs; - perf_header__process_sections(header, fd, &session->tevent, perf_file_section__process); @@ -3739,8 +3737,6 @@ int perf_event__process_attr(struct perf_tool *tool __maybe_unused, perf_evlist__id_add(evlist, evsel, 0, i, event->attr.id[i]); } - symbol_conf.nr_events = evlist->nr_entries; - return 0; } diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 1a16438eb3ce..1be9a6bad967 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -90,7 +90,6 @@ struct intlist; struct symbol_conf { unsigned short priv_size; - unsigned short nr_events; bool try_vmlinux_path, init_annotation, force, -- cgit From 9132d3d92d8953ee79690408a9a24d938be22cd8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 25 May 2018 11:27:38 -0300 Subject: perf annotate: Add comment about annotated_src->nr_histograms When we have multiple groups in an evlist, say: $ perf stat -e '{cycles,instructions},{cache-references,cache-misses}' sleep 1 Performance counter stats for 'sleep 1': 343,134 cycles:u 249,292 instructions:u # 0.73 insn per cycle 15,556 cache-references:u 8,925 cache-misses:u # 57.373 % of all cache refs 1.000957550 seconds time elapsed $ Then the perf_evsel instances for the two group leaders ("cycles" and "cache-references") will have evsel->nr_members set to 2, while all the evsel->evlist->nr_entries will be set to 4, so we can't use evsel->evlist->nr_entries everywhere, as event groups need to be taken into account. But this probably requires us to audit at least the forced-group code, where we want all of the events to be in a "group", to see them all in the screen, one column for each, even knowing that they were not necessarily scheduled to count at the same time by the kernel perf subsystem. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-2g0vwqnc49wl4ttjk8dvpgcc@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'tools') diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 7ad503fbff74..3dc4ca1d6c08 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -202,6 +202,10 @@ struct cyc_hist { /** struct annotated_source - symbols with hits have this attached as in sannotation * * @histograms: Array of addr hit histograms per event being monitored + * nr_histograms: This may not be the same as evsel->evlist->nr_entries if + * we have more than a group in a evlist, where we will want + * to see each group separately, that is why symbol__annotate2() + * sets src->nr_histograms to evsel->nr_members. * @lines: If 'print_lines' is specified, per source code line percentages * @source: source parsed from a disassembler like objdump -dS * @cyc_hist: Average cycles per basic block -- cgit From 982d410bc6b405a75086236d3c1da1f18c40d6dd Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 25 May 2018 17:28:37 -0300 Subject: perf annotate stdio: Use annotation_options consistently Accross all the routines, this way we can have eventually have a consistent set of defaults for all UIs. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-6qgtixurjgdk5u0n3rw78ges@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 15 +++++++-------- tools/perf/builtin-top.c | 14 ++++++++------ tools/perf/util/annotate.c | 31 +++++++++++++++---------------- tools/perf/util/annotate.h | 15 +++++++++------ tools/perf/util/top.h | 3 ++- 5 files changed, 41 insertions(+), 37 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 2b21bbcd70ea..7238010f28d4 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -40,9 +40,8 @@ struct perf_annotate { struct perf_tool tool; struct perf_session *session; + struct annotation_options opts; bool use_tui, use_stdio, use_stdio2, use_gtk; - bool full_paths; - bool print_line; bool skip_missing; bool has_br_stack; bool group_set; @@ -289,10 +288,9 @@ static int hist_entry__tty_annotate(struct hist_entry *he, struct perf_annotate *ann) { if (!ann->use_stdio2) - return symbol__tty_annotate(he->ms.sym, he->ms.map, evsel, - ann->print_line, ann->full_paths, 0, 0); - return symbol__tty_annotate2(he->ms.sym, he->ms.map, evsel, - ann->print_line, ann->full_paths); + return symbol__tty_annotate(he->ms.sym, he->ms.map, evsel, &ann->opts); + + return symbol__tty_annotate2(he->ms.sym, he->ms.map, evsel, &ann->opts); } static void hists__find_annotations(struct hists *hists, @@ -476,6 +474,7 @@ int cmd_annotate(int argc, const char **argv) .ordered_events = true, .ordering_requires_timestamps = true, }, + .opts = annotation__default_options, }; struct perf_data data = { .mode = PERF_DATA_MODE_READ, @@ -503,9 +502,9 @@ int cmd_annotate(int argc, const char **argv) "file", "vmlinux pathname"), OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules, "load module symbols - WARNING: use only with -k and LIVE kernel"), - OPT_BOOLEAN('l', "print-line", &annotate.print_line, + OPT_BOOLEAN('l', "print-line", &annotate.opts.print_lines, "print matching source lines (may be slow)"), - OPT_BOOLEAN('P', "full-paths", &annotate.full_paths, + OPT_BOOLEAN('P', "full-paths", &annotate.opts.full_path, "Don't shorten the displayed pathnames"), OPT_BOOLEAN(0, "skip-missing", &annotate.skip_missing, "Skip symbols that cannot be annotated"), diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 4284840022a3..5e58cd4de90b 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -243,10 +243,9 @@ static void perf_top__show_details(struct perf_top *top) goto out_unlock; printf("Showing %s for %s\n", perf_evsel__name(top->sym_evsel), symbol->name); - printf(" Events Pcnt (>=%d%%)\n", top->sym_pcnt_filter); + printf(" Events Pcnt (>=%d%%)\n", top->annotation_opts.min_pcnt); - more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel, - 0, top->sym_pcnt_filter, top->print_entries, 4); + more = symbol__annotate_printf(symbol, he->ms.map, top->sym_evsel, &top->annotation_opts); if (top->evlist->enabled) { if (top->zero) @@ -406,7 +405,7 @@ static void perf_top__print_mapped_keys(struct perf_top *top) fprintf(stdout, "\t[f] profile display filter (count). \t(%d)\n", top->count_filter); - fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", top->sym_pcnt_filter); + fprintf(stdout, "\t[F] annotate display filter (percent). \t(%d%%)\n", top->annotation_opts.min_pcnt); fprintf(stdout, "\t[s] annotate symbol. \t(%s)\n", name?: "NULL"); fprintf(stdout, "\t[S] stop annotation.\n"); @@ -509,7 +508,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c) prompt_integer(&top->count_filter, "Enter display event count filter"); break; case 'F': - prompt_percent(&top->sym_pcnt_filter, + prompt_percent(&top->annotation_opts.min_pcnt, "Enter details display event filter (percent)"); break; case 'K': @@ -1259,7 +1258,7 @@ int cmd_top(int argc, const char **argv) .overwrite = 1, }, .max_stack = sysctl__max_stack(), - .sym_pcnt_filter = 5, + .annotation_opts = annotation__default_options, .nr_threads_synthesize = UINT_MAX, }; struct record_opts *opts = &top.record_opts; @@ -1385,6 +1384,9 @@ int cmd_top(int argc, const char **argv) if (status < 0) return status; + top.annotation_opts.min_pcnt = 5; + top.annotation_opts.context = 4; + top.evlist = perf_evlist__new(); if (top.evlist == NULL) return -ENOMEM; diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index bcd5d3e17b85..abcc7e24c365 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1985,8 +1985,8 @@ static int annotated_source__addr_fmt_width(struct list_head *lines, u64 start) } int symbol__annotate_printf(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, bool full_paths, - int min_pcnt, int max_lines, int context) + struct perf_evsel *evsel, + struct annotation_options *opts) { struct dso *dso = map->dso; char *filename; @@ -1998,6 +1998,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, u64 start = map__rip_2objdump(map, sym->start); int printed = 2, queue_len = 0, addr_fmt_width; int more = 0; + bool context = opts->context; u64 len; int width = symbol_conf.show_total_period ? 12 : 8; int graph_dotted_len; @@ -2007,7 +2008,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, if (!filename) return -ENOMEM; - if (full_paths) + if (opts->full_path) d_filename = filename; else d_filename = basename(filename); @@ -2042,7 +2043,7 @@ int symbol__annotate_printf(struct symbol *sym, struct map *map, } err = annotation_line__print(pos, sym, start, evsel, len, - min_pcnt, printed, max_lines, + opts->min_pcnt, printed, opts->max_lines, queue, addr_fmt_width); switch (err) { @@ -2375,20 +2376,19 @@ static void symbol__calc_lines(struct symbol *sym, struct map *map, } int symbol__tty_annotate2(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, bool print_lines, - bool full_paths) + struct perf_evsel *evsel, + struct annotation_options *opts) { struct dso *dso = map->dso; struct rb_root source_line = RB_ROOT; - struct annotation_options opts = annotation__default_options; struct annotation *notes = symbol__annotation(sym); char buf[1024]; - if (symbol__annotate2(sym, map, evsel, &opts, NULL) < 0) + if (symbol__annotate2(sym, map, evsel, opts, NULL) < 0) return -1; - if (print_lines) { - srcline_full_filename = full_paths; + if (opts->print_lines) { + srcline_full_filename = opts->full_path; symbol__calc_lines(sym, map, &source_line); print_summary(&source_line, dso->long_name); } @@ -2403,8 +2403,8 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map, } int symbol__tty_annotate(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, bool print_lines, - bool full_paths, int min_pcnt, int max_lines) + struct perf_evsel *evsel, + struct annotation_options *opts) { struct dso *dso = map->dso; struct rb_root source_line = RB_ROOT; @@ -2414,14 +2414,13 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, symbol__calc_percent(sym, evsel); - if (print_lines) { - srcline_full_filename = full_paths; + if (opts->print_lines) { + srcline_full_filename = opts->full_path; symbol__calc_lines(sym, map, &source_line); print_summary(&source_line, dso->long_name); } - symbol__annotate_printf(sym, map, evsel, full_paths, - min_pcnt, max_lines, 0); + symbol__annotate_printf(sym, map, evsel, opts); annotated_source__purge(symbol__annotation(sym)->src); diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 3dc4ca1d6c08..20f3326cc640 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -67,12 +67,17 @@ struct annotation_options { bool hide_src_code, use_offset, jump_arrows, + print_lines, + full_path, show_linenr, show_nr_jumps, show_nr_samples, show_total_period, show_minmax_cycle; u8 offset_level; + int min_pcnt; + int max_lines; + int context; }; enum { @@ -328,8 +333,8 @@ int symbol__strerror_disassemble(struct symbol *sym, struct map *map, int errnum, char *buf, size_t buflen); int symbol__annotate_printf(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, bool full_paths, - int min_pcnt, int max_lines, int context); + struct perf_evsel *evsel, + struct annotation_options *options); int symbol__annotate_fprintf2(struct symbol *sym, FILE *fp); void symbol__annotate_zero_histogram(struct symbol *sym, int evidx); void symbol__annotate_decay_histogram(struct symbol *sym, int evidx); @@ -340,12 +345,10 @@ int map_symbol__annotation_dump(struct map_symbol *ms, struct perf_evsel *evsel) bool ui__has_annotation(void); int symbol__tty_annotate(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, bool print_lines, - bool full_paths, int min_pcnt, int max_lines); + struct perf_evsel *evsel, struct annotation_options *opts); int symbol__tty_annotate2(struct symbol *sym, struct map *map, - struct perf_evsel *evsel, bool print_lines, - bool full_paths); + struct perf_evsel *evsel, struct annotation_options *opts); #ifdef HAVE_SLANG_SUPPORT int symbol__tui_annotate(struct symbol *sym, struct map *map, diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 9892323cdd7c..9add1f72ce95 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h @@ -3,6 +3,7 @@ #define __PERF_TOP_H 1 #include "tool.h" +#include "annotate.h" #include #include #include @@ -16,6 +17,7 @@ struct perf_top { struct perf_tool tool; struct perf_evlist *evlist; struct record_opts record_opts; + struct annotation_options annotation_opts; /* * Symbols will be added here in perf_event__process_sample and will * get out after decayed. @@ -35,7 +37,6 @@ struct perf_top { struct perf_session *session; struct winsize winsize; int realtime_prio; - int sym_pcnt_filter; const char *sym_filter; float min_percent; unsigned int nr_threads_synthesize; -- cgit From e2d88aaa649e65851463426b133d87b61d3accbd Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 28 May 2018 11:05:20 -0300 Subject: perf srcline: Introduce map__srcline() to make code more compact Replacing a common open coded sequence. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-2d7d1nzd3ksqornloqeer99r@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/map.c | 12 ++++++---- tools/perf/util/map.h | 1 + tools/perf/util/sort.c | 60 +++++++++++--------------------------------------- 3 files changed, 22 insertions(+), 51 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 6ae97eda370b..92abc8e248c5 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -415,16 +415,20 @@ size_t map__fprintf_dsoname(struct map *map, FILE *fp) return fprintf(fp, "%s", dsoname); } +char *map__srcline(struct map *map, u64 addr, struct symbol *sym) +{ + if (map == NULL) + return SRCLINE_UNKNOWN; + return get_srcline(map->dso, map__rip_2objdump(map, addr), sym, true, true, addr); +} + int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, FILE *fp) { - char *srcline; int ret = 0; if (map && map->dso) { - srcline = get_srcline(map->dso, - map__rip_2objdump(map, addr), NULL, - true, true, addr); + char *srcline = map__srcline(map, addr, NULL); if (srcline != SRCLINE_UNKNOWN) ret = fprintf(fp, "%s%s", prefix, srcline); free_srcline(srcline); diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 97e2a063bd65..4cb90f242bed 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h @@ -169,6 +169,7 @@ static inline void __map__zput(struct map **map) int map__overlap(struct map *l, struct map *r); size_t map__fprintf(struct map *map, FILE *fp); size_t map__fprintf_dsoname(struct map *map, FILE *fp); +char *map__srcline(struct map *map, u64 addr, struct symbol *sym); int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, FILE *fp); diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 4058ade352a5..71096dbfeb88 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -333,13 +333,7 @@ struct sort_entry sort_sym = { char *hist_entry__get_srcline(struct hist_entry *he) { - struct map *map = he->ms.map; - - if (!map) - return SRCLINE_UNKNOWN; - - return get_srcline(map->dso, map__rip_2objdump(map, he->ip), - he->ms.sym, true, true, he->ip); + return map__srcline(he->ms.map, he->ip, he->ms.sym); } static int64_t @@ -375,28 +369,14 @@ static int64_t sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right) { if (!left->branch_info->srcline_from) { - struct map *map = left->branch_info->from.map; - if (!map) - left->branch_info->srcline_from = SRCLINE_UNKNOWN; - else - left->branch_info->srcline_from = get_srcline(map->dso, - map__rip_2objdump(map, - left->branch_info->from.al_addr), - left->branch_info->from.sym, - true, true, - left->branch_info->from.al_addr); + left->branch_info->srcline_from = map__srcline(left->branch_info->from.map, + left->branch_info->from.al_addr, + left->branch_info->from.sym); } if (!right->branch_info->srcline_from) { - struct map *map = right->branch_info->from.map; - if (!map) - right->branch_info->srcline_from = SRCLINE_UNKNOWN; - else - right->branch_info->srcline_from = get_srcline(map->dso, - map__rip_2objdump(map, - right->branch_info->from.al_addr), - right->branch_info->from.sym, - true, true, - right->branch_info->from.al_addr); + right->branch_info->srcline_from = map__srcline(right->branch_info->from.map, + right->branch_info->from.al_addr, + right->branch_info->from.sym); } return strcmp(right->branch_info->srcline_from, left->branch_info->srcline_from); } @@ -420,28 +400,14 @@ static int64_t sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right) { if (!left->branch_info->srcline_to) { - struct map *map = left->branch_info->to.map; - if (!map) - left->branch_info->srcline_to = SRCLINE_UNKNOWN; - else - left->branch_info->srcline_to = get_srcline(map->dso, - map__rip_2objdump(map, - left->branch_info->to.al_addr), - left->branch_info->from.sym, - true, true, - left->branch_info->to.al_addr); + left->branch_info->srcline_to = map__srcline(left->branch_info->to.map, + left->branch_info->to.al_addr, + left->branch_info->to.sym); } if (!right->branch_info->srcline_to) { - struct map *map = right->branch_info->to.map; - if (!map) - right->branch_info->srcline_to = SRCLINE_UNKNOWN; - else - right->branch_info->srcline_to = get_srcline(map->dso, - map__rip_2objdump(map, - right->branch_info->to.al_addr), - right->branch_info->to.sym, - true, true, - right->branch_info->to.al_addr); + right->branch_info->srcline_to = map__srcline(right->branch_info->to.map, + right->branch_info->to.al_addr, + right->branch_info->to.sym); } return strcmp(right->branch_info->srcline_to, left->branch_info->srcline_to); } -- cgit From bfa63519fb94fd8b4b0e5ffcd8bde650ea8b20c1 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 28 May 2018 11:11:47 -0300 Subject: perf sort: Introduce addr_map_symbol__srcline() to make code more compact Since we have 'struct addr_map_symbol' and the srcline sort order keys all operate on those, make the code more compact by introducing a function that receives a pointer to such struct and expands the arguments to map__srcline(). Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-j540wq7n3ukkh70gk5be0in5@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/sort.c | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 71096dbfeb88..4ab0b4ab24e4 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -365,19 +365,20 @@ struct sort_entry sort_srcline = { /* --sort srcline_from */ +static char *addr_map_symbol__srcline(struct addr_map_symbol *ams) +{ + return map__srcline(ams->map, ams->al_addr, ams->sym); +} + static int64_t sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right) { - if (!left->branch_info->srcline_from) { - left->branch_info->srcline_from = map__srcline(left->branch_info->from.map, - left->branch_info->from.al_addr, - left->branch_info->from.sym); - } - if (!right->branch_info->srcline_from) { - right->branch_info->srcline_from = map__srcline(right->branch_info->from.map, - right->branch_info->from.al_addr, - right->branch_info->from.sym); - } + if (!left->branch_info->srcline_from) + left->branch_info->srcline_from = addr_map_symbol__srcline(&left->branch_info->from); + + if (!right->branch_info->srcline_from) + right->branch_info->srcline_from = addr_map_symbol__srcline(&right->branch_info->from); + return strcmp(right->branch_info->srcline_from, left->branch_info->srcline_from); } @@ -399,16 +400,12 @@ struct sort_entry sort_srcline_from = { static int64_t sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right) { - if (!left->branch_info->srcline_to) { - left->branch_info->srcline_to = map__srcline(left->branch_info->to.map, - left->branch_info->to.al_addr, - left->branch_info->to.sym); - } - if (!right->branch_info->srcline_to) { - right->branch_info->srcline_to = map__srcline(right->branch_info->to.map, - right->branch_info->to.al_addr, - right->branch_info->to.sym); - } + if (!left->branch_info->srcline_to) + left->branch_info->srcline_to = addr_map_symbol__srcline(&left->branch_info->to); + + if (!right->branch_info->srcline_to) + right->branch_info->srcline_to = addr_map_symbol__srcline(&right->branch_info->to); + return strcmp(right->branch_info->srcline_to, left->branch_info->srcline_to); } -- cgit From 6a53da05c433284252c9363043bf3d8a5789cfca Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 28 May 2018 11:06:58 -0300 Subject: perf srcline: Make hist_entry srcline helper consistent with map's No need to have "get_srcline", plain hist_entry__srcline() is enough and shorter. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-irhzpfmgdaf6cyk0uqqexoh9@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-c2c.c | 2 +- tools/perf/util/sort.c | 8 ++++---- tools/perf/util/sort.h | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 2126bfbcb385..307b3594525f 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -1976,7 +1976,7 @@ static int filter_cb(struct hist_entry *he) c2c_he = container_of(he, struct c2c_hist_entry, he); if (c2c.show_src && !he->srcline) - he->srcline = hist_entry__get_srcline(he); + he->srcline = hist_entry__srcline(he); calc_width(c2c_he); diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 4ab0b4ab24e4..fed2952ab45a 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c @@ -331,7 +331,7 @@ struct sort_entry sort_sym = { /* --sort srcline */ -char *hist_entry__get_srcline(struct hist_entry *he) +char *hist_entry__srcline(struct hist_entry *he) { return map__srcline(he->ms.map, he->ip, he->ms.sym); } @@ -340,9 +340,9 @@ static int64_t sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right) { if (!left->srcline) - left->srcline = hist_entry__get_srcline(left); + left->srcline = hist_entry__srcline(left); if (!right->srcline) - right->srcline = hist_entry__get_srcline(right); + right->srcline = hist_entry__srcline(right); return strcmp(right->srcline, left->srcline); } @@ -351,7 +351,7 @@ static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width) { if (!he->srcline) - he->srcline = hist_entry__get_srcline(he); + he->srcline = hist_entry__srcline(he); return repsep_snprintf(bf, size, "%-.*s", width, he->srcline); } diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 9e6896293bbd..f007a26d6f6d 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -292,5 +292,5 @@ int64_t sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right); int64_t sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right); -char *hist_entry__get_srcline(struct hist_entry *he); +char *hist_entry__srcline(struct hist_entry *he); #endif /* __PERF_SORT_H */ -- cgit From 380195e2b07b123fb2cd701bd60e78a31fbf3b25 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 28 May 2018 11:27:40 -0300 Subject: perf annotate: Pass annotation_options to symbol__annotate() Now all callers to symbol__disassemble() can hand it the per-tool annotation_options, which will allow us to remove lots of stuff from symbol_options, the kitchen sink of perf configs, reducing its size and getting annotation specific stuff grouped together. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-vpr7ys7ggvs2fzpg8wbjcw7e@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-top.c | 2 +- tools/perf/ui/gtk/annotate.c | 2 +- tools/perf/util/annotate.c | 7 +++++-- tools/perf/util/annotate.h | 1 + 4 files changed, 8 insertions(+), 4 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 5e58cd4de90b..2c14ca61c657 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -133,7 +133,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) return err; } - err = symbol__annotate(sym, map, evsel, 0, NULL); + err = symbol__annotate(sym, map, evsel, 0, &top->annotation_opts, NULL); if (err == 0) { top->sym_filter_entry = he; } else { diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c index aeeaf15029f0..48428c9acd89 100644 --- a/tools/perf/ui/gtk/annotate.c +++ b/tools/perf/ui/gtk/annotate.c @@ -169,7 +169,7 @@ static int symbol__gtk_annotate(struct symbol *sym, struct map *map, if (map->dso->annotate_warned) return -1; - err = symbol__annotate(sym, map, evsel, 0, NULL); + err = symbol__annotate(sym, map, evsel, 0, &annotation__default_options, NULL); if (err) { char msg[BUFSIZ]; symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index abcc7e24c365..502f9d124a44 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -1067,6 +1067,7 @@ struct annotate_args { struct arch *arch; struct map_symbol ms; struct perf_evsel *evsel; + struct annotation_options *options; s64 offset; char *line; int line_nr; @@ -1803,11 +1804,13 @@ void symbol__calc_percent(struct symbol *sym, struct perf_evsel *evsel) int symbol__annotate(struct symbol *sym, struct map *map, struct perf_evsel *evsel, size_t privsize, + struct annotation_options *options, struct arch **parch) { struct annotate_args args = { .privsize = privsize, .evsel = evsel, + .options = options, }; struct perf_env *env = perf_evsel__env(evsel); const char *arch_name = perf_env__arch(env); @@ -2409,7 +2412,7 @@ int symbol__tty_annotate(struct symbol *sym, struct map *map, struct dso *dso = map->dso; struct rb_root source_line = RB_ROOT; - if (symbol__annotate(sym, map, evsel, 0, NULL) < 0) + if (symbol__annotate(sym, map, evsel, 0, opts, NULL) < 0) return -1; symbol__calc_percent(sym, evsel); @@ -2655,7 +2658,7 @@ int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *ev if (perf_evsel__is_group_event(evsel)) nr_pcnt = evsel->nr_members; - err = symbol__annotate(sym, map, evsel, 0, parch); + err = symbol__annotate(sym, map, evsel, 0, options, parch); if (err) goto out_free_offsets; diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 20f3326cc640..013d414b0e57 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -306,6 +306,7 @@ void symbol__annotate_zero_histograms(struct symbol *sym); int symbol__annotate(struct symbol *sym, struct map *map, struct perf_evsel *evsel, size_t privsize, + struct annotation_options *options, struct arch **parch); int symbol__annotate2(struct symbol *sym, struct map *map, struct perf_evsel *evsel, -- cgit From 1eddd9e4101d21709c453d80a42d2efc4277cb27 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 28 May 2018 11:42:59 -0300 Subject: perf annotate: Adopt anotation options from symbol_conf Continuing to group annotation options in an annotation specific struct. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-astei92tzxp4yccag5pxb2h7@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 4 ++-- tools/perf/builtin-report.c | 6 ++++-- tools/perf/builtin-top.c | 4 ++-- tools/perf/util/annotate.c | 6 ++++-- tools/perf/util/annotate.h | 4 +++- tools/perf/util/symbol.c | 1 - tools/perf/util/symbol.h | 2 -- 7 files changed, 15 insertions(+), 12 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 7238010f28d4..2ca7172f0780 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -515,9 +515,9 @@ int cmd_annotate(int argc, const char **argv) OPT_CALLBACK(0, "symfs", NULL, "directory", "Look for files with symbols relative to this directory", symbol__config_symfs), - OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, + OPT_BOOLEAN(0, "source", &annotate.opts.annotate_src, "Interleave source code with assembly code (default)"), - OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, + OPT_BOOLEAN(0, "asm-raw", &annotate.opts.show_asm_raw, "Display raw encoding of assembly instructions (default)"), OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", "Specify disassembler style (e.g. -M intel for intel syntax)"), diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 7a689c933f04..bee6dbfbf11e 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -71,6 +71,7 @@ struct report { bool group_set; int max_stack; struct perf_read_values show_threads_values; + struct annotation_options annotation_opts; const char *pretty_printing_style; const char *cpu_list; const char *symbol_filter_str; @@ -988,6 +989,7 @@ int cmd_report(int argc, const char **argv) .max_stack = PERF_MAX_STACK_DEPTH, .pretty_printing_style = "normal", .socket_filter = -1, + .annotation_opts = annotation__default_options, }; const struct option options[] = { OPT_STRING('i', "input", &input_name, "file", @@ -1077,9 +1079,9 @@ int cmd_report(int argc, const char **argv) "list of cpus to profile"), OPT_BOOLEAN('I', "show-info", &report.show_full_info, "Display extended information about perf.data file"), - OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, + OPT_BOOLEAN(0, "source", &report.annotation_opts.annotate_src, "Interleave source code with assembly code (default)"), - OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, + OPT_BOOLEAN(0, "asm-raw", &report.annotation_opts.show_asm_raw, "Display raw encoding of assembly instructions (default)"), OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", "Specify disassembler style (e.g. -M intel for intel syntax)"), diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 2c14ca61c657..e65e72c06a01 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1340,9 +1340,9 @@ int cmd_top(int argc, const char **argv) "only consider symbols in these comms"), OPT_STRING(0, "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", "only consider these symbols"), - OPT_BOOLEAN(0, "source", &symbol_conf.annotate_src, + OPT_BOOLEAN(0, "source", &top.annotation_opts.annotate_src, "Interleave source code with assembly code (default)"), - OPT_BOOLEAN(0, "asm-raw", &symbol_conf.annotate_asm_raw, + OPT_BOOLEAN(0, "asm-raw", &top.annotation_opts.show_asm_raw, "Display raw encoding of assembly instructions (default)"), OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, "Enable kernel symbol demangling"), diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 502f9d124a44..ff8f4f474b22 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -47,6 +47,7 @@ struct annotation_options annotation__default_options = { .use_offset = true, .jump_arrows = true, + .annotate_src = true, .offset_level = ANNOTATION__OFFSET_JUMP_TARGETS, }; @@ -1609,6 +1610,7 @@ fallback: static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) { + struct annotation_options *opts = args->options; struct map *map = args->ms.map; struct dso *dso = map->dso; char *command; @@ -1661,8 +1663,8 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) disassembler_style ? disassembler_style : "", map__rip_2objdump(map, sym->start), map__rip_2objdump(map, sym->end), - symbol_conf.annotate_asm_raw ? "" : "--no-show-raw", - symbol_conf.annotate_src ? "-S" : "", + opts->show_asm_raw ? "" : "--no-show-raw", + opts->annotate_src ? "-S" : "", symfs_filename, symfs_filename); if (err < 0) { diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 013d414b0e57..476ea2a25649 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -73,7 +73,9 @@ struct annotation_options { show_nr_jumps, show_nr_samples, show_total_period, - show_minmax_cycle; + show_minmax_cycle, + show_asm_raw, + annotate_src; u8 offset_level; int min_pcnt; int max_lines; diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 8c84437f2a10..3f632c60888f 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -40,7 +40,6 @@ char **vmlinux_path; struct symbol_conf symbol_conf = { .use_modules = true, .try_vmlinux_path = true, - .annotate_src = true, .demangle = true, .demangle_kernel = false, .cumulate_callchain = true, diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 1be9a6bad967..f25fae4b5743 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h @@ -108,8 +108,6 @@ struct symbol_conf { show_cpu_utilization, initialized, kptr_restrict, - annotate_asm_raw, - annotate_src, event_group, demangle, demangle_kernel, -- cgit From a47e843edca81058b9f4187b78f8b98320ebbd59 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 28 May 2018 11:50:21 -0300 Subject: perf annotate: Move disassembler_style global to annotation_options Continuing to group annotation specific stuff into a struct. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-p3cdhltj58jt0byjzg3g7obx@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 2 +- tools/perf/builtin-report.c | 2 +- tools/perf/builtin-top.c | 2 +- tools/perf/util/annotate.c | 5 ++--- tools/perf/util/annotate.h | 3 +-- 5 files changed, 6 insertions(+), 8 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 2ca7172f0780..3ee063598364 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -519,7 +519,7 @@ int cmd_annotate(int argc, const char **argv) "Interleave source code with assembly code (default)"), OPT_BOOLEAN(0, "asm-raw", &annotate.opts.show_asm_raw, "Display raw encoding of assembly instructions (default)"), - OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", + OPT_STRING('M', "disassembler-style", &annotate.opts.disassembler_style, "disassembler style", "Specify disassembler style (e.g. -M intel for intel syntax)"), OPT_STRING(0, "objdump", &objdump_path, "path", "objdump binary to use for disassembly and annotations"), diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index bee6dbfbf11e..c74f9a219ad1 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -1083,7 +1083,7 @@ int cmd_report(int argc, const char **argv) "Interleave source code with assembly code (default)"), OPT_BOOLEAN(0, "asm-raw", &report.annotation_opts.show_asm_raw, "Display raw encoding of assembly instructions (default)"), - OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", + OPT_STRING('M', "disassembler-style", &report.annotation_opts.disassembler_style, "disassembler style", "Specify disassembler style (e.g. -M intel for intel syntax)"), OPT_BOOLEAN(0, "show-total-period", &symbol_conf.show_total_period, "Show a column with the sum of periods"), diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index e65e72c06a01..739c158fb39e 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1348,7 +1348,7 @@ int cmd_top(int argc, const char **argv) "Enable kernel symbol demangling"), OPT_STRING(0, "objdump", &objdump_path, "path", "objdump binary to use for disassembly and annotations"), - OPT_STRING('M', "disassembler-style", &disassembler_style, "disassembler style", + OPT_STRING('M', "disassembler-style", &top.annotation_opts.disassembler_style, "disassembler style", "Specify disassembler style (e.g. -M intel for intel syntax)"), OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"), OPT_CALLBACK(0, "percent-limit", &top, "percent", diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index ff8f4f474b22..a90777717b60 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -51,7 +51,6 @@ struct annotation_options annotation__default_options = { .offset_level = ANNOTATION__OFFSET_JUMP_TARGETS, }; -const char *disassembler_style; const char *objdump_path; static regex_t file_lineno; @@ -1659,8 +1658,8 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) " --stop-address=0x%016" PRIx64 " -l -d %s %s -C \"%s\" 2>/dev/null|grep -v \"%s:\"|expand", objdump_path ? objdump_path : "objdump", - disassembler_style ? "-M " : "", - disassembler_style ? disassembler_style : "", + opts->disassembler_style ? "-M " : "", + opts->disassembler_style ?: "", map__rip_2objdump(map, sym->start), map__rip_2objdump(map, sym->end), opts->show_asm_raw ? "" : "--no-show-raw", diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 476ea2a25649..71a734b86873 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -80,6 +80,7 @@ struct annotation_options { int min_pcnt; int max_lines; int context; + const char *disassembler_style; }; enum { @@ -368,8 +369,6 @@ static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, } #endif -extern const char *disassembler_style; - void annotation_config__init(void); #endif /* __PERF_ANNOTATE_H */ -- cgit From cd0cccbae9f654479a1c5abcd876c7fc4356b882 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 28 May 2018 13:54:59 -0300 Subject: perf hists browser: Pass annotation_options from tool to browser So that things changed in the command line may percolate to the browser code without using globals. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-5daawc40zhl6gcs600com1ua@git.kernel.org [ Merged fix for NO_SLANG=1 build provided by Jiri Olsa ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 2 +- tools/perf/builtin-report.c | 2 +- tools/perf/builtin-top.c | 3 ++- tools/perf/ui/browsers/annotate.c | 19 ++++++++++++------- tools/perf/ui/browsers/hists.c | 29 ++++++++++++++++++++--------- tools/perf/ui/browsers/hists.h | 3 +++ tools/perf/util/annotate.h | 7 ++++--- tools/perf/util/hist.h | 20 ++++++++++++++------ 8 files changed, 57 insertions(+), 28 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 3ee063598364..2339ae719e1d 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -341,7 +341,7 @@ find_next: /* skip missing symbols */ nd = rb_next(nd); } else if (use_browser == 1) { - key = hist_entry__tui_annotate(he, evsel, NULL); + key = hist_entry__tui_annotate(he, evsel, NULL, &ann->opts); switch (key) { case -1: diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index c74f9a219ad1..14b516a3a0de 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -561,7 +561,7 @@ static int report__browse_hists(struct report *rep) ret = perf_evlist__tui_browse_hists(evlist, help, NULL, rep->min_percent, &session->header.env, - true); + true, &rep->annotation_opts); /* * Usually "ret" is the last pressed key, and we only * care if the key notifies us to switch data file. diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 739c158fb39e..bd60a631a481 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -606,7 +606,8 @@ static void *display_thread_tui(void *arg) perf_evlist__tui_browse_hists(top->evlist, help, &hbt, top->min_percent, &top->session->header.env, - !top->record_opts.overwrite); + !top->record_opts.overwrite, + &top->annotation_opts); done = 1; return NULL; diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 3bfe17e176fe..3b4f1c10ff57 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c @@ -29,6 +29,7 @@ struct annotate_browser { struct rb_node *curr_hot; struct annotation_line *selection; struct arch *arch; + struct annotation_options *opts; bool searching_backwards; char search_bf[128]; }; @@ -418,7 +419,7 @@ static bool annotate_browser__callq(struct annotate_browser *browser, } pthread_mutex_unlock(¬es->lock); - symbol__tui_annotate(dl->ops.target.sym, ms->map, evsel, hbt); + symbol__tui_annotate(dl->ops.target.sym, ms->map, evsel, hbt, browser->opts); sym_title(ms->sym, ms->map, title, sizeof(title)); ui_browser__show_title(&browser->b, title); return true; @@ -817,24 +818,27 @@ out: } int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel, - struct hist_browser_timer *hbt) + struct hist_browser_timer *hbt, + struct annotation_options *opts) { - return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt); + return symbol__tui_annotate(ms->sym, ms->map, evsel, hbt, opts); } int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, - struct hist_browser_timer *hbt) + struct hist_browser_timer *hbt, + struct annotation_options *opts) { /* reset abort key so that it can get Ctrl-C as a key */ SLang_reset_tty(); SLang_init_tty(0, 0, 0); - return map_symbol__tui_annotate(&he->ms, evsel, hbt); + return map_symbol__tui_annotate(&he->ms, evsel, hbt, opts); } int symbol__tui_annotate(struct symbol *sym, struct map *map, struct perf_evsel *evsel, - struct hist_browser_timer *hbt) + struct hist_browser_timer *hbt, + struct annotation_options *opts) { struct annotation *notes = symbol__annotation(sym); struct map_symbol ms = { @@ -851,6 +855,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, .priv = &ms, .use_navkeypressed = true, }, + .opts = opts, }; int ret = -1, err; @@ -860,7 +865,7 @@ int symbol__tui_annotate(struct symbol *sym, struct map *map, if (map->dso->annotate_warned) return -1; - err = symbol__annotate2(sym, map, evsel, &annotation__default_options, &browser.arch); + err = symbol__annotate2(sym, map, evsel, opts, &browser.arch); if (err) { char msg[BUFSIZ]; symbol__strerror_disassemble(sym, map, err, msg, sizeof(msg)); diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index e5f247247daa..3af1b74608ab 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -2175,7 +2175,8 @@ struct hist_browser *hist_browser__new(struct hists *hists) static struct hist_browser * perf_evsel_browser__new(struct perf_evsel *evsel, struct hist_browser_timer *hbt, - struct perf_env *env) + struct perf_env *env, + struct annotation_options *annotation_opts) { struct hist_browser *browser = hist_browser__new(evsel__hists(evsel)); @@ -2183,6 +2184,7 @@ perf_evsel_browser__new(struct perf_evsel *evsel, browser->hbt = hbt; browser->env = env; browser->title = hists_browser__scnprintf_title; + browser->annotation_opts = annotation_opts; } return browser; } @@ -2344,7 +2346,8 @@ do_annotate(struct hist_browser *browser, struct popup_action *act) return 0; evsel = hists_to_evsel(browser->hists); - err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt); + err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt, + browser->annotation_opts); he = hist_browser__selected_entry(browser); /* * offer option to annotate the other branch source or target @@ -2697,10 +2700,11 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, struct hist_browser_timer *hbt, float min_pcnt, struct perf_env *env, - bool warn_lost_event) + bool warn_lost_event, + struct annotation_options *annotation_opts) { struct hists *hists = evsel__hists(evsel); - struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env); + struct hist_browser *browser = perf_evsel_browser__new(evsel, hbt, env, annotation_opts); struct branch_info *bi; #define MAX_OPTIONS 16 char *options[MAX_OPTIONS]; @@ -3062,6 +3066,7 @@ out: struct perf_evsel_menu { struct ui_browser b; struct perf_evsel *selection; + struct annotation_options *annotation_opts; bool lost_events, lost_events_warned; float min_pcnt; struct perf_env *env; @@ -3163,7 +3168,8 @@ browse_hists: true, hbt, menu->min_pcnt, menu->env, - warn_lost_event); + warn_lost_event, + menu->annotation_opts); ui_browser__show_title(&menu->b, title); switch (key) { case K_TAB: @@ -3222,7 +3228,8 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, struct hist_browser_timer *hbt, float min_pcnt, struct perf_env *env, - bool warn_lost_event) + bool warn_lost_event, + struct annotation_options *annotation_opts) { struct perf_evsel *pos; struct perf_evsel_menu menu = { @@ -3237,6 +3244,7 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, }, .min_pcnt = min_pcnt, .env = env, + .annotation_opts = annotation_opts, }; ui_helpline__push("Press ESC to exit"); @@ -3257,7 +3265,8 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, struct hist_browser_timer *hbt, float min_pcnt, struct perf_env *env, - bool warn_lost_event) + bool warn_lost_event, + struct annotation_options *annotation_opts) { int nr_entries = evlist->nr_entries; @@ -3267,7 +3276,8 @@ single_entry: return perf_evsel__hists_browse(first, nr_entries, help, false, hbt, min_pcnt, - env, warn_lost_event); + env, warn_lost_event, + annotation_opts); } if (symbol_conf.event_group) { @@ -3285,5 +3295,6 @@ single_entry: return __perf_evlist__tui_browse_hists(evlist, nr_entries, help, hbt, min_pcnt, env, - warn_lost_event); + warn_lost_event, + annotation_opts); } diff --git a/tools/perf/ui/browsers/hists.h b/tools/perf/ui/browsers/hists.h index 9428bee076f2..91d3e18b50aa 100644 --- a/tools/perf/ui/browsers/hists.h +++ b/tools/perf/ui/browsers/hists.h @@ -4,6 +4,8 @@ #include "ui/browser.h" +struct annotation_options; + struct hist_browser { struct ui_browser b; struct hists *hists; @@ -12,6 +14,7 @@ struct hist_browser { struct hist_browser_timer *hbt; struct pstack *pstack; struct perf_env *env; + struct annotation_options *annotation_opts; int print_seq; bool show_dso; bool show_headers; diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 71a734b86873..6e6e2a571928 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -357,13 +357,14 @@ int symbol__tty_annotate2(struct symbol *sym, struct map *map, #ifdef HAVE_SLANG_SUPPORT int symbol__tui_annotate(struct symbol *sym, struct map *map, struct perf_evsel *evsel, - struct hist_browser_timer *hbt); + struct hist_browser_timer *hbt, + struct annotation_options *opts); #else static inline int symbol__tui_annotate(struct symbol *sym __maybe_unused, struct map *map __maybe_unused, struct perf_evsel *evsel __maybe_unused, - struct hist_browser_timer *hbt - __maybe_unused) + struct hist_browser_timer *hbt __maybe_unused, + struct annotation_options *opts __maybe_unused) { return 0; } diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index fbabfd8a215d..cafafbf2aa9f 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -419,19 +419,24 @@ struct hist_browser_timer { int refresh; }; +struct annotation_options; + #ifdef HAVE_SLANG_SUPPORT #include "../ui/keysyms.h" int map_symbol__tui_annotate(struct map_symbol *ms, struct perf_evsel *evsel, - struct hist_browser_timer *hbt); + struct hist_browser_timer *hbt, + struct annotation_options *annotation_opts); int hist_entry__tui_annotate(struct hist_entry *he, struct perf_evsel *evsel, - struct hist_browser_timer *hbt); + struct hist_browser_timer *hbt, + struct annotation_options *annotation_opts); int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, struct hist_browser_timer *hbt, float min_pcnt, struct perf_env *env, - bool warn_lost_event); + bool warn_lost_event, + struct annotation_options *annotation_options); int script_browse(const char *script_opt); #else static inline @@ -440,20 +445,23 @@ int perf_evlist__tui_browse_hists(struct perf_evlist *evlist __maybe_unused, struct hist_browser_timer *hbt __maybe_unused, float min_pcnt __maybe_unused, struct perf_env *env __maybe_unused, - bool warn_lost_event __maybe_unused) + bool warn_lost_event __maybe_unused, + struct annotation_options *annotation_options __maybe_unused) { return 0; } static inline int map_symbol__tui_annotate(struct map_symbol *ms __maybe_unused, struct perf_evsel *evsel __maybe_unused, - struct hist_browser_timer *hbt __maybe_unused) + struct hist_browser_timer *hbt __maybe_unused, + struct annotation_options *annotation_options __maybe_unused) { return 0; } static inline int hist_entry__tui_annotate(struct hist_entry *he __maybe_unused, struct perf_evsel *evsel __maybe_unused, - struct hist_browser_timer *hbt __maybe_unused) + struct hist_browser_timer *hbt __maybe_unused, + struct annotation_options *annotation_opts __maybe_unused) { return 0; } -- cgit From f178fd2d498eccbf6592ace72b9f235f0e58c77d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 28 May 2018 14:24:45 -0300 Subject: perf annotate: Move objdump_path to struct annotation_options One more step in grouping annotation options. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-sogzdhugoavm6fyw60jnb0vs@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/common.c | 4 ++-- tools/perf/arch/common.h | 4 +--- tools/perf/builtin-annotate.c | 7 ++++--- tools/perf/builtin-report.c | 2 +- tools/perf/builtin-top.c | 7 ++++--- tools/perf/ui/browsers/hists.c | 3 ++- tools/perf/util/annotate.c | 3 +-- tools/perf/util/annotate.h | 1 + 8 files changed, 16 insertions(+), 15 deletions(-) (limited to 'tools') diff --git a/tools/perf/arch/common.c b/tools/perf/arch/common.c index c6f373508a4f..82657c01a3b8 100644 --- a/tools/perf/arch/common.c +++ b/tools/perf/arch/common.c @@ -189,7 +189,7 @@ out_error: return -1; } -int perf_env__lookup_objdump(struct perf_env *env) +int perf_env__lookup_objdump(struct perf_env *env, const char **path) { /* * For live mode, env->arch will be NULL and we can use @@ -198,5 +198,5 @@ int perf_env__lookup_objdump(struct perf_env *env) if (env->arch == NULL) return 0; - return perf_env__lookup_binutils_path(env, "objdump", &objdump_path); + return perf_env__lookup_binutils_path(env, "objdump", path); } diff --git a/tools/perf/arch/common.h b/tools/perf/arch/common.h index 2d875baa92e6..2167001b18c5 100644 --- a/tools/perf/arch/common.h +++ b/tools/perf/arch/common.h @@ -4,8 +4,6 @@ #include "../util/env.h" -extern const char *objdump_path; - -int perf_env__lookup_objdump(struct perf_env *env); +int perf_env__lookup_objdump(struct perf_env *env, const char **path); #endif /* ARCH_PERF_COMMON_H */ diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 2339ae719e1d..5eb22cc56363 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -388,8 +388,9 @@ static int __cmd_annotate(struct perf_annotate *ann) goto out; } - if (!objdump_path) { - ret = perf_env__lookup_objdump(&session->header.env); + if (!ann->opts.objdump_path) { + ret = perf_env__lookup_objdump(&session->header.env, + &ann->opts.objdump_path); if (ret) goto out; } @@ -521,7 +522,7 @@ int cmd_annotate(int argc, const char **argv) "Display raw encoding of assembly instructions (default)"), OPT_STRING('M', "disassembler-style", &annotate.opts.disassembler_style, "disassembler style", "Specify disassembler style (e.g. -M intel for intel syntax)"), - OPT_STRING(0, "objdump", &objdump_path, "path", + OPT_STRING(0, "objdump", &annotate.opts.objdump_path, "path", "objdump binary to use for disassembly and annotations"), OPT_BOOLEAN(0, "group", &symbol_conf.event_group, "Show event group information together"), diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index 14b516a3a0de..bc133e7a7ac2 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -1094,7 +1094,7 @@ int cmd_report(int argc, const char **argv) parse_branch_mode), OPT_BOOLEAN(0, "branch-history", &branch_call_mode, "add last branch records to call history"), - OPT_STRING(0, "objdump", &objdump_path, "path", + OPT_STRING(0, "objdump", &report.annotation_opts.objdump_path, "path", "objdump binary to use for disassembly and annotations"), OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle, "Disable symbol demangling"), diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index bd60a631a481..ffdc2769ff9f 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -1077,8 +1077,9 @@ static int __cmd_top(struct perf_top *top) if (top->session == NULL) return -1; - if (!objdump_path) { - ret = perf_env__lookup_objdump(&top->session->header.env); + if (!top->annotation_opts.objdump_path) { + ret = perf_env__lookup_objdump(&top->session->header.env, + &top->annotation_opts.objdump_path); if (ret) goto out_delete; } @@ -1347,7 +1348,7 @@ int cmd_top(int argc, const char **argv) "Display raw encoding of assembly instructions (default)"), OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel, "Enable kernel symbol demangling"), - OPT_STRING(0, "objdump", &objdump_path, "path", + OPT_STRING(0, "objdump", &top.annotation_opts.objdump_path, "path", "objdump binary to use for disassembly and annotations"), OPT_STRING('M', "disassembler-style", &top.annotation_opts.disassembler_style, "disassembler style", "Specify disassembler style (e.g. -M intel for intel syntax)"), diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 3af1b74608ab..22054107f1af 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -2338,7 +2338,8 @@ do_annotate(struct hist_browser *browser, struct popup_action *act) struct hist_entry *he; int err; - if (!objdump_path && perf_env__lookup_objdump(browser->env)) + if (!browser->annotation_opts->objdump_path && + perf_env__lookup_objdump(browser->env, &browser->annotation_opts->objdump_path)) return 0; notes = symbol__annotation(act->ms.sym); diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index a90777717b60..2baa22933b0e 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -51,7 +51,6 @@ struct annotation_options annotation__default_options = { .offset_level = ANNOTATION__OFFSET_JUMP_TARGETS, }; -const char *objdump_path; static regex_t file_lineno; static struct ins_ops *ins__find(struct arch *arch, const char *name); @@ -1657,7 +1656,7 @@ static int symbol__disassemble(struct symbol *sym, struct annotate_args *args) "%s %s%s --start-address=0x%016" PRIx64 " --stop-address=0x%016" PRIx64 " -l -d %s %s -C \"%s\" 2>/dev/null|grep -v \"%s:\"|expand", - objdump_path ? objdump_path : "objdump", + opts->objdump_path ?: "objdump", opts->disassembler_style ? "-M " : "", opts->disassembler_style ?: "", map__rip_2objdump(map, sym->start), diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 6e6e2a571928..a4c0d91907e6 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h @@ -80,6 +80,7 @@ struct annotation_options { int min_pcnt; int max_lines; int context; + const char *objdump_path; const char *disassembler_style; }; -- cgit From e9ee0dce45e522221c18b2f24621a0d00d0bff40 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Mon, 28 May 2018 15:48:17 +0200 Subject: perf test: Use header file util/debug.h Use the header file util/debug.h instead of declaration of verbose variable. Signed-off-by: Thomas Richter Cc: Heiko Carstens Cc: Hendrik Brueckner Cc: Martin Schwidefsky Link: http://lkml.kernel.org/r/20180528134817.36643-1-tmricht@linux.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/python-use.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/perf/tests/python-use.c b/tools/perf/tests/python-use.c index 5d2df65ada6a..40ab72149ce1 100644 --- a/tools/perf/tests/python-use.c +++ b/tools/perf/tests/python-use.c @@ -7,8 +7,7 @@ #include #include #include "tests.h" - -extern int verbose; +#include "util/debug.h" int test__python_use(struct test *test __maybe_unused, int subtest __maybe_unused) { -- cgit From 9d0199cd2a7a326510fc7f731d7974ef2fbc03d0 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 28 May 2018 14:34:40 -0300 Subject: perf report: No need to have report_callchain_help as a global It is used in a single place, move the declaration to that function. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-p650ofrl8xike4dewxod51gg@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-report.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index bc133e7a7ac2..cdb5b6949832 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -946,12 +946,6 @@ parse_percent_limit(const struct option *opt, const char *str, return 0; } -#define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function,percent" - -const char report_callchain_help[] = "Display call graph (stack chain/backtrace):\n\n" - CALLCHAIN_REPORT_HELP - "\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT; - int cmd_report(int argc, const char **argv) { struct perf_session *session; @@ -960,6 +954,10 @@ int cmd_report(int argc, const char **argv) bool has_br_stack = false; int branch_mode = -1; bool branch_call_mode = false; +#define CALLCHAIN_DEFAULT_OPT "graph,0.5,caller,function,percent" + const char report_callchain_help[] = "Display call graph (stack chain/backtrace):\n\n" + CALLCHAIN_REPORT_HELP + "\n\t\t\t\tDefault: " CALLCHAIN_DEFAULT_OPT; char callchain_default_opt[] = CALLCHAIN_DEFAULT_OPT; const char * const report_usage[] = { "perf report []", -- cgit From 27de9b2bd996de0ca4079c42c81c85158e10145c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 28 May 2018 16:00:29 -0300 Subject: perf evsel: Add has_callchain() helper to make code more compact/clear Its common to have the (evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN), so add an evsel__has_callchain(evsel) helper. This will actually get more uses as we check that instead of symbol_conf.use_callchain in places where that produces the same result but makes this decision to be more fine grained, per evsel. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-145340oytbthatpfeaq1do18@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-sched.c | 3 +-- tools/perf/builtin-script.c | 10 +++------- tools/perf/builtin-trace.c | 2 +- tools/perf/tests/parse-events.c | 4 ++-- tools/perf/util/evsel.c | 4 ++-- tools/perf/util/evsel.h | 5 +++++ tools/perf/util/hist.c | 2 +- tools/perf/util/session.c | 2 +- 8 files changed, 16 insertions(+), 16 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 4dfdee668b0c..97f9e755e8e6 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -2933,8 +2933,7 @@ static int timehist_check_attr(struct perf_sched *sched, return -1; } - if (sched->show_callchain && - !(evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN)) { + if (sched->show_callchain && !evsel__has_callchain(evsel)) { pr_info("Samples do not have callchains.\n"); sched->show_callchain = 0; symbol_conf.use_callchain = 0; diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index cefc8813e91e..48e940efb3cb 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -517,7 +517,7 @@ static int perf_session__check_output_opt(struct perf_session *session) evlist__for_each_entry(session->evlist, evsel) { not_pipe = true; - if (evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) { + if (evsel__has_callchain(evsel)) { use_callchain = true; break; } @@ -532,22 +532,18 @@ static int perf_session__check_output_opt(struct perf_session *session) */ if (symbol_conf.use_callchain && !output[PERF_TYPE_TRACEPOINT].user_set) { - struct perf_event_attr *attr; - j = PERF_TYPE_TRACEPOINT; evlist__for_each_entry(session->evlist, evsel) { if (evsel->attr.type != j) continue; - attr = &evsel->attr; - - if (attr->sample_type & PERF_SAMPLE_CALLCHAIN) { + if (evsel__has_callchain(evsel)) { output[j].fields |= PERF_OUTPUT_IP; output[j].fields |= PERF_OUTPUT_SYM; output[j].fields |= PERF_OUTPUT_SYMOFFSET; output[j].fields |= PERF_OUTPUT_DSO; - set_print_ip_opts(attr); + set_print_ip_opts(&evsel->attr); goto out; } } diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c index 560aed7da36a..6a748eca2edb 100644 --- a/tools/perf/builtin-trace.c +++ b/tools/perf/builtin-trace.c @@ -2491,7 +2491,7 @@ static int trace__run(struct trace *trace, int argc, const char **argv) * to override an explicitely set --max-stack global setting. */ evlist__for_each_entry(evlist, evsel) { - if ((evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) && + if (evsel__has_callchain(evsel) && evsel->attr.sample_max_stack == 0) evsel->attr.sample_max_stack = trace->max_stack; } diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index b9ebe15afb13..7d4077068454 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -499,7 +499,7 @@ static int test__checkevent_pmu_partial_time_callgraph(struct perf_evlist *evlis * while this test executes only parse events method. */ TEST_ASSERT_VAL("wrong period", 0 == evsel->attr.sample_period); - TEST_ASSERT_VAL("wrong callgraph", !(PERF_SAMPLE_CALLCHAIN & evsel->attr.sample_type)); + TEST_ASSERT_VAL("wrong callgraph", !evsel__has_callchain(evsel)); TEST_ASSERT_VAL("wrong time", !(PERF_SAMPLE_TIME & evsel->attr.sample_type)); /* cpu/config=2,call-graph=no,time=0,period=2000/ */ @@ -512,7 +512,7 @@ static int test__checkevent_pmu_partial_time_callgraph(struct perf_evlist *evlis * while this test executes only parse events method. */ TEST_ASSERT_VAL("wrong period", 0 == evsel->attr.sample_period); - TEST_ASSERT_VAL("wrong callgraph", !(PERF_SAMPLE_CALLCHAIN & evsel->attr.sample_type)); + TEST_ASSERT_VAL("wrong callgraph", !evsel__has_callchain(evsel)); TEST_ASSERT_VAL("wrong time", !(PERF_SAMPLE_TIME & evsel->attr.sample_type)); return 0; diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index 150db5ed7400..94fce4f537e9 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c @@ -2197,7 +2197,7 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event, } } - if (type & PERF_SAMPLE_CALLCHAIN) { + if (evsel__has_callchain(evsel)) { const u64 max_callchain_nr = UINT64_MAX / sizeof(u64); OVERFLOW_CHECK_u64(array); @@ -2857,7 +2857,7 @@ int perf_evsel__open_strerror(struct perf_evsel *evsel, struct target *target, "Hint: Try again after reducing the number of events.\n" "Hint: Try increasing the limit with 'ulimit -n '"); case ENOMEM: - if ((evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) != 0 && + if (evsel__has_callchain(evsel) && access("/proc/sys/kernel/perf_event_max_stack", F_OK) == 0) return scnprintf(msg, size, "Not enough memory to setup event with callchain.\n" diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h index b13f5f234c8f..d277930b19a1 100644 --- a/tools/perf/util/evsel.h +++ b/tools/perf/util/evsel.h @@ -459,6 +459,11 @@ static inline bool perf_evsel__has_branch_callstack(const struct perf_evsel *evs return evsel->attr.branch_sample_type & PERF_SAMPLE_BRANCH_CALL_STACK; } +static inline bool evsel__has_callchain(const struct perf_evsel *evsel) +{ + return (evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN) != 0; +} + typedef int (*attr__fprintf_f)(FILE *, const char *, const char *, void *); int perf_event_attr__fprintf(FILE *fp, struct perf_event_attr *attr, diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 95333b068109..34864c87cd3c 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -1757,7 +1757,7 @@ void perf_evsel__output_resort(struct perf_evsel *evsel, struct ui_progress *pro bool use_callchain; if (evsel && symbol_conf.use_callchain && !symbol_conf.show_ref_callgraph) - use_callchain = evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN; + use_callchain = evsel__has_callchain(evsel); else use_callchain = symbol_conf.use_callchain; diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index b998bb475589..8b9369303561 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c @@ -1094,7 +1094,7 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event, sample_type = evsel->attr.sample_type; - if (sample_type & PERF_SAMPLE_CALLCHAIN) + if (evsel__has_callchain(evsel)) callchain__printf(evsel, sample); if ((sample_type & PERF_SAMPLE_BRANCH_STACK) && !perf_evsel__has_branch_callstack(evsel)) -- cgit From b879833cbaac85b1437f574791b8855d26b0dc80 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 4 Jun 2018 10:34:20 -0300 Subject: perf script: Check if evsel has callchains before trying to use it We were checking just if callchain processing was asked for by the user, not if the evsel itself has callchains, and since we can have some evsels with callchains and others without, check that. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-inxl7k49q9f9w1se039fbxuw@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index 48e940efb3cb..b3bf35512d21 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -606,7 +606,7 @@ static int perf_sample__fprintf_start(struct perf_sample *sample, if (PRINT_FIELD(COMM)) { if (latency_format) printed += fprintf(fp, "%8.8s ", thread__comm_str(thread)); - else if (PRINT_FIELD(IP) && symbol_conf.use_callchain) + else if (PRINT_FIELD(IP) && evsel__has_callchain(evsel) && symbol_conf.use_callchain) printed += fprintf(fp, "%s ", thread__comm_str(thread)); else printed += fprintf(fp, "%16s ", thread__comm_str(thread)); -- cgit From 4c50563d818622bb0f99b378b4e6683f189b39fb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 28 May 2018 16:07:56 -0300 Subject: perf sched: Use sched->show_callchain where appropriate Instead of using symbol_conf.use_callchain, reducing its usage a bit more. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-edgwb1b2mpbrdeg0w64wp7ms@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-sched.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index 97f9e755e8e6..cbf39dab19c1 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c @@ -2143,7 +2143,7 @@ static void save_task_callchain(struct perf_sched *sched, return; } - if (!symbol_conf.use_callchain || sample->callchain == NULL) + if (!sched->show_callchain || sample->callchain == NULL) return; if (thread__resolve_callchain(thread, cursor, evsel, sample, @@ -2271,10 +2271,11 @@ static struct thread *get_idle_thread(int cpu) return idle_threads[cpu]; } -static void save_idle_callchain(struct idle_thread_runtime *itr, +static void save_idle_callchain(struct perf_sched *sched, + struct idle_thread_runtime *itr, struct perf_sample *sample) { - if (!symbol_conf.use_callchain || sample->callchain == NULL) + if (!sched->show_callchain || sample->callchain == NULL) return; callchain_cursor__copy(&itr->cursor, &callchain_cursor); @@ -2320,7 +2321,7 @@ static struct thread *timehist_get_thread(struct perf_sched *sched, /* copy task callchain when entering to idle */ if (perf_evsel__intval(evsel, sample, "next_pid") == 0) - save_idle_callchain(itr, sample); + save_idle_callchain(sched, itr, sample); } } @@ -2849,7 +2850,7 @@ static void timehist_print_summary(struct perf_sched *sched, printf(" CPU %2d idle entire time window\n", i); } - if (sched->idle_hist && symbol_conf.use_callchain) { + if (sched->idle_hist && sched->show_callchain) { callchain_param.mode = CHAIN_FOLDED; callchain_param.value = CCVAL_PERIOD; -- cgit From 3c545084130c1fd5cf873a5fec3ee29070128e06 Mon Sep 17 00:00:00 2001 From: Tom Hromatka Date: Thu, 26 Apr 2018 10:54:09 -0600 Subject: selftests: sparc64: char: Selftest for privileged ADI driver Add a selftest for the sparc64 privileged ADI driver. These tests verify the read(), pread(), write(), pwrite(), and seek() functionality of the driver. The tests also report simple performance statistics: Syscall Call AvgTime AvgSize Count (ticks) (bytes) ------------------------------- read 3 119638 8133 pread 4 118164 6741 write 3 339442 8133 pwrite 4 280134 6741 seek 10 2919 0 Pass 8 Fail 0 Xfail 0 Xpass 0 Skip 0 Error 0 Signed-off-by: Tom Hromatka Reviewed-by: Allen Pais Reviewed-by: Shuah Khan (Samsung OSG) Signed-off-by: David S. Miller --- tools/testing/selftests/Makefile | 1 + tools/testing/selftests/sparc64/Makefile | 46 ++ tools/testing/selftests/sparc64/drivers/.gitignore | 1 + tools/testing/selftests/sparc64/drivers/Makefile | 15 + tools/testing/selftests/sparc64/drivers/adi-test.c | 721 +++++++++++++++++++++ .../selftests/sparc64/drivers/drivers_test.sh | 30 + tools/testing/selftests/sparc64/run.sh | 3 + 7 files changed, 817 insertions(+) create mode 100644 tools/testing/selftests/sparc64/Makefile create mode 100644 tools/testing/selftests/sparc64/drivers/.gitignore create mode 100644 tools/testing/selftests/sparc64/drivers/Makefile create mode 100644 tools/testing/selftests/sparc64/drivers/adi-test.c create mode 100755 tools/testing/selftests/sparc64/drivers/drivers_test.sh create mode 100755 tools/testing/selftests/sparc64/run.sh (limited to 'tools') diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 32aafa92074c..3e3984344ce5 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -31,6 +31,7 @@ TARGETS += ptrace TARGETS += seccomp TARGETS += sigaltstack TARGETS += size +TARGETS += sparc64 TARGETS += splice TARGETS += static_keys TARGETS += sync diff --git a/tools/testing/selftests/sparc64/Makefile b/tools/testing/selftests/sparc64/Makefile new file mode 100644 index 000000000000..2082eeffd779 --- /dev/null +++ b/tools/testing/selftests/sparc64/Makefile @@ -0,0 +1,46 @@ +SUBDIRS := drivers + +TEST_PROGS := run.sh + +.PHONY: all clean + +include ../lib.mk + +all: + @for DIR in $(SUBDIRS); do \ + BUILD_TARGET=$(OUTPUT)/$$DIR; \ + mkdir $$BUILD_TARGET -p; \ + make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\ + #SUBDIR test prog name should be in the form: SUBDIR_test.sh \ + TEST=$$DIR"_test.sh"; \ + if [ -e $$DIR/$$TEST ]; then \ + rsync -a $$DIR/$$TEST $$BUILD_TARGET/; \ + fi \ + done + +override define RUN_TESTS + @cd $(OUTPUT); ./run.sh +endef + +override define INSTALL_RULE + mkdir -p $(INSTALL_PATH) + install -t $(INSTALL_PATH) $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) + + @for SUBDIR in $(SUBDIRS); do \ + BUILD_TARGET=$(OUTPUT)/$$SUBDIR; \ + mkdir $$BUILD_TARGET -p; \ + $(MAKE) OUTPUT=$$BUILD_TARGET -C $$SUBDIR INSTALL_PATH=$(INSTALL_PATH)/$$SUBDIR install; \ + done; +endef + +override define EMIT_TESTS + echo "./run.sh" +endef + +override define CLEAN + @for DIR in $(SUBDIRS); do \ + BUILD_TARGET=$(OUTPUT)/$$DIR; \ + mkdir $$BUILD_TARGET -p; \ + make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\ + done +endef diff --git a/tools/testing/selftests/sparc64/drivers/.gitignore b/tools/testing/selftests/sparc64/drivers/.gitignore new file mode 100644 index 000000000000..90e835ed74e6 --- /dev/null +++ b/tools/testing/selftests/sparc64/drivers/.gitignore @@ -0,0 +1 @@ +adi-test diff --git a/tools/testing/selftests/sparc64/drivers/Makefile b/tools/testing/selftests/sparc64/drivers/Makefile new file mode 100644 index 000000000000..6264f40bbdbc --- /dev/null +++ b/tools/testing/selftests/sparc64/drivers/Makefile @@ -0,0 +1,15 @@ + +INCLUDEDIR := -I. +CFLAGS := $(CFLAGS) $(INCLUDEDIR) -Wall -O2 -g + +TEST_GEN_FILES := adi-test + +all: $(TEST_GEN_FILES) + +$(TEST_GEN_FILES): adi-test.c + +TEST_PROGS := drivers_test.sh + +include ../../lib.mk + +$(OUTPUT)/adi-test: adi-test.c diff --git a/tools/testing/selftests/sparc64/drivers/adi-test.c b/tools/testing/selftests/sparc64/drivers/adi-test.c new file mode 100644 index 000000000000..95d93c6a88a5 --- /dev/null +++ b/tools/testing/selftests/sparc64/drivers/adi-test.c @@ -0,0 +1,721 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * selftest for sparc64's privileged ADI driver + * + * Author: Tom Hromatka + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../kselftest.h" + +#define DEBUG_LEVEL_1_BIT (0x0001) +#define DEBUG_LEVEL_2_BIT (0x0002) +#define DEBUG_LEVEL_3_BIT (0x0004) +#define DEBUG_LEVEL_4_BIT (0x0008) +#define DEBUG_TIMING_BIT (0x1000) + +#ifndef ARRAY_SIZE +# define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) +#endif + +/* bit mask of enabled bits to print */ +#define DEBUG 0x0001 + +#define DEBUG_PRINT_L1(...) debug_print(DEBUG_LEVEL_1_BIT, __VA_ARGS__) +#define DEBUG_PRINT_L2(...) debug_print(DEBUG_LEVEL_2_BIT, __VA_ARGS__) +#define DEBUG_PRINT_L3(...) debug_print(DEBUG_LEVEL_3_BIT, __VA_ARGS__) +#define DEBUG_PRINT_L4(...) debug_print(DEBUG_LEVEL_4_BIT, __VA_ARGS__) +#define DEBUG_PRINT_T(...) debug_print(DEBUG_TIMING_BIT, __VA_ARGS__) + +static void debug_print(int level, const char *s, ...) +{ + va_list args; + + va_start(args, s); + + if (DEBUG & level) + vfprintf(stdout, s, args); + va_end(args); +} + +#ifndef min +#define min(x, y) ((x) < (y) ? x : y) +#endif + +#define RETURN_FROM_TEST(_ret) \ + do { \ + DEBUG_PRINT_L1( \ + "\tTest %s returned %d\n", __func__, _ret); \ + return _ret; \ + } while (0) + +#define ADI_BLKSZ 64 +#define ADI_MAX_VERSION 15 + +#define TEST_STEP_FAILURE(_ret) \ + do { \ + fprintf(stderr, "\tTest step failure: %d at %s:%d\n", \ + _ret, __func__, __LINE__); \ + goto out; \ + } while (0) + +#define RDTICK(_x) \ + asm volatile(" rd %%tick, %0\n" : "=r" (_x)) + +static int random_version(void) +{ + long tick; + + RDTICK(tick); + + return tick % (ADI_MAX_VERSION + 1); +} + +#define MAX_RANGES_SUPPORTED 5 +static const char system_ram_str[] = "System RAM\n"; +static int range_count; +static unsigned long long int start_addr[MAX_RANGES_SUPPORTED]; +static unsigned long long int end_addr[MAX_RANGES_SUPPORTED]; + +struct stats { + char name[16]; + unsigned long total; + unsigned long count; + unsigned long bytes; +}; + +static struct stats read_stats = { + .name = "read", .total = 0, .count = 0, .bytes = 0}; +static struct stats pread_stats = { + .name = "pread", .total = 0, .count = 0, .bytes = 0}; +static struct stats write_stats = { + .name = "write", .total = 0, .count = 0, .bytes = 0}; +static struct stats pwrite_stats = { + .name = "pwrite", .total = 0, .count = 0, .bytes = 0}; +static struct stats seek_stats = { + .name = "seek", .total = 0, .count = 0, .bytes = 0}; + +static void update_stats(struct stats * const ustats, + unsigned long measurement, unsigned long bytes) +{ + ustats->total += measurement; + ustats->bytes += bytes; + ustats->count++; +} + +static void print_ustats(const struct stats * const ustats) +{ + DEBUG_PRINT_L1("%s\t%7d\t%7.0f\t%7.0f\n", + ustats->name, ustats->count, + (float)ustats->total / (float)ustats->count, + (float)ustats->bytes / (float)ustats->count); +} + +static void print_stats(void) +{ + DEBUG_PRINT_L1("\nSyscall\tCall\tAvgTime\tAvgSize\n" + "\tCount\t(ticks)\t(bytes)\n" + "-------------------------------\n"); + + print_ustats(&read_stats); + print_ustats(&pread_stats); + print_ustats(&write_stats); + print_ustats(&pwrite_stats); + print_ustats(&seek_stats); +} + +static int build_memory_map(void) +{ + char line[256]; + FILE *fp; + int i; + + range_count = 0; + + fp = fopen("/proc/iomem", "r"); + if (!fp) { + fprintf(stderr, "/proc/iomem: error %d: %s\n", + errno, strerror(errno)); + return -errno; + } + + while (fgets(line, sizeof(line), fp) != 0) { + if (strstr(line, system_ram_str)) { + char *dash, *end_ptr; + + /* Given a line like this: + * d0400000-10ffaffff : System RAM + * replace the "-" with a space + */ + dash = strstr(line, "-"); + dash[0] = 0x20; + + start_addr[range_count] = strtoull(line, &end_ptr, 16); + end_addr[range_count] = strtoull(end_ptr, NULL, 16); + range_count++; + } + } + + fclose(fp); + + DEBUG_PRINT_L1("RAM Ranges\n"); + for (i = 0; i < range_count; i++) + DEBUG_PRINT_L1("\trange %d: 0x%llx\t- 0x%llx\n", + i, start_addr[i], end_addr[i]); + + if (range_count == 0) { + fprintf(stderr, "No valid address ranges found. Error.\n"); + return -1; + } + + return 0; +} + +static int read_adi(int fd, unsigned char *buf, int buf_sz) +{ + int ret, bytes_read = 0; + long start, end, elapsed_time = 0; + + do { + RDTICK(start); + ret = read(fd, buf + bytes_read, buf_sz - bytes_read); + RDTICK(end); + if (ret < 0) + return -errno; + + elapsed_time += end - start; + update_stats(&read_stats, elapsed_time, buf_sz); + bytes_read += ret; + + } while (bytes_read < buf_sz); + + DEBUG_PRINT_T("\tread elapsed timed = %ld\n", elapsed_time); + DEBUG_PRINT_L3("\tRead %d bytes\n", bytes_read); + + return bytes_read; +} + +static int pread_adi(int fd, unsigned char *buf, + int buf_sz, unsigned long offset) +{ + int ret, i, bytes_read = 0; + unsigned long cur_offset; + long start, end, elapsed_time = 0; + + cur_offset = offset; + do { + RDTICK(start); + ret = pread(fd, buf + bytes_read, buf_sz - bytes_read, + cur_offset); + RDTICK(end); + if (ret < 0) + return -errno; + + elapsed_time += end - start; + update_stats(&pread_stats, elapsed_time, buf_sz); + bytes_read += ret; + cur_offset += ret; + + } while (bytes_read < buf_sz); + + DEBUG_PRINT_T("\tpread elapsed timed = %ld\n", elapsed_time); + DEBUG_PRINT_L3("\tRead %d bytes starting at offset 0x%lx\n", + bytes_read, offset); + for (i = 0; i < bytes_read; i++) + DEBUG_PRINT_L4("\t\t0x%lx\t%d\n", offset + i, buf[i]); + + return bytes_read; +} + +static int write_adi(int fd, const unsigned char * const buf, int buf_sz) +{ + int ret, bytes_written = 0; + long start, end, elapsed_time = 0; + + do { + RDTICK(start); + ret = write(fd, buf + bytes_written, buf_sz - bytes_written); + RDTICK(end); + if (ret < 0) + return -errno; + + elapsed_time += (end - start); + update_stats(&write_stats, elapsed_time, buf_sz); + bytes_written += ret; + } while (bytes_written < buf_sz); + + DEBUG_PRINT_T("\twrite elapsed timed = %ld\n", elapsed_time); + DEBUG_PRINT_L3("\tWrote %d of %d bytes\n", bytes_written, buf_sz); + + return bytes_written; +} + +static int pwrite_adi(int fd, const unsigned char * const buf, + int buf_sz, unsigned long offset) +{ + int ret, bytes_written = 0; + unsigned long cur_offset; + long start, end, elapsed_time = 0; + + cur_offset = offset; + + do { + RDTICK(start); + ret = pwrite(fd, buf + bytes_written, + buf_sz - bytes_written, cur_offset); + RDTICK(end); + if (ret < 0) { + fprintf(stderr, "pwrite(): error %d: %s\n", + errno, strerror(errno)); + return -errno; + } + + elapsed_time += (end - start); + update_stats(&pwrite_stats, elapsed_time, buf_sz); + bytes_written += ret; + cur_offset += ret; + + } while (bytes_written < buf_sz); + + DEBUG_PRINT_T("\tpwrite elapsed timed = %ld\n", elapsed_time); + DEBUG_PRINT_L3("\tWrote %d of %d bytes starting at address 0x%lx\n", + bytes_written, buf_sz, offset); + + return bytes_written; +} + +static off_t seek_adi(int fd, off_t offset, int whence) +{ + long start, end; + off_t ret; + + RDTICK(start); + ret = lseek(fd, offset, whence); + RDTICK(end); + DEBUG_PRINT_L2("\tlseek ret = 0x%llx\n", ret); + if (ret < 0) + goto out; + + DEBUG_PRINT_T("\tlseek elapsed timed = %ld\n", end - start); + update_stats(&seek_stats, end - start, 0); + +out: + (void)lseek(fd, 0, SEEK_END); + return ret; +} + +static int test0_prpw_aligned_1byte(int fd) +{ + /* somewhat arbitrarily chosen address */ + unsigned long paddr = + (end_addr[range_count - 1] - 0x1000) & ~(ADI_BLKSZ - 1); + unsigned char version[1], expected_version; + loff_t offset; + int ret; + + version[0] = random_version(); + expected_version = version[0]; + + offset = paddr / ADI_BLKSZ; + + ret = pwrite_adi(fd, version, sizeof(version), offset); + if (ret != sizeof(version)) + TEST_STEP_FAILURE(ret); + + ret = pread_adi(fd, version, sizeof(version), offset); + if (ret != sizeof(version)) + TEST_STEP_FAILURE(ret); + + if (expected_version != version[0]) { + DEBUG_PRINT_L2("\tExpected version %d but read version %d\n", + expected_version, version[0]); + TEST_STEP_FAILURE(-expected_version); + } + + ret = 0; +out: + RETURN_FROM_TEST(ret); +} + +#define TEST1_VERSION_SZ 4096 +static int test1_prpw_aligned_4096bytes(int fd) +{ + /* somewhat arbitrarily chosen address */ + unsigned long paddr = + (end_addr[range_count - 1] - 0x6000) & ~(ADI_BLKSZ - 1); + unsigned char version[TEST1_VERSION_SZ], + expected_version[TEST1_VERSION_SZ]; + loff_t offset; + int ret, i; + + for (i = 0; i < TEST1_VERSION_SZ; i++) { + version[i] = random_version(); + expected_version[i] = version[i]; + } + + offset = paddr / ADI_BLKSZ; + + ret = pwrite_adi(fd, version, sizeof(version), offset); + if (ret != sizeof(version)) + TEST_STEP_FAILURE(ret); + + ret = pread_adi(fd, version, sizeof(version), offset); + if (ret != sizeof(version)) + TEST_STEP_FAILURE(ret); + + for (i = 0; i < TEST1_VERSION_SZ; i++) { + if (expected_version[i] != version[i]) { + DEBUG_PRINT_L2( + "\tExpected version %d but read version %d\n", + expected_version, version[0]); + TEST_STEP_FAILURE(-expected_version[i]); + } + } + + ret = 0; +out: + RETURN_FROM_TEST(ret); +} + +#define TEST2_VERSION_SZ 10327 +static int test2_prpw_aligned_10327bytes(int fd) +{ + /* somewhat arbitrarily chosen address */ + unsigned long paddr = + (start_addr[0] + 0x6000) & ~(ADI_BLKSZ - 1); + unsigned char version[TEST2_VERSION_SZ], + expected_version[TEST2_VERSION_SZ]; + loff_t offset; + int ret, i; + + for (i = 0; i < TEST2_VERSION_SZ; i++) { + version[i] = random_version(); + expected_version[i] = version[i]; + } + + offset = paddr / ADI_BLKSZ; + + ret = pwrite_adi(fd, version, sizeof(version), offset); + if (ret != sizeof(version)) + TEST_STEP_FAILURE(ret); + + ret = pread_adi(fd, version, sizeof(version), offset); + if (ret != sizeof(version)) + TEST_STEP_FAILURE(ret); + + for (i = 0; i < TEST2_VERSION_SZ; i++) { + if (expected_version[i] != version[i]) { + DEBUG_PRINT_L2( + "\tExpected version %d but read version %d\n", + expected_version, version[0]); + TEST_STEP_FAILURE(-expected_version[i]); + } + } + + ret = 0; +out: + RETURN_FROM_TEST(ret); +} + +#define TEST3_VERSION_SZ 12541 +static int test3_prpw_unaligned_12541bytes(int fd) +{ + /* somewhat arbitrarily chosen address */ + unsigned long paddr = + ((start_addr[0] + 0xC000) & ~(ADI_BLKSZ - 1)) + 17; + unsigned char version[TEST3_VERSION_SZ], + expected_version[TEST3_VERSION_SZ]; + loff_t offset; + int ret, i; + + for (i = 0; i < TEST3_VERSION_SZ; i++) { + version[i] = random_version(); + expected_version[i] = version[i]; + } + + offset = paddr / ADI_BLKSZ; + + ret = pwrite_adi(fd, version, sizeof(version), offset); + if (ret != sizeof(version)) + TEST_STEP_FAILURE(ret); + + ret = pread_adi(fd, version, sizeof(version), offset); + if (ret != sizeof(version)) + TEST_STEP_FAILURE(ret); + + for (i = 0; i < TEST3_VERSION_SZ; i++) { + if (expected_version[i] != version[i]) { + DEBUG_PRINT_L2( + "\tExpected version %d but read version %d\n", + expected_version, version[0]); + TEST_STEP_FAILURE(-expected_version[i]); + } + } + + ret = 0; +out: + RETURN_FROM_TEST(ret); +} + +static int test4_lseek(int fd) +{ +#define OFFSET_ADD (0x100) +#define OFFSET_SUBTRACT (0xFFFFFFF000000000) + + off_t offset_out, offset_in; + int ret; + + + offset_in = 0x123456789abcdef0; + offset_out = seek_adi(fd, offset_in, SEEK_SET); + if (offset_out != offset_in) { + ret = -1; + TEST_STEP_FAILURE(ret); + } + + /* seek to the current offset. this should return EINVAL */ + offset_out = seek_adi(fd, offset_in, SEEK_SET); + if (offset_out < 0 && errno == EINVAL) + DEBUG_PRINT_L2( + "\tSEEK_SET failed as designed. Not an error\n"); + else { + ret = -2; + TEST_STEP_FAILURE(ret); + } + + offset_out = seek_adi(fd, 0, SEEK_CUR); + if (offset_out != offset_in) { + ret = -3; + TEST_STEP_FAILURE(ret); + } + + offset_out = seek_adi(fd, OFFSET_ADD, SEEK_CUR); + if (offset_out != (offset_in + OFFSET_ADD)) { + ret = -4; + TEST_STEP_FAILURE(ret); + } + + offset_out = seek_adi(fd, OFFSET_SUBTRACT, SEEK_CUR); + if (offset_out != (offset_in + OFFSET_ADD + OFFSET_SUBTRACT)) { + ret = -5; + TEST_STEP_FAILURE(ret); + } + + ret = 0; +out: + RETURN_FROM_TEST(ret); +} + +static int test5_rw_aligned_1byte(int fd) +{ + /* somewhat arbitrarily chosen address */ + unsigned long paddr = + (end_addr[range_count - 1] - 0xF000) & ~(ADI_BLKSZ - 1); + unsigned char version, expected_version; + loff_t offset; + off_t oret; + int ret; + + offset = paddr / ADI_BLKSZ; + version = expected_version = random_version(); + + oret = seek_adi(fd, offset, SEEK_SET); + if (oret != offset) { + ret = -1; + TEST_STEP_FAILURE(ret); + } + + ret = write_adi(fd, &version, sizeof(version)); + if (ret != sizeof(version)) + TEST_STEP_FAILURE(ret); + + oret = seek_adi(fd, offset, SEEK_SET); + if (oret != offset) { + ret = -1; + TEST_STEP_FAILURE(ret); + } + + ret = read_adi(fd, &version, sizeof(version)); + if (ret != sizeof(version)) + TEST_STEP_FAILURE(ret); + + if (expected_version != version) { + DEBUG_PRINT_L2("\tExpected version %d but read version %d\n", + expected_version, version); + TEST_STEP_FAILURE(-expected_version); + } + + ret = 0; +out: + RETURN_FROM_TEST(ret); +} + +#define TEST6_VERSION_SZ 9434 +static int test6_rw_aligned_9434bytes(int fd) +{ + /* somewhat arbitrarily chosen address */ + unsigned long paddr = + (end_addr[range_count - 1] - 0x5F000) & ~(ADI_BLKSZ - 1); + unsigned char version[TEST6_VERSION_SZ], + expected_version[TEST6_VERSION_SZ]; + loff_t offset; + off_t oret; + int ret, i; + + offset = paddr / ADI_BLKSZ; + for (i = 0; i < TEST6_VERSION_SZ; i++) + version[i] = expected_version[i] = random_version(); + + oret = seek_adi(fd, offset, SEEK_SET); + if (oret != offset) { + ret = -1; + TEST_STEP_FAILURE(ret); + } + + ret = write_adi(fd, version, sizeof(version)); + if (ret != sizeof(version)) + TEST_STEP_FAILURE(ret); + + memset(version, 0, TEST6_VERSION_SZ); + + oret = seek_adi(fd, offset, SEEK_SET); + if (oret != offset) { + ret = -1; + TEST_STEP_FAILURE(ret); + } + + ret = read_adi(fd, version, sizeof(version)); + if (ret != sizeof(version)) + TEST_STEP_FAILURE(ret); + + for (i = 0; i < TEST6_VERSION_SZ; i++) { + if (expected_version[i] != version[i]) { + DEBUG_PRINT_L2( + "\tExpected version %d but read version %d\n", + expected_version[i], version[i]); + TEST_STEP_FAILURE(-expected_version[i]); + } + } + + ret = 0; +out: + RETURN_FROM_TEST(ret); +} + +#define TEST7_VERSION_SZ 14963 +static int test7_rw_aligned_14963bytes(int fd) +{ + /* somewhat arbitrarily chosen address */ + unsigned long paddr = + ((start_addr[range_count - 1] + 0xF000) & ~(ADI_BLKSZ - 1)) + 39; + unsigned char version[TEST7_VERSION_SZ], + expected_version[TEST7_VERSION_SZ]; + loff_t offset; + off_t oret; + int ret, i; + + offset = paddr / ADI_BLKSZ; + for (i = 0; i < TEST7_VERSION_SZ; i++) { + version[i] = random_version(); + expected_version[i] = version[i]; + } + + oret = seek_adi(fd, offset, SEEK_SET); + if (oret != offset) { + ret = -1; + TEST_STEP_FAILURE(ret); + } + + ret = write_adi(fd, version, sizeof(version)); + if (ret != sizeof(version)) + TEST_STEP_FAILURE(ret); + + memset(version, 0, TEST7_VERSION_SZ); + + oret = seek_adi(fd, offset, SEEK_SET); + if (oret != offset) { + ret = -1; + TEST_STEP_FAILURE(ret); + } + + ret = read_adi(fd, version, sizeof(version)); + if (ret != sizeof(version)) + TEST_STEP_FAILURE(ret); + + for (i = 0; i < TEST7_VERSION_SZ; i++) { + if (expected_version[i] != version[i]) { + DEBUG_PRINT_L2( + "\tExpected version %d but read version %d\n", + expected_version[i], version[i]); + TEST_STEP_FAILURE(-expected_version[i]); + } + + paddr += ADI_BLKSZ; + } + + ret = 0; +out: + RETURN_FROM_TEST(ret); +} + +static int (*tests[])(int fd) = { + test0_prpw_aligned_1byte, + test1_prpw_aligned_4096bytes, + test2_prpw_aligned_10327bytes, + test3_prpw_unaligned_12541bytes, + test4_lseek, + test5_rw_aligned_1byte, + test6_rw_aligned_9434bytes, + test7_rw_aligned_14963bytes, +}; +#define TEST_COUNT ARRAY_SIZE(tests) + +int main(int argc, char *argv[]) +{ + int fd, ret, test; + + ret = build_memory_map(); + if (ret < 0) + return ret; + + fd = open("/dev/adi", O_RDWR); + if (fd < 0) { + fprintf(stderr, "open: error %d: %s\n", + errno, strerror(errno)); + return -errno; + } + + for (test = 0; test < TEST_COUNT; test++) { + DEBUG_PRINT_L1("Running test #%d\n", test); + + ret = (*tests[test])(fd); + if (ret != 0) + ksft_test_result_fail("Test #%d failed: error %d\n", + test, ret); + else + ksft_test_result_pass("Test #%d passed\n", test); + } + + print_stats(); + close(fd); + + if (ksft_get_fail_cnt() > 0) + ksft_exit_fail(); + else + ksft_exit_pass(); + + /* it's impossible to get here, but the compiler throws a warning + * about control reaching the end of non-void function. bah. + */ + return 0; +} diff --git a/tools/testing/selftests/sparc64/drivers/drivers_test.sh b/tools/testing/selftests/sparc64/drivers/drivers_test.sh new file mode 100755 index 000000000000..6d08273b7532 --- /dev/null +++ b/tools/testing/selftests/sparc64/drivers/drivers_test.sh @@ -0,0 +1,30 @@ +#!/bin/sh +# SPDX-License-Identifier: GPL-2.0 + +SRC_TREE=../../../../ + +test_run() +{ + if [ -f ${SRC_TREE}/drivers/char/adi.ko ]; then + insmod ${SRC_TREE}/drivers/char/adi.ko 2> /dev/null + if [ $? -ne 0 ]; then + rc=1 + fi + else + # Use modprobe dry run to check for missing adi module + if ! /sbin/modprobe -q -n adi; then + echo "adi: [SKIP]" + elif /sbin/modprobe -q adi; then + echo "adi: ok" + else + echo "adi: [FAIL]" + rc=1 + fi + fi + ./adi-test + rmmod adi 2> /dev/null +} + +rc=0 +test_run +exit $rc diff --git a/tools/testing/selftests/sparc64/run.sh b/tools/testing/selftests/sparc64/run.sh new file mode 100755 index 000000000000..38ad61f9328e --- /dev/null +++ b/tools/testing/selftests/sparc64/run.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +(cd drivers; ./drivers_test.sh) -- cgit From 4e49ed2f9ac32b0ba22c113dc405a49d3133eb57 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Sat, 2 Jun 2018 08:44:03 -0400 Subject: selftests/lib.mk: Introduce OVERRIDE_TARGETS Introduce OVERRIDE_TARGETS to allow tests to express dependencies on header files and .so, which require to override the selftests lib.mk targets. Signed-off-by: Mathieu Desnoyers Signed-off-by: Thomas Gleixner Acked-by: Shuah Khan Cc: Joel Fernandes Cc: Peter Zijlstra Cc: Catalin Marinas Cc: Dave Watson Cc: Will Deacon Cc: Andi Kleen Cc: linux-kselftest@vger.kernel.org Cc: "H . Peter Anvin" Cc: Chris Lameter Cc: Russell King Cc: Andrew Hunter Cc: Michael Kerrisk Cc: "Paul E . McKenney" Cc: Paul Turner Cc: Boqun Feng Cc: Josh Triplett Cc: Steven Rostedt Cc: Ben Maurer Cc: linux-api@vger.kernel.org Cc: Andy Lutomirski Cc: Andrew Morton Cc: Linus Torvalds Link: https://lkml.kernel.org/r/20180602124408.8430-12-mathieu.desnoyers@efficios.com --- tools/testing/selftests/lib.mk | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'tools') diff --git a/tools/testing/selftests/lib.mk b/tools/testing/selftests/lib.mk index c1b1a4dc6a96..ceb6c7c48547 100644 --- a/tools/testing/selftests/lib.mk +++ b/tools/testing/selftests/lib.mk @@ -106,6 +106,9 @@ COMPILE.S = $(CC) $(ASFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c LINK.S = $(CC) $(ASFLAGS) $(CPPFLAGS) $(LDFLAGS) $(TARGET_ARCH) endif +# Selftest makefiles can override those targets by setting +# OVERRIDE_TARGETS = 1. +ifeq ($(OVERRIDE_TARGETS),) $(OUTPUT)/%:%.c $(LINK.c) $^ $(LDLIBS) -o $@ @@ -114,5 +117,6 @@ $(OUTPUT)/%.o:%.S $(OUTPUT)/%:%.S $(LINK.S) $^ $(LDLIBS) -o $@ +endif .PHONY: run_tests all clean install emit_tests -- cgit From 2e155fb7d605d37c423ad0076f82feca572efdce Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Sat, 2 Jun 2018 08:44:04 -0400 Subject: rseq/selftests: Provide rseq library This rseq helper library provides a user-space API to the rseq() system call. The rseq fast-path exposes the instruction pointer addresses where the rseq assembly blocks begin and end, as well as the associated abort instruction pointer, in the __rseq_table section. This section allows debuggers may know where to place breakpoints when single-stepping through assembly blocks which may be aborted at any point by the kernel. Signed-off-by: Mathieu Desnoyers Signed-off-by: Thomas Gleixner Cc: Joel Fernandes Cc: Peter Zijlstra Cc: Catalin Marinas Cc: Dave Watson Cc: Will Deacon Cc: Shuah Khan Cc: Andi Kleen Cc: linux-kselftest@vger.kernel.org Cc: "H . Peter Anvin" Cc: Chris Lameter Cc: Russell King Cc: Andrew Hunter Cc: Michael Kerrisk Cc: "Paul E . McKenney" Cc: Paul Turner Cc: Boqun Feng Cc: Josh Triplett Cc: Steven Rostedt Cc: Ben Maurer Cc: linux-api@vger.kernel.org Cc: Andy Lutomirski Cc: Andrew Morton Cc: Linus Torvalds Link: https://lkml.kernel.org/r/20180602124408.8430-13-mathieu.desnoyers@efficios.com --- tools/testing/selftests/rseq/rseq-arm.h | 715 +++++++++++++++++++ tools/testing/selftests/rseq/rseq-ppc.h | 671 ++++++++++++++++++ tools/testing/selftests/rseq/rseq-skip.h | 65 ++ tools/testing/selftests/rseq/rseq-x86.h | 1132 ++++++++++++++++++++++++++++++ tools/testing/selftests/rseq/rseq.c | 117 +++ tools/testing/selftests/rseq/rseq.h | 147 ++++ 6 files changed, 2847 insertions(+) create mode 100644 tools/testing/selftests/rseq/rseq-arm.h create mode 100644 tools/testing/selftests/rseq/rseq-ppc.h create mode 100644 tools/testing/selftests/rseq/rseq-skip.h create mode 100644 tools/testing/selftests/rseq/rseq-x86.h create mode 100644 tools/testing/selftests/rseq/rseq.c create mode 100644 tools/testing/selftests/rseq/rseq.h (limited to 'tools') diff --git a/tools/testing/selftests/rseq/rseq-arm.h b/tools/testing/selftests/rseq/rseq-arm.h new file mode 100644 index 000000000000..3b055f9aeaab --- /dev/null +++ b/tools/testing/selftests/rseq/rseq-arm.h @@ -0,0 +1,715 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * rseq-arm.h + * + * (C) Copyright 2016-2018 - Mathieu Desnoyers + */ + +#define RSEQ_SIG 0x53053053 + +#define rseq_smp_mb() __asm__ __volatile__ ("dmb" ::: "memory", "cc") +#define rseq_smp_rmb() __asm__ __volatile__ ("dmb" ::: "memory", "cc") +#define rseq_smp_wmb() __asm__ __volatile__ ("dmb" ::: "memory", "cc") + +#define rseq_smp_load_acquire(p) \ +__extension__ ({ \ + __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \ + rseq_smp_mb(); \ + ____p1; \ +}) + +#define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb() + +#define rseq_smp_store_release(p, v) \ +do { \ + rseq_smp_mb(); \ + RSEQ_WRITE_ONCE(*p, v); \ +} while (0) + +#ifdef RSEQ_SKIP_FASTPATH +#include "rseq-skip.h" +#else /* !RSEQ_SKIP_FASTPATH */ + +#define __RSEQ_ASM_DEFINE_TABLE(version, flags, start_ip, \ + post_commit_offset, abort_ip) \ + ".pushsection __rseq_table, \"aw\"\n\t" \ + ".balign 32\n\t" \ + ".word " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \ + ".word " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) ", 0x0\n\t" \ + ".popsection\n\t" + +#define RSEQ_ASM_DEFINE_TABLE(start_ip, post_commit_ip, abort_ip) \ + __RSEQ_ASM_DEFINE_TABLE(0x0, 0x0, start_ip, \ + (post_commit_ip - start_ip), abort_ip) + +#define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \ + RSEQ_INJECT_ASM(1) \ + "adr r0, " __rseq_str(cs_label) "\n\t" \ + "str r0, %[" __rseq_str(rseq_cs) "]\n\t" \ + __rseq_str(label) ":\n\t" + +#define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \ + RSEQ_INJECT_ASM(2) \ + "ldr r0, %[" __rseq_str(current_cpu_id) "]\n\t" \ + "cmp %[" __rseq_str(cpu_id) "], r0\n\t" \ + "bne " __rseq_str(label) "\n\t" + +#define __RSEQ_ASM_DEFINE_ABORT(table_label, label, teardown, \ + abort_label, version, flags, \ + start_ip, post_commit_offset, abort_ip) \ + __rseq_str(table_label) ":\n\t" \ + ".word " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \ + ".word " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) ", 0x0\n\t" \ + ".word " __rseq_str(RSEQ_SIG) "\n\t" \ + __rseq_str(label) ":\n\t" \ + teardown \ + "b %l[" __rseq_str(abort_label) "]\n\t" + +#define RSEQ_ASM_DEFINE_ABORT(table_label, label, teardown, abort_label, \ + start_ip, post_commit_ip, abort_ip) \ + __RSEQ_ASM_DEFINE_ABORT(table_label, label, teardown, \ + abort_label, 0x0, 0x0, start_ip, \ + (post_commit_ip - start_ip), abort_ip) + +#define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label) \ + __rseq_str(label) ":\n\t" \ + teardown \ + "b %l[" __rseq_str(cmpfail_label) "]\n\t" + +#define rseq_workaround_gcc_asm_size_guess() __asm__ __volatile__("") + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + "ldr r0, %[v]\n\t" + "cmp %[expect], r0\n\t" + "bne %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + "ldr r0, %[v]\n\t" + "cmp %[expect], r0\n\t" + "bne %l[error2]\n\t" +#endif + /* final store */ + "str %[newv], %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(5) + "b 5f\n\t" + RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f) + "5:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) + RSEQ_INJECT_INPUT + : "r0", "memory", "cc" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + rseq_workaround_gcc_asm_size_guess(); + return 0; +abort: + rseq_workaround_gcc_asm_size_guess(); + RSEQ_INJECT_FAILED + return -1; +cmpfail: + rseq_workaround_gcc_asm_size_guess(); + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, + off_t voffp, intptr_t *load, int cpu) +{ + RSEQ_INJECT_C(9) + + rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + "ldr r0, %[v]\n\t" + "cmp %[expectnot], r0\n\t" + "beq %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + "ldr r0, %[v]\n\t" + "cmp %[expectnot], r0\n\t" + "beq %l[error2]\n\t" +#endif + "str r0, %[load]\n\t" + "add r0, %[voffp]\n\t" + "ldr r0, [r0]\n\t" + /* final store */ + "str r0, %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(5) + "b 5f\n\t" + RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f) + "5:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* final store input */ + [v] "m" (*v), + [expectnot] "r" (expectnot), + [voffp] "Ir" (voffp), + [load] "m" (*load) + RSEQ_INJECT_INPUT + : "r0", "memory", "cc" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + rseq_workaround_gcc_asm_size_guess(); + return 0; +abort: + rseq_workaround_gcc_asm_size_guess(); + RSEQ_INJECT_FAILED + return -1; +cmpfail: + rseq_workaround_gcc_asm_size_guess(); + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_addv(intptr_t *v, intptr_t count, int cpu) +{ + RSEQ_INJECT_C(9) + + rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) +#endif + "ldr r0, %[v]\n\t" + "add r0, %[count]\n\t" + /* final store */ + "str r0, %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(4) + "b 5f\n\t" + RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f) + "5:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + [v] "m" (*v), + [count] "Ir" (count) + RSEQ_INJECT_INPUT + : "r0", "memory", "cc" + RSEQ_INJECT_CLOBBER + : abort +#ifdef RSEQ_COMPARE_TWICE + , error1 +#endif + ); + rseq_workaround_gcc_asm_size_guess(); + return 0; +abort: + rseq_workaround_gcc_asm_size_guess(); + RSEQ_INJECT_FAILED + return -1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + intptr_t *v2, intptr_t newv2, + intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + "ldr r0, %[v]\n\t" + "cmp %[expect], r0\n\t" + "bne %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + "ldr r0, %[v]\n\t" + "cmp %[expect], r0\n\t" + "bne %l[error2]\n\t" +#endif + /* try store */ + "str %[newv2], %[v2]\n\t" + RSEQ_INJECT_ASM(5) + /* final store */ + "str %[newv], %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(6) + "b 5f\n\t" + RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f) + "5:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* try store input */ + [v2] "m" (*v2), + [newv2] "r" (newv2), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) + RSEQ_INJECT_INPUT + : "r0", "memory", "cc" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + rseq_workaround_gcc_asm_size_guess(); + return 0; +abort: + rseq_workaround_gcc_asm_size_guess(); + RSEQ_INJECT_FAILED + return -1; +cmpfail: + rseq_workaround_gcc_asm_size_guess(); + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect, + intptr_t *v2, intptr_t newv2, + intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + "ldr r0, %[v]\n\t" + "cmp %[expect], r0\n\t" + "bne %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + "ldr r0, %[v]\n\t" + "cmp %[expect], r0\n\t" + "bne %l[error2]\n\t" +#endif + /* try store */ + "str %[newv2], %[v2]\n\t" + RSEQ_INJECT_ASM(5) + "dmb\n\t" /* full mb provides store-release */ + /* final store */ + "str %[newv], %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(6) + "b 5f\n\t" + RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f) + "5:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* try store input */ + [v2] "m" (*v2), + [newv2] "r" (newv2), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) + RSEQ_INJECT_INPUT + : "r0", "memory", "cc" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + rseq_workaround_gcc_asm_size_guess(); + return 0; +abort: + rseq_workaround_gcc_asm_size_guess(); + RSEQ_INJECT_FAILED + return -1; +cmpfail: + rseq_workaround_gcc_asm_size_guess(); + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + intptr_t *v2, intptr_t expect2, + intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + "ldr r0, %[v]\n\t" + "cmp %[expect], r0\n\t" + "bne %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) + "ldr r0, %[v2]\n\t" + "cmp %[expect2], r0\n\t" + "bne %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(5) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + "ldr r0, %[v]\n\t" + "cmp %[expect], r0\n\t" + "bne %l[error2]\n\t" + "ldr r0, %[v2]\n\t" + "cmp %[expect2], r0\n\t" + "bne %l[error3]\n\t" +#endif + /* final store */ + "str %[newv], %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(6) + "b 5f\n\t" + RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f) + "5:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* cmp2 input */ + [v2] "m" (*v2), + [expect2] "r" (expect2), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) + RSEQ_INJECT_INPUT + : "r0", "memory", "cc" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2, error3 +#endif + ); + rseq_workaround_gcc_asm_size_guess(); + return 0; +abort: + rseq_workaround_gcc_asm_size_guess(); + RSEQ_INJECT_FAILED + return -1; +cmpfail: + rseq_workaround_gcc_asm_size_guess(); + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("1st expected value comparison failed"); +error3: + rseq_bug("2nd expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + void *dst, void *src, size_t len, + intptr_t newv, int cpu) +{ + uint32_t rseq_scratch[3]; + + RSEQ_INJECT_C(9) + + rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */ + "str %[src], %[rseq_scratch0]\n\t" + "str %[dst], %[rseq_scratch1]\n\t" + "str %[len], %[rseq_scratch2]\n\t" + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + "ldr r0, %[v]\n\t" + "cmp %[expect], r0\n\t" + "bne 5f\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 6f) + "ldr r0, %[v]\n\t" + "cmp %[expect], r0\n\t" + "bne 7f\n\t" +#endif + /* try memcpy */ + "cmp %[len], #0\n\t" \ + "beq 333f\n\t" \ + "222:\n\t" \ + "ldrb %%r0, [%[src]]\n\t" \ + "strb %%r0, [%[dst]]\n\t" \ + "adds %[src], #1\n\t" \ + "adds %[dst], #1\n\t" \ + "subs %[len], #1\n\t" \ + "bne 222b\n\t" \ + "333:\n\t" \ + RSEQ_INJECT_ASM(5) + /* final store */ + "str %[newv], %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(6) + /* teardown */ + "ldr %[len], %[rseq_scratch2]\n\t" + "ldr %[dst], %[rseq_scratch1]\n\t" + "ldr %[src], %[rseq_scratch0]\n\t" + "b 8f\n\t" + RSEQ_ASM_DEFINE_ABORT(3, 4, + /* teardown */ + "ldr %[len], %[rseq_scratch2]\n\t" + "ldr %[dst], %[rseq_scratch1]\n\t" + "ldr %[src], %[rseq_scratch0]\n\t", + abort, 1b, 2b, 4f) + RSEQ_ASM_DEFINE_CMPFAIL(5, + /* teardown */ + "ldr %[len], %[rseq_scratch2]\n\t" + "ldr %[dst], %[rseq_scratch1]\n\t" + "ldr %[src], %[rseq_scratch0]\n\t", + cmpfail) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_DEFINE_CMPFAIL(6, + /* teardown */ + "ldr %[len], %[rseq_scratch2]\n\t" + "ldr %[dst], %[rseq_scratch1]\n\t" + "ldr %[src], %[rseq_scratch0]\n\t", + error1) + RSEQ_ASM_DEFINE_CMPFAIL(7, + /* teardown */ + "ldr %[len], %[rseq_scratch2]\n\t" + "ldr %[dst], %[rseq_scratch1]\n\t" + "ldr %[src], %[rseq_scratch0]\n\t", + error2) +#endif + "8:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv), + /* try memcpy input */ + [dst] "r" (dst), + [src] "r" (src), + [len] "r" (len), + [rseq_scratch0] "m" (rseq_scratch[0]), + [rseq_scratch1] "m" (rseq_scratch[1]), + [rseq_scratch2] "m" (rseq_scratch[2]) + RSEQ_INJECT_INPUT + : "r0", "memory", "cc" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + rseq_workaround_gcc_asm_size_guess(); + return 0; +abort: + rseq_workaround_gcc_asm_size_guess(); + RSEQ_INJECT_FAILED + return -1; +cmpfail: + rseq_workaround_gcc_asm_size_guess(); + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_workaround_gcc_asm_size_guess(); + rseq_bug("cpu_id comparison failed"); +error2: + rseq_workaround_gcc_asm_size_guess(); + rseq_bug("expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect, + void *dst, void *src, size_t len, + intptr_t newv, int cpu) +{ + uint32_t rseq_scratch[3]; + + RSEQ_INJECT_C(9) + + rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */ + "str %[src], %[rseq_scratch0]\n\t" + "str %[dst], %[rseq_scratch1]\n\t" + "str %[len], %[rseq_scratch2]\n\t" + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + "ldr r0, %[v]\n\t" + "cmp %[expect], r0\n\t" + "bne 5f\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 6f) + "ldr r0, %[v]\n\t" + "cmp %[expect], r0\n\t" + "bne 7f\n\t" +#endif + /* try memcpy */ + "cmp %[len], #0\n\t" \ + "beq 333f\n\t" \ + "222:\n\t" \ + "ldrb %%r0, [%[src]]\n\t" \ + "strb %%r0, [%[dst]]\n\t" \ + "adds %[src], #1\n\t" \ + "adds %[dst], #1\n\t" \ + "subs %[len], #1\n\t" \ + "bne 222b\n\t" \ + "333:\n\t" \ + RSEQ_INJECT_ASM(5) + "dmb\n\t" /* full mb provides store-release */ + /* final store */ + "str %[newv], %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(6) + /* teardown */ + "ldr %[len], %[rseq_scratch2]\n\t" + "ldr %[dst], %[rseq_scratch1]\n\t" + "ldr %[src], %[rseq_scratch0]\n\t" + "b 8f\n\t" + RSEQ_ASM_DEFINE_ABORT(3, 4, + /* teardown */ + "ldr %[len], %[rseq_scratch2]\n\t" + "ldr %[dst], %[rseq_scratch1]\n\t" + "ldr %[src], %[rseq_scratch0]\n\t", + abort, 1b, 2b, 4f) + RSEQ_ASM_DEFINE_CMPFAIL(5, + /* teardown */ + "ldr %[len], %[rseq_scratch2]\n\t" + "ldr %[dst], %[rseq_scratch1]\n\t" + "ldr %[src], %[rseq_scratch0]\n\t", + cmpfail) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_DEFINE_CMPFAIL(6, + /* teardown */ + "ldr %[len], %[rseq_scratch2]\n\t" + "ldr %[dst], %[rseq_scratch1]\n\t" + "ldr %[src], %[rseq_scratch0]\n\t", + error1) + RSEQ_ASM_DEFINE_CMPFAIL(7, + /* teardown */ + "ldr %[len], %[rseq_scratch2]\n\t" + "ldr %[dst], %[rseq_scratch1]\n\t" + "ldr %[src], %[rseq_scratch0]\n\t", + error2) +#endif + "8:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv), + /* try memcpy input */ + [dst] "r" (dst), + [src] "r" (src), + [len] "r" (len), + [rseq_scratch0] "m" (rseq_scratch[0]), + [rseq_scratch1] "m" (rseq_scratch[1]), + [rseq_scratch2] "m" (rseq_scratch[2]) + RSEQ_INJECT_INPUT + : "r0", "memory", "cc" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + rseq_workaround_gcc_asm_size_guess(); + return 0; +abort: + rseq_workaround_gcc_asm_size_guess(); + RSEQ_INJECT_FAILED + return -1; +cmpfail: + rseq_workaround_gcc_asm_size_guess(); + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_workaround_gcc_asm_size_guess(); + rseq_bug("cpu_id comparison failed"); +error2: + rseq_workaround_gcc_asm_size_guess(); + rseq_bug("expected value comparison failed"); +#endif +} + +#endif /* !RSEQ_SKIP_FASTPATH */ diff --git a/tools/testing/selftests/rseq/rseq-ppc.h b/tools/testing/selftests/rseq/rseq-ppc.h new file mode 100644 index 000000000000..52630c9f42be --- /dev/null +++ b/tools/testing/selftests/rseq/rseq-ppc.h @@ -0,0 +1,671 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * rseq-ppc.h + * + * (C) Copyright 2016-2018 - Mathieu Desnoyers + * (C) Copyright 2016-2018 - Boqun Feng + */ + +#define RSEQ_SIG 0x53053053 + +#define rseq_smp_mb() __asm__ __volatile__ ("sync" ::: "memory", "cc") +#define rseq_smp_lwsync() __asm__ __volatile__ ("lwsync" ::: "memory", "cc") +#define rseq_smp_rmb() rseq_smp_lwsync() +#define rseq_smp_wmb() rseq_smp_lwsync() + +#define rseq_smp_load_acquire(p) \ +__extension__ ({ \ + __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \ + rseq_smp_lwsync(); \ + ____p1; \ +}) + +#define rseq_smp_acquire__after_ctrl_dep() rseq_smp_lwsync() + +#define rseq_smp_store_release(p, v) \ +do { \ + rseq_smp_lwsync(); \ + RSEQ_WRITE_ONCE(*p, v); \ +} while (0) + +#ifdef RSEQ_SKIP_FASTPATH +#include "rseq-skip.h" +#else /* !RSEQ_SKIP_FASTPATH */ + +/* + * The __rseq_table section can be used by debuggers to better handle + * single-stepping through the restartable critical sections. + */ + +#ifdef __PPC64__ + +#define STORE_WORD "std " +#define LOAD_WORD "ld " +#define LOADX_WORD "ldx " +#define CMP_WORD "cmpd " + +#define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \ + start_ip, post_commit_offset, abort_ip) \ + ".pushsection __rseq_table, \"aw\"\n\t" \ + ".balign 32\n\t" \ + __rseq_str(label) ":\n\t" \ + ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \ + ".quad " __rseq_str(start_ip) ", " __rseq_str(post_commit_offset) ", " __rseq_str(abort_ip) "\n\t" \ + ".popsection\n\t" + +#define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \ + RSEQ_INJECT_ASM(1) \ + "lis %%r17, (" __rseq_str(cs_label) ")@highest\n\t" \ + "ori %%r17, %%r17, (" __rseq_str(cs_label) ")@higher\n\t" \ + "rldicr %%r17, %%r17, 32, 31\n\t" \ + "oris %%r17, %%r17, (" __rseq_str(cs_label) ")@high\n\t" \ + "ori %%r17, %%r17, (" __rseq_str(cs_label) ")@l\n\t" \ + "std %%r17, %[" __rseq_str(rseq_cs) "]\n\t" \ + __rseq_str(label) ":\n\t" + +#else /* #ifdef __PPC64__ */ + +#define STORE_WORD "stw " +#define LOAD_WORD "lwz " +#define LOADX_WORD "lwzx " +#define CMP_WORD "cmpw " + +#define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \ + start_ip, post_commit_offset, abort_ip) \ + ".pushsection __rseq_table, \"aw\"\n\t" \ + ".balign 32\n\t" \ + __rseq_str(label) ":\n\t" \ + ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \ + /* 32-bit only supported on BE */ \ + ".long 0x0, " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) "\n\t" \ + ".popsection\n\t" + +#define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \ + RSEQ_INJECT_ASM(1) \ + "lis %%r17, (" __rseq_str(cs_label) ")@ha\n\t" \ + "addi %%r17, %%r17, (" __rseq_str(cs_label) ")@l\n\t" \ + "stw %%r17, %[" __rseq_str(rseq_cs) "]\n\t" \ + __rseq_str(label) ":\n\t" + +#endif /* #ifdef __PPC64__ */ + +#define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \ + __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \ + (post_commit_ip - start_ip), abort_ip) + +#define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \ + RSEQ_INJECT_ASM(2) \ + "lwz %%r17, %[" __rseq_str(current_cpu_id) "]\n\t" \ + "cmpw cr7, %[" __rseq_str(cpu_id) "], %%r17\n\t" \ + "bne- cr7, " __rseq_str(label) "\n\t" + +#define RSEQ_ASM_DEFINE_ABORT(label, abort_label) \ + ".pushsection __rseq_failure, \"ax\"\n\t" \ + ".long " __rseq_str(RSEQ_SIG) "\n\t" \ + __rseq_str(label) ":\n\t" \ + "b %l[" __rseq_str(abort_label) "]\n\t" \ + ".popsection\n\t" + +/* + * RSEQ_ASM_OPs: asm operations for rseq + * RSEQ_ASM_OP_R_*: has hard-code registers in it + * RSEQ_ASM_OP_* (else): doesn't have hard-code registers(unless cr7) + */ +#define RSEQ_ASM_OP_CMPEQ(var, expect, label) \ + LOAD_WORD "%%r17, %[" __rseq_str(var) "]\n\t" \ + CMP_WORD "cr7, %%r17, %[" __rseq_str(expect) "]\n\t" \ + "bne- cr7, " __rseq_str(label) "\n\t" + +#define RSEQ_ASM_OP_CMPNE(var, expectnot, label) \ + LOAD_WORD "%%r17, %[" __rseq_str(var) "]\n\t" \ + CMP_WORD "cr7, %%r17, %[" __rseq_str(expectnot) "]\n\t" \ + "beq- cr7, " __rseq_str(label) "\n\t" + +#define RSEQ_ASM_OP_STORE(value, var) \ + STORE_WORD "%[" __rseq_str(value) "], %[" __rseq_str(var) "]\n\t" + +/* Load @var to r17 */ +#define RSEQ_ASM_OP_R_LOAD(var) \ + LOAD_WORD "%%r17, %[" __rseq_str(var) "]\n\t" + +/* Store r17 to @var */ +#define RSEQ_ASM_OP_R_STORE(var) \ + STORE_WORD "%%r17, %[" __rseq_str(var) "]\n\t" + +/* Add @count to r17 */ +#define RSEQ_ASM_OP_R_ADD(count) \ + "add %%r17, %[" __rseq_str(count) "], %%r17\n\t" + +/* Load (r17 + voffp) to r17 */ +#define RSEQ_ASM_OP_R_LOADX(voffp) \ + LOADX_WORD "%%r17, %[" __rseq_str(voffp) "], %%r17\n\t" + +/* TODO: implement a faster memcpy. */ +#define RSEQ_ASM_OP_R_MEMCPY() \ + "cmpdi %%r19, 0\n\t" \ + "beq 333f\n\t" \ + "addi %%r20, %%r20, -1\n\t" \ + "addi %%r21, %%r21, -1\n\t" \ + "222:\n\t" \ + "lbzu %%r18, 1(%%r20)\n\t" \ + "stbu %%r18, 1(%%r21)\n\t" \ + "addi %%r19, %%r19, -1\n\t" \ + "cmpdi %%r19, 0\n\t" \ + "bne 222b\n\t" \ + "333:\n\t" \ + +#define RSEQ_ASM_OP_R_FINAL_STORE(var, post_commit_label) \ + STORE_WORD "%%r17, %[" __rseq_str(var) "]\n\t" \ + __rseq_str(post_commit_label) ":\n\t" + +#define RSEQ_ASM_OP_FINAL_STORE(value, var, post_commit_label) \ + STORE_WORD "%[" __rseq_str(value) "], %[" __rseq_str(var) "]\n\t" \ + __rseq_str(post_commit_label) ":\n\t" + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + /* cmp cpuid */ + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + /* cmp @v equal to @expect */ + RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail]) + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + /* cmp cpuid */ + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + /* cmp @v equal to @expect */ + RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2]) +#endif + /* final store */ + RSEQ_ASM_OP_FINAL_STORE(newv, v, 2) + RSEQ_INJECT_ASM(5) + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) + RSEQ_INJECT_INPUT + : "memory", "cc", "r17" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, + off_t voffp, intptr_t *load, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + /* cmp cpuid */ + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + /* cmp @v not equal to @expectnot */ + RSEQ_ASM_OP_CMPNE(v, expectnot, %l[cmpfail]) + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + /* cmp cpuid */ + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + /* cmp @v not equal to @expectnot */ + RSEQ_ASM_OP_CMPNE(v, expectnot, %l[error2]) +#endif + /* load the value of @v */ + RSEQ_ASM_OP_R_LOAD(v) + /* store it in @load */ + RSEQ_ASM_OP_R_STORE(load) + /* dereference voffp(v) */ + RSEQ_ASM_OP_R_LOADX(voffp) + /* final store the value at voffp(v) */ + RSEQ_ASM_OP_R_FINAL_STORE(v, 2) + RSEQ_INJECT_ASM(5) + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* final store input */ + [v] "m" (*v), + [expectnot] "r" (expectnot), + [voffp] "b" (voffp), + [load] "m" (*load) + RSEQ_INJECT_INPUT + : "memory", "cc", "r17" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_addv(intptr_t *v, intptr_t count, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + /* cmp cpuid */ + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) +#ifdef RSEQ_COMPARE_TWICE + /* cmp cpuid */ + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) +#endif + /* load the value of @v */ + RSEQ_ASM_OP_R_LOAD(v) + /* add @count to it */ + RSEQ_ASM_OP_R_ADD(count) + /* final store */ + RSEQ_ASM_OP_R_FINAL_STORE(v, 2) + RSEQ_INJECT_ASM(4) + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* final store input */ + [v] "m" (*v), + [count] "r" (count) + RSEQ_INJECT_INPUT + : "memory", "cc", "r17" + RSEQ_INJECT_CLOBBER + : abort +#ifdef RSEQ_COMPARE_TWICE + , error1 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + intptr_t *v2, intptr_t newv2, + intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + /* cmp cpuid */ + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + /* cmp @v equal to @expect */ + RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail]) + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + /* cmp cpuid */ + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + /* cmp @v equal to @expect */ + RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2]) +#endif + /* try store */ + RSEQ_ASM_OP_STORE(newv2, v2) + RSEQ_INJECT_ASM(5) + /* final store */ + RSEQ_ASM_OP_FINAL_STORE(newv, v, 2) + RSEQ_INJECT_ASM(6) + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* try store input */ + [v2] "m" (*v2), + [newv2] "r" (newv2), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) + RSEQ_INJECT_INPUT + : "memory", "cc", "r17" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect, + intptr_t *v2, intptr_t newv2, + intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + /* cmp cpuid */ + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + /* cmp @v equal to @expect */ + RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail]) + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + /* cmp cpuid */ + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + /* cmp @v equal to @expect */ + RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2]) +#endif + /* try store */ + RSEQ_ASM_OP_STORE(newv2, v2) + RSEQ_INJECT_ASM(5) + /* for 'release' */ + "lwsync\n\t" + /* final store */ + RSEQ_ASM_OP_FINAL_STORE(newv, v, 2) + RSEQ_INJECT_ASM(6) + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* try store input */ + [v2] "m" (*v2), + [newv2] "r" (newv2), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) + RSEQ_INJECT_INPUT + : "memory", "cc", "r17" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + intptr_t *v2, intptr_t expect2, + intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + /* cmp cpuid */ + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + /* cmp @v equal to @expect */ + RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail]) + RSEQ_INJECT_ASM(4) + /* cmp @v2 equal to @expct2 */ + RSEQ_ASM_OP_CMPEQ(v2, expect2, %l[cmpfail]) + RSEQ_INJECT_ASM(5) +#ifdef RSEQ_COMPARE_TWICE + /* cmp cpuid */ + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + /* cmp @v equal to @expect */ + RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2]) + /* cmp @v2 equal to @expct2 */ + RSEQ_ASM_OP_CMPEQ(v2, expect2, %l[error3]) +#endif + /* final store */ + RSEQ_ASM_OP_FINAL_STORE(newv, v, 2) + RSEQ_INJECT_ASM(6) + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* cmp2 input */ + [v2] "m" (*v2), + [expect2] "r" (expect2), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) + RSEQ_INJECT_INPUT + : "memory", "cc", "r17" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2, error3 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("1st expected value comparison failed"); +error3: + rseq_bug("2nd expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + void *dst, void *src, size_t len, + intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + /* setup for mempcy */ + "mr %%r19, %[len]\n\t" + "mr %%r20, %[src]\n\t" + "mr %%r21, %[dst]\n\t" + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + /* cmp cpuid */ + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + /* cmp @v equal to @expect */ + RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail]) + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + /* cmp cpuid */ + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + /* cmp @v equal to @expect */ + RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2]) +#endif + /* try memcpy */ + RSEQ_ASM_OP_R_MEMCPY() + RSEQ_INJECT_ASM(5) + /* final store */ + RSEQ_ASM_OP_FINAL_STORE(newv, v, 2) + RSEQ_INJECT_ASM(6) + /* teardown */ + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv), + /* try memcpy input */ + [dst] "r" (dst), + [src] "r" (src), + [len] "r" (len) + RSEQ_INJECT_INPUT + : "memory", "cc", "r17", "r18", "r19", "r20", "r21" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect, + void *dst, void *src, size_t len, + intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + /* setup for mempcy */ + "mr %%r19, %[len]\n\t" + "mr %%r20, %[src]\n\t" + "mr %%r21, %[dst]\n\t" + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + /* cmp cpuid */ + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + /* cmp @v equal to @expect */ + RSEQ_ASM_OP_CMPEQ(v, expect, %l[cmpfail]) + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + /* cmp cpuid */ + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + /* cmp @v equal to @expect */ + RSEQ_ASM_OP_CMPEQ(v, expect, %l[error2]) +#endif + /* try memcpy */ + RSEQ_ASM_OP_R_MEMCPY() + RSEQ_INJECT_ASM(5) + /* for 'release' */ + "lwsync\n\t" + /* final store */ + RSEQ_ASM_OP_FINAL_STORE(newv, v, 2) + RSEQ_INJECT_ASM(6) + /* teardown */ + RSEQ_ASM_DEFINE_ABORT(4, abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv), + /* try memcpy input */ + [dst] "r" (dst), + [src] "r" (src), + [len] "r" (len) + RSEQ_INJECT_INPUT + : "memory", "cc", "r17", "r18", "r19", "r20", "r21" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +#undef STORE_WORD +#undef LOAD_WORD +#undef LOADX_WORD +#undef CMP_WORD + +#endif /* !RSEQ_SKIP_FASTPATH */ diff --git a/tools/testing/selftests/rseq/rseq-skip.h b/tools/testing/selftests/rseq/rseq-skip.h new file mode 100644 index 000000000000..72750b5905a9 --- /dev/null +++ b/tools/testing/selftests/rseq/rseq-skip.h @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * rseq-skip.h + * + * (C) Copyright 2017-2018 - Mathieu Desnoyers + */ + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) +{ + return -1; +} + +static inline __attribute__((always_inline)) +int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, + off_t voffp, intptr_t *load, int cpu) +{ + return -1; +} + +static inline __attribute__((always_inline)) +int rseq_addv(intptr_t *v, intptr_t count, int cpu) +{ + return -1; +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + intptr_t *v2, intptr_t newv2, + intptr_t newv, int cpu) +{ + return -1; +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect, + intptr_t *v2, intptr_t newv2, + intptr_t newv, int cpu) +{ + return -1; +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + intptr_t *v2, intptr_t expect2, + intptr_t newv, int cpu) +{ + return -1; +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + void *dst, void *src, size_t len, + intptr_t newv, int cpu) +{ + return -1; +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect, + void *dst, void *src, size_t len, + intptr_t newv, int cpu) +{ + return -1; +} diff --git a/tools/testing/selftests/rseq/rseq-x86.h b/tools/testing/selftests/rseq/rseq-x86.h new file mode 100644 index 000000000000..089410a314e9 --- /dev/null +++ b/tools/testing/selftests/rseq/rseq-x86.h @@ -0,0 +1,1132 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * rseq-x86.h + * + * (C) Copyright 2016-2018 - Mathieu Desnoyers + */ + +#include + +#define RSEQ_SIG 0x53053053 + +#ifdef __x86_64__ + +#define rseq_smp_mb() \ + __asm__ __volatile__ ("lock; addl $0,-128(%%rsp)" ::: "memory", "cc") +#define rseq_smp_rmb() rseq_barrier() +#define rseq_smp_wmb() rseq_barrier() + +#define rseq_smp_load_acquire(p) \ +__extension__ ({ \ + __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \ + rseq_barrier(); \ + ____p1; \ +}) + +#define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb() + +#define rseq_smp_store_release(p, v) \ +do { \ + rseq_barrier(); \ + RSEQ_WRITE_ONCE(*p, v); \ +} while (0) + +#ifdef RSEQ_SKIP_FASTPATH +#include "rseq-skip.h" +#else /* !RSEQ_SKIP_FASTPATH */ + +#define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \ + start_ip, post_commit_offset, abort_ip) \ + ".pushsection __rseq_table, \"aw\"\n\t" \ + ".balign 32\n\t" \ + __rseq_str(label) ":\n\t" \ + ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \ + ".quad " __rseq_str(start_ip) ", " __rseq_str(post_commit_offset) ", " __rseq_str(abort_ip) "\n\t" \ + ".popsection\n\t" + +#define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \ + __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \ + (post_commit_ip - start_ip), abort_ip) + +#define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \ + RSEQ_INJECT_ASM(1) \ + "leaq " __rseq_str(cs_label) "(%%rip), %%rax\n\t" \ + "movq %%rax, %[" __rseq_str(rseq_cs) "]\n\t" \ + __rseq_str(label) ":\n\t" + +#define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \ + RSEQ_INJECT_ASM(2) \ + "cmpl %[" __rseq_str(cpu_id) "], %[" __rseq_str(current_cpu_id) "]\n\t" \ + "jnz " __rseq_str(label) "\n\t" + +#define RSEQ_ASM_DEFINE_ABORT(label, teardown, abort_label) \ + ".pushsection __rseq_failure, \"ax\"\n\t" \ + /* Disassembler-friendly signature: nopl (%rip). */\ + ".byte 0x0f, 0x1f, 0x05\n\t" \ + ".long " __rseq_str(RSEQ_SIG) "\n\t" \ + __rseq_str(label) ":\n\t" \ + teardown \ + "jmp %l[" __rseq_str(abort_label) "]\n\t" \ + ".popsection\n\t" + +#define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label) \ + ".pushsection __rseq_failure, \"ax\"\n\t" \ + __rseq_str(label) ":\n\t" \ + teardown \ + "jmp %l[" __rseq_str(cmpfail_label) "]\n\t" \ + ".popsection\n\t" + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + "cmpq %[v], %[expect]\n\t" + "jnz %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + "cmpq %[v], %[expect]\n\t" + "jnz %l[error2]\n\t" +#endif + /* final store */ + "movq %[newv], %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(5) + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) + : "memory", "cc", "rax" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +/* + * Compare @v against @expectnot. When it does _not_ match, load @v + * into @load, and store the content of *@v + voffp into @v. + */ +static inline __attribute__((always_inline)) +int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, + off_t voffp, intptr_t *load, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + "movq %[v], %%rbx\n\t" + "cmpq %%rbx, %[expectnot]\n\t" + "je %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + "movq %[v], %%rbx\n\t" + "cmpq %%rbx, %[expectnot]\n\t" + "je %l[error2]\n\t" +#endif + "movq %%rbx, %[load]\n\t" + "addq %[voffp], %%rbx\n\t" + "movq (%%rbx), %%rbx\n\t" + /* final store */ + "movq %%rbx, %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(5) + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* final store input */ + [v] "m" (*v), + [expectnot] "r" (expectnot), + [voffp] "er" (voffp), + [load] "m" (*load) + : "memory", "cc", "rax", "rbx" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_addv(intptr_t *v, intptr_t count, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) +#endif + /* final store */ + "addq %[count], %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(4) + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* final store input */ + [v] "m" (*v), + [count] "er" (count) + : "memory", "cc", "rax" + RSEQ_INJECT_CLOBBER + : abort +#ifdef RSEQ_COMPARE_TWICE + , error1 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + intptr_t *v2, intptr_t newv2, + intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + "cmpq %[v], %[expect]\n\t" + "jnz %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + "cmpq %[v], %[expect]\n\t" + "jnz %l[error2]\n\t" +#endif + /* try store */ + "movq %[newv2], %[v2]\n\t" + RSEQ_INJECT_ASM(5) + /* final store */ + "movq %[newv], %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(6) + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* try store input */ + [v2] "m" (*v2), + [newv2] "r" (newv2), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) + : "memory", "cc", "rax" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +/* x86-64 is TSO. */ +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect, + intptr_t *v2, intptr_t newv2, + intptr_t newv, int cpu) +{ + return rseq_cmpeqv_trystorev_storev(v, expect, v2, newv2, newv, cpu); +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + intptr_t *v2, intptr_t expect2, + intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + "cmpq %[v], %[expect]\n\t" + "jnz %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) + "cmpq %[v2], %[expect2]\n\t" + "jnz %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(5) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + "cmpq %[v], %[expect]\n\t" + "jnz %l[error2]\n\t" + "cmpq %[v2], %[expect2]\n\t" + "jnz %l[error3]\n\t" +#endif + /* final store */ + "movq %[newv], %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(6) + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* cmp2 input */ + [v2] "m" (*v2), + [expect2] "r" (expect2), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) + : "memory", "cc", "rax" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2, error3 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("1st expected value comparison failed"); +error3: + rseq_bug("2nd expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + void *dst, void *src, size_t len, + intptr_t newv, int cpu) +{ + uint64_t rseq_scratch[3]; + + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + "movq %[src], %[rseq_scratch0]\n\t" + "movq %[dst], %[rseq_scratch1]\n\t" + "movq %[len], %[rseq_scratch2]\n\t" + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + "cmpq %[v], %[expect]\n\t" + "jnz 5f\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 6f) + "cmpq %[v], %[expect]\n\t" + "jnz 7f\n\t" +#endif + /* try memcpy */ + "test %[len], %[len]\n\t" \ + "jz 333f\n\t" \ + "222:\n\t" \ + "movb (%[src]), %%al\n\t" \ + "movb %%al, (%[dst])\n\t" \ + "inc %[src]\n\t" \ + "inc %[dst]\n\t" \ + "dec %[len]\n\t" \ + "jnz 222b\n\t" \ + "333:\n\t" \ + RSEQ_INJECT_ASM(5) + /* final store */ + "movq %[newv], %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(6) + /* teardown */ + "movq %[rseq_scratch2], %[len]\n\t" + "movq %[rseq_scratch1], %[dst]\n\t" + "movq %[rseq_scratch0], %[src]\n\t" + RSEQ_ASM_DEFINE_ABORT(4, + "movq %[rseq_scratch2], %[len]\n\t" + "movq %[rseq_scratch1], %[dst]\n\t" + "movq %[rseq_scratch0], %[src]\n\t", + abort) + RSEQ_ASM_DEFINE_CMPFAIL(5, + "movq %[rseq_scratch2], %[len]\n\t" + "movq %[rseq_scratch1], %[dst]\n\t" + "movq %[rseq_scratch0], %[src]\n\t", + cmpfail) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_DEFINE_CMPFAIL(6, + "movq %[rseq_scratch2], %[len]\n\t" + "movq %[rseq_scratch1], %[dst]\n\t" + "movq %[rseq_scratch0], %[src]\n\t", + error1) + RSEQ_ASM_DEFINE_CMPFAIL(7, + "movq %[rseq_scratch2], %[len]\n\t" + "movq %[rseq_scratch1], %[dst]\n\t" + "movq %[rseq_scratch0], %[src]\n\t", + error2) +#endif + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv), + /* try memcpy input */ + [dst] "r" (dst), + [src] "r" (src), + [len] "r" (len), + [rseq_scratch0] "m" (rseq_scratch[0]), + [rseq_scratch1] "m" (rseq_scratch[1]), + [rseq_scratch2] "m" (rseq_scratch[2]) + : "memory", "cc", "rax" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +/* x86-64 is TSO. */ +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect, + void *dst, void *src, size_t len, + intptr_t newv, int cpu) +{ + return rseq_cmpeqv_trymemcpy_storev(v, expect, dst, src, len, + newv, cpu); +} + +#endif /* !RSEQ_SKIP_FASTPATH */ + +#elif __i386__ + +#define rseq_smp_mb() \ + __asm__ __volatile__ ("lock; addl $0,-128(%%esp)" ::: "memory", "cc") +#define rseq_smp_rmb() \ + __asm__ __volatile__ ("lock; addl $0,-128(%%esp)" ::: "memory", "cc") +#define rseq_smp_wmb() \ + __asm__ __volatile__ ("lock; addl $0,-128(%%esp)" ::: "memory", "cc") + +#define rseq_smp_load_acquire(p) \ +__extension__ ({ \ + __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \ + rseq_smp_mb(); \ + ____p1; \ +}) + +#define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb() + +#define rseq_smp_store_release(p, v) \ +do { \ + rseq_smp_mb(); \ + RSEQ_WRITE_ONCE(*p, v); \ +} while (0) + +#ifdef RSEQ_SKIP_FASTPATH +#include "rseq-skip.h" +#else /* !RSEQ_SKIP_FASTPATH */ + +/* + * Use eax as scratch register and take memory operands as input to + * lessen register pressure. Especially needed when compiling in O0. + */ +#define __RSEQ_ASM_DEFINE_TABLE(label, version, flags, \ + start_ip, post_commit_offset, abort_ip) \ + ".pushsection __rseq_table, \"aw\"\n\t" \ + ".balign 32\n\t" \ + __rseq_str(label) ":\n\t" \ + ".long " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \ + ".long " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) ", 0x0\n\t" \ + ".popsection\n\t" + +#define RSEQ_ASM_DEFINE_TABLE(label, start_ip, post_commit_ip, abort_ip) \ + __RSEQ_ASM_DEFINE_TABLE(label, 0x0, 0x0, start_ip, \ + (post_commit_ip - start_ip), abort_ip) + +#define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \ + RSEQ_INJECT_ASM(1) \ + "movl $" __rseq_str(cs_label) ", %[rseq_cs]\n\t" \ + __rseq_str(label) ":\n\t" + +#define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \ + RSEQ_INJECT_ASM(2) \ + "cmpl %[" __rseq_str(cpu_id) "], %[" __rseq_str(current_cpu_id) "]\n\t" \ + "jnz " __rseq_str(label) "\n\t" + +#define RSEQ_ASM_DEFINE_ABORT(label, teardown, abort_label) \ + ".pushsection __rseq_failure, \"ax\"\n\t" \ + /* Disassembler-friendly signature: nopl . */ \ + ".byte 0x0f, 0x1f, 0x05\n\t" \ + ".long " __rseq_str(RSEQ_SIG) "\n\t" \ + __rseq_str(label) ":\n\t" \ + teardown \ + "jmp %l[" __rseq_str(abort_label) "]\n\t" \ + ".popsection\n\t" + +#define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label) \ + ".pushsection __rseq_failure, \"ax\"\n\t" \ + __rseq_str(label) ":\n\t" \ + teardown \ + "jmp %l[" __rseq_str(cmpfail_label) "]\n\t" \ + ".popsection\n\t" + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + "cmpl %[v], %[expect]\n\t" + "jnz %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + "cmpl %[v], %[expect]\n\t" + "jnz %l[error2]\n\t" +#endif + /* final store */ + "movl %[newv], %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(5) + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) + : "memory", "cc", "eax" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +/* + * Compare @v against @expectnot. When it does _not_ match, load @v + * into @load, and store the content of *@v + voffp into @v. + */ +static inline __attribute__((always_inline)) +int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, + off_t voffp, intptr_t *load, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + "movl %[v], %%ebx\n\t" + "cmpl %%ebx, %[expectnot]\n\t" + "je %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + "movl %[v], %%ebx\n\t" + "cmpl %%ebx, %[expectnot]\n\t" + "je %l[error2]\n\t" +#endif + "movl %%ebx, %[load]\n\t" + "addl %[voffp], %%ebx\n\t" + "movl (%%ebx), %%ebx\n\t" + /* final store */ + "movl %%ebx, %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(5) + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* final store input */ + [v] "m" (*v), + [expectnot] "r" (expectnot), + [voffp] "ir" (voffp), + [load] "m" (*load) + : "memory", "cc", "eax", "ebx" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_addv(intptr_t *v, intptr_t count, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) +#endif + /* final store */ + "addl %[count], %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(4) + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* final store input */ + [v] "m" (*v), + [count] "ir" (count) + : "memory", "cc", "eax" + RSEQ_INJECT_CLOBBER + : abort +#ifdef RSEQ_COMPARE_TWICE + , error1 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + intptr_t *v2, intptr_t newv2, + intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + "cmpl %[v], %[expect]\n\t" + "jnz %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + "cmpl %[v], %[expect]\n\t" + "jnz %l[error2]\n\t" +#endif + /* try store */ + "movl %[newv2], %%eax\n\t" + "movl %%eax, %[v2]\n\t" + RSEQ_INJECT_ASM(5) + /* final store */ + "movl %[newv], %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(6) + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* try store input */ + [v2] "m" (*v2), + [newv2] "m" (newv2), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) + : "memory", "cc", "eax" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect, + intptr_t *v2, intptr_t newv2, + intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + "movl %[expect], %%eax\n\t" + "cmpl %[v], %%eax\n\t" + "jnz %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + "movl %[expect], %%eax\n\t" + "cmpl %[v], %%eax\n\t" + "jnz %l[error2]\n\t" +#endif + /* try store */ + "movl %[newv2], %[v2]\n\t" + RSEQ_INJECT_ASM(5) + "lock; addl $0,-128(%%esp)\n\t" + /* final store */ + "movl %[newv], %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(6) + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* try store input */ + [v2] "m" (*v2), + [newv2] "r" (newv2), + /* final store input */ + [v] "m" (*v), + [expect] "m" (expect), + [newv] "r" (newv) + : "memory", "cc", "eax" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif + +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + intptr_t *v2, intptr_t expect2, + intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + "cmpl %[v], %[expect]\n\t" + "jnz %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) + "cmpl %[expect2], %[v2]\n\t" + "jnz %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(5) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + "cmpl %[v], %[expect]\n\t" + "jnz %l[error2]\n\t" + "cmpl %[expect2], %[v2]\n\t" + "jnz %l[error3]\n\t" +#endif + "movl %[newv], %%eax\n\t" + /* final store */ + "movl %%eax, %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(6) + RSEQ_ASM_DEFINE_ABORT(4, "", abort) + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* cmp2 input */ + [v2] "m" (*v2), + [expect2] "r" (expect2), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), + [newv] "m" (newv) + : "memory", "cc", "eax" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2, error3 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("1st expected value comparison failed"); +error3: + rseq_bug("2nd expected value comparison failed"); +#endif +} + +/* TODO: implement a faster memcpy. */ +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + void *dst, void *src, size_t len, + intptr_t newv, int cpu) +{ + uint32_t rseq_scratch[3]; + + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + "movl %[src], %[rseq_scratch0]\n\t" + "movl %[dst], %[rseq_scratch1]\n\t" + "movl %[len], %[rseq_scratch2]\n\t" + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + "movl %[expect], %%eax\n\t" + "cmpl %%eax, %[v]\n\t" + "jnz 5f\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 6f) + "movl %[expect], %%eax\n\t" + "cmpl %%eax, %[v]\n\t" + "jnz 7f\n\t" +#endif + /* try memcpy */ + "test %[len], %[len]\n\t" \ + "jz 333f\n\t" \ + "222:\n\t" \ + "movb (%[src]), %%al\n\t" \ + "movb %%al, (%[dst])\n\t" \ + "inc %[src]\n\t" \ + "inc %[dst]\n\t" \ + "dec %[len]\n\t" \ + "jnz 222b\n\t" \ + "333:\n\t" \ + RSEQ_INJECT_ASM(5) + "movl %[newv], %%eax\n\t" + /* final store */ + "movl %%eax, %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(6) + /* teardown */ + "movl %[rseq_scratch2], %[len]\n\t" + "movl %[rseq_scratch1], %[dst]\n\t" + "movl %[rseq_scratch0], %[src]\n\t" + RSEQ_ASM_DEFINE_ABORT(4, + "movl %[rseq_scratch2], %[len]\n\t" + "movl %[rseq_scratch1], %[dst]\n\t" + "movl %[rseq_scratch0], %[src]\n\t", + abort) + RSEQ_ASM_DEFINE_CMPFAIL(5, + "movl %[rseq_scratch2], %[len]\n\t" + "movl %[rseq_scratch1], %[dst]\n\t" + "movl %[rseq_scratch0], %[src]\n\t", + cmpfail) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_DEFINE_CMPFAIL(6, + "movl %[rseq_scratch2], %[len]\n\t" + "movl %[rseq_scratch1], %[dst]\n\t" + "movl %[rseq_scratch0], %[src]\n\t", + error1) + RSEQ_ASM_DEFINE_CMPFAIL(7, + "movl %[rseq_scratch2], %[len]\n\t" + "movl %[rseq_scratch1], %[dst]\n\t" + "movl %[rseq_scratch0], %[src]\n\t", + error2) +#endif + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* final store input */ + [v] "m" (*v), + [expect] "m" (expect), + [newv] "m" (newv), + /* try memcpy input */ + [dst] "r" (dst), + [src] "r" (src), + [len] "r" (len), + [rseq_scratch0] "m" (rseq_scratch[0]), + [rseq_scratch1] "m" (rseq_scratch[1]), + [rseq_scratch2] "m" (rseq_scratch[2]) + : "memory", "cc", "eax" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +/* TODO: implement a faster memcpy. */ +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect, + void *dst, void *src, size_t len, + intptr_t newv, int cpu) +{ + uint32_t rseq_scratch[3]; + + RSEQ_INJECT_C(9) + + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(3, 1f, 2f, 4f) /* start, commit, abort */ + "movl %[src], %[rseq_scratch0]\n\t" + "movl %[dst], %[rseq_scratch1]\n\t" + "movl %[len], %[rseq_scratch2]\n\t" + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3b, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + "movl %[expect], %%eax\n\t" + "cmpl %%eax, %[v]\n\t" + "jnz 5f\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 6f) + "movl %[expect], %%eax\n\t" + "cmpl %%eax, %[v]\n\t" + "jnz 7f\n\t" +#endif + /* try memcpy */ + "test %[len], %[len]\n\t" \ + "jz 333f\n\t" \ + "222:\n\t" \ + "movb (%[src]), %%al\n\t" \ + "movb %%al, (%[dst])\n\t" \ + "inc %[src]\n\t" \ + "inc %[dst]\n\t" \ + "dec %[len]\n\t" \ + "jnz 222b\n\t" \ + "333:\n\t" \ + RSEQ_INJECT_ASM(5) + "lock; addl $0,-128(%%esp)\n\t" + "movl %[newv], %%eax\n\t" + /* final store */ + "movl %%eax, %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(6) + /* teardown */ + "movl %[rseq_scratch2], %[len]\n\t" + "movl %[rseq_scratch1], %[dst]\n\t" + "movl %[rseq_scratch0], %[src]\n\t" + RSEQ_ASM_DEFINE_ABORT(4, + "movl %[rseq_scratch2], %[len]\n\t" + "movl %[rseq_scratch1], %[dst]\n\t" + "movl %[rseq_scratch0], %[src]\n\t", + abort) + RSEQ_ASM_DEFINE_CMPFAIL(5, + "movl %[rseq_scratch2], %[len]\n\t" + "movl %[rseq_scratch1], %[dst]\n\t" + "movl %[rseq_scratch0], %[src]\n\t", + cmpfail) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_DEFINE_CMPFAIL(6, + "movl %[rseq_scratch2], %[len]\n\t" + "movl %[rseq_scratch1], %[dst]\n\t" + "movl %[rseq_scratch0], %[src]\n\t", + error1) + RSEQ_ASM_DEFINE_CMPFAIL(7, + "movl %[rseq_scratch2], %[len]\n\t" + "movl %[rseq_scratch1], %[dst]\n\t" + "movl %[rseq_scratch0], %[src]\n\t", + error2) +#endif + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* final store input */ + [v] "m" (*v), + [expect] "m" (expect), + [newv] "m" (newv), + /* try memcpy input */ + [dst] "r" (dst), + [src] "r" (src), + [len] "r" (len), + [rseq_scratch0] "m" (rseq_scratch[0]), + [rseq_scratch1] "m" (rseq_scratch[1]), + [rseq_scratch2] "m" (rseq_scratch[2]) + : "memory", "cc", "eax" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + return 0; +abort: + RSEQ_INJECT_FAILED + return -1; +cmpfail: + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +#endif /* !RSEQ_SKIP_FASTPATH */ + +#endif diff --git a/tools/testing/selftests/rseq/rseq.c b/tools/testing/selftests/rseq/rseq.c new file mode 100644 index 000000000000..4847e97ed049 --- /dev/null +++ b/tools/testing/selftests/rseq/rseq.c @@ -0,0 +1,117 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * rseq.c + * + * Copyright (C) 2016 Mathieu Desnoyers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; only + * version 2.1 of the License. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rseq.h" + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +__attribute__((tls_model("initial-exec"))) __thread +volatile struct rseq __rseq_abi = { + .cpu_id = RSEQ_CPU_ID_UNINITIALIZED, +}; + +static __attribute__((tls_model("initial-exec"))) __thread +volatile int refcount; + +static void signal_off_save(sigset_t *oldset) +{ + sigset_t set; + int ret; + + sigfillset(&set); + ret = pthread_sigmask(SIG_BLOCK, &set, oldset); + if (ret) + abort(); +} + +static void signal_restore(sigset_t oldset) +{ + int ret; + + ret = pthread_sigmask(SIG_SETMASK, &oldset, NULL); + if (ret) + abort(); +} + +static int sys_rseq(volatile struct rseq *rseq_abi, uint32_t rseq_len, + int flags, uint32_t sig) +{ + return syscall(__NR_rseq, rseq_abi, rseq_len, flags, sig); +} + +int rseq_register_current_thread(void) +{ + int rc, ret = 0; + sigset_t oldset; + + signal_off_save(&oldset); + if (refcount++) + goto end; + rc = sys_rseq(&__rseq_abi, sizeof(struct rseq), 0, RSEQ_SIG); + if (!rc) { + assert(rseq_current_cpu_raw() >= 0); + goto end; + } + if (errno != EBUSY) + __rseq_abi.cpu_id = -2; + ret = -1; + refcount--; +end: + signal_restore(oldset); + return ret; +} + +int rseq_unregister_current_thread(void) +{ + int rc, ret = 0; + sigset_t oldset; + + signal_off_save(&oldset); + if (--refcount) + goto end; + rc = sys_rseq(&__rseq_abi, sizeof(struct rseq), + RSEQ_FLAG_UNREGISTER, RSEQ_SIG); + if (!rc) + goto end; + ret = -1; +end: + signal_restore(oldset); + return ret; +} + +int32_t rseq_fallback_current_cpu(void) +{ + int32_t cpu; + + cpu = sched_getcpu(); + if (cpu < 0) { + perror("sched_getcpu()"); + abort(); + } + return cpu; +} diff --git a/tools/testing/selftests/rseq/rseq.h b/tools/testing/selftests/rseq/rseq.h new file mode 100644 index 000000000000..0a808575cbc4 --- /dev/null +++ b/tools/testing/selftests/rseq/rseq.h @@ -0,0 +1,147 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * rseq.h + * + * (C) Copyright 2016-2018 - Mathieu Desnoyers + */ + +#ifndef RSEQ_H +#define RSEQ_H + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Empty code injection macros, override when testing. + * It is important to consider that the ASM injection macros need to be + * fully reentrant (e.g. do not modify the stack). + */ +#ifndef RSEQ_INJECT_ASM +#define RSEQ_INJECT_ASM(n) +#endif + +#ifndef RSEQ_INJECT_C +#define RSEQ_INJECT_C(n) +#endif + +#ifndef RSEQ_INJECT_INPUT +#define RSEQ_INJECT_INPUT +#endif + +#ifndef RSEQ_INJECT_CLOBBER +#define RSEQ_INJECT_CLOBBER +#endif + +#ifndef RSEQ_INJECT_FAILED +#define RSEQ_INJECT_FAILED +#endif + +extern __thread volatile struct rseq __rseq_abi; + +#define rseq_likely(x) __builtin_expect(!!(x), 1) +#define rseq_unlikely(x) __builtin_expect(!!(x), 0) +#define rseq_barrier() __asm__ __volatile__("" : : : "memory") + +#define RSEQ_ACCESS_ONCE(x) (*(__volatile__ __typeof__(x) *)&(x)) +#define RSEQ_WRITE_ONCE(x, v) __extension__ ({ RSEQ_ACCESS_ONCE(x) = (v); }) +#define RSEQ_READ_ONCE(x) RSEQ_ACCESS_ONCE(x) + +#define __rseq_str_1(x) #x +#define __rseq_str(x) __rseq_str_1(x) + +#define rseq_log(fmt, args...) \ + fprintf(stderr, fmt "(in %s() at " __FILE__ ":" __rseq_str(__LINE__)"\n", \ + ## args, __func__) + +#define rseq_bug(fmt, args...) \ + do { \ + rseq_log(fmt, ##args); \ + abort(); \ + } while (0) + +#if defined(__x86_64__) || defined(__i386__) +#include +#elif defined(__ARMEL__) +#include +#elif defined(__PPC__) +#include +#else +#error unsupported target +#endif + +/* + * Register rseq for the current thread. This needs to be called once + * by any thread which uses restartable sequences, before they start + * using restartable sequences, to ensure restartable sequences + * succeed. A restartable sequence executed from a non-registered + * thread will always fail. + */ +int rseq_register_current_thread(void); + +/* + * Unregister rseq for current thread. + */ +int rseq_unregister_current_thread(void); + +/* + * Restartable sequence fallback for reading the current CPU number. + */ +int32_t rseq_fallback_current_cpu(void); + +/* + * Values returned can be either the current CPU number, -1 (rseq is + * uninitialized), or -2 (rseq initialization has failed). + */ +static inline int32_t rseq_current_cpu_raw(void) +{ + return RSEQ_ACCESS_ONCE(__rseq_abi.cpu_id); +} + +/* + * Returns a possible CPU number, which is typically the current CPU. + * The returned CPU number can be used to prepare for an rseq critical + * section, which will confirm whether the cpu number is indeed the + * current one, and whether rseq is initialized. + * + * The CPU number returned by rseq_cpu_start should always be validated + * by passing it to a rseq asm sequence, or by comparing it to the + * return value of rseq_current_cpu_raw() if the rseq asm sequence + * does not need to be invoked. + */ +static inline uint32_t rseq_cpu_start(void) +{ + return RSEQ_ACCESS_ONCE(__rseq_abi.cpu_id_start); +} + +static inline uint32_t rseq_current_cpu(void) +{ + int32_t cpu; + + cpu = rseq_current_cpu_raw(); + if (rseq_unlikely(cpu < 0)) + cpu = rseq_fallback_current_cpu(); + return cpu; +} + +/* + * rseq_prepare_unload() should be invoked by each thread using rseq_finish*() + * at least once between their last rseq_finish*() and library unload of the + * library defining the rseq critical section (struct rseq_cs). This also + * applies to use of rseq in code generated by JIT: rseq_prepare_unload() + * should be invoked at least once by each thread using rseq_finish*() before + * reclaim of the memory holding the struct rseq_cs. + */ +static inline void rseq_prepare_unload(void) +{ + __rseq_abi.rseq_cs = 0; +} + +#endif /* RSEQ_H_ */ -- cgit From 1badac4f80c3d325d6d1b9fc3b6344120aa799be Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Sat, 2 Jun 2018 08:44:05 -0400 Subject: rseq/selftests: Provide basic test "basic_test" only asserts that RSEQ works moderately correctly. E.g. that the CPUID pointer works. Signed-off-by: Mathieu Desnoyers Signed-off-by: Thomas Gleixner Cc: Joel Fernandes Cc: Peter Zijlstra Cc: Catalin Marinas Cc: Dave Watson Cc: Will Deacon Cc: Shuah Khan Cc: Andi Kleen Cc: linux-kselftest@vger.kernel.org Cc: "H . Peter Anvin" Cc: Chris Lameter Cc: Russell King Cc: Andrew Hunter Cc: Michael Kerrisk Cc: "Paul E . McKenney" Cc: Paul Turner Cc: Boqun Feng Cc: Josh Triplett Cc: Steven Rostedt Cc: Ben Maurer Cc: linux-api@vger.kernel.org Cc: Andy Lutomirski Cc: Andrew Morton Cc: Linus Torvalds Link: https://lkml.kernel.org/r/20180602124408.8430-14-mathieu.desnoyers@efficios.com --- tools/testing/selftests/rseq/basic_test.c | 56 +++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 tools/testing/selftests/rseq/basic_test.c (limited to 'tools') diff --git a/tools/testing/selftests/rseq/basic_test.c b/tools/testing/selftests/rseq/basic_test.c new file mode 100644 index 000000000000..d8efbfb89193 --- /dev/null +++ b/tools/testing/selftests/rseq/basic_test.c @@ -0,0 +1,56 @@ +// SPDX-License-Identifier: LGPL-2.1 +/* + * Basic test coverage for critical regions and rseq_current_cpu(). + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include + +#include "rseq.h" + +void test_cpu_pointer(void) +{ + cpu_set_t affinity, test_affinity; + int i; + + sched_getaffinity(0, sizeof(affinity), &affinity); + CPU_ZERO(&test_affinity); + for (i = 0; i < CPU_SETSIZE; i++) { + if (CPU_ISSET(i, &affinity)) { + CPU_SET(i, &test_affinity); + sched_setaffinity(0, sizeof(test_affinity), + &test_affinity); + assert(sched_getcpu() == i); + assert(rseq_current_cpu() == i); + assert(rseq_current_cpu_raw() == i); + assert(rseq_cpu_start() == i); + CPU_CLR(i, &test_affinity); + } + } + sched_setaffinity(0, sizeof(affinity), &affinity); +} + +int main(int argc, char **argv) +{ + if (rseq_register_current_thread()) { + fprintf(stderr, "Error: rseq_register_current_thread(...) failed(%d): %s\n", + errno, strerror(errno)); + goto init_thread_error; + } + printf("testing current cpu\n"); + test_cpu_pointer(); + if (rseq_unregister_current_thread()) { + fprintf(stderr, "Error: rseq_unregister_current_thread(...) failed(%d): %s\n", + errno, strerror(errno)); + goto init_thread_error; + } + return 0; + +init_thread_error: + return -1; +} -- cgit From 01a5ec4217599fd78ba76fa7199a350c5fb4650f Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Sat, 2 Jun 2018 08:44:06 -0400 Subject: rseq/selftests: Provide basic percpu ops test "basic_percpu_ops_test" is a slightly more "realistic" variant, implementing a few simple per-cpu operations and testing their correctness. Signed-off-by: Mathieu Desnoyers Signed-off-by: Thomas Gleixner Cc: Joel Fernandes Cc: Peter Zijlstra Cc: Catalin Marinas Cc: Dave Watson Cc: Will Deacon Cc: Shuah Khan Cc: Andi Kleen Cc: linux-kselftest@vger.kernel.org Cc: "H . Peter Anvin" Cc: Chris Lameter Cc: Russell King Cc: Andrew Hunter Cc: Michael Kerrisk Cc: "Paul E . McKenney" Cc: Paul Turner Cc: Boqun Feng Cc: Josh Triplett Cc: Steven Rostedt Cc: Ben Maurer Cc: linux-api@vger.kernel.org Cc: Andy Lutomirski Cc: Andrew Morton Cc: Linus Torvalds Link: https://lkml.kernel.org/r/20180602124408.8430-15-mathieu.desnoyers@efficios.com --- .../testing/selftests/rseq/basic_percpu_ops_test.c | 312 +++++++++++++++++++++ 1 file changed, 312 insertions(+) create mode 100644 tools/testing/selftests/rseq/basic_percpu_ops_test.c (limited to 'tools') diff --git a/tools/testing/selftests/rseq/basic_percpu_ops_test.c b/tools/testing/selftests/rseq/basic_percpu_ops_test.c new file mode 100644 index 000000000000..eb3f6db36d36 --- /dev/null +++ b/tools/testing/selftests/rseq/basic_percpu_ops_test.c @@ -0,0 +1,312 @@ +// SPDX-License-Identifier: LGPL-2.1 +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include "rseq.h" + +#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) + +struct percpu_lock_entry { + intptr_t v; +} __attribute__((aligned(128))); + +struct percpu_lock { + struct percpu_lock_entry c[CPU_SETSIZE]; +}; + +struct test_data_entry { + intptr_t count; +} __attribute__((aligned(128))); + +struct spinlock_test_data { + struct percpu_lock lock; + struct test_data_entry c[CPU_SETSIZE]; + int reps; +}; + +struct percpu_list_node { + intptr_t data; + struct percpu_list_node *next; +}; + +struct percpu_list_entry { + struct percpu_list_node *head; +} __attribute__((aligned(128))); + +struct percpu_list { + struct percpu_list_entry c[CPU_SETSIZE]; +}; + +/* A simple percpu spinlock. Returns the cpu lock was acquired on. */ +int rseq_this_cpu_lock(struct percpu_lock *lock) +{ + int cpu; + + for (;;) { + int ret; + + cpu = rseq_cpu_start(); + ret = rseq_cmpeqv_storev(&lock->c[cpu].v, + 0, 1, cpu); + if (rseq_likely(!ret)) + break; + /* Retry if comparison fails or rseq aborts. */ + } + /* + * Acquire semantic when taking lock after control dependency. + * Matches rseq_smp_store_release(). + */ + rseq_smp_acquire__after_ctrl_dep(); + return cpu; +} + +void rseq_percpu_unlock(struct percpu_lock *lock, int cpu) +{ + assert(lock->c[cpu].v == 1); + /* + * Release lock, with release semantic. Matches + * rseq_smp_acquire__after_ctrl_dep(). + */ + rseq_smp_store_release(&lock->c[cpu].v, 0); +} + +void *test_percpu_spinlock_thread(void *arg) +{ + struct spinlock_test_data *data = arg; + int i, cpu; + + if (rseq_register_current_thread()) { + fprintf(stderr, "Error: rseq_register_current_thread(...) failed(%d): %s\n", + errno, strerror(errno)); + abort(); + } + for (i = 0; i < data->reps; i++) { + cpu = rseq_this_cpu_lock(&data->lock); + data->c[cpu].count++; + rseq_percpu_unlock(&data->lock, cpu); + } + if (rseq_unregister_current_thread()) { + fprintf(stderr, "Error: rseq_unregister_current_thread(...) failed(%d): %s\n", + errno, strerror(errno)); + abort(); + } + + return NULL; +} + +/* + * A simple test which implements a sharded counter using a per-cpu + * lock. Obviously real applications might prefer to simply use a + * per-cpu increment; however, this is reasonable for a test and the + * lock can be extended to synchronize more complicated operations. + */ +void test_percpu_spinlock(void) +{ + const int num_threads = 200; + int i; + uint64_t sum; + pthread_t test_threads[num_threads]; + struct spinlock_test_data data; + + memset(&data, 0, sizeof(data)); + data.reps = 5000; + + for (i = 0; i < num_threads; i++) + pthread_create(&test_threads[i], NULL, + test_percpu_spinlock_thread, &data); + + for (i = 0; i < num_threads; i++) + pthread_join(test_threads[i], NULL); + + sum = 0; + for (i = 0; i < CPU_SETSIZE; i++) + sum += data.c[i].count; + + assert(sum == (uint64_t)data.reps * num_threads); +} + +void this_cpu_list_push(struct percpu_list *list, + struct percpu_list_node *node, + int *_cpu) +{ + int cpu; + + for (;;) { + intptr_t *targetptr, newval, expect; + int ret; + + cpu = rseq_cpu_start(); + /* Load list->c[cpu].head with single-copy atomicity. */ + expect = (intptr_t)RSEQ_READ_ONCE(list->c[cpu].head); + newval = (intptr_t)node; + targetptr = (intptr_t *)&list->c[cpu].head; + node->next = (struct percpu_list_node *)expect; + ret = rseq_cmpeqv_storev(targetptr, expect, newval, cpu); + if (rseq_likely(!ret)) + break; + /* Retry if comparison fails or rseq aborts. */ + } + if (_cpu) + *_cpu = cpu; +} + +/* + * Unlike a traditional lock-less linked list; the availability of a + * rseq primitive allows us to implement pop without concerns over + * ABA-type races. + */ +struct percpu_list_node *this_cpu_list_pop(struct percpu_list *list, + int *_cpu) +{ + for (;;) { + struct percpu_list_node *head; + intptr_t *targetptr, expectnot, *load; + off_t offset; + int ret, cpu; + + cpu = rseq_cpu_start(); + targetptr = (intptr_t *)&list->c[cpu].head; + expectnot = (intptr_t)NULL; + offset = offsetof(struct percpu_list_node, next); + load = (intptr_t *)&head; + ret = rseq_cmpnev_storeoffp_load(targetptr, expectnot, + offset, load, cpu); + if (rseq_likely(!ret)) { + if (_cpu) + *_cpu = cpu; + return head; + } + if (ret > 0) + return NULL; + /* Retry if rseq aborts. */ + } +} + +/* + * __percpu_list_pop is not safe against concurrent accesses. Should + * only be used on lists that are not concurrently modified. + */ +struct percpu_list_node *__percpu_list_pop(struct percpu_list *list, int cpu) +{ + struct percpu_list_node *node; + + node = list->c[cpu].head; + if (!node) + return NULL; + list->c[cpu].head = node->next; + return node; +} + +void *test_percpu_list_thread(void *arg) +{ + int i; + struct percpu_list *list = (struct percpu_list *)arg; + + if (rseq_register_current_thread()) { + fprintf(stderr, "Error: rseq_register_current_thread(...) failed(%d): %s\n", + errno, strerror(errno)); + abort(); + } + + for (i = 0; i < 100000; i++) { + struct percpu_list_node *node; + + node = this_cpu_list_pop(list, NULL); + sched_yield(); /* encourage shuffling */ + if (node) + this_cpu_list_push(list, node, NULL); + } + + if (rseq_unregister_current_thread()) { + fprintf(stderr, "Error: rseq_unregister_current_thread(...) failed(%d): %s\n", + errno, strerror(errno)); + abort(); + } + + return NULL; +} + +/* Simultaneous modification to a per-cpu linked list from many threads. */ +void test_percpu_list(void) +{ + int i, j; + uint64_t sum = 0, expected_sum = 0; + struct percpu_list list; + pthread_t test_threads[200]; + cpu_set_t allowed_cpus; + + memset(&list, 0, sizeof(list)); + + /* Generate list entries for every usable cpu. */ + sched_getaffinity(0, sizeof(allowed_cpus), &allowed_cpus); + for (i = 0; i < CPU_SETSIZE; i++) { + if (!CPU_ISSET(i, &allowed_cpus)) + continue; + for (j = 1; j <= 100; j++) { + struct percpu_list_node *node; + + expected_sum += j; + + node = malloc(sizeof(*node)); + assert(node); + node->data = j; + node->next = list.c[i].head; + list.c[i].head = node; + } + } + + for (i = 0; i < 200; i++) + pthread_create(&test_threads[i], NULL, + test_percpu_list_thread, &list); + + for (i = 0; i < 200; i++) + pthread_join(test_threads[i], NULL); + + for (i = 0; i < CPU_SETSIZE; i++) { + struct percpu_list_node *node; + + if (!CPU_ISSET(i, &allowed_cpus)) + continue; + + while ((node = __percpu_list_pop(&list, i))) { + sum += node->data; + free(node); + } + } + + /* + * All entries should now be accounted for (unless some external + * actor is interfering with our allowed affinity while this + * test is running). + */ + assert(sum == expected_sum); +} + +int main(int argc, char **argv) +{ + if (rseq_register_current_thread()) { + fprintf(stderr, "Error: rseq_register_current_thread(...) failed(%d): %s\n", + errno, strerror(errno)); + goto error; + } + printf("spinlock\n"); + test_percpu_spinlock(); + printf("percpu_list\n"); + test_percpu_list(); + if (rseq_unregister_current_thread()) { + fprintf(stderr, "Error: rseq_unregister_current_thread(...) failed(%d): %s\n", + errno, strerror(errno)); + goto error; + } + return 0; + +error: + return -1; +} -- cgit From c960e9909d33b9780534729afc42493328ca3e18 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Sat, 2 Jun 2018 08:44:07 -0400 Subject: rseq/selftests: Provide parametrized tests "param_test" is a parametrizable restartable sequences test. See the "--help" output for usage. "param_test_benchmark" is the same as "param_test", but it removes testing book-keeping code to allow accurate benchmarks. "param_test_compare_twice" is the same as "param_test", but it performs each comparison within rseq critical section twice, thus validating invariants. If any of the second comparisons fails, an error message is printed and the test aborts. Signed-off-by: Mathieu Desnoyers Signed-off-by: Thomas Gleixner Cc: Joel Fernandes Cc: Peter Zijlstra Cc: Catalin Marinas Cc: Dave Watson Cc: Will Deacon Cc: Shuah Khan Cc: Andi Kleen Cc: linux-kselftest@vger.kernel.org Cc: "H . Peter Anvin" Cc: Chris Lameter Cc: Russell King Cc: Andrew Hunter Cc: Michael Kerrisk Cc: "Paul E . McKenney" Cc: Paul Turner Cc: Boqun Feng Cc: Josh Triplett Cc: Steven Rostedt Cc: Ben Maurer Cc: linux-api@vger.kernel.org Cc: Andy Lutomirski Cc: Andrew Morton Cc: Linus Torvalds Link: https://lkml.kernel.org/r/20180602124408.8430-16-mathieu.desnoyers@efficios.com --- tools/testing/selftests/rseq/param_test.c | 1260 +++++++++++++++++++++++++++++ 1 file changed, 1260 insertions(+) create mode 100644 tools/testing/selftests/rseq/param_test.c (limited to 'tools') diff --git a/tools/testing/selftests/rseq/param_test.c b/tools/testing/selftests/rseq/param_test.c new file mode 100644 index 000000000000..6a9f602a8718 --- /dev/null +++ b/tools/testing/selftests/rseq/param_test.c @@ -0,0 +1,1260 @@ +// SPDX-License-Identifier: LGPL-2.1 +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static inline pid_t gettid(void) +{ + return syscall(__NR_gettid); +} + +#define NR_INJECT 9 +static int loop_cnt[NR_INJECT + 1]; + +static int loop_cnt_1 asm("asm_loop_cnt_1") __attribute__((used)); +static int loop_cnt_2 asm("asm_loop_cnt_2") __attribute__((used)); +static int loop_cnt_3 asm("asm_loop_cnt_3") __attribute__((used)); +static int loop_cnt_4 asm("asm_loop_cnt_4") __attribute__((used)); +static int loop_cnt_5 asm("asm_loop_cnt_5") __attribute__((used)); +static int loop_cnt_6 asm("asm_loop_cnt_6") __attribute__((used)); + +static int opt_modulo, verbose; + +static int opt_yield, opt_signal, opt_sleep, + opt_disable_rseq, opt_threads = 200, + opt_disable_mod = 0, opt_test = 's', opt_mb = 0; + +#ifndef RSEQ_SKIP_FASTPATH +static long long opt_reps = 5000; +#else +static long long opt_reps = 100; +#endif + +static __thread __attribute__((tls_model("initial-exec"))) +unsigned int signals_delivered; + +#ifndef BENCHMARK + +static __thread __attribute__((tls_model("initial-exec"), unused)) +unsigned int yield_mod_cnt, nr_abort; + +#define printf_verbose(fmt, ...) \ + do { \ + if (verbose) \ + printf(fmt, ## __VA_ARGS__); \ + } while (0) + +#if defined(__x86_64__) || defined(__i386__) + +#define INJECT_ASM_REG "eax" + +#define RSEQ_INJECT_CLOBBER \ + , INJECT_ASM_REG + +#ifdef __i386__ + +#define RSEQ_INJECT_ASM(n) \ + "mov asm_loop_cnt_" #n ", %%" INJECT_ASM_REG "\n\t" \ + "test %%" INJECT_ASM_REG ",%%" INJECT_ASM_REG "\n\t" \ + "jz 333f\n\t" \ + "222:\n\t" \ + "dec %%" INJECT_ASM_REG "\n\t" \ + "jnz 222b\n\t" \ + "333:\n\t" + +#elif defined(__x86_64__) + +#define RSEQ_INJECT_ASM(n) \ + "lea asm_loop_cnt_" #n "(%%rip), %%" INJECT_ASM_REG "\n\t" \ + "mov (%%" INJECT_ASM_REG "), %%" INJECT_ASM_REG "\n\t" \ + "test %%" INJECT_ASM_REG ",%%" INJECT_ASM_REG "\n\t" \ + "jz 333f\n\t" \ + "222:\n\t" \ + "dec %%" INJECT_ASM_REG "\n\t" \ + "jnz 222b\n\t" \ + "333:\n\t" + +#else +#error "Unsupported architecture" +#endif + +#elif defined(__ARMEL__) + +#define RSEQ_INJECT_INPUT \ + , [loop_cnt_1]"m"(loop_cnt[1]) \ + , [loop_cnt_2]"m"(loop_cnt[2]) \ + , [loop_cnt_3]"m"(loop_cnt[3]) \ + , [loop_cnt_4]"m"(loop_cnt[4]) \ + , [loop_cnt_5]"m"(loop_cnt[5]) \ + , [loop_cnt_6]"m"(loop_cnt[6]) + +#define INJECT_ASM_REG "r4" + +#define RSEQ_INJECT_CLOBBER \ + , INJECT_ASM_REG + +#define RSEQ_INJECT_ASM(n) \ + "ldr " INJECT_ASM_REG ", %[loop_cnt_" #n "]\n\t" \ + "cmp " INJECT_ASM_REG ", #0\n\t" \ + "beq 333f\n\t" \ + "222:\n\t" \ + "subs " INJECT_ASM_REG ", #1\n\t" \ + "bne 222b\n\t" \ + "333:\n\t" + +#elif __PPC__ + +#define RSEQ_INJECT_INPUT \ + , [loop_cnt_1]"m"(loop_cnt[1]) \ + , [loop_cnt_2]"m"(loop_cnt[2]) \ + , [loop_cnt_3]"m"(loop_cnt[3]) \ + , [loop_cnt_4]"m"(loop_cnt[4]) \ + , [loop_cnt_5]"m"(loop_cnt[5]) \ + , [loop_cnt_6]"m"(loop_cnt[6]) + +#define INJECT_ASM_REG "r18" + +#define RSEQ_INJECT_CLOBBER \ + , INJECT_ASM_REG + +#define RSEQ_INJECT_ASM(n) \ + "lwz %%" INJECT_ASM_REG ", %[loop_cnt_" #n "]\n\t" \ + "cmpwi %%" INJECT_ASM_REG ", 0\n\t" \ + "beq 333f\n\t" \ + "222:\n\t" \ + "subic. %%" INJECT_ASM_REG ", %%" INJECT_ASM_REG ", 1\n\t" \ + "bne 222b\n\t" \ + "333:\n\t" +#else +#error unsupported target +#endif + +#define RSEQ_INJECT_FAILED \ + nr_abort++; + +#define RSEQ_INJECT_C(n) \ +{ \ + int loc_i, loc_nr_loops = loop_cnt[n]; \ + \ + for (loc_i = 0; loc_i < loc_nr_loops; loc_i++) { \ + rseq_barrier(); \ + } \ + if (loc_nr_loops == -1 && opt_modulo) { \ + if (yield_mod_cnt == opt_modulo - 1) { \ + if (opt_sleep > 0) \ + poll(NULL, 0, opt_sleep); \ + if (opt_yield) \ + sched_yield(); \ + if (opt_signal) \ + raise(SIGUSR1); \ + yield_mod_cnt = 0; \ + } else { \ + yield_mod_cnt++; \ + } \ + } \ +} + +#else + +#define printf_verbose(fmt, ...) + +#endif /* BENCHMARK */ + +#include "rseq.h" + +struct percpu_lock_entry { + intptr_t v; +} __attribute__((aligned(128))); + +struct percpu_lock { + struct percpu_lock_entry c[CPU_SETSIZE]; +}; + +struct test_data_entry { + intptr_t count; +} __attribute__((aligned(128))); + +struct spinlock_test_data { + struct percpu_lock lock; + struct test_data_entry c[CPU_SETSIZE]; +}; + +struct spinlock_thread_test_data { + struct spinlock_test_data *data; + long long reps; + int reg; +}; + +struct inc_test_data { + struct test_data_entry c[CPU_SETSIZE]; +}; + +struct inc_thread_test_data { + struct inc_test_data *data; + long long reps; + int reg; +}; + +struct percpu_list_node { + intptr_t data; + struct percpu_list_node *next; +}; + +struct percpu_list_entry { + struct percpu_list_node *head; +} __attribute__((aligned(128))); + +struct percpu_list { + struct percpu_list_entry c[CPU_SETSIZE]; +}; + +#define BUFFER_ITEM_PER_CPU 100 + +struct percpu_buffer_node { + intptr_t data; +}; + +struct percpu_buffer_entry { + intptr_t offset; + intptr_t buflen; + struct percpu_buffer_node **array; +} __attribute__((aligned(128))); + +struct percpu_buffer { + struct percpu_buffer_entry c[CPU_SETSIZE]; +}; + +#define MEMCPY_BUFFER_ITEM_PER_CPU 100 + +struct percpu_memcpy_buffer_node { + intptr_t data1; + uint64_t data2; +}; + +struct percpu_memcpy_buffer_entry { + intptr_t offset; + intptr_t buflen; + struct percpu_memcpy_buffer_node *array; +} __attribute__((aligned(128))); + +struct percpu_memcpy_buffer { + struct percpu_memcpy_buffer_entry c[CPU_SETSIZE]; +}; + +/* A simple percpu spinlock. Grabs lock on current cpu. */ +static int rseq_this_cpu_lock(struct percpu_lock *lock) +{ + int cpu; + + for (;;) { + int ret; + + cpu = rseq_cpu_start(); + ret = rseq_cmpeqv_storev(&lock->c[cpu].v, + 0, 1, cpu); + if (rseq_likely(!ret)) + break; + /* Retry if comparison fails or rseq aborts. */ + } + /* + * Acquire semantic when taking lock after control dependency. + * Matches rseq_smp_store_release(). + */ + rseq_smp_acquire__after_ctrl_dep(); + return cpu; +} + +static void rseq_percpu_unlock(struct percpu_lock *lock, int cpu) +{ + assert(lock->c[cpu].v == 1); + /* + * Release lock, with release semantic. Matches + * rseq_smp_acquire__after_ctrl_dep(). + */ + rseq_smp_store_release(&lock->c[cpu].v, 0); +} + +void *test_percpu_spinlock_thread(void *arg) +{ + struct spinlock_thread_test_data *thread_data = arg; + struct spinlock_test_data *data = thread_data->data; + long long i, reps; + + if (!opt_disable_rseq && thread_data->reg && + rseq_register_current_thread()) + abort(); + reps = thread_data->reps; + for (i = 0; i < reps; i++) { + int cpu = rseq_cpu_start(); + + cpu = rseq_this_cpu_lock(&data->lock); + data->c[cpu].count++; + rseq_percpu_unlock(&data->lock, cpu); +#ifndef BENCHMARK + if (i != 0 && !(i % (reps / 10))) + printf_verbose("tid %d: count %lld\n", (int) gettid(), i); +#endif + } + printf_verbose("tid %d: number of rseq abort: %d, signals delivered: %u\n", + (int) gettid(), nr_abort, signals_delivered); + if (!opt_disable_rseq && thread_data->reg && + rseq_unregister_current_thread()) + abort(); + return NULL; +} + +/* + * A simple test which implements a sharded counter using a per-cpu + * lock. Obviously real applications might prefer to simply use a + * per-cpu increment; however, this is reasonable for a test and the + * lock can be extended to synchronize more complicated operations. + */ +void test_percpu_spinlock(void) +{ + const int num_threads = opt_threads; + int i, ret; + uint64_t sum; + pthread_t test_threads[num_threads]; + struct spinlock_test_data data; + struct spinlock_thread_test_data thread_data[num_threads]; + + memset(&data, 0, sizeof(data)); + for (i = 0; i < num_threads; i++) { + thread_data[i].reps = opt_reps; + if (opt_disable_mod <= 0 || (i % opt_disable_mod)) + thread_data[i].reg = 1; + else + thread_data[i].reg = 0; + thread_data[i].data = &data; + ret = pthread_create(&test_threads[i], NULL, + test_percpu_spinlock_thread, + &thread_data[i]); + if (ret) { + errno = ret; + perror("pthread_create"); + abort(); + } + } + + for (i = 0; i < num_threads; i++) { + ret = pthread_join(test_threads[i], NULL); + if (ret) { + errno = ret; + perror("pthread_join"); + abort(); + } + } + + sum = 0; + for (i = 0; i < CPU_SETSIZE; i++) + sum += data.c[i].count; + + assert(sum == (uint64_t)opt_reps * num_threads); +} + +void *test_percpu_inc_thread(void *arg) +{ + struct inc_thread_test_data *thread_data = arg; + struct inc_test_data *data = thread_data->data; + long long i, reps; + + if (!opt_disable_rseq && thread_data->reg && + rseq_register_current_thread()) + abort(); + reps = thread_data->reps; + for (i = 0; i < reps; i++) { + int ret; + + do { + int cpu; + + cpu = rseq_cpu_start(); + ret = rseq_addv(&data->c[cpu].count, 1, cpu); + } while (rseq_unlikely(ret)); +#ifndef BENCHMARK + if (i != 0 && !(i % (reps / 10))) + printf_verbose("tid %d: count %lld\n", (int) gettid(), i); +#endif + } + printf_verbose("tid %d: number of rseq abort: %d, signals delivered: %u\n", + (int) gettid(), nr_abort, signals_delivered); + if (!opt_disable_rseq && thread_data->reg && + rseq_unregister_current_thread()) + abort(); + return NULL; +} + +void test_percpu_inc(void) +{ + const int num_threads = opt_threads; + int i, ret; + uint64_t sum; + pthread_t test_threads[num_threads]; + struct inc_test_data data; + struct inc_thread_test_data thread_data[num_threads]; + + memset(&data, 0, sizeof(data)); + for (i = 0; i < num_threads; i++) { + thread_data[i].reps = opt_reps; + if (opt_disable_mod <= 0 || (i % opt_disable_mod)) + thread_data[i].reg = 1; + else + thread_data[i].reg = 0; + thread_data[i].data = &data; + ret = pthread_create(&test_threads[i], NULL, + test_percpu_inc_thread, + &thread_data[i]); + if (ret) { + errno = ret; + perror("pthread_create"); + abort(); + } + } + + for (i = 0; i < num_threads; i++) { + ret = pthread_join(test_threads[i], NULL); + if (ret) { + errno = ret; + perror("pthread_join"); + abort(); + } + } + + sum = 0; + for (i = 0; i < CPU_SETSIZE; i++) + sum += data.c[i].count; + + assert(sum == (uint64_t)opt_reps * num_threads); +} + +void this_cpu_list_push(struct percpu_list *list, + struct percpu_list_node *node, + int *_cpu) +{ + int cpu; + + for (;;) { + intptr_t *targetptr, newval, expect; + int ret; + + cpu = rseq_cpu_start(); + /* Load list->c[cpu].head with single-copy atomicity. */ + expect = (intptr_t)RSEQ_READ_ONCE(list->c[cpu].head); + newval = (intptr_t)node; + targetptr = (intptr_t *)&list->c[cpu].head; + node->next = (struct percpu_list_node *)expect; + ret = rseq_cmpeqv_storev(targetptr, expect, newval, cpu); + if (rseq_likely(!ret)) + break; + /* Retry if comparison fails or rseq aborts. */ + } + if (_cpu) + *_cpu = cpu; +} + +/* + * Unlike a traditional lock-less linked list; the availability of a + * rseq primitive allows us to implement pop without concerns over + * ABA-type races. + */ +struct percpu_list_node *this_cpu_list_pop(struct percpu_list *list, + int *_cpu) +{ + struct percpu_list_node *node = NULL; + int cpu; + + for (;;) { + struct percpu_list_node *head; + intptr_t *targetptr, expectnot, *load; + off_t offset; + int ret; + + cpu = rseq_cpu_start(); + targetptr = (intptr_t *)&list->c[cpu].head; + expectnot = (intptr_t)NULL; + offset = offsetof(struct percpu_list_node, next); + load = (intptr_t *)&head; + ret = rseq_cmpnev_storeoffp_load(targetptr, expectnot, + offset, load, cpu); + if (rseq_likely(!ret)) { + node = head; + break; + } + if (ret > 0) + break; + /* Retry if rseq aborts. */ + } + if (_cpu) + *_cpu = cpu; + return node; +} + +/* + * __percpu_list_pop is not safe against concurrent accesses. Should + * only be used on lists that are not concurrently modified. + */ +struct percpu_list_node *__percpu_list_pop(struct percpu_list *list, int cpu) +{ + struct percpu_list_node *node; + + node = list->c[cpu].head; + if (!node) + return NULL; + list->c[cpu].head = node->next; + return node; +} + +void *test_percpu_list_thread(void *arg) +{ + long long i, reps; + struct percpu_list *list = (struct percpu_list *)arg; + + if (!opt_disable_rseq && rseq_register_current_thread()) + abort(); + + reps = opt_reps; + for (i = 0; i < reps; i++) { + struct percpu_list_node *node; + + node = this_cpu_list_pop(list, NULL); + if (opt_yield) + sched_yield(); /* encourage shuffling */ + if (node) + this_cpu_list_push(list, node, NULL); + } + + printf_verbose("tid %d: number of rseq abort: %d, signals delivered: %u\n", + (int) gettid(), nr_abort, signals_delivered); + if (!opt_disable_rseq && rseq_unregister_current_thread()) + abort(); + + return NULL; +} + +/* Simultaneous modification to a per-cpu linked list from many threads. */ +void test_percpu_list(void) +{ + const int num_threads = opt_threads; + int i, j, ret; + uint64_t sum = 0, expected_sum = 0; + struct percpu_list list; + pthread_t test_threads[num_threads]; + cpu_set_t allowed_cpus; + + memset(&list, 0, sizeof(list)); + + /* Generate list entries for every usable cpu. */ + sched_getaffinity(0, sizeof(allowed_cpus), &allowed_cpus); + for (i = 0; i < CPU_SETSIZE; i++) { + if (!CPU_ISSET(i, &allowed_cpus)) + continue; + for (j = 1; j <= 100; j++) { + struct percpu_list_node *node; + + expected_sum += j; + + node = malloc(sizeof(*node)); + assert(node); + node->data = j; + node->next = list.c[i].head; + list.c[i].head = node; + } + } + + for (i = 0; i < num_threads; i++) { + ret = pthread_create(&test_threads[i], NULL, + test_percpu_list_thread, &list); + if (ret) { + errno = ret; + perror("pthread_create"); + abort(); + } + } + + for (i = 0; i < num_threads; i++) { + ret = pthread_join(test_threads[i], NULL); + if (ret) { + errno = ret; + perror("pthread_join"); + abort(); + } + } + + for (i = 0; i < CPU_SETSIZE; i++) { + struct percpu_list_node *node; + + if (!CPU_ISSET(i, &allowed_cpus)) + continue; + + while ((node = __percpu_list_pop(&list, i))) { + sum += node->data; + free(node); + } + } + + /* + * All entries should now be accounted for (unless some external + * actor is interfering with our allowed affinity while this + * test is running). + */ + assert(sum == expected_sum); +} + +bool this_cpu_buffer_push(struct percpu_buffer *buffer, + struct percpu_buffer_node *node, + int *_cpu) +{ + bool result = false; + int cpu; + + for (;;) { + intptr_t *targetptr_spec, newval_spec; + intptr_t *targetptr_final, newval_final; + intptr_t offset; + int ret; + + cpu = rseq_cpu_start(); + offset = RSEQ_READ_ONCE(buffer->c[cpu].offset); + if (offset == buffer->c[cpu].buflen) + break; + newval_spec = (intptr_t)node; + targetptr_spec = (intptr_t *)&buffer->c[cpu].array[offset]; + newval_final = offset + 1; + targetptr_final = &buffer->c[cpu].offset; + if (opt_mb) + ret = rseq_cmpeqv_trystorev_storev_release( + targetptr_final, offset, targetptr_spec, + newval_spec, newval_final, cpu); + else + ret = rseq_cmpeqv_trystorev_storev(targetptr_final, + offset, targetptr_spec, newval_spec, + newval_final, cpu); + if (rseq_likely(!ret)) { + result = true; + break; + } + /* Retry if comparison fails or rseq aborts. */ + } + if (_cpu) + *_cpu = cpu; + return result; +} + +struct percpu_buffer_node *this_cpu_buffer_pop(struct percpu_buffer *buffer, + int *_cpu) +{ + struct percpu_buffer_node *head; + int cpu; + + for (;;) { + intptr_t *targetptr, newval; + intptr_t offset; + int ret; + + cpu = rseq_cpu_start(); + /* Load offset with single-copy atomicity. */ + offset = RSEQ_READ_ONCE(buffer->c[cpu].offset); + if (offset == 0) { + head = NULL; + break; + } + head = RSEQ_READ_ONCE(buffer->c[cpu].array[offset - 1]); + newval = offset - 1; + targetptr = (intptr_t *)&buffer->c[cpu].offset; + ret = rseq_cmpeqv_cmpeqv_storev(targetptr, offset, + (intptr_t *)&buffer->c[cpu].array[offset - 1], + (intptr_t)head, newval, cpu); + if (rseq_likely(!ret)) + break; + /* Retry if comparison fails or rseq aborts. */ + } + if (_cpu) + *_cpu = cpu; + return head; +} + +/* + * __percpu_buffer_pop is not safe against concurrent accesses. Should + * only be used on buffers that are not concurrently modified. + */ +struct percpu_buffer_node *__percpu_buffer_pop(struct percpu_buffer *buffer, + int cpu) +{ + struct percpu_buffer_node *head; + intptr_t offset; + + offset = buffer->c[cpu].offset; + if (offset == 0) + return NULL; + head = buffer->c[cpu].array[offset - 1]; + buffer->c[cpu].offset = offset - 1; + return head; +} + +void *test_percpu_buffer_thread(void *arg) +{ + long long i, reps; + struct percpu_buffer *buffer = (struct percpu_buffer *)arg; + + if (!opt_disable_rseq && rseq_register_current_thread()) + abort(); + + reps = opt_reps; + for (i = 0; i < reps; i++) { + struct percpu_buffer_node *node; + + node = this_cpu_buffer_pop(buffer, NULL); + if (opt_yield) + sched_yield(); /* encourage shuffling */ + if (node) { + if (!this_cpu_buffer_push(buffer, node, NULL)) { + /* Should increase buffer size. */ + abort(); + } + } + } + + printf_verbose("tid %d: number of rseq abort: %d, signals delivered: %u\n", + (int) gettid(), nr_abort, signals_delivered); + if (!opt_disable_rseq && rseq_unregister_current_thread()) + abort(); + + return NULL; +} + +/* Simultaneous modification to a per-cpu buffer from many threads. */ +void test_percpu_buffer(void) +{ + const int num_threads = opt_threads; + int i, j, ret; + uint64_t sum = 0, expected_sum = 0; + struct percpu_buffer buffer; + pthread_t test_threads[num_threads]; + cpu_set_t allowed_cpus; + + memset(&buffer, 0, sizeof(buffer)); + + /* Generate list entries for every usable cpu. */ + sched_getaffinity(0, sizeof(allowed_cpus), &allowed_cpus); + for (i = 0; i < CPU_SETSIZE; i++) { + if (!CPU_ISSET(i, &allowed_cpus)) + continue; + /* Worse-case is every item in same CPU. */ + buffer.c[i].array = + malloc(sizeof(*buffer.c[i].array) * CPU_SETSIZE * + BUFFER_ITEM_PER_CPU); + assert(buffer.c[i].array); + buffer.c[i].buflen = CPU_SETSIZE * BUFFER_ITEM_PER_CPU; + for (j = 1; j <= BUFFER_ITEM_PER_CPU; j++) { + struct percpu_buffer_node *node; + + expected_sum += j; + + /* + * We could theoretically put the word-sized + * "data" directly in the buffer. However, we + * want to model objects that would not fit + * within a single word, so allocate an object + * for each node. + */ + node = malloc(sizeof(*node)); + assert(node); + node->data = j; + buffer.c[i].array[j - 1] = node; + buffer.c[i].offset++; + } + } + + for (i = 0; i < num_threads; i++) { + ret = pthread_create(&test_threads[i], NULL, + test_percpu_buffer_thread, &buffer); + if (ret) { + errno = ret; + perror("pthread_create"); + abort(); + } + } + + for (i = 0; i < num_threads; i++) { + ret = pthread_join(test_threads[i], NULL); + if (ret) { + errno = ret; + perror("pthread_join"); + abort(); + } + } + + for (i = 0; i < CPU_SETSIZE; i++) { + struct percpu_buffer_node *node; + + if (!CPU_ISSET(i, &allowed_cpus)) + continue; + + while ((node = __percpu_buffer_pop(&buffer, i))) { + sum += node->data; + free(node); + } + free(buffer.c[i].array); + } + + /* + * All entries should now be accounted for (unless some external + * actor is interfering with our allowed affinity while this + * test is running). + */ + assert(sum == expected_sum); +} + +bool this_cpu_memcpy_buffer_push(struct percpu_memcpy_buffer *buffer, + struct percpu_memcpy_buffer_node item, + int *_cpu) +{ + bool result = false; + int cpu; + + for (;;) { + intptr_t *targetptr_final, newval_final, offset; + char *destptr, *srcptr; + size_t copylen; + int ret; + + cpu = rseq_cpu_start(); + /* Load offset with single-copy atomicity. */ + offset = RSEQ_READ_ONCE(buffer->c[cpu].offset); + if (offset == buffer->c[cpu].buflen) + break; + destptr = (char *)&buffer->c[cpu].array[offset]; + srcptr = (char *)&item; + /* copylen must be <= 4kB. */ + copylen = sizeof(item); + newval_final = offset + 1; + targetptr_final = &buffer->c[cpu].offset; + if (opt_mb) + ret = rseq_cmpeqv_trymemcpy_storev_release( + targetptr_final, offset, + destptr, srcptr, copylen, + newval_final, cpu); + else + ret = rseq_cmpeqv_trymemcpy_storev(targetptr_final, + offset, destptr, srcptr, copylen, + newval_final, cpu); + if (rseq_likely(!ret)) { + result = true; + break; + } + /* Retry if comparison fails or rseq aborts. */ + } + if (_cpu) + *_cpu = cpu; + return result; +} + +bool this_cpu_memcpy_buffer_pop(struct percpu_memcpy_buffer *buffer, + struct percpu_memcpy_buffer_node *item, + int *_cpu) +{ + bool result = false; + int cpu; + + for (;;) { + intptr_t *targetptr_final, newval_final, offset; + char *destptr, *srcptr; + size_t copylen; + int ret; + + cpu = rseq_cpu_start(); + /* Load offset with single-copy atomicity. */ + offset = RSEQ_READ_ONCE(buffer->c[cpu].offset); + if (offset == 0) + break; + destptr = (char *)item; + srcptr = (char *)&buffer->c[cpu].array[offset - 1]; + /* copylen must be <= 4kB. */ + copylen = sizeof(*item); + newval_final = offset - 1; + targetptr_final = &buffer->c[cpu].offset; + ret = rseq_cmpeqv_trymemcpy_storev(targetptr_final, + offset, destptr, srcptr, copylen, + newval_final, cpu); + if (rseq_likely(!ret)) { + result = true; + break; + } + /* Retry if comparison fails or rseq aborts. */ + } + if (_cpu) + *_cpu = cpu; + return result; +} + +/* + * __percpu_memcpy_buffer_pop is not safe against concurrent accesses. Should + * only be used on buffers that are not concurrently modified. + */ +bool __percpu_memcpy_buffer_pop(struct percpu_memcpy_buffer *buffer, + struct percpu_memcpy_buffer_node *item, + int cpu) +{ + intptr_t offset; + + offset = buffer->c[cpu].offset; + if (offset == 0) + return false; + memcpy(item, &buffer->c[cpu].array[offset - 1], sizeof(*item)); + buffer->c[cpu].offset = offset - 1; + return true; +} + +void *test_percpu_memcpy_buffer_thread(void *arg) +{ + long long i, reps; + struct percpu_memcpy_buffer *buffer = (struct percpu_memcpy_buffer *)arg; + + if (!opt_disable_rseq && rseq_register_current_thread()) + abort(); + + reps = opt_reps; + for (i = 0; i < reps; i++) { + struct percpu_memcpy_buffer_node item; + bool result; + + result = this_cpu_memcpy_buffer_pop(buffer, &item, NULL); + if (opt_yield) + sched_yield(); /* encourage shuffling */ + if (result) { + if (!this_cpu_memcpy_buffer_push(buffer, item, NULL)) { + /* Should increase buffer size. */ + abort(); + } + } + } + + printf_verbose("tid %d: number of rseq abort: %d, signals delivered: %u\n", + (int) gettid(), nr_abort, signals_delivered); + if (!opt_disable_rseq && rseq_unregister_current_thread()) + abort(); + + return NULL; +} + +/* Simultaneous modification to a per-cpu buffer from many threads. */ +void test_percpu_memcpy_buffer(void) +{ + const int num_threads = opt_threads; + int i, j, ret; + uint64_t sum = 0, expected_sum = 0; + struct percpu_memcpy_buffer buffer; + pthread_t test_threads[num_threads]; + cpu_set_t allowed_cpus; + + memset(&buffer, 0, sizeof(buffer)); + + /* Generate list entries for every usable cpu. */ + sched_getaffinity(0, sizeof(allowed_cpus), &allowed_cpus); + for (i = 0; i < CPU_SETSIZE; i++) { + if (!CPU_ISSET(i, &allowed_cpus)) + continue; + /* Worse-case is every item in same CPU. */ + buffer.c[i].array = + malloc(sizeof(*buffer.c[i].array) * CPU_SETSIZE * + MEMCPY_BUFFER_ITEM_PER_CPU); + assert(buffer.c[i].array); + buffer.c[i].buflen = CPU_SETSIZE * MEMCPY_BUFFER_ITEM_PER_CPU; + for (j = 1; j <= MEMCPY_BUFFER_ITEM_PER_CPU; j++) { + expected_sum += 2 * j + 1; + + /* + * We could theoretically put the word-sized + * "data" directly in the buffer. However, we + * want to model objects that would not fit + * within a single word, so allocate an object + * for each node. + */ + buffer.c[i].array[j - 1].data1 = j; + buffer.c[i].array[j - 1].data2 = j + 1; + buffer.c[i].offset++; + } + } + + for (i = 0; i < num_threads; i++) { + ret = pthread_create(&test_threads[i], NULL, + test_percpu_memcpy_buffer_thread, + &buffer); + if (ret) { + errno = ret; + perror("pthread_create"); + abort(); + } + } + + for (i = 0; i < num_threads; i++) { + ret = pthread_join(test_threads[i], NULL); + if (ret) { + errno = ret; + perror("pthread_join"); + abort(); + } + } + + for (i = 0; i < CPU_SETSIZE; i++) { + struct percpu_memcpy_buffer_node item; + + if (!CPU_ISSET(i, &allowed_cpus)) + continue; + + while (__percpu_memcpy_buffer_pop(&buffer, &item, i)) { + sum += item.data1; + sum += item.data2; + } + free(buffer.c[i].array); + } + + /* + * All entries should now be accounted for (unless some external + * actor is interfering with our allowed affinity while this + * test is running). + */ + assert(sum == expected_sum); +} + +static void test_signal_interrupt_handler(int signo) +{ + signals_delivered++; +} + +static int set_signal_handler(void) +{ + int ret = 0; + struct sigaction sa; + sigset_t sigset; + + ret = sigemptyset(&sigset); + if (ret < 0) { + perror("sigemptyset"); + return ret; + } + + sa.sa_handler = test_signal_interrupt_handler; + sa.sa_mask = sigset; + sa.sa_flags = 0; + ret = sigaction(SIGUSR1, &sa, NULL); + if (ret < 0) { + perror("sigaction"); + return ret; + } + + printf_verbose("Signal handler set for SIGUSR1\n"); + + return ret; +} + +static void show_usage(int argc, char **argv) +{ + printf("Usage : %s \n", + argv[0]); + printf("OPTIONS:\n"); + printf(" [-1 loops] Number of loops for delay injection 1\n"); + printf(" [-2 loops] Number of loops for delay injection 2\n"); + printf(" [-3 loops] Number of loops for delay injection 3\n"); + printf(" [-4 loops] Number of loops for delay injection 4\n"); + printf(" [-5 loops] Number of loops for delay injection 5\n"); + printf(" [-6 loops] Number of loops for delay injection 6\n"); + printf(" [-7 loops] Number of loops for delay injection 7 (-1 to enable -m)\n"); + printf(" [-8 loops] Number of loops for delay injection 8 (-1 to enable -m)\n"); + printf(" [-9 loops] Number of loops for delay injection 9 (-1 to enable -m)\n"); + printf(" [-m N] Yield/sleep/kill every modulo N (default 0: disabled) (>= 0)\n"); + printf(" [-y] Yield\n"); + printf(" [-k] Kill thread with signal\n"); + printf(" [-s S] S: =0: disabled (default), >0: sleep time (ms)\n"); + printf(" [-t N] Number of threads (default 200)\n"); + printf(" [-r N] Number of repetitions per thread (default 5000)\n"); + printf(" [-d] Disable rseq system call (no initialization)\n"); + printf(" [-D M] Disable rseq for each M threads\n"); + printf(" [-T test] Choose test: (s)pinlock, (l)ist, (b)uffer, (m)emcpy, (i)ncrement\n"); + printf(" [-M] Push into buffer and memcpy buffer with memory barriers.\n"); + printf(" [-v] Verbose output.\n"); + printf(" [-h] Show this help.\n"); + printf("\n"); +} + +int main(int argc, char **argv) +{ + int i; + + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') + continue; + switch (argv[i][1]) { + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (argc < i + 2) { + show_usage(argc, argv); + goto error; + } + loop_cnt[argv[i][1] - '0'] = atol(argv[i + 1]); + i++; + break; + case 'm': + if (argc < i + 2) { + show_usage(argc, argv); + goto error; + } + opt_modulo = atol(argv[i + 1]); + if (opt_modulo < 0) { + show_usage(argc, argv); + goto error; + } + i++; + break; + case 's': + if (argc < i + 2) { + show_usage(argc, argv); + goto error; + } + opt_sleep = atol(argv[i + 1]); + if (opt_sleep < 0) { + show_usage(argc, argv); + goto error; + } + i++; + break; + case 'y': + opt_yield = 1; + break; + case 'k': + opt_signal = 1; + break; + case 'd': + opt_disable_rseq = 1; + break; + case 'D': + if (argc < i + 2) { + show_usage(argc, argv); + goto error; + } + opt_disable_mod = atol(argv[i + 1]); + if (opt_disable_mod < 0) { + show_usage(argc, argv); + goto error; + } + i++; + break; + case 't': + if (argc < i + 2) { + show_usage(argc, argv); + goto error; + } + opt_threads = atol(argv[i + 1]); + if (opt_threads < 0) { + show_usage(argc, argv); + goto error; + } + i++; + break; + case 'r': + if (argc < i + 2) { + show_usage(argc, argv); + goto error; + } + opt_reps = atoll(argv[i + 1]); + if (opt_reps < 0) { + show_usage(argc, argv); + goto error; + } + i++; + break; + case 'h': + show_usage(argc, argv); + goto end; + case 'T': + if (argc < i + 2) { + show_usage(argc, argv); + goto error; + } + opt_test = *argv[i + 1]; + switch (opt_test) { + case 's': + case 'l': + case 'i': + case 'b': + case 'm': + break; + default: + show_usage(argc, argv); + goto error; + } + i++; + break; + case 'v': + verbose = 1; + break; + case 'M': + opt_mb = 1; + break; + default: + show_usage(argc, argv); + goto error; + } + } + + loop_cnt_1 = loop_cnt[1]; + loop_cnt_2 = loop_cnt[2]; + loop_cnt_3 = loop_cnt[3]; + loop_cnt_4 = loop_cnt[4]; + loop_cnt_5 = loop_cnt[5]; + loop_cnt_6 = loop_cnt[6]; + + if (set_signal_handler()) + goto error; + + if (!opt_disable_rseq && rseq_register_current_thread()) + goto error; + switch (opt_test) { + case 's': + printf_verbose("spinlock\n"); + test_percpu_spinlock(); + break; + case 'l': + printf_verbose("linked list\n"); + test_percpu_list(); + break; + case 'b': + printf_verbose("buffer\n"); + test_percpu_buffer(); + break; + case 'm': + printf_verbose("memcpy buffer\n"); + test_percpu_memcpy_buffer(); + break; + case 'i': + printf_verbose("counter increment\n"); + test_percpu_inc(); + break; + } + if (!opt_disable_rseq && rseq_unregister_current_thread()) + abort(); +end: + return 0; + +error: + return -1; +} -- cgit From ccba8b64452b8dbf2c9670de026d00f519bb5da0 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Sat, 2 Jun 2018 08:44:08 -0400 Subject: rseq/selftests: Provide Makefile, scripts, gitignore A run_param_test.sh script runs many variants of the parametrizable tests. Wire up the rseq Makefile, add directory entry into MAINTAINERS file. Signed-off-by: Mathieu Desnoyers Signed-off-by: Thomas Gleixner Cc: Joel Fernandes Cc: Peter Zijlstra Cc: Catalin Marinas Cc: Dave Watson Cc: Will Deacon Cc: Shuah Khan Cc: Andi Kleen Cc: linux-kselftest@vger.kernel.org Cc: "H . Peter Anvin" Cc: Chris Lameter Cc: Russell King Cc: Andrew Hunter Cc: Michael Kerrisk Cc: "Paul E . McKenney" Cc: Paul Turner Cc: Boqun Feng Cc: Josh Triplett Cc: Steven Rostedt Cc: Ben Maurer Cc: linux-api@vger.kernel.org Cc: Andy Lutomirski Cc: Andrew Morton Cc: Linus Torvalds Link: https://lkml.kernel.org/r/20180602124408.8430-17-mathieu.desnoyers@efficios.com --- MAINTAINERS | 1 + tools/testing/selftests/Makefile | 1 + tools/testing/selftests/rseq/.gitignore | 6 ++ tools/testing/selftests/rseq/Makefile | 30 ++++++ tools/testing/selftests/rseq/run_param_test.sh | 121 +++++++++++++++++++++++++ 5 files changed, 159 insertions(+) create mode 100644 tools/testing/selftests/rseq/.gitignore create mode 100644 tools/testing/selftests/rseq/Makefile create mode 100644 tools/testing/selftests/rseq/run_param_test.sh (limited to 'tools') diff --git a/MAINTAINERS b/MAINTAINERS index a384243d911b..e743b9dab0c1 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -11986,6 +11986,7 @@ S: Supported F: kernel/rseq.c F: include/uapi/linux/rseq.h F: include/trace/events/rseq.h +F: tools/testing/selftests/rseq/ RFKILL M: Johannes Berg diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 32aafa92074c..593fb44c9cd4 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -28,6 +28,7 @@ TARGETS += powerpc TARGETS += proc TARGETS += pstore TARGETS += ptrace +TARGETS += rseq TARGETS += seccomp TARGETS += sigaltstack TARGETS += size diff --git a/tools/testing/selftests/rseq/.gitignore b/tools/testing/selftests/rseq/.gitignore new file mode 100644 index 000000000000..cc610da7e369 --- /dev/null +++ b/tools/testing/selftests/rseq/.gitignore @@ -0,0 +1,6 @@ +basic_percpu_ops_test +basic_test +basic_rseq_op_test +param_test +param_test_benchmark +param_test_compare_twice diff --git a/tools/testing/selftests/rseq/Makefile b/tools/testing/selftests/rseq/Makefile new file mode 100644 index 000000000000..c30c52e1d0d2 --- /dev/null +++ b/tools/testing/selftests/rseq/Makefile @@ -0,0 +1,30 @@ +# SPDX-License-Identifier: GPL-2.0+ OR MIT +CFLAGS += -O2 -Wall -g -I./ -I../../../../usr/include/ -L./ -Wl,-rpath=./ +LDLIBS += -lpthread + +# Own dependencies because we only want to build against 1st prerequisite, but +# still track changes to header files and depend on shared object. +OVERRIDE_TARGETS = 1 + +TEST_GEN_PROGS = basic_test basic_percpu_ops_test param_test \ + param_test_benchmark param_test_compare_twice + +TEST_GEN_PROGS_EXTENDED = librseq.so + +TEST_PROGS = run_param_test.sh + +include ../lib.mk + +$(OUTPUT)/librseq.so: rseq.c rseq.h rseq-*.h + $(CC) $(CFLAGS) -shared -fPIC $< $(LDLIBS) -o $@ + +$(OUTPUT)/%: %.c $(TEST_GEN_PROGS_EXTENDED) rseq.h rseq-*.h + $(CC) $(CFLAGS) $< $(LDLIBS) -lrseq -o $@ + +$(OUTPUT)/param_test_benchmark: param_test.c $(TEST_GEN_PROGS_EXTENDED) \ + rseq.h rseq-*.h + $(CC) $(CFLAGS) -DBENCHMARK $< $(LDLIBS) -lrseq -o $@ + +$(OUTPUT)/param_test_compare_twice: param_test.c $(TEST_GEN_PROGS_EXTENDED) \ + rseq.h rseq-*.h + $(CC) $(CFLAGS) -DRSEQ_COMPARE_TWICE $< $(LDLIBS) -lrseq -o $@ diff --git a/tools/testing/selftests/rseq/run_param_test.sh b/tools/testing/selftests/rseq/run_param_test.sh new file mode 100644 index 000000000000..3acd6d75ff9f --- /dev/null +++ b/tools/testing/selftests/rseq/run_param_test.sh @@ -0,0 +1,121 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0+ or MIT + +EXTRA_ARGS=${@} + +OLDIFS="$IFS" +IFS=$'\n' +TEST_LIST=( + "-T s" + "-T l" + "-T b" + "-T b -M" + "-T m" + "-T m -M" + "-T i" +) + +TEST_NAME=( + "spinlock" + "list" + "buffer" + "buffer with barrier" + "memcpy" + "memcpy with barrier" + "increment" +) +IFS="$OLDIFS" + +REPS=1000 +SLOW_REPS=100 + +function do_tests() +{ + local i=0 + while [ "$i" -lt "${#TEST_LIST[@]}" ]; do + echo "Running test ${TEST_NAME[$i]}" + ./param_test ${TEST_LIST[$i]} -r ${REPS} ${@} ${EXTRA_ARGS} || exit 1 + echo "Running compare-twice test ${TEST_NAME[$i]}" + ./param_test_compare_twice ${TEST_LIST[$i]} -r ${REPS} ${@} ${EXTRA_ARGS} || exit 1 + let "i++" + done +} + +echo "Default parameters" +do_tests + +echo "Loop injection: 10000 loops" + +OLDIFS="$IFS" +IFS=$'\n' +INJECT_LIST=( + "1" + "2" + "3" + "4" + "5" + "6" + "7" + "8" + "9" +) +IFS="$OLDIFS" + +NR_LOOPS=10000 + +i=0 +while [ "$i" -lt "${#INJECT_LIST[@]}" ]; do + echo "Injecting at <${INJECT_LIST[$i]}>" + do_tests -${INJECT_LIST[i]} ${NR_LOOPS} + let "i++" +done +NR_LOOPS= + +function inject_blocking() +{ + OLDIFS="$IFS" + IFS=$'\n' + INJECT_LIST=( + "7" + "8" + "9" + ) + IFS="$OLDIFS" + + NR_LOOPS=-1 + + i=0 + while [ "$i" -lt "${#INJECT_LIST[@]}" ]; do + echo "Injecting at <${INJECT_LIST[$i]}>" + do_tests -${INJECT_LIST[i]} -1 ${@} + let "i++" + done + NR_LOOPS= +} + +echo "Yield injection (25%)" +inject_blocking -m 4 -y + +echo "Yield injection (50%)" +inject_blocking -m 2 -y + +echo "Yield injection (100%)" +inject_blocking -m 1 -y + +echo "Kill injection (25%)" +inject_blocking -m 4 -k + +echo "Kill injection (50%)" +inject_blocking -m 2 -k + +echo "Kill injection (100%)" +inject_blocking -m 1 -k + +echo "Sleep injection (1ms, 25%)" +inject_blocking -m 4 -s 1 + +echo "Sleep injection (1ms, 50%)" +inject_blocking -m 2 -s 1 + +echo "Sleep injection (1ms, 100%)" +inject_blocking -m 1 -s 1 -- cgit From cd77849a69cf5d81a86dd88dac7a594a67cb5c87 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Fri, 1 Jun 2018 07:23:51 -0500 Subject: objtool: Fix GCC 8 cold subfunction detection for aliased functions The kbuild test robot reported the following issue: kernel/time/posix-stubs.o: warning: objtool: sys_ni_posix_timers.cold.1()+0x0: unreachable instruction This file creates symbol aliases for the sys_ni_posix_timers() function. So there are multiple ELF function symbols for the same function: 23: 0000000000000150 26 FUNC GLOBAL DEFAULT 1 __x64_sys_timer_create 24: 0000000000000150 26 FUNC GLOBAL DEFAULT 1 sys_ni_posix_timers 25: 0000000000000150 26 FUNC GLOBAL DEFAULT 1 __ia32_sys_timer_create 26: 0000000000000150 26 FUNC GLOBAL DEFAULT 1 __x64_sys_timer_gettime Here's the corresponding cold subfunction: 11: 0000000000000000 45 FUNC LOCAL DEFAULT 6 sys_ni_posix_timers.cold.1 When analyzing overlapping functions, objtool only looks at the first one in the symbol list. The rest of the functions are basically ignored because they point to instructions which have already been analyzed. So in this case it analyzes the __x64_sys_timer_create() function, but then it fails to recognize that its cold subfunction is sys_ni_posix_timers.cold.1(), because the names are different. Make the subfunction detection a little smarter by associating each subfunction with the first function which jumps to it, since that's the one which will be analyzed. Unfortunately we still have to leave the original subfunction detection code in place, thanks to GCC switch tables. (See the comment for more details.) Fixes: 13810435b9a7 ("objtool: Support GCC 8's cold subfunctions") Reported-by: kbuild test robot Signed-off-by: Josh Poimboeuf Signed-off-by: Thomas Gleixner Cc: Peter Zijlstra Link: https://lkml.kernel.org/r/d3ba52662cbc8e3a64a3b64d44b4efc5674fd9ab.1527855808.git.jpoimboe@redhat.com --- tools/objtool/check.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'tools') diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 3a31b238f885..38047c6aa575 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -543,6 +543,28 @@ static int add_jump_destinations(struct objtool_file *file) dest_off); return -1; } + + /* + * For GCC 8+, create parent/child links for any cold + * subfunctions. This is _mostly_ redundant with a similar + * initialization in read_symbols(). + * + * If a function has aliases, we want the *first* such function + * in the symbol table to be the subfunction's parent. In that + * case we overwrite the initialization done in read_symbols(). + * + * However this code can't completely replace the + * read_symbols() code because this doesn't detect the case + * where the parent function's only reference to a subfunction + * is through a switch table. + */ + if (insn->func && insn->jump_dest->func && + insn->func != insn->jump_dest->func && + !strstr(insn->func->name, ".cold.") && + strstr(insn->jump_dest->func->name, ".cold.")) { + insn->func->cfunc = insn->jump_dest->func; + insn->jump_dest->func->pfunc = insn->func; + } } return 0; -- cgit From 0b5d6ece5e6a8b45c4ebbaaf831675b5b605850f Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 29 May 2018 13:28:24 -0300 Subject: perf hists: Introduce hist_entry__has_callchain() method We'll use this helper more frequently when reworking symbol_conf.use_callchain logic, where knowing if a hist_entry has callchains is the important bit, so make going from hist_entry to hists to evsel easier, compact. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-p6gioxkzpkpz71dtt4wcs36o@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/sort.h | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'tools') diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index f007a26d6f6d..1a046157bfef 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -151,6 +151,12 @@ struct hist_entry { struct callchain_root callchain[0]; /* must be last member */ }; +static __pure inline bool hist_entry__has_callchains(struct hist_entry *he) +{ + const struct perf_evsel *evsel = hists_to_evsel(he->hists); + return evsel__has_callchain(evsel); +} + static inline bool hist_entry__has_pairs(struct hist_entry *he) { return !list_empty(&he->pairs.node); -- cgit From fabd37b837f6e80aedba9ad706b517f5eeea9a50 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 29 May 2018 13:59:24 -0300 Subject: perf hists: Check if a hist_entry has callchains before using them So far if we use 'perf record -g' this will make symbol_conf.use_callchain 'true' and logic will assume that all events have callchains enabled, but ever since we added the possibility of setting up callchains for some events (e.g.: -e cycles/call-graph=dwarf/) while not for others, we limit usage scenarios by looking at that symbol_conf.use_callchain global boolean, we better look at each event attributes. On the road to that we need to look if a hist_entry has callchains, that is, to go from hist_entry->hists to the evsel that contains it, to then look at evsel->sample_type for PERF_SAMPLE_CALLCHAIN. The next step is to add a symbol_conf.ignore_callchains global, to use in the places where what we really want to know is if callchains should be ignored, even if present. Then -g will mean just to select a callchain mode to be applied to all events not explicitely setting some other callchain mode, i.e. a default callchain mode, and --no-call-graph will set symbol_conf.ignore_callchains with that clear intention. That too will at some point become a per evsel thing, that tools can set for all or just a few of its evsels. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-0sas5cm4dsw2obn75g7ruz69@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/browsers/hists.c | 11 ++++++----- tools/perf/ui/gtk/hists.c | 5 +++-- tools/perf/ui/hist.c | 2 +- tools/perf/ui/stdio/hist.c | 4 ++-- tools/perf/util/hist.c | 11 ++++++----- tools/perf/util/hist.h | 6 ++++++ tools/perf/util/sort.h | 3 +-- 7 files changed, 25 insertions(+), 17 deletions(-) (limited to 'tools') diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 22054107f1af..a96f62ca984a 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c @@ -1231,6 +1231,7 @@ static int hist_browser__show_entry(struct hist_browser *browser, int width = browser->b.width; char folded_sign = ' '; bool current_entry = ui_browser__is_current_entry(&browser->b, row); + bool use_callchain = hist_entry__has_callchains(entry) && symbol_conf.use_callchain; off_t row_offset = entry->row_offset; bool first = true; struct perf_hpp_fmt *fmt; @@ -1240,7 +1241,7 @@ static int hist_browser__show_entry(struct hist_browser *browser, browser->selection = &entry->ms; } - if (symbol_conf.use_callchain) { + if (use_callchain) { hist_entry__init_have_children(entry); folded_sign = hist_entry__folded(entry); } @@ -1276,7 +1277,7 @@ static int hist_browser__show_entry(struct hist_browser *browser, } if (first) { - if (symbol_conf.use_callchain) { + if (use_callchain) { ui_browser__printf(&browser->b, "%c ", folded_sign); width -= 2; } @@ -1583,7 +1584,7 @@ hists_browser__scnprintf_headers(struct hist_browser *browser, char *buf, int column = 0; int span = 0; - if (symbol_conf.use_callchain) { + if (hists__has_callchains(hists) && symbol_conf.use_callchain) { ret = scnprintf(buf, size, " "); if (advance_hpp_check(&dummy_hpp, ret)) return ret; @@ -1987,7 +1988,7 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser, bool first = true; int ret; - if (symbol_conf.use_callchain) { + if (hist_entry__has_callchains(he) && symbol_conf.use_callchain) { folded_sign = hist_entry__folded(he); printed += fprintf(fp, "%c ", folded_sign); } @@ -2671,7 +2672,7 @@ static void hist_browser__update_percent_limit(struct hist_browser *hb, he->nr_rows = 0; } - if (!he->leaf || !symbol_conf.use_callchain) + if (!he->leaf || !hist_entry__has_callchains(he) || !symbol_conf.use_callchain) goto next; if (callchain_param.mode == CHAIN_GRAPH_REL) { diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index 24e1ec201ffd..b085f1b3e34d 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c @@ -382,7 +382,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, gtk_tree_store_set(store, &iter, col_idx++, s, -1); } - if (symbol_conf.use_callchain && hists__has(hists, sym)) { + if (hists__has_callchains(hists) && + symbol_conf.use_callchain && hists__has(hists, sym)) { if (callchain_param.mode == CHAIN_GRAPH_REL) total = symbol_conf.cumulate_callchain ? h->stat_acc->period : h->stat.period; @@ -479,7 +480,7 @@ static void perf_gtk__add_hierarchy_entries(struct hists *hists, } } - if (symbol_conf.use_callchain && he->leaf) { + if (he->leaf && hist_entry__has_callchains(he) && symbol_conf.use_callchain) { if (callchain_param.mode == CHAIN_GRAPH_REL) total = symbol_conf.cumulate_callchain ? he->stat_acc->period : he->stat.period; diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index 706f6f1e9c7d..fe3dfaa64a91 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c @@ -207,7 +207,7 @@ static int __hpp__sort_acc(struct hist_entry *a, struct hist_entry *b, if (ret) return ret; - if (a->thread != b->thread || !symbol_conf.use_callchain) + if (a->thread != b->thread || !hist_entry__has_callchains(a) || !symbol_conf.use_callchain) return 0; ret = b->callchain->max_depth - a->callchain->max_depth; diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index c1eb476da91b..69b7a28f7a1c 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c @@ -516,7 +516,7 @@ static int hist_entry__hierarchy_fprintf(struct hist_entry *he, } printed += putc('\n', fp); - if (symbol_conf.use_callchain && he->leaf) { + if (he->leaf && hist_entry__has_callchains(he) && symbol_conf.use_callchain) { u64 total = hists__total_period(hists); printed += hist_entry_callchain__fprintf(he, total, 0, fp); @@ -550,7 +550,7 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size, ret = fprintf(fp, "%s\n", bf); - if (use_callchain) + if (hist_entry__has_callchains(he) && use_callchain) callchain_ret = hist_entry_callchain__fprintf(he, total_period, 0, fp); diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 34864c87cd3c..52e8fda93a47 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -410,7 +410,7 @@ static int hist_entry__init(struct hist_entry *he, map__get(he->mem_info->daddr.map); } - if (symbol_conf.use_callchain) + if (hist_entry__has_callchains(he) && symbol_conf.use_callchain) callchain_init(he->callchain); if (he->raw_data) { @@ -492,7 +492,7 @@ static u8 symbol__parent_filter(const struct symbol *parent) static void hist_entry__add_callchain_period(struct hist_entry *he, u64 period) { - if (!symbol_conf.use_callchain) + if (!hist_entry__has_callchains(he) || !symbol_conf.use_callchain) return; he->hists->callchain_period += period; @@ -986,7 +986,7 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter, iter->he = he; he_cache[iter->curr++] = he; - if (symbol_conf.use_callchain) + if (hist_entry__has_callchains(he) && symbol_conf.use_callchain) callchain_append(he->callchain, &cursor, sample->period); return 0; } @@ -1373,7 +1373,8 @@ static int hists__hierarchy_insert_entry(struct hists *hists, if (new_he) { new_he->leaf = true; - if (symbol_conf.use_callchain) { + if (hist_entry__has_callchains(new_he) && + symbol_conf.use_callchain) { callchain_cursor_reset(&callchain_cursor); if (callchain_merge(&callchain_cursor, new_he->callchain, @@ -1414,7 +1415,7 @@ static int hists__collapse_insert_entry(struct hists *hists, if (symbol_conf.cumulate_callchain) he_stat__add_stat(iter->stat_acc, he->stat_acc); - if (symbol_conf.use_callchain) { + if (hist_entry__has_callchains(he) && symbol_conf.use_callchain) { callchain_cursor_reset(&callchain_cursor); if (callchain_merge(&callchain_cursor, iter->callchain, diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index cafafbf2aa9f..06607c434949 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -220,6 +220,12 @@ static inline struct hists *evsel__hists(struct perf_evsel *evsel) return &hevsel->hists; } +static __pure inline bool hists__has_callchains(struct hists *hists) +{ + const struct perf_evsel *evsel = hists_to_evsel(hists); + return evsel__has_callchain(evsel); +} + int hists__init(void); int __hists__init(struct hists *hists, struct perf_hpp_list *hpp_list); diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 1a046157bfef..7cf2d5cc038e 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -153,8 +153,7 @@ struct hist_entry { static __pure inline bool hist_entry__has_callchains(struct hist_entry *he) { - const struct perf_evsel *evsel = hists_to_evsel(he->hists); - return evsel__has_callchain(evsel); + return hists__has_callchains(he->hists); } static inline bool hist_entry__has_pairs(struct hist_entry *he) -- cgit From dcaeae4e2c266452e04dc3d83b10469be9fe419e Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 4 Jun 2018 15:56:53 +0300 Subject: perf tests kmod-path: Add tests for vdso32 and vdsox32 Add tests for vdso32 and vdsox32. This will cause the overall test to fail because __kmod_path__parse() does not handle vdso32 or vdsox32. Fixes: 1f121b03d058 ("perf tools: Deal with kernel module names in '[]' correctly") Signed-off-by: Adrian Hunter Cc: Jiri Olsa Cc: Wang Nan Link: http://lkml.kernel.org/r/1528117014-30032-2-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/kmod-path.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) (limited to 'tools') diff --git a/tools/perf/tests/kmod-path.c b/tools/perf/tests/kmod-path.c index 8e57d46109de..148dd31cc201 100644 --- a/tools/perf/tests/kmod-path.c +++ b/tools/perf/tests/kmod-path.c @@ -127,6 +127,22 @@ int test__kmod_path__parse(struct test *t __maybe_unused, int subtest __maybe_un M("[vdso]", PERF_RECORD_MISC_KERNEL, false); M("[vdso]", PERF_RECORD_MISC_USER, false); + T("[vdso32]", true , true , false, false, "[vdso32]", NULL); + T("[vdso32]", false , true , false, false, NULL , NULL); + T("[vdso32]", true , false , false, false, "[vdso32]", NULL); + T("[vdso32]", false , false , false, false, NULL , NULL); + M("[vdso32]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false); + M("[vdso32]", PERF_RECORD_MISC_KERNEL, false); + M("[vdso32]", PERF_RECORD_MISC_USER, false); + + T("[vdsox32]", true , true , false, false, "[vdsox32]", NULL); + T("[vdsox32]", false , true , false, false, NULL , NULL); + T("[vdsox32]", true , false , false, false, "[vdsox32]", NULL); + T("[vdsox32]", false , false , false, false, NULL , NULL); + M("[vdsox32]", PERF_RECORD_MISC_CPUMODE_UNKNOWN, false); + M("[vdsox32]", PERF_RECORD_MISC_KERNEL, false); + M("[vdsox32]", PERF_RECORD_MISC_USER, false); + /* path alloc_name alloc_ext kmod comp name ext */ T("[vsyscall]", true , true , false, false, "[vsyscall]", NULL); T("[vsyscall]", false , true , false, false, NULL , NULL); -- cgit From aef4feace285f27c8ed35830a5d575bec7f3e90a Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Mon, 4 Jun 2018 15:56:54 +0300 Subject: perf tools: Fix symbol and object code resolution for vdso32 and vdsox32 Fix __kmod_path__parse() so that perf tools does not treat vdso32 and vdsox32 as kernel modules and fail to find the object. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Cc: Wang Nan Cc: stable@vger.kernel.org Fixes: 1f121b03d058 ("perf tools: Deal with kernel module names in '[]' correctly") Link: http://lkml.kernel.org/r/1528117014-30032-3-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/dso.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools') diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c index cdfc2e5f55f5..51cf82cf1882 100644 --- a/tools/perf/util/dso.c +++ b/tools/perf/util/dso.c @@ -354,6 +354,8 @@ int __kmod_path__parse(struct kmod_path *m, const char *path, if ((strncmp(name, "[kernel.kallsyms]", 17) == 0) || (strncmp(name, "[guest.kernel.kallsyms", 22) == 0) || (strncmp(name, "[vdso]", 6) == 0) || + (strncmp(name, "[vdso32]", 8) == 0) || + (strncmp(name, "[vdsox32]", 9) == 0) || (strncmp(name, "[vsyscall]", 10) == 0)) { m->kmod = false; -- cgit From f92da71280fb8da3a7c489e08a096f0b8715f939 Mon Sep 17 00:00:00 2001 From: Alexey Budankov Date: Mon, 4 Jun 2018 09:50:56 +0300 Subject: perf record: Enable arbitrary event names thru name= modifier Enable complex event names containing [.:=,] symbols to be encoded into Perf trace using name= modifier e.g. like this: perf record -e cpu/name=\'OFFCORE_RESPONSE:request=DEMAND_RFO:response=L3_HIT.SNOOP_HITM\',\ period=0x3567e0,event=0x3c,cmask=0x1/Duk ./futex Below is how it looks like in the report output. Please note explicit escaped quoting at cmdline string in the header so that thestring can be directly reused for another collection in shell: perf report --header # ======== ... # cmdline : /root/abudanko/kernel/tip/tools/perf/perf record -v -e cpu/name=\'OFFCORE_RESPONSE:request=DEMAND_RFO:response=L3_HIT.SNOOP_HITM\',period=0x3567e0,event=0x3c,cmask=0x1/Duk ./futex # event : name = OFFCORE_RESPONSE:request=DEMAND_RFO:response=L3_HIT.SNOOP_HITM, , type = 4, size = 112, config = 0x100003c, { sample_period, sample_freq } = 3500000, sample_type = IP|TID|TIME, disabled = 1, inh ... # ======== # # # Total Lost Samples: 0 # # Samples: 24K of event 'OFFCORE_RESPONSE:request=DEMAND_RFO:response=L3_HIT.SNOOP_HITM' # Event count (approx.): 86492000000 # # Overhead Command Shared Object Symbol # ........ ....... ................ .............................................. # 14.75% futex [kernel.vmlinux] [k] __entry_trampoline_start ... perf stat -e cpu/name=\'CPU_CLK_UNHALTED.THREAD:cmask=0x1\',period=0x3567e0,event=0x3c,cmask=0x1/Duk ./futex 10000000 process context switches in 16678890291ns (1667.9ns/ctxsw) Performance counter stats for './futex': 88,095,770,571 CPU_CLK_UNHALTED.THREAD:cmask=0x1 16.679542407 seconds time elapsed Signed-off-by: Alexey Budankov Acked-by: Andi Kleen Acked-by: Jiri Olsa Cc: Alexander Shishkin Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/c194b060-761d-0d50-3b21-bb4ed680002d@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-list.txt | 6 +++++- tools/perf/Documentation/perf-record.txt | 3 +++ tools/perf/util/header.c | 20 ++++++++++++++++++-- tools/perf/util/parse-events.l | 18 +++++++++++++++++- 4 files changed, 43 insertions(+), 4 deletions(-) (limited to 'tools') diff --git a/tools/perf/Documentation/perf-list.txt b/tools/perf/Documentation/perf-list.txt index 2549c34a7895..11300dbe35c5 100644 --- a/tools/perf/Documentation/perf-list.txt +++ b/tools/perf/Documentation/perf-list.txt @@ -124,7 +124,11 @@ The available PMUs and their raw parameters can be listed with For example the raw event "LSD.UOPS" core pmu event above could be specified as - perf stat -e cpu/event=0xa8,umask=0x1,name=LSD.UOPS_CYCLES,cmask=1/ ... + perf stat -e cpu/event=0xa8,umask=0x1,name=LSD.UOPS_CYCLES,cmask=0x1/ ... + + or using extended name syntax + + perf stat -e cpu/event=0xa8,umask=0x1,cmask=0x1,name=\'LSD.UOPS_CYCLES:cmask=0x1\'/ ... PER SOCKET PMUS --------------- diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index cc37b3a4be76..04168da4268e 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt @@ -57,6 +57,9 @@ OPTIONS FP mode, "dwarf" for DWARF mode, "lbr" for LBR mode and "no" for disable callgraph. - 'stack-size': user stack size for dwarf mode + - 'name' : User defined event name. Single quotes (') may be used to + escape symbols in the name from parsing by shell and tool + like this: name=\'CPU_CLK_UNHALTED.THREAD:cmask=0x1\'. See the linkperf:perf-list[1] man page for more parameters. diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 2625cc38a0d6..540cd2dcd3e7 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -1459,8 +1459,24 @@ static void print_cmdline(struct feat_fd *ff, FILE *fp) fprintf(fp, "# cmdline : "); - for (i = 0; i < nr; i++) - fprintf(fp, "%s ", ff->ph->env.cmdline_argv[i]); + for (i = 0; i < nr; i++) { + char *argv_i = strdup(ff->ph->env.cmdline_argv[i]); + if (!argv_i) { + fprintf(fp, "%s ", ff->ph->env.cmdline_argv[i]); + } else { + char *mem = argv_i; + do { + char *quote = strchr(argv_i, '\''); + if (!quote) + break; + *quote++ = '\0'; + fprintf(fp, "%s\\\'", argv_i); + argv_i = quote; + } while (1); + fprintf(fp, "%s ", argv_i); + free(mem); + } + } fputc('\n', fp); } diff --git a/tools/perf/util/parse-events.l b/tools/perf/util/parse-events.l index a1a01b1ac8b8..5f761f3ed0f3 100644 --- a/tools/perf/util/parse-events.l +++ b/tools/perf/util/parse-events.l @@ -53,7 +53,21 @@ static int str(yyscan_t scanner, int token) YYSTYPE *yylval = parse_events_get_lval(scanner); char *text = parse_events_get_text(scanner); - yylval->str = strdup(text); + if (text[0] != '\'') { + yylval->str = strdup(text); + } else { + /* + * If a text tag specified on the command line + * contains opening single quite ' then it is + * expected that the tag ends with single quote + * as well, like this: + * name=\'CPU_CLK_UNHALTED.THREAD:cmask=1\' + * quotes need to be escaped to bypass shell + * processing. + */ + yylval->str = strndup(&text[1], strlen(text) - 2); + } + return token; } @@ -176,6 +190,7 @@ num_dec [0-9]+ num_hex 0x[a-fA-F0-9]+ num_raw_hex [a-fA-F0-9]+ name [a-zA-Z_*?\[\]][a-zA-Z0-9_*?.\[\]]* +name_tag [\'][a-zA-Z_*?\[\]][a-zA-Z0-9_*?\-,\.\[\]:=]*[\'] name_minus [a-zA-Z_*?][a-zA-Z0-9\-_*?.:]* drv_cfg_term [a-zA-Z0-9_\.]+(=[a-zA-Z0-9_*?\.:]+)? /* If you add a modifier you need to update check_modifier() */ @@ -344,6 +359,7 @@ r{num_raw_hex} { return raw(yyscanner); } {bpf_object} { if (!isbpf(yyscanner)) { USER_REJECT }; return str(yyscanner, PE_BPF_OBJECT); } {bpf_source} { if (!isbpf(yyscanner)) { USER_REJECT }; return str(yyscanner, PE_BPF_SOURCE); } {name} { return pmu_str_check(yyscanner); } +{name_tag} { return str(yyscanner, PE_NAME); } "/" { BEGIN(config); return '/'; } - { return '-'; } , { BEGIN(event); return ','; } -- cgit From 0ce2da1483967c75a0e031af152e0fca4110d376 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 5 Jun 2018 14:13:13 +0200 Subject: perf stat: Display user and system time Adding the support to read rusage data once the workload is finished and display the system/user time values: $ perf stat --null perf bench sched pipe ... Performance counter stats for 'perf bench sched pipe': 5.342599256 seconds time elapsed 2.544434000 seconds user 4.549691000 seconds sys It works only in non -r mode and only for workload target. So as of now, for workload targets, we display 3 types of timings. The time we meassure in perf stat from enable to disable+period: 5.342599256 seconds time elapsed The time spent in user and system lands, displayed only for workload session/target: 2.544434000 seconds user 4.549691000 seconds sys Those times are the very same displayed by 'time' tool. They are returned by wait4 call via the getrusage struct interface. Committer notes: Had to rename some variables to avoid this on older systems such as centos:6: builtin-stat.c: In function 'print_footer': builtin-stat.c:1831: warning: declaration of 'stime' shadows a global declaration /usr/include/time.h:297: warning: shadowed declaration is here Committer testing: # perf stat --null time perf bench sched pipe # Running 'sched/pipe' benchmark: # Executed 1000000 pipe operations between two processes Total time: 5.526 [sec] 5.526534 usecs/op 180945 ops/sec 1.00user 6.25system 0:05.52elapsed 131%CPU (0avgtext+0avgdata 8056maxresident)k 0inputs+0outputs (0major+606minor)pagefaults 0swaps Performance counter stats for 'time perf bench sched pipe': 5.530978744 seconds time elapsed 1.004037000 seconds user 6.259937000 seconds sys # Suggested-by: Ingo Molnar Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20180605121313.31337-1-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-stat.txt | 40 ++++++++++++++++++++++++---------- tools/perf/builtin-stat.c | 28 +++++++++++++++++++++++- 2 files changed, 56 insertions(+), 12 deletions(-) (limited to 'tools') diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 3a822f308e6d..5dfe102fb5b5 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt @@ -310,20 +310,38 @@ Users who wants to get the actual value can apply --no-metric-only. EXAMPLES -------- -$ perf stat -- make -j +$ perf stat -- make - Performance counter stats for 'make -j': + Performance counter stats for 'make': - 8117.370256 task clock ticks # 11.281 CPU utilization factor - 678 context switches # 0.000 M/sec - 133 CPU migrations # 0.000 M/sec - 235724 pagefaults # 0.029 M/sec - 24821162526 CPU cycles # 3057.784 M/sec - 18687303457 instructions # 2302.138 M/sec - 172158895 cache references # 21.209 M/sec - 27075259 cache misses # 3.335 M/sec + 83723.452481 task-clock:u (msec) # 1.004 CPUs utilized + 0 context-switches:u # 0.000 K/sec + 0 cpu-migrations:u # 0.000 K/sec + 3,228,188 page-faults:u # 0.039 M/sec + 229,570,665,834 cycles:u # 2.742 GHz + 313,163,853,778 instructions:u # 1.36 insn per cycle + 69,704,684,856 branches:u # 832.559 M/sec + 2,078,861,393 branch-misses:u # 2.98% of all branches - Wall-clock time elapsed: 719.554352 msecs + 83.409183620 seconds time elapsed + + 74.684747000 seconds user + 8.739217000 seconds sys + +TIMINGS +------- +As displayed in the example above we can display 3 types of timings. +We always display the time the counters were enabled/alive: + + 83.409183620 seconds time elapsed + +For workload sessions we also display time the workloads spent in +user/system lands: + + 74.684747000 seconds user + 8.739217000 seconds sys + +Those times are the very same as displayed by the 'time' tool. CSV FORMAT ---------- diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index a4f662a462c6..096ccb25c11f 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -80,6 +80,9 @@ #include #include #include +#include +#include +#include #include "sane_ctype.h" @@ -175,6 +178,8 @@ static int output_fd; static int print_free_counters_hint; static int print_mixed_hw_group_error; static u64 *walltime_run; +static bool ru_display = false; +static struct rusage ru_data; struct perf_stat { bool record; @@ -726,7 +731,7 @@ try_again: break; } } - waitpid(child_pid, &status, 0); + wait4(child_pid, &status, 0, &ru_data); if (workload_exec_errno) { const char *emsg = str_error_r(workload_exec_errno, msg, sizeof(msg)); @@ -1804,6 +1809,11 @@ static void print_table(FILE *output, int precision, double avg) fprintf(output, "\n%*s# Final result:\n", indent, ""); } +static double timeval2double(struct timeval *t) +{ + return t->tv_sec + (double) t->tv_usec/USEC_PER_SEC; +} + static void print_footer(void) { double avg = avg_stats(&walltime_nsecs_stats) / NSEC_PER_SEC; @@ -1815,6 +1825,15 @@ static void print_footer(void) if (run_count == 1) { fprintf(output, " %17.9f seconds time elapsed", avg); + + if (ru_display) { + double ru_utime = timeval2double(&ru_data.ru_utime); + double ru_stime = timeval2double(&ru_data.ru_stime); + + fprintf(output, "\n\n"); + fprintf(output, " %17.9f seconds user\n", ru_utime); + fprintf(output, " %17.9f seconds sys\n", ru_stime); + } } else { double sd = stddev_stats(&walltime_nsecs_stats) / NSEC_PER_SEC; /* @@ -2950,6 +2969,13 @@ int cmd_stat(int argc, const char **argv) setup_system_wide(argc); + /* + * Display user/system times only for single + * run and when there's specified tracee. + */ + if ((run_count == 1) && target__none(&target)) + ru_display = true; + if (run_count < 0) { pr_err("Run count must be a positive number\n"); parse_options_usage(stat_usage, stat_options, "r", 1); -- cgit From ceac7b79df7bd67ef9aaf464b0179a2686aff4ee Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Tue, 5 Jun 2018 14:14:16 +0200 Subject: perf tools: Fix pmu events parsing rule Currently all the event parsing fails end up in the event_pmu rule, and display misleading help like: $ perf stat -e inst kill event syntax error: 'inst' \___ Cannot find PMU `inst'. Missing kernel support? ... The reason is that the event_pmu is too strong and match also single string. Changing it to force the '/' separators to be part of the rule, and getting the proper error now: $ perf stat -e inst kill event syntax error: 'inst' \___ parser error Run 'perf list' for a list of valid events ... Suggested-by: Adrian Hunter Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: Adrian Hunter Cc: Alexander Shishkin Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20180605121416.31645-1-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.y | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index e37608a87dba..155d2570274f 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -73,6 +73,7 @@ static void inc_group_count(struct list_head *list, %type value_sym %type event_config %type opt_event_config +%type opt_pmu_config %type event_term %type event_pmu %type event_legacy_symbol @@ -224,7 +225,7 @@ event_def: event_pmu | event_bpf_file event_pmu: -PE_NAME opt_event_config +PE_NAME opt_pmu_config { struct list_head *list, *orig_terms, *terms; @@ -496,6 +497,17 @@ opt_event_config: $$ = NULL; } +opt_pmu_config: +'/' event_config '/' +{ + $$ = $2; +} +| +'/' '/' +{ + $$ = NULL; +} + start_terms: event_config { struct parse_events_state *parse_state = _parse_state; -- cgit From f6c66d73bb8192d357bb5fb8cd5826920f811d8c Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 5 Jun 2018 10:30:00 +0300 Subject: perf test code-reading: Fix perf_env setup for PTI entry trampolines The "Object code reading" test will not create maps for the PTI entry trampolines unless the machine environment exists to show that the arch is x86_64. Signed-off-by: Adrian Hunter Reported-by: Arnaldo Carvalho de Melo Tested-by: Arnaldo Carvalho de Melo Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1528183800-21577-1-git-send-email-adrian.hunter@intel.com [ split from a larger patch ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/code-reading.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tools') diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c index afa4ce21ba7c..4892bd2dc33e 100644 --- a/tools/perf/tests/code-reading.c +++ b/tools/perf/tests/code-reading.c @@ -560,6 +560,7 @@ static int do_test_code_reading(bool try_kcore) pid = getpid(); machine = machine__new_host(); + machine->env = &perf_env; ret = machine__create_kernel_maps(machine); if (ret < 0) { -- cgit From 97802f3b81dc0d1da0f89c498249547d73a01164 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Tue, 5 Jun 2018 10:30:00 +0300 Subject: perf map: Consider PTI entry trampolines in rip_2objdump() perf tools uses map__rip_2objdump() to calculate objdump virtual addresses. map__rip_2objdump() needs to be amended to deal with PTI entry trampolines. Signed-off-by: Adrian Hunter Reported-by: Arnaldo Carvalho de Melo Tested-by: Arnaldo Carvalho de Melo Cc: Jiri Olsa Link: http://lkml.kernel.org/r/1528183800-21577-1-git-send-email-adrian.hunter@intel.com [ split from a larger patch ] Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/map.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'tools') diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index 92abc8e248c5..89ac5b5dc218 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c @@ -449,6 +449,20 @@ int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix, */ u64 map__rip_2objdump(struct map *map, u64 rip) { + struct kmap *kmap = __map__kmap(map); + + /* + * vmlinux does not have program headers for PTI entry trampolines and + * kcore may not either. However the trampoline object code is on the + * main kernel map, so just use that instead. + */ + if (kmap && is_entry_trampoline(kmap->name) && kmap->kmaps && kmap->kmaps->machine) { + struct map *kernel_map = machine__kernel_map(kmap->kmaps->machine); + + if (kernel_map) + map = kernel_map; + } + if (!map->dso->adjust_symbols) return rip; -- cgit From 005cc008bc188f81f0c1ae53dafb50cdb6df19c2 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Mon, 4 Jun 2018 11:11:13 -0300 Subject: perf test record+probe_libc_inet_pton: Ask 'nm' for dynamic symbols Adrian reported that this test fails in his system where: probe libc's inet_pton & backtrace it with ping: FAILED! root@kbl04:~/git/linux-perf# nm -g /lib/x86_64-linux-gnu/libc-2.19.so | grep inet_pton nm: /lib/x86_64-linux-gnu/libc-2.19.so: no symbols This fails on ubuntu systems, with Adrian's being kubuntu 14.04, I tested with ubuntu 14.04.4 and 18.04, and there we need to use the -D/--dynamic 'nm' option to have this test working. And it works as well with that on fedora 27, so use it. Reported-by: Adrian Hunter Cc: David Ahern Cc: Heiko Carstens Cc: Hendrik Brueckner Cc: Jiri Olsa Cc: Martin Schwidefsky Cc: Namhyung Kim Cc: Naveen N. Rao Cc: Sandipan Das Cc: Thomas Richter Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-zlfnbauad3ljlmtjgo0v660u@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/shell/record+probe_libc_inet_pton.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/tests/shell/record+probe_libc_inet_pton.sh b/tools/perf/tests/shell/record+probe_libc_inet_pton.sh index 650b208f700f..263057039693 100755 --- a/tools/perf/tests/shell/record+probe_libc_inet_pton.sh +++ b/tools/perf/tests/shell/record+probe_libc_inet_pton.sh @@ -11,7 +11,7 @@ . $(dirname $0)/lib/probe.sh libc=$(grep -w libc /proc/self/maps | head -1 | sed -r 's/.*[[:space:]](\/.*)/\1/g') -nm -g $libc 2>/dev/null | fgrep -q inet_pton || exit 254 +nm -Dg $libc 2>/dev/null | fgrep -q inet_pton || exit 254 trace_libc_inet_pton_backtrace() { idx=0 -- cgit From ec1e6e6a681815e4d02a54eed92edec6fa4128ee Mon Sep 17 00:00:00 2001 From: Ravi Bangoria Date: Tue, 5 Jun 2018 18:18:01 +0530 Subject: perf script powerpc: Python script for hypervisor call statistics Add python script to show hypervisor call statistics. Ex, # perf record -a -e "{powerpc:hcall_entry,powerpc:hcall_exit}" # perf script -s scripts/python/powerpc-hcalls.py hcall count min(ns) max(ns) avg(ns) -------------------------------------------------------------------- H_RANDOM 82 838 1164 904 H_PUT_TCE 47 1078 5928 2003 H_EOI 266 1336 3546 1654 H_ENTER 28 1646 4038 1952 H_PUT_TCE_INDIRECT 230 2166 18168 6109 H_IPI 238 1072 3232 1688 H_SEND_LOGICAL_LAN 42 5488 21366 7694 H_STUFF_TCE 294 986 6210 3591 H_XIRR 266 2286 6990 3783 H_PROTECT 10 2196 3556 2555 H_VIO_SIGNAL 294 1028 2784 1311 H_ADD_LOGICAL_LAN_BUFFER 53 1978 3450 2600 H_SEND_CRQ 77 1762 7240 2447 Signed-off-by: Ravi Bangoria Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Michael Ellerman Cc: Namhyung Kim Cc: Naveen N. Rao Link: http://lkml.kernel.org/r/20180605124801.17210-1-ravi.bangoria@linux.ibm.com [ Fixup typo: table_loockup -> table_lookup ] Signed-off-by: Arnaldo Carvalho de Melo --- .../perf/scripts/python/bin/powerpc-hcalls-record | 2 + .../perf/scripts/python/bin/powerpc-hcalls-report | 2 + tools/perf/scripts/python/powerpc-hcalls.py | 200 +++++++++++++++++++++ 3 files changed, 204 insertions(+) create mode 100644 tools/perf/scripts/python/bin/powerpc-hcalls-record create mode 100644 tools/perf/scripts/python/bin/powerpc-hcalls-report create mode 100644 tools/perf/scripts/python/powerpc-hcalls.py (limited to 'tools') diff --git a/tools/perf/scripts/python/bin/powerpc-hcalls-record b/tools/perf/scripts/python/bin/powerpc-hcalls-record new file mode 100644 index 000000000000..b7402aa9147d --- /dev/null +++ b/tools/perf/scripts/python/bin/powerpc-hcalls-record @@ -0,0 +1,2 @@ +#!/bin/bash +perf record -e "{powerpc:hcall_entry,powerpc:hcall_exit}" $@ diff --git a/tools/perf/scripts/python/bin/powerpc-hcalls-report b/tools/perf/scripts/python/bin/powerpc-hcalls-report new file mode 100644 index 000000000000..dd32ad7465f6 --- /dev/null +++ b/tools/perf/scripts/python/bin/powerpc-hcalls-report @@ -0,0 +1,2 @@ +#!/bin/bash +perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/powerpc-hcalls.py diff --git a/tools/perf/scripts/python/powerpc-hcalls.py b/tools/perf/scripts/python/powerpc-hcalls.py new file mode 100644 index 000000000000..00e0e7476e55 --- /dev/null +++ b/tools/perf/scripts/python/powerpc-hcalls.py @@ -0,0 +1,200 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright (C) 2018 Ravi Bangoria, IBM Corporation +# +# Hypervisor call statisics + +import os +import sys + +sys.path.append(os.environ['PERF_EXEC_PATH'] + \ + '/scripts/python/Perf-Trace-Util/lib/Perf/Trace') + +from perf_trace_context import * +from Core import * +from Util import * + +# output: { +# opcode: { +# 'min': minimum time nsec +# 'max': maximum time nsec +# 'time': average time nsec +# 'cnt': counter +# } ... +# } +output = {} + +# d_enter: { +# cpu: { +# opcode: nsec +# } ... +# } +d_enter = {} + +hcall_table = { + 4: 'H_REMOVE', + 8: 'H_ENTER', + 12: 'H_READ', + 16: 'H_CLEAR_MOD', + 20: 'H_CLEAR_REF', + 24: 'H_PROTECT', + 28: 'H_GET_TCE', + 32: 'H_PUT_TCE', + 36: 'H_SET_SPRG0', + 40: 'H_SET_DABR', + 44: 'H_PAGE_INIT', + 48: 'H_SET_ASR', + 52: 'H_ASR_ON', + 56: 'H_ASR_OFF', + 60: 'H_LOGICAL_CI_LOAD', + 64: 'H_LOGICAL_CI_STORE', + 68: 'H_LOGICAL_CACHE_LOAD', + 72: 'H_LOGICAL_CACHE_STORE', + 76: 'H_LOGICAL_ICBI', + 80: 'H_LOGICAL_DCBF', + 84: 'H_GET_TERM_CHAR', + 88: 'H_PUT_TERM_CHAR', + 92: 'H_REAL_TO_LOGICAL', + 96: 'H_HYPERVISOR_DATA', + 100: 'H_EOI', + 104: 'H_CPPR', + 108: 'H_IPI', + 112: 'H_IPOLL', + 116: 'H_XIRR', + 120: 'H_MIGRATE_DMA', + 124: 'H_PERFMON', + 220: 'H_REGISTER_VPA', + 224: 'H_CEDE', + 228: 'H_CONFER', + 232: 'H_PROD', + 236: 'H_GET_PPP', + 240: 'H_SET_PPP', + 244: 'H_PURR', + 248: 'H_PIC', + 252: 'H_REG_CRQ', + 256: 'H_FREE_CRQ', + 260: 'H_VIO_SIGNAL', + 264: 'H_SEND_CRQ', + 272: 'H_COPY_RDMA', + 276: 'H_REGISTER_LOGICAL_LAN', + 280: 'H_FREE_LOGICAL_LAN', + 284: 'H_ADD_LOGICAL_LAN_BUFFER', + 288: 'H_SEND_LOGICAL_LAN', + 292: 'H_BULK_REMOVE', + 304: 'H_MULTICAST_CTRL', + 308: 'H_SET_XDABR', + 312: 'H_STUFF_TCE', + 316: 'H_PUT_TCE_INDIRECT', + 332: 'H_CHANGE_LOGICAL_LAN_MAC', + 336: 'H_VTERM_PARTNER_INFO', + 340: 'H_REGISTER_VTERM', + 344: 'H_FREE_VTERM', + 348: 'H_RESET_EVENTS', + 352: 'H_ALLOC_RESOURCE', + 356: 'H_FREE_RESOURCE', + 360: 'H_MODIFY_QP', + 364: 'H_QUERY_QP', + 368: 'H_REREGISTER_PMR', + 372: 'H_REGISTER_SMR', + 376: 'H_QUERY_MR', + 380: 'H_QUERY_MW', + 384: 'H_QUERY_HCA', + 388: 'H_QUERY_PORT', + 392: 'H_MODIFY_PORT', + 396: 'H_DEFINE_AQP1', + 400: 'H_GET_TRACE_BUFFER', + 404: 'H_DEFINE_AQP0', + 408: 'H_RESIZE_MR', + 412: 'H_ATTACH_MCQP', + 416: 'H_DETACH_MCQP', + 420: 'H_CREATE_RPT', + 424: 'H_REMOVE_RPT', + 428: 'H_REGISTER_RPAGES', + 432: 'H_DISABLE_AND_GETC', + 436: 'H_ERROR_DATA', + 440: 'H_GET_HCA_INFO', + 444: 'H_GET_PERF_COUNT', + 448: 'H_MANAGE_TRACE', + 468: 'H_FREE_LOGICAL_LAN_BUFFER', + 472: 'H_POLL_PENDING', + 484: 'H_QUERY_INT_STATE', + 580: 'H_ILLAN_ATTRIBUTES', + 592: 'H_MODIFY_HEA_QP', + 596: 'H_QUERY_HEA_QP', + 600: 'H_QUERY_HEA', + 604: 'H_QUERY_HEA_PORT', + 608: 'H_MODIFY_HEA_PORT', + 612: 'H_REG_BCMC', + 616: 'H_DEREG_BCMC', + 620: 'H_REGISTER_HEA_RPAGES', + 624: 'H_DISABLE_AND_GET_HEA', + 628: 'H_GET_HEA_INFO', + 632: 'H_ALLOC_HEA_RESOURCE', + 644: 'H_ADD_CONN', + 648: 'H_DEL_CONN', + 664: 'H_JOIN', + 676: 'H_VASI_STATE', + 688: 'H_ENABLE_CRQ', + 696: 'H_GET_EM_PARMS', + 720: 'H_SET_MPP', + 724: 'H_GET_MPP', + 748: 'H_HOME_NODE_ASSOCIATIVITY', + 756: 'H_BEST_ENERGY', + 764: 'H_XIRR_X', + 768: 'H_RANDOM', + 772: 'H_COP', + 788: 'H_GET_MPP_X', + 796: 'H_SET_MODE', + 61440: 'H_RTAS', +} + +def hcall_table_lookup(opcode): + if (hcall_table.has_key(opcode)): + return hcall_table[opcode] + else: + return opcode + +print_ptrn = '%-28s%10s%10s%10s%10s' + +def trace_end(): + print print_ptrn % ('hcall', 'count', 'min(ns)', 'max(ns)', 'avg(ns)') + print '-' * 68 + for opcode in output: + h_name = hcall_table_lookup(opcode) + time = output[opcode]['time'] + cnt = output[opcode]['cnt'] + min_t = output[opcode]['min'] + max_t = output[opcode]['max'] + + print print_ptrn % (h_name, cnt, min_t, max_t, time/cnt) + +def powerpc__hcall_exit(name, context, cpu, sec, nsec, pid, comm, callchain, + opcode, retval): + if (d_enter.has_key(cpu) and d_enter[cpu].has_key(opcode)): + diff = nsecs(sec, nsec) - d_enter[cpu][opcode] + + if (output.has_key(opcode)): + output[opcode]['time'] += diff + output[opcode]['cnt'] += 1 + if (output[opcode]['min'] > diff): + output[opcode]['min'] = diff + if (output[opcode]['max'] < diff): + output[opcode]['max'] = diff + else: + output[opcode] = { + 'time': diff, + 'cnt': 1, + 'min': diff, + 'max': diff, + } + + del d_enter[cpu][opcode] +# else: +# print "Can't find matching hcall_enter event. Ignoring sample" + +def powerpc__hcall_entry(event_name, context, cpu, sec, nsec, pid, comm, + callchain, opcode): + if (d_enter.has_key(cpu)): + d_enter[cpu][opcode] = nsecs(sec, nsec) + else: + d_enter[cpu] = {opcode: nsecs(sec, nsec)} -- cgit From dbcb82b93f3e8322891e47472c89e63058b81e99 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 31 May 2018 13:23:42 +0300 Subject: perf intel-pt: Fix sync_switch INTEL_PT_SS_NOT_TRACING sync_switch is a facility to synchronize decoding more closely with the point in the kernel when the context actually switched. In one case, INTEL_PT_SS_NOT_TRACING state was not correctly transitioning to INTEL_PT_SS_TRACING state due to a missing case clause. Add it. Signed-off-by: Adrian Hunter Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1527762225-26024-2-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tools') diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 492986a25ef6..3db7f0ee52a8 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -1521,6 +1521,7 @@ static int intel_pt_sample(struct intel_pt_queue *ptq) if (intel_pt_is_switch_ip(ptq, state->to_ip)) { switch (ptq->switch_state) { + case INTEL_PT_SS_NOT_TRACING: case INTEL_PT_SS_UNKNOWN: case INTEL_PT_SS_EXPECTING_SWITCH_IP: err = intel_pt_next_tid(pt, ptq); -- cgit From bd2e49ec48feb1855f7624198849eea4610e2286 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 31 May 2018 13:23:43 +0300 Subject: perf intel-pt: Fix decoding to accept CBR between FUP and corresponding TIP It is possible to have a CBR packet between a FUP packet and corresponding TIP packet. Stop treating it as an error. Signed-off-by: Adrian Hunter Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1527762225-26024-3-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'tools') 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 f9157aed1289..e5eb91777383 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -1604,7 +1604,6 @@ static int intel_pt_walk_fup_tip(struct intel_pt_decoder *decoder) case INTEL_PT_PSB: case INTEL_PT_TSC: case INTEL_PT_TMA: - case INTEL_PT_CBR: case INTEL_PT_MODE_TSX: case INTEL_PT_BAD: case INTEL_PT_PSBEND: @@ -1620,6 +1619,10 @@ static int intel_pt_walk_fup_tip(struct intel_pt_decoder *decoder) decoder->pkt_step = 0; return -ENOENT; + case INTEL_PT_CBR: + intel_pt_calc_cbr(decoder); + break; + case INTEL_PT_OVF: return intel_pt_overflow(decoder); -- cgit From dd27b87ab5fcf3ea1c060b5e3ab5d31cc78e9f4c Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 31 May 2018 13:23:44 +0300 Subject: perf intel-pt: Fix MTC timing after overflow On some platforms, overflows will clear before MTC wraparound, and there is no following TSC/TMA packet. In that case the previous TMA is valid. Since there will be a valid TMA either way, stop setting 'have_tma' to false upon overflow. Signed-off-by: Adrian Hunter Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1527762225-26024-4-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | 1 - 1 file changed, 1 deletion(-) (limited to 'tools') 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 e5eb91777383..881d7c5e5e2a 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -1376,7 +1376,6 @@ static int intel_pt_overflow(struct intel_pt_decoder *decoder) { intel_pt_log("ERROR: Buffer overflow\n"); intel_pt_clear_tx_flags(decoder); - decoder->have_tma = false; decoder->cbr = 0; decoder->timestamp_insn_cnt = 0; decoder->pkt_state = INTEL_PT_STATE_ERR_RESYNC; -- cgit From 9fb523363f6e3984457fee95bb7019395384ffa7 Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 31 May 2018 13:23:45 +0300 Subject: perf intel-pt: Fix "Unexpected indirect branch" error Some Atom CPUs can produce FUP packets that contain NLIP (next linear instruction pointer) instead of CLIP (current linear instruction pointer). That will result in "Unexpected indirect branch" errors. Fix by comparing IP to NLIP in that case. Signed-off-by: Adrian Hunter Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1527762225-26024-5-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt-decoder/intel-pt-decoder.c | 17 +++++++++++++++-- tools/perf/util/intel-pt-decoder/intel-pt-decoder.h | 9 +++++++++ tools/perf/util/intel-pt.c | 4 ++++ 3 files changed, 28 insertions(+), 2 deletions(-) (limited to 'tools') 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 881d7c5e5e2a..d404bed7003a 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.c @@ -113,6 +113,7 @@ struct intel_pt_decoder { bool have_cyc; bool fixup_last_mtc; bool have_last_ip; + enum intel_pt_param_flags flags; uint64_t pos; uint64_t last_ip; uint64_t ip; @@ -226,6 +227,8 @@ struct intel_pt_decoder *intel_pt_decoder_new(struct intel_pt_params *params) decoder->return_compression = params->return_compression; decoder->branch_enable = params->branch_enable; + decoder->flags = params->flags; + decoder->period = params->period; decoder->period_type = params->period_type; @@ -1097,6 +1100,15 @@ static bool intel_pt_fup_event(struct intel_pt_decoder *decoder) return ret; } +static inline bool intel_pt_fup_with_nlip(struct intel_pt_decoder *decoder, + struct intel_pt_insn *intel_pt_insn, + uint64_t ip, int err) +{ + return decoder->flags & INTEL_PT_FUP_WITH_NLIP && !err && + intel_pt_insn->branch == INTEL_PT_BR_INDIRECT && + ip == decoder->ip + intel_pt_insn->length; +} + static int intel_pt_walk_fup(struct intel_pt_decoder *decoder) { struct intel_pt_insn intel_pt_insn; @@ -1109,10 +1121,11 @@ static int intel_pt_walk_fup(struct intel_pt_decoder *decoder) err = intel_pt_walk_insn(decoder, &intel_pt_insn, ip); if (err == INTEL_PT_RETURN) return 0; - if (err == -EAGAIN) { + if (err == -EAGAIN || + intel_pt_fup_with_nlip(decoder, &intel_pt_insn, ip, err)) { if (intel_pt_fup_event(decoder)) return 0; - return err; + return -EAGAIN; } decoder->set_fup_tx_flags = false; if (err) diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h index fc1752d50019..51c18d67f4ca 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h +++ b/tools/perf/util/intel-pt-decoder/intel-pt-decoder.h @@ -60,6 +60,14 @@ enum { INTEL_PT_ERR_MAX, }; +enum intel_pt_param_flags { + /* + * FUP packet can contain next linear instruction pointer instead of + * current linear instruction pointer. + */ + INTEL_PT_FUP_WITH_NLIP = 1 << 0, +}; + struct intel_pt_state { enum intel_pt_sample_type type; int err; @@ -106,6 +114,7 @@ struct intel_pt_params { unsigned int mtc_period; uint32_t tsc_ctc_ratio_n; uint32_t tsc_ctc_ratio_d; + enum intel_pt_param_flags flags; }; struct intel_pt_decoder; diff --git a/tools/perf/util/intel-pt.c b/tools/perf/util/intel-pt.c index 3db7f0ee52a8..aec68908d604 100644 --- a/tools/perf/util/intel-pt.c +++ b/tools/perf/util/intel-pt.c @@ -749,6 +749,7 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt, unsigned int queue_nr) { struct intel_pt_params params = { .get_trace = 0, }; + struct perf_env *env = pt->machine->env; struct intel_pt_queue *ptq; ptq = zalloc(sizeof(struct intel_pt_queue)); @@ -830,6 +831,9 @@ static struct intel_pt_queue *intel_pt_alloc_queue(struct intel_pt *pt, } } + if (env->cpuid && !strncmp(env->cpuid, "GenuineIntel,6,92,", 18)) + params.flags |= INTEL_PT_FUP_WITH_NLIP; + ptq->decoder = intel_pt_decoder_new(¶ms); if (!ptq->decoder) goto out_free; -- cgit From 8d628d26b997e6b2e93bf31cfc09e42cc496922e Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 5 Jun 2018 16:31:21 -0300 Subject: perf annnotate: Make __symbol__inc_addr_samples handle src->histograms == NULL Making it a bit more robust, this took place here when a sample appeared right after: ffffffff8a925000 D __nosave_end And before the next considered symbol, which, using kallsyms make us over guess the size of __nosave_end, and then the sequence: hist_entry__inc_addr_samples -> symbol__inc_addr_samples -> symbol__hists -> annotated_source__alloc_histograms Ends up not liking to allocate gigabytes of ram for annotation... This will be alleviated by considering BSS symbols, which we should but don't so far, and then we should investigate those samples further. The testcase was to have: perf top -e cycles/call-graph=fp/,cache-misses/call-graph=dwarf/,instructions Running for a while till it segfaulted trying to access NULL notes->src->histograms. Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-ndfjtpiop3tdcnyjgp320ra8@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/annotate.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'tools') diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 2baa22933b0e..f91775b4bc3c 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c @@ -819,6 +819,11 @@ static int __symbol__inc_addr_samples(struct symbol *sym, struct map *map, offset = addr - sym->start; h = annotated_source__histogram(src, evidx); + if (h == NULL) { + pr_debug("%s(%d): ENOMEM! sym->name=%s, start=%#" PRIx64 ", addr=%#" PRIx64 ", end=%#" PRIx64 ", func: %d\n", + __func__, __LINE__, sym->name, sym->start, addr, sym->end, sym->type == STT_FUNC); + return -ENOMEM; + } h->nr_samples++; h->addr[offset].nr_samples++; h->period += sample->period; -- cgit From 2be732c02adb15ed7f2196f075fe63ba6991642c Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Tue, 5 Jun 2018 17:06:57 -0300 Subject: perf symbols: Add BSS symbols when reading from /proc/kallsyms We were not considering 'B' and 'b' (BSS, uninitialized data objects, that gets set to zero at program start), do it so that we can resolve more symbols in tools doing resolution of data operands, like 'perf c2c'. When using vmlinux, i.e. an ELF symbol table, those were already considered, as the decision was about STT_FUNC or STT_OBJECT, and the later covers BSS symbols. # grep -i ' b ' /proc/kallsyms | head -20 | tail -5 ffffffffa789d030 b execute_command ffffffffa789d038 b initcall_command_line ffffffffa789d040 b static_command_line ffffffffa789d048 B ROOT_DEV ffffffffa789d050 b once.73786 # # readelf -s /lib/modules/`uname -r`/build/vmlinux | grep ROOT_DEV 79219: ffffffff8289d048 4 OBJECT GLOBAL DEFAULT 58 ROOT_DEV # Cc: Adrian Hunter Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-z960xobig39ca1pmp5brl2fr@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/symbol.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 3f632c60888f..d188b7588152 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c @@ -73,7 +73,7 @@ static enum dso_binary_type binary_type_symtab[] = { static bool symbol_type__filter(char symbol_type) { symbol_type = toupper(symbol_type); - return symbol_type == 'T' || symbol_type == 'W' || symbol_type == 'D'; + return symbol_type == 'T' || symbol_type == 'W' || symbol_type == 'D' || symbol_type == 'B'; } static int prefix_underscores_count(const char *str) -- cgit From 5f9e0f3158a5cd0ef7bb205b9f1826b2ec1893a9 Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Fri, 1 Jun 2018 17:01:01 +0800 Subject: perf script python: Move dsoname code to a new function This patch creates a new function get_dsoname() and move the code which gets the dsoname string to this function. That's because in next patch, when we process LBR data, we will also need get_dsoname() to return dsoname for branch from/to. Signed-off-by: Jin Yao Reviewed-by: Andi Kleen Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1527843663-32288-2-git-send-email-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- .../util/scripting-engines/trace-event-python.c | 23 ++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index 7f8afacd08ee..f863e96fb7bc 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -372,6 +372,19 @@ static PyObject *get_field_numeric_entry(struct event_format *event, return obj; } +static const char *get_dsoname(struct map *map) +{ + const char *dsoname = "[unknown]"; + + if (map && map->dso) { + if (symbol_conf.show_kernel_path && map->dso->long_name) + dsoname = map->dso->long_name; + else + dsoname = map->dso->name; + } + + return dsoname; +} static PyObject *python_process_callchain(struct perf_sample *sample, struct perf_evsel *evsel, @@ -427,14 +440,8 @@ static PyObject *python_process_callchain(struct perf_sample *sample, } if (node->map) { - struct map *map = node->map; - const char *dsoname = "[unknown]"; - if (map && map->dso) { - if (symbol_conf.show_kernel_path && map->dso->long_name) - dsoname = map->dso->long_name; - else - dsoname = map->dso->name; - } + const char *dsoname = get_dsoname(node->map); + pydict_set_item_string_decref(pyelem, "dso", _PyUnicode_FromString(dsoname)); } -- cgit From 48a1f565261d2ab1e17f9a3ad532cf6d9e07748d Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Fri, 1 Jun 2018 17:01:02 +0800 Subject: perf script python: Add more PMU fields to event handler dict When doing pmu sampling and then running a script with perf script -s script.py, the process_event function gets dictionary with some fields from the perf ring buffer (like ip, sym, callchain etc). But we miss quite a few fields we report now, for example, LBRs, data source, weight, transaction, iregs, uregs, etc. This patch reports these fields for perf script python processing. New keys/items: --------------- key : brstack items: from, to, from_dsoname, to_dsoname, mispred, predicted, in_tx, abort, cycles. key : brstacksym items: from, to, pred, in_tx, abort (converted string) key : datasrc key : datasrc_decode (decoded string) key : iregs key : uregs key : weight key : transaction v2: --- Add new fields for dso. Use PyBool_FromLong() for mispred/predicted/in_tx/abort Committer notes: !sym->name isn't valid, as its not a pointer, its a [0] array, use !sym->name[0] instead, guaranteed to be the case by symbol__new. This was caught by just one of the containers: 52 54.22 ubuntu:17.04 : FAIL gcc (Ubuntu 6.3.0-12ubuntu2) 6.3.0 20170406 CC /tmp/build/perf/util/scripting-engines/trace-event-python.o util/scripting-engines/trace-event-python.c:534:20: error: address of array 'sym->name' will always evaluate to 'true' [-Werror,-Wpointer-bool-conversion] if (!sym || !sym->name) ~~~~~~^~~~ 1 error generated. mv: cannot stat '/tmp/build/perf/util/scripting-engines/.trace-event-python.o.tmp': No such file or directory /git/linux/tools/build/Makefile.build:96: recipe for target '/tmp/build/perf/util/scripting-engines/trace-event-python.o' failed make[5]: *** [/tmp/build/perf/util/scripting-engines/trace-event-python.o] Error 1 Signed-off-by: Jin Yao Reviewed-by: Andi Kleen Cc: Alexander Shishkin Cc: Jin Yao Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1527843663-32288-3-git-send-email-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- .../util/scripting-engines/trace-event-python.c | 227 ++++++++++++++++++++- 1 file changed, 226 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c index f863e96fb7bc..46e9e19ab1ac 100644 --- a/tools/perf/util/scripting-engines/trace-event-python.c +++ b/tools/perf/util/scripting-engines/trace-event-python.c @@ -48,6 +48,7 @@ #include "cpumap.h" #include "print_binary.h" #include "stat.h" +#include "mem-events.h" #if PY_MAJOR_VERSION < 3 #define _PyUnicode_FromString(arg) \ @@ -455,6 +456,166 @@ exit: return pylist; } +static PyObject *python_process_brstack(struct perf_sample *sample, + struct thread *thread) +{ + struct branch_stack *br = sample->branch_stack; + PyObject *pylist; + u64 i; + + pylist = PyList_New(0); + if (!pylist) + Py_FatalError("couldn't create Python list"); + + if (!(br && br->nr)) + goto exit; + + for (i = 0; i < br->nr; i++) { + PyObject *pyelem; + struct addr_location al; + const char *dsoname; + + pyelem = PyDict_New(); + if (!pyelem) + Py_FatalError("couldn't create Python dictionary"); + + pydict_set_item_string_decref(pyelem, "from", + PyLong_FromUnsignedLongLong(br->entries[i].from)); + pydict_set_item_string_decref(pyelem, "to", + PyLong_FromUnsignedLongLong(br->entries[i].to)); + pydict_set_item_string_decref(pyelem, "mispred", + PyBool_FromLong(br->entries[i].flags.mispred)); + pydict_set_item_string_decref(pyelem, "predicted", + PyBool_FromLong(br->entries[i].flags.predicted)); + pydict_set_item_string_decref(pyelem, "in_tx", + PyBool_FromLong(br->entries[i].flags.in_tx)); + pydict_set_item_string_decref(pyelem, "abort", + PyBool_FromLong(br->entries[i].flags.abort)); + pydict_set_item_string_decref(pyelem, "cycles", + PyLong_FromUnsignedLongLong(br->entries[i].flags.cycles)); + + thread__find_map(thread, sample->cpumode, + br->entries[i].from, &al); + dsoname = get_dsoname(al.map); + pydict_set_item_string_decref(pyelem, "from_dsoname", + _PyUnicode_FromString(dsoname)); + + thread__find_map(thread, sample->cpumode, + br->entries[i].to, &al); + dsoname = get_dsoname(al.map); + pydict_set_item_string_decref(pyelem, "to_dsoname", + _PyUnicode_FromString(dsoname)); + + PyList_Append(pylist, pyelem); + Py_DECREF(pyelem); + } + +exit: + return pylist; +} + +static unsigned long get_offset(struct symbol *sym, struct addr_location *al) +{ + unsigned long offset; + + if (al->addr < sym->end) + offset = al->addr - sym->start; + else + offset = al->addr - al->map->start - sym->start; + + return offset; +} + +static int get_symoff(struct symbol *sym, struct addr_location *al, + bool print_off, char *bf, int size) +{ + unsigned long offset; + + if (!sym || !sym->name[0]) + return scnprintf(bf, size, "%s", "[unknown]"); + + if (!print_off) + return scnprintf(bf, size, "%s", sym->name); + + offset = get_offset(sym, al); + + return scnprintf(bf, size, "%s+0x%x", sym->name, offset); +} + +static int get_br_mspred(struct branch_flags *flags, char *bf, int size) +{ + if (!flags->mispred && !flags->predicted) + return scnprintf(bf, size, "%s", "-"); + + if (flags->mispred) + return scnprintf(bf, size, "%s", "M"); + + return scnprintf(bf, size, "%s", "P"); +} + +static PyObject *python_process_brstacksym(struct perf_sample *sample, + struct thread *thread) +{ + struct branch_stack *br = sample->branch_stack; + PyObject *pylist; + u64 i; + char bf[512]; + struct addr_location al; + + pylist = PyList_New(0); + if (!pylist) + Py_FatalError("couldn't create Python list"); + + if (!(br && br->nr)) + goto exit; + + for (i = 0; i < br->nr; i++) { + PyObject *pyelem; + + pyelem = PyDict_New(); + if (!pyelem) + Py_FatalError("couldn't create Python dictionary"); + + thread__find_symbol(thread, sample->cpumode, + br->entries[i].from, &al); + get_symoff(al.sym, &al, true, bf, sizeof(bf)); + pydict_set_item_string_decref(pyelem, "from", + _PyUnicode_FromString(bf)); + + thread__find_symbol(thread, sample->cpumode, + br->entries[i].to, &al); + get_symoff(al.sym, &al, true, bf, sizeof(bf)); + pydict_set_item_string_decref(pyelem, "to", + _PyUnicode_FromString(bf)); + + get_br_mspred(&br->entries[i].flags, bf, sizeof(bf)); + pydict_set_item_string_decref(pyelem, "pred", + _PyUnicode_FromString(bf)); + + if (br->entries[i].flags.in_tx) { + pydict_set_item_string_decref(pyelem, "in_tx", + _PyUnicode_FromString("X")); + } else { + pydict_set_item_string_decref(pyelem, "in_tx", + _PyUnicode_FromString("-")); + } + + if (br->entries[i].flags.abort) { + pydict_set_item_string_decref(pyelem, "abort", + _PyUnicode_FromString("A")); + } else { + pydict_set_item_string_decref(pyelem, "abort", + _PyUnicode_FromString("-")); + } + + PyList_Append(pylist, pyelem); + Py_DECREF(pyelem); + } + +exit: + return pylist; +} + static PyObject *get_sample_value_as_tuple(struct sample_read_value *value) { PyObject *t; @@ -505,12 +666,63 @@ static void set_sample_read_in_dict(PyObject *dict_sample, pydict_set_item_string_decref(dict_sample, "values", values); } +static void set_sample_datasrc_in_dict(PyObject *dict, + struct perf_sample *sample) +{ + struct mem_info mi = { .data_src.val = sample->data_src }; + char decode[100]; + + pydict_set_item_string_decref(dict, "datasrc", + PyLong_FromUnsignedLongLong(sample->data_src)); + + perf_script__meminfo_scnprintf(decode, 100, &mi); + + pydict_set_item_string_decref(dict, "datasrc_decode", + _PyUnicode_FromString(decode)); +} + +static int regs_map(struct regs_dump *regs, uint64_t mask, char *bf, int size) +{ + unsigned int i = 0, r; + int printed = 0; + + bf[0] = 0; + + for_each_set_bit(r, (unsigned long *) &mask, sizeof(mask) * 8) { + u64 val = regs->regs[i++]; + + printed += scnprintf(bf + printed, size - printed, + "%5s:0x%" PRIx64 " ", + perf_reg_name(r), val); + } + + return printed; +} + +static void set_regs_in_dict(PyObject *dict, + struct perf_sample *sample, + struct perf_evsel *evsel) +{ + struct perf_event_attr *attr = &evsel->attr; + char bf[512]; + + regs_map(&sample->intr_regs, attr->sample_regs_intr, bf, sizeof(bf)); + + pydict_set_item_string_decref(dict, "iregs", + _PyUnicode_FromString(bf)); + + regs_map(&sample->user_regs, attr->sample_regs_user, bf, sizeof(bf)); + + pydict_set_item_string_decref(dict, "uregs", + _PyUnicode_FromString(bf)); +} + static PyObject *get_perf_sample_dict(struct perf_sample *sample, struct perf_evsel *evsel, struct addr_location *al, PyObject *callchain) { - PyObject *dict, *dict_sample; + PyObject *dict, *dict_sample, *brstack, *brstacksym; dict = PyDict_New(); if (!dict) @@ -541,6 +753,11 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample, pydict_set_item_string_decref(dict_sample, "addr", PyLong_FromUnsignedLongLong(sample->addr)); set_sample_read_in_dict(dict_sample, sample, evsel); + pydict_set_item_string_decref(dict_sample, "weight", + PyLong_FromUnsignedLongLong(sample->weight)); + pydict_set_item_string_decref(dict_sample, "transaction", + PyLong_FromUnsignedLongLong(sample->transaction)); + set_sample_datasrc_in_dict(dict_sample, sample); pydict_set_item_string_decref(dict, "sample", dict_sample); pydict_set_item_string_decref(dict, "raw_buf", _PyBytes_FromStringAndSize( @@ -558,6 +775,14 @@ static PyObject *get_perf_sample_dict(struct perf_sample *sample, pydict_set_item_string_decref(dict, "callchain", callchain); + brstack = python_process_brstack(sample, al->thread); + pydict_set_item_string_decref(dict, "brstack", brstack); + + brstacksym = python_process_brstacksym(sample, al->thread); + pydict_set_item_string_decref(dict, "brstacksym", brstacksym); + + set_regs_in_dict(dict, sample, evsel); + return dict; } -- cgit From ac56aa4549cdfd9c56387b35e99e3c868cfc7bd0 Mon Sep 17 00:00:00 2001 From: Jin Yao Date: Fri, 1 Jun 2018 17:01:03 +0800 Subject: perf script python: Add dict fields introduction to Documentation Add a brief introduction about fields to perf-script-python.txt. It should help python script developers in easily finding what fields are supported. Signed-off-by: Jin Yao Reviewed-by: Andi Kleen Cc: Alexander Shishkin Cc: Jin Yao Cc: Jiri Olsa Cc: Kan Liang Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1527843663-32288-4-git-send-email-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-script-python.txt | 26 +++++++++++++++++++++++++ 1 file changed, 26 insertions(+) (limited to 'tools') diff --git a/tools/perf/Documentation/perf-script-python.txt b/tools/perf/Documentation/perf-script-python.txt index 51ec2d20068a..0fb9eda3cbca 100644 --- a/tools/perf/Documentation/perf-script-python.txt +++ b/tools/perf/Documentation/perf-script-python.txt @@ -610,6 +610,32 @@ Various utility functions for use with perf script: nsecs_str(nsecs) - returns printable string in the form secs.nsecs avg(total, n) - returns average given a sum and a total number of values +SUPPORTED FIELDS +---------------- + +Currently supported fields: + +ev_name, comm, pid, tid, cpu, ip, time, period, phys_addr, addr, +symbol, dso, time_enabled, time_running, values, callchain, +brstack, brstacksym, datasrc, datasrc_decode, iregs, uregs, +weight, transaction, raw_buf, attr. + +Some fields have sub items: + +brstack: + from, to, from_dsoname, to_dsoname, mispred, + predicted, in_tx, abort, cycles. + +brstacksym: + items: from, to, pred, in_tx, abort (converted string) + +For example, +We can use this code to print brstack "from", "to", "cycles". + +if 'brstack' in dict: + for entry in dict['brstack']: + print "from %s, to %s, cycles %s" % (entry["from"], entry["to"], entry["cycles"]) + SEE ALSO -------- linkperf:perf-script[1] -- cgit From 41477acf092251eb0cfe83068f48dbcb2521478a Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 7 Jun 2018 14:19:54 -0300 Subject: perf hists: Save the callchain_size in struct hist_entry So that we can figure out the real size of the struct and also be able to tell if callchains may be present in this histogram entry. Since we can't always guarantee that from hist_entry->hists we can use hists_to_evsel, to then look at evsel->attr.sample_type for PERF_SAMPLE_CALLCHAIN, like with the 'perf c2c' tool, that uses plain 'struct hists' instances, we need another way of deciding if a specific hist_entry instance has callchains associated with it, i.e. if its hist_entry->callchain[0] has space allocated for. Cc: Adrian Hunter Cc: David Ahern Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-ptvndealxs1k7myluvu9flnq@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/hist.c | 6 ++++-- tools/perf/util/sort.h | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 52e8fda93a47..0441a92b855f 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -370,9 +370,11 @@ void hists__delete_entries(struct hists *hists) static int hist_entry__init(struct hist_entry *he, struct hist_entry *template, - bool sample_self) + bool sample_self, + size_t callchain_size) { *he = *template; + he->callchain_size = callchain_size; if (symbol_conf.cumulate_callchain) { he->stat_acc = malloc(sizeof(he->stat)); @@ -473,7 +475,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template, he = ops->new(callchain_size); if (he) { - err = hist_entry__init(he, template, sample_self); + err = hist_entry__init(he, template, sample_self, callchain_size); if (err) { ops->free(he); he = NULL; diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 7cf2d5cc038e..9ab9257ed887 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -112,6 +112,8 @@ struct hist_entry { char level; u8 filtered; + + u16 callchain_size; union { /* * Since perf diff only supports the stdio output, TUI -- cgit From e5654455795f2f89328f7b301dacb6926e57e2b8 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 7 Jun 2018 14:27:19 -0300 Subject: perf hists: Make hist_entry__has_callchains() work with 'perf c2c' Since 'perf c2c' uses 'struct hists' not allocated together with a 'struct perf_evsel' instance, we can't go from a 'struct hist_entry' pointer to a 'struct perf_evsel' via he->hists, so, instead, check if space was set aside for hist_entry->callchain[0] at hist_entry__new() time. Reported-by: Jin Yao Reported-by: Jiri Olsa Cc: Adrian Hunter Cc: David Ahern Cc: Namhyung Kim Cc: Wang Nan Fixes: fabd37b837f6 ("perf hists: Check if a hist_entry has callchains before using them") Link: https://lkml.kernel.org/n/tip-e8ife8djvvvwmeze3s4yodii@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/sort.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h index 9ab9257ed887..8bf302cafcec 100644 --- a/tools/perf/util/sort.h +++ b/tools/perf/util/sort.h @@ -155,7 +155,7 @@ struct hist_entry { static __pure inline bool hist_entry__has_callchains(struct hist_entry *he) { - return hists__has_callchains(he->hists); + return he->callchain_size != 0; } static inline bool hist_entry__has_pairs(struct hist_entry *he) -- cgit From 29f9fcdd3f8edccad5809cf939ce921752460fe7 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 7 Jun 2018 14:33:31 -0300 Subject: perf hists browser gtk: Use hist_entry__has_callchains() Since we can't go from struct hists to struct evsel for all cases (c2c is an exception) and we have access to the hist_entry, use hist_entry__has_callchains() in the GTK+ hists browser to figure out if callchains are available. Cc: Adrian Hunter Cc: David Ahern Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-8owkgrruzzi5emvblwh4e6le@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/ui/gtk/hists.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c index b085f1b3e34d..4ab663ec3e5e 100644 --- a/tools/perf/ui/gtk/hists.c +++ b/tools/perf/ui/gtk/hists.c @@ -382,7 +382,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, gtk_tree_store_set(store, &iter, col_idx++, s, -1); } - if (hists__has_callchains(hists) && + if (hist_entry__has_callchains(h) && symbol_conf.use_callchain && hists__has(hists, sym)) { if (callchain_param.mode == CHAIN_GRAPH_REL) total = symbol_conf.cumulate_callchain ? -- cgit From c9d366287042489090da0391318df528bdce9941 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Thu, 7 Jun 2018 14:42:27 -0300 Subject: perf hists: Reimplement hists__has_callchains() There are places where we have only access to struct hists and need to know if any of its hist_entries has callchains, like when drawing headers for the various output modes (stdio, TUI, etc), so, when adding a new hist_entry, check if it has callchains, storing this info for later use by hists__has_callchains(). This reimplementation is necessary because not always a 'struct hists' is allocated together with a 'struct perf evsel', so we can't go from 'hists' to 'perf_event_attr.sample_type & PERF_SAMPLE_CALLCHAIN'. Cc: Adrian Hunter Cc: David Ahern Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-hg5g7yddjio3ljwyqnnaj5dt@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/hist.c | 6 ++++-- tools/perf/util/hist.h | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 0441a92b855f..828cb9794c76 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c @@ -621,9 +621,11 @@ __hists__add_entry(struct hists *hists, .raw_data = sample->raw_data, .raw_size = sample->raw_size, .ops = ops, - }; + }, *he = hists__findnew_entry(hists, &entry, al, sample_self); - return hists__findnew_entry(hists, &entry, al, sample_self); + if (!hists->has_callchains && he && he->callchain_size != 0) + hists->has_callchains = true; + return he; } struct hist_entry *hists__add_entry(struct hists *hists, diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 06607c434949..73049f7f0f60 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h @@ -85,6 +85,7 @@ struct hists { struct events_stats stats; u64 event_stream; u16 col_len[HISTC_NR_COLS]; + bool has_callchains; int socket_filter; struct perf_hpp_list *hpp_list; struct list_head hpp_formats; @@ -222,8 +223,7 @@ static inline struct hists *evsel__hists(struct perf_evsel *evsel) static __pure inline bool hists__has_callchains(struct hists *hists) { - const struct perf_evsel *evsel = hists_to_evsel(hists); - return evsel__has_callchain(evsel); + return hists->has_callchains; } int hists__init(void); -- cgit From f7fa827f5f432a0b1f34e10fc49da93aeef9f817 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 7 Jun 2018 00:15:05 +0200 Subject: perf tools: Fix error index for pmu event parser For events we provide specific error message we need to set error column index, PMU parser is missing that, adding it. Before: $ perf stat -e cycles,krava/cycles/ kill event syntax error: 'cycles,krava/cycles/' \___ Cannot find PMU `krava'. Missing kernel support? After: $ perf stat -e cycles,krava/cycles/ kill event syntax error: 'cycles,krava/cycles/' \___ Cannot find PMU `krava'. Missing kernel support? Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Frederic Weisbecker Cc: Milian Wolff Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/20180606221513.11302-3-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/parse-events.y | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'tools') diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y index 155d2570274f..da8fe57691b8 100644 --- a/tools/perf/util/parse-events.y +++ b/tools/perf/util/parse-events.y @@ -227,11 +227,16 @@ event_def: event_pmu | event_pmu: PE_NAME opt_pmu_config { + struct parse_events_state *parse_state = _parse_state; + struct parse_events_error *error = parse_state->error; struct list_head *list, *orig_terms, *terms; if (parse_events_copy_term_list($2, &orig_terms)) YYABORT; + if (error) + error->idx = @1.first_column; + ALLOC_LIST(list); if (parse_events_add_pmu(_parse_state, list, $1, $2, false, false)) { struct perf_pmu *pmu = NULL; -- cgit From 9660e08ee8cbc94ac835f2c30576c6e51fbece8f Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 7 Jun 2018 00:15:06 +0200 Subject: perf stat: Add --interval-clear option Adding --interval-clear option to clear the screen before next interval. Committer testing: # perf stat -I 1000 --interval-clear And, as expected, it behaves almost like: # watch -n 0 perf stat -a sleep 1 Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Frederic Weisbecker Cc: Milian Wolff Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/20180606221513.11302-4-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/Documentation/perf-stat.txt | 3 +++ tools/perf/builtin-stat.c | 11 +++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/perf/Documentation/perf-stat.txt b/tools/perf/Documentation/perf-stat.txt index 5dfe102fb5b5..b10a90b6a718 100644 --- a/tools/perf/Documentation/perf-stat.txt +++ b/tools/perf/Documentation/perf-stat.txt @@ -178,6 +178,9 @@ Print count deltas for fixed number of times. This option should be used together with "-I" option. example: 'perf stat -I 1000 --interval-count 2 -e cycles -a' +--interval-clear:: +Clear the screen before next interval. + --timeout msecs:: Stop the 'perf stat' session and print count deltas after N milliseconds (minimum: 10 ms). This option is not supported with the "-I" option. diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 096ccb25c11f..f1532e3ac7d7 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -65,6 +65,7 @@ #include "util/tool.h" #include "util/string2.h" #include "util/metricgroup.h" +#include "util/top.h" #include "asm/bug.h" #include @@ -173,6 +174,7 @@ static struct cpu_map *aggr_map; static aggr_get_id_t aggr_get_id; static bool append_file; static bool interval_count; +static bool interval_clear; static const char *output_name; static int output_fd; static int print_free_counters_hint; @@ -1704,9 +1706,12 @@ static void print_interval(char *prefix, struct timespec *ts) FILE *output = stat_config.output; static int num_print_interval; + if (interval_clear) + puts(CONSOLE_CLEAR); + sprintf(prefix, "%6lu.%09lu%s", ts->tv_sec, ts->tv_nsec, csv_sep); - if (num_print_interval == 0 && !csv_output) { + if ((num_print_interval == 0 && !csv_output) || interval_clear) { switch (stat_config.aggr_mode) { case AGGR_SOCKET: fprintf(output, "# time socket cpus"); @@ -1738,7 +1743,7 @@ static void print_interval(char *prefix, struct timespec *ts) } } - if (num_print_interval == 0 && metric_only) + if ((num_print_interval == 0 && metric_only) || interval_clear) print_metric_headers(" ", true); if (++num_print_interval == 25) num_print_interval = 0; @@ -2057,6 +2062,8 @@ static const struct option stat_options[] = { "(overhead is possible for values <= 100ms)"), OPT_INTEGER(0, "interval-count", &stat_config.times, "print counts for fixed number of times"), + OPT_BOOLEAN(0, "interval-clear", &interval_clear, + "clear screen in between new interval"), OPT_UINTEGER(0, "timeout", &stat_config.timeout, "stop workload and print counts after a timeout period in ms (>= 10ms)"), OPT_SET_UINT(0, "per-socket", &stat_config.aggr_mode, -- cgit From b37d33edbf41b532ddd156707c037c6f4784e40b Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 7 Jun 2018 00:15:07 +0200 Subject: perf stat: Use only color_fprintf call in print_metric_only We can call color_fprintf also for non color case, it's handled properly. This change simplifies following patch. Signed-off-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Frederic Weisbecker Cc: Milian Wolff Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/20180606221513.11302-5-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index f1532e3ac7d7..9e7b6f108956 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -1008,10 +1008,7 @@ static void print_metric_only(void *ctx, const char *color, const char *fmt, if (!valid_only_metric(unit)) return; unit = fixunit(buf, os->evsel, unit); - if (color) - n = color_fprintf(out, color, fmt, val); - else - n = fprintf(out, fmt, val); + n = color_fprintf(out, color ?: "", fmt, val); if (n > METRIC_ONLY_LEN) n = METRIC_ONLY_LEN; if (mlen < strlen(unit)) -- cgit From f515572734fb323aa0efe9ea2c546cd7fee327f7 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 7 Jun 2018 00:15:08 +0200 Subject: perf stat: Fix metric column header display alignment Make the metric only display aligned. Before: # perf stat --topdown -I 1000 # time core cpus retiring bad speculation frontend bound backend bound 1.000394323 S0-C0 2 37.4% 12.0% 31.4% 19.2% 1.000394323 S0-C1 2 25.1% 9.2% 43.8% 21.9% 2.001521204 S0-C0 2 36.4% 11.4% 32.4% 19.8% 2.001521204 S0-C1 2 26.2% 9.4% 43.1% 21.3% 3.001930208 S0-C0 2 35.1% 10.7% 33.6% 20.6% 3.001930208 S0-C1 2 28.9% 10.0% 40.0% 21.1% After: # perf stat --topdown -I 1000 # time core cpus retiring bad speculation frontend bound backend bound 1.000303722 S0-C0 2 34.2% 7.6% 34.2% 24.0% 1.000303722 S0-C1 2 33.1% 6.4% 36.9% 23.6% 2.001281055 S0-C0 2 34.6% 6.7% 36.8% 21.8% 2.001281055 S0-C1 2 32.8% 7.1% 38.1% 22.0% 3.001546080 S0-C0 2 39.3% 5.5% 32.7% 22.5% 3.001546080 S0-C1 2 37.8% 6.0% 33.1% 23.1% Signed-off-by: Jiri Olsa Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Frederic Weisbecker Cc: Milian Wolff Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/20180606221513.11302-6-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 9e7b6f108956..8f3fdc052728 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -1001,19 +1001,20 @@ static void print_metric_only(void *ctx, const char *color, const char *fmt, { struct outstate *os = ctx; FILE *out = os->fh; - int n; - char buf[1024]; + char buf[1024], str[1024]; unsigned mlen = METRIC_ONLY_LEN; if (!valid_only_metric(unit)) return; unit = fixunit(buf, os->evsel, unit); - n = color_fprintf(out, color ?: "", fmt, val); - if (n > METRIC_ONLY_LEN) - n = METRIC_ONLY_LEN; if (mlen < strlen(unit)) mlen = strlen(unit) + 1; - fprintf(out, "%*s", mlen - n, ""); + + if (color) + mlen += strlen(color) + sizeof(PERF_COLOR_RESET) - 1; + + color_snprintf(str, sizeof(str), color ?: "", fmt, val); + fprintf(out, "%*s ", mlen, str); } static void print_metric_only_csv(void *ctx, const char *color __maybe_unused, @@ -1053,7 +1054,7 @@ static void print_metric_header(void *ctx, const char *color __maybe_unused, if (csv_output) fprintf(os->fh, "%s%s", unit, csv_sep); else - fprintf(os->fh, "%-*s ", METRIC_ONLY_LEN, unit); + fprintf(os->fh, "%*s ", METRIC_ONLY_LEN, unit); } static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg) @@ -1721,7 +1722,7 @@ static void print_interval(char *prefix, struct timespec *ts) fprintf(output, " counts %*s events\n", unit_width, "unit"); break; case AGGR_NONE: - fprintf(output, "# time CPU"); + fprintf(output, "# time CPU "); if (!metric_only) fprintf(output, " counts %*s events\n", unit_width, "unit"); break; -- cgit From c1a1f5d9da800dc715d8c1d8a9692c63c70c2955 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 7 Jun 2018 00:15:09 +0200 Subject: perf stat: Allow to specify specific metric column len The following change will introduce new metrics, that doesn't need such wide hard coded spacing. Switch METRIC_ONLY_LEN macro usage with metric_only_len variable. Signed-off-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Frederic Weisbecker Cc: Milian Wolff Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/20180606221513.11302-7-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 8f3fdc052728..3fc1f5286d50 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -145,6 +145,8 @@ static struct target target = { typedef int (*aggr_get_id_t)(struct cpu_map *m, int cpu); +#define METRIC_ONLY_LEN 20 + static int run_count = 1; static bool no_inherit = false; static volatile pid_t child_pid = -1; @@ -182,6 +184,7 @@ static int print_mixed_hw_group_error; static u64 *walltime_run; static bool ru_display = false; static struct rusage ru_data; +static unsigned int metric_only_len = METRIC_ONLY_LEN; struct perf_stat { bool record; @@ -969,8 +972,6 @@ static void print_metric_csv(void *ctx, fprintf(out, "%s%s%s%s", csv_sep, vals, csv_sep, unit); } -#define METRIC_ONLY_LEN 20 - /* Filter out some columns that don't work well in metrics only mode */ static bool valid_only_metric(const char *unit) @@ -1002,7 +1003,7 @@ static void print_metric_only(void *ctx, const char *color, const char *fmt, struct outstate *os = ctx; FILE *out = os->fh; char buf[1024], str[1024]; - unsigned mlen = METRIC_ONLY_LEN; + unsigned mlen = metric_only_len; if (!valid_only_metric(unit)) return; @@ -1054,7 +1055,7 @@ static void print_metric_header(void *ctx, const char *color __maybe_unused, if (csv_output) fprintf(os->fh, "%s%s", unit, csv_sep); else - fprintf(os->fh, "%*s ", METRIC_ONLY_LEN, unit); + fprintf(os->fh, "%*s ", metric_only_len, unit); } static void nsec_printout(int id, int nr, struct perf_evsel *evsel, double avg) -- cgit From a5cfa6217c94a1f1cfad4481fc14f5fc399abde3 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Thu, 7 Jun 2018 00:15:10 +0200 Subject: perf stat: Add event parsing error handling to add_default_attributes Add missing error handling for parse_events calls in add_default_attributes functions. The error handler displays error details, like for transactions (-T): Before: $ perf stat -T Cannot set up transaction events After: $ perf stat -T Cannot set up transaction events event syntax error: '..cycles,cpu/cycles-t/,cpu/tx-start/,cpu/el-start/,cpu/cycles-ct/}' \___ unknown term Signed-off-by: Jiri Olsa Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: Frederic Weisbecker Cc: Milian Wolff Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Stephane Eranian Link: http://lkml.kernel.org/r/20180606221513.11302-8-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-stat.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c index 3fc1f5286d50..22547a490e1f 100644 --- a/tools/perf/builtin-stat.c +++ b/tools/perf/builtin-stat.c @@ -2442,14 +2442,13 @@ static int add_default_attributes(void) (PERF_COUNT_HW_CACHE_OP_PREFETCH << 8) | (PERF_COUNT_HW_CACHE_RESULT_MISS << 16) }, }; + struct parse_events_error errinfo; /* Set attrs if no event is selected and !null_run: */ if (null_run) return 0; if (transaction_run) { - struct parse_events_error errinfo; - if (pmu_have_event("cpu", "cycles-ct") && pmu_have_event("cpu", "el-start")) err = parse_events(evsel_list, transaction_attrs, @@ -2460,6 +2459,7 @@ static int add_default_attributes(void) &errinfo); if (err) { fprintf(stderr, "Cannot set up transaction events\n"); + parse_events_print_error(&errinfo, transaction_attrs); return -1; } return 0; @@ -2485,10 +2485,11 @@ static int add_default_attributes(void) pmu_have_event("msr", "smi")) { if (!force_metric_only) metric_only = true; - err = parse_events(evsel_list, smi_cost_attrs, NULL); + err = parse_events(evsel_list, smi_cost_attrs, &errinfo); } else { fprintf(stderr, "To measure SMI cost, it needs " "msr/aperf/, msr/smi/ and cpu/cycles/ support\n"); + parse_events_print_error(&errinfo, smi_cost_attrs); return -1; } if (err) { @@ -2523,12 +2524,13 @@ static int add_default_attributes(void) if (topdown_attrs[0] && str) { if (warn) arch_topdown_group_warn(); - err = parse_events(evsel_list, str, NULL); + err = parse_events(evsel_list, str, &errinfo); if (err) { fprintf(stderr, "Cannot set up top down events %s: %d\n", str, err); free(str); + parse_events_print_error(&errinfo, str); return -1; } } else { -- cgit From 58990d1ff3f7896ee341030e9a7c2e4002570683 Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 7 Jun 2018 17:40:03 +0200 Subject: bpf: reject passing modified ctx to helper functions As commit 28e33f9d78ee ("bpf: disallow arithmetic operations on context pointer") already describes, f1174f77b50c ("bpf/verifier: rework value tracking") removed the specific white-listed cases we had previously where we would allow for pointer arithmetic in order to further generalize it, and allow e.g. context access via modified registers. While the dereferencing of modified context pointers had been forbidden through 28e33f9d78ee, syzkaller did recently manage to trigger several KASAN splats for slab out of bounds access and use after frees by simply passing a modified context pointer to a helper function which would then do the bad access since verifier allowed it in adjust_ptr_min_max_vals(). Rejecting arithmetic on ctx pointer in adjust_ptr_min_max_vals() generally could break existing programs as there's a valid use case in tracing in combination with passing the ctx to helpers as bpf_probe_read(), where the register then becomes unknown at verification time due to adding a non-constant offset to it. An access sequence may look like the following: offset = args->filename; /* field __data_loc filename */ bpf_probe_read(&dst, len, (char *)args + offset); // args is ctx There are two options: i) we could special case the ctx and as soon as we add a constant or bounded offset to it (hence ctx type wouldn't change) we could turn the ctx into an unknown scalar, or ii) we generalize the sanity test for ctx member access into a small helper and assert it on the ctx register that was passed as a function argument. Fwiw, latter is more obvious and less complex at the same time, and one case that may potentially be legitimate in future for ctx member access at least would be for ctx to carry a const offset. Therefore, fix follows approach from ii) and adds test cases to BPF kselftests. Fixes: f1174f77b50c ("bpf/verifier: rework value tracking") Reported-by: syzbot+3d0b2441dbb71751615e@syzkaller.appspotmail.com Reported-by: syzbot+c8504affd4fdd0c1b626@syzkaller.appspotmail.com Reported-by: syzbot+e5190cb881d8660fb1a3@syzkaller.appspotmail.com Reported-by: syzbot+efae31b384d5badbd620@syzkaller.appspotmail.com Signed-off-by: Daniel Borkmann Acked-by: Alexei Starovoitov Acked-by: Yonghong Song Acked-by: Edward Cree Signed-off-by: Alexei Starovoitov --- kernel/bpf/verifier.c | 48 +++++++++++++++--------- tools/testing/selftests/bpf/test_verifier.c | 58 ++++++++++++++++++++++++++++- 2 files changed, 88 insertions(+), 18 deletions(-) (limited to 'tools') diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index d6403b5166f4..cced0c1e63e2 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -1617,6 +1617,30 @@ static int get_callee_stack_depth(struct bpf_verifier_env *env, } #endif +static int check_ctx_reg(struct bpf_verifier_env *env, + const struct bpf_reg_state *reg, int regno) +{ + /* Access to ctx or passing it to a helper is only allowed in + * its original, unmodified form. + */ + + if (reg->off) { + verbose(env, "dereference of modified ctx ptr R%d off=%d disallowed\n", + regno, reg->off); + return -EACCES; + } + + if (!tnum_is_const(reg->var_off) || reg->var_off.value) { + char tn_buf[48]; + + tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off); + verbose(env, "variable ctx access var_off=%s disallowed\n", tn_buf); + return -EACCES; + } + + return 0; +} + /* truncate register to smaller size (in bytes) * must be called with size < BPF_REG_SIZE */ @@ -1686,24 +1710,11 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn verbose(env, "R%d leaks addr into ctx\n", value_regno); return -EACCES; } - /* ctx accesses must be at a fixed offset, so that we can - * determine what type of data were returned. - */ - if (reg->off) { - verbose(env, - "dereference of modified ctx ptr R%d off=%d+%d, ctx+const is allowed, ctx+const+const is not\n", - regno, reg->off, off - reg->off); - return -EACCES; - } - if (!tnum_is_const(reg->var_off) || reg->var_off.value) { - char tn_buf[48]; - tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off); - verbose(env, - "variable ctx access var_off=%s off=%d size=%d", - tn_buf, off, size); - return -EACCES; - } + err = check_ctx_reg(env, reg, regno); + if (err < 0) + return err; + err = check_ctx_access(env, insn_idx, off, size, t, ®_type); if (!err && t == BPF_READ && value_regno >= 0) { /* ctx access returns either a scalar, or a @@ -1984,6 +1995,9 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 regno, expected_type = PTR_TO_CTX; if (type != expected_type) goto err_type; + err = check_ctx_reg(env, reg, regno); + if (err < 0) + return err; } else if (arg_type_is_mem_ptr(arg_type)) { expected_type = PTR_TO_STACK; /* One exception here. In case function allows for NULL to be diff --git a/tools/testing/selftests/bpf/test_verifier.c b/tools/testing/selftests/bpf/test_verifier.c index 7cb1d74057ce..2ecd27b670d7 100644 --- a/tools/testing/selftests/bpf/test_verifier.c +++ b/tools/testing/selftests/bpf/test_verifier.c @@ -8647,7 +8647,7 @@ static struct bpf_test tests[] = { offsetof(struct __sk_buff, mark)), BPF_EXIT_INSN(), }, - .errstr = "dereference of modified ctx ptr R1 off=68+8, ctx+const is allowed, ctx+const+const is not", + .errstr = "dereference of modified ctx ptr", .result = REJECT, .prog_type = BPF_PROG_TYPE_SCHED_CLS, }, @@ -12258,6 +12258,62 @@ static struct bpf_test tests[] = { .result = ACCEPT, .retval = 5, }, + { + "pass unmodified ctx pointer to helper", + .insns = { + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_csum_update), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .result = ACCEPT, + }, + { + "pass modified ctx pointer to helper, 1", + .insns = { + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -612), + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_csum_update), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .result = REJECT, + .errstr = "dereference of modified ctx ptr", + }, + { + "pass modified ctx pointer to helper, 2", + .insns = { + BPF_ALU64_IMM(BPF_ADD, BPF_REG_1, -612), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_get_socket_cookie), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .result_unpriv = REJECT, + .result = REJECT, + .errstr_unpriv = "dereference of modified ctx ptr", + .errstr = "dereference of modified ctx ptr", + }, + { + "pass modified ctx pointer to helper, 3", + .insns = { + BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, 0), + BPF_ALU64_IMM(BPF_AND, BPF_REG_3, 4), + BPF_ALU64_REG(BPF_ADD, BPF_REG_1, BPF_REG_3), + BPF_MOV64_IMM(BPF_REG_2, 0), + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, + BPF_FUNC_csum_update), + BPF_MOV64_IMM(BPF_REG_0, 0), + BPF_EXIT_INSN(), + }, + .prog_type = BPF_PROG_TYPE_SCHED_CLS, + .result = REJECT, + .errstr = "variable ctx access var_off=(0x0; 0x4)", + }, }; static int probe_filter_length(const struct bpf_insn *fp) -- cgit From 9855c4626c67abc24902246ba961e6dd9022dd27 Mon Sep 17 00:00:00 2001 From: "Naveen N. Rao" Date: Wed, 6 Jun 2018 15:01:54 +0530 Subject: selftests/ftrace: Add ppc support for kprobe args tests Add powerpc support for the recently added kprobe args tests. Signed-off-by: Naveen N. Rao Reviewed-by: Masami Hiramatsu Acked-by: Steven Rostedt (VMware) Signed-off-by: Shuah Khan (Samsung OSG) --- .../testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc | 8 ++++++++ .../testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc | 7 +++++++ 2 files changed, 15 insertions(+) (limited to 'tools') diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc index 5ba73035e1d9..a0002563e9ee 100644 --- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_string.tc @@ -24,6 +24,14 @@ arm*) ARG2=%r1 OFFS=4 ;; +ppc64*) + ARG2=%r4 + OFFS=8 +;; +ppc*) + ARG2=%r4 + OFFS=4 +;; *) echo "Please implement other architecture here" exit_untested diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc index 231bcd2c4eb5..d026ff4e562f 100644 --- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc +++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args_syntax.tc @@ -34,6 +34,13 @@ arm*) GOODREG=%r0 BADREG=%ax ;; +ppc*) + GOODREG=%r3 + BADREG=%msr +;; +*) + echo "Please implement other architecture here" + exit_untested esac test_goodarg() # Good-args -- cgit From 53c3daf8cfeae4b1289723c7abeb9540c1630cf8 Mon Sep 17 00:00:00 2001 From: Dan Carpenter Date: Thu, 7 Jun 2018 11:30:02 +0300 Subject: kselftest/cgroup: fix a signedness bug "len" needs to be signed for the error handling to work. Signed-off-by: Dan Carpenter Signed-off-by: Shuah Khan (Samsung OSG) --- tools/testing/selftests/cgroup/cgroup_util.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/testing/selftests/cgroup/cgroup_util.c b/tools/testing/selftests/cgroup/cgroup_util.c index b69bdeb4b9fe..1e9e3c470561 100644 --- a/tools/testing/selftests/cgroup/cgroup_util.c +++ b/tools/testing/selftests/cgroup/cgroup_util.c @@ -35,7 +35,7 @@ out: return len; } -static ssize_t write_text(const char *path, char *buf, size_t len) +static ssize_t write_text(const char *path, char *buf, ssize_t len) { int fd; @@ -140,7 +140,7 @@ long cg_read_key_long(const char *cgroup, const char *control, const char *key) int cg_write(const char *cgroup, const char *control, char *buf) { char path[PATH_MAX]; - size_t len = strlen(buf); + ssize_t len = strlen(buf); snprintf(path, sizeof(path), "%s/%s", cgroup, control); -- cgit From 23316a366e1654e4ad05817c6075bc1019efb30a Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Wed, 6 Jun 2018 09:12:44 -0700 Subject: tools/bpf: fix selftest get_cgroup_id_user Commit f269099a7e7a ("tools/bpf: add a selftest for bpf_get_current_cgroup_id() helper") added a test for bpf_get_current_cgroup_id() helper. The bpf program is attached to tracepoint syscalls/sys_enter_nanosleep and will record the cgroup id if the tracepoint is hit. The test program creates a cgroup and attachs itself to this cgroup and expects that the test program process cgroup id is the same as the cgroup_id retrieved by the bpf program. In a light system where no other processes called nanosleep syscall, the test case can pass. In a busy system where many different processes can hit syscalls/sys_enter_nanosleep tracepoint, the cgroup id recorded by bpf program may not match the test program process cgroup_id. This patch fixed an issue by communicating the test program pid to bpf program. The bpf program only records cgroup id if the current task pid is the same as passed-in pid. This ensures that the recorded cgroup_id is for the cgroup within which the test program resides. Fixes: f269099a7e7a ("tools/bpf: add a selftest for bpf_get_current_cgroup_id() helper") Signed-off-by: Yonghong Song Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/get_cgroup_id_kern.c | 14 +++++++++++++- tools/testing/selftests/bpf/get_cgroup_id_user.c | 12 ++++++++++-- 2 files changed, 23 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/testing/selftests/bpf/get_cgroup_id_kern.c b/tools/testing/selftests/bpf/get_cgroup_id_kern.c index 2cf8cb23f209..014dba10b8a5 100644 --- a/tools/testing/selftests/bpf/get_cgroup_id_kern.c +++ b/tools/testing/selftests/bpf/get_cgroup_id_kern.c @@ -11,12 +11,24 @@ struct bpf_map_def SEC("maps") cg_ids = { .max_entries = 1, }; +struct bpf_map_def SEC("maps") pidmap = { + .type = BPF_MAP_TYPE_ARRAY, + .key_size = sizeof(__u32), + .value_size = sizeof(__u32), + .max_entries = 1, +}; + SEC("tracepoint/syscalls/sys_enter_nanosleep") int trace(void *ctx) { - __u32 key = 0; + __u32 pid = bpf_get_current_pid_tgid(); + __u32 key = 0, *expected_pid; __u64 *val; + expected_pid = bpf_map_lookup_elem(&pidmap, &key); + if (!expected_pid || *expected_pid != pid) + return 0; + val = bpf_map_lookup_elem(&cg_ids, &key); if (val) *val = bpf_get_current_cgroup_id(); diff --git a/tools/testing/selftests/bpf/get_cgroup_id_user.c b/tools/testing/selftests/bpf/get_cgroup_id_user.c index ea19a42e5894..e8da7b39158d 100644 --- a/tools/testing/selftests/bpf/get_cgroup_id_user.c +++ b/tools/testing/selftests/bpf/get_cgroup_id_user.c @@ -50,13 +50,13 @@ int main(int argc, char **argv) const char *probe_name = "syscalls/sys_enter_nanosleep"; const char *file = "get_cgroup_id_kern.o"; int err, bytes, efd, prog_fd, pmu_fd; + int cgroup_fd, cgidmap_fd, pidmap_fd; struct perf_event_attr attr = {}; - int cgroup_fd, cgidmap_fd; struct bpf_object *obj; __u64 kcgid = 0, ucgid; + __u32 key = 0, pid; int exit_code = 1; char buf[256]; - __u32 key = 0; err = setup_cgroup_environment(); if (CHECK(err, "setup_cgroup_environment", "err %d errno %d\n", err, @@ -81,6 +81,14 @@ int main(int argc, char **argv) cgidmap_fd, errno)) goto close_prog; + pidmap_fd = bpf_find_map(__func__, obj, "pidmap"); + if (CHECK(pidmap_fd < 0, "bpf_find_map", "err %d errno %d\n", + pidmap_fd, errno)) + goto close_prog; + + pid = getpid(); + bpf_map_update_elem(pidmap_fd, &key, &pid, 0); + snprintf(buf, sizeof(buf), "/sys/kernel/debug/tracing/events/%s/id", probe_name); efd = open(buf, O_RDONLY, 0); -- cgit From 4c8205273626f27b9e5a64bdc194ab483a8cce66 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Fri, 8 Jun 2018 02:22:11 +0200 Subject: perf c2c: Keep struct hist_entry at the end of struct c2c_hist_entry Exactly as the comment just before 'struct c2c_hist_entry" says, i.e. the last entry in struct hist_entry is a zero length array, that when allocating space for hist_entry gets extra space if callchains are in use, which, if hist_entry is not at the end of c2c_hist_entry, the members after it gets corrupted when callchains get added to the rb trees collecting them, etc. Signed-off-by: Jiri Olsa Reported-by: Arnaldo Carvalho de Melo Cc: Jin Yao Fixes: 7f834c2e84bb ("perf c2c report: Display node for cacheline address") Link: http://lkml.kernel.org/n/tip-bh0ke4fh2ygpj3yowna7o1di@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-c2c.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-c2c.c b/tools/perf/builtin-c2c.c index 307b3594525f..6a8738f7ead3 100644 --- a/tools/perf/builtin-c2c.c +++ b/tools/perf/builtin-c2c.c @@ -56,16 +56,16 @@ struct c2c_hist_entry { struct compute_stats cstats; + unsigned long paddr; + unsigned long paddr_cnt; + bool paddr_zero; + char *nodestr; + /* * must be at the end, * because of its callchain dynamic entry */ struct hist_entry he; - - unsigned long paddr; - unsigned long paddr_cnt; - bool paddr_zero; - char *nodestr; }; static char const *coalesce_default = "pid,iaddr"; -- cgit From fad76d4333fe73cf3f73704aa34d4ce523b1c458 Mon Sep 17 00:00:00 2001 From: Seeteena Thoufeek Date: Fri, 8 Jun 2018 16:32:28 +0530 Subject: perf script: Show hw-cache events 'perf script' fails to report hardware cache events (PERF_TYPE_HW_CACHE) where as 'perf report' shows the samples. Fix it. Ex, # perf record -e L1-dcache-loads ./a.out [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.008 MB perf.data (11 samples)] Before patch: # perf script | wc -l 0 After patch: # perf script | wc -l 11 Committer testing: [root@jouet ~]# perf script | head -30 | tail Timer 9803 [2] 8.963330: 1554 L1-dcache-loads: 7ffef89baae4 __vdso_clock_gettime+0xf4 ([vdso]) swapper 0 [2] 8.963343: 5626 L1-dcache-loads: ffffffffa66f4f6b cpuidle_not_av+0xb (/lib/modules/4.17.0-rc5/build/vmlinux) firefox 4853 [2] 8.964070: 18935 L1-dcache-loads: 7f0b9a00dc30 xcb_poll_for_event+0x0 (/usr/lib64/libxcb.so.1.1.0) Softwar~cTh 4928 [2] 8.964548: 15928 L1-dcache-loads: ffffffffa60d795c update_curr+0x10c (/lib/modules/4.17.0-rc5/build/vmlinux) firefox 4853 [2] 8.964675: 14978 L1-dcache-loads: ffffffffa6897018 mutex_unlock+0x18 (/lib/modules/4.17.0-rc5/build/vmlinux) gnome-shell 2026 [3] 8.964693: 50670 L1-dcache-loads: 7fa08854de6d g_source_iter_next+0x6d (/usr/lib64/libglib-2.0.so.0.5400.3) Compositor 4929 [1] 8.964784: 71772 L1-dcache-loads: 7f0b936bf078 [unknown] (/usr/lib64/firefox/libxul.so) Xwayland 2096 [2] 8.964919: 16799 L1-dcache-loads: 7f68ce2fcb8a glXGetCurrentContext+0x1a (/usr/lib64/libGLX.so.0.0.0) gnome-shell 2026 [3] 8.964997: 50670 L1-dcache-loads: 7fa08854de6d g_source_iter_next+0x6d (/usr/lib64/libglib-2.0.so.0.5400.3) [root@jouet ~]# Signed-off-by: Seeteena Thoufeek Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Jiri Olsa Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/1528455748-20087-1-git-send-email-s1seetee@linux.vnet.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'tools') diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index b3bf35512d21..a31d7082188e 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -180,6 +180,18 @@ static struct { PERF_OUTPUT_EVNAME | PERF_OUTPUT_TRACE }, + [PERF_TYPE_HW_CACHE] = { + .user_set = false, + + .fields = PERF_OUTPUT_COMM | PERF_OUTPUT_TID | + PERF_OUTPUT_CPU | PERF_OUTPUT_TIME | + PERF_OUTPUT_EVNAME | PERF_OUTPUT_IP | + PERF_OUTPUT_SYM | PERF_OUTPUT_SYMOFFSET | + PERF_OUTPUT_DSO | PERF_OUTPUT_PERIOD, + + .invalid_fields = PERF_OUTPUT_TRACE | PERF_OUTPUT_BPF_OUTPUT, + }, + [PERF_TYPE_RAW] = { .user_set = false, -- cgit From 1c9ca7e9836a4df1518568ea47461c5ef7c2cf8b Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Fri, 8 Jun 2018 08:51:27 +0200 Subject: selftests: bpf: fix urandom_read build issue MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit gcc complains that urandom_read gets built twice. gcc -o tools/testing/selftests/bpf/urandom_read -static urandom_read.c -Wl,--build-id gcc -Wall -O2 -I../../../include/uapi -I../../../lib -I../../../lib/bpf -I../../../../include/generated -I../../../include urandom_read.c urandom_read -lcap -lelf -lrt -lpthread -o tools/testing/selftests/bpf/urandom_read gcc: fatal error: input file ‘tools/testing/selftests/bpf/urandom_read’ is the same as output file compilation terminated. ../lib.mk:110: recipe for target 'tools/testing/selftests/bpf/urandom_read' failed To fix this issue remove the urandom_read target and so target TEST_CUSTOM_PROGS gets used. Fixes: 81f77fd0deeb ("bpf: add selftest for stackmap with BPF_F_STACK_BUILD_ID") Signed-off-by: Anders Roxell Acked-by: Yonghong Song Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/Makefile | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/testing/selftests/bpf/Makefile b/tools/testing/selftests/bpf/Makefile index 607ed8729c06..7a6214e9ae58 100644 --- a/tools/testing/selftests/bpf/Makefile +++ b/tools/testing/selftests/bpf/Makefile @@ -16,9 +16,7 @@ LDLIBS += -lcap -lelf -lrt -lpthread TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read all: $(TEST_CUSTOM_PROGS) -$(TEST_CUSTOM_PROGS): urandom_read - -urandom_read: urandom_read.c +$(TEST_CUSTOM_PROGS): $(OUTPUT)/%: %.c $(CC) -o $(TEST_CUSTOM_PROGS) -static $< -Wl,--build-id # Order correspond to 'make run_tests' order -- cgit From 766d3571d8e50d3a73b77043dc632226f9e6b389 Mon Sep 17 00:00:00 2001 From: "Michael S. Tsirkin" Date: Fri, 8 Jun 2018 02:19:53 +0300 Subject: kvm: fix typo in flag name KVM_X86_DISABLE_EXITS_HTL really refers to exit on halt. Obviously a typo: should be named KVM_X86_DISABLE_EXITS_HLT. Fixes: caa057a2cad ("KVM: X86: Provide a capability to disable HLT intercepts") Cc: stable@vger.kernel.org Signed-off-by: Michael S. Tsirkin Signed-off-by: Paolo Bonzini --- arch/x86/kvm/x86.c | 4 ++-- include/uapi/linux/kvm.h | 4 ++-- tools/include/uapi/linux/kvm.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) (limited to 'tools') diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 439fb0c7dbc0..06dd4cdb2ca8 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2899,7 +2899,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) r = KVM_CLOCK_TSC_STABLE; break; case KVM_CAP_X86_DISABLE_EXITS: - r |= KVM_X86_DISABLE_EXITS_HTL | KVM_X86_DISABLE_EXITS_PAUSE; + r |= KVM_X86_DISABLE_EXITS_HLT | KVM_X86_DISABLE_EXITS_PAUSE; if(kvm_can_mwait_in_guest()) r |= KVM_X86_DISABLE_EXITS_MWAIT; break; @@ -4253,7 +4253,7 @@ split_irqchip_unlock: if ((cap->args[0] & KVM_X86_DISABLE_EXITS_MWAIT) && kvm_can_mwait_in_guest()) kvm->arch.mwait_in_guest = true; - if (cap->args[0] & KVM_X86_DISABLE_EXITS_HTL) + if (cap->args[0] & KVM_X86_DISABLE_EXITS_HLT) kvm->arch.hlt_in_guest = true; if (cap->args[0] & KVM_X86_DISABLE_EXITS_PAUSE) kvm->arch.pause_in_guest = true; diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index b252ceb3965c..b6270a3b38e9 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -677,10 +677,10 @@ struct kvm_ioeventfd { }; #define KVM_X86_DISABLE_EXITS_MWAIT (1 << 0) -#define KVM_X86_DISABLE_EXITS_HTL (1 << 1) +#define KVM_X86_DISABLE_EXITS_HLT (1 << 1) #define KVM_X86_DISABLE_EXITS_PAUSE (1 << 2) #define KVM_X86_DISABLE_VALID_EXITS (KVM_X86_DISABLE_EXITS_MWAIT | \ - KVM_X86_DISABLE_EXITS_HTL | \ + KVM_X86_DISABLE_EXITS_HLT | \ KVM_X86_DISABLE_EXITS_PAUSE) /* for KVM_ENABLE_CAP */ diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h index b02c41e53d56..39e364c70caf 100644 --- a/tools/include/uapi/linux/kvm.h +++ b/tools/include/uapi/linux/kvm.h @@ -677,10 +677,10 @@ struct kvm_ioeventfd { }; #define KVM_X86_DISABLE_EXITS_MWAIT (1 << 0) -#define KVM_X86_DISABLE_EXITS_HTL (1 << 1) +#define KVM_X86_DISABLE_EXITS_HLT (1 << 1) #define KVM_X86_DISABLE_EXITS_PAUSE (1 << 2) #define KVM_X86_DISABLE_VALID_EXITS (KVM_X86_DISABLE_EXITS_MWAIT | \ - KVM_X86_DISABLE_EXITS_HTL | \ + KVM_X86_DISABLE_EXITS_HLT | \ KVM_X86_DISABLE_EXITS_PAUSE) /* for KVM_ENABLE_CAP */ -- cgit From 31962c8c78b3cb480e28120a20b45811b76e207d Mon Sep 17 00:00:00 2001 From: Davide Caratti Date: Mon, 11 Jun 2018 16:02:36 +0200 Subject: tc-testing: ife: fix wrong teardown command in test b7b8 fix failures in the 'teardown' stage of test b7b8, probably a leftover of commit 7c5995b33d6e ("tc-testing: fixed copy-pasting error in ife tests") Fixes: a56e6bcd34b55 ("tc-testing: updated ife test cases") Signed-off-by: Davide Caratti Signed-off-by: David S. Miller --- tools/testing/selftests/tc-testing/tc-tests/actions/ife.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/testing/selftests/tc-testing/tc-tests/actions/ife.json b/tools/testing/selftests/tc-testing/tc-tests/actions/ife.json index de97e4ff705c..637ea0219617 100644 --- a/tools/testing/selftests/tc-testing/tc-tests/actions/ife.json +++ b/tools/testing/selftests/tc-testing/tc-tests/actions/ife.json @@ -568,7 +568,7 @@ "matchPattern": "action order [0-9]*: ife encode action pass.*type 0xED3E.*use tcindex 65535.*index 1", "matchCount": "1", "teardown": [ - "$TC actions flush action skbedit" + "$TC actions flush action ife" ] }, { -- cgit From 73df93c57c0b18195a2fe5429747e00018b3e863 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Mon, 11 Jun 2018 22:35:48 -0700 Subject: tools/bpftool: fix a bug in bpftool perf Commit b04df400c302 ("tools/bpftool: add perf subcommand") introduced bpftool subcommand perf to query bpf program kuprobe and tracepoint attachments. The perf subcommand will first test whether bpf subcommand BPF_TASK_FD_QUERY is supported in kernel or not. It does it by opening a file with argv[0] and feeds the file descriptor and current task pid to the kernel for querying. Such an approach won't work if the argv[0] cannot be opened successfully in the current directory. This is especially true when bpftool is accessible through PATH env variable. The error below reflects the open failure for file argv[0] at home directory. [yhs@localhost ~]$ which bpftool /usr/local/sbin/bpftool [yhs@localhost ~]$ bpftool perf Error: perf_query_support: No such file or directory To fix the issue, let us open root directory ("/") which exists in every linux system. With the fix, the error message will correctly reflect the permission issue. [yhs@localhost ~]$ which bpftool /usr/local/sbin/bpftool [yhs@localhost ~]$ bpftool perf Error: perf_query_support: Operation not permitted HINT: non root or kernel doesn't support TASK_FD_QUERY Fixes: b04df400c302 ("tools/bpftool: add perf subcommand") Reported-by: Alexei Starovoitov Signed-off-by: Yonghong Song Reviewed-by: Jakub Kicinski Signed-off-by: Daniel Borkmann --- tools/bpf/bpftool/perf.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/bpf/bpftool/perf.c b/tools/bpf/bpftool/perf.c index ac6b1a12c9b7..b76b77dcfd1f 100644 --- a/tools/bpf/bpftool/perf.c +++ b/tools/bpf/bpftool/perf.c @@ -29,9 +29,10 @@ static bool has_perf_query_support(void) if (perf_query_supported) goto out; - fd = open(bin_name, O_RDONLY); + fd = open("/", O_RDONLY); if (fd < 0) { - p_err("perf_query_support: %s", strerror(errno)); + p_err("perf_query_support: cannot open directory \"/\" (%s)", + strerror(errno)); goto out; } -- cgit From 3bce593ac06b4f18710274cfb084369b3d7909eb Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Tue, 12 Jun 2018 13:05:10 +0200 Subject: selftests: bpf: config: add config fragments Tests test_tunnel.sh fails due to config fragments ins't enabled. Fixes: 933a741e3b82 ("selftests/bpf: bpf tunnel test.") Signed-off-by: Anders Roxell Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/config | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'tools') diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config index 1eefe211a4a8..7eb613ffef55 100644 --- a/tools/testing/selftests/bpf/config +++ b/tools/testing/selftests/bpf/config @@ -7,3 +7,13 @@ CONFIG_CGROUP_BPF=y CONFIG_NETDEVSIM=m CONFIG_NET_CLS_ACT=y CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_IPIP=y +CONFIG_IPV6=y +CONFIG_NET_IPGRE_DEMUX=y +CONFIG_NET_IPGRE=y +CONFIG_IPV6_GRE=y +CONFIG_CRYPTO_USER_API_HASH=m +CONFIG_CRYPTO_HMAC=m +CONFIG_CRYPTO_SHA256=m +CONFIG_VXLAN=y +CONFIG_GENEVE=y -- cgit From 07480cbc05ef1ff7301cb11afb7d894ad3d0916a Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 14 Jun 2018 11:06:55 -0700 Subject: tools: bpftool: improve accuracy of load time BPF program load time is reported from the kernel relative to boot time. If conversion to wall clock does not take nanosecond parts into account, the load time reported by bpftool may differ by one second from run to run. This means JSON object reported by bpftool for a program will randomly change. Fixes: 71bb428fe2c1 ("tools: bpf: add bpftool") Signed-off-by: Jakub Kicinski Reviewed-by: Quentin Monnet Signed-off-by: Daniel Borkmann --- tools/bpf/bpftool/prog.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index a4f435203fef..05f42a46d6ed 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -90,7 +90,9 @@ static void print_boot_time(__u64 nsecs, char *buf, unsigned int size) } wallclock_secs = (real_time_ts.tv_sec - boot_time_ts.tv_sec) + - nsecs / 1000000000; + (real_time_ts.tv_nsec - boot_time_ts.tv_nsec + nsecs) / + 1000000000; + if (!localtime_r(&wallclock_secs, &load_tm)) { snprintf(buf, size, "%llu", nsecs / 1000000000); -- cgit From 47cf52a246e526e2092d60ac01c54af9bd45dcc9 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Thu, 14 Jun 2018 11:06:56 -0700 Subject: selftests/bpf: test offloads even with BPF programs present Modern distroes increasingly make use of BPF programs. Default Ubuntu 18.04 installation boots with a number of cgroup_skb programs loaded. test_offloads.py tries to check if programs and maps are not leaked on error paths by confirming the list of programs on the system is empty between tests. Since we can no longer expect the system to have no BPF objects at boot try to remember the programs and maps present at the start, and skip those when scanning the system. Signed-off-by: Jakub Kicinski Reviewed-by: Quentin Monnet Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_offload.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/testing/selftests/bpf/test_offload.py b/tools/testing/selftests/bpf/test_offload.py index e78aad0a68bb..be800d0e7a84 100755 --- a/tools/testing/selftests/bpf/test_offload.py +++ b/tools/testing/selftests/bpf/test_offload.py @@ -163,6 +163,10 @@ def bpftool(args, JSON=True, ns="", fail=True): def bpftool_prog_list(expected=None, ns=""): _, progs = bpftool("prog show", JSON=True, ns=ns, fail=True) + # Remove the base progs + for p in base_progs: + if p in progs: + progs.remove(p) if expected is not None: if len(progs) != expected: fail(True, "%d BPF programs loaded, expected %d" % @@ -171,6 +175,10 @@ def bpftool_prog_list(expected=None, ns=""): def bpftool_map_list(expected=None, ns=""): _, maps = bpftool("map show", JSON=True, ns=ns, fail=True) + # Remove the base maps + for m in base_maps: + if m in maps: + maps.remove(m) if expected is not None: if len(maps) != expected: fail(True, "%d BPF maps loaded, expected %d" % @@ -585,8 +593,8 @@ skip(os.getuid() != 0, "test must be run as root") # Check tools ret, progs = bpftool("prog", fail=False) skip(ret != 0, "bpftool not installed") -# Check no BPF programs are loaded -skip(len(progs) != 0, "BPF programs already loaded on the system") +base_progs = progs +_, base_maps = bpftool("map") # Check netdevsim ret, out = cmd("modprobe netdevsim", fail=False) -- cgit From 36ffdbc0a2d9f7280e49dbe5ea53c289ad112a8c Mon Sep 17 00:00:00 2001 From: Jian Wang Date: Fri, 15 Jun 2018 03:22:17 +0200 Subject: bpf, selftest: check tunnel type more accurately Grep tunnel type directly to make sure 'ip' command supports it. Signed-off-by: Jian Wang Acked-by: Yonghong Song Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_tunnel.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/testing/selftests/bpf/test_tunnel.sh b/tools/testing/selftests/bpf/test_tunnel.sh index aeb2901f21f4..c4b5fbbaa760 100755 --- a/tools/testing/selftests/bpf/test_tunnel.sh +++ b/tools/testing/selftests/bpf/test_tunnel.sh @@ -668,7 +668,7 @@ cleanup_exit() check() { - ip link help $1 2>&1 | grep -q "^Usage:" + ip link help 2>&1 | grep -q "\s$1\s" if [ $? -ne 0 ];then echo "SKIP $1: iproute2 not support" cleanup -- cgit From 26bf8a89d887c0686acef0f44eaadd49abfcab03 Mon Sep 17 00:00:00 2001 From: William Tu Date: Thu, 14 Jun 2018 05:01:06 -0700 Subject: bpf, selftests: delete xfrm tunnel when test exits. Make the printting of bpf xfrm tunnel better and cleanup xfrm state and policy when xfrm test finishes. Signed-off-by: William Tu Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_tunnel.sh | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'tools') diff --git a/tools/testing/selftests/bpf/test_tunnel.sh b/tools/testing/selftests/bpf/test_tunnel.sh index c4b5fbbaa760..546aee3e9fb4 100755 --- a/tools/testing/selftests/bpf/test_tunnel.sh +++ b/tools/testing/selftests/bpf/test_tunnel.sh @@ -608,28 +608,26 @@ setup_xfrm_tunnel() test_xfrm_tunnel() { config_device - #tcpdump -nei veth1 ip & - output=$(mktemp) - cat /sys/kernel/debug/tracing/trace_pipe | tee $output & - setup_xfrm_tunnel + > /sys/kernel/debug/tracing/trace + setup_xfrm_tunnel tc qdisc add dev veth1 clsact tc filter add dev veth1 proto ip ingress bpf da obj test_tunnel_kern.o \ sec xfrm_get_state ip netns exec at_ns0 ping $PING_ARG 10.1.1.200 sleep 1 - grep "reqid 1" $output + grep "reqid 1" /sys/kernel/debug/tracing/trace check_err $? - grep "spi 0x1" $output + grep "spi 0x1" /sys/kernel/debug/tracing/trace check_err $? - grep "remote ip 0xac100164" $output + grep "remote ip 0xac100164" /sys/kernel/debug/tracing/trace check_err $? cleanup if [ $ret -ne 0 ]; then - echo -e ${RED}"FAIL: xfrm tunnel"${NC} - return 1 - fi - echo -e ${GREEN}"PASS: xfrm tunnel"${NC} + echo -e ${RED}"FAIL: xfrm tunnel"${NC} + return 1 + fi + echo -e ${GREEN}"PASS: xfrm tunnel"${NC} } attach_bpf() @@ -657,6 +655,10 @@ cleanup() ip link del ip6geneve11 2> /dev/null ip link del erspan11 2> /dev/null ip link del ip6erspan11 2> /dev/null + ip xfrm policy delete dir out src 10.1.1.200/32 dst 10.1.1.100/32 2> /dev/null + ip xfrm policy delete dir in src 10.1.1.100/32 dst 10.1.1.200/32 2> /dev/null + ip xfrm state delete src 172.16.1.100 dst 172.16.1.200 proto esp spi 0x1 2> /dev/null + ip xfrm state delete src 172.16.1.200 dst 172.16.1.100 proto esp spi 0x2 2> /dev/null } cleanup_exit() -- cgit From 5fb94e9ca333f0fe1d96de06704a79942b3832c3 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 8 May 2018 15:14:57 -0300 Subject: docs: Fix some broken references As we move stuff around, some doc references are broken. Fix some of them via this script: ./scripts/documentation-file-ref-check --fix Manually checked if the produced result is valid, removing a few false-positives. Acked-by: Takashi Iwai Acked-by: Masami Hiramatsu Acked-by: Stephen Boyd Acked-by: Charles Keepax Acked-by: Mathieu Poirier Reviewed-by: Coly Li Signed-off-by: Mauro Carvalho Chehab Acked-by: Jonathan Corbet --- Documentation/admin-guide/kernel-parameters.txt | 4 ++-- .../devicetree/bindings/input/rotary-encoder.txt | 2 +- Documentation/driver-api/gpio/consumer.rst | 2 +- Documentation/kprobes.txt | 4 ++-- Documentation/trace/coresight.txt | 2 +- Documentation/trace/ftrace-uses.rst | 2 +- Documentation/trace/histogram.txt | 2 +- Documentation/trace/intel_th.rst | 2 +- Documentation/trace/tracepoint-analysis.rst | 6 +++--- Documentation/translations/ja_JP/howto.rst | 4 ++-- Documentation/translations/zh_CN/magic-number.txt | 4 ++-- .../translations/zh_CN/video4linux/omap3isp.txt | 4 ++-- MAINTAINERS | 20 ++++++++++---------- arch/Kconfig | 2 +- arch/arm/include/asm/cacheflush.h | 2 +- arch/arm64/include/asm/cacheflush.h | 2 +- arch/microblaze/include/asm/cacheflush.h | 2 +- arch/um/Kconfig.um | 2 +- arch/unicore32/include/asm/cacheflush.h | 2 +- arch/x86/entry/vsyscall/vsyscall_64.c | 2 +- arch/xtensa/include/asm/cacheflush.h | 4 ++-- block/Kconfig | 2 +- certs/Kconfig | 2 +- crypto/asymmetric_keys/asymmetric_type.c | 2 +- crypto/asymmetric_keys/signature.c | 2 +- drivers/char/Kconfig | 2 +- drivers/clk/clk.c | 4 ++-- drivers/clk/ingenic/cgu.h | 2 +- drivers/gpu/vga/Kconfig | 2 +- drivers/gpu/vga/vgaarb.c | 2 +- drivers/input/joystick/Kconfig | 10 +++++----- drivers/input/joystick/walkera0701.c | 2 +- drivers/input/misc/Kconfig | 4 ++-- drivers/input/misc/rotary_encoder.c | 2 +- drivers/input/mouse/Kconfig | 6 +++--- drivers/input/mouse/alps.c | 2 +- drivers/input/touchscreen/wm97xx-core.c | 2 +- drivers/lightnvm/pblk-rb.c | 2 +- drivers/md/bcache/Kconfig | 2 +- drivers/md/bcache/btree.c | 2 +- drivers/md/bcache/extents.c | 2 +- drivers/media/dvb-core/dvb_ringbuffer.c | 2 +- drivers/media/pci/meye/Kconfig | 2 +- drivers/media/platform/pxa_camera.c | 4 ++-- .../media/platform/soc_camera/sh_mobile_ceu_camera.c | 2 +- drivers/media/radio/Kconfig | 2 +- drivers/media/radio/si470x/Kconfig | 2 +- drivers/media/usb/dvb-usb-v2/lmedm04.c | 2 +- drivers/media/usb/zr364xx/Kconfig | 2 +- drivers/parport/Kconfig | 6 +++--- drivers/staging/media/bcm2048/TODO | 2 +- include/keys/asymmetric-subtype.h | 2 +- include/keys/asymmetric-type.h | 2 +- include/linux/assoc_array.h | 2 +- include/linux/assoc_array_priv.h | 2 +- include/linux/circ_buf.h | 2 +- include/linux/ftrace.h | 2 +- include/linux/rculist_nulls.h | 2 +- include/uapi/linux/prctl.h | 2 +- include/xen/interface/io/kbdif.h | 2 +- kernel/cgroup/cpuset.c | 2 +- kernel/trace/Kconfig | 16 ++++++++-------- lib/Kconfig | 2 +- security/selinux/hooks.c | 2 +- sound/core/Kconfig | 4 ++-- sound/drivers/Kconfig | 4 ++-- sound/pci/Kconfig | 10 +++++----- tools/include/uapi/linux/prctl.h | 2 +- tools/lib/api/fs/fs.c | 2 +- tools/perf/util/bpf-prologue.c | 2 +- .../pm-graph/config/custom-timeline-functions.cfg | 4 ++-- 71 files changed, 113 insertions(+), 113 deletions(-) (limited to 'tools') diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt index 638342d0a095..6fa3f31ed2a5 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -4335,7 +4335,7 @@ [FTRACE] Set and start specified trace events in order to facilitate early boot debugging. The event-list is a comma separated list of trace events to enable. See - also Documentation/trace/events.txt + also Documentation/trace/events.rst trace_options=[option-list] [FTRACE] Enable or disable tracer options at boot. @@ -4350,7 +4350,7 @@ trace_options=stacktrace - See also Documentation/trace/ftrace.txt "trace options" + See also Documentation/trace/ftrace.rst "trace options" section. tp_printk[FTRACE] diff --git a/Documentation/devicetree/bindings/input/rotary-encoder.txt b/Documentation/devicetree/bindings/input/rotary-encoder.txt index f99fe5cdeaec..a644408b33b8 100644 --- a/Documentation/devicetree/bindings/input/rotary-encoder.txt +++ b/Documentation/devicetree/bindings/input/rotary-encoder.txt @@ -28,7 +28,7 @@ Deprecated properties: This property is deprecated. Instead, a 'steps-per-period ' value should be used, such as "rotary-encoder,steps-per-period = <2>". -See Documentation/input/rotary-encoder.txt for more information. +See Documentation/input/devices/rotary-encoder.rst for more information. Example: diff --git a/Documentation/driver-api/gpio/consumer.rst b/Documentation/driver-api/gpio/consumer.rst index c71a50d85b50..aa03f389d41d 100644 --- a/Documentation/driver-api/gpio/consumer.rst +++ b/Documentation/driver-api/gpio/consumer.rst @@ -57,7 +57,7 @@ device that displays digits), an additional index argument can be specified:: enum gpiod_flags flags) For a more detailed description of the con_id parameter in the DeviceTree case -see Documentation/gpio/board.txt +see Documentation/driver-api/gpio/board.rst The flags parameter is used to optionally specify a direction and initial value for the GPIO. Values can be: diff --git a/Documentation/kprobes.txt b/Documentation/kprobes.txt index 22208bf2386d..cb3b0de83fc6 100644 --- a/Documentation/kprobes.txt +++ b/Documentation/kprobes.txt @@ -724,8 +724,8 @@ migrate your tool to one of the following options: See following documents: - - Documentation/trace/kprobetrace.txt - - Documentation/trace/events.txt + - Documentation/trace/kprobetrace.rst + - Documentation/trace/events.rst - tools/perf/Documentation/perf-probe.txt diff --git a/Documentation/trace/coresight.txt b/Documentation/trace/coresight.txt index 1d74ad0202b6..efbc832146e7 100644 --- a/Documentation/trace/coresight.txt +++ b/Documentation/trace/coresight.txt @@ -426,5 +426,5 @@ root@genericarmv8:~# Details on how to use the generic STM API can be found here [2]. [1]. Documentation/ABI/testing/sysfs-bus-coresight-devices-stm -[2]. Documentation/trace/stm.txt +[2]. Documentation/trace/stm.rst [3]. https://github.com/Linaro/perf-opencsd diff --git a/Documentation/trace/ftrace-uses.rst b/Documentation/trace/ftrace-uses.rst index 00283b6dd101..1fbc69894eed 100644 --- a/Documentation/trace/ftrace-uses.rst +++ b/Documentation/trace/ftrace-uses.rst @@ -199,7 +199,7 @@ If @buf is NULL and reset is set, all functions will be enabled for tracing. The @buf can also be a glob expression to enable all functions that match a specific pattern. -See Filter Commands in :file:`Documentation/trace/ftrace.txt`. +See Filter Commands in :file:`Documentation/trace/ftrace.rst`. To just trace the schedule function: diff --git a/Documentation/trace/histogram.txt b/Documentation/trace/histogram.txt index b13771cb12c1..e73bcf9cb5f3 100644 --- a/Documentation/trace/histogram.txt +++ b/Documentation/trace/histogram.txt @@ -7,7 +7,7 @@ Histogram triggers are special event triggers that can be used to aggregate trace event data into histograms. For information on - trace events and event triggers, see Documentation/trace/events.txt. + trace events and event triggers, see Documentation/trace/events.rst. 2. Histogram Trigger Command diff --git a/Documentation/trace/intel_th.rst b/Documentation/trace/intel_th.rst index 990f13265178..19e2d633f3c7 100644 --- a/Documentation/trace/intel_th.rst +++ b/Documentation/trace/intel_th.rst @@ -38,7 +38,7 @@ description is at Documentation/ABI/testing/sysfs-bus-intel_th-devices-gth. STH registers an stm class device, through which it provides interface to userspace and kernelspace software trace sources. See -Documentation/trace/stm.txt for more information on that. +Documentation/trace/stm.rst for more information on that. MSU can be configured to collect trace data into a system memory buffer, which can later on be read from its device nodes via read() or diff --git a/Documentation/trace/tracepoint-analysis.rst b/Documentation/trace/tracepoint-analysis.rst index bef37abf4ad3..716326b9f152 100644 --- a/Documentation/trace/tracepoint-analysis.rst +++ b/Documentation/trace/tracepoint-analysis.rst @@ -55,7 +55,7 @@ simple case of:: 3.1 System-Wide Event Enabling ------------------------------ -See Documentation/trace/events.txt for a proper description on how events +See Documentation/trace/events.rst for a proper description on how events can be enabled system-wide. A short example of enabling all events related to page allocation would look something like:: @@ -112,7 +112,7 @@ at that point. 3.4 Local Event Enabling ------------------------ -Documentation/trace/ftrace.txt describes how to enable events on a per-thread +Documentation/trace/ftrace.rst describes how to enable events on a per-thread basis using set_ftrace_pid. 3.5 Local Event Enablement with PCL @@ -137,7 +137,7 @@ basis using PCL such as follows. 4. Event Filtering ================== -Documentation/trace/ftrace.txt covers in-depth how to filter events in +Documentation/trace/ftrace.rst covers in-depth how to filter events in ftrace. Obviously using grep and awk of trace_pipe is an option as well as any script reading trace_pipe. diff --git a/Documentation/translations/ja_JP/howto.rst b/Documentation/translations/ja_JP/howto.rst index 8d7ed0cbbf5f..f3116381c26b 100644 --- a/Documentation/translations/ja_JP/howto.rst +++ b/Documentation/translations/ja_JP/howto.rst @@ -1,5 +1,5 @@ NOTE: -This is a version of Documentation/HOWTO translated into Japanese. +This is a version of Documentation/process/howto.rst translated into Japanese. This document is maintained by Tsugikazu Shibata If you find any difference between this document and the original file or a problem with the translation, please contact the maintainer of this file. @@ -109,7 +109,7 @@ linux-api@vger.kernel.org に送ることを勧めます。 ています。 カーネルに関して初めての人はここからスタートすると良い でしょう。 - :ref:`Documentation/Process/changes.rst ` + :ref:`Documentation/process/changes.rst ` このファイルはカーネルをうまく生成(訳注 build )し、走らせるのに最 小限のレベルで必要な数々のソフトウェアパッケージの一覧を示してい ます。 diff --git a/Documentation/translations/zh_CN/magic-number.txt b/Documentation/translations/zh_CN/magic-number.txt index e9db693c0a23..7159cec04090 100644 --- a/Documentation/translations/zh_CN/magic-number.txt +++ b/Documentation/translations/zh_CN/magic-number.txt @@ -1,4 +1,4 @@ -Chinese translated version of Documentation/magic-number.txt +Chinese translated version of Documentation/process/magic-number.rst If you have any comment or update to the content, please post to LKML directly. However, if you have problem communicating in English you can also ask the @@ -7,7 +7,7 @@ translation is outdated or there is problem with translation. Chinese maintainer: Jia Wei Wei --------------------------------------------------------------------- -Documentation/magic-number.txt的中文翻译 +Documentation/process/magic-number.rst的中文翻译 如果想评论或更新本文的内容,请直接发信到LKML。如果你使用英文交流有困难的话,也可 以向中文版维护者求助。如果本翻译更新不及时或者翻译存在问题,请联系中文版维护者。 diff --git a/Documentation/translations/zh_CN/video4linux/omap3isp.txt b/Documentation/translations/zh_CN/video4linux/omap3isp.txt index 67ffbf352ae0..e9f29375aa95 100644 --- a/Documentation/translations/zh_CN/video4linux/omap3isp.txt +++ b/Documentation/translations/zh_CN/video4linux/omap3isp.txt @@ -1,4 +1,4 @@ -Chinese translated version of Documentation/video4linux/omap3isp.txt +Chinese translated version of Documentation/media/v4l-drivers/omap3isp.rst If you have any comment or update to the content, please contact the original document maintainer directly. However, if you have a problem @@ -11,7 +11,7 @@ Maintainer: Laurent Pinchart David Cohen Chinese maintainer: Fu Wei --------------------------------------------------------------------- -Documentation/video4linux/omap3isp.txt 的中文翻译 +Documentation/media/v4l-drivers/omap3isp.rst 的中文翻译 如果想评论或更新本文的内容,请直接联系原文档的维护者。如果你使用英文 交流有困难的话,也可以向中文版维护者求助。如果本翻译更新不及时或者翻 diff --git a/MAINTAINERS b/MAINTAINERS index 653a2c29ca43..09554034be46 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -3079,7 +3079,7 @@ M: Clemens Ladisch L: alsa-devel@alsa-project.org (moderated for non-subscribers) T: git git://git.alsa-project.org/alsa-kernel.git S: Maintained -F: Documentation/sound/alsa/Bt87x.txt +F: Documentation/sound/cards/bt87x.rst F: sound/pci/bt87x.c BT8XXGPIO DRIVER @@ -3375,7 +3375,7 @@ M: David Howells M: David Woodhouse L: keyrings@vger.kernel.org S: Maintained -F: Documentation/module-signing.txt +F: Documentation/admin-guide/module-signing.rst F: certs/ F: scripts/sign-file.c F: scripts/extract-cert.c @@ -6501,7 +6501,7 @@ L: linux-mm@kvack.org S: Maintained F: mm/hmm* F: include/linux/hmm* -F: Documentation/vm/hmm.txt +F: Documentation/vm/hmm.rst HOST AP DRIVER M: Jouni Malinen @@ -7401,7 +7401,7 @@ F: drivers/platform/x86/intel-wmi-thunderbolt.c INTEL(R) TRACE HUB M: Alexander Shishkin S: Supported -F: Documentation/trace/intel_th.txt +F: Documentation/trace/intel_th.rst F: drivers/hwtracing/intel_th/ INTEL(R) TRUSTED EXECUTION TECHNOLOGY (TXT) @@ -9665,7 +9665,7 @@ F: include/uapi/linux/mmc/ MULTIPLEXER SUBSYSTEM M: Peter Rosin S: Maintained -F: Documentation/ABI/testing/mux/sysfs-class-mux* +F: Documentation/ABI/testing/sysfs-class-mux* F: Documentation/devicetree/bindings/mux/ F: include/linux/dt-bindings/mux/ F: include/linux/mux/ @@ -10244,7 +10244,7 @@ F: arch/powerpc/include/asm/pnv-ocxl.h F: drivers/misc/ocxl/ F: include/misc/ocxl* F: include/uapi/misc/ocxl.h -F: Documentation/accelerators/ocxl.txt +F: Documentation/accelerators/ocxl.rst OMAP AUDIO SUPPORT M: Peter Ujfalusi @@ -13794,7 +13794,7 @@ SYSTEM TRACE MODULE CLASS M: Alexander Shishkin S: Maintained T: git git://git.kernel.org/pub/scm/linux/kernel/git/ash/stm.git -F: Documentation/trace/stm.txt +F: Documentation/trace/stm.rst F: drivers/hwtracing/stm/ F: include/linux/stm.h F: include/uapi/linux/stm.h @@ -14471,7 +14471,7 @@ M: Steven Rostedt M: Ingo Molnar T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git perf/core S: Maintained -F: Documentation/trace/ftrace.txt +F: Documentation/trace/ftrace.rst F: arch/*/*/*/ftrace.h F: arch/*/kernel/ftrace.c F: include/*/ftrace.h @@ -14940,7 +14940,7 @@ M: Heikki Krogerus L: linux-usb@vger.kernel.org S: Maintained F: Documentation/ABI/testing/sysfs-class-typec -F: Documentation/usb/typec.rst +F: Documentation/driver-api/usb/typec.rst F: drivers/usb/typec/ F: include/linux/usb/typec.h @@ -15770,7 +15770,7 @@ YEALINK PHONE DRIVER M: Henk Vergonet L: usbb2k-api-dev@nongnu.org S: Maintained -F: Documentation/input/yealink.rst +F: Documentation/input/devices/yealink.rst F: drivers/input/misc/yealink.* Z8530 DRIVER FOR AX.25 diff --git a/arch/Kconfig b/arch/Kconfig index 47b235d43909..1aa59063f1fd 100644 --- a/arch/Kconfig +++ b/arch/Kconfig @@ -403,7 +403,7 @@ config SECCOMP_FILTER in terms of Berkeley Packet Filter programs which implement task-defined system call filtering polices. - See Documentation/prctl/seccomp_filter.txt for details. + See Documentation/userspace-api/seccomp_filter.rst for details. preferred-plugin-hostcc := $(if-success,[ $(gcc-version) -ge 40800 ],$(HOSTCXX),$(HOSTCC)) diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h index 869080bedb89..ec1a5fd0d294 100644 --- a/arch/arm/include/asm/cacheflush.h +++ b/arch/arm/include/asm/cacheflush.h @@ -35,7 +35,7 @@ * Start addresses are inclusive and end addresses are exclusive; * start addresses should be rounded down, end addresses up. * - * See Documentation/cachetlb.txt for more information. + * See Documentation/core-api/cachetlb.rst for more information. * Please note that the implementation of these, and the required * effects are cache-type (VIVT/VIPT/PIPT) specific. * diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h index 0094c6653b06..d264a7274811 100644 --- a/arch/arm64/include/asm/cacheflush.h +++ b/arch/arm64/include/asm/cacheflush.h @@ -36,7 +36,7 @@ * Start addresses are inclusive and end addresses are exclusive; start * addresses should be rounded down, end addresses up. * - * See Documentation/cachetlb.txt for more information. Please note that + * See Documentation/core-api/cachetlb.rst for more information. Please note that * the implementation assumes non-aliasing VIPT D-cache and (aliasing) * VIPT I-cache. * diff --git a/arch/microblaze/include/asm/cacheflush.h b/arch/microblaze/include/asm/cacheflush.h index ffea82a16d2c..b091de77b15b 100644 --- a/arch/microblaze/include/asm/cacheflush.h +++ b/arch/microblaze/include/asm/cacheflush.h @@ -19,7 +19,7 @@ #include #include -/* Look at Documentation/cachetlb.txt */ +/* Look at Documentation/core-api/cachetlb.rst */ /* * Cache handling functions. diff --git a/arch/um/Kconfig.um b/arch/um/Kconfig.um index 3e7f228b22e1..20da5a8ca949 100644 --- a/arch/um/Kconfig.um +++ b/arch/um/Kconfig.um @@ -80,7 +80,7 @@ config MAGIC_SYSRQ On UML, this is accomplished by sending a "sysrq" command with mconsole, followed by the letter for the requested command. - The keys are documented in . Don't say Y + The keys are documented in . Don't say Y unless you really know what this hack does. config KERNEL_STACK_ORDER diff --git a/arch/unicore32/include/asm/cacheflush.h b/arch/unicore32/include/asm/cacheflush.h index 1d9132b66039..1c8b9f13a9e1 100644 --- a/arch/unicore32/include/asm/cacheflush.h +++ b/arch/unicore32/include/asm/cacheflush.h @@ -33,7 +33,7 @@ * Start addresses are inclusive and end addresses are exclusive; * start addresses should be rounded down, end addresses up. * - * See Documentation/cachetlb.txt for more information. + * See Documentation/core-api/cachetlb.rst for more information. * Please note that the implementation of these, and the required * effects are cache-type (VIVT/VIPT/PIPT) specific. * diff --git a/arch/x86/entry/vsyscall/vsyscall_64.c b/arch/x86/entry/vsyscall/vsyscall_64.c index 7782cdbcd67d..82ed001e8909 100644 --- a/arch/x86/entry/vsyscall/vsyscall_64.c +++ b/arch/x86/entry/vsyscall/vsyscall_64.c @@ -201,7 +201,7 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address) /* * Handle seccomp. regs->ip must be the original value. - * See seccomp_send_sigsys and Documentation/prctl/seccomp_filter.txt. + * See seccomp_send_sigsys and Documentation/userspace-api/seccomp_filter.rst. * * We could optimize the seccomp disabled case, but performance * here doesn't matter. diff --git a/arch/xtensa/include/asm/cacheflush.h b/arch/xtensa/include/asm/cacheflush.h index 397d6a1a4224..a0d50be5a8cb 100644 --- a/arch/xtensa/include/asm/cacheflush.h +++ b/arch/xtensa/include/asm/cacheflush.h @@ -88,7 +88,7 @@ static inline void __invalidate_icache_page_alias(unsigned long virt, * * Pages can get remapped. Because this might change the 'color' of that page, * we have to flush the cache before the PTE is changed. - * (see also Documentation/cachetlb.txt) + * (see also Documentation/core-api/cachetlb.rst) */ #if defined(CONFIG_MMU) && \ @@ -152,7 +152,7 @@ void local_flush_cache_page(struct vm_area_struct *vma, __invalidate_icache_range(start,(end) - (start)); \ } while (0) -/* This is not required, see Documentation/cachetlb.txt */ +/* This is not required, see Documentation/core-api/cachetlb.rst */ #define flush_icache_page(vma,page) do { } while (0) #define flush_dcache_mmap_lock(mapping) do { } while (0) diff --git a/block/Kconfig b/block/Kconfig index 28ec55752b68..eb50fd4977c2 100644 --- a/block/Kconfig +++ b/block/Kconfig @@ -114,7 +114,7 @@ config BLK_DEV_THROTTLING one needs to mount and use blkio cgroup controller for creating cgroups and specifying per device IO rate policies. - See Documentation/cgroups/blkio-controller.txt for more information. + See Documentation/cgroup-v1/blkio-controller.txt for more information. config BLK_DEV_THROTTLING_LOW bool "Block throttling .low limit interface support (EXPERIMENTAL)" diff --git a/certs/Kconfig b/certs/Kconfig index 5f7663df6e8e..c94e93d8bccf 100644 --- a/certs/Kconfig +++ b/certs/Kconfig @@ -13,7 +13,7 @@ config MODULE_SIG_KEY If this option is unchanged from its default "certs/signing_key.pem", then the kernel will automatically generate the private key and - certificate as described in Documentation/module-signing.txt + certificate as described in Documentation/admin-guide/module-signing.rst config SYSTEM_TRUSTED_KEYRING bool "Provide system-wide ring of trusted keys" diff --git a/crypto/asymmetric_keys/asymmetric_type.c b/crypto/asymmetric_keys/asymmetric_type.c index 39aecad286fe..26539e9a8bda 100644 --- a/crypto/asymmetric_keys/asymmetric_type.c +++ b/crypto/asymmetric_keys/asymmetric_type.c @@ -1,6 +1,6 @@ /* Asymmetric public-key cryptography key type * - * See Documentation/security/asymmetric-keys.txt + * See Documentation/crypto/asymmetric-keys.txt * * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) diff --git a/crypto/asymmetric_keys/signature.c b/crypto/asymmetric_keys/signature.c index 11b7ba170904..28198314bc39 100644 --- a/crypto/asymmetric_keys/signature.c +++ b/crypto/asymmetric_keys/signature.c @@ -1,6 +1,6 @@ /* Signature verification with an asymmetric key * - * See Documentation/security/asymmetric-keys.txt + * See Documentation/crypto/asymmetric-keys.txt * * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig index 410c30c42120..212f447938ae 100644 --- a/drivers/char/Kconfig +++ b/drivers/char/Kconfig @@ -81,7 +81,7 @@ config PRINTER corresponding drivers into the kernel. To compile this driver as a module, choose M here and read - . The module will be called lp. + . The module will be called lp. If you have several parallel ports, you can specify which ports to use with the "lp" kernel command line option. (Try "man bootparam" diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index a24a6afb50b6..9760b526ca31 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -6,7 +6,7 @@ * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * Standard functionality for the common clock API. See Documentation/clk.txt + * Standard functionality for the common clock API. See Documentation/driver-api/clk.rst */ #include @@ -2747,7 +2747,7 @@ static int __clk_core_init(struct clk_core *core) goto out; } - /* check that clk_ops are sane. See Documentation/clk.txt */ + /* check that clk_ops are sane. See Documentation/driver-api/clk.rst */ if (core->ops->set_rate && !((core->ops->round_rate || core->ops->determine_rate) && core->ops->recalc_rate)) { diff --git a/drivers/clk/ingenic/cgu.h b/drivers/clk/ingenic/cgu.h index 542192376ebf..502bcbb61b04 100644 --- a/drivers/clk/ingenic/cgu.h +++ b/drivers/clk/ingenic/cgu.h @@ -194,7 +194,7 @@ struct ingenic_cgu { /** * struct ingenic_clk - private data for a clock - * @hw: see Documentation/clk.txt + * @hw: see Documentation/driver-api/clk.rst * @cgu: a pointer to the CGU data * @idx: the index of this clock in cgu->clock_info */ diff --git a/drivers/gpu/vga/Kconfig b/drivers/gpu/vga/Kconfig index 29437eabe095..b677e5d524e6 100644 --- a/drivers/gpu/vga/Kconfig +++ b/drivers/gpu/vga/Kconfig @@ -6,7 +6,7 @@ config VGA_ARB Some "legacy" VGA devices implemented on PCI typically have the same hard-decoded addresses as they did on ISA. When multiple PCI devices are accessed at same time they need some kind of coordination. Please - see Documentation/vgaarbiter.txt for more details. Select this to + see Documentation/gpu/vgaarbiter.rst for more details. Select this to enable VGA arbiter. config VGA_ARB_MAX_GPUS diff --git a/drivers/gpu/vga/vgaarb.c b/drivers/gpu/vga/vgaarb.c index 1c5e74cb9279..c61b04555779 100644 --- a/drivers/gpu/vga/vgaarb.c +++ b/drivers/gpu/vga/vgaarb.c @@ -1,6 +1,6 @@ /* * vgaarb.c: Implements the VGA arbitration. For details refer to - * Documentation/vgaarbiter.txt + * Documentation/gpu/vgaarbiter.rst * * * (C) Copyright 2005 Benjamin Herrenschmidt diff --git a/drivers/input/joystick/Kconfig b/drivers/input/joystick/Kconfig index 32ec4cee6716..d8f9c6e1fc08 100644 --- a/drivers/input/joystick/Kconfig +++ b/drivers/input/joystick/Kconfig @@ -214,7 +214,7 @@ config JOYSTICK_DB9 gamepad, Sega Saturn gamepad, or a Multisystem -- Atari, Amiga, Commodore, Amstrad CPC joystick connected to your parallel port. For more information on how to use the driver please read - . + . To compile this driver as a module, choose M here: the module will be called db9. @@ -229,7 +229,7 @@ config JOYSTICK_GAMECON Sony PlayStation gamepad or a Multisystem -- Atari, Amiga, Commodore, Amstrad CPC joystick connected to your parallel port. For more information on how to use the driver please read - . + . To compile this driver as a module, choose M here: the module will be called gamecon. @@ -241,7 +241,7 @@ config JOYSTICK_TURBOGRAFX Say Y here if you have the TurboGraFX interface by Steffen Schwenke, and want to use it with Multisystem -- Atari, Amiga, Commodore, Amstrad CPC joystick. For more information on how to use the driver - please read . + please read . To compile this driver as a module, choose M here: the module will be called turbografx. @@ -287,7 +287,7 @@ config JOYSTICK_XPAD and/or "Event interface support" (CONFIG_INPUT_EVDEV) as well. For information about how to connect the X-Box pad to USB, see - . + . To compile this driver as a module, choose M here: the module will be called xpad. @@ -313,7 +313,7 @@ config JOYSTICK_WALKERA0701 Say Y or M here if you have a Walkera WK-0701 transmitter which is supplied with a ready to fly Walkera helicopters such as HM36, HM37, HM60 and want to use it via parport as a joystick. More - information is available: + information is available: To compile this driver as a module, choose M here: the module will be called walkera0701. diff --git a/drivers/input/joystick/walkera0701.c b/drivers/input/joystick/walkera0701.c index 36a5b93156ed..dce313dc260a 100644 --- a/drivers/input/joystick/walkera0701.c +++ b/drivers/input/joystick/walkera0701.c @@ -3,7 +3,7 @@ * * Copyright (c) 2008 Peter Popovec * - * More about driver: + * More about driver: */ /* diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig index 572b15fa18c2..c25606e00693 100644 --- a/drivers/input/misc/Kconfig +++ b/drivers/input/misc/Kconfig @@ -411,7 +411,7 @@ config INPUT_YEALINK usb sound driver, so you might want to enable that as well. For information about how to use these additional functions, see - . + . To compile this driver as a module, choose M here: the module will be called yealink. @@ -595,7 +595,7 @@ config INPUT_GPIO_ROTARY_ENCODER depends on GPIOLIB || COMPILE_TEST help Say Y here to add support for rotary encoders connected to GPIO lines. - Check file:Documentation/input/rotary-encoder.txt for more + Check file:Documentation/input/devices/rotary-encoder.rst for more information. To compile this driver as a module, choose M here: the diff --git a/drivers/input/misc/rotary_encoder.c b/drivers/input/misc/rotary_encoder.c index 6d304381fc30..30ec77ad32c6 100644 --- a/drivers/input/misc/rotary_encoder.c +++ b/drivers/input/misc/rotary_encoder.c @@ -7,7 +7,7 @@ * state machine code inspired by code from Tim Ruetz * * A generic driver for rotary encoders connected to GPIO lines. - * See file:Documentation/input/rotary-encoder.txt for more information + * See file:Documentation/input/devices/rotary-encoder.rst for more information * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig index f27f23f2d99a..566a1e3aa504 100644 --- a/drivers/input/mouse/Kconfig +++ b/drivers/input/mouse/Kconfig @@ -129,7 +129,7 @@ config MOUSE_PS2_ELANTECH This driver exposes some configuration registers via sysfs entries. For further information, - see . + see . If unsure, say N. @@ -228,7 +228,7 @@ config MOUSE_APPLETOUCH scrolling in X11. For further information, see - . + . To compile this driver as a module, choose M here: the module will be called appletouch. @@ -251,7 +251,7 @@ config MOUSE_BCM5974 The interface is currently identical to the appletouch interface, for further information, see - . + . To compile this driver as a module, choose M here: the module will be called bcm5974. diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c index cb5579716dba..0a6f7ca883e7 100644 --- a/drivers/input/mouse/alps.c +++ b/drivers/input/mouse/alps.c @@ -212,7 +212,7 @@ static void alps_set_abs_params_v7(struct alps_data *priv, static void alps_set_abs_params_ss4_v2(struct alps_data *priv, struct input_dev *dev1); -/* Packet formats are described in Documentation/input/alps.txt */ +/* Packet formats are described in Documentation/input/devices/alps.rst */ static bool alps_is_valid_first_byte(struct alps_data *priv, unsigned char data) diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c index fd714ee881f7..2566b4d8b342 100644 --- a/drivers/input/touchscreen/wm97xx-core.c +++ b/drivers/input/touchscreen/wm97xx-core.c @@ -68,7 +68,7 @@ * The default values correspond to Mainstone II in QVGA mode * * Please read - * Documentation/input/input-programming.txt for more details. + * Documentation/input/input-programming.rst for more details. */ static int abs_x[3] = {150, 4000, 5}; diff --git a/drivers/lightnvm/pblk-rb.c b/drivers/lightnvm/pblk-rb.c index 00cd1f20a196..55e9442a99e2 100644 --- a/drivers/lightnvm/pblk-rb.c +++ b/drivers/lightnvm/pblk-rb.c @@ -38,7 +38,7 @@ void pblk_rb_data_free(struct pblk_rb *rb) /* * Initialize ring buffer. The data and metadata buffers must be previously * allocated and their size must be a power of two - * (Documentation/circular-buffers.txt) + * (Documentation/core-api/circular-buffers.rst) */ int pblk_rb_init(struct pblk_rb *rb, struct pblk_rb_entry *rb_entry_base, unsigned int power_size, unsigned int power_seg_sz) diff --git a/drivers/md/bcache/Kconfig b/drivers/md/bcache/Kconfig index 4d200883c505..17bf109c58e9 100644 --- a/drivers/md/bcache/Kconfig +++ b/drivers/md/bcache/Kconfig @@ -5,7 +5,7 @@ config BCACHE Allows a block device to be used as cache for other devices; uses a btree for indexing and the layout is optimized for SSDs. - See Documentation/bcache.txt for details. + See Documentation/admin-guide/bcache.rst for details. config BCACHE_DEBUG bool "Bcache debugging" diff --git a/drivers/md/bcache/btree.c b/drivers/md/bcache/btree.c index 2a0968c04e21..547c9eedc2f4 100644 --- a/drivers/md/bcache/btree.c +++ b/drivers/md/bcache/btree.c @@ -18,7 +18,7 @@ * as keys are inserted we only sort the pages that have not yet been written. * When garbage collection is run, we resort the entire node. * - * All configuration is done via sysfs; see Documentation/bcache.txt. + * All configuration is done via sysfs; see Documentation/admin-guide/bcache.rst. */ #include "bcache.h" diff --git a/drivers/md/bcache/extents.c b/drivers/md/bcache/extents.c index c334e6666461..1d096742eb41 100644 --- a/drivers/md/bcache/extents.c +++ b/drivers/md/bcache/extents.c @@ -18,7 +18,7 @@ * as keys are inserted we only sort the pages that have not yet been written. * When garbage collection is run, we resort the entire node. * - * All configuration is done via sysfs; see Documentation/bcache.txt. + * All configuration is done via sysfs; see Documentation/admin-guide/bcache.rst. */ #include "bcache.h" diff --git a/drivers/media/dvb-core/dvb_ringbuffer.c b/drivers/media/dvb-core/dvb_ringbuffer.c index 4330b6fa4af2..d1d471af0636 100644 --- a/drivers/media/dvb-core/dvb_ringbuffer.c +++ b/drivers/media/dvb-core/dvb_ringbuffer.c @@ -55,7 +55,7 @@ int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf) * this pairs with smp_store_release() in dvb_ringbuffer_write(), * dvb_ringbuffer_write_user(), or dvb_ringbuffer_reset() * - * for memory barriers also see Documentation/circular-buffers.txt + * for memory barriers also see Documentation/core-api/circular-buffers.rst */ return (rbuf->pread == smp_load_acquire(&rbuf->pwrite)); } diff --git a/drivers/media/pci/meye/Kconfig b/drivers/media/pci/meye/Kconfig index 2e60334ffef5..9a50f54231ad 100644 --- a/drivers/media/pci/meye/Kconfig +++ b/drivers/media/pci/meye/Kconfig @@ -5,7 +5,7 @@ config VIDEO_MEYE ---help--- This is the video4linux driver for the Motion Eye camera found in the Vaio Picturebook laptops. Please read the material in - for more information. + for more information. If you say Y or M here, you need to say Y or M to "Sony Laptop Extras" in the misc device section. diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c index 4d5a26b4cdda..d85ffbfb7c1f 100644 --- a/drivers/media/platform/pxa_camera.c +++ b/drivers/media/platform/pxa_camera.c @@ -1021,7 +1021,7 @@ static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev, * - a videobuffer is queued on the pcdev->capture list * * Please check the "DMA hot chaining timeslice issue" in - * Documentation/video4linux/pxa_camera.txt + * Documentation/media/v4l-drivers/pxa_camera.rst * * Context: should only be called within the dma irq handler */ @@ -1443,7 +1443,7 @@ static void pxac_vb2_queue(struct vb2_buffer *vb) /* * Please check the DMA prepared buffer structure in : - * Documentation/video4linux/pxa_camera.txt + * Documentation/media/v4l-drivers/pxa_camera.rst * Please check also in pxa_camera_check_link_miss() to understand why DMA chain * modification while DMA chain is running will work anyway. */ diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c index 242342fd7ede..9897213f2618 100644 --- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c +++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c @@ -1111,7 +1111,7 @@ static void sh_mobile_ceu_put_formats(struct soc_camera_device *icd) /* * CEU can scale and crop, but we don't want to waste bandwidth and kill the * framerate by always requesting the maximum image from the client. See - * Documentation/video4linux/sh_mobile_ceu_camera.txt for a description of + * Documentation/media/v4l-drivers/sh_mobile_ceu_camera.rst for a description of * scaling and cropping algorithms and for the meaning of referenced here steps. */ static int sh_mobile_ceu_set_selection(struct soc_camera_device *icd, diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig index 39b04ad924c0..b426d6f9787d 100644 --- a/drivers/media/radio/Kconfig +++ b/drivers/media/radio/Kconfig @@ -272,7 +272,7 @@ config RADIO_RTRACK been reported to be used by these cards. More information is contained in the file - . + . To compile this driver as a module, choose M here: the module will be called radio-aimslab. diff --git a/drivers/media/radio/si470x/Kconfig b/drivers/media/radio/si470x/Kconfig index a21172e413a9..6dbb158cd2a0 100644 --- a/drivers/media/radio/si470x/Kconfig +++ b/drivers/media/radio/si470x/Kconfig @@ -29,7 +29,7 @@ config USB_SI470X Please have a look at the documentation, especially on how to redirect the audio stream from the radio to your sound device: - Documentation/video4linux/si470x.txt + Documentation/media/v4l-drivers/si470x.rst Say Y here if you want to connect this type of radio to your computer's USB port. diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c index be26c029546b..39db6dc4b5cd 100644 --- a/drivers/media/usb/dvb-usb-v2/lmedm04.c +++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c @@ -21,7 +21,7 @@ * * LME2510C + M88RS2000 * - * For firmware see Documentation/dvb/lmedm04.txt + * For firmware see Documentation/media/dvb-drivers/lmedm04.rst * * I2C addresses: * 0xd0 - STV0288 - Demodulator diff --git a/drivers/media/usb/zr364xx/Kconfig b/drivers/media/usb/zr364xx/Kconfig index 0f585662881d..ac429bca70e8 100644 --- a/drivers/media/usb/zr364xx/Kconfig +++ b/drivers/media/usb/zr364xx/Kconfig @@ -6,7 +6,7 @@ config USB_ZR364XX ---help--- Say Y here if you want to connect this type of camera to your computer's USB port. - See for more info + See for more info and list of supported cameras. To compile this driver as a module, choose M here: the diff --git a/drivers/parport/Kconfig b/drivers/parport/Kconfig index 44333bd8f908..a97f4eada60b 100644 --- a/drivers/parport/Kconfig +++ b/drivers/parport/Kconfig @@ -20,7 +20,7 @@ menuconfig PARPORT drive, PLIP link (Parallel Line Internet Protocol is mainly used to create a mini network by connecting the parallel ports of two local machines) etc., then you need to say Y here; please read - and + and . For extensive information about drivers for many devices attaching @@ -33,7 +33,7 @@ menuconfig PARPORT the module will be called parport. If you have more than one parallel port and want to specify which port and IRQ to be used by this driver at module load time, take a - look at . + look at . If unsure, say Y. @@ -71,7 +71,7 @@ config PARPORT_PC_FIFO As well as actually having a FIFO, or DMA capability, the kernel will need to know which IRQ the parallel port has. By default, parallel port interrupts will not be used, and so neither will the - FIFO. See to find out how to + FIFO. See to find out how to specify which IRQ/DMA to use. config PARPORT_PC_SUPERIO diff --git a/drivers/staging/media/bcm2048/TODO b/drivers/staging/media/bcm2048/TODO index 051f85dbe89e..6bee2a2dad68 100644 --- a/drivers/staging/media/bcm2048/TODO +++ b/drivers/staging/media/bcm2048/TODO @@ -3,7 +3,7 @@ TODO: From the initial code review: The main thing you need to do is to implement all the controls using the -control framework (see Documentation/video4linux/v4l2-controls.txt). +control framework (see Documentation/media/kapi/v4l2-controls.rst). Most drivers are by now converted to the control framework, so you will find many examples of how to do this in drivers/media/radio. diff --git a/include/keys/asymmetric-subtype.h b/include/keys/asymmetric-subtype.h index 2480469ce8fb..e0a9c2368872 100644 --- a/include/keys/asymmetric-subtype.h +++ b/include/keys/asymmetric-subtype.h @@ -1,6 +1,6 @@ /* Asymmetric public-key cryptography key subtype * - * See Documentation/security/asymmetric-keys.txt + * See Documentation/crypto/asymmetric-keys.txt * * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) diff --git a/include/keys/asymmetric-type.h b/include/keys/asymmetric-type.h index b38240716d41..1cb77cd5135e 100644 --- a/include/keys/asymmetric-type.h +++ b/include/keys/asymmetric-type.h @@ -1,6 +1,6 @@ /* Asymmetric Public-key cryptography key type interface * - * See Documentation/security/asymmetric-keys.txt + * See Documentation/crypto/asymmetric-keys.txt * * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) diff --git a/include/linux/assoc_array.h b/include/linux/assoc_array.h index a89df3be1686..65e3832f96b2 100644 --- a/include/linux/assoc_array.h +++ b/include/linux/assoc_array.h @@ -1,6 +1,6 @@ /* Generic associative array implementation. * - * See Documentation/assoc_array.txt for information. + * See Documentation/core-api/assoc_array.rst for information. * * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) diff --git a/include/linux/assoc_array_priv.h b/include/linux/assoc_array_priv.h index 711275e6681c..a00a06550c10 100644 --- a/include/linux/assoc_array_priv.h +++ b/include/linux/assoc_array_priv.h @@ -1,6 +1,6 @@ /* Private definitions for the generic associative array implementation. * - * See Documentation/assoc_array.txt for information. + * See Documentation/core-api/assoc_array.rst for information. * * Copyright (C) 2013 Red Hat, Inc. All Rights Reserved. * Written by David Howells (dhowells@redhat.com) diff --git a/include/linux/circ_buf.h b/include/linux/circ_buf.h index 7cf262a421c3..b3233e8202f9 100644 --- a/include/linux/circ_buf.h +++ b/include/linux/circ_buf.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* - * See Documentation/circular-buffers.txt for more information. + * See Documentation/core-api/circular-buffers.rst for more information. */ #ifndef _LINUX_CIRC_BUF_H diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index 9c3c9a319e48..8154f4920fcb 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ /* * Ftrace header. For implementation details beyond the random comments - * scattered below, see: Documentation/trace/ftrace-design.txt + * scattered below, see: Documentation/trace/ftrace-design.rst */ #ifndef _LINUX_FTRACE_H diff --git a/include/linux/rculist_nulls.h b/include/linux/rculist_nulls.h index e4b257ff881b..bc8206a8f30e 100644 --- a/include/linux/rculist_nulls.h +++ b/include/linux/rculist_nulls.h @@ -109,7 +109,7 @@ static inline void hlist_nulls_add_head_rcu(struct hlist_nulls_node *n, * * The barrier() is needed to make sure compiler doesn't cache first element [1], * as this loop can be restarted [2] - * [1] Documentation/atomic_ops.txt around line 114 + * [1] Documentation/core-api/atomic_ops.rst around line 114 * [2] Documentation/RCU/rculist_nulls.txt around line 146 */ #define hlist_nulls_for_each_entry_rcu(tpos, pos, head, member) \ diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h index db9f15f5db04..c0d7ea0bf5b6 100644 --- a/include/uapi/linux/prctl.h +++ b/include/uapi/linux/prctl.h @@ -170,7 +170,7 @@ struct prctl_mm_map { * asking selinux for a specific new context (e.g. with runcon) will result * in execve returning -EPERM. * - * See Documentation/prctl/no_new_privs.txt for more details. + * See Documentation/userspace-api/no_new_privs.rst for more details. */ #define PR_SET_NO_NEW_PRIVS 38 #define PR_GET_NO_NEW_PRIVS 39 diff --git a/include/xen/interface/io/kbdif.h b/include/xen/interface/io/kbdif.h index 2a9510ade701..e2340a4130cf 100644 --- a/include/xen/interface/io/kbdif.h +++ b/include/xen/interface/io/kbdif.h @@ -317,7 +317,7 @@ struct xenkbd_position { * Linux [2] and Windows [3] multi-touch support. * * [1] https://cgit.freedesktop.org/wayland/wayland/tree/protocol/wayland.xml - * [2] https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.txt + * [2] https://www.kernel.org/doc/Documentation/input/multi-touch-protocol.rst * [3] https://msdn.microsoft.com/en-us/library/jj151564(v=vs.85).aspx * * diff --git a/kernel/cgroup/cpuset.c b/kernel/cgroup/cpuset.c index d8b12e0d39cd..266f10cb7222 100644 --- a/kernel/cgroup/cpuset.c +++ b/kernel/cgroup/cpuset.c @@ -605,7 +605,7 @@ static inline int nr_cpusets(void) * load balancing domains (sched domains) as specified by that partial * partition. * - * See "What is sched_load_balance" in Documentation/cgroups/cpusets.txt + * See "What is sched_load_balance" in Documentation/cgroup-v1/cpusets.txt * for a background explanation of this. * * Does not return errors, on the theory that the callers of this diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig index dd6c0a2ad969..dcc0166d1997 100644 --- a/kernel/trace/Kconfig +++ b/kernel/trace/Kconfig @@ -12,22 +12,22 @@ config NOP_TRACER config HAVE_FTRACE_NMI_ENTER bool help - See Documentation/trace/ftrace-design.txt + See Documentation/trace/ftrace-design.rst config HAVE_FUNCTION_TRACER bool help - See Documentation/trace/ftrace-design.txt + See Documentation/trace/ftrace-design.rst config HAVE_FUNCTION_GRAPH_TRACER bool help - See Documentation/trace/ftrace-design.txt + See Documentation/trace/ftrace-design.rst config HAVE_DYNAMIC_FTRACE bool help - See Documentation/trace/ftrace-design.txt + See Documentation/trace/ftrace-design.rst config HAVE_DYNAMIC_FTRACE_WITH_REGS bool @@ -35,12 +35,12 @@ config HAVE_DYNAMIC_FTRACE_WITH_REGS config HAVE_FTRACE_MCOUNT_RECORD bool help - See Documentation/trace/ftrace-design.txt + See Documentation/trace/ftrace-design.rst config HAVE_SYSCALL_TRACEPOINTS bool help - See Documentation/trace/ftrace-design.txt + See Documentation/trace/ftrace-design.rst config HAVE_FENTRY bool @@ -448,7 +448,7 @@ config KPROBE_EVENTS help This allows the user to add tracing events (similar to tracepoints) on the fly via the ftrace interface. See - Documentation/trace/kprobetrace.txt for more details. + Documentation/trace/kprobetrace.rst for more details. Those events can be inserted wherever kprobes can probe, and record various register and memory values. @@ -575,7 +575,7 @@ config MMIOTRACE implementation and works via page faults. Tracing is disabled by default and can be enabled at run-time. - See Documentation/trace/mmiotrace.txt. + See Documentation/trace/mmiotrace.rst. If you are not helping to develop drivers, say N. config TRACING_MAP diff --git a/lib/Kconfig b/lib/Kconfig index 809fdd155739..e34b04b56057 100644 --- a/lib/Kconfig +++ b/lib/Kconfig @@ -405,7 +405,7 @@ config ASSOCIATIVE_ARRAY See: - Documentation/assoc_array.txt + Documentation/core-api/assoc_array.rst for more information. diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c index 9a46dc24ac10..2b5ee5fbd652 100644 --- a/security/selinux/hooks.c +++ b/security/selinux/hooks.c @@ -4728,7 +4728,7 @@ err_af: } /* This supports connect(2) and SCTP connect services such as sctp_connectx(3) - * and sctp_sendmsg(3) as described in Documentation/security/LSM-sctp.txt + * and sctp_sendmsg(3) as described in Documentation/security/LSM-sctp.rst */ static int selinux_socket_connect_helper(struct socket *sock, struct sockaddr *address, int addrlen) diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 6e937a8146a1..63b3ef9c83f5 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -48,7 +48,7 @@ config SND_MIXER_OSS depends on SND_OSSEMUL help To enable OSS mixer API emulation (/dev/mixer*), say Y here - and read . + and read . Many programs still use the OSS API, so say Y. @@ -61,7 +61,7 @@ config SND_PCM_OSS select SND_PCM help To enable OSS digital audio (PCM) emulation (/dev/dsp*), say Y - here and read . + here and read . Many programs still use the OSS API, so say Y. diff --git a/sound/drivers/Kconfig b/sound/drivers/Kconfig index 7144cc36e8ae..648a12da44f9 100644 --- a/sound/drivers/Kconfig +++ b/sound/drivers/Kconfig @@ -153,7 +153,7 @@ config SND_SERIAL_U16550 select SND_RAWMIDI help To include support for MIDI serial port interfaces, say Y here - and read . + and read . This driver works with serial UARTs 16550 and better. This driver accesses the serial port hardware directly, so @@ -223,7 +223,7 @@ config SND_AC97_POWER_SAVE the device frequently. A value of 10 seconds would be a good choice for normal operations. - See Documentation/sound/alsa/powersave.txt for more details. + See Documentation/sound/designs/powersave.rst for more details. config SND_AC97_POWER_SAVE_DEFAULT int "Default time-out for AC97 power-save mode" diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index d9f3fdb777e4..4105d9f653d9 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig @@ -175,7 +175,7 @@ config SND_BT87X help If you want to record audio from TV cards based on Brooktree Bt878/Bt879 chips, say Y here and read - . + . To compile this driver as a module, choose M here: the module will be called snd-bt87x. @@ -210,7 +210,7 @@ config SND_CMIPCI help If you want to use soundcards based on C-Media CMI8338, CMI8738, CMI8768 or CMI8770 chips, say Y here and read - . + . To compile this driver as a module, choose M here: the module will be called snd-cmipci. @@ -472,8 +472,8 @@ config SND_EMU10K1 Audigy and E-mu APS (partially supported) soundcards. The confusing multitude of mixer controls is documented in - and - . + and + . To compile this driver as a module, choose M here: the module will be called snd-emu10k1. @@ -735,7 +735,7 @@ config SND_MIXART select SND_PCM help If you want to use Digigram miXart soundcards, say Y here and - read . + read . To compile this driver as a module, choose M here: the module will be called snd-mixart. diff --git a/tools/include/uapi/linux/prctl.h b/tools/include/uapi/linux/prctl.h index db9f15f5db04..c0d7ea0bf5b6 100644 --- a/tools/include/uapi/linux/prctl.h +++ b/tools/include/uapi/linux/prctl.h @@ -170,7 +170,7 @@ struct prctl_mm_map { * asking selinux for a specific new context (e.g. with runcon) will result * in execve returning -EPERM. * - * See Documentation/prctl/no_new_privs.txt for more details. + * See Documentation/userspace-api/no_new_privs.rst for more details. */ #define PR_SET_NO_NEW_PRIVS 38 #define PR_GET_NO_NEW_PRIVS 39 diff --git a/tools/lib/api/fs/fs.c b/tools/lib/api/fs/fs.c index 6a12bbf39f7b..7aba8243a0e7 100644 --- a/tools/lib/api/fs/fs.c +++ b/tools/lib/api/fs/fs.c @@ -201,7 +201,7 @@ static void mem_toupper(char *f, size_t len) /* * Check for "NAME_PATH" environment variable to override fs location (for - * testing). This matches the recommendation in Documentation/sysfs-rules.txt + * testing). This matches the recommendation in Documentation/admin-guide/sysfs-rules.rst * for SYSFS_PATH. */ static bool fs__env_override(struct fs *fs) diff --git a/tools/perf/util/bpf-prologue.c b/tools/perf/util/bpf-prologue.c index 29347756b0af..77e4891e17b0 100644 --- a/tools/perf/util/bpf-prologue.c +++ b/tools/perf/util/bpf-prologue.c @@ -61,7 +61,7 @@ check_pos(struct bpf_insn_pos *pos) /* * Convert type string (u8/u16/u32/u64/s8/s16/s32/s64 ..., see - * Documentation/trace/kprobetrace.txt) to size field of BPF_LDX_MEM + * Documentation/trace/kprobetrace.rst) to size field of BPF_LDX_MEM * instruction (BPF_{B,H,W,DW}). */ static int diff --git a/tools/power/pm-graph/config/custom-timeline-functions.cfg b/tools/power/pm-graph/config/custom-timeline-functions.cfg index 4f80ad7d7275..f8fcb06fd68b 100644 --- a/tools/power/pm-graph/config/custom-timeline-functions.cfg +++ b/tools/power/pm-graph/config/custom-timeline-functions.cfg @@ -105,7 +105,7 @@ override-dev-timeline-functions: true # example: [color=#CC00CC] # # arglist: A list of arguments from registers/stack addresses. See URL: -# https://www.kernel.org/doc/Documentation/trace/kprobetrace.txt +# https://www.kernel.org/doc/Documentation/trace/kprobetrace.rst # # example: cpu=%di:s32 # @@ -170,7 +170,7 @@ pm_restore_console: # example: [color=#CC00CC] # # arglist: A list of arguments from registers/stack addresses. See URL: -# https://www.kernel.org/doc/Documentation/trace/kprobetrace.txt +# https://www.kernel.org/doc/Documentation/trace/kprobetrace.rst # # example: port=+36(%di):s32 # -- cgit From 856e7c4b619af622d56b3b454f7bec32a170ac99 Mon Sep 17 00:00:00 2001 From: "Shuah Khan (Samsung OSG)" Date: Tue, 12 Jun 2018 16:46:03 -0600 Subject: selftests: pstore: return Kselftest Skip code for skipped tests When pstore_post_reboot test gets skipped because of unmet dependencies and/or unsupported configuration, it returns 0 which is treated as a pass by the Kselftest framework. This leads to false positive result even when the test could not be run. Change it to return kselftest skip code when a test gets skipped to clearly report that the test could not be run. Kselftest framework SKIP code is 4 and the framework prints appropriate messages to indicate that the test is skipped. Signed-off-by: Shuah Khan (Samsung OSG) Reviewed-by: Kees Cook Signed-off-by: Shuah Khan (Samsung OSG) --- tools/testing/selftests/pstore/pstore_post_reboot_tests | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/testing/selftests/pstore/pstore_post_reboot_tests b/tools/testing/selftests/pstore/pstore_post_reboot_tests index 6ccb154cb4aa..22f8df1ad7d4 100755 --- a/tools/testing/selftests/pstore/pstore_post_reboot_tests +++ b/tools/testing/selftests/pstore/pstore_post_reboot_tests @@ -7,13 +7,16 @@ # # Released under the terms of the GPL v2. +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=4 + . ./common_tests if [ -e $REBOOT_FLAG ]; then rm $REBOOT_FLAG else prlog "pstore_crash_test has not been executed yet. we skip further tests." - exit 0 + exit $ksft_skip fi prlog -n "Mounting pstore filesystem ... " -- cgit From 8781578087b8fb8829558bac96c3c24e5ba26f82 Mon Sep 17 00:00:00 2001 From: "Shuah Khan (Samsung OSG)" Date: Tue, 12 Jun 2018 17:40:31 -0600 Subject: selftests: static_keys: return Kselftest Skip code for skipped tests When static_keys test is skipped because of unmet dependencies and/or unsupported configuration, it exits with error which is treated as a fail by the Kselftest framework. This leads to false negative result even when the test could not be run. Change it to return kselftest skip code when a test gets skipped to clearly report that the test could not be run. Added an explicit searches for test_static_key_base and test_static_keys modules and return skip code if they aren't found to differentiate between the failure to load the module condition and module not found condition. Kselftest framework SKIP code is 4 and the framework prints appropriate messages to indicate that the test is skipped. Signed-off-by: Shuah Khan (Samsung OSG) --- tools/testing/selftests/static_keys/test_static_keys.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'tools') diff --git a/tools/testing/selftests/static_keys/test_static_keys.sh b/tools/testing/selftests/static_keys/test_static_keys.sh index 24cff498b31a..fc9f8cde7d42 100755 --- a/tools/testing/selftests/static_keys/test_static_keys.sh +++ b/tools/testing/selftests/static_keys/test_static_keys.sh @@ -2,6 +2,19 @@ # SPDX-License-Identifier: GPL-2.0 # Runs static keys kernel module tests +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=4 + +if ! /sbin/modprobe -q -n test_static_key_base; then + echo "static_key: module test_static_key_base is not found [SKIP]" + exit $ksft_skip +fi + +if ! /sbin/modprobe -q -n test_static_keys; then + echo "static_key: module test_static_keys is not found [SKIP]" + exit $ksft_skip +fi + if /sbin/modprobe -q test_static_key_base; then if /sbin/modprobe -q test_static_keys; then echo "static_key: ok" -- cgit From c7db6ffb831fd36a03485a0d88b1e505378975ad Mon Sep 17 00:00:00 2001 From: "Shuah Khan (Samsung OSG)" Date: Tue, 12 Jun 2018 18:11:37 -0600 Subject: selftests: sysctl: return Kselftest Skip code for skipped tests When sysctl test is skipped because of unmet dependencies and/or unsupported configuration, it exits with error which is treated as a fail by the Kselftest framework. This leads to false negative result even when the test could not be run. Change it to return kselftest skip code when a test gets skipped to clearly report that the test could not be run. Changed return code to kselftest skip code in skip error legs that check requirements and module probe test error leg. Kselftest framework SKIP code is 4 and the framework prints appropriate messages to indicate that the test is skipped. Signed-off-by: Shuah Khan (Samsung OSG) Reviewed-by: Kees Cook Signed-off-by: Shuah Khan (Samsung OSG) --- tools/testing/selftests/sysctl/sysctl.sh | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) (limited to 'tools') diff --git a/tools/testing/selftests/sysctl/sysctl.sh b/tools/testing/selftests/sysctl/sysctl.sh index ec232c3cfcaa..584eb8ea780a 100755 --- a/tools/testing/selftests/sysctl/sysctl.sh +++ b/tools/testing/selftests/sysctl/sysctl.sh @@ -14,6 +14,9 @@ # This performs a series tests against the proc sysctl interface. +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=4 + TEST_NAME="sysctl" TEST_DRIVER="test_${TEST_NAME}" TEST_DIR=$(dirname $0) @@ -41,7 +44,7 @@ test_modprobe() echo "$0: $DIR not present" >&2 echo "You must have the following enabled in your kernel:" >&2 cat $TEST_DIR/config >&2 - exit 1 + exit $ksft_skip fi } @@ -98,28 +101,30 @@ test_reqs() uid=$(id -u) if [ $uid -ne 0 ]; then echo $msg must be run as root >&2 - exit 0 + exit $ksft_skip fi if ! which perl 2> /dev/null > /dev/null; then echo "$0: You need perl installed" - exit 1 + exit $ksft_skip fi if ! which getconf 2> /dev/null > /dev/null; then echo "$0: You need getconf installed" - exit 1 + exit $ksft_skip fi if ! which diff 2> /dev/null > /dev/null; then echo "$0: You need diff installed" - exit 1 + exit $ksft_skip fi } function load_req_mod() { - trap "test_modprobe" EXIT - if [ ! -d $DIR ]; then + if ! modprobe -q -n $TEST_DRIVER; then + echo "$0: module $TEST_DRIVER not found [SKIP]" + exit $ksft_skip + fi modprobe $TEST_DRIVER if [ $? -ne 0 ]; then exit @@ -765,6 +770,7 @@ function parse_args() test_reqs allow_user_defaults check_production_sysctl_writes_strict +test_modprobe load_req_mod trap "test_finish" EXIT -- cgit From d7d5311d4aa9611fe1a5a851e6f75733237a668a Mon Sep 17 00:00:00 2001 From: "Shuah Khan (Samsung OSG)" Date: Wed, 13 Jun 2018 21:10:48 -0600 Subject: selftests: user: return Kselftest Skip code for skipped tests When user test is skipped because of unmet dependencies and/or unsupported configuration, it exits with error which is treated as a fail by the Kselftest framework. This leads to false negative result even when the test could not be run. Change it to return kselftest skip code when a test gets skipped to clearly report that the test could not be run. Add an explicit check for module presence and return skip code if module isn't present. Kselftest framework SKIP code is 4 and the framework prints appropriate messages to indicate that the test is skipped. Signed-off-by: Shuah Khan (Samsung OSG) --- tools/testing/selftests/user/test_user_copy.sh | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'tools') diff --git a/tools/testing/selftests/user/test_user_copy.sh b/tools/testing/selftests/user/test_user_copy.sh index d60506fc77f8..f9b31a57439b 100755 --- a/tools/testing/selftests/user/test_user_copy.sh +++ b/tools/testing/selftests/user/test_user_copy.sh @@ -2,6 +2,13 @@ # SPDX-License-Identifier: GPL-2.0 # Runs copy_to/from_user infrastructure using test_user_copy kernel module +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=4 + +if ! /sbin/modprobe -q -n test_user_copy; then + echo "user: module test_user_copy is not found [SKIP]" + exit $ksft_skip +fi if /sbin/modprobe -q test_user_copy; then /sbin/modprobe -q -r test_user_copy echo "user_copy: ok" -- cgit From 685814466bf8398192cf855415a0bb2cefc1930e Mon Sep 17 00:00:00 2001 From: "Shuah Khan (Samsung OSG)" Date: Thu, 14 Jun 2018 16:56:13 -0600 Subject: selftests: zram: return Kselftest Skip code for skipped tests When zram test is skipped because of unmet dependencies and/or unsupported configuration, it exits with error which is treated as a fail by the Kselftest framework. This leads to false negative result even when the test could not be run. Change it to return kselftest skip code when a test gets skipped to clearly report that the test could not be run. Kselftest framework SKIP code is 4 and the framework prints appropriate messages to indicate that the test is skipped. Signed-off-by: Shuah Khan (Samsung OSG) --- tools/testing/selftests/zram/zram.sh | 5 ++++- tools/testing/selftests/zram/zram_lib.sh | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/testing/selftests/zram/zram.sh b/tools/testing/selftests/zram/zram.sh index 754de7da426a..232e958ec454 100755 --- a/tools/testing/selftests/zram/zram.sh +++ b/tools/testing/selftests/zram/zram.sh @@ -2,6 +2,9 @@ # SPDX-License-Identifier: GPL-2.0 TCID="zram.sh" +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=4 + . ./zram_lib.sh run_zram () { @@ -24,5 +27,5 @@ elif [ -b /dev/zram0 ]; then else echo "$TCID : No zram.ko module or /dev/zram0 device file not found" echo "$TCID : CONFIG_ZRAM is not set" - exit 1 + exit $ksft_skip fi diff --git a/tools/testing/selftests/zram/zram_lib.sh b/tools/testing/selftests/zram/zram_lib.sh index f6a9c73e7a44..9e73a4fb9b0a 100755 --- a/tools/testing/selftests/zram/zram_lib.sh +++ b/tools/testing/selftests/zram/zram_lib.sh @@ -18,6 +18,9 @@ MODULE=0 dev_makeswap=-1 dev_mounted=-1 +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=4 + trap INT check_prereqs() @@ -27,7 +30,7 @@ check_prereqs() if [ $uid -ne 0 ]; then echo $msg must be run as root >&2 - exit 0 + exit $ksft_skip fi } -- cgit From a4d7537789724985cafbc9260a31ca4f2b7cf123 Mon Sep 17 00:00:00 2001 From: "Shuah Khan (Samsung OSG)" Date: Wed, 13 Jun 2018 21:31:43 -0600 Subject: selftests: vm: return Kselftest Skip code for skipped tests When vm test is skipped because of unmet dependencies and/or unsupported configuration, it exits with error which is treated as a fail by the Kselftest framework. This leads to false negative result even when the test could not be run. Change it to return kselftest skip code when a test gets skipped to clearly report that the test could not be run. Kselftest framework SKIP code is 4 and the framework prints appropriate messages to indicate that the test is skipped. Signed-off-by: Shuah Khan (Samsung OSG) Acked-by: Mike Rapoport Signed-off-by: Shuah Khan (Samsung OSG) --- tools/testing/selftests/vm/compaction_test.c | 4 +++- tools/testing/selftests/vm/mlock2-tests.c | 12 +++++++----- tools/testing/selftests/vm/run_vmtests | 5 ++++- tools/testing/selftests/vm/userfaultfd.c | 4 +++- 4 files changed, 17 insertions(+), 8 deletions(-) (limited to 'tools') diff --git a/tools/testing/selftests/vm/compaction_test.c b/tools/testing/selftests/vm/compaction_test.c index 1097f04e4d80..bcec71250873 100644 --- a/tools/testing/selftests/vm/compaction_test.c +++ b/tools/testing/selftests/vm/compaction_test.c @@ -16,6 +16,8 @@ #include #include +#include "../kselftest.h" + #define MAP_SIZE 1048576 struct map_list { @@ -169,7 +171,7 @@ int main(int argc, char **argv) printf("Either the sysctl compact_unevictable_allowed is not\n" "set to 1 or couldn't read the proc file.\n" "Skipping the test\n"); - return 0; + return KSFT_SKIP; } lim.rlim_cur = RLIM_INFINITY; diff --git a/tools/testing/selftests/vm/mlock2-tests.c b/tools/testing/selftests/vm/mlock2-tests.c index 4997b9222cfa..637b6d0ac0d0 100644 --- a/tools/testing/selftests/vm/mlock2-tests.c +++ b/tools/testing/selftests/vm/mlock2-tests.c @@ -9,6 +9,8 @@ #include #include "mlock2.h" +#include "../kselftest.h" + struct vm_boundaries { unsigned long start; unsigned long end; @@ -303,7 +305,7 @@ static int test_mlock_lock() if (mlock2_(map, 2 * page_size, 0)) { if (errno == ENOSYS) { printf("Cannot call new mlock family, skipping test\n"); - _exit(0); + _exit(KSFT_SKIP); } perror("mlock2(0)"); goto unmap; @@ -412,7 +414,7 @@ static int test_mlock_onfault() if (mlock2_(map, 2 * page_size, MLOCK_ONFAULT)) { if (errno == ENOSYS) { printf("Cannot call new mlock family, skipping test\n"); - _exit(0); + _exit(KSFT_SKIP); } perror("mlock2(MLOCK_ONFAULT)"); goto unmap; @@ -425,7 +427,7 @@ static int test_mlock_onfault() if (munlock(map, 2 * page_size)) { if (errno == ENOSYS) { printf("Cannot call new mlock family, skipping test\n"); - _exit(0); + _exit(KSFT_SKIP); } perror("munlock()"); goto unmap; @@ -457,7 +459,7 @@ static int test_lock_onfault_of_present() if (mlock2_(map, 2 * page_size, MLOCK_ONFAULT)) { if (errno == ENOSYS) { printf("Cannot call new mlock family, skipping test\n"); - _exit(0); + _exit(KSFT_SKIP); } perror("mlock2(MLOCK_ONFAULT)"); goto unmap; @@ -583,7 +585,7 @@ static int test_vma_management(bool call_mlock) if (call_mlock && mlock2_(map, 3 * page_size, MLOCK_ONFAULT)) { if (errno == ENOSYS) { printf("Cannot call new mlock family, skipping test\n"); - _exit(0); + _exit(KSFT_SKIP); } perror("mlock(ONFAULT)\n"); goto out; diff --git a/tools/testing/selftests/vm/run_vmtests b/tools/testing/selftests/vm/run_vmtests index 22d564673830..88cbe5575f0c 100755 --- a/tools/testing/selftests/vm/run_vmtests +++ b/tools/testing/selftests/vm/run_vmtests @@ -2,6 +2,9 @@ # SPDX-License-Identifier: GPL-2.0 #please run as root +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=4 + mnt=./huge exitcode=0 @@ -36,7 +39,7 @@ if [ -n "$freepgs" ] && [ -n "$hpgsize_KB" ]; then echo $(( $lackpgs + $nr_hugepgs )) > /proc/sys/vm/nr_hugepages if [ $? -ne 0 ]; then echo "Please run this test as root" - exit 1 + exit $ksft_skip fi while read name size unit; do if [ "$name" = "HugePages_Free:" ]; then diff --git a/tools/testing/selftests/vm/userfaultfd.c b/tools/testing/selftests/vm/userfaultfd.c index de2f9ec8a87f..7b8171e3128a 100644 --- a/tools/testing/selftests/vm/userfaultfd.c +++ b/tools/testing/selftests/vm/userfaultfd.c @@ -69,6 +69,8 @@ #include #include +#include "../kselftest.h" + #ifdef __NR_userfaultfd static unsigned long nr_cpus, nr_pages, nr_pages_per_cpu, page_size; @@ -1322,7 +1324,7 @@ int main(int argc, char **argv) int main(void) { printf("skip: Skipping userfaultfd test (missing __NR_userfaultfd)\n"); - return 0; + return KSFT_SKIP; } #endif /* __NR_userfaultfd */ -- cgit From d6a3e55131fcb1e5ca1753f4b6f297a177b2fc91 Mon Sep 17 00:00:00 2001 From: Fathi Boudra Date: Thu, 14 Jun 2018 11:57:08 +0200 Subject: selftests: sync: add config fragment for testing sync framework Unless the software synchronization objects (CONFIG_SW_SYNC) is enabled, the sync test will be skipped: TAP version 13 1..0 # Skipped: Sync framework not supported by kernel Add a config fragment file to be able to run "make kselftest-merge" to enable relevant configuration required in order to run the sync test. Signed-off-by: Fathi Boudra Link: https://lkml.org/lkml/2017/5/5/14 Signed-off-by: Anders Roxell Signed-off-by: Shuah Khan (Samsung OSG) --- tools/testing/selftests/sync/config | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 tools/testing/selftests/sync/config (limited to 'tools') diff --git a/tools/testing/selftests/sync/config b/tools/testing/selftests/sync/config new file mode 100644 index 000000000000..1ab7e8130db2 --- /dev/null +++ b/tools/testing/selftests/sync/config @@ -0,0 +1,4 @@ +CONFIG_STAGING=y +CONFIG_ANDROID=y +CONFIG_SYNC=y +CONFIG_SW_SYNC=y -- cgit From 3c62c91a3635d6c4ef23e00b4fc84fa77bbf99cc Mon Sep 17 00:00:00 2001 From: "Shuah Khan (Samsung OSG)" Date: Tue, 12 Jun 2018 16:50:37 -0600 Subject: selftests: sparc64: Fix to do nothing on non-sparc64 sparc64 test fails with the following errors on non-sparc64 systems. Fix the Makefile to do nothing on non-sparc64 systems to suppress the errors: make run_tests adi-test.c: Assembler messages: adi-test.c:302: Error: no such instruction: `rd %tick,%r13' adi-test.c:304: Error: no such instruction: `rd %tick,%rbp' adi-test.c:190: Error: no such instruction: `rd %tick,%rbp' adi-test.c:192: Error: no such instruction: `rd %tick,%rdx' adi-test.c:273: Error: no such instruction: `rd %tick,%rbx' adi-test.c:276: Error: no such instruction: `rd %tick,%rdx' adi-test.c:217: Error: no such instruction: `rd %tick,%rbp' adi-test.c:220: Error: no such instruction: `rd %tick,%rdx' adi-test.c:79: Error: no such instruction: `rd %tick,%rax' adi-test.c:79: Error: no such instruction: `rd %tick,%rax' adi-test.c:79: Error: no such instruction: `rd %tick,%rax' adi-test.c:79: Error: no such instruction: `rd %tick,%rax' adi-test.c:246: Error: no such instruction: `rd %tick,%rbp' adi-test.c:248: Error: no such instruction: `rd %tick,%rdx' adi-test.c:79: Error: no such instruction: `rd %tick,%rax' adi-test.c:79: Error: no such instruction: `rd %tick,%rax' adi-test.c:79: Error: no such instruction: `rd %tick,%rax' : recipe for target 'adi-test' failed make[1]: *** [adi-test] Error 1 adi: [FAIL] ./drivers_test.sh: 24: ./drivers_test.sh: ./adi-test: not found ../lib.mk:73: recipe for target 'run_tests' failed make: *** [run_tests] Error 1 Signed-off-by: Shuah Khan (Samsung OSG) Reviewed-by: Tom Hromatka Acked-by: David S. Miller Signed-off-by: Shuah Khan (Samsung OSG) --- tools/testing/selftests/sparc64/Makefile | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'tools') diff --git a/tools/testing/selftests/sparc64/Makefile b/tools/testing/selftests/sparc64/Makefile index 2082eeffd779..442f0ca45441 100644 --- a/tools/testing/selftests/sparc64/Makefile +++ b/tools/testing/selftests/sparc64/Makefile @@ -1,7 +1,17 @@ +uname_M := $(shell uname -m 2>/dev/null || echo not) +ARCH ?= $(shell echo $(uname_M) | sed -e s/x86_64/x86/) + +ifneq ($(ARCH),sparc64) +nothing: +.PHONY: all clean run_tests install +.SILENT: +else + SUBDIRS := drivers TEST_PROGS := run.sh + .PHONY: all clean include ../lib.mk @@ -44,3 +54,4 @@ override define CLEAN make OUTPUT=$$BUILD_TARGET -C $$DIR $@;\ done endef +endif -- cgit From 953c9d28d2c9bca15a17b11a022fbc657cc5631a Mon Sep 17 00:00:00 2001 From: "Shuah Khan (Samsung OSG)" Date: Tue, 12 Jun 2018 17:12:24 -0600 Subject: selftests: sparc64: delete RUN_TESTS and EMIT_TESTS overrides Delete RUN_TESTS and EMIT_TESTS overrides and use common defines in lib.mk. Common defines work just fine and there is no need to define custom overrides. Signed-off-by: Shuah Khan (Samsung OSG) Reviewed-by: Tom Hromatka Signed-off-by: Shuah Khan (Samsung OSG) --- tools/testing/selftests/sparc64/Makefile | 8 -------- 1 file changed, 8 deletions(-) (limited to 'tools') diff --git a/tools/testing/selftests/sparc64/Makefile b/tools/testing/selftests/sparc64/Makefile index 442f0ca45441..76b2206932c3 100644 --- a/tools/testing/selftests/sparc64/Makefile +++ b/tools/testing/selftests/sparc64/Makefile @@ -28,10 +28,6 @@ all: fi \ done -override define RUN_TESTS - @cd $(OUTPUT); ./run.sh -endef - override define INSTALL_RULE mkdir -p $(INSTALL_PATH) install -t $(INSTALL_PATH) $(TEST_PROGS) $(TEST_PROGS_EXTENDED) $(TEST_FILES) @@ -43,10 +39,6 @@ override define INSTALL_RULE done; endef -override define EMIT_TESTS - echo "./run.sh" -endef - override define CLEAN @for DIR in $(SUBDIRS); do \ BUILD_TARGET=$(OUTPUT)/$$DIR; \ -- cgit From eb83d5f7d07ed913d62ca4ad1e14fb6ca4937bab Mon Sep 17 00:00:00 2001 From: "Shuah Khan (Samsung OSG)" Date: Wed, 13 Jun 2018 16:20:52 -0600 Subject: selftests: sparc64: Add missing SPDX License Identifiers Add missing SPDX License Identifiers to Makefile(s). Signed-off-by: Shuah Khan (Samsung OSG) Reviewed-by: Tom Hromatka Signed-off-by: Shuah Khan (Samsung OSG) --- tools/testing/selftests/sparc64/Makefile | 1 + tools/testing/selftests/sparc64/drivers/Makefile | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/testing/selftests/sparc64/Makefile b/tools/testing/selftests/sparc64/Makefile index 76b2206932c3..a19531dba4dc 100644 --- a/tools/testing/selftests/sparc64/Makefile +++ b/tools/testing/selftests/sparc64/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 uname_M := $(shell uname -m 2>/dev/null || echo not) ARCH ?= $(shell echo $(uname_M) | sed -e s/x86_64/x86/) diff --git a/tools/testing/selftests/sparc64/drivers/Makefile b/tools/testing/selftests/sparc64/drivers/Makefile index 6264f40bbdbc..deb0df415565 100644 --- a/tools/testing/selftests/sparc64/drivers/Makefile +++ b/tools/testing/selftests/sparc64/drivers/Makefile @@ -1,4 +1,4 @@ - +# SPDX-License-Identifier: GPL-2.0 INCLUDEDIR := -I. CFLAGS := $(CFLAGS) $(INCLUDEDIR) -Wall -O2 -g -- cgit From 684fb246578b9e81fc7b4ca5c71eae22edb650b2 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Tue, 19 Jun 2018 10:47:50 -0500 Subject: objtool: Add machine_real_restart() to the noreturn list machine_real_restart() is annotated as '__noreturn", so add it to the objtool noreturn list. This fixes the following warning with clang and CONFIG_CC_OPTIMIZE_FOR_SIZE=y: arch/x86/kernel/reboot.o: warning: objtool: native_machine_emergency_restart() falls through to next function machine_power_off() Reported-by: Matthias Kaehlcke Signed-off-by: Josh Poimboeuf Signed-off-by: Thomas Gleixner Tested-by: Matthias Kaehlcke Reviewed-by: Matthias Kaehlcke Link: https://lkml.kernel.org/r/791712792aa4431bdd55bf1beb33a169ddf3b4a2.1529423255.git.jpoimboe@redhat.com --- tools/objtool/check.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tools') diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 38047c6aa575..f4a25bd1871f 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -164,6 +164,7 @@ static int __dead_end_function(struct objtool_file *file, struct symbol *func, "lbug_with_loc", "fortify_panic", "usercopy_abort", + "machine_real_restart", }; if (func->bind == STB_WEAK) -- cgit From 744f4be542d705a39dac9810350e96f37474eda3 Mon Sep 17 00:00:00 2001 From: Paul Burton Date: Thu, 14 Jun 2018 11:06:22 -0700 Subject: rseq/selftests: Implement MIPS support Implement support for both MIPS32 & MIPS64 in the rseq selftests, in order to sanity check the recently enabled rseq syscall. The tests all pass on a MIPS Boston development board running either a MIPS32r2 interAptiv CPU & a MIPS64r6 I6500 CPU, both of which were configured with 2 cores each of which have 2 hardware threads (VP(E)s) - ie. 4 CPUs. Signed-off-by: Paul Burton Reviewed-by: James Hogan Patchwork: https://patchwork.linux-mips.org/patch/19524/ Cc: Ralf Baechle Cc: Mathieu Desnoyers Cc: Peter Zijlstra Cc: Paul E. McKenney Cc: Boqun Feng Cc: linux-mips@linux-mips.org Cc: linux-kernel@vger.kernel.org --- tools/testing/selftests/rseq/param_test.c | 24 + tools/testing/selftests/rseq/rseq-mips.h | 725 ++++++++++++++++++++++++++++++ tools/testing/selftests/rseq/rseq.h | 2 + 3 files changed, 751 insertions(+) create mode 100644 tools/testing/selftests/rseq/rseq-mips.h (limited to 'tools') diff --git a/tools/testing/selftests/rseq/param_test.c b/tools/testing/selftests/rseq/param_test.c index 6a9f602a8718..615252331813 100644 --- a/tools/testing/selftests/rseq/param_test.c +++ b/tools/testing/selftests/rseq/param_test.c @@ -137,6 +137,30 @@ unsigned int yield_mod_cnt, nr_abort; "subic. %%" INJECT_ASM_REG ", %%" INJECT_ASM_REG ", 1\n\t" \ "bne 222b\n\t" \ "333:\n\t" + +#elif defined(__mips__) + +#define RSEQ_INJECT_INPUT \ + , [loop_cnt_1]"m"(loop_cnt[1]) \ + , [loop_cnt_2]"m"(loop_cnt[2]) \ + , [loop_cnt_3]"m"(loop_cnt[3]) \ + , [loop_cnt_4]"m"(loop_cnt[4]) \ + , [loop_cnt_5]"m"(loop_cnt[5]) \ + , [loop_cnt_6]"m"(loop_cnt[6]) + +#define INJECT_ASM_REG "$5" + +#define RSEQ_INJECT_CLOBBER \ + , INJECT_ASM_REG + +#define RSEQ_INJECT_ASM(n) \ + "lw " INJECT_ASM_REG ", %[loop_cnt_" #n "]\n\t" \ + "beqz " INJECT_ASM_REG ", 333f\n\t" \ + "222:\n\t" \ + "addiu " INJECT_ASM_REG ", -1\n\t" \ + "bnez " INJECT_ASM_REG ", 222b\n\t" \ + "333:\n\t" + #else #error unsupported target #endif diff --git a/tools/testing/selftests/rseq/rseq-mips.h b/tools/testing/selftests/rseq/rseq-mips.h new file mode 100644 index 000000000000..7f48ecf46994 --- /dev/null +++ b/tools/testing/selftests/rseq/rseq-mips.h @@ -0,0 +1,725 @@ +/* SPDX-License-Identifier: LGPL-2.1 OR MIT */ +/* + * Author: Paul Burton + * (C) Copyright 2018 MIPS Tech LLC + * + * Based on rseq-arm.h: + * (C) Copyright 2016-2018 - Mathieu Desnoyers + */ + +#define RSEQ_SIG 0x53053053 + +#define rseq_smp_mb() __asm__ __volatile__ ("sync" ::: "memory") +#define rseq_smp_rmb() rseq_smp_mb() +#define rseq_smp_wmb() rseq_smp_mb() + +#define rseq_smp_load_acquire(p) \ +__extension__ ({ \ + __typeof(*p) ____p1 = RSEQ_READ_ONCE(*p); \ + rseq_smp_mb(); \ + ____p1; \ +}) + +#define rseq_smp_acquire__after_ctrl_dep() rseq_smp_rmb() + +#define rseq_smp_store_release(p, v) \ +do { \ + rseq_smp_mb(); \ + RSEQ_WRITE_ONCE(*p, v); \ +} while (0) + +#ifdef RSEQ_SKIP_FASTPATH +#include "rseq-skip.h" +#else /* !RSEQ_SKIP_FASTPATH */ + +#if _MIPS_SZLONG == 64 +# define LONG ".dword" +# define LONG_LA "dla" +# define LONG_L "ld" +# define LONG_S "sd" +# define LONG_ADDI "daddiu" +# define U32_U64_PAD(x) x +#elif _MIPS_SZLONG == 32 +# define LONG ".word" +# define LONG_LA "la" +# define LONG_L "lw" +# define LONG_S "sw" +# define LONG_ADDI "addiu" +# ifdef __BIG_ENDIAN +# define U32_U64_PAD(x) "0x0, " x +# else +# define U32_U64_PAD(x) x ", 0x0" +# endif +#else +# error unsupported _MIPS_SZLONG +#endif + +#define __RSEQ_ASM_DEFINE_TABLE(version, flags, start_ip, \ + post_commit_offset, abort_ip) \ + ".pushsection __rseq_table, \"aw\"\n\t" \ + ".balign 32\n\t" \ + ".word " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \ + LONG " " U32_U64_PAD(__rseq_str(start_ip)) "\n\t" \ + LONG " " U32_U64_PAD(__rseq_str(post_commit_offset)) "\n\t" \ + LONG " " U32_U64_PAD(__rseq_str(abort_ip)) "\n\t" \ + ".popsection\n\t" + +#define RSEQ_ASM_DEFINE_TABLE(start_ip, post_commit_ip, abort_ip) \ + __RSEQ_ASM_DEFINE_TABLE(0x0, 0x0, start_ip, \ + (post_commit_ip - start_ip), abort_ip) + +#define RSEQ_ASM_STORE_RSEQ_CS(label, cs_label, rseq_cs) \ + RSEQ_INJECT_ASM(1) \ + LONG_LA " $4, " __rseq_str(cs_label) "\n\t" \ + LONG_S " $4, %[" __rseq_str(rseq_cs) "]\n\t" \ + __rseq_str(label) ":\n\t" + +#define RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, label) \ + RSEQ_INJECT_ASM(2) \ + "lw $4, %[" __rseq_str(current_cpu_id) "]\n\t" \ + "bne $4, %[" __rseq_str(cpu_id) "], " __rseq_str(label) "\n\t" + +#define __RSEQ_ASM_DEFINE_ABORT(table_label, label, teardown, \ + abort_label, version, flags, \ + start_ip, post_commit_offset, abort_ip) \ + ".balign 32\n\t" \ + __rseq_str(table_label) ":\n\t" \ + ".word " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \ + LONG " " U32_U64_PAD(__rseq_str(start_ip)) "\n\t" \ + LONG " " U32_U64_PAD(__rseq_str(post_commit_offset)) "\n\t" \ + LONG " " U32_U64_PAD(__rseq_str(abort_ip)) "\n\t" \ + ".word " __rseq_str(RSEQ_SIG) "\n\t" \ + __rseq_str(label) ":\n\t" \ + teardown \ + "b %l[" __rseq_str(abort_label) "]\n\t" + +#define RSEQ_ASM_DEFINE_ABORT(table_label, label, teardown, abort_label, \ + start_ip, post_commit_ip, abort_ip) \ + __RSEQ_ASM_DEFINE_ABORT(table_label, label, teardown, \ + abort_label, 0x0, 0x0, start_ip, \ + (post_commit_ip - start_ip), abort_ip) + +#define RSEQ_ASM_DEFINE_CMPFAIL(label, teardown, cmpfail_label) \ + __rseq_str(label) ":\n\t" \ + teardown \ + "b %l[" __rseq_str(cmpfail_label) "]\n\t" + +#define rseq_workaround_gcc_asm_size_guess() __asm__ __volatile__("") + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_storev(intptr_t *v, intptr_t expect, intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + LONG_L " $4, %[v]\n\t" + "bne $4, %[expect], %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + LONG_L " $4, %[v]\n\t" + "bne $4, %[expect], %l[error2]\n\t" +#endif + /* final store */ + LONG_S " %[newv], %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(5) + "b 5f\n\t" + RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f) + "5:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) + RSEQ_INJECT_INPUT + : "$4", "memory" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + rseq_workaround_gcc_asm_size_guess(); + return 0; +abort: + rseq_workaround_gcc_asm_size_guess(); + RSEQ_INJECT_FAILED + return -1; +cmpfail: + rseq_workaround_gcc_asm_size_guess(); + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpnev_storeoffp_load(intptr_t *v, intptr_t expectnot, + off_t voffp, intptr_t *load, int cpu) +{ + RSEQ_INJECT_C(9) + + rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + LONG_L " $4, %[v]\n\t" + "beq $4, %[expectnot], %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + LONG_L " $4, %[v]\n\t" + "beq $4, %[expectnot], %l[error2]\n\t" +#endif + LONG_S " $4, %[load]\n\t" + LONG_ADDI " $4, %[voffp]\n\t" + LONG_L " $4, 0($4)\n\t" + /* final store */ + LONG_S " $4, %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(5) + "b 5f\n\t" + RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f) + "5:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* final store input */ + [v] "m" (*v), + [expectnot] "r" (expectnot), + [voffp] "Ir" (voffp), + [load] "m" (*load) + RSEQ_INJECT_INPUT + : "$4", "memory" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + rseq_workaround_gcc_asm_size_guess(); + return 0; +abort: + rseq_workaround_gcc_asm_size_guess(); + RSEQ_INJECT_FAILED + return -1; +cmpfail: + rseq_workaround_gcc_asm_size_guess(); + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_addv(intptr_t *v, intptr_t count, int cpu) +{ + RSEQ_INJECT_C(9) + + rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) +#endif + LONG_L " $4, %[v]\n\t" + LONG_ADDI " $4, %[count]\n\t" + /* final store */ + LONG_S " $4, %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(4) + "b 5f\n\t" + RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f) + "5:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + [v] "m" (*v), + [count] "Ir" (count) + RSEQ_INJECT_INPUT + : "$4", "memory" + RSEQ_INJECT_CLOBBER + : abort +#ifdef RSEQ_COMPARE_TWICE + , error1 +#endif + ); + rseq_workaround_gcc_asm_size_guess(); + return 0; +abort: + rseq_workaround_gcc_asm_size_guess(); + RSEQ_INJECT_FAILED + return -1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trystorev_storev(intptr_t *v, intptr_t expect, + intptr_t *v2, intptr_t newv2, + intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + LONG_L " $4, %[v]\n\t" + "bne $4, %[expect], %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + LONG_L " $4, %[v]\n\t" + "bne $4, %[expect], %l[error2]\n\t" +#endif + /* try store */ + LONG_S " %[newv2], %[v2]\n\t" + RSEQ_INJECT_ASM(5) + /* final store */ + LONG_S " %[newv], %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(6) + "b 5f\n\t" + RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f) + "5:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* try store input */ + [v2] "m" (*v2), + [newv2] "r" (newv2), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) + RSEQ_INJECT_INPUT + : "$4", "memory" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + rseq_workaround_gcc_asm_size_guess(); + return 0; +abort: + rseq_workaround_gcc_asm_size_guess(); + RSEQ_INJECT_FAILED + return -1; +cmpfail: + rseq_workaround_gcc_asm_size_guess(); + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trystorev_storev_release(intptr_t *v, intptr_t expect, + intptr_t *v2, intptr_t newv2, + intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + LONG_L " $4, %[v]\n\t" + "bne $4, %[expect], %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + LONG_L " $4, %[v]\n\t" + "bne $4, %[expect], %l[error2]\n\t" +#endif + /* try store */ + LONG_S " %[newv2], %[v2]\n\t" + RSEQ_INJECT_ASM(5) + "sync\n\t" /* full sync provides store-release */ + /* final store */ + LONG_S " %[newv], %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(6) + "b 5f\n\t" + RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f) + "5:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* try store input */ + [v2] "m" (*v2), + [newv2] "r" (newv2), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) + RSEQ_INJECT_INPUT + : "$4", "memory" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + rseq_workaround_gcc_asm_size_guess(); + return 0; +abort: + rseq_workaround_gcc_asm_size_guess(); + RSEQ_INJECT_FAILED + return -1; +cmpfail: + rseq_workaround_gcc_asm_size_guess(); + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_cmpeqv_storev(intptr_t *v, intptr_t expect, + intptr_t *v2, intptr_t expect2, + intptr_t newv, int cpu) +{ + RSEQ_INJECT_C(9) + + rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */ + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + LONG_L " $4, %[v]\n\t" + "bne $4, %[expect], %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(4) + LONG_L " $4, %[v2]\n\t" + "bne $4, %[expect2], %l[cmpfail]\n\t" + RSEQ_INJECT_ASM(5) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, %l[error1]) + LONG_L " $4, %[v]\n\t" + "bne $4, %[expect], %l[error2]\n\t" + LONG_L " $4, %[v2]\n\t" + "bne $4, %[expect2], %l[error3]\n\t" +#endif + /* final store */ + LONG_S " %[newv], %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(6) + "b 5f\n\t" + RSEQ_ASM_DEFINE_ABORT(3, 4, "", abort, 1b, 2b, 4f) + "5:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* cmp2 input */ + [v2] "m" (*v2), + [expect2] "r" (expect2), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv) + RSEQ_INJECT_INPUT + : "$4", "memory" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2, error3 +#endif + ); + rseq_workaround_gcc_asm_size_guess(); + return 0; +abort: + rseq_workaround_gcc_asm_size_guess(); + RSEQ_INJECT_FAILED + return -1; +cmpfail: + rseq_workaround_gcc_asm_size_guess(); + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_bug("cpu_id comparison failed"); +error2: + rseq_bug("1st expected value comparison failed"); +error3: + rseq_bug("2nd expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trymemcpy_storev(intptr_t *v, intptr_t expect, + void *dst, void *src, size_t len, + intptr_t newv, int cpu) +{ + uintptr_t rseq_scratch[3]; + + RSEQ_INJECT_C(9) + + rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */ + LONG_S " %[src], %[rseq_scratch0]\n\t" + LONG_S " %[dst], %[rseq_scratch1]\n\t" + LONG_S " %[len], %[rseq_scratch2]\n\t" + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + LONG_L " $4, %[v]\n\t" + "bne $4, %[expect], 5f\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 6f) + LONG_L " $4, %[v]\n\t" + "bne $4, %[expect], 7f\n\t" +#endif + /* try memcpy */ + "beqz %[len], 333f\n\t" \ + "222:\n\t" \ + "lb $4, 0(%[src])\n\t" \ + "sb $4, 0(%[dst])\n\t" \ + LONG_ADDI " %[src], 1\n\t" \ + LONG_ADDI " %[dst], 1\n\t" \ + LONG_ADDI " %[len], -1\n\t" \ + "bnez %[len], 222b\n\t" \ + "333:\n\t" \ + RSEQ_INJECT_ASM(5) + /* final store */ + LONG_S " %[newv], %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(6) + /* teardown */ + LONG_L " %[len], %[rseq_scratch2]\n\t" + LONG_L " %[dst], %[rseq_scratch1]\n\t" + LONG_L " %[src], %[rseq_scratch0]\n\t" + "b 8f\n\t" + RSEQ_ASM_DEFINE_ABORT(3, 4, + /* teardown */ + LONG_L " %[len], %[rseq_scratch2]\n\t" + LONG_L " %[dst], %[rseq_scratch1]\n\t" + LONG_L " %[src], %[rseq_scratch0]\n\t", + abort, 1b, 2b, 4f) + RSEQ_ASM_DEFINE_CMPFAIL(5, + /* teardown */ + LONG_L " %[len], %[rseq_scratch2]\n\t" + LONG_L " %[dst], %[rseq_scratch1]\n\t" + LONG_L " %[src], %[rseq_scratch0]\n\t", + cmpfail) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_DEFINE_CMPFAIL(6, + /* teardown */ + LONG_L " %[len], %[rseq_scratch2]\n\t" + LONG_L " %[dst], %[rseq_scratch1]\n\t" + LONG_L " %[src], %[rseq_scratch0]\n\t", + error1) + RSEQ_ASM_DEFINE_CMPFAIL(7, + /* teardown */ + LONG_L " %[len], %[rseq_scratch2]\n\t" + LONG_L " %[dst], %[rseq_scratch1]\n\t" + LONG_L " %[src], %[rseq_scratch0]\n\t", + error2) +#endif + "8:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv), + /* try memcpy input */ + [dst] "r" (dst), + [src] "r" (src), + [len] "r" (len), + [rseq_scratch0] "m" (rseq_scratch[0]), + [rseq_scratch1] "m" (rseq_scratch[1]), + [rseq_scratch2] "m" (rseq_scratch[2]) + RSEQ_INJECT_INPUT + : "$4", "memory" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + rseq_workaround_gcc_asm_size_guess(); + return 0; +abort: + rseq_workaround_gcc_asm_size_guess(); + RSEQ_INJECT_FAILED + return -1; +cmpfail: + rseq_workaround_gcc_asm_size_guess(); + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_workaround_gcc_asm_size_guess(); + rseq_bug("cpu_id comparison failed"); +error2: + rseq_workaround_gcc_asm_size_guess(); + rseq_bug("expected value comparison failed"); +#endif +} + +static inline __attribute__((always_inline)) +int rseq_cmpeqv_trymemcpy_storev_release(intptr_t *v, intptr_t expect, + void *dst, void *src, size_t len, + intptr_t newv, int cpu) +{ + uintptr_t rseq_scratch[3]; + + RSEQ_INJECT_C(9) + + rseq_workaround_gcc_asm_size_guess(); + __asm__ __volatile__ goto ( + RSEQ_ASM_DEFINE_TABLE(1f, 2f, 4f) /* start, commit, abort */ + LONG_S " %[src], %[rseq_scratch0]\n\t" + LONG_S " %[dst], %[rseq_scratch1]\n\t" + LONG_S " %[len], %[rseq_scratch2]\n\t" + /* Start rseq by storing table entry pointer into rseq_cs. */ + RSEQ_ASM_STORE_RSEQ_CS(1, 3f, rseq_cs) + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 4f) + RSEQ_INJECT_ASM(3) + LONG_L " $4, %[v]\n\t" + "bne $4, %[expect], 5f\n\t" + RSEQ_INJECT_ASM(4) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_CMP_CPU_ID(cpu_id, current_cpu_id, 6f) + LONG_L " $4, %[v]\n\t" + "bne $4, %[expect], 7f\n\t" +#endif + /* try memcpy */ + "beqz %[len], 333f\n\t" \ + "222:\n\t" \ + "lb $4, 0(%[src])\n\t" \ + "sb $4, 0(%[dst])\n\t" \ + LONG_ADDI " %[src], 1\n\t" \ + LONG_ADDI " %[dst], 1\n\t" \ + LONG_ADDI " %[len], -1\n\t" \ + "bnez %[len], 222b\n\t" \ + "333:\n\t" \ + RSEQ_INJECT_ASM(5) + "sync\n\t" /* full sync provides store-release */ + /* final store */ + LONG_S " %[newv], %[v]\n\t" + "2:\n\t" + RSEQ_INJECT_ASM(6) + /* teardown */ + LONG_L " %[len], %[rseq_scratch2]\n\t" + LONG_L " %[dst], %[rseq_scratch1]\n\t" + LONG_L " %[src], %[rseq_scratch0]\n\t" + "b 8f\n\t" + RSEQ_ASM_DEFINE_ABORT(3, 4, + /* teardown */ + LONG_L " %[len], %[rseq_scratch2]\n\t" + LONG_L " %[dst], %[rseq_scratch1]\n\t" + LONG_L " %[src], %[rseq_scratch0]\n\t", + abort, 1b, 2b, 4f) + RSEQ_ASM_DEFINE_CMPFAIL(5, + /* teardown */ + LONG_L " %[len], %[rseq_scratch2]\n\t" + LONG_L " %[dst], %[rseq_scratch1]\n\t" + LONG_L " %[src], %[rseq_scratch0]\n\t", + cmpfail) +#ifdef RSEQ_COMPARE_TWICE + RSEQ_ASM_DEFINE_CMPFAIL(6, + /* teardown */ + LONG_L " %[len], %[rseq_scratch2]\n\t" + LONG_L " %[dst], %[rseq_scratch1]\n\t" + LONG_L " %[src], %[rseq_scratch0]\n\t", + error1) + RSEQ_ASM_DEFINE_CMPFAIL(7, + /* teardown */ + LONG_L " %[len], %[rseq_scratch2]\n\t" + LONG_L " %[dst], %[rseq_scratch1]\n\t" + LONG_L " %[src], %[rseq_scratch0]\n\t", + error2) +#endif + "8:\n\t" + : /* gcc asm goto does not allow outputs */ + : [cpu_id] "r" (cpu), + [current_cpu_id] "m" (__rseq_abi.cpu_id), + [rseq_cs] "m" (__rseq_abi.rseq_cs), + /* final store input */ + [v] "m" (*v), + [expect] "r" (expect), + [newv] "r" (newv), + /* try memcpy input */ + [dst] "r" (dst), + [src] "r" (src), + [len] "r" (len), + [rseq_scratch0] "m" (rseq_scratch[0]), + [rseq_scratch1] "m" (rseq_scratch[1]), + [rseq_scratch2] "m" (rseq_scratch[2]) + RSEQ_INJECT_INPUT + : "$4", "memory" + RSEQ_INJECT_CLOBBER + : abort, cmpfail +#ifdef RSEQ_COMPARE_TWICE + , error1, error2 +#endif + ); + rseq_workaround_gcc_asm_size_guess(); + return 0; +abort: + rseq_workaround_gcc_asm_size_guess(); + RSEQ_INJECT_FAILED + return -1; +cmpfail: + rseq_workaround_gcc_asm_size_guess(); + return 1; +#ifdef RSEQ_COMPARE_TWICE +error1: + rseq_workaround_gcc_asm_size_guess(); + rseq_bug("cpu_id comparison failed"); +error2: + rseq_workaround_gcc_asm_size_guess(); + rseq_bug("expected value comparison failed"); +#endif +} + +#endif /* !RSEQ_SKIP_FASTPATH */ diff --git a/tools/testing/selftests/rseq/rseq.h b/tools/testing/selftests/rseq/rseq.h index 0a808575cbc4..a4684112676c 100644 --- a/tools/testing/selftests/rseq/rseq.h +++ b/tools/testing/selftests/rseq/rseq.h @@ -73,6 +73,8 @@ extern __thread volatile struct rseq __rseq_abi; #include #elif defined(__PPC__) #include +#elif defined(__mips__) +#include #else #error unsupported target #endif -- cgit From bdd5ae3aa51939bb1fd26cd9fe7af07ca8c60397 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Wed, 6 Jun 2018 17:18:36 -0400 Subject: tools/power turbostat: fix show/hide issues resulting from mis-merge The --show and --hide options failed on "Node", which was listed as "Node%". The --show and --hide options were generally fouled-up do due to come content merges that scrambled the list of column name indexes. Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 106 +++++++++++++++++----------------- 1 file changed, 54 insertions(+), 52 deletions(-) (limited to 'tools') diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index d6cff3070ebd..f09a272941a1 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -381,19 +381,23 @@ int get_msr(int cpu, off_t offset, unsigned long long *msr) } /* - * Each string in this array is compared in --show and --hide cmdline. - * Thus, strings that are proper sub-sets must follow their more specific peers. + * This list matches the column headers, except + * 1. built-in only, the sysfs counters are not here -- we learn of those at run-time + * 2. Core and CPU are moved to the end, we can't have strings that contain them + * matching on them for --show and --hide. */ struct msr_counter bic[] = { { 0x0, "usec" }, { 0x0, "Time_Of_Day_Seconds" }, { 0x0, "Package" }, + { 0x0, "Node" }, { 0x0, "Avg_MHz" }, + { 0x0, "Busy%" }, { 0x0, "Bzy_MHz" }, { 0x0, "TSC_MHz" }, { 0x0, "IRQ" }, { 0x0, "SMI", "", 32, 0, FORMAT_DELTA, NULL}, - { 0x0, "Busy%" }, + { 0x0, "sysfs" }, { 0x0, "CPU%c1" }, { 0x0, "CPU%c3" }, { 0x0, "CPU%c6" }, @@ -424,15 +428,13 @@ struct msr_counter bic[] = { { 0x0, "Cor_J" }, { 0x0, "GFX_J" }, { 0x0, "RAM_J" }, - { 0x0, "Core" }, - { 0x0, "CPU" }, { 0x0, "Mod%c6" }, - { 0x0, "sysfs" }, { 0x0, "Totl%C0" }, { 0x0, "Any%C0" }, { 0x0, "GFX%C0" }, { 0x0, "CPUGFX%" }, - { 0x0, "Node%" }, + { 0x0, "Core" }, + { 0x0, "CPU" }, }; @@ -441,51 +443,51 @@ struct msr_counter bic[] = { #define BIC_USEC (1ULL << 0) #define BIC_TOD (1ULL << 1) #define BIC_Package (1ULL << 2) -#define BIC_Avg_MHz (1ULL << 3) -#define BIC_Bzy_MHz (1ULL << 4) -#define BIC_TSC_MHz (1ULL << 5) -#define BIC_IRQ (1ULL << 6) -#define BIC_SMI (1ULL << 7) -#define BIC_Busy (1ULL << 8) -#define BIC_CPU_c1 (1ULL << 9) -#define BIC_CPU_c3 (1ULL << 10) -#define BIC_CPU_c6 (1ULL << 11) -#define BIC_CPU_c7 (1ULL << 12) -#define BIC_ThreadC (1ULL << 13) -#define BIC_CoreTmp (1ULL << 14) -#define BIC_CoreCnt (1ULL << 15) -#define BIC_PkgTmp (1ULL << 16) -#define BIC_GFX_rc6 (1ULL << 17) -#define BIC_GFXMHz (1ULL << 18) -#define BIC_Pkgpc2 (1ULL << 19) -#define BIC_Pkgpc3 (1ULL << 20) -#define BIC_Pkgpc6 (1ULL << 21) -#define BIC_Pkgpc7 (1ULL << 22) -#define BIC_Pkgpc8 (1ULL << 23) -#define BIC_Pkgpc9 (1ULL << 24) -#define BIC_Pkgpc10 (1ULL << 25) -#define BIC_CPU_LPI (1ULL << 26) -#define BIC_SYS_LPI (1ULL << 27) -#define BIC_PkgWatt (1ULL << 26) -#define BIC_CorWatt (1ULL << 27) -#define BIC_GFXWatt (1ULL << 28) -#define BIC_PkgCnt (1ULL << 29) -#define BIC_RAMWatt (1ULL << 30) -#define BIC_PKG__ (1ULL << 31) -#define BIC_RAM__ (1ULL << 32) -#define BIC_Pkg_J (1ULL << 33) -#define BIC_Cor_J (1ULL << 34) -#define BIC_GFX_J (1ULL << 35) -#define BIC_RAM_J (1ULL << 36) -#define BIC_Core (1ULL << 37) -#define BIC_CPU (1ULL << 38) -#define BIC_Mod_c6 (1ULL << 39) -#define BIC_sysfs (1ULL << 40) -#define BIC_Totl_c0 (1ULL << 41) -#define BIC_Any_c0 (1ULL << 42) -#define BIC_GFX_c0 (1ULL << 43) -#define BIC_CPUGFX (1ULL << 44) -#define BIC_Node (1ULL << 45) +#define BIC_Node (1ULL << 3) +#define BIC_Avg_MHz (1ULL << 4) +#define BIC_Busy (1ULL << 5) +#define BIC_Bzy_MHz (1ULL << 6) +#define BIC_TSC_MHz (1ULL << 7) +#define BIC_IRQ (1ULL << 8) +#define BIC_SMI (1ULL << 9) +#define BIC_sysfs (1ULL << 10) +#define BIC_CPU_c1 (1ULL << 11) +#define BIC_CPU_c3 (1ULL << 12) +#define BIC_CPU_c6 (1ULL << 13) +#define BIC_CPU_c7 (1ULL << 14) +#define BIC_ThreadC (1ULL << 15) +#define BIC_CoreTmp (1ULL << 16) +#define BIC_CoreCnt (1ULL << 17) +#define BIC_PkgTmp (1ULL << 18) +#define BIC_GFX_rc6 (1ULL << 19) +#define BIC_GFXMHz (1ULL << 20) +#define BIC_Pkgpc2 (1ULL << 21) +#define BIC_Pkgpc3 (1ULL << 22) +#define BIC_Pkgpc6 (1ULL << 23) +#define BIC_Pkgpc7 (1ULL << 24) +#define BIC_Pkgpc8 (1ULL << 25) +#define BIC_Pkgpc9 (1ULL << 26) +#define BIC_Pkgpc10 (1ULL << 27) +#define BIC_CPU_LPI (1ULL << 28) +#define BIC_SYS_LPI (1ULL << 29) +#define BIC_PkgWatt (1ULL << 30) +#define BIC_CorWatt (1ULL << 31) +#define BIC_GFXWatt (1ULL << 32) +#define BIC_PkgCnt (1ULL << 33) +#define BIC_RAMWatt (1ULL << 34) +#define BIC_PKG__ (1ULL << 35) +#define BIC_RAM__ (1ULL << 36) +#define BIC_Pkg_J (1ULL << 37) +#define BIC_Cor_J (1ULL << 38) +#define BIC_GFX_J (1ULL << 39) +#define BIC_RAM_J (1ULL << 40) +#define BIC_Mod_c6 (1ULL << 41) +#define BIC_Totl_c0 (1ULL << 42) +#define BIC_Any_c0 (1ULL << 43) +#define BIC_GFX_c0 (1ULL << 44) +#define BIC_CPUGFX (1ULL << 45) +#define BIC_Core (1ULL << 46) +#define BIC_CPU (1ULL << 47) #define BIC_DISABLED_BY_DEFAULT (BIC_USEC | BIC_TOD) -- cgit From d9d226ffadbf4a8e60f5b8fc866aaa5028c7e479 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Wed, 6 Jun 2018 15:47:36 -0400 Subject: tools/power turbostat: decode cpuid.1.HT eg. the "HT" here: CPUID(1): SSE3 MONITOR - EIST TM2 TSC MSR ACPI-TM HT TM Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index f09a272941a1..b0f294bf89c3 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -4394,7 +4394,7 @@ void process_cpuid() if (!quiet) { fprintf(outf, "%d CPUID levels; family:model:stepping 0x%x:%x:%x (%d:%d:%d)\n", max_level, family, model, stepping, family, model, stepping); - fprintf(outf, "CPUID(1): %s %s %s %s %s %s %s %s %s\n", + fprintf(outf, "CPUID(1): %s %s %s %s %s %s %s %s %s %s\n", ecx & (1 << 0) ? "SSE3" : "-", ecx & (1 << 3) ? "MONITOR" : "-", ecx & (1 << 6) ? "SMX" : "-", @@ -4403,6 +4403,7 @@ void process_cpuid() edx & (1 << 4) ? "TSC" : "-", edx & (1 << 5) ? "MSR" : "-", edx & (1 << 22) ? "ACPI-TM" : "-", + edx & (1 << 28) ? "HT" : "-", edx & (1 << 29) ? "TM" : "-"); } -- cgit From 4c2122d42116ebaa1665ad0fbef2c558fdc0e3c6 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Wed, 6 Jun 2018 17:44:48 -0400 Subject: tools/power turbostat: add optional APIC X2APIC columns Add APIC and X2APIC columns to the topology section. They are disabled-by-default -- enable like so: --debug or --enable APIC,X2APIC Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.8 | 2 +- tools/power/x86/turbostat/turbostat.c | 75 +++++++++++++++++++++++++++++++---- 2 files changed, 68 insertions(+), 9 deletions(-) (limited to 'tools') diff --git a/tools/power/x86/turbostat/turbostat.8 b/tools/power/x86/turbostat/turbostat.8 index ca9ef7017624..d39e4ff7d0bf 100644 --- a/tools/power/x86/turbostat/turbostat.8 +++ b/tools/power/x86/turbostat/turbostat.8 @@ -56,7 +56,7 @@ name as necessary to disambiguate it from others is necessary. Note that option .PP \fB--hide column\fP do not show the specified built-in columns. May be invoked multiple times, or with a comma-separated list of column names. Use "--hide sysfs" to hide the sysfs statistics columns as a group. .PP -\fB--enable column\fP show the specified built-in columns, which are otherwise disabled, by default. Currently the only built-in counters disabled by default are "usec" and "Time_Of_Day_Seconds". +\fB--enable column\fP show the specified built-in columns, which are otherwise disabled, by default. Currently the only built-in counters disabled by default are "usec", "Time_Of_Day_Seconds", "APIC" and "X2APIC". The column name "all" can be used to enable all disabled-by-default built-in counters. .PP \fB--show column\fP show only the specified built-in columns. May be invoked multiple times, or with a comma-separated list of column names. Use "--show sysfs" to show the sysfs statistics columns as a group. diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index b0f294bf89c3..3bc2c9d94739 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -109,6 +109,7 @@ unsigned int has_hwp_activity_window; /* IA32_HWP_REQUEST[bits 41:32] */ unsigned int has_hwp_epp; /* IA32_HWP_REQUEST[bits 31:24] */ unsigned int has_hwp_pkg; /* IA32_HWP_REQUEST_PKG */ unsigned int has_misc_feature_control; +unsigned int first_counter_read = 1; #define RAPL_PKG (1 << 0) /* 0x610 MSR_PKG_POWER_LIMIT */ @@ -170,6 +171,8 @@ struct thread_data { unsigned long long irq_count; unsigned int smi_count; unsigned int cpu_id; + unsigned int apic_id; + unsigned int x2apic_id; unsigned int flags; #define CPU_IS_FIRST_THREAD_IN_CORE 0x2 #define CPU_IS_FIRST_CORE_IN_PACKAGE 0x4 @@ -435,10 +438,10 @@ struct msr_counter bic[] = { { 0x0, "CPUGFX%" }, { 0x0, "Core" }, { 0x0, "CPU" }, + { 0x0, "APIC" }, + { 0x0, "X2APIC" }, }; - - #define MAX_BIC (sizeof(bic) / sizeof(struct msr_counter)) #define BIC_USEC (1ULL << 0) #define BIC_TOD (1ULL << 1) @@ -488,11 +491,13 @@ struct msr_counter bic[] = { #define BIC_CPUGFX (1ULL << 45) #define BIC_Core (1ULL << 46) #define BIC_CPU (1ULL << 47) +#define BIC_APIC (1ULL << 48) +#define BIC_X2APIC (1ULL << 49) -#define BIC_DISABLED_BY_DEFAULT (BIC_USEC | BIC_TOD) +#define BIC_DISABLED_BY_DEFAULT (BIC_USEC | BIC_TOD | BIC_APIC | BIC_X2APIC) unsigned long long bic_enabled = (0xFFFFFFFFFFFFFFFFULL & ~BIC_DISABLED_BY_DEFAULT); -unsigned long long bic_present = BIC_USEC | BIC_TOD | BIC_sysfs; +unsigned long long bic_present = BIC_USEC | BIC_TOD | BIC_sysfs | BIC_APIC | BIC_X2APIC; #define DO_BIC(COUNTER_NAME) (bic_enabled & bic_present & COUNTER_NAME) #define ENABLE_BIC(COUNTER_NAME) (bic_enabled |= COUNTER_NAME) @@ -603,6 +608,10 @@ void print_header(char *delim) outp += sprintf(outp, "%sCore", (printed++ ? delim : "")); if (DO_BIC(BIC_CPU)) outp += sprintf(outp, "%sCPU", (printed++ ? delim : "")); + if (DO_BIC(BIC_APIC)) + outp += sprintf(outp, "%sAPIC", (printed++ ? delim : "")); + if (DO_BIC(BIC_X2APIC)) + outp += sprintf(outp, "%sX2APIC", (printed++ ? delim : "")); if (DO_BIC(BIC_Avg_MHz)) outp += sprintf(outp, "%sAvg_MHz", (printed++ ? delim : "")); if (DO_BIC(BIC_Busy)) @@ -882,6 +891,10 @@ int format_counters(struct thread_data *t, struct core_data *c, outp += sprintf(outp, "%s-", (printed++ ? delim : "")); if (DO_BIC(BIC_CPU)) outp += sprintf(outp, "%s-", (printed++ ? delim : "")); + if (DO_BIC(BIC_APIC)) + outp += sprintf(outp, "%s-", (printed++ ? delim : "")); + if (DO_BIC(BIC_X2APIC)) + outp += sprintf(outp, "%s-", (printed++ ? delim : "")); } else { if (DO_BIC(BIC_Package)) { if (p) @@ -906,6 +919,10 @@ int format_counters(struct thread_data *t, struct core_data *c, } if (DO_BIC(BIC_CPU)) outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), t->cpu_id); + if (DO_BIC(BIC_APIC)) + outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), t->apic_id); + if (DO_BIC(BIC_X2APIC)) + outp += sprintf(outp, "%s%d", (printed++ ? delim : ""), t->x2apic_id); } if (DO_BIC(BIC_Avg_MHz)) @@ -1233,6 +1250,12 @@ delta_thread(struct thread_data *new, struct thread_data *old, int i; struct msr_counter *mp; + /* we run cpuid just the 1st time, copy the results */ + if (DO_BIC(BIC_APIC)) + new->apic_id = old->apic_id; + if (DO_BIC(BIC_X2APIC)) + new->x2apic_id = old->x2apic_id; + /* * the timestamps from start of measurement interval are in "old" * the timestamp from end of measurement interval are in "new" @@ -1395,6 +1418,12 @@ int sum_counters(struct thread_data *t, struct core_data *c, int i; struct msr_counter *mp; + /* copy un-changing apic_id's */ + if (DO_BIC(BIC_APIC)) + average.threads.apic_id = t->apic_id; + if (DO_BIC(BIC_X2APIC)) + average.threads.x2apic_id = t->x2apic_id; + /* remember first tv_begin */ if (average.threads.tv_begin.tv_sec == 0) average.threads.tv_begin = t->tv_begin; @@ -1621,6 +1650,34 @@ int get_mp(int cpu, struct msr_counter *mp, unsigned long long *counterp) return 0; } +void get_apic_id(struct thread_data *t) +{ + unsigned int eax, ebx, ecx, edx, max_level; + + eax = ebx = ecx = edx = 0; + + if (!genuine_intel) + return; + + __cpuid(0, max_level, ebx, ecx, edx); + + __cpuid(1, eax, ebx, ecx, edx); + t->apic_id = (ebx >> 24) & 0xf; + + if (max_level < 0xb) + return; + + if (!DO_BIC(BIC_X2APIC)) + return; + + ecx = 0; + __cpuid(0xb, eax, ebx, ecx, edx); + t->x2apic_id = edx; + + if (debug && (t->apic_id != t->x2apic_id)) + fprintf(stderr, "cpu%d: apic 0x%x x2apic 0x%x\n", t->cpu_id, t->apic_id, t->x2apic_id); +} + /* * get_counters(...) * migrate to cpu @@ -1634,7 +1691,6 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) struct msr_counter *mp; int i; - gettimeofday(&t->tv_begin, (struct timezone *)NULL); if (cpu_migrate(cpu)) { @@ -1642,6 +1698,8 @@ int get_counters(struct thread_data *t, struct core_data *c, struct pkg_data *p) return -1; } + if (first_counter_read) + get_apic_id(t); retry: t->tsc = rdtsc(); /* we are running on local CPU of interest */ @@ -2881,6 +2939,7 @@ void do_sleep(void) } } + void turbostat_loop() { int retval; @@ -2894,6 +2953,7 @@ restart: snapshot_proc_sysfs_files(); retval = for_all_cpus(get_counters, EVEN_COUNTERS); + first_counter_read = 0; if (retval < -1) { exit(retval); } else if (retval == -1) { @@ -4655,7 +4715,6 @@ void process_cpuid() return; } - /* * in /dev/cpu/ return success for names that are numbers * ie. filter out ".", "..", "microcode". @@ -4949,6 +5008,7 @@ int fork_it(char **argv) snapshot_proc_sysfs_files(); status = for_all_cpus(get_counters, EVEN_COUNTERS); + first_counter_read = 0; if (status) exit(status); /* clear affinity side-effect of get_counters() */ @@ -5384,7 +5444,7 @@ void cmdline(int argc, char **argv) break; case 'e': /* --enable specified counter */ - bic_enabled |= bic_lookup(optarg, SHOW_LIST); + bic_enabled = bic_enabled | bic_lookup(optarg, SHOW_LIST); break; case 'd': debug++; @@ -5468,7 +5528,6 @@ void cmdline(int argc, char **argv) int main(int argc, char **argv) { outf = stderr; - cmdline(argc, argv); if (!quiet) -- cgit From 42dd45209201edb222de5f9eadc1c8f93700ef28 Mon Sep 17 00:00:00 2001 From: Nathan Ciobanu Date: Fri, 8 Jun 2018 15:15:12 -0700 Subject: tools/power turbostat: fix segfault on 'no node' machines Running turbostat on machines that don't expose nodes in sysfs (no /sys/bus/node) causes a segfault or a -nan value diesplayed in the log. This is caused by physical_node_id being reported as -1 and logical_node_id being calculated as a negative number resulting in the new GET_THREAD/GET_CORE returning an incorrect address. Signed-off-by: Nathan Ciobanu Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'tools') diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 3bc2c9d94739..97cc00a9c763 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -2492,6 +2492,12 @@ void set_node_data(void) if (pni[pkg].count > topo.nodes_per_pkg) topo.nodes_per_pkg = pni[0].count; + /* Fake 1 node per pkg for machines that don't + * expose nodes and thus avoid -nan results + */ + if (topo.nodes_per_pkg == 0) + topo.nodes_per_pkg = 1; + for (cpu = 0; cpu < topo.num_cpus; cpu++) { pkg = cpus[cpu].physical_package_id; node = cpus[cpu].physical_node_id; @@ -4904,6 +4910,13 @@ void init_counter(struct thread_data *thread_base, struct core_data *core_base, struct core_data *c; struct pkg_data *p; + + /* Workaround for systems where physical_node_id==-1 + * and logical_node_id==(-1 - topo.num_cpus) + */ + if (node_id < 0) + node_id = 0; + t = GET_THREAD(thread_base, thread_id, core_id, node_id, pkg_id); c = GET_CORE(core_base, core_id, node_id, pkg_id); p = GET_PKG(pkg_base, pkg_id); -- cgit From 2ee19bdea1bbc04a06606b5c9681a07d005ecbaf Mon Sep 17 00:00:00 2001 From: Nathan Ciobanu Date: Wed, 13 Jun 2018 19:51:32 -0700 Subject: tools/power turbostat: alphabetize the help output Sort the command line arguments output of help() in alphabetical order in line with other linux tools. Signed-off-by: Nathan Ciobanu Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 97cc00a9c763..d33b655299ba 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -528,12 +528,12 @@ void help(void) " eg. --add msr0x10,u64,cpu,delta,MY_TSC\n" "--cpu cpu-set limit output to summary plus cpu-set:\n" " {core | package | j,k,l..m,n-p }\n" - "--quiet skip decoding system configuration header\n" "--interval sec.subsec Override default 5-second measurement interval\n" - "--help print this help message\n" "--list list column headers only\n" "--num_iterations num number of the measurement iterations\n" "--out file create or truncate \"file\" for all output\n" + "--quiet skip decoding system configuration header\n" + "--help print this help message\n" "--version print version information\n" "\n" "For more help, run \"man turbostat\"\n"); -- cgit From cc4816503f835c7cea184776fe8ae5bb3f505083 Mon Sep 17 00:00:00 2001 From: Nathan Ciobanu Date: Wed, 13 Jun 2018 19:51:33 -0700 Subject: tools/power turbostat: add single character tokens to help Improve the help() output by adding the single character tokens (e.g -a). Signed-off-by: Nathan Ciobanu Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'tools') diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index d33b655299ba..2dcc05f3ee6f 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -524,17 +524,20 @@ void help(void) "when COMMAND completes.\n" "If no COMMAND is specified, turbostat wakes every 5-seconds\n" "to print statistics, until interrupted.\n" - "--add add a counter\n" - " eg. --add msr0x10,u64,cpu,delta,MY_TSC\n" - "--cpu cpu-set limit output to summary plus cpu-set:\n" - " {core | package | j,k,l..m,n-p }\n" - "--interval sec.subsec Override default 5-second measurement interval\n" - "--list list column headers only\n" - "--num_iterations num number of the measurement iterations\n" - "--out file create or truncate \"file\" for all output\n" - "--quiet skip decoding system configuration header\n" - "--help print this help message\n" - "--version print version information\n" + " -a, --add add a counter\n" + " eg. --add msr0x10,u64,cpu,delta,MY_TSC\n" + " -c, --cpu cpu-set limit output to summary plus cpu-set:\n" + " {core | package | j,k,l..m,n-p }\n" + " -i, --interval sec.subsec\n" + " Override default 5-second measurement interval\n" + " -l, --list list column headers only\n" + " -n, --num_iterations num\n" + " number of the measurement iterations\n" + " -o, --out file\n" + " create or truncate \"file\" for all output\n" + " -q, --quiet skip decoding system configuration header\n" + " -h, --help print this help message\n" + " -v, --version print version information\n" "\n" "For more help, run \"man turbostat\"\n"); } -- cgit From 9ce80578d5f5279545c272563851d059a2359f3e Mon Sep 17 00:00:00 2001 From: Nathan Ciobanu Date: Wed, 13 Jun 2018 19:51:34 -0700 Subject: tools/power turbostat: add the missing command line switches Document the missing command line tokens in the help() function. Signed-off-by: Nathan Ciobanu Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'tools') diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 2dcc05f3ee6f..108c3bf2a67c 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -528,14 +528,28 @@ void help(void) " eg. --add msr0x10,u64,cpu,delta,MY_TSC\n" " -c, --cpu cpu-set limit output to summary plus cpu-set:\n" " {core | package | j,k,l..m,n-p }\n" + " -d, --debug displays usec, Time_Of_Day_Seconds and more debugging\n" + " -D, --Dump displays the raw counter values\n" + " -e, --enable [all | column]\n" + " shows all or the specified disabled column\n" + " -H, --hide [column|column,column,...]\n" + " hide the specified column(s)\n" " -i, --interval sec.subsec\n" " Override default 5-second measurement interval\n" + " -J, --Joules displays energy in Joules instead of Watts\n" " -l, --list list column headers only\n" " -n, --num_iterations num\n" " number of the measurement iterations\n" " -o, --out file\n" " create or truncate \"file\" for all output\n" " -q, --quiet skip decoding system configuration header\n" + " -s, --show [column|column,column,...]\n" + " show only the specified column(s)\n" + " -S, --Summary\n" + " limits output to 1-line system summary per interval\n" + " -T, --TCC temperature\n" + " sets the Thermal Control Circuit temperature in\n" + " degrees Celsius\n" " -h, --help print this help message\n" " -v, --version print version information\n" "\n" -- cgit From 73780cd816e071b0fc0f74e204a9cb30fdb291c5 Mon Sep 17 00:00:00 2001 From: Len Brown Date: Wed, 20 Jun 2018 13:55:29 -0400 Subject: tools/power turbostat: version 18.06.20 Signed-off-by: Len Brown --- tools/power/x86/turbostat/turbostat.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/power/x86/turbostat/turbostat.c b/tools/power/x86/turbostat/turbostat.c index 108c3bf2a67c..4d14bbbf9b63 100644 --- a/tools/power/x86/turbostat/turbostat.c +++ b/tools/power/x86/turbostat/turbostat.c @@ -5102,7 +5102,7 @@ int get_and_dump_counters(void) } void print_version() { - fprintf(outf, "turbostat version 18.06.01" + fprintf(outf, "turbostat version 18.06.20" " - Len Brown \n"); } -- cgit From 73f9c33beb9e85850a11a1597b35a13650352509 Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Tue, 19 Jun 2018 18:41:11 +0200 Subject: selftests: net: add config fragments Add fragments to pass bridge and vlan tests. Fixes: 33b01b7b4f19 ("selftests: add rtnetlink test script") Signed-off-by: Anders Roxell Signed-off-by: David S. Miller --- tools/testing/selftests/net/config | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools') diff --git a/tools/testing/selftests/net/config b/tools/testing/selftests/net/config index 7ba089b33e8b..cd3a2f1545b5 100644 --- a/tools/testing/selftests/net/config +++ b/tools/testing/selftests/net/config @@ -12,3 +12,5 @@ CONFIG_NET_IPVTI=y CONFIG_INET6_XFRM_MODE_TUNNEL=y CONFIG_IPV6_VTI=y CONFIG_DUMMY=y +CONFIG_BRIDGE=y +CONFIG_VLAN_8021Q=y -- cgit From 3739a21e0ef6ac06f46bd38e81daa95e8cb462bc Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Thu, 21 Jun 2018 00:43:44 +0200 Subject: selftests: net: add tcp_inq to gitignore sha: 702353b538f5 ("selftest: add test for TCP_INQ") forgot to add tcp_inq to .gitignore. Signed-off-by: Anders Roxell Signed-off-by: David S. Miller --- tools/testing/selftests/net/.gitignore | 1 + 1 file changed, 1 insertion(+) (limited to 'tools') diff --git a/tools/testing/selftests/net/.gitignore b/tools/testing/selftests/net/.gitignore index 128e548aa377..1a0ac3a29ec5 100644 --- a/tools/testing/selftests/net/.gitignore +++ b/tools/testing/selftests/net/.gitignore @@ -12,3 +12,4 @@ tcp_mmap udpgso udpgso_bench_rx udpgso_bench_tx +tcp_inq -- cgit From e7c9996bb3dedb5553e6b34e6dbbed210a72f3e1 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Tue, 19 Jun 2018 09:32:28 -0400 Subject: rseq/selftests: Make run_param_test.sh executable The executable bit of the run_param_test.sh script got lost in the merge. Signed-off-by: Mathieu Desnoyers Cc: Andrew Hunter Cc: Andrew Morton Cc: Andy Lutomirski Cc: Ben Maurer Cc: Boqun Feng Cc: Catalin Marinas Cc: Chris Lameter Cc: Dave Watson Cc: Joel Fernandes Cc: Josh Triplett Cc: Linus Torvalds Cc: Michael Kerrisk Cc: Paul E . McKenney Cc: Paul Turner Cc: Peter Zijlstra Cc: Russell King Cc: Shuah Khan Cc: Steven Rostedt Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-api@vger.kernel.org Cc: linux-kselftest@vger.kernel.org Link: https://lore.kernel.org/lkml/20180619133230.4087-2-mathieu.desnoyers@efficios.com Signed-off-by: Ingo Molnar --- tools/testing/selftests/rseq/run_param_test.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 tools/testing/selftests/rseq/run_param_test.sh (limited to 'tools') diff --git a/tools/testing/selftests/rseq/run_param_test.sh b/tools/testing/selftests/rseq/run_param_test.sh old mode 100644 new mode 100755 -- cgit From 0ea73d5e286193be4dec70d04021d6005b5b1771 Mon Sep 17 00:00:00 2001 From: Mathieu Desnoyers Date: Tue, 19 Jun 2018 09:32:29 -0400 Subject: rseq/selftests/arm: Align 'struct rseq_cs' on 32 bytes uapi/linux/rseq.h aligns 'struct rseq_cs' on 32 bytes. Satisfy this alignment requirement in its definition within the rseq-arm.h inline assembly as well. Signed-off-by: Mathieu Desnoyers Cc: Andrew Hunter Cc: Andrew Morton Cc: Andy Lutomirski Cc: Ben Maurer Cc: Boqun Feng Cc: Catalin Marinas Cc: Chris Lameter Cc: Dave Watson Cc: Joel Fernandes Cc: Josh Triplett Cc: Linus Torvalds Cc: Michael Kerrisk Cc: Paul E . McKenney Cc: Paul Turner Cc: Peter Zijlstra Cc: Russell King Cc: Shuah Khan Cc: Steven Rostedt Cc: Thomas Gleixner Cc: Will Deacon Cc: linux-api@vger.kernel.org Cc: linux-kselftest@vger.kernel.org Link: https://lore.kernel.org/lkml/20180619133230.4087-3-mathieu.desnoyers@efficios.com Signed-off-by: Ingo Molnar --- tools/testing/selftests/rseq/rseq-arm.h | 1 + 1 file changed, 1 insertion(+) (limited to 'tools') diff --git a/tools/testing/selftests/rseq/rseq-arm.h b/tools/testing/selftests/rseq/rseq-arm.h index 3b055f9aeaab..3cea19877227 100644 --- a/tools/testing/selftests/rseq/rseq-arm.h +++ b/tools/testing/selftests/rseq/rseq-arm.h @@ -57,6 +57,7 @@ do { \ #define __RSEQ_ASM_DEFINE_ABORT(table_label, label, teardown, \ abort_label, version, flags, \ start_ip, post_commit_offset, abort_ip) \ + ".balign 32\n\t" \ __rseq_str(table_label) ":\n\t" \ ".word " __rseq_str(version) ", " __rseq_str(flags) "\n\t" \ ".word " __rseq_str(start_ip) ", 0x0, " __rseq_str(post_commit_offset) ", 0x0, " __rseq_str(abort_ip) ", 0x0\n\t" \ -- cgit From 957f9a13df6c70aac31a1dade5e417c286d6d258 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 20 Jun 2018 11:42:45 -0700 Subject: tools: bpftool: remove duplicated error message on prog load do_pin_fd() will already print out an error message if something goes wrong. Printing another error is unnecessary and will break JSON output, since error messages are full objects: $ bpftool -jp prog load tracex1_kern.o /sys/fs/bpf/a { "error": "can't pin the object (/sys/fs/bpf/a): File exists" },{ "error": "failed to pin program" } Fixes: 49a086c201a9 ("bpftool: implement prog load command") Signed-off-by: Jakub Kicinski Reviewed-by: Quentin Monnet Acked-by: Song Liu Signed-off-by: Daniel Borkmann --- tools/bpf/bpftool/prog.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index 05f42a46d6ed..12b694fe0404 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -694,10 +694,8 @@ static int do_load(int argc, char **argv) return -1; } - if (do_pin_fd(prog_fd, argv[1])) { - p_err("failed to pin program"); + if (do_pin_fd(prog_fd, argv[1])) return -1; - } if (json_output) jsonw_null(json_wtr); -- cgit From bfee71fb7376081349117fdc89f685a9e14a58c2 Mon Sep 17 00:00:00 2001 From: Jakub Kicinski Date: Wed, 20 Jun 2018 11:42:46 -0700 Subject: tools: bpftool: remember to close the libbpf object after prog load Remembering to close all descriptors and free memory may not seem important in a user space tool like bpftool, but if we were to run in batch mode the consumed resources start to add up quickly. Make sure program load closes the libbpf object (which unloads and frees it). Fixes: 49a086c201a9 ("bpftool: implement prog load command") Signed-off-by: Jakub Kicinski Reviewed-by: Quentin Monnet Acked-by: Song Liu Signed-off-by: Daniel Borkmann --- tools/bpf/bpftool/prog.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/bpf/bpftool/prog.c b/tools/bpf/bpftool/prog.c index 12b694fe0404..959aa53ab678 100644 --- a/tools/bpf/bpftool/prog.c +++ b/tools/bpf/bpftool/prog.c @@ -695,12 +695,18 @@ static int do_load(int argc, char **argv) } if (do_pin_fd(prog_fd, argv[1])) - return -1; + goto err_close_obj; if (json_output) jsonw_null(json_wtr); + bpf_object__close(obj); + return 0; + +err_close_obj: + bpf_object__close(obj); + return -1; } static int do_help(int argc, char **argv) -- cgit From 81e167c2a216e7b54e6add9d2badcda267fe33b1 Mon Sep 17 00:00:00 2001 From: Jeffrin Jose T Date: Thu, 21 Jun 2018 22:30:20 +0530 Subject: selftests: bpf: notification about privilege required to run test_kmod.sh testing script The test_kmod.sh script require root privilege for the successful execution of the test. This patch is to notify the user about the privilege the script demands for the successful execution of the test. Signed-off-by: Jeffrin Jose T (Rajagiri SET) Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_kmod.sh | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'tools') diff --git a/tools/testing/selftests/bpf/test_kmod.sh b/tools/testing/selftests/bpf/test_kmod.sh index 35669ccd4d23..9df0d2ac45f8 100755 --- a/tools/testing/selftests/bpf/test_kmod.sh +++ b/tools/testing/selftests/bpf/test_kmod.sh @@ -1,6 +1,15 @@ #!/bin/sh # SPDX-License-Identifier: GPL-2.0 +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=4 + +msg="skip all tests:" +if [ "$(id -u)" != "0" ]; then + echo $msg please run this as root >&2 + exit $ksft_skip +fi + SRC_TREE=../../../../ test_run() -- cgit From 3e1a61b30c6a3a31314570c0c418a6bf84b056b1 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Thu, 21 Jun 2018 10:02:20 -0700 Subject: tools/bpf: fix test_sockmap failure On one of our production test machine, when running bpf selftest test_sockmap, I got the following error: # sudo ./test_sockmap libbpf: failed to create map (name: 'sock_map'): Operation not permitted libbpf: failed to load object 'test_sockmap_kern.o' libbpf: Can't get the 0th fd from program sk_skb1: only -1 instances ...... load_bpf_file: (-1) Operation not permitted ERROR: (-1) load bpf failed The error is due to not-big-enough rlimit struct rlimit r = {10 * 1024 * 1024, RLIM_INFINITY}; The test already includes "bpf_rlimit.h", which sets current and max rlimit to RLIM_INFINITY. Let us just use it. Signed-off-by: Yonghong Song Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_sockmap.c | 6 ------ 1 file changed, 6 deletions(-) (limited to 'tools') diff --git a/tools/testing/selftests/bpf/test_sockmap.c b/tools/testing/selftests/bpf/test_sockmap.c index 05c8cb71724a..9e78df207919 100644 --- a/tools/testing/selftests/bpf/test_sockmap.c +++ b/tools/testing/selftests/bpf/test_sockmap.c @@ -1413,18 +1413,12 @@ out: int main(int argc, char **argv) { - struct rlimit r = {10 * 1024 * 1024, RLIM_INFINITY}; int iov_count = 1, length = 1024, rate = 1; struct sockmap_options options = {0}; int opt, longindex, err, cg_fd = 0; char *bpf_file = BPF_SOCKMAP_FILENAME; int test = PING_PONG; - if (setrlimit(RLIMIT_MEMLOCK, &r)) { - perror("setrlimit(RLIMIT_MEMLOCK)"); - return 1; - } - if (argc < 2) return test_suite(); -- cgit From 01766229533f9bdb1144a41b4345c8c7286da7b4 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Mon, 11 Jun 2018 09:31:52 +0200 Subject: perf record: Support s390 random socket_id assignment On s390 the socket identifier assigned to a CPU identifier is random and (depending on the configuration of the LPAR) may be higher than the CPU identifier. This is currently not supported. Fix this by allowing arbitrary socket identifiers being assigned to CPU id. Output before: [root@p23lp27 perf]# ./perf report --header -I -v ... socket_id number is too big.You may need to upgrade the perf tool. Error: The perf.data file has no samples! # ======== # captured on : Tue May 29 09:29:57 2018 # header version : 1 ... # Core ID and Socket ID information is not available ... [root@p23lp27 perf]# Output after: [root@p23lp27 perf]# ./perf report --header -I -v ... Error: The perf.data file has no samples! # ======== # captured on : Tue May 29 09:29:57 2018 # header version : 1 ... # CPU 0: Core ID 0, Socket ID 6 # CPU 1: Core ID 1, Socket ID 3 # CPU 2: Core ID -1, Socket ID -1 ... [root@p23lp27 perf]# Signed-off-by: Thomas Richter Reviewed-by: Hendrik Brueckner Cc: Heiko Carstens Cc: Martin Schwidefsky Link: http://lkml.kernel.org/r/20180611073153.15592-1-tmricht@linux.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/header.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 540cd2dcd3e7..59fcc790c865 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -2129,6 +2129,7 @@ static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused) int cpu_nr = ff->ph->env.nr_cpus_avail; u64 size = 0; struct perf_header *ph = ff->ph; + bool do_core_id_test = true; ph->env.cpu = calloc(cpu_nr, sizeof(*ph->env.cpu)); if (!ph->env.cpu) @@ -2183,6 +2184,13 @@ static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused) return 0; } + /* On s390 the socket_id number is not related to the numbers of cpus. + * The socket_id number might be higher than the numbers of cpus. + * This depends on the configuration. + */ + if (ph->env.arch && !strncmp(ph->env.arch, "s390", 4)) + do_core_id_test = false; + for (i = 0; i < (u32)cpu_nr; i++) { if (do_read_u32(ff, &nr)) goto free_cpu; @@ -2192,7 +2200,7 @@ static int process_cpu_topology(struct feat_fd *ff, void *data __maybe_unused) if (do_read_u32(ff, &nr)) goto free_cpu; - if (nr != (u32)-1 && nr > (u32)cpu_nr) { + if (do_core_id_test && nr != (u32)-1 && nr > (u32)cpu_nr) { pr_debug("socket_id number is too big." "You may need to upgrade the perf tool.\n"); goto free_cpu; -- cgit From b930e62ecd362843002bdf84c2940439822af321 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Mon, 11 Jun 2018 09:31:53 +0200 Subject: perf test session topology: Fix test on s390 On s390 this test case fails because the socket identifiction numbers assigned to the CPU are higher than the CPU identification numbers. F/ix this by adding the platform architecture into the perf data header flag information. This helps identifiing the test platform and handles s390 specifics in process_cpu_topology(). Before: [root@p23lp27 perf]# perf test -vvvvv -F 39 39: Session topology : --- start --- templ file: /tmp/perf-test-iUv755 socket_id number is too big.You may need to upgrade the perf tool. ---- end ---- Session topology: Skip [root@p23lp27 perf]# After: [root@p23lp27 perf]# perf test -vvvvv -F 39 39: Session topology : --- start --- templ file: /tmp/perf-test-8X8VTs CPU 0, core 0, socket 6 CPU 1, core 1, socket 3 ---- end ---- Session topology: Ok [root@p23lp27 perf]# Signed-off-by: Thomas Richter Reviewed-by: Hendrik Brueckner Cc: Heiko Carstens Cc: Martin Schwidefsky Fixes: c84974ed9fb6 ("perf test: Add entry to test cpu topology") Link: http://lkml.kernel.org/r/20180611073153.15592-2-tmricht@linux.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/topology.c | 1 + 1 file changed, 1 insertion(+) (limited to 'tools') diff --git a/tools/perf/tests/topology.c b/tools/perf/tests/topology.c index 40e30a26b23c..9497d02f69e6 100644 --- a/tools/perf/tests/topology.c +++ b/tools/perf/tests/topology.c @@ -45,6 +45,7 @@ static int session_write_header(char *path) perf_header__set_feat(&session->header, HEADER_CPU_TOPOLOGY); perf_header__set_feat(&session->header, HEADER_NRCPUS); + perf_header__set_feat(&session->header, HEADER_ARCH); session->header.data_size += DATA_SIZE; -- cgit From 143c99f6ac6812d23254e80844d6e34be897d3e1 Mon Sep 17 00:00:00 2001 From: Sandipan Das Date: Mon, 11 Jun 2018 16:10:49 +0530 Subject: perf report powerpc: Fix crash if callchain is empty For some cases, the callchain provided by the kernel may be empty. So, the callchain ip filtering code will cause a crash if we do not check whether the struct ip_callchain pointer is NULL before accessing any members. This can be observed on a powerpc64le system running Fedora 27 as shown below. # perf record -b -e cycles:u ls Before: # perf report --branch-history perf: Segmentation fault -------- backtrace -------- perf[0x1027615c] linux-vdso64.so.1(__kernel_sigtramp_rt64+0x0)[0x7fff856304d8] perf(arch_skip_callchain_idx+0x44)[0x10257c58] perf[0x1017f2e4] perf(thread__resolve_callchain+0x124)[0x1017ff5c] perf(sample__resolve_callchain+0xf0)[0x10172788] ... After: # perf report --branch-history Samples: 25 of event 'cycles:u', Event count (approx.): 2306870 Overhead Source:Line Symbol Shared Object + 11.60% _init+35736 [.] _init ls + 9.84% strcoll_l.c:137 [.] __strcoll_l libc-2.26.so + 9.16% memcpy.S:175 [.] __memcpy_power7 libc-2.26.so + 9.01% gconv_charset.h:54 [.] _nl_find_locale libc-2.26.so + 8.87% dl-addr.c:52 [.] _dl_addr libc-2.26.so + 8.83% _init+236 [.] _init ls ... Reported-by: Ravi Bangoria Signed-off-by: Sandipan Das Acked-by: Ravi Bangoria Cc: Jiri Olsa Cc: Naveen N. Rao Cc: Sukadev Bhattiprolu Link: http://lkml.kernel.org/r/20180611104049.11048-1-sandipan@linux.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/powerpc/util/skip-callchain-idx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/arch/powerpc/util/skip-callchain-idx.c b/tools/perf/arch/powerpc/util/skip-callchain-idx.c index 3598b8b75d27..ef5d59a5742e 100644 --- a/tools/perf/arch/powerpc/util/skip-callchain-idx.c +++ b/tools/perf/arch/powerpc/util/skip-callchain-idx.c @@ -243,7 +243,7 @@ int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain) u64 ip; u64 skip_slot = -1; - if (chain->nr < 3) + if (!chain || chain->nr < 3) return skip_slot; ip = chain->ips[2]; -- cgit From 933ccf2002aaef1037cb676622a694f5390c3d59 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 11 Jun 2018 11:34:21 +0200 Subject: perf tests: Add event parsing error handling to parse events test Add missing error handling for parse_events calls in test_event function that led to following segfault on s390: running test 52 'intel_pt//u' perf: Segmentation fault ... /lib64/libc.so.6(vasprintf+0xe6) [0x3fffca3f106] /lib64/libc.so.6(asprintf+0x46) [0x3fffca1aa96] ./perf(parse_events_add_pmu+0xb8) [0x80132088] ./perf(parse_events_parse+0xc62) [0x8019529a] ./perf(parse_events+0x98) [0x801341c0] ./perf(test__parse_events+0x48) [0x800cd140] ./perf(cmd_test+0x26a) [0x800bd44a] test child interrupted Adding the struct parse_events_error argument to parse_events call. Also adding parse_events_print_error to get more details on the parsing failures, like: # perf test 6 -v running test 52 'intel_pt//u'failed to parse event 'intel_pt//u', err 1, str 'Cannot find PMU `intel_pt'. Missing kernel support?' event syntax error: 'intel_pt//u' \___ Cannot find PMU `intel_pt'. Missing kernel support? Committer note: Use named initializers in the struct parse_events_error variable to avoid breaking the build on centos5, 6 and others with a similar gcc: cc1: warnings being treated as errors tests/parse-events.c: In function 'test_event': tests/parse-events.c:1696: error: missing initializer tests/parse-events.c:1696: error: (near initialization for 'err.str') Reported-by: Kim Phillips Signed-off-by: Jiri Olsa Tested-by: Kim Phillips Cc: Alexander Shishkin Cc: David Ahern Cc: Heiko Carstens Cc: Hendrik Brueckner Cc: Martin Schwidefsky Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Richter Link: http://lkml.kernel.org/r/20180611093422.1005-1-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/parse-events.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'tools') diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 7d4077068454..9751e7563a45 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -1686,6 +1686,7 @@ static struct terms_test test__terms[] = { static int test_event(struct evlist_test *e) { + struct parse_events_error err = { .idx = 0, }; struct perf_evlist *evlist; int ret; @@ -1693,10 +1694,11 @@ static int test_event(struct evlist_test *e) if (evlist == NULL) return -ENOMEM; - ret = parse_events(evlist, e->name, NULL); + ret = parse_events(evlist, e->name, &err); if (ret) { - pr_debug("failed to parse event '%s', err %d\n", - e->name, ret); + pr_debug("failed to parse event '%s', err %d, str '%s'\n", + e->name, ret, err.str); + parse_events_print_error(&err, e->name); } else { ret = e->check(evlist); } -- cgit From 16ddcfbf7f3d07aa781e26b39f2c28636a4ed2fd Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Mon, 11 Jun 2018 11:34:22 +0200 Subject: perf tests: Add valid callback for parse-events test Adding optional 'valid' callback for events tests in parse-events object, so we don't try to parse PMUs, which are not supported. Following line is displayed for skipped test: running test 52 'intel_pt//u'... SKIP Committer note: Use named initializers in the struct evlist_test variable to avoid breaking the build on centos:5, 6 and others with a similar gcc: cc1: warnings being treated as errors tests/parse-events.c: In function 'test_pmu_events': tests/parse-events.c:1817: error: missing initializer tests/parse-events.c:1817: error: (near initialization for 'e.type') Signed-off-by: Jiri Olsa Cc: Alexander Shishkin Cc: David Ahern Cc: Heiko Carstens Cc: Hendrik Brueckner Cc: Kim Phillips Cc: Martin Schwidefsky Cc: Namhyung Kim Cc: Peter Zijlstra Cc: Thomas Richter Link: http://lkml.kernel.org/r/20180611093422.1005-2-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/tests/parse-events.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/perf/tests/parse-events.c b/tools/perf/tests/parse-events.c index 9751e7563a45..61211918bfba 100644 --- a/tools/perf/tests/parse-events.c +++ b/tools/perf/tests/parse-events.c @@ -1309,6 +1309,11 @@ static int test__checkevent_config_cache(struct perf_evlist *evlist) return 0; } +static bool test__intel_pt_valid(void) +{ + return !!perf_pmu__find("intel_pt"); +} + static int test__intel_pt(struct perf_evlist *evlist) { struct perf_evsel *evsel = perf_evlist__first(evlist); @@ -1375,6 +1380,7 @@ struct evlist_test { const char *name; __u32 type; const int id; + bool (*valid)(void); int (*check)(struct perf_evlist *evlist); }; @@ -1648,6 +1654,7 @@ static struct evlist_test test__events[] = { }, { .name = "intel_pt//u", + .valid = test__intel_pt_valid, .check = test__intel_pt, .id = 52, }, @@ -1690,6 +1697,11 @@ static int test_event(struct evlist_test *e) struct perf_evlist *evlist; int ret; + if (e->valid && !e->valid()) { + pr_debug("... SKIP"); + return 0; + } + evlist = perf_evlist__new(); if (evlist == NULL) return -ENOMEM; @@ -1716,10 +1728,11 @@ static int test_events(struct evlist_test *events, unsigned cnt) for (i = 0; i < cnt; i++) { struct evlist_test *e = &events[i]; - pr_debug("running test %d '%s'\n", e->id, e->name); + pr_debug("running test %d '%s'", e->id, e->name); ret1 = test_event(e); if (ret1) ret2 = ret1; + pr_debug("\n"); } return ret2; @@ -1801,7 +1814,7 @@ static int test_pmu_events(void) } while (!ret && (ent = readdir(dir))) { - struct evlist_test e; + struct evlist_test e = { .id = 0, }; char name[2 * NAME_MAX + 1 + 12 + 3]; /* Names containing . are special and cannot be used directly */ -- cgit From 621a5a327c1e36ffd7bb567f44a559f64f76358f Mon Sep 17 00:00:00 2001 From: Adrian Hunter Date: Thu, 7 Jun 2018 14:30:02 +0300 Subject: perf intel-pt: Fix packet decoding of CYC packets Use a 64-bit type so that the cycle count is not limited to 32-bits. Signed-off-by: Adrian Hunter Cc: Jiri Olsa Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1528371002-8862-1-git-send-email-adrian.hunter@intel.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c index ba4c9dd18643..d426761a549d 100644 --- a/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c +++ b/tools/perf/util/intel-pt-decoder/intel-pt-pkt-decoder.c @@ -366,7 +366,7 @@ static int intel_pt_get_cyc(unsigned int byte, const unsigned char *buf, if (len < offs) return INTEL_PT_NEED_MORE_BYTES; byte = buf[offs++]; - payload |= (byte >> 1) << shift; + payload |= ((uint64_t)byte >> 1) << shift; } packet->type = INTEL_PT_CYC; -- cgit From 7b818dc57230bf050bbc4218cd4df8ec59b9945d Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 15 Jun 2018 11:33:35 -0300 Subject: tools headers uapi: Synchronize drm/drm.h To pick up the new ioctls added in these csets: 7595bda2fb43 ("drm: Add DRM client cap for aspect-ratio") The DRM caps are not yet being decoded in 'perf trace', so this sync doesn't incur in any change in behaviour in any tools, just silencing this tools/perf/ build warning: Warning: Kernel ABI header at 'tools/include/uapi/drm/drm.h' differs from latest version at 'include/uapi/drm/drm.h' Cc: Adrian Hunter Cc: Ankit Nautiyal Cc: David Ahern Cc: Jiri Olsa Cc: Maarten Lankhorst Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-atwz0arwanq1npu8pptwkoxt@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/drm/drm.h | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'tools') diff --git a/tools/include/uapi/drm/drm.h b/tools/include/uapi/drm/drm.h index 6fdff5945c8a..9c660e1688ab 100644 --- a/tools/include/uapi/drm/drm.h +++ b/tools/include/uapi/drm/drm.h @@ -680,6 +680,13 @@ struct drm_get_cap { */ #define DRM_CLIENT_CAP_ATOMIC 3 +/** + * DRM_CLIENT_CAP_ASPECT_RATIO + * + * If set to 1, the DRM core will provide aspect ratio information in modes. + */ +#define DRM_CLIENT_CAP_ASPECT_RATIO 4 + /** DRM_IOCTL_SET_CLIENT_CAP ioctl argument type */ struct drm_set_client_cap { __u64 capability; -- cgit From b1494ec029af6d6ea189cbc96ad66463f8df3579 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 15 Jun 2018 11:48:43 -0300 Subject: perf tools: Update x86's syscall_64.tbl, adding 'io_pgetevents' and 'rseq' This updates the tools/perf/ copy of the system call table for x86 which makes 'perf trace' become aware of the new 'io_pgetevents' and 'rseq' syscalls, no matter in which system it gets built, i.e. older systems where the syscalls are not available in the running kernel (via tracefs) or in the system headers will still be aware of these syscalls/. These are the csets introducing the source drift: 05c17cedf85b ("x86: Wire up restartable sequence system call") 7a074e96dee6 ("aio: implement io_pgetevents") This results in this build time change: $ diff -u /tmp/build/perf/arch/x86/include/generated/asm/syscalls_64.c.old /tmp/build/perf/arch/x86/include/generated/asm/syscalls_64.c --- /tmp/build/perf/arch/x86/include/generated/asm/syscalls_64.c.old 2018-06-15 11:48:17.648948094 -0300 +++ /tmp/build/perf/arch/x86/include/generated/asm/syscalls_64.c 2018-06-15 11:48:22.133942480 -0300 @@ -332,5 +332,7 @@ [330] = "pkey_alloc", [331] = "pkey_free", [332] = "statx", + [333] = "io_pgetevents", + [334] = "rseq", }; -#define SYSCALLTBL_x86_64_MAX_ID 332 +#define SYSCALLTBL_x86_64_MAX_ID 334 $ This silences the following tools/perf/ build warning: Warning: Kernel ABI header at 'tools/perf/arch/x86/entry/syscalls/syscall_64.tbl' differs from latest version at 'arch/x86/entry/syscalls/syscall_64.tbl' Cc: Adrian Hunter Cc: Christoph Hellwig Cc: David Ahern Cc: Jiri Olsa Cc: Mathieu Desnoyers Cc: Namhyung Kim Cc: Thomas Gleixner Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-tfvyz51sabuzemrszbrhzxni@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/arch/x86/entry/syscalls/syscall_64.tbl | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools') diff --git a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl index 4dfe42666d0c..f0b1709a5ffb 100644 --- a/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl +++ b/tools/perf/arch/x86/entry/syscalls/syscall_64.tbl @@ -341,6 +341,8 @@ 330 common pkey_alloc __x64_sys_pkey_alloc 331 common pkey_free __x64_sys_pkey_free 332 common statx __x64_sys_statx +333 common io_pgetevents __x64_sys_io_pgetevents +334 common rseq __x64_sys_rseq # # x32-specific system call numbers start at 512 to avoid cache impact -- cgit From 801f5e1ac783df9fafff8899ef2d5511bd4dbdcb Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 15 Jun 2018 12:04:32 -0300 Subject: tools include powerpc: Update arch/powerpc/include/uapi/asm/unistd.h copy to get 'rseq' syscall This updates the tools/perf/ copy of the powerpc file used to generate the syscall table file used to make 'perf trace' become aware of the new 'rseq' syscall, no matter in which system it gets built, i.e. older systems where the syscalls are not available in the running kernel (via tracefs) or in the system headers will still be aware of these syscalls/. From this commit: bb862b021d75 ("powerpc: Wire up restartable sequences system call") Silencing this tools/perf build warning: Warning: Kernel ABI header at 'tools/arch/powerpc/include/uapi/asm/unistd.h' differs from latest version at 'arch/powerpc/include/uapi/asm/unistd.h' Cc: Adrian Hunter Cc: Alexander Shishkin Cc: Boqun Feng Cc: David Ahern Cc: Hendrik Brueckner Cc: Jiri Olsa Cc: Mathieu Desnoyers Cc: Michael Ellerman Cc: Namhyung Kim Cc: Ravi Bangoria Cc: Thomas Gleixner Cc: Thomas Richter Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-adtgz6u3apd76tghiu9w0k19@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/arch/powerpc/include/uapi/asm/unistd.h | 1 + 1 file changed, 1 insertion(+) (limited to 'tools') diff --git a/tools/arch/powerpc/include/uapi/asm/unistd.h b/tools/arch/powerpc/include/uapi/asm/unistd.h index 389c36fd8299..ac5ba55066dd 100644 --- a/tools/arch/powerpc/include/uapi/asm/unistd.h +++ b/tools/arch/powerpc/include/uapi/asm/unistd.h @@ -398,5 +398,6 @@ #define __NR_pkey_alloc 384 #define __NR_pkey_free 385 #define __NR_pkey_mprotect 386 +#define __NR_rseq 387 #endif /* _UAPI_ASM_POWERPC_UNISTD_H_ */ -- cgit From bb9a33cb8a807e5ae9906563f5c1533904651b8b Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 15 Jun 2018 16:46:57 -0300 Subject: tools include uapi: Update if_link.h to pick IFLA_{BRPORT_ISOLATED,VXLAN_TTL_INHERIT} The IFLA_BRPORT_ISOLATED and IFLA_VXLAN_TTL_INHERIT defines were added in: 7d850abd5f4e ("net: bridge: add support for port isolation") 72f6d71e491e ("vxlan: add ttl inherit support") Pick them, silencing this build warning: Warning: Kernel ABI header at 'tools/include/uapi/linux/if_link.h' differs from latest version at 'include/uapi/linux/if_link.h' Cc: Alexei Starovoitov Cc: David S. Miller Cc: Eric Leblond Cc: Hangbin Liu Cc: Nikolay Aleksandrov Link: https://lkml.kernel.org/n/tip-ezi5u0mmdqm0wfm0y2y8176r@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/linux/if_link.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'tools') diff --git a/tools/include/uapi/linux/if_link.h b/tools/include/uapi/linux/if_link.h index 68699f654118..cf01b6824244 100644 --- a/tools/include/uapi/linux/if_link.h +++ b/tools/include/uapi/linux/if_link.h @@ -333,6 +333,7 @@ enum { IFLA_BRPORT_BCAST_FLOOD, IFLA_BRPORT_GROUP_FWD_MASK, IFLA_BRPORT_NEIGH_SUPPRESS, + IFLA_BRPORT_ISOLATED, __IFLA_BRPORT_MAX }; #define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1) @@ -516,6 +517,7 @@ enum { IFLA_VXLAN_COLLECT_METADATA, IFLA_VXLAN_LABEL, IFLA_VXLAN_GPE, + IFLA_VXLAN_TTL_INHERIT, __IFLA_VXLAN_MAX }; #define IFLA_VXLAN_MAX (__IFLA_VXLAN_MAX - 1) -- cgit From f568b472815fd6c34fe4cc30dde4572ee300d6c4 Mon Sep 17 00:00:00 2001 From: Arnaldo Carvalho de Melo Date: Fri, 15 Jun 2018 16:55:32 -0300 Subject: tools include uapi: Synchronize bpf.h with the kernel To pick the rename in: bd3a08aaa9a3 ("bpf: flowlabel in bpf_fib_lookup should be flowinfo") Silencing this build warning: Warning: Kernel ABI header at 'tools/include/uapi/linux/bpf.h' differs from latest version at 'include/uapi/linux/bpf.h' Cc: Adrian Hunter Cc: Alexei Starovoitov Cc: David Ahern Cc: Jiri Olsa Cc: Namhyung Kim Cc: Wang Nan Link: https://lkml.kernel.org/n/tip-zd1sgtbybtjrrt7bqdybu0s0@git.kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/include/uapi/linux/bpf.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/include/uapi/linux/bpf.h b/tools/include/uapi/linux/bpf.h index e0b06784f227..59b19b6a40d7 100644 --- a/tools/include/uapi/linux/bpf.h +++ b/tools/include/uapi/linux/bpf.h @@ -2630,7 +2630,7 @@ struct bpf_fib_lookup { union { /* inputs to lookup */ __u8 tos; /* AF_INET */ - __be32 flowlabel; /* AF_INET6 */ + __be32 flowinfo; /* AF_INET6, flow_label + priority */ /* output: metric of fib result (IPv4/IPv6 only) */ __u32 rt_metric; -- cgit From c6555c14572aeadf4fe2819abd971c4e7608b926 Mon Sep 17 00:00:00 2001 From: Yonghong Song Date: Sat, 16 Jun 2018 10:47:39 -0700 Subject: perf tools: Fix a clang 7.0 compilation error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Arnaldo reported the perf build failure with latest llvm/clang compiler (7.0). $ make LIBCLANGLLVM=1 -C tools/perf/ CC /tmp/tmp.t53Qo38zci/tests/kmod-path.o util/c++/clang.cpp: In function ‘std::unique_ptr > perf::getBPFObjectFromModule(llvm::Module*)’: util/c++/clang.cpp:150:43: error: no matching function for call to ‘llvm::TargetMachine::addPassesToEmitFile(llvm::legacy::PassManager&, llvm::raw_svector_ostream&, llvm::TargetMachine::CodeGenFileType)’ TargetMachine::CGFT_ObjectFile)) { ^ In file included from util/c++/clang.cpp:25:0: /usr/local/include/llvm/Target/TargetMachine.h:254:16: note: candidate: virtual bool llvm::TargetMachine::addPassesToEmitFile( llvm::legacy::PassManagerBase&, llvm::raw_pwrite_stream&, llvm::raw_pwrite_stream*, llvm::TargetMachine::CodeGenFileType, bool, llvm::MachineModuleInfo*) virtual bool addPassesToEmitFile(PassManagerBase &, raw_pwrite_stream &, ^~~~~~~~~~~~~~~~~~~ /usr/local/include/llvm/Target/TargetMachine.h:254:16: note: candidate expects 6 arguments, 3 provided mv: cannot stat '/tmp/tmp.t53Qo38zci/util/c++/.clang.o.tmp': No such file or directory make[7]: *** [/home/acme/git/perf/tools/build/Makefile.build:101: /tmp/tmp.t53Qo38zci/util/c++/clang.o] Error 1 make[6]: *** [/home/acme/git/perf/tools/build/Makefile.build:139: c++] Error 2 make[5]: *** [/home/acme/git/perf/tools/build/Makefile.build:139: util] Error 2 make[5]: *** Waiting for unfinished jobs.... CC /tmp/tmp.t53Qo38zci/tests/thread-map.o The function addPassesToEmitFile signature changed in llvm 7.0 and such a change caused the failure. This patch fixed the issue with using proper function signatures under different compiler versions. Reported-by: Arnaldo Carvalho de Melo Signed-off-by: Yonghong Song Tested-by: Arnaldo Carvalho de Melo Cc: Alexei Starovoitov Cc: Daniel Borkmann Cc: Jiri Olsa Cc: Martin KaFai Lau Cc: Wang Nan Link: http://lkml.kernel.org/r/20180616174739.1076733-1-yhs@fb.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/c++/clang.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/perf/util/c++/clang.cpp b/tools/perf/util/c++/clang.cpp index bf31ceab33bd..89512504551b 100644 --- a/tools/perf/util/c++/clang.cpp +++ b/tools/perf/util/c++/clang.cpp @@ -146,8 +146,15 @@ getBPFObjectFromModule(llvm::Module *Module) raw_svector_ostream ostream(*Buffer); legacy::PassManager PM; - if (TargetMachine->addPassesToEmitFile(PM, ostream, - TargetMachine::CGFT_ObjectFile)) { + bool NotAdded; +#if CLANG_VERSION_MAJOR < 7 + NotAdded = TargetMachine->addPassesToEmitFile(PM, ostream, + TargetMachine::CGFT_ObjectFile); +#else + NotAdded = TargetMachine->addPassesToEmitFile(PM, ostream, nullptr, + TargetMachine::CGFT_ObjectFile); +#endif + if (NotAdded) { llvm::errs() << "TargetMachine can't emit a file of this type\n"; return std::unique_ptr>(nullptr);; } -- cgit From ea23ac73085743a4f1682d6605fe019577c82e1e Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Fri, 15 Jun 2018 12:11:03 +0200 Subject: perf alias: Remove trailing newline when reading sysfs files Remove a trailing newline when reading sysfs file contents such as /sys/devices/cpum_cf/events/TX_NC_TEND. This shows when verbose option -v is used. Output before: tx_nc_tend -> 'cpum_cf'/'event=0x008d '/ Output after: tx_nc_tend -> 'cpum_cf'/'event=0x8d'/ Signed-off-by: Thomas Richter Reviewed-by: Hendrik Brueckner Cc: Heiko Carstens Cc: Jiri Olsa Cc: Martin Schwidefsky Link: http://lkml.kernel.org/r/20180615101105.47047-1-tmricht@linux.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/pmu.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'tools') diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index d2fb597c9a8c..2738fc8d200d 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -303,6 +303,9 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI buf[ret] = 0; + /* Remove trailing newline from sysfs file */ + rtrim(buf); + return __perf_pmu__new_alias(list, dir, name, NULL, buf, NULL, NULL, NULL, NULL, NULL, NULL); } -- cgit From 0c24d6fb7bd3578e5b9e4972d01bbe3d087ded33 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Fri, 15 Jun 2018 12:11:04 +0200 Subject: perf alias: Rebuild alias expression string to make it comparable PMU alias definitions in sysfs files may have spaces, newlines and numbers with leading zeroes. Some alias definitions may also appear in JSON files without spaces, etc. Scan alias definitions and remove leading zeroes, spaces, newlines, etc and rebuild string to make alias->str member comparable. s390 for example has terms specified as event=0x0091 (read from files ..//events/ and terms specified as event=0x91 (read from JSON files). Signed-off-by: Thomas Richter Reviewed-by: Hendrik Brueckner Cc: Heiko Carstens Cc: Jiri Olsa Cc: Martin Schwidefsky Link: http://lkml.kernel.org/r/20180615101105.47047-2-tmricht@linux.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/pmu.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index 2738fc8d200d..f321ce97d9ec 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -241,9 +241,11 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, char *metric_expr, char *metric_name) { + struct parse_events_term *term; struct perf_pmu_alias *alias; int ret; int num; + char newval[256]; alias = malloc(sizeof(*alias)); if (!alias) @@ -262,6 +264,27 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, return ret; } + /* Scan event and remove leading zeroes, spaces, newlines, some + * platforms have terms specified as + * event=0x0091 (read from files ..//events/ + * and terms specified as event=0x91 (read from JSON files). + * + * Rebuild string to make alias->str member comparable. + */ + memset(newval, 0, sizeof(newval)); + ret = 0; + list_for_each_entry(term, &alias->terms, list) { + if (ret) + ret += scnprintf(newval + ret, sizeof(newval) - ret, + ","); + if (term->type_val == PARSE_EVENTS__TERM_TYPE_NUM) + ret += scnprintf(newval + ret, sizeof(newval) - ret, + "%s=%#x", term->config, term->val.num); + else if (term->type_val == PARSE_EVENTS__TERM_TYPE_STR) + ret += scnprintf(newval + ret, sizeof(newval) - ret, + "%s=%s", term->config, term->val.str); + } + alias->name = strdup(name); if (dir) { /* @@ -285,7 +308,7 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, snprintf(alias->unit, sizeof(alias->unit), "%s", unit); } alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1; - alias->str = strdup(val); + alias->str = strdup(newval); list_add_tail(&alias->list, list); -- cgit From 6dde6429c5ff5b38d6d40a14a6ee105117e6364d Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Fri, 15 Jun 2018 12:11:05 +0200 Subject: perf stat: Remove duplicate event counting 'perf stat' shows a mismatch in perf stat regarding counter names on s390: Run command: [root@s35lp76 perf]# ./perf stat -e tx_nc_tend -v -- ~/mytesttx 1 >/tmp/111 tx_nc_tend: 1 573146 573146 tx_nc_tend: 1 573146 573146 Performance counter stats for '/root/mytesttx 1': 3 tx_nc_tend 0.001037252 seconds time elapsed [root@s35lp76 perf]# shows transaction counter tx_nc_tend with value 3 but it was triggered only once as seen by the output of mytesttx. When looking up the event name tx_nc_tend the following function sequence is called: parse_events_multi_pmu_add() +--> perf_pmu__scan() being called with NULL argument +--> pmu_read_sysfs() scans directory ../devices/ for all PMUs +--> perf_pmu__find() tries to find a PMU in the global pmu list. +--> pmu_lookup() called to read all file entries when not in global list. pmu_lookup() causes the issue. It calls +---> pmu_aliases() to read all the entries in the PMU directory. On s390 this is named /sys/devices/cpum_cf/events. +--> pmu_aliases_parse() reads all files and creates an alias for each file name. So we end up with first entry created by reading the sysfs file [root@s35lp76 perf]# cat /sys/devices/cpum_cf /events/TX_NC_TEND event=0x008d [root@s35lp76 perf]# Debug output shows this entry tx_nc_tend -> 'cpum_cf'/'event=0x008d '/ After all files in this directory have been read and aliases created this function is called: +--> pmu_add_cpu_aliases() This function looks up the CPU tables created by the json files. With json files for s390 now available all the aliases are added to the PMU alias list a second time. The second entry is added by reading the json file converted by jevent resulting in file pmu-events/pmu-events.c: { .name = "tx_nc_tend", .event = "event=0x8d", .desc = "Unit: cpum_cf Completed TEND \ instructions \ in non-constrained TX mode", .topic = "extended", .long_desc = "A TEND instruction has \ completed in a \ non-constrained \ transactional-execution mode", .pmu = "cpum_cf", }, Debug output shows this entry tx_nc_tend -> 'cpum_cf'/'event=0x8d'/ Function pmu_aliases_parse() and pmu_add_cpu_aliases() both use __perf_pmu__new_alias() to add an alias to the PMU alias list. There is no check if an alias already exist So we end up with 2 entries for tx_nc_tend in the PMU alias list. Having set up the PMU alias list for this PMU now parse_events_multi_add_pmu() reads the complete alias list and adds each alias with parse_events_add_pmu() to the global perfev_list. This causes the alias to be added multiple times to the event list. Fix this by making __perf_pmu__new_alias() to merge alias definitions if an alias is already on the alias list. Also print a debug message when the alias has mismatches in some fields. Output before: [root@s35lp76 perf]# ./perf stat -e tx_nc_tend -v \ -- ~/mytesttx 1 >/tmp/111 tx_nc_tend: 1 551446 551446 Performance counter stats for '/root/mytesttx 1': 3 tx_nc_tend 0.000961134 seconds time elapsed [root@s35lp76 perf]# Output after: [root@s35lp76 perf]# ./perf stat -e tx_nc_tend -v \ -- ~/mytesttx 1 >/tmp/111 tx_nc_tend: 1 551446 551446 Performance counter stats for '/root/mytesttx 1': 1 tx_nc_tend 0.000961134 seconds time elapsed [root@s35lp76 perf]# Signed-off-by: Thomas Richter Reviewed-by: Hendrik Brueckner Reviewed-by: Jiri Olsa Cc: Heiko Carstens Cc: Martin Schwidefsky Link: http://lkml.kernel.org/r/20180615101105.47047-3-tmricht@linux.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/util/pmu.c | 71 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c index f321ce97d9ec..3ba6a1742f91 100644 --- a/tools/perf/util/pmu.c +++ b/tools/perf/util/pmu.c @@ -234,6 +234,74 @@ static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias, return 0; } +static void perf_pmu_assign_str(char *name, const char *field, char **old_str, + char **new_str) +{ + if (!*old_str) + goto set_new; + + if (*new_str) { /* Have new string, check with old */ + if (strcasecmp(*old_str, *new_str)) + pr_debug("alias %s differs in field '%s'\n", + name, field); + zfree(old_str); + } else /* Nothing new --> keep old string */ + return; +set_new: + *old_str = *new_str; + *new_str = NULL; +} + +static void perf_pmu_update_alias(struct perf_pmu_alias *old, + struct perf_pmu_alias *newalias) +{ + perf_pmu_assign_str(old->name, "desc", &old->desc, &newalias->desc); + perf_pmu_assign_str(old->name, "long_desc", &old->long_desc, + &newalias->long_desc); + perf_pmu_assign_str(old->name, "topic", &old->topic, &newalias->topic); + perf_pmu_assign_str(old->name, "metric_expr", &old->metric_expr, + &newalias->metric_expr); + perf_pmu_assign_str(old->name, "metric_name", &old->metric_name, + &newalias->metric_name); + perf_pmu_assign_str(old->name, "value", &old->str, &newalias->str); + old->scale = newalias->scale; + old->per_pkg = newalias->per_pkg; + old->snapshot = newalias->snapshot; + memcpy(old->unit, newalias->unit, sizeof(old->unit)); +} + +/* Delete an alias entry. */ +static void perf_pmu_free_alias(struct perf_pmu_alias *newalias) +{ + zfree(&newalias->name); + zfree(&newalias->desc); + zfree(&newalias->long_desc); + zfree(&newalias->topic); + zfree(&newalias->str); + zfree(&newalias->metric_expr); + zfree(&newalias->metric_name); + parse_events_terms__purge(&newalias->terms); + free(newalias); +} + +/* Merge an alias, search in alias list. If this name is already + * present merge both of them to combine all information. + */ +static bool perf_pmu_merge_alias(struct perf_pmu_alias *newalias, + struct list_head *alist) +{ + struct perf_pmu_alias *a; + + list_for_each_entry(a, alist, list) { + if (!strcasecmp(newalias->name, a->name)) { + perf_pmu_update_alias(a, newalias); + perf_pmu_free_alias(newalias); + return true; + } + } + return false; +} + static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, char *desc, char *val, char *long_desc, char *topic, @@ -310,7 +378,8 @@ static int __perf_pmu__new_alias(struct list_head *list, char *dir, char *name, alias->per_pkg = perpkg && sscanf(perpkg, "%d", &num) == 1 && num == 1; alias->str = strdup(newval); - list_add_tail(&alias->list, list); + if (!perf_pmu_merge_alias(alias, list)) + list_add_tail(&alias->list, list); return 0; } -- cgit From 983107072be1a39cbde67d45cb0059138190e015 Mon Sep 17 00:00:00 2001 From: Jiri Olsa Date: Wed, 20 Jun 2018 11:40:36 +0200 Subject: perf bench: Fix numa report output code Currently we can hit following assert when running numa bench: $ perf bench numa mem -p 3 -t 1 -P 512 -s 100 -zZ0cm --thp 1 perf: bench/numa.c:1577: __bench_numa: Assertion `!(!(((wait_stat) & 0x7f) == 0))' failed. The assertion is correct, because we hit the SIGFPE in following line: Thread 2.2 "thread 0/0" received signal SIGFPE, Arithmetic exception. [Switching to Thread 0x7fffd28c6700 (LWP 11750)] 0x000.. in worker_thread (__tdata=0x7.. ) at bench/numa.c:1257 1257 td->speed_gbs = bytes_done / (td->runtime_ns / NSEC_PER_SEC) / 1e9; We don't check if the runtime is actually bigger than 1 second, and thus this might end up with zero division within FPU. Adding the check to prevent this. Signed-off-by: Jiri Olsa Cc: Alexander Shishkin Cc: David Ahern Cc: Namhyung Kim Cc: Peter Zijlstra Link: http://lkml.kernel.org/r/20180620094036.17278-1-jolsa@kernel.org Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/bench/numa.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/perf/bench/numa.c b/tools/perf/bench/numa.c index 63eb49082774..44195514b19e 100644 --- a/tools/perf/bench/numa.c +++ b/tools/perf/bench/numa.c @@ -1098,7 +1098,7 @@ static void *worker_thread(void *__tdata) u8 *global_data; u8 *process_data; u8 *thread_data; - u64 bytes_done; + u64 bytes_done, secs; long work_done; u32 l; struct rusage rusage; @@ -1254,7 +1254,8 @@ static void *worker_thread(void *__tdata) timersub(&stop, &start0, &diff); td->runtime_ns = diff.tv_sec * NSEC_PER_SEC; td->runtime_ns += diff.tv_usec * NSEC_PER_USEC; - td->speed_gbs = bytes_done / (td->runtime_ns / NSEC_PER_SEC) / 1e9; + secs = td->runtime_ns / NSEC_PER_SEC; + td->speed_gbs = secs ? bytes_done / secs / 1e9 : 0; getrusage(RUSAGE_THREAD, &rusage); td->system_time_ns = rusage.ru_stime.tv_sec * NSEC_PER_SEC; -- cgit From 10e9cec905f96fdf47f398be70726e2931b376cd Mon Sep 17 00:00:00 2001 From: Ravi Bangoria Date: Mon, 25 Jun 2018 18:12:18 +0530 Subject: perf script: Add missing output fields in a hint A few fields are missing in a perf script -F hint. Add them. Signed-off-by: Ravi Bangoria Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: David Carrillo-Cisneros Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Link: http://lkml.kernel.org/r/20180625124220.6434-2-ravi.bangoria@linux.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index a31d7082188e..f3fefbcc4503 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -3125,8 +3125,9 @@ int cmd_script(int argc, const char **argv) "+field to add and -field to remove." "Valid types: hw,sw,trace,raw,synth. " "Fields: comm,tid,pid,time,cpu,event,trace,ip,sym,dso," - "addr,symoff,period,iregs,uregs,brstack,brstacksym,flags," - "bpf-output,callindent,insn,insnlen,brstackinsn,synth,phys_addr", + "addr,symoff,srcline,period,iregs,uregs,brstack," + "brstacksym,flags,bpf-output,brstackinsn,brstackoff," + "callindent,insn,insnlen,synth,phys_addr,metric,misc", parse_output_fields), OPT_BOOLEAN('a', "all-cpus", &system_wide, "system-wide collection from all CPUs"), -- cgit From a3af66f51bd0bca72881ead4bf2bd19cb366582b Mon Sep 17 00:00:00 2001 From: Ravi Bangoria Date: Mon, 25 Jun 2018 18:12:19 +0530 Subject: perf script: Fix crash because of missing evsel->priv 'perf script' in piped mode is crashing because evsel->priv is not set properly. Fix it. Before: # perf record -o - -- ls | perf script Segmentation fault (core dumped) # After: # perf record -o - -- ls | perf script ls 2282 1031.731974: 250000 cpu-clock:uhH: 7effe4b3d29e ls 2282 1031.732222: 250000 cpu-clock:uhH: 7effe4b3a650 # Signed-off-by: Ravi Bangoria Tested-by: Arnaldo Carvalho de Melo Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: David Carrillo-Cisneros Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Fixes: a14390fde64e ("perf script: Allow creating per-event dump files") Link: http://lkml.kernel.org/r/20180625124220.6434-3-ravi.bangoria@linux.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-script.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'tools') diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index f3fefbcc4503..ad2ac1300420 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -1834,6 +1834,7 @@ static int process_attr(struct perf_tool *tool, union perf_event *event, struct perf_evlist *evlist; struct perf_evsel *evsel, *pos; int err; + static struct perf_evsel_script *es; err = perf_event__process_attr(tool, event, pevlist); if (err) @@ -1842,6 +1843,19 @@ static int process_attr(struct perf_tool *tool, union perf_event *event, evlist = *pevlist; evsel = perf_evlist__last(*pevlist); + if (!evsel->priv) { + if (scr->per_event_dump) { + evsel->priv = perf_evsel_script__new(evsel, + scr->session->data); + } else { + es = zalloc(sizeof(*es)); + if (!es) + return -ENOMEM; + es->fp = stdout; + evsel->priv = es; + } + } + if (evsel->attr.type >= PERF_TYPE_MAX && evsel->attr.type != PERF_TYPE_SYNTH) return 0; -- cgit From 92ead7ee30c80f8852d28735cbcb9d79bc85f715 Mon Sep 17 00:00:00 2001 From: Ravi Bangoria Date: Mon, 25 Jun 2018 18:12:20 +0530 Subject: perf tools: Fix crash caused by accessing feat_ops[HEADER_LAST_FEATURE] perf_event__process_feature() accesses feat_ops[HEADER_LAST_FEATURE] which is not defined and thus perf is crashing. HEADER_LAST_FEATURE is used as an end marker for the perf report but it's unused for perf script/annotate. Ignore HEADER_LAST_FEATURE for perf script/annotate, just like it is done in 'perf report'. Before: # perf record -o - ls | perf script Segmentation fault (core dumped) # After: # perf record -o - ls | perf script Segmentation fault (core dumped) ls 7031 4392.099856: 250000 cpu-clock:uhH: 7f5e0ce7cd60 ls 7031 4392.100355: 250000 cpu-clock:uhH: 7f5e0c706ef7 # Signed-off-by: Ravi Bangoria Cc: Alexander Shishkin Cc: Andi Kleen Cc: David Ahern Cc: David Carrillo-Cisneros Cc: Jin Yao Cc: Jiri Olsa Cc: Namhyung Kim Fixes: 57b5de463925 ("perf report: Support forced leader feature in pipe mode") Link: http://lkml.kernel.org/r/20180625124220.6434-4-ravi.bangoria@linux.ibm.com Signed-off-by: Arnaldo Carvalho de Melo --- tools/perf/builtin-annotate.c | 11 ++++++++++- tools/perf/builtin-report.c | 3 ++- tools/perf/builtin-script.c | 11 ++++++++++- tools/perf/util/header.c | 2 +- 4 files changed, 23 insertions(+), 4 deletions(-) (limited to 'tools') diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index 5eb22cc56363..8180319285af 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c @@ -283,6 +283,15 @@ out_put: return ret; } +static int process_feature_event(struct perf_tool *tool, + union perf_event *event, + struct perf_session *session) +{ + if (event->feat.feat_id < HEADER_LAST_FEATURE) + return perf_event__process_feature(tool, event, session); + return 0; +} + static int hist_entry__tty_annotate(struct hist_entry *he, struct perf_evsel *evsel, struct perf_annotate *ann) @@ -471,7 +480,7 @@ int cmd_annotate(int argc, const char **argv) .attr = perf_event__process_attr, .build_id = perf_event__process_build_id, .tracing_data = perf_event__process_tracing_data, - .feature = perf_event__process_feature, + .feature = process_feature_event, .ordered_events = true, .ordering_requires_timestamps = true, }, diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index cdb5b6949832..c04dc7b53797 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c @@ -217,7 +217,8 @@ static int process_feature_event(struct perf_tool *tool, } /* - * All features are received, we can force the + * (feat_id = HEADER_LAST_FEATURE) is the end marker which + * means all features are received, now we can force the * group if needed. */ setup_forced_leader(rep, session->evlist); diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c index ad2ac1300420..568ddfac3213 100644 --- a/tools/perf/builtin-script.c +++ b/tools/perf/builtin-script.c @@ -3044,6 +3044,15 @@ int process_cpu_map_event(struct perf_tool *tool __maybe_unused, return set_maps(script); } +static int process_feature_event(struct perf_tool *tool, + union perf_event *event, + struct perf_session *session) +{ + if (event->feat.feat_id < HEADER_LAST_FEATURE) + return perf_event__process_feature(tool, event, session); + return 0; +} + #ifdef HAVE_AUXTRACE_SUPPORT static int perf_script__process_auxtrace_info(struct perf_tool *tool, union perf_event *event, @@ -3088,7 +3097,7 @@ int cmd_script(int argc, const char **argv) .attr = process_attr, .event_update = perf_event__process_event_update, .tracing_data = perf_event__process_tracing_data, - .feature = perf_event__process_feature, + .feature = process_feature_event, .build_id = perf_event__process_build_id, .id_index = perf_event__process_id_index, .auxtrace_info = perf_script__process_auxtrace_info, diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 59fcc790c865..653ff65aa2c3 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c @@ -3464,7 +3464,7 @@ int perf_event__process_feature(struct perf_tool *tool, pr_warning("invalid record type %d in pipe-mode\n", type); return 0; } - if (feat == HEADER_RESERVED || feat > HEADER_LAST_FEATURE) { + if (feat == HEADER_RESERVED || feat >= HEADER_LAST_FEATURE) { pr_warning("invalid record type %d in pipe-mode\n", type); return -1; } -- cgit From 32fdbd90cc03f01d452138bab4d8a120873d6acf Mon Sep 17 00:00:00 2001 From: Ingo Molnar Date: Tue, 26 Jun 2018 08:43:14 +0200 Subject: tools/headers: Pick up latest kernel ABIs Sync KVM ABI additions and x86 CPU features additions - neither of which has any impact on the tooling build. Cc: Arnaldo Carvalho de Melo Cc: Peter Zijlstra Cc: Namhyung Kim Cc: Jiri Olsa Cc: linux-kernel@vger.kernel.org Signed-off-by: Ingo Molnar --- tools/arch/arm/include/uapi/asm/kvm.h | 1 + tools/arch/arm64/include/uapi/asm/kvm.h | 1 + tools/arch/powerpc/include/uapi/asm/kvm.h | 1 + tools/arch/x86/include/asm/cpufeatures.h | 2 ++ tools/include/uapi/linux/kvm.h | 1 + 5 files changed, 6 insertions(+) (limited to 'tools') diff --git a/tools/arch/arm/include/uapi/asm/kvm.h b/tools/arch/arm/include/uapi/asm/kvm.h index caae4843cb70..16e006f708ca 100644 --- a/tools/arch/arm/include/uapi/asm/kvm.h +++ b/tools/arch/arm/include/uapi/asm/kvm.h @@ -91,6 +91,7 @@ struct kvm_regs { #define KVM_VGIC_V3_ADDR_TYPE_DIST 2 #define KVM_VGIC_V3_ADDR_TYPE_REDIST 3 #define KVM_VGIC_ITS_ADDR_TYPE 4 +#define KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION 5 #define KVM_VGIC_V3_DIST_SIZE SZ_64K #define KVM_VGIC_V3_REDIST_SIZE (2 * SZ_64K) diff --git a/tools/arch/arm64/include/uapi/asm/kvm.h b/tools/arch/arm64/include/uapi/asm/kvm.h index 04b3256f8e6d..4e76630dd655 100644 --- a/tools/arch/arm64/include/uapi/asm/kvm.h +++ b/tools/arch/arm64/include/uapi/asm/kvm.h @@ -91,6 +91,7 @@ struct kvm_regs { #define KVM_VGIC_V3_ADDR_TYPE_DIST 2 #define KVM_VGIC_V3_ADDR_TYPE_REDIST 3 #define KVM_VGIC_ITS_ADDR_TYPE 4 +#define KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION 5 #define KVM_VGIC_V3_DIST_SIZE SZ_64K #define KVM_VGIC_V3_REDIST_SIZE (2 * SZ_64K) diff --git a/tools/arch/powerpc/include/uapi/asm/kvm.h b/tools/arch/powerpc/include/uapi/asm/kvm.h index 833ed9a16adf..1b32b56a03d3 100644 --- a/tools/arch/powerpc/include/uapi/asm/kvm.h +++ b/tools/arch/powerpc/include/uapi/asm/kvm.h @@ -633,6 +633,7 @@ struct kvm_ppc_cpu_char { #define KVM_REG_PPC_PSSCR (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbd) #define KVM_REG_PPC_DEC_EXPIRY (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xbe) +#define KVM_REG_PPC_ONLINE (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xbf) /* Transactional Memory checkpointed state: * This is all GPRs, all VSX regs and a subset of SPRs diff --git a/tools/arch/x86/include/asm/cpufeatures.h b/tools/arch/x86/include/asm/cpufeatures.h index fb00a2fca990..5701f5cecd31 100644 --- a/tools/arch/x86/include/asm/cpufeatures.h +++ b/tools/arch/x86/include/asm/cpufeatures.h @@ -282,7 +282,9 @@ #define X86_FEATURE_AMD_IBPB (13*32+12) /* "" Indirect Branch Prediction Barrier */ #define X86_FEATURE_AMD_IBRS (13*32+14) /* "" Indirect Branch Restricted Speculation */ #define X86_FEATURE_AMD_STIBP (13*32+15) /* "" Single Thread Indirect Branch Predictors */ +#define X86_FEATURE_AMD_SSBD (13*32+24) /* "" Speculative Store Bypass Disable */ #define X86_FEATURE_VIRT_SSBD (13*32+25) /* Virtualized Speculative Store Bypass Disable */ +#define X86_FEATURE_AMD_SSB_NO (13*32+26) /* "" Speculative Store Bypass is fixed in hardware. */ /* Thermal and Power Management Leaf, CPUID level 0x00000006 (EAX), word 14 */ #define X86_FEATURE_DTHERM (14*32+ 0) /* Digital Thermal Sensor */ diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h index 39e364c70caf..b6270a3b38e9 100644 --- a/tools/include/uapi/linux/kvm.h +++ b/tools/include/uapi/linux/kvm.h @@ -948,6 +948,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_S390_BPB 152 #define KVM_CAP_GET_MSR_FEATURES 153 #define KVM_CAP_HYPERV_EVENTFD 154 +#define KVM_CAP_HYPERV_TLBFLUSH 155 #ifdef KVM_CAP_IRQ_ROUTING -- cgit From 5fadfc61934a33d362ca47c7f70786105d5681c1 Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Mon, 25 Jun 2018 16:56:05 +0200 Subject: selftests: bpf: add missing NET_SCHED to config CONFIG_NET_SCHED wasn't enabled in arm64's defconfig only for x86. So bpf/test_tunnel.sh tests fails with: RTNETLINK answers: Operation not supported RTNETLINK answers: Operation not supported We have an error talking to the kernel, -1 Enable NET_SCHED and more tests pass. Fixes: 3bce593ac06b ("selftests: bpf: config: add config fragments") Signed-off-by: Anders Roxell Acked-by: Song Liu Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/config | 1 + 1 file changed, 1 insertion(+) (limited to 'tools') diff --git a/tools/testing/selftests/bpf/config b/tools/testing/selftests/bpf/config index 7eb613ffef55..b4994a94968b 100644 --- a/tools/testing/selftests/bpf/config +++ b/tools/testing/selftests/bpf/config @@ -6,6 +6,7 @@ CONFIG_TEST_BPF=m CONFIG_CGROUP_BPF=y CONFIG_NETDEVSIM=m CONFIG_NET_CLS_ACT=y +CONFIG_NET_SCHED=y CONFIG_NET_SCH_INGRESS=y CONFIG_NET_IPIP=y CONFIG_IPV6=y -- cgit From b0e4b8bcd48bde31690f066044767475b2e4852b Mon Sep 17 00:00:00 2001 From: Jeffrin Jose T Date: Sat, 23 Jun 2018 00:24:17 +0530 Subject: selftests: bpf: notification about privilege required to run test_lirc_mode2.sh testing script The test_lirc_mode2.sh script require root privilege for the successful execution of the test. This patch is to notify the user about the privilege the script demands for the successful execution of the test. Signed-off-by: Jeffrin Jose T (Rajagiri SET) Acked-by: Song Liu Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_lirc_mode2.sh | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'tools') diff --git a/tools/testing/selftests/bpf/test_lirc_mode2.sh b/tools/testing/selftests/bpf/test_lirc_mode2.sh index ce2e15e4f976..677686198df3 100755 --- a/tools/testing/selftests/bpf/test_lirc_mode2.sh +++ b/tools/testing/selftests/bpf/test_lirc_mode2.sh @@ -1,6 +1,15 @@ #!/bin/bash # SPDX-License-Identifier: GPL-2.0 +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=4 + +msg="skip all tests:" +if [ $UID != 0 ]; then + echo $msg please run this as root >&2 + exit $ksft_skip +fi + GREEN='\033[0;92m' RED='\033[0;31m' NC='\033[0m' # No Color -- cgit From dd349c3ffd93d15d01f4f5ace73870ca45ea249d Mon Sep 17 00:00:00 2001 From: Jeffrin Jose T Date: Sat, 23 Jun 2018 03:10:32 +0530 Subject: selftests: bpf: notification about privilege required to run test_lwt_seg6local.sh testing script This test needs root privilege for it's successful execution. This patch is atleast used to notify the user about the privilege the script demands for the smooth execution of the test. Signed-off-by: Jeffrin Jose T (Rajagiri SET) Acked-by: Song Liu Signed-off-by: Daniel Borkmann --- tools/testing/selftests/bpf/test_lwt_seg6local.sh | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'tools') diff --git a/tools/testing/selftests/bpf/test_lwt_seg6local.sh b/tools/testing/selftests/bpf/test_lwt_seg6local.sh index 1c77994b5e71..270fa8f49573 100755 --- a/tools/testing/selftests/bpf/test_lwt_seg6local.sh +++ b/tools/testing/selftests/bpf/test_lwt_seg6local.sh @@ -21,6 +21,15 @@ # An UDP datagram is sent from fb00::1 to fb00::6. The test succeeds if this # datagram can be read on NS6 when binding to fb00::6. +# Kselftest framework requirement - SKIP code is 4. +ksft_skip=4 + +msg="skip all tests:" +if [ $UID != 0 ]; then + echo $msg please run this as root >&2 + exit $ksft_skip +fi + TMP_FILE="/tmp/selftest_lwt_seg6local.txt" cleanup() -- cgit From ec348020566009d3da9b99f07c05814d13969c78 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 26 Jun 2018 22:17:17 -0700 Subject: selftests/x86/sigreturn/64: Fix spurious failures on AMD CPUs When I wrote the sigreturn test, I didn't realize that AMD's busted IRET behavior was different from Intel's busted IRET behavior: On AMD CPUs, the CPU leaks the high 32 bits of the kernel stack pointer to certain userspace contexts. Gee, thanks. There's very little the kernel can do about it. Modify the test so it passes. Signed-off-by: Andy Lutomirski Cc: Borislav Petkov Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/86e7fd3564497f657de30a36da4505799eebef01.1530076529.git.luto@kernel.org Signed-off-by: Ingo Molnar --- tools/testing/selftests/x86/sigreturn.c | 46 +++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 17 deletions(-) (limited to 'tools') diff --git a/tools/testing/selftests/x86/sigreturn.c b/tools/testing/selftests/x86/sigreturn.c index 246145b84a12..2559e2c01793 100644 --- a/tools/testing/selftests/x86/sigreturn.c +++ b/tools/testing/selftests/x86/sigreturn.c @@ -612,19 +612,38 @@ static int test_valid_sigreturn(int cs_bits, bool use_16bit_ss, int force_ss) greg_t req = requested_regs[i], res = resulting_regs[i]; if (i == REG_TRAPNO || i == REG_IP) continue; /* don't care */ - if (i == REG_SP) { - printf("\tSP: %llx -> %llx\n", (unsigned long long)req, - (unsigned long long)res); + if (i == REG_SP) { /* - * In many circumstances, the high 32 bits of rsp - * are zeroed. For example, we could be a real - * 32-bit program, or we could hit any of a number - * of poorly-documented IRET or segmented ESP - * oddities. If this happens, it's okay. + * If we were using a 16-bit stack segment, then + * the kernel is a bit stuck: IRET only restores + * the low 16 bits of ESP/RSP if SS is 16-bit. + * The kernel uses a hack to restore bits 31:16, + * but that hack doesn't help with bits 63:32. + * On Intel CPUs, bits 63:32 end up zeroed, and, on + * AMD CPUs, they leak the high bits of the kernel + * espfix64 stack pointer. There's very little that + * the kernel can do about it. + * + * Similarly, if we are returning to a 32-bit context, + * the CPU will often lose the high 32 bits of RSP. */ - if (res == (req & 0xFFFFFFFF)) - continue; /* OK; not expected to work */ + + if (res == req) + continue; + + if (cs_bits != 64 && ((res ^ req) & 0xFFFFFFFF) == 0) { + printf("[NOTE]\tSP: %llx -> %llx\n", + (unsigned long long)req, + (unsigned long long)res); + continue; + } + + printf("[FAIL]\tSP mismatch: requested 0x%llx; got 0x%llx\n", + (unsigned long long)requested_regs[i], + (unsigned long long)resulting_regs[i]); + nerrs++; + continue; } bool ignore_reg = false; @@ -663,13 +682,6 @@ static int test_valid_sigreturn(int cs_bits, bool use_16bit_ss, int force_ss) } if (requested_regs[i] != resulting_regs[i] && !ignore_reg) { - /* - * SP is particularly interesting here. The - * usual cause of failures is that we hit the - * nasty IRET case of returning to a 16-bit SS, - * in which case bits 16:31 of the *kernel* - * stack pointer persist in ESP. - */ printf("[FAIL]\tReg %d mismatch: requested 0x%llx; got 0x%llx\n", i, (unsigned long long)requested_regs[i], (unsigned long long)resulting_regs[i]); -- cgit From e8a445dea219c32727016af14f847d2e8f7ebec8 Mon Sep 17 00:00:00 2001 From: Andy Lutomirski Date: Tue, 26 Jun 2018 22:17:18 -0700 Subject: selftests/x86/sigreturn: Do minor cleanups We have short names for the requested and resulting register values. Use them instead of spelling out the whole register entry for each case. Signed-off-by: Andy Lutomirski Cc: Borislav Petkov Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/bb3bc1f923a2f6fe7912d22a1068fe29d6033d38.1530076529.git.luto@kernel.org Signed-off-by: Ingo Molnar --- tools/testing/selftests/x86/sigreturn.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) (limited to 'tools') diff --git a/tools/testing/selftests/x86/sigreturn.c b/tools/testing/selftests/x86/sigreturn.c index 2559e2c01793..4d9dc3f2fd70 100644 --- a/tools/testing/selftests/x86/sigreturn.c +++ b/tools/testing/selftests/x86/sigreturn.c @@ -610,6 +610,7 @@ static int test_valid_sigreturn(int cs_bits, bool use_16bit_ss, int force_ss) */ for (int i = 0; i < NGREG; i++) { greg_t req = requested_regs[i], res = resulting_regs[i]; + if (i == REG_TRAPNO || i == REG_IP) continue; /* don't care */ @@ -673,18 +674,18 @@ static int test_valid_sigreturn(int cs_bits, bool use_16bit_ss, int force_ss) #endif /* Sanity check on the kernel */ - if (i == REG_CX && requested_regs[i] != resulting_regs[i]) { + if (i == REG_CX && req != res) { printf("[FAIL]\tCX (saved SP) mismatch: requested 0x%llx; got 0x%llx\n", - (unsigned long long)requested_regs[i], - (unsigned long long)resulting_regs[i]); + (unsigned long long)req, + (unsigned long long)res); nerrs++; continue; } - if (requested_regs[i] != resulting_regs[i] && !ignore_reg) { + if (req != res && !ignore_reg) { printf("[FAIL]\tReg %d mismatch: requested 0x%llx; got 0x%llx\n", - i, (unsigned long long)requested_regs[i], - (unsigned long long)resulting_regs[i]); + i, (unsigned long long)req, + (unsigned long long)res); nerrs++; } } -- cgit From 933e671f8cff87552d4d26cf3874633b11ae78ba Mon Sep 17 00:00:00 2001 From: Shuah Khan Date: Tue, 26 Jun 2018 12:22:28 -0600 Subject: selftests/net: Fix permissions for fib_tests.sh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fib_tests.sh became non-executable at some point. This is what happens: selftests: net: fib_tests.sh: Warning: file fib_tests.sh is not executable, correct this. not ok 1..11 selftests: net: fib_tests.sh [FAIL] Fixes: d69faad76584 ("selftests: fib_tests: Add prefix route tests with metric") Signed-off-by: Daniel Díaz Signed-off-by: David S. Miller --- tools/testing/selftests/net/fib_tests.sh | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 tools/testing/selftests/net/fib_tests.sh (limited to 'tools') diff --git a/tools/testing/selftests/net/fib_tests.sh b/tools/testing/selftests/net/fib_tests.sh old mode 100644 new mode 100755 -- cgit From 9544bc5347207a68eb308cc8aaaed6c3a687cabd Mon Sep 17 00:00:00 2001 From: Jens Axboe Date: Fri, 29 Jun 2018 08:48:06 -0600 Subject: sg: remove ->sg_magic member This was introduced more than a decade ago when sg chaining was added, but we never really caught anything with it. The scatterlist entry size can be critical, since drivers allocate it, so remove the magic member. Recently it's been triggering allocation stalls and failures in NVMe. Tested-by: Jordan Glover Acked-by: Christoph Hellwig Signed-off-by: Jens Axboe --- drivers/gpu/drm/i915/i915_drv.h | 3 --- include/linux/scatterlist.h | 18 ------------------ lib/scatterlist.c | 6 ------ tools/virtio/linux/scatterlist.h | 18 ------------------ 4 files changed, 45 deletions(-) (limited to 'tools') diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 34c125e2d90c..9180f67746b4 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -2238,9 +2238,6 @@ static inline struct scatterlist *____sg_next(struct scatterlist *sg) **/ static inline struct scatterlist *__sg_next(struct scatterlist *sg) { -#ifdef CONFIG_DEBUG_SG - BUG_ON(sg->sg_magic != SG_MAGIC); -#endif return sg_is_last(sg) ? NULL : ____sg_next(sg); } diff --git a/include/linux/scatterlist.h b/include/linux/scatterlist.h index 51f52020ad5f..093aa57120b0 100644 --- a/include/linux/scatterlist.h +++ b/include/linux/scatterlist.h @@ -9,9 +9,6 @@ #include struct scatterlist { -#ifdef CONFIG_DEBUG_SG - unsigned long sg_magic; -#endif unsigned long page_link; unsigned int offset; unsigned int length; @@ -64,7 +61,6 @@ struct sg_table { * */ -#define SG_MAGIC 0x87654321 #define SG_CHAIN 0x01UL #define SG_END 0x02UL @@ -98,7 +94,6 @@ static inline void sg_assign_page(struct scatterlist *sg, struct page *page) */ BUG_ON((unsigned long) page & (SG_CHAIN | SG_END)); #ifdef CONFIG_DEBUG_SG - BUG_ON(sg->sg_magic != SG_MAGIC); BUG_ON(sg_is_chain(sg)); #endif sg->page_link = page_link | (unsigned long) page; @@ -129,7 +124,6 @@ static inline void sg_set_page(struct scatterlist *sg, struct page *page, static inline struct page *sg_page(struct scatterlist *sg) { #ifdef CONFIG_DEBUG_SG - BUG_ON(sg->sg_magic != SG_MAGIC); BUG_ON(sg_is_chain(sg)); #endif return (struct page *)((sg)->page_link & ~(SG_CHAIN | SG_END)); @@ -195,9 +189,6 @@ static inline void sg_chain(struct scatterlist *prv, unsigned int prv_nents, **/ static inline void sg_mark_end(struct scatterlist *sg) { -#ifdef CONFIG_DEBUG_SG - BUG_ON(sg->sg_magic != SG_MAGIC); -#endif /* * Set termination bit, clear potential chain bit */ @@ -215,9 +206,6 @@ static inline void sg_mark_end(struct scatterlist *sg) **/ static inline void sg_unmark_end(struct scatterlist *sg) { -#ifdef CONFIG_DEBUG_SG - BUG_ON(sg->sg_magic != SG_MAGIC); -#endif sg->page_link &= ~SG_END; } @@ -260,12 +248,6 @@ static inline void *sg_virt(struct scatterlist *sg) static inline void sg_init_marker(struct scatterlist *sgl, unsigned int nents) { -#ifdef CONFIG_DEBUG_SG - unsigned int i; - - for (i = 0; i < nents; i++) - sgl[i].sg_magic = SG_MAGIC; -#endif sg_mark_end(&sgl[nents - 1]); } diff --git a/lib/scatterlist.c b/lib/scatterlist.c index 06dad7a072fd..d4ae67d6cd1e 100644 --- a/lib/scatterlist.c +++ b/lib/scatterlist.c @@ -24,9 +24,6 @@ **/ struct scatterlist *sg_next(struct scatterlist *sg) { -#ifdef CONFIG_DEBUG_SG - BUG_ON(sg->sg_magic != SG_MAGIC); -#endif if (sg_is_last(sg)) return NULL; @@ -111,10 +108,7 @@ struct scatterlist *sg_last(struct scatterlist *sgl, unsigned int nents) for_each_sg(sgl, sg, nents, i) ret = sg; -#ifdef CONFIG_DEBUG_SG - BUG_ON(sgl[0].sg_magic != SG_MAGIC); BUG_ON(!sg_is_last(ret)); -#endif return ret; } EXPORT_SYMBOL(sg_last); diff --git a/tools/virtio/linux/scatterlist.h b/tools/virtio/linux/scatterlist.h index 9a45f90e2d08..369ee308b668 100644 --- a/tools/virtio/linux/scatterlist.h +++ b/tools/virtio/linux/scatterlist.h @@ -36,7 +36,6 @@ static inline void sg_assign_page(struct scatterlist *sg, struct page *page) */ BUG_ON((unsigned long) page & 0x03); #ifdef CONFIG_DEBUG_SG - BUG_ON(sg->sg_magic != SG_MAGIC); BUG_ON(sg_is_chain(sg)); #endif sg->page_link = page_link | (unsigned long) page; @@ -67,7 +66,6 @@ static inline void sg_set_page(struct scatterlist *sg, struct page *page, static inline struct page *sg_page(struct scatterlist *sg) { #ifdef CONFIG_DEBUG_SG - BUG_ON(sg->sg_magic != SG_MAGIC); BUG_ON(sg_is_chain(sg)); #endif return (struct page *)((sg)->page_link & ~0x3); @@ -116,9 +114,6 @@ static inline void sg_chain(struct scatterlist *prv, unsigned int prv_nents, **/ static inline void sg_mark_end(struct scatterlist *sg) { -#ifdef CONFIG_DEBUG_SG - BUG_ON(sg->sg_magic != SG_MAGIC); -#endif /* * Set termination bit, clear potential chain bit */ @@ -136,17 +131,11 @@ static inline void sg_mark_end(struct scatterlist *sg) **/ static inline void sg_unmark_end(struct scatterlist *sg) { -#ifdef CONFIG_DEBUG_SG - BUG_ON(sg->sg_magic != SG_MAGIC); -#endif sg->page_link &= ~0x02; } static inline struct scatterlist *sg_next(struct scatterlist *sg) { -#ifdef CONFIG_DEBUG_SG - BUG_ON(sg->sg_magic != SG_MAGIC); -#endif if (sg_is_last(sg)) return NULL; @@ -160,13 +149,6 @@ static inline struct scatterlist *sg_next(struct scatterlist *sg) static inline void sg_init_table(struct scatterlist *sgl, unsigned int nents) { memset(sgl, 0, sizeof(*sgl) * nents); -#ifdef CONFIG_DEBUG_SG - { - unsigned int i; - for (i = 0; i < nents; i++) - sgl[i].sg_magic = SG_MAGIC; - } -#endif sg_mark_end(&sgl[nents - 1]); } -- cgit From 08b393d01c88aff27347ed2b1b354eb4db2f1532 Mon Sep 17 00:00:00 2001 From: Josh Poimboeuf Date: Wed, 27 Jun 2018 17:03:45 -0500 Subject: objtool: Support GCC 8 '-fnoreorder-functions' Since the following commit: cd77849a69cf ("objtool: Fix GCC 8 cold subfunction detection for aliased functions") ... if the kernel is built with EXTRA_CFLAGS='-fno-reorder-functions', objtool can get stuck in an infinite loop. That flag causes the new GCC 8 cold subfunctions to be placed in .text instead of .text.unlikely. But it also has an unfortunate quirk: in the symbol table, the subfunction (e.g., nmi_panic.cold.7) is nested inside the parent (nmi_panic). That function overlap confuses objtool, and causes it to get into an infinite loop in next_insn_same_func(). Here's Allan's description of the loop: "Objtool iterates through the instructions in nmi_panic using next_insn_same_func. Once it reaches the end of nmi_panic at 0x534 it jumps to 0x528 as that's the start of nmi_panic.cold.7. However, since the instructions starting at 0x528 are still associated with nmi_panic objtool will get stuck in a loop, continually jumping back to 0x528 after reaching 0x534." Fix it by shortening the length of the parent function so that the functions no longer overlap. Reported-and-analyzed-by: Allan Xavier Signed-off-by: Josh Poimboeuf Cc: Allan Xavier Cc: Andy Lutomirski Cc: Borislav Petkov Cc: Brian Gerst Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Thomas Gleixner Link: http://lkml.kernel.org/r/9e704c52bee651129b036be14feda317ae5606ae.1530136978.git.jpoimboe@redhat.com Signed-off-by: Ingo Molnar --- tools/objtool/elf.c | 41 ++++++++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 13 deletions(-) (limited to 'tools') diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 4e60e105583e..0d1acb704f64 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -302,19 +302,34 @@ static int read_symbols(struct elf *elf) continue; sym->pfunc = sym->cfunc = sym; coldstr = strstr(sym->name, ".cold."); - if (coldstr) { - coldstr[0] = '\0'; - pfunc = find_symbol_by_name(elf, sym->name); - coldstr[0] = '.'; - - if (!pfunc) { - WARN("%s(): can't find parent function", - sym->name); - goto err; - } - - sym->pfunc = pfunc; - pfunc->cfunc = sym; + if (!coldstr) + continue; + + coldstr[0] = '\0'; + pfunc = find_symbol_by_name(elf, sym->name); + coldstr[0] = '.'; + + if (!pfunc) { + WARN("%s(): can't find parent function", + sym->name); + goto err; + } + + sym->pfunc = pfunc; + pfunc->cfunc = sym; + + /* + * Unfortunately, -fnoreorder-functions puts the child + * inside the parent. Remove the overlap so we can + * have sane assumptions. + * + * Note that pfunc->len now no longer matches + * pfunc->sym.st_size. + */ + if (sym->sec == pfunc->sec && + sym->offset >= pfunc->offset && + sym->offset + sym->len == pfunc->offset + pfunc->len) { + pfunc->len -= sym->len; } } } -- cgit