Commit 8fd34e1c authored by Wang Nan's avatar Wang Nan Committed by Arnaldo Carvalho de Melo

perf test: Improve bp_signal

Will Deacon [1] has some question on patch [2]. This patch improves
test__bp_signal so we can test:

 1. A watchpoint and a breakpoint that fire on the same instruction
 2. Nested signals

Test result:

 On x86_64 and ARM64 (result are similar with patch [2] on ARM64):

  # ./perf test -v signal
  17: Test breakpoint overflow signal handler                  :
  --- start ---
  test child forked, pid 10213
  count1 1, count2 3, count3 2, overflow 3, overflows_2 3
  test child finished with 0
  ---- end ----
  Test breakpoint overflow signal handler: Ok

So at least 2 cases Will doubted are handled correctly.

[1] http://lkml.kernel.org/g/20160104165535.GI1616@arm.com
[2] http://lkml.kernel.org/g/1450921362-198371-1-git-send-email-wangnan0@huawei.comSigned-off-by: default avatarWang Nan <wangnan0@huawei.com>
Cc: Alexei Starovoitov <ast@kernel.org>
Cc: Brendan Gregg <brendan.d.gregg@gmail.com>
Cc: Daniel Borkmann <daniel@iogearbox.net>
Cc: He Kuang <hekuang@huawei.com>
Cc: Li Zefan <lizefan@huawei.com>
Cc: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Will Deacon <will.deacon@arm.com>
Cc: pi3orama@163.com
Link: http://lkml.kernel.org/r/1453715801-7732-9-git-send-email-wangnan0@huawei.comSigned-off-by: default avatarJiri Olsa <jolsa@kernel.org>
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 6a7d550e
...@@ -29,14 +29,59 @@ ...@@ -29,14 +29,59 @@
static int fd1; static int fd1;
static int fd2; static int fd2;
static int fd3;
static int overflows; static int overflows;
static int overflows_2;
volatile long the_var;
/*
* Use ASM to ensure watchpoint and breakpoint can be triggered
* at one instruction.
*/
#if defined (__x86_64__)
extern void __test_function(volatile long *ptr);
asm (
".globl __test_function\n"
"__test_function:\n"
"incq (%rdi)\n"
"ret\n");
#elif defined (__aarch64__)
extern void __test_function(volatile long *ptr);
asm (
".globl __test_function\n"
"__test_function:\n"
"str x30, [x0]\n"
"ret\n");
#else
static void __test_function(volatile long *ptr)
{
*ptr = 0x1234;
}
#endif
__attribute__ ((noinline)) __attribute__ ((noinline))
static int test_function(void) static int test_function(void)
{ {
__test_function(&the_var);
the_var++;
return time(NULL); return time(NULL);
} }
static void sig_handler_2(int signum __maybe_unused,
siginfo_t *oh __maybe_unused,
void *uc __maybe_unused)
{
overflows_2++;
if (overflows_2 > 10) {
ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
}
}
static void sig_handler(int signum __maybe_unused, static void sig_handler(int signum __maybe_unused,
siginfo_t *oh __maybe_unused, siginfo_t *oh __maybe_unused,
void *uc __maybe_unused) void *uc __maybe_unused)
...@@ -54,10 +99,11 @@ static void sig_handler(int signum __maybe_unused, ...@@ -54,10 +99,11 @@ static void sig_handler(int signum __maybe_unused,
*/ */
ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0); ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0); ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
} }
} }
static int bp_event(void *fn, int setup_signal) static int __event(bool is_x, void *addr, int signal)
{ {
struct perf_event_attr pe; struct perf_event_attr pe;
int fd; int fd;
...@@ -67,8 +113,8 @@ static int bp_event(void *fn, int setup_signal) ...@@ -67,8 +113,8 @@ static int bp_event(void *fn, int setup_signal)
pe.size = sizeof(struct perf_event_attr); pe.size = sizeof(struct perf_event_attr);
pe.config = 0; pe.config = 0;
pe.bp_type = HW_BREAKPOINT_X; pe.bp_type = is_x ? HW_BREAKPOINT_X : HW_BREAKPOINT_W;
pe.bp_addr = (unsigned long) fn; pe.bp_addr = (unsigned long) addr;
pe.bp_len = sizeof(long); pe.bp_len = sizeof(long);
pe.sample_period = 1; pe.sample_period = 1;
...@@ -86,17 +132,25 @@ static int bp_event(void *fn, int setup_signal) ...@@ -86,17 +132,25 @@ static int bp_event(void *fn, int setup_signal)
return TEST_FAIL; return TEST_FAIL;
} }
if (setup_signal) { fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC); fcntl(fd, F_SETSIG, signal);
fcntl(fd, F_SETSIG, SIGIO); fcntl(fd, F_SETOWN, getpid());
fcntl(fd, F_SETOWN, getpid());
}
ioctl(fd, PERF_EVENT_IOC_RESET, 0); ioctl(fd, PERF_EVENT_IOC_RESET, 0);
return fd; return fd;
} }
static int bp_event(void *addr, int signal)
{
return __event(true, addr, signal);
}
static int wp_event(void *addr, int signal)
{
return __event(false, addr, signal);
}
static long long bp_count(int fd) static long long bp_count(int fd)
{ {
long long count; long long count;
...@@ -114,7 +168,7 @@ static long long bp_count(int fd) ...@@ -114,7 +168,7 @@ static long long bp_count(int fd)
int test__bp_signal(int subtest __maybe_unused) int test__bp_signal(int subtest __maybe_unused)
{ {
struct sigaction sa; struct sigaction sa;
long long count1, count2; long long count1, count2, count3;
/* setup SIGIO signal handler */ /* setup SIGIO signal handler */
memset(&sa, 0, sizeof(struct sigaction)); memset(&sa, 0, sizeof(struct sigaction));
...@@ -126,21 +180,52 @@ int test__bp_signal(int subtest __maybe_unused) ...@@ -126,21 +180,52 @@ int test__bp_signal(int subtest __maybe_unused)
return TEST_FAIL; return TEST_FAIL;
} }
sa.sa_sigaction = (void *) sig_handler_2;
if (sigaction(SIGUSR1, &sa, NULL) < 0) {
pr_debug("failed setting up signal handler 2\n");
return TEST_FAIL;
}
/* /*
* We create following events: * We create following events:
* *
* fd1 - breakpoint event on test_function with SIGIO * fd1 - breakpoint event on __test_function with SIGIO
* signal configured. We should get signal * signal configured. We should get signal
* notification each time the breakpoint is hit * notification each time the breakpoint is hit
* *
* fd2 - breakpoint event on sig_handler without SIGIO * fd2 - breakpoint event on sig_handler with SIGUSR1
* configured. We should get SIGUSR1 each time when
* breakpoint is hit
*
* fd3 - watchpoint event on __test_function with SIGIO
* configured. * configured.
* *
* Following processing should happen: * Following processing should happen:
* - execute test_function * Exec: Action: Result:
* - fd1 event breakpoint hit -> count1 == 1 * incq (%rdi) - fd1 event breakpoint hit -> count1 == 1
* - SIGIO is delivered -> overflows == 1 * - SIGIO is delivered
* - fd2 event breakpoint hit -> count2 == 1 * sig_handler - fd2 event breakpoint hit -> count2 == 1
* - SIGUSR1 is delivered
* sig_handler_2 -> overflows_2 == 1 (nested signal)
* sys_rt_sigreturn - return from sig_handler_2
* overflows++ -> overflows = 1
* sys_rt_sigreturn - return from sig_handler
* incq (%rdi) - fd3 event watchpoint hit -> count3 == 1 (wp and bp in one insn)
* - SIGIO is delivered
* sig_handler - fd2 event breakpoint hit -> count2 == 2
* - SIGUSR1 is delivered
* sig_handler_2 -> overflows_2 == 2 (nested signal)
* sys_rt_sigreturn - return from sig_handler_2
* overflows++ -> overflows = 2
* sys_rt_sigreturn - return from sig_handler
* the_var++ - fd3 event watchpoint hit -> count3 == 2 (standalone watchpoint)
* - SIGIO is delivered
* sig_handler - fd2 event breakpoint hit -> count2 == 3
* - SIGUSR1 is delivered
* sig_handler_2 -> overflows_2 == 3 (nested signal)
* sys_rt_sigreturn - return from sig_handler_2
* overflows++ -> overflows == 3
* sys_rt_sigreturn - return from sig_handler
* *
* The test case check following error conditions: * The test case check following error conditions:
* - we get stuck in signal handler because of debug * - we get stuck in signal handler because of debug
...@@ -152,11 +237,13 @@ int test__bp_signal(int subtest __maybe_unused) ...@@ -152,11 +237,13 @@ int test__bp_signal(int subtest __maybe_unused)
* *
*/ */
fd1 = bp_event(test_function, 1); fd1 = bp_event(__test_function, SIGIO);
fd2 = bp_event(sig_handler, 0); fd2 = bp_event(sig_handler, SIGUSR1);
fd3 = wp_event((void *)&the_var, SIGIO);
ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0); ioctl(fd1, PERF_EVENT_IOC_ENABLE, 0);
ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0); ioctl(fd2, PERF_EVENT_IOC_ENABLE, 0);
ioctl(fd3, PERF_EVENT_IOC_ENABLE, 0);
/* /*
* Kick off the test by trigering 'fd1' * Kick off the test by trigering 'fd1'
...@@ -166,15 +253,18 @@ int test__bp_signal(int subtest __maybe_unused) ...@@ -166,15 +253,18 @@ int test__bp_signal(int subtest __maybe_unused)
ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0); ioctl(fd1, PERF_EVENT_IOC_DISABLE, 0);
ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0); ioctl(fd2, PERF_EVENT_IOC_DISABLE, 0);
ioctl(fd3, PERF_EVENT_IOC_DISABLE, 0);
count1 = bp_count(fd1); count1 = bp_count(fd1);
count2 = bp_count(fd2); count2 = bp_count(fd2);
count3 = bp_count(fd3);
close(fd1); close(fd1);
close(fd2); close(fd2);
close(fd3);
pr_debug("count1 %lld, count2 %lld, overflow %d\n", pr_debug("count1 %lld, count2 %lld, count3 %lld, overflow %d, overflows_2 %d\n",
count1, count2, overflows); count1, count2, count3, overflows, overflows_2);
if (count1 != 1) { if (count1 != 1) {
if (count1 == 11) if (count1 == 11)
...@@ -183,12 +273,18 @@ int test__bp_signal(int subtest __maybe_unused) ...@@ -183,12 +273,18 @@ int test__bp_signal(int subtest __maybe_unused)
pr_debug("failed: wrong count for bp1%lld\n", count1); pr_debug("failed: wrong count for bp1%lld\n", count1);
} }
if (overflows != 1) if (overflows != 3)
pr_debug("failed: wrong overflow hit\n"); pr_debug("failed: wrong overflow hit\n");
if (count2 != 1) if (overflows_2 != 3)
pr_debug("failed: wrong overflow_2 hit\n");
if (count2 != 3)
pr_debug("failed: wrong count for bp2\n"); pr_debug("failed: wrong count for bp2\n");
return count1 == 1 && overflows == 1 && count2 == 1 ? if (count3 != 2)
pr_debug("failed: wrong count for bp3\n");
return count1 == 1 && overflows == 3 && count2 == 3 && overflows_2 == 3 && count3 == 2 ?
TEST_OK : TEST_FAIL; TEST_OK : TEST_FAIL;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment