18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include "debug.h" 38c2ecf20Sopenharmony_ci#include "evlist.h" 48c2ecf20Sopenharmony_ci#include "evsel.h" 58c2ecf20Sopenharmony_ci#include "target.h" 68c2ecf20Sopenharmony_ci#include "thread_map.h" 78c2ecf20Sopenharmony_ci#include "tests.h" 88c2ecf20Sopenharmony_ci#include "util/mmap.h" 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <errno.h> 118c2ecf20Sopenharmony_ci#include <signal.h> 128c2ecf20Sopenharmony_ci#include <linux/string.h> 138c2ecf20Sopenharmony_ci#include <perf/cpumap.h> 148c2ecf20Sopenharmony_ci#include <perf/evlist.h> 158c2ecf20Sopenharmony_ci#include <perf/mmap.h> 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistatic int exited; 188c2ecf20Sopenharmony_cistatic int nr_exit; 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistatic void sig_handler(int sig __maybe_unused) 218c2ecf20Sopenharmony_ci{ 228c2ecf20Sopenharmony_ci exited = 1; 238c2ecf20Sopenharmony_ci} 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci/* 268c2ecf20Sopenharmony_ci * perf_evlist__prepare_workload will send a SIGUSR1 if the fork fails, since 278c2ecf20Sopenharmony_ci * we asked by setting its exec_error to this handler. 288c2ecf20Sopenharmony_ci */ 298c2ecf20Sopenharmony_cistatic void workload_exec_failed_signal(int signo __maybe_unused, 308c2ecf20Sopenharmony_ci siginfo_t *info __maybe_unused, 318c2ecf20Sopenharmony_ci void *ucontext __maybe_unused) 328c2ecf20Sopenharmony_ci{ 338c2ecf20Sopenharmony_ci exited = 1; 348c2ecf20Sopenharmony_ci nr_exit = -1; 358c2ecf20Sopenharmony_ci} 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci/* 388c2ecf20Sopenharmony_ci * This test will start a workload that does nothing then it checks 398c2ecf20Sopenharmony_ci * if the number of exit event reported by the kernel is 1 or not 408c2ecf20Sopenharmony_ci * in order to check the kernel returns correct number of event. 418c2ecf20Sopenharmony_ci */ 428c2ecf20Sopenharmony_ciint test__task_exit(struct test *test __maybe_unused, int subtest __maybe_unused) 438c2ecf20Sopenharmony_ci{ 448c2ecf20Sopenharmony_ci int err = -1; 458c2ecf20Sopenharmony_ci union perf_event *event; 468c2ecf20Sopenharmony_ci struct evsel *evsel; 478c2ecf20Sopenharmony_ci struct evlist *evlist; 488c2ecf20Sopenharmony_ci struct target target = { 498c2ecf20Sopenharmony_ci .uid = UINT_MAX, 508c2ecf20Sopenharmony_ci .uses_mmap = true, 518c2ecf20Sopenharmony_ci }; 528c2ecf20Sopenharmony_ci const char *argv[] = { "true", NULL }; 538c2ecf20Sopenharmony_ci char sbuf[STRERR_BUFSIZE]; 548c2ecf20Sopenharmony_ci struct perf_cpu_map *cpus; 558c2ecf20Sopenharmony_ci struct perf_thread_map *threads; 568c2ecf20Sopenharmony_ci struct mmap *md; 578c2ecf20Sopenharmony_ci int retry_count = 0; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci signal(SIGCHLD, sig_handler); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci evlist = perf_evlist__new_default(); 628c2ecf20Sopenharmony_ci if (evlist == NULL) { 638c2ecf20Sopenharmony_ci pr_debug("perf_evlist__new_default\n"); 648c2ecf20Sopenharmony_ci return -1; 658c2ecf20Sopenharmony_ci } 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci /* 688c2ecf20Sopenharmony_ci * Create maps of threads and cpus to monitor. In this case 698c2ecf20Sopenharmony_ci * we start with all threads and cpus (-1, -1) but then in 708c2ecf20Sopenharmony_ci * perf_evlist__prepare_workload we'll fill in the only thread 718c2ecf20Sopenharmony_ci * we're monitoring, the one forked there. 728c2ecf20Sopenharmony_ci */ 738c2ecf20Sopenharmony_ci cpus = perf_cpu_map__dummy_new(); 748c2ecf20Sopenharmony_ci threads = thread_map__new_by_tid(-1); 758c2ecf20Sopenharmony_ci if (!cpus || !threads) { 768c2ecf20Sopenharmony_ci err = -ENOMEM; 778c2ecf20Sopenharmony_ci pr_debug("Not enough memory to create thread/cpu maps\n"); 788c2ecf20Sopenharmony_ci goto out_free_maps; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci perf_evlist__set_maps(&evlist->core, cpus, threads); 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci cpus = NULL; 848c2ecf20Sopenharmony_ci threads = NULL; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci err = perf_evlist__prepare_workload(evlist, &target, argv, false, 878c2ecf20Sopenharmony_ci workload_exec_failed_signal); 888c2ecf20Sopenharmony_ci if (err < 0) { 898c2ecf20Sopenharmony_ci pr_debug("Couldn't run the workload!\n"); 908c2ecf20Sopenharmony_ci goto out_delete_evlist; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci evsel = evlist__first(evlist); 948c2ecf20Sopenharmony_ci evsel->core.attr.task = 1; 958c2ecf20Sopenharmony_ci#ifdef __s390x__ 968c2ecf20Sopenharmony_ci evsel->core.attr.sample_freq = 1000000; 978c2ecf20Sopenharmony_ci#else 988c2ecf20Sopenharmony_ci evsel->core.attr.sample_freq = 1; 998c2ecf20Sopenharmony_ci#endif 1008c2ecf20Sopenharmony_ci evsel->core.attr.inherit = 0; 1018c2ecf20Sopenharmony_ci evsel->core.attr.watermark = 0; 1028c2ecf20Sopenharmony_ci evsel->core.attr.wakeup_events = 1; 1038c2ecf20Sopenharmony_ci evsel->core.attr.exclude_kernel = 1; 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_ci err = evlist__open(evlist); 1068c2ecf20Sopenharmony_ci if (err < 0) { 1078c2ecf20Sopenharmony_ci pr_debug("Couldn't open the evlist: %s\n", 1088c2ecf20Sopenharmony_ci str_error_r(-err, sbuf, sizeof(sbuf))); 1098c2ecf20Sopenharmony_ci goto out_delete_evlist; 1108c2ecf20Sopenharmony_ci } 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_ci if (evlist__mmap(evlist, 128) < 0) { 1138c2ecf20Sopenharmony_ci pr_debug("failed to mmap events: %d (%s)\n", errno, 1148c2ecf20Sopenharmony_ci str_error_r(errno, sbuf, sizeof(sbuf))); 1158c2ecf20Sopenharmony_ci err = -1; 1168c2ecf20Sopenharmony_ci goto out_delete_evlist; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci perf_evlist__start_workload(evlist); 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ciretry: 1228c2ecf20Sopenharmony_ci md = &evlist->mmap[0]; 1238c2ecf20Sopenharmony_ci if (perf_mmap__read_init(&md->core) < 0) 1248c2ecf20Sopenharmony_ci goto out_init; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci while ((event = perf_mmap__read_event(&md->core)) != NULL) { 1278c2ecf20Sopenharmony_ci if (event->header.type == PERF_RECORD_EXIT) 1288c2ecf20Sopenharmony_ci nr_exit++; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci perf_mmap__consume(&md->core); 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci perf_mmap__read_done(&md->core); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ciout_init: 1358c2ecf20Sopenharmony_ci if (!exited || !nr_exit) { 1368c2ecf20Sopenharmony_ci evlist__poll(evlist, -1); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci if (retry_count++ > 1000) { 1398c2ecf20Sopenharmony_ci pr_debug("Failed after retrying 1000 times\n"); 1408c2ecf20Sopenharmony_ci err = -1; 1418c2ecf20Sopenharmony_ci goto out_free_maps; 1428c2ecf20Sopenharmony_ci } 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci goto retry; 1458c2ecf20Sopenharmony_ci } 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci if (nr_exit != 1) { 1488c2ecf20Sopenharmony_ci pr_debug("received %d EXIT records\n", nr_exit); 1498c2ecf20Sopenharmony_ci err = -1; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ciout_free_maps: 1538c2ecf20Sopenharmony_ci perf_cpu_map__put(cpus); 1548c2ecf20Sopenharmony_ci perf_thread_map__put(threads); 1558c2ecf20Sopenharmony_ciout_delete_evlist: 1568c2ecf20Sopenharmony_ci evlist__delete(evlist); 1578c2ecf20Sopenharmony_ci return err; 1588c2ecf20Sopenharmony_ci} 159