18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * The struct perf_event_attr test support.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * This test is embedded inside into perf directly and is governed
68c2ecf20Sopenharmony_ci * by the PERF_TEST_ATTR environment variable and hook inside
78c2ecf20Sopenharmony_ci * sys_perf_event_open function.
88c2ecf20Sopenharmony_ci *
98c2ecf20Sopenharmony_ci * The general idea is to store 'struct perf_event_attr' details for
108c2ecf20Sopenharmony_ci * each event created within single perf command. Each event details
118c2ecf20Sopenharmony_ci * are stored into separate text file. Once perf command is finished
128c2ecf20Sopenharmony_ci * these files can be checked for values we expect for command.
138c2ecf20Sopenharmony_ci *
148c2ecf20Sopenharmony_ci * Besides 'struct perf_event_attr' values we also store 'fd' and
158c2ecf20Sopenharmony_ci * 'group_fd' values to allow checking for groups created.
168c2ecf20Sopenharmony_ci *
178c2ecf20Sopenharmony_ci * This all is triggered by setting PERF_TEST_ATTR environment variable.
188c2ecf20Sopenharmony_ci * It must contain name of existing directory with access and write
198c2ecf20Sopenharmony_ci * permissions. All the event text files are stored there.
208c2ecf20Sopenharmony_ci */
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <debug.h>
238c2ecf20Sopenharmony_ci#include <errno.h>
248c2ecf20Sopenharmony_ci#include <inttypes.h>
258c2ecf20Sopenharmony_ci#include <stdlib.h>
268c2ecf20Sopenharmony_ci#include <stdio.h>
278c2ecf20Sopenharmony_ci#include <linux/types.h>
288c2ecf20Sopenharmony_ci#include <linux/kernel.h>
298c2ecf20Sopenharmony_ci#include <sys/param.h>
308c2ecf20Sopenharmony_ci#include <sys/types.h>
318c2ecf20Sopenharmony_ci#include <sys/stat.h>
328c2ecf20Sopenharmony_ci#include <unistd.h>
338c2ecf20Sopenharmony_ci#include <subcmd/exec-cmd.h>
348c2ecf20Sopenharmony_ci#include "event.h"
358c2ecf20Sopenharmony_ci#include "util.h"
368c2ecf20Sopenharmony_ci#include "tests.h"
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci#define ENV "PERF_TEST_ATTR"
398c2ecf20Sopenharmony_ci
408c2ecf20Sopenharmony_cistatic char *dir;
418c2ecf20Sopenharmony_cistatic bool ready;
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_civoid test_attr__init(void)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	dir = getenv(ENV);
468c2ecf20Sopenharmony_ci	test_attr__enabled = (dir != NULL);
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci#define BUFSIZE 1024
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_ci#define __WRITE_ASS(str, fmt, data)					\
528c2ecf20Sopenharmony_cido {									\
538c2ecf20Sopenharmony_ci	char buf[BUFSIZE];						\
548c2ecf20Sopenharmony_ci	size_t size;							\
558c2ecf20Sopenharmony_ci									\
568c2ecf20Sopenharmony_ci	size = snprintf(buf, BUFSIZE, #str "=%"fmt "\n", data);		\
578c2ecf20Sopenharmony_ci	if (1 != fwrite(buf, size, 1, file)) {				\
588c2ecf20Sopenharmony_ci		perror("test attr - failed to write event file");	\
598c2ecf20Sopenharmony_ci		fclose(file);						\
608c2ecf20Sopenharmony_ci		return -1;						\
618c2ecf20Sopenharmony_ci	}								\
628c2ecf20Sopenharmony_ci									\
638c2ecf20Sopenharmony_ci} while (0)
648c2ecf20Sopenharmony_ci
658c2ecf20Sopenharmony_ci#define WRITE_ASS(field, fmt) __WRITE_ASS(field, fmt, attr->field)
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic int store_event(struct perf_event_attr *attr, pid_t pid, int cpu,
688c2ecf20Sopenharmony_ci		       int fd, int group_fd, unsigned long flags)
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	FILE *file;
718c2ecf20Sopenharmony_ci	char path[PATH_MAX];
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	if (!ready)
748c2ecf20Sopenharmony_ci		return 0;
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	snprintf(path, PATH_MAX, "%s/event-%d-%llu-%d", dir,
778c2ecf20Sopenharmony_ci		 attr->type, attr->config, fd);
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	file = fopen(path, "w+");
808c2ecf20Sopenharmony_ci	if (!file) {
818c2ecf20Sopenharmony_ci		perror("test attr - failed to open event file");
828c2ecf20Sopenharmony_ci		return -1;
838c2ecf20Sopenharmony_ci	}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_ci	if (fprintf(file, "[event-%d-%llu-%d]\n",
868c2ecf20Sopenharmony_ci		    attr->type, attr->config, fd) < 0) {
878c2ecf20Sopenharmony_ci		perror("test attr - failed to write event file");
888c2ecf20Sopenharmony_ci		fclose(file);
898c2ecf20Sopenharmony_ci		return -1;
908c2ecf20Sopenharmony_ci	}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci	/* syscall arguments */
938c2ecf20Sopenharmony_ci	__WRITE_ASS(fd,       "d", fd);
948c2ecf20Sopenharmony_ci	__WRITE_ASS(group_fd, "d", group_fd);
958c2ecf20Sopenharmony_ci	__WRITE_ASS(cpu,      "d", cpu);
968c2ecf20Sopenharmony_ci	__WRITE_ASS(pid,      "d", pid);
978c2ecf20Sopenharmony_ci	__WRITE_ASS(flags,   "lu", flags);
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	/* struct perf_event_attr */
1008c2ecf20Sopenharmony_ci	WRITE_ASS(type,   PRIu32);
1018c2ecf20Sopenharmony_ci	WRITE_ASS(size,   PRIu32);
1028c2ecf20Sopenharmony_ci	WRITE_ASS(config,  "llu");
1038c2ecf20Sopenharmony_ci	WRITE_ASS(sample_period, "llu");
1048c2ecf20Sopenharmony_ci	WRITE_ASS(sample_type,   "llu");
1058c2ecf20Sopenharmony_ci	WRITE_ASS(read_format,   "llu");
1068c2ecf20Sopenharmony_ci	WRITE_ASS(disabled,       "d");
1078c2ecf20Sopenharmony_ci	WRITE_ASS(inherit,        "d");
1088c2ecf20Sopenharmony_ci	WRITE_ASS(pinned,         "d");
1098c2ecf20Sopenharmony_ci	WRITE_ASS(exclusive,      "d");
1108c2ecf20Sopenharmony_ci	WRITE_ASS(exclude_user,   "d");
1118c2ecf20Sopenharmony_ci	WRITE_ASS(exclude_kernel, "d");
1128c2ecf20Sopenharmony_ci	WRITE_ASS(exclude_hv,     "d");
1138c2ecf20Sopenharmony_ci	WRITE_ASS(exclude_idle,   "d");
1148c2ecf20Sopenharmony_ci	WRITE_ASS(mmap,           "d");
1158c2ecf20Sopenharmony_ci	WRITE_ASS(comm,           "d");
1168c2ecf20Sopenharmony_ci	WRITE_ASS(freq,           "d");
1178c2ecf20Sopenharmony_ci	WRITE_ASS(inherit_stat,   "d");
1188c2ecf20Sopenharmony_ci	WRITE_ASS(enable_on_exec, "d");
1198c2ecf20Sopenharmony_ci	WRITE_ASS(task,           "d");
1208c2ecf20Sopenharmony_ci	WRITE_ASS(watermark,      "d");
1218c2ecf20Sopenharmony_ci	WRITE_ASS(precise_ip,     "d");
1228c2ecf20Sopenharmony_ci	WRITE_ASS(mmap_data,      "d");
1238c2ecf20Sopenharmony_ci	WRITE_ASS(sample_id_all,  "d");
1248c2ecf20Sopenharmony_ci	WRITE_ASS(exclude_host,   "d");
1258c2ecf20Sopenharmony_ci	WRITE_ASS(exclude_guest,  "d");
1268c2ecf20Sopenharmony_ci	WRITE_ASS(exclude_callchain_kernel, "d");
1278c2ecf20Sopenharmony_ci	WRITE_ASS(exclude_callchain_user, "d");
1288c2ecf20Sopenharmony_ci	WRITE_ASS(mmap2,	  "d");
1298c2ecf20Sopenharmony_ci	WRITE_ASS(comm_exec,	  "d");
1308c2ecf20Sopenharmony_ci	WRITE_ASS(context_switch, "d");
1318c2ecf20Sopenharmony_ci	WRITE_ASS(write_backward, "d");
1328c2ecf20Sopenharmony_ci	WRITE_ASS(namespaces,	  "d");
1338c2ecf20Sopenharmony_ci	WRITE_ASS(use_clockid,    "d");
1348c2ecf20Sopenharmony_ci	WRITE_ASS(wakeup_events, PRIu32);
1358c2ecf20Sopenharmony_ci	WRITE_ASS(bp_type, PRIu32);
1368c2ecf20Sopenharmony_ci	WRITE_ASS(config1, "llu");
1378c2ecf20Sopenharmony_ci	WRITE_ASS(config2, "llu");
1388c2ecf20Sopenharmony_ci	WRITE_ASS(branch_sample_type, "llu");
1398c2ecf20Sopenharmony_ci	WRITE_ASS(sample_regs_user,   "llu");
1408c2ecf20Sopenharmony_ci	WRITE_ASS(sample_stack_user,  PRIu32);
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	fclose(file);
1438c2ecf20Sopenharmony_ci	return 0;
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_civoid test_attr__open(struct perf_event_attr *attr, pid_t pid, int cpu,
1478c2ecf20Sopenharmony_ci		     int fd, int group_fd, unsigned long flags)
1488c2ecf20Sopenharmony_ci{
1498c2ecf20Sopenharmony_ci	int errno_saved = errno;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	if ((fd != -1) && store_event(attr, pid, cpu, fd, group_fd, flags)) {
1528c2ecf20Sopenharmony_ci		pr_err("test attr FAILED");
1538c2ecf20Sopenharmony_ci		exit(128);
1548c2ecf20Sopenharmony_ci	}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	errno = errno_saved;
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_civoid test_attr__ready(void)
1608c2ecf20Sopenharmony_ci{
1618c2ecf20Sopenharmony_ci	if (unlikely(test_attr__enabled) && !ready)
1628c2ecf20Sopenharmony_ci		ready = true;
1638c2ecf20Sopenharmony_ci}
1648c2ecf20Sopenharmony_ci
1658c2ecf20Sopenharmony_cistatic int run_dir(const char *d, const char *perf)
1668c2ecf20Sopenharmony_ci{
1678c2ecf20Sopenharmony_ci	char v[] = "-vvvvv";
1688c2ecf20Sopenharmony_ci	int vcnt = min(verbose, (int) sizeof(v) - 1);
1698c2ecf20Sopenharmony_ci	char cmd[3*PATH_MAX];
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	if (verbose > 0)
1728c2ecf20Sopenharmony_ci		vcnt++;
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci	scnprintf(cmd, 3*PATH_MAX, PYTHON " %s/attr.py -d %s/attr/ -p %s %.*s",
1758c2ecf20Sopenharmony_ci		  d, d, perf, vcnt, v);
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	return system(cmd) ? TEST_FAIL : TEST_OK;
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ciint test__attr(struct test *test __maybe_unused, int subtest __maybe_unused)
1818c2ecf20Sopenharmony_ci{
1828c2ecf20Sopenharmony_ci	struct stat st;
1838c2ecf20Sopenharmony_ci	char path_perf[PATH_MAX];
1848c2ecf20Sopenharmony_ci	char path_dir[PATH_MAX];
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci	/* First try development tree tests. */
1878c2ecf20Sopenharmony_ci	if (!lstat("./tests", &st))
1888c2ecf20Sopenharmony_ci		return run_dir("./tests", "./perf");
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	/* Then installed path. */
1918c2ecf20Sopenharmony_ci	snprintf(path_dir,  PATH_MAX, "%s/tests", get_argv_exec_path());
1928c2ecf20Sopenharmony_ci	snprintf(path_perf, PATH_MAX, "%s/perf", BINDIR);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	if (!lstat(path_dir, &st) &&
1958c2ecf20Sopenharmony_ci	    !lstat(path_perf, &st))
1968c2ecf20Sopenharmony_ci		return run_dir(path_dir, path_perf);
1978c2ecf20Sopenharmony_ci
1988c2ecf20Sopenharmony_ci	return TEST_SKIP;
1998c2ecf20Sopenharmony_ci}
200