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