1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/types.h> 3 #include <limits.h> 4 #include <unistd.h> 5 #include <sys/prctl.h> 6 #include <perf/cpumap.h> 7 #include <perf/evlist.h> 8 9 #include "debug.h" 10 #include "parse-events.h" 11 #include "evlist.h" 12 #include "evsel.h" 13 #include "record.h" 14 #include "thread_map.h" 15 #include "tests.h" 16 #include "util/mmap.h" 17 18 #define CHECK__(x) { \ 19 while ((x) < 0) { \ 20 pr_debug(#x " failed!\n"); \ 21 goto out_err; \ 22 } \ 23 } 24 25 #define CHECK_NOT_NULL__(x) { \ 26 while ((x) == NULL) { \ 27 pr_debug(#x " failed!\n"); \ 28 goto out_err; \ 29 } \ 30 } 31 32 static int find_comm(struct evlist *evlist, const char *comm) 33 { 34 union perf_event *event; 35 struct mmap *md; 36 int i, found; 37 38 found = 0; 39 for (i = 0; i < evlist->core.nr_mmaps; i++) { 40 md = &evlist->mmap[i]; 41 if (perf_mmap__read_init(md) < 0) 42 continue; 43 while ((event = perf_mmap__read_event(md)) != NULL) { 44 if (event->header.type == PERF_RECORD_COMM && 45 (pid_t)event->comm.pid == getpid() && 46 (pid_t)event->comm.tid == getpid() && 47 strcmp(event->comm.comm, comm) == 0) 48 found += 1; 49 perf_mmap__consume(md); 50 } 51 perf_mmap__read_done(md); 52 } 53 return found; 54 } 55 56 /** 57 * test__keep_tracking - test using a dummy software event to keep tracking. 58 * 59 * This function implements a test that checks that tracking events continue 60 * when an event is disabled but a dummy software event is not disabled. If the 61 * test passes %0 is returned, otherwise %-1 is returned. 62 */ 63 int test__keep_tracking(struct test *test __maybe_unused, int subtest __maybe_unused) 64 { 65 struct record_opts opts = { 66 .mmap_pages = UINT_MAX, 67 .user_freq = UINT_MAX, 68 .user_interval = ULLONG_MAX, 69 .target = { 70 .uses_mmap = true, 71 }, 72 }; 73 struct perf_thread_map *threads = NULL; 74 struct perf_cpu_map *cpus = NULL; 75 struct evlist *evlist = NULL; 76 struct evsel *evsel = NULL; 77 int found, err = -1; 78 const char *comm; 79 80 threads = thread_map__new(-1, getpid(), UINT_MAX); 81 CHECK_NOT_NULL__(threads); 82 83 cpus = perf_cpu_map__new(NULL); 84 CHECK_NOT_NULL__(cpus); 85 86 evlist = evlist__new(); 87 CHECK_NOT_NULL__(evlist); 88 89 perf_evlist__set_maps(&evlist->core, cpus, threads); 90 91 CHECK__(parse_events(evlist, "dummy:u", NULL)); 92 CHECK__(parse_events(evlist, "cycles:u", NULL)); 93 94 perf_evlist__config(evlist, &opts, NULL); 95 96 evsel = evlist__first(evlist); 97 98 evsel->core.attr.comm = 1; 99 evsel->core.attr.disabled = 1; 100 evsel->core.attr.enable_on_exec = 0; 101 102 if (evlist__open(evlist) < 0) { 103 pr_debug("Unable to open dummy and cycles event\n"); 104 err = TEST_SKIP; 105 goto out_err; 106 } 107 108 CHECK__(evlist__mmap(evlist, UINT_MAX)); 109 110 /* 111 * First, test that a 'comm' event can be found when the event is 112 * enabled. 113 */ 114 115 evlist__enable(evlist); 116 117 comm = "Test COMM 1"; 118 CHECK__(prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0)); 119 120 evlist__disable(evlist); 121 122 found = find_comm(evlist, comm); 123 if (found != 1) { 124 pr_debug("First time, failed to find tracking event.\n"); 125 goto out_err; 126 } 127 128 /* 129 * Secondly, test that a 'comm' event can be found when the event is 130 * disabled with the dummy event still enabled. 131 */ 132 133 evlist__enable(evlist); 134 135 evsel = evlist__last(evlist); 136 137 CHECK__(evsel__disable(evsel)); 138 139 comm = "Test COMM 2"; 140 CHECK__(prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0)); 141 142 evlist__disable(evlist); 143 144 found = find_comm(evlist, comm); 145 if (found != 1) { 146 pr_debug("Second time, failed to find tracking event.\n"); 147 goto out_err; 148 } 149 150 err = 0; 151 152 out_err: 153 if (evlist) { 154 evlist__disable(evlist); 155 evlist__delete(evlist); 156 } else { 157 perf_cpu_map__put(cpus); 158 perf_thread_map__put(threads); 159 } 160 161 return err; 162 } 163