History

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

Jiri Olsa committed 8 years ago

Commit 032db281 parent 5f970524 files · +201 −0Browse files

Unified · Split

4 files
  1. tools/perf/tests/Build +1 −0
  2. tools/perf/tests/bp_account.c +195 −0
  3. tools/perf/tests/builtin-test.c +4 −0
  4. tools/perf/tests/tests.h +1 −0
tools/perf/tests/Build+1−0
@@ -20,6 +20,7 @@ perf-y += hists_cumulate.o · 19 unmodified lines
2020 perf-y += python-use.o
2121 perf-y += bp_signal.o
2222 perf-y += bp_signal_overflow.o
23+perf-y += bp_account.o
2324 perf-y += task-exit.o
2425 perf-y += sw-clock.o
2526 perf-y += mmap-thread-lookup.o
tools/perf/tests/bp_account.c+195−0
@@ -0,0 +1,195 @@
1+/*
2+ * Powerpc needs __SANE_USERSPACE_TYPES__ before <linux/types.h> to select
3+ * 'int-ll64.h' and avoid compile warnings when printing __u64 with %llu.
4+ */
5+#define __SANE_USERSPACE_TYPES__
6+
7+#include <stdlib.h>
8+#include <stdio.h>
9+#include <unistd.h>
10+#include <string.h>
11+#include <sys/ioctl.h>
12+#include <time.h>
13+#include <fcntl.h>
14+#include <signal.h>
15+#include <sys/mman.h>
16+#include <linux/compiler.h>
17+#include <linux/hw_breakpoint.h>
18+#include <sys/ioctl.h>
19+
20+#include "tests.h"
21+#include "debug.h"
22+#include "perf.h"
23+#include "cloexec.h"
24+
25+volatile long the_var;
26+
27+static noinline int test_function(void)
28+{
29+ return 0;
30+}
31+
32+static int __event(bool is_x, void *addr, struct perf_event_attr *attr)
33+{
34+ int fd;
35+
36+ memset(attr, 0, sizeof(struct perf_event_attr));
37+ attr->type = PERF_TYPE_BREAKPOINT;
38+ attr->size = sizeof(struct perf_event_attr);
39+
40+ attr->config = 0;
41+ attr->bp_type = is_x ? HW_BREAKPOINT_X : HW_BREAKPOINT_W;
42+ attr->bp_addr = (unsigned long) addr;
43+ attr->bp_len = sizeof(long);
44+
45+ attr->sample_period = 1;
46+ attr->sample_type = PERF_SAMPLE_IP;
47+
48+ attr->exclude_kernel = 1;
49+ attr->exclude_hv = 1;
50+
51+ fd = sys_perf_event_open(attr, -1, 0, -1,
52+ perf_event_open_cloexec_flag());
53+ if (fd < 0) {
54+ pr_debug("failed opening event %llx\n", attr->config);
55+ return TEST_FAIL;
56+ }
57+
58+ return fd;
59+}
60+
61+static int wp_event(void *addr, struct perf_event_attr *attr)
62+{
63+ return __event(false, addr, attr);
64+}
65+
66+static int bp_event(void *addr, struct perf_event_attr *attr)
67+{
68+ return __event(true, addr, attr);
69+}
70+
71+static int bp_accounting(int wp_cnt, int share)
72+{
73+ struct perf_event_attr attr, attr_mod, attr_new;
74+ int i, fd[wp_cnt], fd_wp, ret;
75+
76+ for (i = 0; i < wp_cnt; i++) {
77+ fd[i] = wp_event((void *)&the_var, &attr);
78+ TEST_ASSERT_VAL("failed to create wp\n", fd[i] != -1);
79+ pr_debug("wp %d created\n", i);
80+ }
81+
82+ attr_mod = attr;
83+ attr_mod.bp_type = HW_BREAKPOINT_X;
84+ attr_mod.bp_addr = (unsigned long) test_function;
85+
86+ ret = ioctl(fd[0], PERF_EVENT_IOC_MODIFY_ATTRIBUTES, &attr_mod);
87+ TEST_ASSERT_VAL("failed to modify wp\n", ret == 0);
88+
89+ pr_debug("wp 0 modified to bp\n");
90+
91+ if (!share) {
92+ fd_wp = wp_event((void *)&the_var, &attr_new);
93+ TEST_ASSERT_VAL("failed to create max wp\n", fd_wp != -1);
94+ pr_debug("wp max created\n");
95+ }
96+
97+ for (i = 0; i < wp_cnt; i++)
98+ close(fd[i]);
99+
100+ return 0;
101+}
102+
103+static int detect_cnt(bool is_x)
104+{
105+ struct perf_event_attr attr;
106+ void *addr = is_x ? test_function : (void *) &the_var;
107+ int fd[100], cnt = 0, i;
108+
109+ while (1) {
110+ fd[cnt] = __event(is_x, addr, &attr);
111+
112+ if (fd[cnt] < 0)
113+ break;
114+
115+ if (cnt == 100) {
116+ pr_debug("way too many debug registers, fix the test\n");
117+ return 0;
118+ }
119+
120+ cnt++;
121+ }
122+
123+ for (i = 0; i < cnt; i++)
124+ close(fd[i]);
125+
126+ return cnt;
127+}
128+
129+static int detect_ioctl(void)
130+{
131+ struct perf_event_attr attr;
132+ int fd, ret = 1;
133+
134+ fd = wp_event((void *) &the_var, &attr);
135+ if (fd > 0) {
136+ ret = ioctl(fd, PERF_EVENT_IOC_MODIFY_ATTRIBUTES, &attr);
137+ close(fd);
138+ }
139+
140+ return ret ? 0 : 1;
141+}
142+
143+static int detect_share(int wp_cnt, int bp_cnt)
144+{
145+ struct perf_event_attr attr;
146+ int i, fd[wp_cnt + bp_cnt], ret;
147+
148+ for (i = 0; i < wp_cnt; i++) {
149+ fd[i] = wp_event((void *)&the_var, &attr);
150+ TEST_ASSERT_VAL("failed to create wp\n", fd[i] != -1);
151+ }
152+
153+ for (; i < (bp_cnt + wp_cnt); i++) {
154+ fd[i] = bp_event((void *)test_function, &attr);
155+ if (fd[i] == -1)
156+ break;
157+ }
158+
159+ ret = i != (bp_cnt + wp_cnt);
160+
161+ while (i--)
162+ close(fd[i]);
163+
164+ return ret;
165+}
166+
167+/*
168+ * This test does following:
169+ * - detects the number of watch/break-points,
170+ * skip test if any is missing
171+ * - detects PERF_EVENT_IOC_MODIFY_ATTRIBUTES ioctl,
172+ * skip test if it's missing
173+ * - detects if watchpoints and breakpoints share
174+ * same slots
175+ * - create all possible watchpoints on cpu 0
176+ * - change one of it to breakpoint
177+ * - in case wp and bp do not share slots,
178+ * we create another watchpoint to ensure
179+ * the slot accounting is correct
180+ */
181+int test__bp_accounting(struct test *test __maybe_unused, int subtest __maybe_unused)
182+{
183+ int has_ioctl = detect_ioctl();
184+ int wp_cnt = detect_cnt(false);
185+ int bp_cnt = detect_cnt(true);
186+ int share = detect_share(wp_cnt, bp_cnt);
187+
188+ pr_debug("watchpoints count %d, breakpoints count %d, has_ioctl %d, share %d\n",
189+ wp_cnt, bp_cnt, has_ioctl, share);
190+
191+ if (!wp_cnt || !bp_cnt || !has_ioctl)
192+ return TEST_SKIP;
193+
194+ return bp_accounting(wp_cnt, share);
195+}
tools/perf/tests/builtin-test.c+4−0
@@ -115,6 +115,10 @@ static struct test generic_tests[] = { · 114 unmodified lines
115115 .func = test__bp_signal_overflow,
116116 .is_supported = test__bp_signal_is_supported,
117117 },
118+ {
119+ .desc = "Breakpoint accounting",
120+ .func = test__bp_accounting,
121+ },
118122 {
119123 .desc = "Number of exit events of a simple workload",
120124 .func = test__task_exit,
tools/perf/tests/tests.h+1−0
@@ -58,6 +58,7 @@ int test__hists_link(struct test *test, int subtest); · 57 unmodified lines
5858 int test__python_use(struct test *test, int subtest);
5959 int test__bp_signal(struct test *test, int subtest);
6060 int test__bp_signal_overflow(struct test *test, int subtest);
61+int test__bp_accounting(struct test *test, int subtest);
6162 int test__task_exit(struct test *test, int subtest);
6263 int test__mem(struct test *test, int subtest);
6364 int test__sw_clock_freq(struct test *test, int subtest);