Files
mckernel/test/perf_overflow/perf_common.c
Masamichi Takagi c3c0b7197f test: perf: prevent overflow counter from stopping counter
Fixes: 1a204b6 "perf: overflow test"
Change-Id: I4d8e93b97f7a8d58ef7811f55b5c995b16c5af69
2020-05-14 01:10:14 +00:00

217 lines
4.2 KiB
C

/* 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;
}