1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Test backward bit in event attribute, read ring buffer from end to
4  * beginning
5  */
6 
7 #include <perf.h>
8 #include <evlist.h>
9 #include <sys/prctl.h>
10 #include "tests.h"
11 #include "debug.h"
12 #include <errno.h>
13 
14 #define NR_ITERS 111
15 
testcase(void)16 static void testcase(void)
17 {
18 	int i;
19 
20 	for (i = 0; i < NR_ITERS; i++) {
21 		char proc_name[10];
22 
23 		snprintf(proc_name, sizeof(proc_name), "p:%d\n", i);
24 		prctl(PR_SET_NAME, proc_name);
25 	}
26 }
27 
count_samples(struct perf_evlist * evlist,int * sample_count,int * comm_count)28 static int count_samples(struct perf_evlist *evlist, int *sample_count,
29 			 int *comm_count)
30 {
31 	int i;
32 
33 	for (i = 0; i < evlist->nr_mmaps; i++) {
34 		struct perf_mmap *map = &evlist->overwrite_mmap[i];
35 		union perf_event *event;
36 
37 		perf_mmap__read_init(map);
38 		while ((event = perf_mmap__read_event(map)) != NULL) {
39 			const u32 type = event->header.type;
40 
41 			switch (type) {
42 			case PERF_RECORD_SAMPLE:
43 				(*sample_count)++;
44 				break;
45 			case PERF_RECORD_COMM:
46 				(*comm_count)++;
47 				break;
48 			default:
49 				pr_err("Unexpected record of type %d\n", type);
50 				return TEST_FAIL;
51 			}
52 		}
53 		perf_mmap__read_done(map);
54 	}
55 	return TEST_OK;
56 }
57 
do_test(struct perf_evlist * evlist,int mmap_pages,int * sample_count,int * comm_count)58 static int do_test(struct perf_evlist *evlist, int mmap_pages,
59 		   int *sample_count, int *comm_count)
60 {
61 	int err;
62 	char sbuf[STRERR_BUFSIZE];
63 
64 	err = perf_evlist__mmap(evlist, mmap_pages);
65 	if (err < 0) {
66 		pr_debug("perf_evlist__mmap: %s\n",
67 			 str_error_r(errno, sbuf, sizeof(sbuf)));
68 		return TEST_FAIL;
69 	}
70 
71 	perf_evlist__enable(evlist);
72 	testcase();
73 	perf_evlist__disable(evlist);
74 
75 	err = count_samples(evlist, sample_count, comm_count);
76 	perf_evlist__munmap(evlist);
77 	return err;
78 }
79 
80 
test__backward_ring_buffer(struct test * test __maybe_unused,int subtest __maybe_unused)81 int test__backward_ring_buffer(struct test *test __maybe_unused, int subtest __maybe_unused)
82 {
83 	int ret = TEST_SKIP, err, sample_count = 0, comm_count = 0;
84 	char pid[16], sbuf[STRERR_BUFSIZE];
85 	struct perf_evlist *evlist;
86 	struct perf_evsel *evsel __maybe_unused;
87 	struct parse_events_error parse_error;
88 	struct record_opts opts = {
89 		.target = {
90 			.uid = UINT_MAX,
91 			.uses_mmap = true,
92 		},
93 		.freq	      = 0,
94 		.mmap_pages   = 256,
95 		.default_interval = 1,
96 	};
97 
98 	snprintf(pid, sizeof(pid), "%d", getpid());
99 	pid[sizeof(pid) - 1] = '\0';
100 	opts.target.tid = opts.target.pid = pid;
101 
102 	evlist = perf_evlist__new();
103 	if (!evlist) {
104 		pr_debug("Not enough memory to create evlist\n");
105 		return TEST_FAIL;
106 	}
107 
108 	err = perf_evlist__create_maps(evlist, &opts.target);
109 	if (err < 0) {
110 		pr_debug("Not enough memory to create thread/cpu maps\n");
111 		goto out_delete_evlist;
112 	}
113 
114 	bzero(&parse_error, sizeof(parse_error));
115 	/*
116 	 * Set backward bit, ring buffer should be writing from end. Record
117 	 * it in aux evlist
118 	 */
119 	err = parse_events(evlist, "syscalls:sys_enter_prctl/overwrite/", &parse_error);
120 	if (err) {
121 		pr_debug("Failed to parse tracepoint event, try use root\n");
122 		ret = TEST_SKIP;
123 		goto out_delete_evlist;
124 	}
125 
126 	perf_evlist__config(evlist, &opts, NULL);
127 
128 	err = perf_evlist__open(evlist);
129 	if (err < 0) {
130 		pr_debug("perf_evlist__open: %s\n",
131 			 str_error_r(errno, sbuf, sizeof(sbuf)));
132 		goto out_delete_evlist;
133 	}
134 
135 	ret = TEST_FAIL;
136 	err = do_test(evlist, opts.mmap_pages, &sample_count,
137 		      &comm_count);
138 	if (err != TEST_OK)
139 		goto out_delete_evlist;
140 
141 	if ((sample_count != NR_ITERS) || (comm_count != NR_ITERS)) {
142 		pr_err("Unexpected counter: sample_count=%d, comm_count=%d\n",
143 		       sample_count, comm_count);
144 		goto out_delete_evlist;
145 	}
146 
147 	err = do_test(evlist, 1, &sample_count, &comm_count);
148 	if (err != TEST_OK)
149 		goto out_delete_evlist;
150 
151 	ret = TEST_OK;
152 out_delete_evlist:
153 	perf_evlist__delete(evlist);
154 	return ret;
155 }
156