diff options
| author | Ingo Molnar <mingo@kernel.org> | 2015-10-06 09:04:10 +0200 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2015-10-06 09:04:10 +0200 |
| commit | 1c748dc2cbbe45d48572e395e11be677fbf7a28c (patch) | |
| tree | df5ec1da23e37e944805a4ca37021fdc2a9ac4aa /tools/perf/arch/x86/tests/rdpmc.c | |
| parent | e3b0ac1b7a8a590440a2030e7d10d48c59ab8a2a (diff) | |
| parent | 27bf90bf0690f55c3679bcc4c325823cf1cfd19d (diff) | |
Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core
Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo:
User visible changes:
- Switch the default callchain output mode to 'graph,0.5,caller', to make it
look like the default for other tools, reducing the learning curve for
people used to 'caller' based viewing. (Arnaldo Carvalho de Melo)
- Implement column based horizontal scrolling in the hists browser (top, report),
making it possible to use the TUI for things like 'perf mem report' where
there are many more columns than can fit in a terminal. (Arnaldo Carvalho de Melo)
- Support sorting by symbol_iaddr with perf.data files produced by
'perf mem record'. (Don Zickus)
- Display DATA_SRC sample type bit, i.e. when running 'perf evlist -v' the
"DATA_SRC" wasn't appearing when set, fix it to look like: (Jiri Olsa)
cpu/mem-loads/pp: ...SNIP... sample_type: IP|TID|TIME|ADDR|CPU|PERIOD|DATA_SRC
- Introduce the 'P' event modifier, meaning 'max precision level, please', i.e.:
$ perf record -e cycles:P usleep 1
Is now similar to:
$ perf record usleep 1
Useful, for instance, when specifying multiple events. (Jiri Olsa)
- Make 'perf -v' and 'perf -h' work. (Jiri Olsa)
- Fail properly when pattern matching fails to find a tracepoint, i.e.
'-e non:existent' was being correctly handled, with a proper error message
about that not being a valid event, but '-e non:existent*' wasn't,
fix it. (Jiri Olsa)
Infrastructure changes:
- Separate arch specific entries in 'perf test' and add an 'Intel CQM' one
to be fun on x86 only. (Matt Fleming)
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools/perf/arch/x86/tests/rdpmc.c')
| -rw-r--r-- | tools/perf/arch/x86/tests/rdpmc.c | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/tools/perf/arch/x86/tests/rdpmc.c b/tools/perf/arch/x86/tests/rdpmc.c new file mode 100644 index 000000000000..e7688214c7cf --- /dev/null +++ b/tools/perf/arch/x86/tests/rdpmc.c @@ -0,0 +1,174 @@ +#include <unistd.h> +#include <stdlib.h> +#include <signal.h> +#include <sys/mman.h> +#include <linux/types.h> +#include "perf.h" +#include "debug.h" +#include "tests/tests.h" +#include "cloexec.h" +#include "arch-tests.h" + +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); + rem = cyc & ((1 << time_shift) - 1); + 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; + char sbuf[STRERR_BUFSIZE]; + + sigfillset(&sa.sa_mask); + sa.sa_sigaction = segfault_handler; + sigaction(SIGSEGV, &sa, NULL); + + fd = sys_perf_event_open(&attr, 0, -1, -1, + perf_event_open_cloexec_flag()); + if (fd < 0) { + pr_err("Error: sys_perf_event_open() syscall returned " + "with %d (%s)\n", fd, + strerror_r(errno, sbuf, sizeof(sbuf))); + 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", + strerror_r(errno, sbuf, sizeof(sbuf))); + 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; +} + +int test__rdpmc(void) +{ + 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; +} |
