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