1 // SPDX-License-Identifier: GPL-2.0 2 #include "evlist.h" 3 #include "evsel.h" 4 #include "thread_map.h" 5 #include "cpumap.h" 6 #include "tests.h" 7 8 #include <errno.h> 9 #include <signal.h> 10 #include <perf/evlist.h> 11 12 static int exited; 13 static int nr_exit; 14 15 static void sig_handler(int sig __maybe_unused) 16 { 17 exited = 1; 18 } 19 20 /* 21 * perf_evlist__prepare_workload will send a SIGUSR1 if the fork fails, since 22 * we asked by setting its exec_error to this handler. 23 */ 24 static void workload_exec_failed_signal(int signo __maybe_unused, 25 siginfo_t *info __maybe_unused, 26 void *ucontext __maybe_unused) 27 { 28 exited = 1; 29 nr_exit = -1; 30 } 31 32 /* 33 * This test will start a workload that does nothing then it checks 34 * if the number of exit event reported by the kernel is 1 or not 35 * in order to check the kernel returns correct number of event. 36 */ 37 int test__task_exit(struct test *test __maybe_unused, int subtest __maybe_unused) 38 { 39 int err = -1; 40 union perf_event *event; 41 struct evsel *evsel; 42 struct evlist *evlist; 43 struct target target = { 44 .uid = UINT_MAX, 45 .uses_mmap = true, 46 }; 47 const char *argv[] = { "true", NULL }; 48 char sbuf[STRERR_BUFSIZE]; 49 struct perf_cpu_map *cpus; 50 struct perf_thread_map *threads; 51 struct perf_mmap *md; 52 53 signal(SIGCHLD, sig_handler); 54 55 evlist = perf_evlist__new_default(); 56 if (evlist == NULL) { 57 pr_debug("perf_evlist__new_default\n"); 58 return -1; 59 } 60 61 /* 62 * Create maps of threads and cpus to monitor. In this case 63 * we start with all threads and cpus (-1, -1) but then in 64 * perf_evlist__prepare_workload we'll fill in the only thread 65 * we're monitoring, the one forked there. 66 */ 67 cpus = perf_cpu_map__dummy_new(); 68 threads = thread_map__new_by_tid(-1); 69 if (!cpus || !threads) { 70 err = -ENOMEM; 71 pr_debug("Not enough memory to create thread/cpu maps\n"); 72 goto out_free_maps; 73 } 74 75 perf_evlist__set_maps(&evlist->core, cpus, threads); 76 77 cpus = NULL; 78 threads = NULL; 79 80 err = perf_evlist__prepare_workload(evlist, &target, argv, false, 81 workload_exec_failed_signal); 82 if (err < 0) { 83 pr_debug("Couldn't run the workload!\n"); 84 goto out_delete_evlist; 85 } 86 87 evsel = perf_evlist__first(evlist); 88 evsel->core.attr.task = 1; 89 #ifdef __s390x__ 90 evsel->core.attr.sample_freq = 1000000; 91 #else 92 evsel->core.attr.sample_freq = 1; 93 #endif 94 evsel->core.attr.inherit = 0; 95 evsel->core.attr.watermark = 0; 96 evsel->core.attr.wakeup_events = 1; 97 evsel->core.attr.exclude_kernel = 1; 98 99 err = evlist__open(evlist); 100 if (err < 0) { 101 pr_debug("Couldn't open the evlist: %s\n", 102 str_error_r(-err, sbuf, sizeof(sbuf))); 103 goto out_delete_evlist; 104 } 105 106 if (perf_evlist__mmap(evlist, 128) < 0) { 107 pr_debug("failed to mmap events: %d (%s)\n", errno, 108 str_error_r(errno, sbuf, sizeof(sbuf))); 109 goto out_delete_evlist; 110 } 111 112 perf_evlist__start_workload(evlist); 113 114 retry: 115 md = &evlist->mmap[0]; 116 if (perf_mmap__read_init(md) < 0) 117 goto out_init; 118 119 while ((event = perf_mmap__read_event(md)) != NULL) { 120 if (event->header.type == PERF_RECORD_EXIT) 121 nr_exit++; 122 123 perf_mmap__consume(md); 124 } 125 perf_mmap__read_done(md); 126 127 out_init: 128 if (!exited || !nr_exit) { 129 perf_evlist__poll(evlist, -1); 130 goto retry; 131 } 132 133 if (nr_exit != 1) { 134 pr_debug("received %d EXIT records\n", nr_exit); 135 err = -1; 136 } 137 138 out_free_maps: 139 perf_cpu_map__put(cpus); 140 perf_thread_map__put(threads); 141 out_delete_evlist: 142 evlist__delete(evlist); 143 return err; 144 } 145