uti: futex call function in mcctrl

Previously, futex code of McKerenl was called by mccontrol,
but there ware some problems with this method.
(Mainly, location of McKernel image on memory)

Call futex code in mcctrl instead of the one in McKernel image,
giving the following benefits:
1. Not relying on shared kernel virtual address space with Linux any more
2. The cpu id store / retrieve is not needed and resulting in the code

Change-Id: Ic40929b64a655b270c435859fa287fedb713ee5c
refe: #1428
This commit is contained in:
Ken Sato
2020-09-18 14:42:26 +09:00
committed by Masamichi Takagi
parent 35296c8210
commit a9973e913d
62 changed files with 4320 additions and 1116 deletions

171
test/uti/arm64/CT31.c Normal file
View File

@@ -0,0 +1,171 @@
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include <signal.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "util.h"
#define WAITER_CPU 0
#define WAKER_CPU 1
pthread_mutex_t mutex;
pthread_cond_t cond;
pthread_barrier_t bar;
int flag;
pthread_t thr;
long t_cond_wait, t_fwq;
long nloop;
long blocktime = 10L * 1000 * 1000;
int linux_run;
void *util_fn(void *arg)
{
int i;
int ret;
long start, end;
unsigned long mem;
print_cpu_last_executed_on("Utility thread");
if (!linux_run) {
ret = syscall(732);
OKNGNOJUMP(ret == -1, "Utility thread is running on Linux\n");
}
pthread_barrier_wait(&bar);
for (i = 0; i < nloop; i++) {
start = rdtsc_light();
fwq(blocktime, &mem);
end = rdtsc_light();
t_fwq += end - start;
pthread_mutex_lock(&mutex);
flag = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
fn_fail:
return NULL;
}
static struct option options[] = {
/* end */
{ NULL, 0, NULL, 0, }
};
int main(int argc, char **argv)
{
int i;
int ret;
long start, end;
cpu_set_t cpuset;
pthread_attr_t attr;
pthread_barrierattr_t bar_attr;
struct sched_param param = { .sched_priority = 99 };
int opt;
unsigned long mem;
while ((opt = getopt_long(argc, argv, "+b:l", options, NULL)) != -1) {
switch (opt) {
case 'b':
blocktime = atoi(optarg);
break;
case 'l':
linux_run = 1;
break;
default: /* '?' */
printf("unknown option %c\n", optopt);
exit(1);
}
}
nloop = (10 * 1000000000UL) / blocktime;
printf("[INFO] nloop=%ld,blocktime=%ld\n", nloop, blocktime);
CPU_ZERO(&cpuset);
CPU_SET(WAITER_CPU, &cpuset);
if ((ret = sched_setaffinity(0, sizeof(cpu_set_t), &cpuset))) {
printf("Error: sched_setaffinity: %s\n", strerror(errno));
goto fn_fail;
}
print_cpu_last_executed_on("Master thread");
fwq_init(&mem);
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
pthread_barrierattr_init(&bar_attr);
pthread_barrier_init(&bar, &bar_attr, 2);
if (!linux_run) {
ret = syscall(732);
OKNGNOJUMP(ret != -1, "Master thread is running on McKernel\n");
ret = syscall(731, 1, NULL);
OKNGNOJUMP(ret != -1, "util_indicate_clone\n");
}
if ((ret = pthread_attr_init(&attr))) {
printf("%s: Error: pthread_attr_init failed (%d)\n", __FUNCTION__, ret);
goto fn_fail;
}
CPU_ZERO(&cpuset);
CPU_SET(WAKER_CPU, &cpuset);
if ((ret = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset))) {
printf("%s: Error: pthread_attr_setaffinity_np failed (%d)\n", __FUNCTION__, ret);
goto fn_fail;
}
if ((ret = pthread_create(&thr, &attr, util_fn, NULL))) {
fprintf(stderr, "Error: pthread_create failed (%d)\n", ret);
goto fn_fail;
}
if ((ret = sched_setscheduler(0, SCHED_FIFO, &param))) {
fprintf(stderr, "Warning: sched_setscheduler: %s\n",
strerror(errno));
}
if (!linux_run) {
syscall(701, 1 | 2);
}
pthread_barrier_wait(&bar);
for (i = 0; i < nloop; i++) {
start = rdtsc_light();
pthread_mutex_lock(&mutex); /* no futex */
while(!flag) {
pthread_cond_wait(&cond, &mutex); /* 1st futex */
}
flag = 0;
pthread_mutex_unlock(&mutex); /* 2nd futex */
end = rdtsc_light();
t_cond_wait += end - start;
}
if (!linux_run) {
syscall(701, 4 | 8);
}
pthread_join(thr, NULL);
printf("[INFO] waker: %ld nsec, waiter: %ld nsec, (waiter - waker) / nloop: %ld nsec\n", t_fwq * 10, t_cond_wait * 10, (t_cond_wait - t_fwq) * 10 / nloop);
ret = 0;
fn_fail:
return ret;
}

171
test/uti/arm64/CT32.c Normal file
View File

@@ -0,0 +1,171 @@
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include <signal.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "util.h"
#define WAITER_CPU 0
#define WAKER_CPU 1
pthread_mutex_t mutex;
pthread_cond_t cond;
pthread_barrier_t bar;
int flag;
pthread_t thr;
long t_cond_wait, t_fwq;
long nloop;
long blocktime = 10L * 1000 * 1000;
int linux_run;
void *util_fn(void *arg)
{
int i;
int ret;
long start, end;
unsigned long mem;
print_cpu_last_executed_on("Utility thread");
if (!linux_run) {
ret = syscall(732);
OKNGNOJUMP(ret == -1, "Utility thread is running on Linux\n");
}
pthread_barrier_wait(&bar);
for (i = 0; i < nloop; i++) {
start = rdtsc_light();
pthread_mutex_lock(&mutex); /* no futex */
while(!flag) {
pthread_cond_wait(&cond, &mutex); /* 1st futex */
}
flag = 0;
pthread_mutex_unlock(&mutex); /* 2nd futex */
end = rdtsc_light();
t_cond_wait += end - start;
}
fn_fail:
return NULL;
}
static struct option options[] = {
/* end */
{ NULL, 0, NULL, 0, }
};
int main(int argc, char **argv)
{
int i;
int ret;
long start, end;
cpu_set_t cpuset;
pthread_attr_t attr;
pthread_barrierattr_t bar_attr;
struct sched_param param = { .sched_priority = 99 };
int opt;
unsigned long mem;
while ((opt = getopt_long(argc, argv, "+b:l", options, NULL)) != -1) {
switch (opt) {
case 'b':
blocktime = atoi(optarg);
break;
case 'l':
linux_run = 1;
break;
default: /* '?' */
printf("unknown option %c\n", optopt);
exit(1);
}
}
nloop = (10 * 1000000000UL) / blocktime;
printf("[INFO] nloop=%ld,blocktime=%ld\n", nloop, blocktime);
CPU_ZERO(&cpuset);
CPU_SET(WAITER_CPU, &cpuset);
if ((ret = sched_setaffinity(0, sizeof(cpu_set_t), &cpuset))) {
printf("Error: sched_setaffinity: %s\n", strerror(errno));
goto fn_fail;
}
print_cpu_last_executed_on("Master thread");
fwq_init(&mem);
pthread_mutex_init(&mutex, NULL);
pthread_cond_init(&cond, NULL);
pthread_barrierattr_init(&bar_attr);
pthread_barrier_init(&bar, &bar_attr, 2);
if (!linux_run) {
ret = syscall(732);
OKNGNOJUMP(ret != -1, "Master thread is running on McKernel\n");
ret = syscall(731, 1, NULL);
OKNGNOJUMP(ret != -1, "util_indicate_clone\n");
}
if ((ret = pthread_attr_init(&attr))) {
printf("%s: Error: pthread_attr_init failed (%d)\n", __FUNCTION__, ret);
goto fn_fail;
}
CPU_ZERO(&cpuset);
CPU_SET(WAKER_CPU, &cpuset);
if ((ret = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset))) {
printf("%s: Error: pthread_attr_setaffinity_np failed (%d)\n", __FUNCTION__, ret);
goto fn_fail;
}
if ((ret = pthread_create(&thr, &attr, util_fn, NULL))) {
fprintf(stderr, "Error: pthread_create failed (%d)\n", ret);
goto fn_fail;
}
if ((ret = sched_setscheduler(0, SCHED_FIFO, &param))) {
fprintf(stderr, "Warning: sched_setscheduler: %s\n",
strerror(errno));
}
if (!linux_run) {
syscall(701, 1 | 2);
}
pthread_barrier_wait(&bar);
for (i = 0; i < nloop; i++) {
start = rdtsc_light();
fwq(blocktime, &mem);
end = rdtsc_light();
t_fwq += end - start;
pthread_mutex_lock(&mutex);
flag = 1;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
}
if (!linux_run) {
syscall(701, 4 | 8);
}
pthread_join(thr, NULL);
printf("[INFO] waker: %ld nsec, waiter: %ld nsec, (waiter - waker) / nloop: %ld nsec\n", t_fwq * 10, t_cond_wait * 10, (t_cond_wait - t_fwq) * 10 / nloop);
ret = 0;
fn_fail:
return ret;
}

171
test/uti/arm64/CT33.c Normal file
View File

@@ -0,0 +1,171 @@
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/futex.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>
#include "util.h"
#define WAITER_CPU 0
#define WAKER_CPU 1
int sem;
pthread_barrier_t bar;
int flag;
pthread_t thr;
long t_futex_wait, t_fwq;
long nloop;
long blocktime = 10L * 1000 * 1000;
int linux_run;
void *util_fn(void *arg)
{
int i;
int ret;
long start, end;
int testid = 32101;
unsigned long mem;
print_cpu_last_executed_on("Utility thread");
if (!linux_run) {
ret = syscall(732);
OKNGNOJUMP(ret == -1, "Utility thread is running on Linux\n");
}
pthread_barrier_wait(&bar);
for (i = 0; i < nloop; i++) {
start = rdtsc_light();
fwq(blocktime, &mem);
end = rdtsc_light();
t_fwq += end - start;
sem = i + 1;
if ((ret = syscall(__NR_futex, &sem, FUTEX_WAKE, 1,
NULL, NULL, 0)) != 1) {
printf("Error: futex wake: %d,%d\n", ret, errno);
}
//pthread_barrier_wait(&bar);
}
ret = 0;
fn_fail:
return NULL;
}
static struct option options[] = {
/* end */
{ NULL, 0, NULL, 0, }
};
int main(int argc, char **argv)
{
int i;
int ret;
long start, end;
cpu_set_t cpuset;
pthread_attr_t attr;
pthread_barrierattr_t bar_attr;
struct sched_param param = { .sched_priority = 99 };
int opt;
unsigned long mem;
while ((opt = getopt_long(argc, argv, "+b:l", options, NULL)) != -1) {
switch (opt) {
case 'b':
blocktime = atoi(optarg);
break;
case 'l':
linux_run = 1;
break;
default: /* '?' */
printf("unknown option %c\n", optopt);
exit(1);
}
}
nloop = (10 * 1000000000UL) / blocktime;
printf("[INFO] nloop=%ld,blocktime=%ld\n", nloop, blocktime);
CPU_ZERO(&cpuset);
CPU_SET(WAITER_CPU, &cpuset);
if ((ret = sched_setaffinity(0, sizeof(cpu_set_t), &cpuset))) {
printf("Error: sched_setaffinity: %s\n", strerror(errno));
goto fn_fail;
}
print_cpu_last_executed_on("Master thread");
fwq_init(&mem);
pthread_barrierattr_init(&bar_attr);
pthread_barrier_init(&bar, &bar_attr, 2);
if ((ret = pthread_attr_init(&attr))) {
printf("Error: pthread_attr_init: %s\n", strerror(errno));
goto fn_fail;
}
CPU_ZERO(&cpuset);
CPU_SET(WAKER_CPU, &cpuset);
if ((ret = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset))) {
printf("Error: pthread_attr_setaffinity_np: %s\n", strerror(errno));
goto fn_fail;
}
if (!linux_run) {
ret = syscall(732);
OKNGNOJUMP(ret != -1, "Master thread is running on McKernel\n");
ret = syscall(731, 1, NULL);
OKNGNOJUMP(ret != -1, "util_indicate_clone\n");
}
if ((ret = pthread_create(&thr, &attr, util_fn, NULL))) {
printf("Error: pthread_create: %s\n", strerror(errno));
goto fn_fail;
}
if ((ret = sched_setscheduler(0, SCHED_FIFO, &param))) {
printf("Warning: sched_setscheduler: %s\n", strerror(errno));
}
if (!linux_run) {
syscall(701, 1 | 2);
}
pthread_barrier_wait(&bar);
start = rdtsc_light();
for (i = 0; i < nloop; i++) {
if ((ret = syscall(__NR_futex, &sem, FUTEX_WAIT, i, NULL, NULL, 0))) {
printf("Error: futex wait failed (%s)\n", strerror(errno));
}
//pthread_barrier_wait(&bar); /* 2nd futex */
}
end = rdtsc_light();
t_futex_wait += end - start;
if (!linux_run) {
syscall(701, 4 | 8);
}
pthread_join(thr, NULL);
printf("[INFO] waiter: %ld nsec, waker: %ld nsec, (waiter - waker) / nloop: %ld nsec\n", t_futex_wait * 10, t_fwq * 10, (t_futex_wait - t_fwq) * 10 / nloop);
ret = 0;
fn_fail:
return ret;
}

170
test/uti/arm64/CT34.c Normal file
View File

@@ -0,0 +1,170 @@
#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <errno.h>
#include <sys/mman.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <linux/futex.h>
#include <getopt.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdint.h>
#include "util.h"
#define WAITER_CPU 0
#define WAKER_CPU 1
int sem;
pthread_barrier_t bar;
int flag;
pthread_t thr;
long t_futex_wait, t_fwq;
long nloop;
long blocktime = 10L * 1000 * 1000;
int linux_run;
void *util_fn(void *arg)
{
int i;
int ret;
long start, end;
int testid = 32101;
unsigned long mem;
print_cpu_last_executed_on("Utility thread");
if (!linux_run) {
ret = syscall(732);
OKNGNOJUMP(ret == -1, "Utility thread is running on Linux\n");
}
pthread_barrier_wait(&bar);
start = rdtsc_light();
for (i = 0; i < nloop; i++) {
if ((ret = syscall(__NR_futex, &sem, FUTEX_WAIT, i, NULL, NULL, 0))) {
printf("Error: futex wait failed (%s)\n", strerror(errno));
}
//pthread_barrier_wait(&bar); /* 2nd futex */
}
end = rdtsc_light();
t_futex_wait += end - start;
ret = 0;
fn_fail:
return NULL;
}
static struct option options[] = {
/* end */
{ NULL, 0, NULL, 0, }
};
int main(int argc, char **argv)
{
int i;
int ret;
long start, end;
cpu_set_t cpuset;
pthread_attr_t attr;
pthread_barrierattr_t bar_attr;
struct sched_param param = { .sched_priority = 99 };
int opt;
unsigned long mem;
while ((opt = getopt_long(argc, argv, "+b:l", options, NULL)) != -1) {
switch (opt) {
case 'b':
blocktime = atoi(optarg);
break;
case 'l':
linux_run = 1;
break;
default: /* '?' */
printf("unknown option %c\n", optopt);
exit(1);
}
}
nloop = (10 * 1000000000UL) / blocktime;
printf("[INFO] nloop=%ld,blocktime=%ld\n", nloop, blocktime);
CPU_ZERO(&cpuset);
CPU_SET(WAKER_CPU, &cpuset);
if ((ret = sched_setaffinity(0, sizeof(cpu_set_t), &cpuset))) {
printf("Error: sched_setaffinity: %s\n", strerror(errno));
goto fn_fail;
}
print_cpu_last_executed_on("Master thread");
fwq_init(&mem);
pthread_barrierattr_init(&bar_attr);
pthread_barrier_init(&bar, &bar_attr, 2);
if ((ret = pthread_attr_init(&attr))) {
printf("Error: pthread_attr_init: %s\n", strerror(errno));
goto fn_fail;
}
CPU_ZERO(&cpuset);
CPU_SET(WAITER_CPU, &cpuset);
if ((ret = pthread_attr_setaffinity_np(&attr, sizeof(cpu_set_t), &cpuset))) {
printf("Error: pthread_attr_setaffinity_np: %s\n", strerror(errno));
goto fn_fail;
}
if (!linux_run) {
ret = syscall(732);
OKNGNOJUMP(ret != -1, "Master thread is running on McKernel\n");
ret = syscall(731, 1, NULL);
OKNGNOJUMP(ret != -1, "util_indicate_clone\n");
}
if ((ret = pthread_create(&thr, &attr, util_fn, NULL))) {
printf("Error: pthread_create: %s\n", strerror(errno));
goto fn_fail;
}
if ((ret = sched_setscheduler(0, SCHED_FIFO, &param))) {
printf("Warning: sched_setscheduler: %s\n", strerror(errno));
}
if (!linux_run) {
syscall(701, 1 | 2);
}
pthread_barrier_wait(&bar);
for (i = 0; i < nloop; i++) {
start = rdtsc_light();
fwq(blocktime, &mem);
end = rdtsc_light();
t_fwq += end - start;
sem = i + 1;
if ((ret = syscall(__NR_futex, &sem, FUTEX_WAKE, 1,
NULL, NULL, 0)) != 1) {
printf("Error: futex wake: %d, %d\n", ret, errno);
}
//pthread_barrier_wait(&bar);
}
if (!linux_run) {
syscall(701, 4 | 8);
}
pthread_join(thr, NULL);
printf("[INFO] waiter: %ld nsec, waker: %ld nsec, (waiter - waker) / nloop: %ld nsec\n", t_futex_wait * 10, t_fwq * 10, (t_futex_wait - t_fwq) * 10 / nloop);
ret = 0;
fn_fail:
return ret;
}

View File

@@ -1,6 +1,9 @@
# Makefile COPYRIGHT FUJITSU LIMITED 2019
CC = gcc
LDFLAGS = -Wall -lpthread
LDFLAGS = -Wall -lpthread
CCFLAGS = -g -O0
CPPFLAGS =
SRCS = $(shell ls CT*.c)
TARGET = $(SRCS:.c=)
@@ -10,5 +13,23 @@ all: $(TARGET)
test: all
./run.sh
%.o:: %.c
$(CC) $(CCFLAGS) $(CPPFLAGS) -c $<
util.o:: util.c
$(CC) $(CCFLAGS) $(CPPFLAGS) -c $<
CT31: CT31.o util.o
$(CC) -o $@ $^ $(LDFLAGS) $(CPPFLAGS)
CT32: CT32.o util.o
$(CC) -o $@ $^ $(LDFLAGS) $(CPPFLAGS)
CT33: CT33.o util.o
$(CC) -o $@ $^ $(LDFLAGS) $(CPPFLAGS)
CT34: CT34.o util.o
$(CC) -o $@ $^ $(LDFLAGS) $(CPPFLAGS)
clean:
rm -f $(TARGET)
rm -f $(TARGET) *.o

122
test/uti/arm64/util.c Normal file
View File

@@ -0,0 +1,122 @@
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <unistd.h>
#include <sys/syscall.h> /* For SYS_xxx definitions */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sched.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include "util.h"
#define TS2NS(sec, nsec) \
((unsigned long)(sec) * 1000000000ULL + \
(unsigned long)(nsec))
#define N_INIT 10000000
static inline void FIXED_SIZE_WORK(unsigned long *ptr)
{
asm volatile("mov %x0, x20\n"
"add x20, x20, #1\n"
"mov x20, %x0\n"
: "+rm" (*ptr)
:
: "x20", "cc", "memory");
}
static inline void BULK_FSW(unsigned long n,
unsigned long *ptr)
{
int j;
for (j = 0; j < (n); j++) {
FIXED_SIZE_WORK(ptr);
}
}
double nspw; /* nsec per work */
unsigned long nsec;
void fwq_init(unsigned long *mem)
{
struct timespec start, end;
unsigned long nsec;
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &start);
BULK_FSW(N_INIT, mem);
clock_gettime(CLOCK_THREAD_CPUTIME_ID, &end);
nsec = (TS2NS(end.tv_sec, end.tv_nsec) -
TS2NS(start.tv_sec, start.tv_nsec));
nspw = nsec / (double)N_INIT;
printf("nsec=%ld, nspw=%f\n", nsec, nspw);
}
void fwq(long delay_nsec, unsigned long *mem)
{
BULK_FSW(delay_nsec / nspw, mem);
}
int print_cpu_last_executed_on(const char *name) {
char fn[256];
char* result;
pid_t tid = syscall(SYS_gettid);
int fd;
int offset;
int mpi_errno = 0;
sprintf(fn, "/proc/%d/task/%d/stat", getpid(), (int)tid);
//printf("fn=%s\n", fn);
fd = open(fn, O_RDONLY);
if(fd == -1) {
printf("open() failed\n");
goto fn_fail;
}
result = malloc(65536);
if(result == NULL) {
printf("malloc() failed");
goto fn_fail;
}
int amount = 0;
offset = 0;
while(1) {
amount = read(fd, result + offset, 65536);
// printf("amount=%d\n", amount);
if(amount == -1) {
printf("read() failed");
goto fn_fail;
}
if(amount == 0) {
goto eof;
}
offset += amount;
}
eof:;
//printf("result:%s\n", result);
char* next_delim = result;
char* field;
int i;
for(i = 0; i < 39; i++) {
field = strsep(&next_delim, " ");
}
int cpu = sched_getcpu();
if(cpu == -1) {
printf("getcpu() failed\n");
goto fn_fail;
}
printf("[INFO] %s (tid: %d) is running on %02d,%02d\n", name, tid, atoi(field), cpu);
fn_exit:
free(result);
return mpi_errno;
fn_fail:
mpi_errno = -1;
goto fn_exit;
}

70
test/uti/arm64/util.h Normal file
View File

@@ -0,0 +1,70 @@
#ifndef __UTIL_H_INCLUDED__
#define __UTIL_H_INCLUDED__
#include <stdint.h>
#define isb() asm volatile("isb" : : : "memory")
#define DEBUG
#ifdef DEBUG
#define dprintf(...) do { \
char msg[1024]; \
sprintf(msg, __VA_ARGS__); \
fprintf(stderr, "%s,%s", __func__, msg); \
} while (0)
#else
#define dprintf(...) do { } while (0)
#endif
#define eprintf(...) do { \
char msg[1024]; \
sprintf(msg, __VA_ARGS__); \
fprintf(stderr, "%s,%s", __func__, msg); \
} while (0)
#define CHKANDJUMP(cond, err, ...) do { \
if (cond) { \
eprintf(__VA_ARGS__); \
ret = err; \
goto fn_fail; \
} \
} while (0)
#define _OKNG(verb, jump, cond, fmt, args...) do { \
if (cond) { \
if (verb) \
printf("[ OK ] " fmt, ##args); \
} else { \
printf("[ NG ] " fmt, ##args); \
if (jump) \
goto fn_fail; \
} \
} while (0)
#define OKNG(args...) _OKNG(1, 1, ##args)
#define NG(args...) _OKNG(0, 1, ##args)
#define OKNGNOJUMP(args...) _OKNG(1, 0, ##args)
#define DIFFNSEC(end, start) ((end.tv_sec - start.tv_sec) * 1000000000UL + (end.tv_nsec - start.tv_nsec))
#define TIMER_KIND CLOCK_MONOTONIC_RAW /* CLOCK_THREAD_CPUTIME_ID */
static inline uint64_t rdtsc_light(void )
{
unsigned long cval;
isb();
asm volatile("mrs %0, cntvct_el0" : "=r" (cval));
return cval;
}
extern double nspw; /* nsec per work */
extern unsigned long nsec;
void fwq_init(unsigned long *mem);
void fwq(long delay_nsec, unsigned long *mem);
int print_cpu_last_executed_on(const char *name);
#endif