forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
perf tests: Add breakpoint accounting/modify test
Adding test that: - detects the number of watch/break-points, skip test if any is missing - detects PERF_EVENT_IOC_MODIFY_ATTRIBUTES ioctl, skip test if it's missing - detects if watchpoints and breakpoints share same slots - create all possible watchpoints on cpu 0 - change one of it to breakpoint - in case wp and bp do not share slots, we create another watchpoint to ensure the slot accounting is correct Signed-off-by: Jiri Olsa <[email protected]> Cc: Alexander Shishkin <[email protected]> Cc: Arnaldo Carvalho de Melo <[email protected]> Cc: David Ahern <[email protected]> Cc: Frederic Weisbecker <[email protected]> Cc: Hari Bathini <[email protected]> Cc: Jin Yao <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Kan Liang <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Michael Ellerman <[email protected]> Cc: Milind Chabbi <[email protected]> Cc: Namhyung Kim <[email protected]> Cc: Oleg Nesterov <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Sukadev Bhattiprolu <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: Will Deacon <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Ingo Molnar <[email protected]>
- Loading branch information
Showing
4 changed files
with
201 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
/* | ||
* Powerpc needs __SANE_USERSPACE_TYPES__ before <linux/types.h> to select | ||
* 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu. | ||
*/ | ||
#define __SANE_USERSPACE_TYPES__ | ||
|
||
#include <stdlib.h> | ||
#include <stdio.h> | ||
#include <unistd.h> | ||
#include <string.h> | ||
#include <sys/ioctl.h> | ||
#include <time.h> | ||
#include <fcntl.h> | ||
#include <signal.h> | ||
#include <sys/mman.h> | ||
#include <linux/compiler.h> | ||
#include <linux/hw_breakpoint.h> | ||
#include <sys/ioctl.h> | ||
|
||
#include "tests.h" | ||
#include "debug.h" | ||
#include "perf.h" | ||
#include "cloexec.h" | ||
|
||
volatile long the_var; | ||
|
||
static noinline int test_function(void) | ||
{ | ||
return 0; | ||
} | ||
|
||
static int __event(bool is_x, void *addr, struct perf_event_attr *attr) | ||
{ | ||
int fd; | ||
|
||
memset(attr, 0, sizeof(struct perf_event_attr)); | ||
attr->type = PERF_TYPE_BREAKPOINT; | ||
attr->size = sizeof(struct perf_event_attr); | ||
|
||
attr->config = 0; | ||
attr->bp_type = is_x ? HW_BREAKPOINT_X : HW_BREAKPOINT_W; | ||
attr->bp_addr = (unsigned long) addr; | ||
attr->bp_len = sizeof(long); | ||
|
||
attr->sample_period = 1; | ||
attr->sample_type = PERF_SAMPLE_IP; | ||
|
||
attr->exclude_kernel = 1; | ||
attr->exclude_hv = 1; | ||
|
||
fd = sys_perf_event_open(attr, -1, 0, -1, | ||
perf_event_open_cloexec_flag()); | ||
if (fd < 0) { | ||
pr_debug("failed opening event %llx\n", attr->config); | ||
return TEST_FAIL; | ||
} | ||
|
||
return fd; | ||
} | ||
|
||
static int wp_event(void *addr, struct perf_event_attr *attr) | ||
{ | ||
return __event(false, addr, attr); | ||
} | ||
|
||
static int bp_event(void *addr, struct perf_event_attr *attr) | ||
{ | ||
return __event(true, addr, attr); | ||
} | ||
|
||
static int bp_accounting(int wp_cnt, int share) | ||
{ | ||
struct perf_event_attr attr, attr_mod, attr_new; | ||
int i, fd[wp_cnt], fd_wp, ret; | ||
|
||
for (i = 0; i < wp_cnt; i++) { | ||
fd[i] = wp_event((void *)&the_var, &attr); | ||
TEST_ASSERT_VAL("failed to create wp\n", fd[i] != -1); | ||
pr_debug("wp %d created\n", i); | ||
} | ||
|
||
attr_mod = attr; | ||
attr_mod.bp_type = HW_BREAKPOINT_X; | ||
attr_mod.bp_addr = (unsigned long) test_function; | ||
|
||
ret = ioctl(fd[0], PERF_EVENT_IOC_MODIFY_ATTRIBUTES, &attr_mod); | ||
TEST_ASSERT_VAL("failed to modify wp\n", ret == 0); | ||
|
||
pr_debug("wp 0 modified to bp\n"); | ||
|
||
if (!share) { | ||
fd_wp = wp_event((void *)&the_var, &attr_new); | ||
TEST_ASSERT_VAL("failed to create max wp\n", fd_wp != -1); | ||
pr_debug("wp max created\n"); | ||
} | ||
|
||
for (i = 0; i < wp_cnt; i++) | ||
close(fd[i]); | ||
|
||
return 0; | ||
} | ||
|
||
static int detect_cnt(bool is_x) | ||
{ | ||
struct perf_event_attr attr; | ||
void *addr = is_x ? test_function : (void *) &the_var; | ||
int fd[100], cnt = 0, i; | ||
|
||
while (1) { | ||
fd[cnt] = __event(is_x, addr, &attr); | ||
|
||
if (fd[cnt] < 0) | ||
break; | ||
|
||
if (cnt == 100) { | ||
pr_debug("way too many debug registers, fix the test\n"); | ||
return 0; | ||
} | ||
|
||
cnt++; | ||
} | ||
|
||
for (i = 0; i < cnt; i++) | ||
close(fd[i]); | ||
|
||
return cnt; | ||
} | ||
|
||
static int detect_ioctl(void) | ||
{ | ||
struct perf_event_attr attr; | ||
int fd, ret = 1; | ||
|
||
fd = wp_event((void *) &the_var, &attr); | ||
if (fd > 0) { | ||
ret = ioctl(fd, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, &attr); | ||
close(fd); | ||
} | ||
|
||
return ret ? 0 : 1; | ||
} | ||
|
||
static int detect_share(int wp_cnt, int bp_cnt) | ||
{ | ||
struct perf_event_attr attr; | ||
int i, fd[wp_cnt + bp_cnt], ret; | ||
|
||
for (i = 0; i < wp_cnt; i++) { | ||
fd[i] = wp_event((void *)&the_var, &attr); | ||
TEST_ASSERT_VAL("failed to create wp\n", fd[i] != -1); | ||
} | ||
|
||
for (; i < (bp_cnt + wp_cnt); i++) { | ||
fd[i] = bp_event((void *)test_function, &attr); | ||
if (fd[i] == -1) | ||
break; | ||
} | ||
|
||
ret = i != (bp_cnt + wp_cnt); | ||
|
||
while (i--) | ||
close(fd[i]); | ||
|
||
return ret; | ||
} | ||
|
||
/* | ||
* This test does following: | ||
* - detects the number of watch/break-points, | ||
* skip test if any is missing | ||
* - detects PERF_EVENT_IOC_MODIFY_ATTRIBUTES ioctl, | ||
* skip test if it's missing | ||
* - detects if watchpoints and breakpoints share | ||
* same slots | ||
* - create all possible watchpoints on cpu 0 | ||
* - change one of it to breakpoint | ||
* - in case wp and bp do not share slots, | ||
* we create another watchpoint to ensure | ||
* the slot accounting is correct | ||
*/ | ||
int test__bp_accounting(struct test *test __maybe_unused, int subtest __maybe_unused) | ||
{ | ||
int has_ioctl = detect_ioctl(); | ||
int wp_cnt = detect_cnt(false); | ||
int bp_cnt = detect_cnt(true); | ||
int share = detect_share(wp_cnt, bp_cnt); | ||
|
||
pr_debug("watchpoints count %d, breakpoints count %d, has_ioctl %d, share %d\n", | ||
wp_cnt, bp_cnt, has_ioctl, share); | ||
|
||
if (!wp_cnt || !bp_cnt || !has_ioctl) | ||
return TEST_SKIP; | ||
|
||
return bp_accounting(wp_cnt, share); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters