2016-07-07 14:35:50 +00:00
|
|
|
#include <errno.h>
|
2012-11-10 00:46:46 +00:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <sys/mman.h>
|
2016-07-07 14:35:50 +00:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/wait.h>
|
2014-04-25 19:31:02 +00:00
|
|
|
#include <linux/types.h>
|
2012-11-10 00:46:46 +00:00
|
|
|
#include "perf.h"
|
|
|
|
#include "debug.h"
|
2015-10-05 14:40:20 +00:00
|
|
|
#include "tests/tests.h"
|
2014-06-30 20:28:47 +00:00
|
|
|
#include "cloexec.h"
|
2016-07-07 14:35:50 +00:00
|
|
|
#include "util.h"
|
2015-10-05 14:40:20 +00:00
|
|
|
#include "arch-tests.h"
|
2012-11-10 00:46:46 +00:00
|
|
|
|
|
|
|
static u64 rdpmc(unsigned int counter)
|
|
|
|
{
|
|
|
|
unsigned int low, high;
|
|
|
|
|
|
|
|
asm volatile("rdpmc" : "=a" (low), "=d" (high) : "c" (counter));
|
|
|
|
|
|
|
|
return low | ((u64)high) << 32;
|
|
|
|
}
|
|
|
|
|
|
|
|
static u64 rdtsc(void)
|
|
|
|
{
|
|
|
|
unsigned int low, high;
|
|
|
|
|
|
|
|
asm volatile("rdtsc" : "=a" (low), "=d" (high));
|
|
|
|
|
|
|
|
return low | ((u64)high) << 32;
|
|
|
|
}
|
|
|
|
|
|
|
|
static u64 mmap_read_self(void *addr)
|
|
|
|
{
|
|
|
|
struct perf_event_mmap_page *pc = addr;
|
|
|
|
u32 seq, idx, time_mult = 0, time_shift = 0;
|
|
|
|
u64 count, cyc = 0, time_offset = 0, enabled, running, delta;
|
|
|
|
|
|
|
|
do {
|
|
|
|
seq = pc->lock;
|
|
|
|
barrier();
|
|
|
|
|
|
|
|
enabled = pc->time_enabled;
|
|
|
|
running = pc->time_running;
|
|
|
|
|
|
|
|
if (enabled != running) {
|
|
|
|
cyc = rdtsc();
|
|
|
|
time_mult = pc->time_mult;
|
|
|
|
time_shift = pc->time_shift;
|
|
|
|
time_offset = pc->time_offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
idx = pc->index;
|
|
|
|
count = pc->offset;
|
|
|
|
if (idx)
|
|
|
|
count += rdpmc(idx - 1);
|
|
|
|
|
|
|
|
barrier();
|
|
|
|
} while (pc->lock != seq);
|
|
|
|
|
|
|
|
if (enabled != running) {
|
|
|
|
u64 quot, rem;
|
|
|
|
|
|
|
|
quot = (cyc >> time_shift);
|
2016-03-07 19:44:42 +00:00
|
|
|
rem = cyc & (((u64)1 << time_shift) - 1);
|
2012-11-10 00:46:46 +00:00
|
|
|
delta = time_offset + quot * time_mult +
|
|
|
|
((rem * time_mult) >> time_shift);
|
|
|
|
|
|
|
|
enabled += delta;
|
|
|
|
if (idx)
|
|
|
|
running += delta;
|
|
|
|
|
|
|
|
quot = count / running;
|
|
|
|
rem = count % running;
|
|
|
|
count = quot * enabled + (rem * enabled) / running;
|
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the RDPMC instruction faults then signal this back to the test parent task:
|
|
|
|
*/
|
|
|
|
static void segfault_handler(int sig __maybe_unused,
|
|
|
|
siginfo_t *info __maybe_unused,
|
|
|
|
void *uc __maybe_unused)
|
|
|
|
{
|
|
|
|
exit(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int __test__rdpmc(void)
|
|
|
|
{
|
|
|
|
volatile int tmp = 0;
|
|
|
|
u64 i, loops = 1000;
|
|
|
|
int n;
|
|
|
|
int fd;
|
|
|
|
void *addr;
|
|
|
|
struct perf_event_attr attr = {
|
|
|
|
.type = PERF_TYPE_HARDWARE,
|
|
|
|
.config = PERF_COUNT_HW_INSTRUCTIONS,
|
|
|
|
.exclude_kernel = 1,
|
|
|
|
};
|
|
|
|
u64 delta_sum = 0;
|
|
|
|
struct sigaction sa;
|
2014-08-14 02:22:45 +00:00
|
|
|
char sbuf[STRERR_BUFSIZE];
|
2012-11-10 00:46:46 +00:00
|
|
|
|
|
|
|
sigfillset(&sa.sa_mask);
|
|
|
|
sa.sa_sigaction = segfault_handler;
|
2016-03-02 12:55:22 +00:00
|
|
|
sa.sa_flags = 0;
|
2012-11-10 00:46:46 +00:00
|
|
|
sigaction(SIGSEGV, &sa, NULL);
|
|
|
|
|
2014-06-30 20:28:47 +00:00
|
|
|
fd = sys_perf_event_open(&attr, 0, -1, -1,
|
|
|
|
perf_event_open_cloexec_flag());
|
2012-11-10 00:46:46 +00:00
|
|
|
if (fd < 0) {
|
|
|
|
pr_err("Error: sys_perf_event_open() syscall returned "
|
2014-08-14 02:22:45 +00:00
|
|
|
"with %d (%s)\n", fd,
|
tools: Introduce str_error_r()
The tools so far have been using the strerror_r() GNU variant, that
returns a string, be it the buffer passed or something else.
But that, besides being tricky in cases where we expect that the
function using strerror_r() returns the error formatted in a provided
buffer (we have to check if it returned something else and copy that
instead), breaks the build on systems not using glibc, like Alpine
Linux, where musl libc is used.
So, introduce yet another wrapper, str_error_r(), that has the GNU
interface, but uses the portable XSI variant of strerror_r(), so that
users rest asured that the provided buffer is used and it is what is
returned.
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/n/tip-d4t42fnf48ytlk8rjxs822tf@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-07-06 14:56:20 +00:00
|
|
|
str_error_r(errno, sbuf, sizeof(sbuf)));
|
2012-11-10 00:46:46 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
addr = mmap(NULL, page_size, PROT_READ, MAP_SHARED, fd, 0);
|
|
|
|
if (addr == (void *)(-1)) {
|
|
|
|
pr_err("Error: mmap() syscall returned with (%s)\n",
|
tools: Introduce str_error_r()
The tools so far have been using the strerror_r() GNU variant, that
returns a string, be it the buffer passed or something else.
But that, besides being tricky in cases where we expect that the
function using strerror_r() returns the error formatted in a provided
buffer (we have to check if it returned something else and copy that
instead), breaks the build on systems not using glibc, like Alpine
Linux, where musl libc is used.
So, introduce yet another wrapper, str_error_r(), that has the GNU
interface, but uses the portable XSI variant of strerror_r(), so that
users rest asured that the provided buffer is used and it is what is
returned.
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/n/tip-d4t42fnf48ytlk8rjxs822tf@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2016-07-06 14:56:20 +00:00
|
|
|
str_error_r(errno, sbuf, sizeof(sbuf)));
|
2012-11-10 00:46:46 +00:00
|
|
|
goto out_close;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (n = 0; n < 6; n++) {
|
|
|
|
u64 stamp, now, delta;
|
|
|
|
|
|
|
|
stamp = mmap_read_self(addr);
|
|
|
|
|
|
|
|
for (i = 0; i < loops; i++)
|
|
|
|
tmp++;
|
|
|
|
|
|
|
|
now = mmap_read_self(addr);
|
|
|
|
loops *= 10;
|
|
|
|
|
|
|
|
delta = now - stamp;
|
|
|
|
pr_debug("%14d: %14Lu\n", n, (long long)delta);
|
|
|
|
|
|
|
|
delta_sum += delta;
|
|
|
|
}
|
|
|
|
|
|
|
|
munmap(addr, page_size);
|
|
|
|
pr_debug(" ");
|
|
|
|
out_close:
|
|
|
|
close(fd);
|
|
|
|
|
|
|
|
if (!delta_sum)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
perf tests: Pass the subtest index to each test routine
Some tests have sub-tests we want to run, so allow passing this.
Wang tried to avoid having to touch all tests, but then, having the
test.func in an anonymous union makes the build fail on older compilers,
like the one in RHEL6, where:
test a = {
.func = foo,
};
fails.
To fix it leave the func pointer in the main structure and pass the subtest
index to all tests, end result function is the same, but we have just one
function pointer, not two, with and without the subtest index as an argument.
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: David Ahern <dsahern@gmail.com>
Cc: Jiri Olsa <jolsa@redhat.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Wang Nan <wangnan0@huawei.com>
Link: http://lkml.kernel.org/n/tip-5genj0ficwdmelpoqlds0u4y@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
2015-11-19 15:01:48 +00:00
|
|
|
int test__rdpmc(int subtest __maybe_unused)
|
2012-11-10 00:46:46 +00:00
|
|
|
{
|
|
|
|
int status = 0;
|
|
|
|
int wret = 0;
|
|
|
|
int ret;
|
|
|
|
int pid;
|
|
|
|
|
|
|
|
pid = fork();
|
|
|
|
if (pid < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!pid) {
|
|
|
|
ret = __test__rdpmc();
|
|
|
|
|
|
|
|
exit(ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
wret = waitpid(pid, &status, 0);
|
|
|
|
if (wret < 0 || status)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|