18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <sys/time.h> 38c2ecf20Sopenharmony_ci#include <sys/prctl.h> 48c2ecf20Sopenharmony_ci#include <errno.h> 58c2ecf20Sopenharmony_ci#include <limits.h> 68c2ecf20Sopenharmony_ci#include <time.h> 78c2ecf20Sopenharmony_ci#include <stdlib.h> 88c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 98c2ecf20Sopenharmony_ci#include <perf/cpumap.h> 108c2ecf20Sopenharmony_ci#include <perf/evlist.h> 118c2ecf20Sopenharmony_ci#include <perf/mmap.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "debug.h" 148c2ecf20Sopenharmony_ci#include "parse-events.h" 158c2ecf20Sopenharmony_ci#include "evlist.h" 168c2ecf20Sopenharmony_ci#include "evsel.h" 178c2ecf20Sopenharmony_ci#include "thread_map.h" 188c2ecf20Sopenharmony_ci#include "record.h" 198c2ecf20Sopenharmony_ci#include "tests.h" 208c2ecf20Sopenharmony_ci#include "util/mmap.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic int spin_sleep(void) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci struct timeval start, now, diff, maxtime; 258c2ecf20Sopenharmony_ci struct timespec ts; 268c2ecf20Sopenharmony_ci int err, i; 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci maxtime.tv_sec = 0; 298c2ecf20Sopenharmony_ci maxtime.tv_usec = 50000; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci err = gettimeofday(&start, NULL); 328c2ecf20Sopenharmony_ci if (err) 338c2ecf20Sopenharmony_ci return err; 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci /* Spin for 50ms */ 368c2ecf20Sopenharmony_ci while (1) { 378c2ecf20Sopenharmony_ci for (i = 0; i < 1000; i++) 388c2ecf20Sopenharmony_ci barrier(); 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci err = gettimeofday(&now, NULL); 418c2ecf20Sopenharmony_ci if (err) 428c2ecf20Sopenharmony_ci return err; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci timersub(&now, &start, &diff); 458c2ecf20Sopenharmony_ci if (timercmp(&diff, &maxtime, > /* For checkpatch */)) 468c2ecf20Sopenharmony_ci break; 478c2ecf20Sopenharmony_ci } 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci ts.tv_nsec = 50 * 1000 * 1000; 508c2ecf20Sopenharmony_ci ts.tv_sec = 0; 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci /* Sleep for 50ms */ 538c2ecf20Sopenharmony_ci err = nanosleep(&ts, NULL); 548c2ecf20Sopenharmony_ci if (err == EINTR) 558c2ecf20Sopenharmony_ci err = 0; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci return err; 588c2ecf20Sopenharmony_ci} 598c2ecf20Sopenharmony_ci 608c2ecf20Sopenharmony_cistruct switch_tracking { 618c2ecf20Sopenharmony_ci struct evsel *switch_evsel; 628c2ecf20Sopenharmony_ci struct evsel *cycles_evsel; 638c2ecf20Sopenharmony_ci pid_t *tids; 648c2ecf20Sopenharmony_ci int nr_tids; 658c2ecf20Sopenharmony_ci int comm_seen[4]; 668c2ecf20Sopenharmony_ci int cycles_before_comm_1; 678c2ecf20Sopenharmony_ci int cycles_between_comm_2_and_comm_3; 688c2ecf20Sopenharmony_ci int cycles_after_comm_4; 698c2ecf20Sopenharmony_ci}; 708c2ecf20Sopenharmony_ci 718c2ecf20Sopenharmony_cistatic int check_comm(struct switch_tracking *switch_tracking, 728c2ecf20Sopenharmony_ci union perf_event *event, const char *comm, int nr) 738c2ecf20Sopenharmony_ci{ 748c2ecf20Sopenharmony_ci if (event->header.type == PERF_RECORD_COMM && 758c2ecf20Sopenharmony_ci (pid_t)event->comm.pid == getpid() && 768c2ecf20Sopenharmony_ci (pid_t)event->comm.tid == getpid() && 778c2ecf20Sopenharmony_ci strcmp(event->comm.comm, comm) == 0) { 788c2ecf20Sopenharmony_ci if (switch_tracking->comm_seen[nr]) { 798c2ecf20Sopenharmony_ci pr_debug("Duplicate comm event\n"); 808c2ecf20Sopenharmony_ci return -1; 818c2ecf20Sopenharmony_ci } 828c2ecf20Sopenharmony_ci switch_tracking->comm_seen[nr] = 1; 838c2ecf20Sopenharmony_ci pr_debug3("comm event: %s nr: %d\n", event->comm.comm, nr); 848c2ecf20Sopenharmony_ci return 1; 858c2ecf20Sopenharmony_ci } 868c2ecf20Sopenharmony_ci return 0; 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic int check_cpu(struct switch_tracking *switch_tracking, int cpu) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci int i, nr = cpu + 1; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci if (cpu < 0) 948c2ecf20Sopenharmony_ci return -1; 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (!switch_tracking->tids) { 978c2ecf20Sopenharmony_ci switch_tracking->tids = calloc(nr, sizeof(pid_t)); 988c2ecf20Sopenharmony_ci if (!switch_tracking->tids) 998c2ecf20Sopenharmony_ci return -1; 1008c2ecf20Sopenharmony_ci for (i = 0; i < nr; i++) 1018c2ecf20Sopenharmony_ci switch_tracking->tids[i] = -1; 1028c2ecf20Sopenharmony_ci switch_tracking->nr_tids = nr; 1038c2ecf20Sopenharmony_ci return 0; 1048c2ecf20Sopenharmony_ci } 1058c2ecf20Sopenharmony_ci 1068c2ecf20Sopenharmony_ci if (cpu >= switch_tracking->nr_tids) { 1078c2ecf20Sopenharmony_ci void *addr; 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci addr = realloc(switch_tracking->tids, nr * sizeof(pid_t)); 1108c2ecf20Sopenharmony_ci if (!addr) 1118c2ecf20Sopenharmony_ci return -1; 1128c2ecf20Sopenharmony_ci switch_tracking->tids = addr; 1138c2ecf20Sopenharmony_ci for (i = switch_tracking->nr_tids; i < nr; i++) 1148c2ecf20Sopenharmony_ci switch_tracking->tids[i] = -1; 1158c2ecf20Sopenharmony_ci switch_tracking->nr_tids = nr; 1168c2ecf20Sopenharmony_ci return 0; 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci return 0; 1208c2ecf20Sopenharmony_ci} 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_cistatic int process_sample_event(struct evlist *evlist, 1238c2ecf20Sopenharmony_ci union perf_event *event, 1248c2ecf20Sopenharmony_ci struct switch_tracking *switch_tracking) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci struct perf_sample sample; 1278c2ecf20Sopenharmony_ci struct evsel *evsel; 1288c2ecf20Sopenharmony_ci pid_t next_tid, prev_tid; 1298c2ecf20Sopenharmony_ci int cpu, err; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci if (perf_evlist__parse_sample(evlist, event, &sample)) { 1328c2ecf20Sopenharmony_ci pr_debug("perf_evlist__parse_sample failed\n"); 1338c2ecf20Sopenharmony_ci return -1; 1348c2ecf20Sopenharmony_ci } 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci evsel = perf_evlist__id2evsel(evlist, sample.id); 1378c2ecf20Sopenharmony_ci if (evsel == switch_tracking->switch_evsel) { 1388c2ecf20Sopenharmony_ci next_tid = evsel__intval(evsel, &sample, "next_pid"); 1398c2ecf20Sopenharmony_ci prev_tid = evsel__intval(evsel, &sample, "prev_pid"); 1408c2ecf20Sopenharmony_ci cpu = sample.cpu; 1418c2ecf20Sopenharmony_ci pr_debug3("sched_switch: cpu: %d prev_tid %d next_tid %d\n", 1428c2ecf20Sopenharmony_ci cpu, prev_tid, next_tid); 1438c2ecf20Sopenharmony_ci err = check_cpu(switch_tracking, cpu); 1448c2ecf20Sopenharmony_ci if (err) 1458c2ecf20Sopenharmony_ci return err; 1468c2ecf20Sopenharmony_ci /* 1478c2ecf20Sopenharmony_ci * Check for no missing sched_switch events i.e. that the 1488c2ecf20Sopenharmony_ci * evsel->core.system_wide flag has worked. 1498c2ecf20Sopenharmony_ci */ 1508c2ecf20Sopenharmony_ci if (switch_tracking->tids[cpu] != -1 && 1518c2ecf20Sopenharmony_ci switch_tracking->tids[cpu] != prev_tid) { 1528c2ecf20Sopenharmony_ci pr_debug("Missing sched_switch events\n"); 1538c2ecf20Sopenharmony_ci return -1; 1548c2ecf20Sopenharmony_ci } 1558c2ecf20Sopenharmony_ci switch_tracking->tids[cpu] = next_tid; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (evsel == switch_tracking->cycles_evsel) { 1598c2ecf20Sopenharmony_ci pr_debug3("cycles event\n"); 1608c2ecf20Sopenharmony_ci if (!switch_tracking->comm_seen[0]) 1618c2ecf20Sopenharmony_ci switch_tracking->cycles_before_comm_1 = 1; 1628c2ecf20Sopenharmony_ci if (switch_tracking->comm_seen[1] && 1638c2ecf20Sopenharmony_ci !switch_tracking->comm_seen[2]) 1648c2ecf20Sopenharmony_ci switch_tracking->cycles_between_comm_2_and_comm_3 = 1; 1658c2ecf20Sopenharmony_ci if (switch_tracking->comm_seen[3]) 1668c2ecf20Sopenharmony_ci switch_tracking->cycles_after_comm_4 = 1; 1678c2ecf20Sopenharmony_ci } 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci return 0; 1708c2ecf20Sopenharmony_ci} 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_cistatic int process_event(struct evlist *evlist, union perf_event *event, 1738c2ecf20Sopenharmony_ci struct switch_tracking *switch_tracking) 1748c2ecf20Sopenharmony_ci{ 1758c2ecf20Sopenharmony_ci if (event->header.type == PERF_RECORD_SAMPLE) 1768c2ecf20Sopenharmony_ci return process_sample_event(evlist, event, switch_tracking); 1778c2ecf20Sopenharmony_ci 1788c2ecf20Sopenharmony_ci if (event->header.type == PERF_RECORD_COMM) { 1798c2ecf20Sopenharmony_ci int err, done = 0; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci err = check_comm(switch_tracking, event, "Test COMM 1", 0); 1828c2ecf20Sopenharmony_ci if (err < 0) 1838c2ecf20Sopenharmony_ci return -1; 1848c2ecf20Sopenharmony_ci done += err; 1858c2ecf20Sopenharmony_ci err = check_comm(switch_tracking, event, "Test COMM 2", 1); 1868c2ecf20Sopenharmony_ci if (err < 0) 1878c2ecf20Sopenharmony_ci return -1; 1888c2ecf20Sopenharmony_ci done += err; 1898c2ecf20Sopenharmony_ci err = check_comm(switch_tracking, event, "Test COMM 3", 2); 1908c2ecf20Sopenharmony_ci if (err < 0) 1918c2ecf20Sopenharmony_ci return -1; 1928c2ecf20Sopenharmony_ci done += err; 1938c2ecf20Sopenharmony_ci err = check_comm(switch_tracking, event, "Test COMM 4", 3); 1948c2ecf20Sopenharmony_ci if (err < 0) 1958c2ecf20Sopenharmony_ci return -1; 1968c2ecf20Sopenharmony_ci done += err; 1978c2ecf20Sopenharmony_ci if (done != 1) { 1988c2ecf20Sopenharmony_ci pr_debug("Unexpected comm event\n"); 1998c2ecf20Sopenharmony_ci return -1; 2008c2ecf20Sopenharmony_ci } 2018c2ecf20Sopenharmony_ci } 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci return 0; 2048c2ecf20Sopenharmony_ci} 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_cistruct event_node { 2078c2ecf20Sopenharmony_ci struct list_head list; 2088c2ecf20Sopenharmony_ci union perf_event *event; 2098c2ecf20Sopenharmony_ci u64 event_time; 2108c2ecf20Sopenharmony_ci}; 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_cistatic int add_event(struct evlist *evlist, struct list_head *events, 2138c2ecf20Sopenharmony_ci union perf_event *event) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci struct perf_sample sample; 2168c2ecf20Sopenharmony_ci struct event_node *node; 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci node = malloc(sizeof(struct event_node)); 2198c2ecf20Sopenharmony_ci if (!node) { 2208c2ecf20Sopenharmony_ci pr_debug("malloc failed\n"); 2218c2ecf20Sopenharmony_ci return -1; 2228c2ecf20Sopenharmony_ci } 2238c2ecf20Sopenharmony_ci node->event = event; 2248c2ecf20Sopenharmony_ci list_add(&node->list, events); 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci if (perf_evlist__parse_sample(evlist, event, &sample)) { 2278c2ecf20Sopenharmony_ci pr_debug("perf_evlist__parse_sample failed\n"); 2288c2ecf20Sopenharmony_ci return -1; 2298c2ecf20Sopenharmony_ci } 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_ci if (!sample.time) { 2328c2ecf20Sopenharmony_ci pr_debug("event with no time\n"); 2338c2ecf20Sopenharmony_ci return -1; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci 2368c2ecf20Sopenharmony_ci node->event_time = sample.time; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci return 0; 2398c2ecf20Sopenharmony_ci} 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_cistatic void free_event_nodes(struct list_head *events) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct event_node *node; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci while (!list_empty(events)) { 2468c2ecf20Sopenharmony_ci node = list_entry(events->next, struct event_node, list); 2478c2ecf20Sopenharmony_ci list_del_init(&node->list); 2488c2ecf20Sopenharmony_ci free(node); 2498c2ecf20Sopenharmony_ci } 2508c2ecf20Sopenharmony_ci} 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_cistatic int compar(const void *a, const void *b) 2538c2ecf20Sopenharmony_ci{ 2548c2ecf20Sopenharmony_ci const struct event_node *nodea = a; 2558c2ecf20Sopenharmony_ci const struct event_node *nodeb = b; 2568c2ecf20Sopenharmony_ci s64 cmp = nodea->event_time - nodeb->event_time; 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci return cmp; 2598c2ecf20Sopenharmony_ci} 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_cistatic int process_events(struct evlist *evlist, 2628c2ecf20Sopenharmony_ci struct switch_tracking *switch_tracking) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci union perf_event *event; 2658c2ecf20Sopenharmony_ci unsigned pos, cnt = 0; 2668c2ecf20Sopenharmony_ci LIST_HEAD(events); 2678c2ecf20Sopenharmony_ci struct event_node *events_array, *node; 2688c2ecf20Sopenharmony_ci struct mmap *md; 2698c2ecf20Sopenharmony_ci int i, ret; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci for (i = 0; i < evlist->core.nr_mmaps; i++) { 2728c2ecf20Sopenharmony_ci md = &evlist->mmap[i]; 2738c2ecf20Sopenharmony_ci if (perf_mmap__read_init(&md->core) < 0) 2748c2ecf20Sopenharmony_ci continue; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci while ((event = perf_mmap__read_event(&md->core)) != NULL) { 2778c2ecf20Sopenharmony_ci cnt += 1; 2788c2ecf20Sopenharmony_ci ret = add_event(evlist, &events, event); 2798c2ecf20Sopenharmony_ci perf_mmap__consume(&md->core); 2808c2ecf20Sopenharmony_ci if (ret < 0) 2818c2ecf20Sopenharmony_ci goto out_free_nodes; 2828c2ecf20Sopenharmony_ci } 2838c2ecf20Sopenharmony_ci perf_mmap__read_done(&md->core); 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci events_array = calloc(cnt, sizeof(struct event_node)); 2878c2ecf20Sopenharmony_ci if (!events_array) { 2888c2ecf20Sopenharmony_ci pr_debug("calloc failed\n"); 2898c2ecf20Sopenharmony_ci ret = -1; 2908c2ecf20Sopenharmony_ci goto out_free_nodes; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci pos = 0; 2948c2ecf20Sopenharmony_ci list_for_each_entry(node, &events, list) 2958c2ecf20Sopenharmony_ci events_array[pos++] = *node; 2968c2ecf20Sopenharmony_ci 2978c2ecf20Sopenharmony_ci qsort(events_array, cnt, sizeof(struct event_node), compar); 2988c2ecf20Sopenharmony_ci 2998c2ecf20Sopenharmony_ci for (pos = 0; pos < cnt; pos++) { 3008c2ecf20Sopenharmony_ci ret = process_event(evlist, events_array[pos].event, 3018c2ecf20Sopenharmony_ci switch_tracking); 3028c2ecf20Sopenharmony_ci if (ret < 0) 3038c2ecf20Sopenharmony_ci goto out_free; 3048c2ecf20Sopenharmony_ci } 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci ret = 0; 3078c2ecf20Sopenharmony_ciout_free: 3088c2ecf20Sopenharmony_ci pr_debug("%u events recorded\n", cnt); 3098c2ecf20Sopenharmony_ci free(events_array); 3108c2ecf20Sopenharmony_ciout_free_nodes: 3118c2ecf20Sopenharmony_ci free_event_nodes(&events); 3128c2ecf20Sopenharmony_ci return ret; 3138c2ecf20Sopenharmony_ci} 3148c2ecf20Sopenharmony_ci 3158c2ecf20Sopenharmony_ci/** 3168c2ecf20Sopenharmony_ci * test__switch_tracking - test using sched_switch and tracking events. 3178c2ecf20Sopenharmony_ci * 3188c2ecf20Sopenharmony_ci * This function implements a test that checks that sched_switch events and 3198c2ecf20Sopenharmony_ci * tracking events can be recorded for a workload (current process) using the 3208c2ecf20Sopenharmony_ci * evsel->core.system_wide and evsel->tracking flags (respectively) with other events 3218c2ecf20Sopenharmony_ci * sometimes enabled or disabled. 3228c2ecf20Sopenharmony_ci */ 3238c2ecf20Sopenharmony_ciint test__switch_tracking(struct test *test __maybe_unused, int subtest __maybe_unused) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci const char *sched_switch = "sched:sched_switch"; 3268c2ecf20Sopenharmony_ci struct switch_tracking switch_tracking = { .tids = NULL, }; 3278c2ecf20Sopenharmony_ci struct record_opts opts = { 3288c2ecf20Sopenharmony_ci .mmap_pages = UINT_MAX, 3298c2ecf20Sopenharmony_ci .user_freq = UINT_MAX, 3308c2ecf20Sopenharmony_ci .user_interval = ULLONG_MAX, 3318c2ecf20Sopenharmony_ci .freq = 4000, 3328c2ecf20Sopenharmony_ci .target = { 3338c2ecf20Sopenharmony_ci .uses_mmap = true, 3348c2ecf20Sopenharmony_ci }, 3358c2ecf20Sopenharmony_ci }; 3368c2ecf20Sopenharmony_ci struct perf_thread_map *threads = NULL; 3378c2ecf20Sopenharmony_ci struct perf_cpu_map *cpus = NULL; 3388c2ecf20Sopenharmony_ci struct evlist *evlist = NULL; 3398c2ecf20Sopenharmony_ci struct evsel *evsel, *cpu_clocks_evsel, *cycles_evsel; 3408c2ecf20Sopenharmony_ci struct evsel *switch_evsel, *tracking_evsel; 3418c2ecf20Sopenharmony_ci const char *comm; 3428c2ecf20Sopenharmony_ci int err = -1; 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ci threads = thread_map__new(-1, getpid(), UINT_MAX); 3458c2ecf20Sopenharmony_ci if (!threads) { 3468c2ecf20Sopenharmony_ci pr_debug("thread_map__new failed!\n"); 3478c2ecf20Sopenharmony_ci goto out_err; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci cpus = perf_cpu_map__new(NULL); 3518c2ecf20Sopenharmony_ci if (!cpus) { 3528c2ecf20Sopenharmony_ci pr_debug("perf_cpu_map__new failed!\n"); 3538c2ecf20Sopenharmony_ci goto out_err; 3548c2ecf20Sopenharmony_ci } 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci evlist = evlist__new(); 3578c2ecf20Sopenharmony_ci if (!evlist) { 3588c2ecf20Sopenharmony_ci pr_debug("evlist__new failed!\n"); 3598c2ecf20Sopenharmony_ci goto out_err; 3608c2ecf20Sopenharmony_ci } 3618c2ecf20Sopenharmony_ci 3628c2ecf20Sopenharmony_ci perf_evlist__set_maps(&evlist->core, cpus, threads); 3638c2ecf20Sopenharmony_ci 3648c2ecf20Sopenharmony_ci /* First event */ 3658c2ecf20Sopenharmony_ci err = parse_events(evlist, "cpu-clock:u", NULL); 3668c2ecf20Sopenharmony_ci if (err) { 3678c2ecf20Sopenharmony_ci pr_debug("Failed to parse event dummy:u\n"); 3688c2ecf20Sopenharmony_ci goto out_err; 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci cpu_clocks_evsel = evlist__last(evlist); 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci /* Second event */ 3748c2ecf20Sopenharmony_ci err = parse_events(evlist, "cycles:u", NULL); 3758c2ecf20Sopenharmony_ci if (err) { 3768c2ecf20Sopenharmony_ci pr_debug("Failed to parse event cycles:u\n"); 3778c2ecf20Sopenharmony_ci goto out_err; 3788c2ecf20Sopenharmony_ci } 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci cycles_evsel = evlist__last(evlist); 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci /* Third event */ 3838c2ecf20Sopenharmony_ci if (!perf_evlist__can_select_event(evlist, sched_switch)) { 3848c2ecf20Sopenharmony_ci pr_debug("No sched_switch\n"); 3858c2ecf20Sopenharmony_ci err = 0; 3868c2ecf20Sopenharmony_ci goto out; 3878c2ecf20Sopenharmony_ci } 3888c2ecf20Sopenharmony_ci 3898c2ecf20Sopenharmony_ci err = parse_events(evlist, sched_switch, NULL); 3908c2ecf20Sopenharmony_ci if (err) { 3918c2ecf20Sopenharmony_ci pr_debug("Failed to parse event %s\n", sched_switch); 3928c2ecf20Sopenharmony_ci goto out_err; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci switch_evsel = evlist__last(evlist); 3968c2ecf20Sopenharmony_ci 3978c2ecf20Sopenharmony_ci evsel__set_sample_bit(switch_evsel, CPU); 3988c2ecf20Sopenharmony_ci evsel__set_sample_bit(switch_evsel, TIME); 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci switch_evsel->core.system_wide = true; 4018c2ecf20Sopenharmony_ci switch_evsel->no_aux_samples = true; 4028c2ecf20Sopenharmony_ci switch_evsel->immediate = true; 4038c2ecf20Sopenharmony_ci 4048c2ecf20Sopenharmony_ci /* Test moving an event to the front */ 4058c2ecf20Sopenharmony_ci if (cycles_evsel == evlist__first(evlist)) { 4068c2ecf20Sopenharmony_ci pr_debug("cycles event already at front"); 4078c2ecf20Sopenharmony_ci goto out_err; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci perf_evlist__to_front(evlist, cycles_evsel); 4108c2ecf20Sopenharmony_ci if (cycles_evsel != evlist__first(evlist)) { 4118c2ecf20Sopenharmony_ci pr_debug("Failed to move cycles event to front"); 4128c2ecf20Sopenharmony_ci goto out_err; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci evsel__set_sample_bit(cycles_evsel, CPU); 4168c2ecf20Sopenharmony_ci evsel__set_sample_bit(cycles_evsel, TIME); 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_ci /* Fourth event */ 4198c2ecf20Sopenharmony_ci err = parse_events(evlist, "dummy:u", NULL); 4208c2ecf20Sopenharmony_ci if (err) { 4218c2ecf20Sopenharmony_ci pr_debug("Failed to parse event dummy:u\n"); 4228c2ecf20Sopenharmony_ci goto out_err; 4238c2ecf20Sopenharmony_ci } 4248c2ecf20Sopenharmony_ci 4258c2ecf20Sopenharmony_ci tracking_evsel = evlist__last(evlist); 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_ci perf_evlist__set_tracking_event(evlist, tracking_evsel); 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci tracking_evsel->core.attr.freq = 0; 4308c2ecf20Sopenharmony_ci tracking_evsel->core.attr.sample_period = 1; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci evsel__set_sample_bit(tracking_evsel, TIME); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci /* Config events */ 4358c2ecf20Sopenharmony_ci perf_evlist__config(evlist, &opts, NULL); 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci /* Check moved event is still at the front */ 4388c2ecf20Sopenharmony_ci if (cycles_evsel != evlist__first(evlist)) { 4398c2ecf20Sopenharmony_ci pr_debug("Front event no longer at front"); 4408c2ecf20Sopenharmony_ci goto out_err; 4418c2ecf20Sopenharmony_ci } 4428c2ecf20Sopenharmony_ci 4438c2ecf20Sopenharmony_ci /* Check tracking event is tracking */ 4448c2ecf20Sopenharmony_ci if (!tracking_evsel->core.attr.mmap || !tracking_evsel->core.attr.comm) { 4458c2ecf20Sopenharmony_ci pr_debug("Tracking event not tracking\n"); 4468c2ecf20Sopenharmony_ci goto out_err; 4478c2ecf20Sopenharmony_ci } 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci /* Check non-tracking events are not tracking */ 4508c2ecf20Sopenharmony_ci evlist__for_each_entry(evlist, evsel) { 4518c2ecf20Sopenharmony_ci if (evsel != tracking_evsel) { 4528c2ecf20Sopenharmony_ci if (evsel->core.attr.mmap || evsel->core.attr.comm) { 4538c2ecf20Sopenharmony_ci pr_debug("Non-tracking event is tracking\n"); 4548c2ecf20Sopenharmony_ci goto out_err; 4558c2ecf20Sopenharmony_ci } 4568c2ecf20Sopenharmony_ci } 4578c2ecf20Sopenharmony_ci } 4588c2ecf20Sopenharmony_ci 4598c2ecf20Sopenharmony_ci if (evlist__open(evlist) < 0) { 4608c2ecf20Sopenharmony_ci pr_debug("Not supported\n"); 4618c2ecf20Sopenharmony_ci err = 0; 4628c2ecf20Sopenharmony_ci goto out; 4638c2ecf20Sopenharmony_ci } 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci err = evlist__mmap(evlist, UINT_MAX); 4668c2ecf20Sopenharmony_ci if (err) { 4678c2ecf20Sopenharmony_ci pr_debug("evlist__mmap failed!\n"); 4688c2ecf20Sopenharmony_ci goto out_err; 4698c2ecf20Sopenharmony_ci } 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci evlist__enable(evlist); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci err = evsel__disable(cpu_clocks_evsel); 4748c2ecf20Sopenharmony_ci if (err) { 4758c2ecf20Sopenharmony_ci pr_debug("perf_evlist__disable_event failed!\n"); 4768c2ecf20Sopenharmony_ci goto out_err; 4778c2ecf20Sopenharmony_ci } 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ci err = spin_sleep(); 4808c2ecf20Sopenharmony_ci if (err) { 4818c2ecf20Sopenharmony_ci pr_debug("spin_sleep failed!\n"); 4828c2ecf20Sopenharmony_ci goto out_err; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci comm = "Test COMM 1"; 4868c2ecf20Sopenharmony_ci err = prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0); 4878c2ecf20Sopenharmony_ci if (err) { 4888c2ecf20Sopenharmony_ci pr_debug("PR_SET_NAME failed!\n"); 4898c2ecf20Sopenharmony_ci goto out_err; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci err = evsel__disable(cycles_evsel); 4938c2ecf20Sopenharmony_ci if (err) { 4948c2ecf20Sopenharmony_ci pr_debug("perf_evlist__disable_event failed!\n"); 4958c2ecf20Sopenharmony_ci goto out_err; 4968c2ecf20Sopenharmony_ci } 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci comm = "Test COMM 2"; 4998c2ecf20Sopenharmony_ci err = prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0); 5008c2ecf20Sopenharmony_ci if (err) { 5018c2ecf20Sopenharmony_ci pr_debug("PR_SET_NAME failed!\n"); 5028c2ecf20Sopenharmony_ci goto out_err; 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci err = spin_sleep(); 5068c2ecf20Sopenharmony_ci if (err) { 5078c2ecf20Sopenharmony_ci pr_debug("spin_sleep failed!\n"); 5088c2ecf20Sopenharmony_ci goto out_err; 5098c2ecf20Sopenharmony_ci } 5108c2ecf20Sopenharmony_ci 5118c2ecf20Sopenharmony_ci comm = "Test COMM 3"; 5128c2ecf20Sopenharmony_ci err = prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0); 5138c2ecf20Sopenharmony_ci if (err) { 5148c2ecf20Sopenharmony_ci pr_debug("PR_SET_NAME failed!\n"); 5158c2ecf20Sopenharmony_ci goto out_err; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci err = evsel__enable(cycles_evsel); 5198c2ecf20Sopenharmony_ci if (err) { 5208c2ecf20Sopenharmony_ci pr_debug("perf_evlist__disable_event failed!\n"); 5218c2ecf20Sopenharmony_ci goto out_err; 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_ci comm = "Test COMM 4"; 5258c2ecf20Sopenharmony_ci err = prctl(PR_SET_NAME, (unsigned long)comm, 0, 0, 0); 5268c2ecf20Sopenharmony_ci if (err) { 5278c2ecf20Sopenharmony_ci pr_debug("PR_SET_NAME failed!\n"); 5288c2ecf20Sopenharmony_ci goto out_err; 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci 5318c2ecf20Sopenharmony_ci err = spin_sleep(); 5328c2ecf20Sopenharmony_ci if (err) { 5338c2ecf20Sopenharmony_ci pr_debug("spin_sleep failed!\n"); 5348c2ecf20Sopenharmony_ci goto out_err; 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci evlist__disable(evlist); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci switch_tracking.switch_evsel = switch_evsel; 5408c2ecf20Sopenharmony_ci switch_tracking.cycles_evsel = cycles_evsel; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci err = process_events(evlist, &switch_tracking); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci zfree(&switch_tracking.tids); 5458c2ecf20Sopenharmony_ci 5468c2ecf20Sopenharmony_ci if (err) 5478c2ecf20Sopenharmony_ci goto out_err; 5488c2ecf20Sopenharmony_ci 5498c2ecf20Sopenharmony_ci /* Check all 4 comm events were seen i.e. that evsel->tracking works */ 5508c2ecf20Sopenharmony_ci if (!switch_tracking.comm_seen[0] || !switch_tracking.comm_seen[1] || 5518c2ecf20Sopenharmony_ci !switch_tracking.comm_seen[2] || !switch_tracking.comm_seen[3]) { 5528c2ecf20Sopenharmony_ci pr_debug("Missing comm events\n"); 5538c2ecf20Sopenharmony_ci goto out_err; 5548c2ecf20Sopenharmony_ci } 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci /* Check cycles event got enabled */ 5578c2ecf20Sopenharmony_ci if (!switch_tracking.cycles_before_comm_1) { 5588c2ecf20Sopenharmony_ci pr_debug("Missing cycles events\n"); 5598c2ecf20Sopenharmony_ci goto out_err; 5608c2ecf20Sopenharmony_ci } 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_ci /* Check cycles event got disabled */ 5638c2ecf20Sopenharmony_ci if (switch_tracking.cycles_between_comm_2_and_comm_3) { 5648c2ecf20Sopenharmony_ci pr_debug("cycles events even though event was disabled\n"); 5658c2ecf20Sopenharmony_ci goto out_err; 5668c2ecf20Sopenharmony_ci } 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_ci /* Check cycles event got enabled again */ 5698c2ecf20Sopenharmony_ci if (!switch_tracking.cycles_after_comm_4) { 5708c2ecf20Sopenharmony_ci pr_debug("Missing cycles events\n"); 5718c2ecf20Sopenharmony_ci goto out_err; 5728c2ecf20Sopenharmony_ci } 5738c2ecf20Sopenharmony_ciout: 5748c2ecf20Sopenharmony_ci if (evlist) { 5758c2ecf20Sopenharmony_ci evlist__disable(evlist); 5768c2ecf20Sopenharmony_ci evlist__delete(evlist); 5778c2ecf20Sopenharmony_ci } else { 5788c2ecf20Sopenharmony_ci perf_cpu_map__put(cpus); 5798c2ecf20Sopenharmony_ci perf_thread_map__put(threads); 5808c2ecf20Sopenharmony_ci } 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci return err; 5838c2ecf20Sopenharmony_ci 5848c2ecf20Sopenharmony_ciout_err: 5858c2ecf20Sopenharmony_ci err = -1; 5868c2ecf20Sopenharmony_ci goto out; 5878c2ecf20Sopenharmony_ci} 588