/* perf_common.c COPYRIGHT FUJITSU LIMITED 2019 */ #include "perf_common.h" const char *the_app; // // usage // void print_usage(void) { printf("usage : %s [test_num]\n" "test_num :\n" " 1 simple_test\n" " 2 read_test\n" " 3 reset_test\n" " 4 refresh_test\n" " 5 combination_test\n" "\n" "combination_test :\n" " perf_test 5 -c [ctrl1,ctrl2...]\n" "ex) perf_test 5 -c READ,RESET,REFRESH\n", the_app ); } // // system call // long perf_event_open(struct perf_event_attr *event_attr, pid_t pid, int cpu, int group_fd, unsigned long flags) { int ret = syscall(__NR_perf_event_open, event_attr, pid, cpu, group_fd, flags); return ret; } int init_perf_event_attr(struct perf_event_attr *event_attr) { int ret = -EINVAL; if (event_attr == NULL) { goto out; } memset(event_attr, 0, sizeof(struct perf_event_attr)); event_attr->type = PERF_TYPE_HARDWARE; event_attr->size = sizeof(struct perf_event_attr); event_attr->config = PERF_COUNT_HW_INSTRUCTIONS; event_attr->sample_period = SAMPLE_PERIOD; event_attr->disabled = 1; event_attr->exclude_kernel = 1; event_attr->exclude_hv = 1; ret = 0; out: return ret; } static long system_call3(long syscall_number, long arg0, long arg1, long arg2) { long ret; #if defined(__x86_64__) asm volatile ("syscall" : "=a" (ret) : "a" (syscall_number), "D" (arg0), "S" (arg1), "d" (arg2) : "rcx", "r11", "memory"); #elif defined(__aarch64__) asm volatile( "mov x8, %1;" "mov x0, %2;" "mov x1, %3;" "mov x2, %4;" "svc #0x0;" "mov %0, x0;" : "=r" (ret) : "r" (syscall_number), "r" (arg0), "r" (arg1), "r" (arg2)); #else # error not supported architecture. #endif if (ret < 0) { errno = -ret; } return ret; } int asm_ioctl3(int fd, unsigned long arg1, unsigned long arg2) { return system_call3(__NR_ioctl, fd, arg1, arg2); } int asm_read(int fd, void *buf, size_t size) { return system_call3(__NR_read, fd, (unsigned long)buf, size); } // // command // // sys_read command struct sys_read_arg { long long count; }; static int sys_read(int fd, void *_args) { struct sys_read_arg *args = _args; int ret = asm_read(fd, &args->count, sizeof(args->count)); if (ret < 0) { errno = -ret; perror("sys_read"); } return ret; } static void print_sys_read(void *_args) { struct sys_read_arg *args = _args; printf("sys_read: %lld\n", args->count); } static void release_sys_read_command(struct command *cmd) { free(cmd->args); cmd->args = NULL; } static void build_sys_read_command(struct command *cmd) { cmd->do_cmd = sys_read; cmd->args = calloc(sizeof(struct sys_read_arg), 1); cmd->release = release_sys_read_command; cmd->print = print_sys_read; } // perf_event_ioc_reset command static int perf_event_ioc_reset(int fd, void *_args) { int ret = asm_ioctl3(fd, PERF_EVENT_IOC_RESET, 0); if (ret < 0) { errno = -ret; perror("sys_ioctl: reset"); } return ret; } static void print_perf_event_ioc_reset(void *cmd) { printf("%s:\n", __func__); } static void release_perf_event_ioc_reset(struct command *cmd) { } static void build_perf_event_ioc_reset(struct command *cmd) { cmd->do_cmd = perf_event_ioc_reset; cmd->args = NULL; cmd->release = release_perf_event_ioc_reset; cmd->print = print_perf_event_ioc_reset; } // perf_event_ioc_refresh command int perf_event_ioc_refresh(int fd, void *_args) { /* Prevent overflow counter from stopping counter * Note that it starts counter as well */ int ret = asm_ioctl3(fd, PERF_EVENT_IOC_REFRESH, 256); if (ret < 0) { errno = -ret; perror("sys_ioctl: refresh"); } return ret; } static void print_perf_event_ioc_refresh(void *cmd) { printf("%s:\n", __func__); } static void release_perf_event_ioc_refresh(struct command *cmd) { } static void build_perf_event_ioc_refresh(struct command *cmd) { cmd->do_cmd = perf_event_ioc_refresh; cmd->args = NULL; cmd->release = release_perf_event_ioc_refresh; cmd->print = print_perf_event_ioc_refresh; } // command factory int build_command(const char *cmd_src, struct command *cmd) { int ret = 0; if (strcmp(cmd_src, "READ") == 0) { build_sys_read_command(cmd); } else if (strcmp(cmd_src, "RESET") == 0) { build_perf_event_ioc_reset(cmd); } else if (strcmp(cmd_src, "REFRESH") == 0) { build_perf_event_ioc_refresh(cmd); } else { ret = -EINVAL; } return ret; }