18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include <errno.h>
38c2ecf20Sopenharmony_ci#include <inttypes.h>
48c2ecf20Sopenharmony_ci/* For the CLR_() macros */
58c2ecf20Sopenharmony_ci#include <pthread.h>
68c2ecf20Sopenharmony_ci#include <stdlib.h>
78c2ecf20Sopenharmony_ci#include <perf/cpumap.h>
88c2ecf20Sopenharmony_ci
98c2ecf20Sopenharmony_ci#include "debug.h"
108c2ecf20Sopenharmony_ci#include "evlist.h"
118c2ecf20Sopenharmony_ci#include "evsel.h"
128c2ecf20Sopenharmony_ci#include "thread_map.h"
138c2ecf20Sopenharmony_ci#include "tests.h"
148c2ecf20Sopenharmony_ci#include "util/mmap.h"
158c2ecf20Sopenharmony_ci#include <linux/err.h>
168c2ecf20Sopenharmony_ci#include <linux/kernel.h>
178c2ecf20Sopenharmony_ci#include <linux/string.h>
188c2ecf20Sopenharmony_ci#include <perf/evlist.h>
198c2ecf20Sopenharmony_ci#include <perf/mmap.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/*
228c2ecf20Sopenharmony_ci * This test will generate random numbers of calls to some getpid syscalls,
238c2ecf20Sopenharmony_ci * then establish an mmap for a group of events that are created to monitor
248c2ecf20Sopenharmony_ci * the syscalls.
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci * It will receive the events, using mmap, use its PERF_SAMPLE_ID generated
278c2ecf20Sopenharmony_ci * sample.id field to map back to its respective perf_evsel instance.
288c2ecf20Sopenharmony_ci *
298c2ecf20Sopenharmony_ci * Then it checks if the number of syscalls reported as perf events by
308c2ecf20Sopenharmony_ci * the kernel corresponds to the number of syscalls made.
318c2ecf20Sopenharmony_ci */
328c2ecf20Sopenharmony_ciint test__basic_mmap(struct test *test __maybe_unused, int subtest __maybe_unused)
338c2ecf20Sopenharmony_ci{
348c2ecf20Sopenharmony_ci	int err = -1;
358c2ecf20Sopenharmony_ci	union perf_event *event;
368c2ecf20Sopenharmony_ci	struct perf_thread_map *threads;
378c2ecf20Sopenharmony_ci	struct perf_cpu_map *cpus;
388c2ecf20Sopenharmony_ci	struct evlist *evlist;
398c2ecf20Sopenharmony_ci	cpu_set_t cpu_set;
408c2ecf20Sopenharmony_ci	const char *syscall_names[] = { "getsid", "getppid", "getpgid", };
418c2ecf20Sopenharmony_ci	pid_t (*syscalls[])(void) = { (void *)getsid, getppid, (void*)getpgid };
428c2ecf20Sopenharmony_ci#define nsyscalls ARRAY_SIZE(syscall_names)
438c2ecf20Sopenharmony_ci	unsigned int nr_events[nsyscalls],
448c2ecf20Sopenharmony_ci		     expected_nr_events[nsyscalls], i, j;
458c2ecf20Sopenharmony_ci	struct evsel *evsels[nsyscalls], *evsel;
468c2ecf20Sopenharmony_ci	char sbuf[STRERR_BUFSIZE];
478c2ecf20Sopenharmony_ci	struct mmap *md;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	threads = thread_map__new(-1, getpid(), UINT_MAX);
508c2ecf20Sopenharmony_ci	if (threads == NULL) {
518c2ecf20Sopenharmony_ci		pr_debug("thread_map__new\n");
528c2ecf20Sopenharmony_ci		return -1;
538c2ecf20Sopenharmony_ci	}
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_ci	cpus = perf_cpu_map__new(NULL);
568c2ecf20Sopenharmony_ci	if (cpus == NULL) {
578c2ecf20Sopenharmony_ci		pr_debug("perf_cpu_map__new\n");
588c2ecf20Sopenharmony_ci		goto out_free_threads;
598c2ecf20Sopenharmony_ci	}
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci	CPU_ZERO(&cpu_set);
628c2ecf20Sopenharmony_ci	CPU_SET(cpus->map[0], &cpu_set);
638c2ecf20Sopenharmony_ci	sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
648c2ecf20Sopenharmony_ci	if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {
658c2ecf20Sopenharmony_ci		pr_debug("sched_setaffinity() failed on CPU %d: %s ",
668c2ecf20Sopenharmony_ci			 cpus->map[0], str_error_r(errno, sbuf, sizeof(sbuf)));
678c2ecf20Sopenharmony_ci		goto out_free_cpus;
688c2ecf20Sopenharmony_ci	}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	evlist = evlist__new();
718c2ecf20Sopenharmony_ci	if (evlist == NULL) {
728c2ecf20Sopenharmony_ci		pr_debug("perf_evlist__new\n");
738c2ecf20Sopenharmony_ci		goto out_free_cpus;
748c2ecf20Sopenharmony_ci	}
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	perf_evlist__set_maps(&evlist->core, cpus, threads);
778c2ecf20Sopenharmony_ci
788c2ecf20Sopenharmony_ci	for (i = 0; i < nsyscalls; ++i) {
798c2ecf20Sopenharmony_ci		char name[64];
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci		snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]);
828c2ecf20Sopenharmony_ci		evsels[i] = evsel__newtp("syscalls", name);
838c2ecf20Sopenharmony_ci		if (IS_ERR(evsels[i])) {
848c2ecf20Sopenharmony_ci			pr_debug("evsel__new(%s)\n", name);
858c2ecf20Sopenharmony_ci			goto out_delete_evlist;
868c2ecf20Sopenharmony_ci		}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci		evsels[i]->core.attr.wakeup_events = 1;
898c2ecf20Sopenharmony_ci		evsel__set_sample_id(evsels[i], false);
908c2ecf20Sopenharmony_ci
918c2ecf20Sopenharmony_ci		evlist__add(evlist, evsels[i]);
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_ci		if (evsel__open(evsels[i], cpus, threads) < 0) {
948c2ecf20Sopenharmony_ci			pr_debug("failed to open counter: %s, "
958c2ecf20Sopenharmony_ci				 "tweak /proc/sys/kernel/perf_event_paranoid?\n",
968c2ecf20Sopenharmony_ci				 str_error_r(errno, sbuf, sizeof(sbuf)));
978c2ecf20Sopenharmony_ci			goto out_delete_evlist;
988c2ecf20Sopenharmony_ci		}
998c2ecf20Sopenharmony_ci
1008c2ecf20Sopenharmony_ci		nr_events[i] = 0;
1018c2ecf20Sopenharmony_ci		expected_nr_events[i] = 1 + rand() % 127;
1028c2ecf20Sopenharmony_ci	}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	if (evlist__mmap(evlist, 128) < 0) {
1058c2ecf20Sopenharmony_ci		pr_debug("failed to mmap events: %d (%s)\n", errno,
1068c2ecf20Sopenharmony_ci			 str_error_r(errno, sbuf, sizeof(sbuf)));
1078c2ecf20Sopenharmony_ci		goto out_delete_evlist;
1088c2ecf20Sopenharmony_ci	}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	for (i = 0; i < nsyscalls; ++i)
1118c2ecf20Sopenharmony_ci		for (j = 0; j < expected_nr_events[i]; ++j) {
1128c2ecf20Sopenharmony_ci			int foo = syscalls[i]();
1138c2ecf20Sopenharmony_ci			++foo;
1148c2ecf20Sopenharmony_ci		}
1158c2ecf20Sopenharmony_ci
1168c2ecf20Sopenharmony_ci	md = &evlist->mmap[0];
1178c2ecf20Sopenharmony_ci	if (perf_mmap__read_init(&md->core) < 0)
1188c2ecf20Sopenharmony_ci		goto out_init;
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	while ((event = perf_mmap__read_event(&md->core)) != NULL) {
1218c2ecf20Sopenharmony_ci		struct perf_sample sample;
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_ci		if (event->header.type != PERF_RECORD_SAMPLE) {
1248c2ecf20Sopenharmony_ci			pr_debug("unexpected %s event\n",
1258c2ecf20Sopenharmony_ci				 perf_event__name(event->header.type));
1268c2ecf20Sopenharmony_ci			goto out_delete_evlist;
1278c2ecf20Sopenharmony_ci		}
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci		err = perf_evlist__parse_sample(evlist, event, &sample);
1308c2ecf20Sopenharmony_ci		if (err) {
1318c2ecf20Sopenharmony_ci			pr_err("Can't parse sample, err = %d\n", err);
1328c2ecf20Sopenharmony_ci			goto out_delete_evlist;
1338c2ecf20Sopenharmony_ci		}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci		err = -1;
1368c2ecf20Sopenharmony_ci		evsel = perf_evlist__id2evsel(evlist, sample.id);
1378c2ecf20Sopenharmony_ci		if (evsel == NULL) {
1388c2ecf20Sopenharmony_ci			pr_debug("event with id %" PRIu64
1398c2ecf20Sopenharmony_ci				 " doesn't map to an evsel\n", sample.id);
1408c2ecf20Sopenharmony_ci			goto out_delete_evlist;
1418c2ecf20Sopenharmony_ci		}
1428c2ecf20Sopenharmony_ci		nr_events[evsel->idx]++;
1438c2ecf20Sopenharmony_ci		perf_mmap__consume(&md->core);
1448c2ecf20Sopenharmony_ci	}
1458c2ecf20Sopenharmony_ci	perf_mmap__read_done(&md->core);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ciout_init:
1488c2ecf20Sopenharmony_ci	err = 0;
1498c2ecf20Sopenharmony_ci	evlist__for_each_entry(evlist, evsel) {
1508c2ecf20Sopenharmony_ci		if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) {
1518c2ecf20Sopenharmony_ci			pr_debug("expected %d %s events, got %d\n",
1528c2ecf20Sopenharmony_ci				 expected_nr_events[evsel->idx],
1538c2ecf20Sopenharmony_ci				 evsel__name(evsel), nr_events[evsel->idx]);
1548c2ecf20Sopenharmony_ci			err = -1;
1558c2ecf20Sopenharmony_ci			goto out_delete_evlist;
1568c2ecf20Sopenharmony_ci		}
1578c2ecf20Sopenharmony_ci	}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ciout_delete_evlist:
1608c2ecf20Sopenharmony_ci	evlist__delete(evlist);
1618c2ecf20Sopenharmony_ci	cpus	= NULL;
1628c2ecf20Sopenharmony_ci	threads = NULL;
1638c2ecf20Sopenharmony_ciout_free_cpus:
1648c2ecf20Sopenharmony_ci	perf_cpu_map__put(cpus);
1658c2ecf20Sopenharmony_ciout_free_threads:
1668c2ecf20Sopenharmony_ci	perf_thread_map__put(threads);
1678c2ecf20Sopenharmony_ci	return err;
1688c2ecf20Sopenharmony_ci}
169