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