18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <linux/compiler.h> 38c2ecf20Sopenharmony_ci#include <linux/string.h> 48c2ecf20Sopenharmony_ci#include <errno.h> 58c2ecf20Sopenharmony_ci#include <inttypes.h> 68c2ecf20Sopenharmony_ci#include <string.h> 78c2ecf20Sopenharmony_ci#include <sys/wait.h> 88c2ecf20Sopenharmony_ci#include <perf/cpumap.h> 98c2ecf20Sopenharmony_ci#include "tests.h" 108c2ecf20Sopenharmony_ci#include "evlist.h" 118c2ecf20Sopenharmony_ci#include "evsel.h" 128c2ecf20Sopenharmony_ci#include "debug.h" 138c2ecf20Sopenharmony_ci#include "parse-events.h" 148c2ecf20Sopenharmony_ci#include "thread_map.h" 158c2ecf20Sopenharmony_ci#include "target.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_cistatic int attach__enable_on_exec(struct evlist *evlist) 188c2ecf20Sopenharmony_ci{ 198c2ecf20Sopenharmony_ci struct evsel *evsel = evlist__last(evlist); 208c2ecf20Sopenharmony_ci struct target target = { 218c2ecf20Sopenharmony_ci .uid = UINT_MAX, 228c2ecf20Sopenharmony_ci }; 238c2ecf20Sopenharmony_ci const char *argv[] = { "true", NULL, }; 248c2ecf20Sopenharmony_ci char sbuf[STRERR_BUFSIZE]; 258c2ecf20Sopenharmony_ci int err; 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci pr_debug("attaching to spawned child, enable on exec\n"); 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci err = perf_evlist__create_maps(evlist, &target); 308c2ecf20Sopenharmony_ci if (err < 0) { 318c2ecf20Sopenharmony_ci pr_debug("Not enough memory to create thread/cpu maps\n"); 328c2ecf20Sopenharmony_ci return err; 338c2ecf20Sopenharmony_ci } 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci err = perf_evlist__prepare_workload(evlist, &target, argv, false, NULL); 368c2ecf20Sopenharmony_ci if (err < 0) { 378c2ecf20Sopenharmony_ci pr_debug("Couldn't run the workload!\n"); 388c2ecf20Sopenharmony_ci return err; 398c2ecf20Sopenharmony_ci } 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci evsel->core.attr.enable_on_exec = 1; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci err = evlist__open(evlist); 448c2ecf20Sopenharmony_ci if (err < 0) { 458c2ecf20Sopenharmony_ci pr_debug("perf_evlist__open: %s\n", 468c2ecf20Sopenharmony_ci str_error_r(errno, sbuf, sizeof(sbuf))); 478c2ecf20Sopenharmony_ci return err; 488c2ecf20Sopenharmony_ci } 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_ci return perf_evlist__start_workload(evlist) == 1 ? TEST_OK : TEST_FAIL; 518c2ecf20Sopenharmony_ci} 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic int detach__enable_on_exec(struct evlist *evlist) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci waitpid(evlist->workload.pid, NULL, 0); 568c2ecf20Sopenharmony_ci return 0; 578c2ecf20Sopenharmony_ci} 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic int attach__current_disabled(struct evlist *evlist) 608c2ecf20Sopenharmony_ci{ 618c2ecf20Sopenharmony_ci struct evsel *evsel = evlist__last(evlist); 628c2ecf20Sopenharmony_ci struct perf_thread_map *threads; 638c2ecf20Sopenharmony_ci int err; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci pr_debug("attaching to current thread as disabled\n"); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci threads = thread_map__new(-1, getpid(), UINT_MAX); 688c2ecf20Sopenharmony_ci if (threads == NULL) { 698c2ecf20Sopenharmony_ci pr_debug("thread_map__new\n"); 708c2ecf20Sopenharmony_ci return -1; 718c2ecf20Sopenharmony_ci } 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci evsel->core.attr.disabled = 1; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci err = evsel__open_per_thread(evsel, threads); 768c2ecf20Sopenharmony_ci if (err) { 778c2ecf20Sopenharmony_ci pr_debug("Failed to open event cpu-clock:u\n"); 788c2ecf20Sopenharmony_ci return err; 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci perf_thread_map__put(threads); 828c2ecf20Sopenharmony_ci return evsel__enable(evsel) == 0 ? TEST_OK : TEST_FAIL; 838c2ecf20Sopenharmony_ci} 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistatic int attach__current_enabled(struct evlist *evlist) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct evsel *evsel = evlist__last(evlist); 888c2ecf20Sopenharmony_ci struct perf_thread_map *threads; 898c2ecf20Sopenharmony_ci int err; 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci pr_debug("attaching to current thread as enabled\n"); 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci threads = thread_map__new(-1, getpid(), UINT_MAX); 948c2ecf20Sopenharmony_ci if (threads == NULL) { 958c2ecf20Sopenharmony_ci pr_debug("failed to call thread_map__new\n"); 968c2ecf20Sopenharmony_ci return -1; 978c2ecf20Sopenharmony_ci } 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci err = evsel__open_per_thread(evsel, threads); 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci perf_thread_map__put(threads); 1028c2ecf20Sopenharmony_ci return err == 0 ? TEST_OK : TEST_FAIL; 1038c2ecf20Sopenharmony_ci} 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic int detach__disable(struct evlist *evlist) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci struct evsel *evsel = evlist__last(evlist); 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci return evsel__enable(evsel); 1108c2ecf20Sopenharmony_ci} 1118c2ecf20Sopenharmony_ci 1128c2ecf20Sopenharmony_cistatic int attach__cpu_disabled(struct evlist *evlist) 1138c2ecf20Sopenharmony_ci{ 1148c2ecf20Sopenharmony_ci struct evsel *evsel = evlist__last(evlist); 1158c2ecf20Sopenharmony_ci struct perf_cpu_map *cpus; 1168c2ecf20Sopenharmony_ci int err; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci pr_debug("attaching to CPU 0 as enabled\n"); 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci cpus = perf_cpu_map__new("0"); 1218c2ecf20Sopenharmony_ci if (cpus == NULL) { 1228c2ecf20Sopenharmony_ci pr_debug("failed to call perf_cpu_map__new\n"); 1238c2ecf20Sopenharmony_ci return -1; 1248c2ecf20Sopenharmony_ci } 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci evsel->core.attr.disabled = 1; 1278c2ecf20Sopenharmony_ci 1288c2ecf20Sopenharmony_ci err = evsel__open_per_cpu(evsel, cpus, -1); 1298c2ecf20Sopenharmony_ci if (err) { 1308c2ecf20Sopenharmony_ci if (err == -EACCES) 1318c2ecf20Sopenharmony_ci return TEST_SKIP; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci pr_debug("Failed to open event cpu-clock:u\n"); 1348c2ecf20Sopenharmony_ci return err; 1358c2ecf20Sopenharmony_ci } 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci perf_cpu_map__put(cpus); 1388c2ecf20Sopenharmony_ci return evsel__enable(evsel); 1398c2ecf20Sopenharmony_ci} 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_cistatic int attach__cpu_enabled(struct evlist *evlist) 1428c2ecf20Sopenharmony_ci{ 1438c2ecf20Sopenharmony_ci struct evsel *evsel = evlist__last(evlist); 1448c2ecf20Sopenharmony_ci struct perf_cpu_map *cpus; 1458c2ecf20Sopenharmony_ci int err; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci pr_debug("attaching to CPU 0 as enabled\n"); 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci cpus = perf_cpu_map__new("0"); 1508c2ecf20Sopenharmony_ci if (cpus == NULL) { 1518c2ecf20Sopenharmony_ci pr_debug("failed to call perf_cpu_map__new\n"); 1528c2ecf20Sopenharmony_ci return -1; 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci err = evsel__open_per_cpu(evsel, cpus, -1); 1568c2ecf20Sopenharmony_ci if (err == -EACCES) 1578c2ecf20Sopenharmony_ci return TEST_SKIP; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci perf_cpu_map__put(cpus); 1608c2ecf20Sopenharmony_ci return err ? TEST_FAIL : TEST_OK; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic int test_times(int (attach)(struct evlist *), 1648c2ecf20Sopenharmony_ci int (detach)(struct evlist *)) 1658c2ecf20Sopenharmony_ci{ 1668c2ecf20Sopenharmony_ci struct perf_counts_values count; 1678c2ecf20Sopenharmony_ci struct evlist *evlist = NULL; 1688c2ecf20Sopenharmony_ci struct evsel *evsel; 1698c2ecf20Sopenharmony_ci int err = -1, i; 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_ci evlist = evlist__new(); 1728c2ecf20Sopenharmony_ci if (!evlist) { 1738c2ecf20Sopenharmony_ci pr_debug("failed to create event list\n"); 1748c2ecf20Sopenharmony_ci goto out_err; 1758c2ecf20Sopenharmony_ci } 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci err = parse_events(evlist, "cpu-clock:u", NULL); 1788c2ecf20Sopenharmony_ci if (err) { 1798c2ecf20Sopenharmony_ci pr_debug("failed to parse event cpu-clock:u\n"); 1808c2ecf20Sopenharmony_ci goto out_err; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci evsel = evlist__last(evlist); 1848c2ecf20Sopenharmony_ci evsel->core.attr.read_format |= 1858c2ecf20Sopenharmony_ci PERF_FORMAT_TOTAL_TIME_ENABLED | 1868c2ecf20Sopenharmony_ci PERF_FORMAT_TOTAL_TIME_RUNNING; 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci err = attach(evlist); 1898c2ecf20Sopenharmony_ci if (err == TEST_SKIP) { 1908c2ecf20Sopenharmony_ci pr_debug(" SKIP : not enough rights\n"); 1918c2ecf20Sopenharmony_ci return err; 1928c2ecf20Sopenharmony_ci } 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci TEST_ASSERT_VAL("failed to attach", !err); 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci for (i = 0; i < 100000000; i++) { } 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci TEST_ASSERT_VAL("failed to detach", !detach(evlist)); 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci perf_evsel__read(&evsel->core, 0, 0, &count); 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci err = !(count.ena == count.run); 2038c2ecf20Sopenharmony_ci 2048c2ecf20Sopenharmony_ci pr_debug(" %s: ena %" PRIu64", run %" PRIu64"\n", 2058c2ecf20Sopenharmony_ci !err ? "OK " : "FAILED", 2068c2ecf20Sopenharmony_ci count.ena, count.run); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ciout_err: 2098c2ecf20Sopenharmony_ci evlist__delete(evlist); 2108c2ecf20Sopenharmony_ci return !err ? TEST_OK : TEST_FAIL; 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci/* 2148c2ecf20Sopenharmony_ci * This test creates software event 'cpu-clock' 2158c2ecf20Sopenharmony_ci * attaches it in several ways (explained below) 2168c2ecf20Sopenharmony_ci * and checks that enabled and running times 2178c2ecf20Sopenharmony_ci * match. 2188c2ecf20Sopenharmony_ci */ 2198c2ecf20Sopenharmony_ciint test__event_times(struct test *test __maybe_unused, int subtest __maybe_unused) 2208c2ecf20Sopenharmony_ci{ 2218c2ecf20Sopenharmony_ci int err, ret = 0; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci#define _T(attach, detach) \ 2248c2ecf20Sopenharmony_ci err = test_times(attach, detach); \ 2258c2ecf20Sopenharmony_ci if (err && (ret == TEST_OK || ret == TEST_SKIP)) \ 2268c2ecf20Sopenharmony_ci ret = err; 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci /* attach on newly spawned process after exec */ 2298c2ecf20Sopenharmony_ci _T(attach__enable_on_exec, detach__enable_on_exec) 2308c2ecf20Sopenharmony_ci /* attach on current process as enabled */ 2318c2ecf20Sopenharmony_ci _T(attach__current_enabled, detach__disable) 2328c2ecf20Sopenharmony_ci /* attach on current process as disabled */ 2338c2ecf20Sopenharmony_ci _T(attach__current_disabled, detach__disable) 2348c2ecf20Sopenharmony_ci /* attach on cpu as disabled */ 2358c2ecf20Sopenharmony_ci _T(attach__cpu_disabled, detach__disable) 2368c2ecf20Sopenharmony_ci /* attach on cpu as enabled */ 2378c2ecf20Sopenharmony_ci _T(attach__cpu_enabled, detach__disable) 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci#undef _T 2408c2ecf20Sopenharmony_ci return ret; 2418c2ecf20Sopenharmony_ci} 242