brintos

brintos / linux-shallow public Read only

0
0
Text · 7.7 KiB · 012c8ae Raw
310 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <errno.h>3#include <inttypes.h>4#include <stdlib.h>5#include <perf/cpumap.h>6 7#include "debug.h"8#include "event.h"9#include "evlist.h"10#include "evsel.h"11#include "thread_map.h"12#include "tests.h"13#include "util/mmap.h"14#include "util/sample.h"15#include <linux/err.h>16#include <linux/kernel.h>17#include <linux/string.h>18#include <perf/evlist.h>19#include <perf/mmap.h>20 21/*22 * This test will generate random numbers of calls to some getpid syscalls,23 * then establish an mmap for a group of events that are created to monitor24 * the syscalls.25 *26 * It will receive the events, using mmap, use its PERF_SAMPLE_ID generated27 * sample.id field to map back to its respective perf_evsel instance.28 *29 * Then it checks if the number of syscalls reported as perf events by30 * the kernel corresponds to the number of syscalls made.31 */32static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest __maybe_unused)33{34	int err = TEST_FAIL;35	union perf_event *event;36	struct perf_thread_map *threads;37	struct perf_cpu_map *cpus;38	struct evlist *evlist;39	cpu_set_t cpu_set;40	const char *syscall_names[] = { "getsid", "getppid", "getpgid", };41	pid_t (*syscalls[])(void) = { (void *)getsid, getppid, (void*)getpgid };42#define nsyscalls ARRAY_SIZE(syscall_names)43	unsigned int nr_events[nsyscalls],44		     expected_nr_events[nsyscalls], i, j;45	struct evsel *evsels[nsyscalls], *evsel;46	char sbuf[STRERR_BUFSIZE];47	struct mmap *md;48 49	threads = thread_map__new(-1, getpid(), UINT_MAX);50	if (threads == NULL) {51		pr_debug("thread_map__new\n");52		return -1;53	}54 55	cpus = perf_cpu_map__new_online_cpus();56	if (cpus == NULL) {57		pr_debug("perf_cpu_map__new\n");58		goto out_free_threads;59	}60 61	CPU_ZERO(&cpu_set);62	CPU_SET(perf_cpu_map__cpu(cpus, 0).cpu, &cpu_set);63	sched_setaffinity(0, sizeof(cpu_set), &cpu_set);64	if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) {65		pr_debug("sched_setaffinity() failed on CPU %d: %s ",66			 perf_cpu_map__cpu(cpus, 0).cpu,67			 str_error_r(errno, sbuf, sizeof(sbuf)));68		goto out_free_cpus;69	}70 71	evlist = evlist__new();72	if (evlist == NULL) {73		pr_debug("evlist__new\n");74		goto out_free_cpus;75	}76 77	perf_evlist__set_maps(&evlist->core, cpus, threads);78 79	for (i = 0; i < nsyscalls; ++i) {80		char name[64];81 82		snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]);83		evsels[i] = evsel__newtp("syscalls", name);84		if (IS_ERR(evsels[i])) {85			pr_debug("evsel__new(%s)\n", name);86			if (PTR_ERR(evsels[i]) == -EACCES) {87				/* Permissions failure, flag the failure as a skip. */88				err = TEST_SKIP;89			}90			goto out_delete_evlist;91		}92 93		evsels[i]->core.attr.wakeup_events = 1;94		evsel__set_sample_id(evsels[i], false);95 96		evlist__add(evlist, evsels[i]);97 98		if (evsel__open(evsels[i], cpus, threads) < 0) {99			pr_debug("failed to open counter: %s, "100				 "tweak /proc/sys/kernel/perf_event_paranoid?\n",101				 str_error_r(errno, sbuf, sizeof(sbuf)));102			goto out_delete_evlist;103		}104 105		nr_events[i] = 0;106		expected_nr_events[i] = 1 + rand() % 127;107	}108 109	if (evlist__mmap(evlist, 128) < 0) {110		pr_debug("failed to mmap events: %d (%s)\n", errno,111			 str_error_r(errno, sbuf, sizeof(sbuf)));112		goto out_delete_evlist;113	}114 115	for (i = 0; i < nsyscalls; ++i)116		for (j = 0; j < expected_nr_events[i]; ++j) {117			syscalls[i]();118		}119 120	md = &evlist->mmap[0];121	if (perf_mmap__read_init(&md->core) < 0)122		goto out_init;123 124	while ((event = perf_mmap__read_event(&md->core)) != NULL) {125		struct perf_sample sample;126 127		if (event->header.type != PERF_RECORD_SAMPLE) {128			pr_debug("unexpected %s event\n",129				 perf_event__name(event->header.type));130			goto out_delete_evlist;131		}132 133		err = evlist__parse_sample(evlist, event, &sample);134		if (err) {135			pr_err("Can't parse sample, err = %d\n", err);136			goto out_delete_evlist;137		}138 139		err = -1;140		evsel = evlist__id2evsel(evlist, sample.id);141		if (evsel == NULL) {142			pr_debug("event with id %" PRIu64143				 " doesn't map to an evsel\n", sample.id);144			goto out_delete_evlist;145		}146		nr_events[evsel->core.idx]++;147		perf_mmap__consume(&md->core);148	}149	perf_mmap__read_done(&md->core);150 151out_init:152	err = 0;153	evlist__for_each_entry(evlist, evsel) {154		if (nr_events[evsel->core.idx] != expected_nr_events[evsel->core.idx]) {155			pr_debug("expected %d %s events, got %d\n",156				 expected_nr_events[evsel->core.idx],157				 evsel__name(evsel), nr_events[evsel->core.idx]);158			err = -1;159			goto out_delete_evlist;160		}161	}162 163out_delete_evlist:164	evlist__delete(evlist);165out_free_cpus:166	perf_cpu_map__put(cpus);167out_free_threads:168	perf_thread_map__put(threads);169	return err;170}171 172static int test_stat_user_read(int event)173{174	struct perf_counts_values counts = { .val = 0 };175	struct perf_thread_map *threads;176	struct perf_evsel *evsel;177	struct perf_event_mmap_page *pc;178	struct perf_event_attr attr = {179		.type	= PERF_TYPE_HARDWARE,180		.config	= event,181#ifdef __aarch64__182		.config1 = 0x2,		/* Request user access */183#endif184	};185	int err, i, ret = TEST_FAIL;186	bool opened = false, mapped = false;187 188	threads = perf_thread_map__new_dummy();189	TEST_ASSERT_VAL("failed to create threads", threads);190 191	perf_thread_map__set_pid(threads, 0, 0);192 193	evsel = perf_evsel__new(&attr);194	TEST_ASSERT_VAL("failed to create evsel", evsel);195 196	err = perf_evsel__open(evsel, NULL, threads);197	if (err) {198		pr_err("failed to open evsel: %s\n", strerror(-err));199		ret = TEST_SKIP;200		goto out;201	}202	opened = true;203 204	err = perf_evsel__mmap(evsel, 0);205	if (err) {206		pr_err("failed to mmap evsel: %s\n", strerror(-err));207		goto out;208	}209	mapped = true;210 211	pc = perf_evsel__mmap_base(evsel, 0, 0);212	if (!pc) {213		pr_err("failed to get mmapped address\n");214		goto out;215	}216 217	if (!pc->cap_user_rdpmc || !pc->index) {218		pr_err("userspace counter access not %s\n",219			!pc->cap_user_rdpmc ? "supported" : "enabled");220		ret = TEST_SKIP;221		goto out;222	}223	if (pc->pmc_width < 32) {224		pr_err("userspace counter width not set (%d)\n", pc->pmc_width);225		goto out;226	}227 228	perf_evsel__read(evsel, 0, 0, &counts);229	if (counts.val == 0) {230		pr_err("failed to read value for evsel\n");231		goto out;232	}233 234	for (i = 0; i < 5; i++) {235		volatile int count = 0x10000 << i;236		__u64 start, end, last = 0;237 238		pr_debug("\tloop = %u, ", count);239 240		perf_evsel__read(evsel, 0, 0, &counts);241		start = counts.val;242 243		while (count--) ;244 245		perf_evsel__read(evsel, 0, 0, &counts);246		end = counts.val;247 248		if ((end - start) < last) {249			pr_err("invalid counter data: end=%llu start=%llu last= %llu\n",250				end, start, last);251			goto out;252		}253		last = end - start;254		pr_debug("count = %llu\n", end - start);255	}256	ret = TEST_OK;257 258out:259	if (mapped)260		perf_evsel__munmap(evsel);261	if (opened)262		perf_evsel__close(evsel);263	perf_evsel__delete(evsel);264 265	perf_thread_map__put(threads);266	return ret;267}268 269static int test__mmap_user_read_instr(struct test_suite *test __maybe_unused,270				      int subtest __maybe_unused)271{272	return test_stat_user_read(PERF_COUNT_HW_INSTRUCTIONS);273}274 275static int test__mmap_user_read_cycles(struct test_suite *test __maybe_unused,276				       int subtest __maybe_unused)277{278	return test_stat_user_read(PERF_COUNT_HW_CPU_CYCLES);279}280 281static struct test_case tests__basic_mmap[] = {282	TEST_CASE_REASON("Read samples using the mmap interface",283			 basic_mmap,284			 "permissions"),285	TEST_CASE_REASON("User space counter reading of instructions",286			 mmap_user_read_instr,287#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \288			 (defined(__riscv) && __riscv_xlen == 64)289			 "permissions"290#else291			 "unsupported"292#endif293		),294	TEST_CASE_REASON("User space counter reading of cycles",295			 mmap_user_read_cycles,296#if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \297			 (defined(__riscv) && __riscv_xlen == 64)298			 "permissions"299#else300			 "unsupported"301#endif302		),303	{	.name = NULL, }304};305 306struct test_suite suite__basic_mmap = {307	.desc = "mmap interface tests",308	.test_cases = tests__basic_mmap,309};310