perf: overflow test

Change-Id: Ic7aa0d99ae9a5b7d3ce4436129a360275e6937ca
refs: #1358
This commit is contained in:
TOIDA,Suguru
2019-12-16 13:35:52 +09:00
parent 305511b48f
commit 1a204b6674
18 changed files with 907 additions and 0 deletions

1
.gitignore vendored
View File

@ -15,6 +15,7 @@ CMakeCache.txt
Makefile
!test/*/*/Makefile
!test/signalonfork+wait/Makefile
!test/perf_overflow/Makefile
!test/*/*/*.cmd
Kbuild
cmake_install.cmake

View File

@ -0,0 +1,23 @@
# Makefile COPYRIGHT FUJITSU LIMITED 2019
CC := ${CROSS_COMPILE}gcc
CFLAGS += -Wall -O0 -ggdb3
TARGET := perf_overflow
SRC := $(wildcard *.c)
OBJ := $(SRC:.c=.o)
DEP := $(SRC:.c=.d)
all: $(TARGET)
$(TARGET): $(OBJ)
$(CC) $(CFLAGS) $^ -o $@
%.o: %.c
$(CC) $(CFLAGS) -MMD -MP -c $<
.PHONY: clean
clean:
$(RM) $(OBJ) $(DEP) $(TARGET)
-include $(DEP)

35
test/perf_overflow/README Normal file
View File

@ -0,0 +1,35 @@
==========
How to run
==========
(1) Build McKernel
(2) cd <mckernel>/test/perf_overflow
(3) make
(4) sh run.sh
============
What to test
============
Test overflow handling of performance counter.
The steps of the test programs are as follows:
(1) Starts counting with the initial counter value set to -30
(2) Executes 40 nops
(3) Repeat (4)-(5) with the commands specified by the test-case
(4) Executes sys_read or sys_ioctl(PERF_EVENT_IOC_RESET) or sys_ioctl(PERF_EVENT_IOC_REFRESH)
(5) Executes 40 nops
(6) Checks if the counter value read in (4) is the same as Linux run
000) count the number of executions of nop
001) read counter while counting nop
002) reset counter while nop counting
003) refresh counter while counting nop
010) read, reset, and refresh counter while counting nop
011) read, read, and refresh counter while counting nop
012) reset, reset, and read counter while counting nop
013) refresh, refresh, and reset counter while counting nop
014) refresh, read, and read counter while counting nop
--
README COPYRIGHT FUJITSU LIMITED 2019

View File

@ -0,0 +1,154 @@
/* combination_test.c COPYRIGHT FUJITSU LIMITED 2019 */
#include "combination_test.h"
//
// main
//
static int combination_test(struct command_set *cmd_set)
{
struct perf_event_attr pe;
long long lest_count;
int ret = -1;
int fd;
int i;
ret = init_perf_event_attr(&pe);
if (ret < 0) {
fprintf(stderr,
"%s : Failed to init_perf_event_attr.\n",
__func__);
goto out;
}
fd = perf_event_open(&pe, 0, -1, -1, 0);
if (fd == -1) {
perror("pef_event_open");
goto out;
}
ret = ioctl(fd, PERF_EVENT_IOC_RESET, 0);
if (ret < 0) {
perror("ioctl(PERF_EVENT_IOC_RESET)");
goto out;
}
ret = asm_ioctl3(fd, PERF_EVENT_IOC_ENABLE, 0);
if (ret < 0) {
errno = -ret;
perror("asm_ioctl(PERF_EVENT_IOC_ENABLE)");
goto out;
}
nop10;
nop10;
nop10;
nop10;
for (i = 0; i < cmd_set->nr_cmds; i++) {
struct command *cmd = &cmd_set->cmds[i];
cmd->do_cmd(fd, cmd->args);
nop10;
nop10;
nop10;
nop10;
}
nop10;
nop10;
nop10;
nop10;
ret = asm_ioctl3(fd, PERF_EVENT_IOC_DISABLE, 0);
if (ret < 0) {
errno = -ret;
perror("asm_ioctl(PERF_EVENT_IOC_DISABLE)");
goto out;
}
for (i = 0; i < cmd_set->nr_cmds; i++) {
struct command *cmd = &cmd_set->cmds[i];
cmd->print(cmd->args);
}
ret = read(fd, &lest_count, sizeof(lest_count));
if (ret < 0) {
perror("read(lest_count)");
goto out;
}
printf("---------\n"
"sys_read: %lld\n", lest_count);
ret = 0;
out:
if (fd != -1) {
close(fd);
}
return ret;
}
int combination_main(int argc, char **argv)
{
int ret = -1;
int i;
int opt;
char *input_commands = NULL;
struct command_set cmd_set = {0};
// parse args
while ((opt = getopt(argc, argv, "c:")) != -1) {
switch (opt) {
case 'c':
input_commands = optarg;
break;
default:
print_usage();
goto out;
}
}
if (input_commands == NULL) {
fprintf(stderr,
"%s : combination test requires -c option.\n",
__func__);
print_usage();
goto out;
}
// build command
for (i = 0; i <= MAX_COMBINATION; i++) {
const char *cmd = strtok(input_commands, ",");
input_commands = NULL;
if (cmd == NULL) {
break;
}
if (i == MAX_COMBINATION) {
fprintf(stderr,
"%s : Too many arguments to option '-c'.\n",
__func__);
goto release_out;
}
if (build_command(cmd, &cmd_set.cmds[i]) < 0) {
fprintf(stderr,
"%s : Incorrect command[%s].\n",
__func__, cmd);
print_usage();
goto release_out;
}
}
cmd_set.nr_cmds = i;
// run
ret = combination_test(&cmd_set);
// release command
release_out:
for (i = 0; i < cmd_set.nr_cmds; i++) {
struct command *cmd = &cmd_set.cmds[i];
cmd->release(cmd);
}
out:
return ret;
}

View File

@ -0,0 +1,9 @@
/* combination_test.h COPYRIGHT FUJITSU LIMITED 2019 */
#ifndef _COMBINATION_TEST_H_
#define _COMBINATION_TEST_H_
#include "perf_common.h"
int combination_main(int argc, char **argv);
#endif /* _COMBINATION_TEST_H_ */

64
test/perf_overflow/main.c Normal file
View File

@ -0,0 +1,64 @@
/* main.c COPYRIGHT FUJITSU LIMITED 2019 */
#include "simple_test.h"
#include "read_test.h"
#include "reset_test.h"
#include "refresh_test.h"
#include "combination_test.h"
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <limits.h>
int main(int argc, char *argv[])
{
int ret = -1;
int test_num = -1;
char *endptr = NULL;
the_app = argv[0];
if (argc < 2) {
fprintf(stderr,
"%s : Incorrect number of arguments.\n",
__func__);
print_usage();
goto out;
}
errno = 0;
test_num = strtol(argv[1], &endptr, 0);
if (errno != 0 ||
*endptr != '\0' ||
(test_num < INT_MIN || INT_MAX < test_num)) {
fprintf(stderr, "%s : Failed to get test_num.\n"
"error code : %d\n", __func__, errno);
goto out;
}
switch (test_num) {
case 1:
ret = simple_test();
break;
case 2:
ret = read_test();
break;
case 3:
ret = reset_test();
break;
case 4:
ret = refresh_test();
break;
case 5:
argc--;
argv[1] = argv[0];
ret = combination_main(argc, &argv[1]);
break;
default:
fprintf(stderr, "%s : Incorrect test_num.\n", __func__);
print_usage();
break;
}
out:
return ret;
}

View File

@ -0,0 +1,213 @@
/* 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
static int perf_event_ioc_refresh(int fd, void *_args)
{
int ret = asm_ioctl3(fd, PERF_EVENT_IOC_REFRESH, 0);
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;
}

View File

@ -0,0 +1,47 @@
/* perf_common.h COPYRIGHT FUJITSU LIMITED 2019 */
#ifndef _PERF_COMMON_H_
#define _PERF_COMMON_H_
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <linux/perf_event.h>
#include <sys/ioctl.h>
#include <asm/unistd.h>
#define SAMPLE_PERIOD 30
#define nop10 do { \
asm volatile("nop;nop;nop;nop;nop;" \
"nop;nop;nop;nop;nop"); \
} while (0)
//usage
extern const char *the_app;
void print_usage(void);
//system call
long perf_event_open(struct perf_event_attr *event_attr, pid_t pid,
int cpu, int group_fd, unsigned long flags);
int init_perf_event_attr(struct perf_event_attr *event_attr);
int asm_ioctl3(int fd, unsigned long arg1, unsigned long arg2);
int asm_read(int fd, void *buf, size_t size);
//command
struct command {
void *args;
void (*release)(struct command *cmd);
int (*do_cmd)(int fd, void *args);
void (*print)(void *args);
};
#define MAX_COMBINATION 256
struct command_set {
int nr_cmds;
struct command cmds[MAX_COMBINATION];
};
int build_command(const char *cmd_src, struct command *cmd);
#endif /* _PERF_COMMON_H_ */

View File

@ -0,0 +1,69 @@
/* read_test.c COPYRIGHT FUJITSU LIMITED 2019 */
#include "read_test.h"
int read_test(void)
{
struct perf_event_attr pe;
long long count = 0;
int fd = -1;
int ret = -1;
ret = init_perf_event_attr(&pe);
if (ret < 0) {
fprintf(stderr,
"%s : Failed to init_perf_event_attr.\n",
__func__);
goto out;
}
fd = perf_event_open(&pe, 0, -1, -1, 0);
if (fd == -1) {
ret = errno;
perror("perf_event_open");
goto out;
}
ret = ioctl(fd, PERF_EVENT_IOC_RESET, 0);
if (ret < 0) {
perror("ioctl(PERF_EVENT_IOC_RESET)");
goto out;
}
ret = asm_ioctl3(fd, PERF_EVENT_IOC_ENABLE, 0);
if (ret < 0) {
perror("asm_ioctl(PERF_EVENT_IOC_ENABLE)");
goto out;
}
nop10;
nop10;
nop10;
nop10;
ret = asm_read(fd, &count, sizeof(long long));
if (ret < 0) {
perror("asm_read");
}
nop10;
nop10;
nop10;
nop10;
ret = asm_ioctl3(fd, PERF_EVENT_IOC_DISABLE, 0);
if (ret < 0) {
perror("asm_ioctl(PERF_EVENT_IOC_DISABLE)");
}
printf("Used %lld instructions\n", count);
ret = read(fd, &count, sizeof(long long));
if (ret < 0) {
perror("read");
}
printf("Used %lld instructions\n", count);
ret = 0;
out:
if (fd != -1) {
close(fd);
}
return ret;
}

View File

@ -0,0 +1,9 @@
/* read_test.h COPYRIGHT FUJITSU LIMITED 2019 */
#ifndef _READ_TEST_H_
#define _READ_TEST_H_
#include "perf_common.h"
int read_test(void);
#endif /* _READ_TEST_H_ */

View File

@ -0,0 +1,72 @@
/* refresh_test.c COPYRIGHT FUJITSU LIMITED 2019 */
#include "refresh_test.h"
int refresh_test(void)
{
struct perf_event_attr pe;
long long count = 0;
int fd = -1;
int ret = -1;
ret = init_perf_event_attr(&pe);
if (ret < 0) {
fprintf(stderr,
"%s : Failed to init_perf_event_attr.\n",
__func__);
goto out;
}
fd = perf_event_open(&pe, 0, -1, -1, 0);
if (fd == -1) {
ret = errno;
perror("perf_event_open");
goto out;
}
ret = ioctl(fd, PERF_EVENT_IOC_RESET, 0);
if (ret < 0) {
perror("ioctl(PERF_EVENT_IOC_RESET)");
goto out;
}
ret = asm_ioctl3(fd, PERF_EVENT_IOC_ENABLE, 0);
if (ret < 0) {
perror("asm_ioctl(PERF_EVENT_IOC_ENABLE)");
goto out;
}
nop10;
nop10;
nop10;
nop10;
ret = asm_ioctl3(fd, PERF_EVENT_IOC_REFRESH, 0);
if (ret < 0) {
perror("asm_ioctl(PERF_EVENT_IOC_REFRESH)");
goto out;
}
nop10;
nop10;
nop10;
nop10;
ret = asm_ioctl3(fd, PERF_EVENT_IOC_DISABLE, 0);
if (ret < 0) {
perror("asm_ioctl(PERF_EVENT_IOC_DISABLE)");
goto out;
}
ret = read(fd, &count, sizeof(long long));
if (ret < 0) {
perror("read");
goto out;
}
printf("Used %lld instructions\n", count);
ret = 0;
out:
if (fd != -1) {
close(fd);
}
return ret;
}

View File

@ -0,0 +1,9 @@
/* refresh_test.h COPYRIGHT FUJITSU LIMITED 2019 */
#ifndef _REFRESH_TEST_H_
#define _REFRESH_TEST_H_
#include "perf_common.h"
int refresh_test(void);
#endif /* _REFRESH_TEST_H_ */

View File

@ -0,0 +1,71 @@
/* reset_test.c COPYRIGHT FUJITSU LIMITED 2019 */
#include "refresh_test.h"
int reset_test(void)
{
struct perf_event_attr pe;
long long count = 0;
int fd = -1;
int ret = -1;
ret = init_perf_event_attr(&pe);
if (ret < 0) {
fprintf(stderr,
"%s : Failed to init_perf_event_attr.\n",
__func__);
goto out;
}
fd = perf_event_open(&pe, 0, -1, -1, 0);
if (fd == -1) {
fd = errno;
perror("perf_event_open");
goto out;
}
ret = ioctl(fd, PERF_EVENT_IOC_RESET, 0);
if (ret < 0) {
perror("ioctl(PERF_EVENT_IOC_RESET)");
goto out;
}
ret = asm_ioctl3(fd, PERF_EVENT_IOC_ENABLE, 0);
if (ret < 0) {
perror("asm_ioctl(PERF_EVENT_IOC_ENABLE)");
goto out;
}
nop10;
nop10;
nop10;
nop10;
ret = asm_ioctl3(fd, PERF_EVENT_IOC_RESET, 0);
if (ret < 0) {
perror("asm_ioctl(PERF_EVENT_IOC_RESET)");
}
nop10;
nop10;
nop10;
nop10;
ret = asm_ioctl3(fd, PERF_EVENT_IOC_DISABLE, 0);
if (ret < 0) {
perror("asm_ioctl(PERF_EVENT_IOC_DISABLE)");
goto out;
}
ret = read(fd, &count, sizeof(long long));
if (ret < 0) {
perror("read");
goto out;
}
printf("Used %lld instructions\n", count);
ret = 0;
out:
if (fd != -1) {
close(fd);
}
return ret;
}

View File

@ -0,0 +1,9 @@
/* reset_test.h COPYRIGHT FUJITSU LIMITED 2019 */
#ifndef _RESET_TEST_H_
#define _RESET_TEST_H_
#include "perf_common.h"
int reset_test(void);
#endif /* _RESET_TEST_H_ */

View File

@ -0,0 +1,12 @@
[root@hostname perf_overflow]# sh run.sh
mcstop+release.sh ... done
mcreboot.sh -c 12-59 -m 512M@4 ... done
000: OK
001: OK
002: OK
003: OK
010: OK
011: OK
012: OK
013: OK
014: OK

37
test/perf_overflow/run.sh Normal file
View File

@ -0,0 +1,37 @@
#!/bin/env bash
# run.sh COPYRIGHT FUJITSU LIMITED 2019
test_dir=$(dirname "${BASH_SOURCE[0]}")
result_dir="$test_dir/results"
# read config
. "${test_dir}/../common.sh"
# settings
test_bin="$test_dir/perf_overflow"
test_cases=`cat << __EOF__
000 1
001 2
002 3
003 4
010 5 -c READ,RESET,REFRESH
011 5 -c READ,READ,REFRESH
012 5 -c RESET,RESET,READ
013 5 -c REFRESH,REFRESH,RESET
014 5 -c REFRESH,READ,READ
__EOF__`
mkdir -p "$result_dir"
while read num args
do
"$test_bin" $args > "$result_dir/${num}.host"
"${MCEXEC}" 0 "$test_bin" $args > "$result_dir/${num}.mck"
diff -q "$result_dir/${num}.host" "$result_dir/${num}.mck"
if [ $? -eq 0 ]; then
echo "$num: OK"
else
echo "$num: NG"
fi
done <<EOF
$test_cases
EOF

View File

@ -0,0 +1,64 @@
/* simple_test.c COPYRIGHT FUJITSU LIMITED 2019 */
#include "simple_test.h"
int simple_test(void)
{
struct perf_event_attr pe;
long long count = 0;
int fd = -1;
int ret = -1;
ret = init_perf_event_attr(&pe);
if (ret < 0) {
fprintf(stderr,
"%s : Failed to init_perf_event_attr.\n",
__func__);
goto out;
}
fd = perf_event_open(&pe, 0, -1, -1, 0);
if (fd == -1) {
ret = errno;
perror("perf_event_open");
goto out;
}
ret = ioctl(fd, PERF_EVENT_IOC_RESET, 0);
if (ret < 0) {
perror("ioctl(PERF_EVENT_IOC_RESET)");
goto out;
}
ret = asm_ioctl3(fd, PERF_EVENT_IOC_ENABLE, 0);
if (ret < 0) {
perror("asm_ioctl(PERF_EVENT_IOC_ENABLE)");
goto out;
}
nop10;
nop10;
nop10;
nop10;
nop10;
nop10;
nop10;
nop10;
ret = asm_ioctl3(fd, PERF_EVENT_IOC_DISABLE, 0);
if (ret < 0) {
perror("asm_ioctl(PERF_EVENT_IOC_DISABLE)");
}
ret = read(fd, &count, sizeof(long long));
if (ret < 0) {
perror("read");
}
printf("Used %lld instructions\n", count);
ret = 0;
out:
if (fd != -1) {
close(fd);
}
return ret;
}

View File

@ -0,0 +1,9 @@
/* simple_test.h COPYRIGHT FUJITSU LIMITED 2019 */
#ifndef _SIMPLE_TEST_H_
#define _SIMPLE_TEST_H_
#include "perf_common.h"
int simple_test(void);
#endif /* _SIMPLE_TEST_H_ */