1e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/*
2e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Originally done by Vince Weaver <vincent.weaver@maine.edu> for
3e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * perf_event_tests (git://github.com/deater/perf_event_tests)
4e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */
5e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
6e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng/*
7e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * Powerpc needs __SANE_USERSPACE_TYPES__ before <linux/types.h> to select
8e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng * 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu.
9e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng */
10e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define __SANE_USERSPACE_TYPES__
11e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
12e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <stdlib.h>
13e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <stdio.h>
14e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <unistd.h>
15e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <string.h>
16e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <sys/ioctl.h>
17e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <time.h>
18e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <fcntl.h>
19e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <signal.h>
20e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <sys/mman.h>
21e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <linux/compiler.h>
22e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include <linux/hw_breakpoint.h>
23e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
24e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "tests.h"
25e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "debug.h"
26e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#include "perf.h"
27e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
28e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int overflows;
29e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
30e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng__attribute__ ((noinline))
31e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic int test_function(void)
32e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
33e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return time(NULL);
34e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
35e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
36e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic void sig_handler(int signum __maybe_unused,
37e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			siginfo_t *oh __maybe_unused,
38e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng			void *uc __maybe_unused)
39e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
40e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	overflows++;
41e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
42e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
43e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengstatic long long bp_count(int fd)
44e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
45e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	long long count;
46e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int ret;
47e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
48e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ret = read(fd, &count, sizeof(long long));
49e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (ret != sizeof(long long)) {
50e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		pr_debug("failed to read: %d\n", ret);
51e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return TEST_FAIL;
52e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
53e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
54e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return count;
55e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
56e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
57e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define EXECUTIONS 10000
58e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng#define THRESHOLD  100
59e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
60e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Chengint test__bp_signal_overflow(void)
61e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng{
62e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct perf_event_attr pe;
63e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	struct sigaction sa;
64e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	long long count;
65e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	int fd, i, fails = 0;
66e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
67e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	/* setup SIGIO signal handler */
68e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	memset(&sa, 0, sizeof(struct sigaction));
69e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sa.sa_sigaction = (void *) sig_handler;
70e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	sa.sa_flags = SA_SIGINFO;
71e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
72e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (sigaction(SIGIO, &sa, NULL) < 0) {
73e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		pr_debug("failed setting up signal handler\n");
74e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return TEST_FAIL;
75e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
76e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
77e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	memset(&pe, 0, sizeof(struct perf_event_attr));
78e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pe.type = PERF_TYPE_BREAKPOINT;
79e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pe.size = sizeof(struct perf_event_attr);
80e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
81e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pe.config = 0;
82e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pe.bp_type = HW_BREAKPOINT_X;
83e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pe.bp_addr = (unsigned long) test_function;
84e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pe.bp_len = sizeof(long);
85e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
86e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pe.sample_period = THRESHOLD;
87e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pe.sample_type = PERF_SAMPLE_IP;
88e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pe.wakeup_events = 1;
89e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
90e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pe.disabled = 1;
91e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pe.exclude_kernel = 1;
92e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pe.exclude_hv = 1;
93e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
94e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	fd = sys_perf_event_open(&pe, 0, -1, -1, 0);
95e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (fd < 0) {
96e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		pr_debug("failed opening event %llx\n", pe.config);
97e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		return TEST_FAIL;
98e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
99e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
100e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	fcntl(fd, F_SETFL, O_RDWR|O_NONBLOCK|O_ASYNC);
101e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	fcntl(fd, F_SETSIG, SIGIO);
102e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	fcntl(fd, F_SETOWN, getpid());
103e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
104e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ioctl(fd, PERF_EVENT_IOC_RESET, 0);
105e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
106e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
107e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	for (i = 0; i < EXECUTIONS; i++)
108e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		test_function();
109e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
110e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
111e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
112e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	count = bp_count(fd);
113e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
114e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	close(fd);
115e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
116e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	pr_debug("count %lld, overflow %d\n",
117e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		 count, overflows);
118e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
119e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (count != EXECUTIONS) {
120e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		pr_debug("\tWrong number of executions %lld != %d\n",
121e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		count, EXECUTIONS);
122e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		fails++;
123e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
124e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
125e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	if (overflows != EXECUTIONS / THRESHOLD) {
126e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		pr_debug("\tWrong number of overflows %d != %d\n",
127e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		overflows, EXECUTIONS / THRESHOLD);
128e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng		fails++;
129e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	}
130e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng
131e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng	return fails ? TEST_FAIL : TEST_OK;
132e6e8a0bd7cffcc9ae2e0e75546fb12a19213d4aeBen Cheng}
133