Commit f28d8a46 authored by Florian Fischer's avatar Florian Fischer
Browse files

Merge branch 'work-work-work' into 'main'

work work work

See merge request i4/manycore/fgbs-syscall-eval!2
parents 9acf37a1 3bb12208
Pipeline #66485 passed with stage
in 5 minutes and 11 seconds
---
BasedOnStyle: Google
ColumnLimit: 100
TabWidth: 2
UseTab: Always
Checks: >
bugprone-*,
cert-*,
linuxkernel-*,
modernize-*,
performance-*,
portability-*,
readability-*,
-cert-err58-cpp,
-clang-diagnostic-empty-translation-unit,
-readability-braces-around-statements,
-readability-function-cognitive-complexity,
-readability-implicit-bool-conversion,
-readability-isolate-declaration,
-readability-magic-numbers,
WarningsAsErrors: >
bugprone-*,
modernize-*,
clang-*,
readability-*,
performance-*,
HeaderFilterRegex: .*
......@@ -2,7 +2,9 @@ image: "flowdalic/debian-testing-dev:1.14"
before_script:
- |
apt install -y bear
readarray TOOLS <<EOF
bear
cc
gcc
EOF
......@@ -14,3 +16,11 @@ before_script:
test-eval:
script:
- make
tidy:
script:
- bear -- make all && make tidy
check-format:
script:
- make check-format
BENCH_MAIN := bench.c
SYSCALLS := blocking io-uring io-uring-sqpoll epoll aio-sig aio-thrd
SYSCALLS := blocking io-uring io-uring-sqpoll io-uring-no-syscall epoll aio-sig aio-thrd
OBJ := $(addprefix bench-,$(SYSCALLS))
LDFLAGS := -luring -pthread -lrt
# CFLAGS := -Werror -Wall -g -O3
CFLAGS := -Werror -Wall -g -O0
CFLAGS := -Werror -Wall -g -O3
# CFLAGS := -Werror -Wall -g -O0
.PHONY: all clean eval docker-eval
.PHONY: all clean eval docker-eval check
eval: all
@for syscall in $(SYSCALLS); do echo -n "$$syscall " ; ./bench-$$syscall; done
......@@ -19,7 +19,7 @@ docker-eval:
all: $(OBJ)
define generateTargets
bench-$(1): $(1).c bench.c | Makefile
bench-$(1): $(1).c bench.c stopwatch.c | Makefile
$(CC) $(CFLAGS) -o $$@ $$^ $(LDFLAGS)
endef
......@@ -27,3 +27,14 @@ $(foreach syscall,$(SYSCALLS),$(eval $(call generateTargets,$(syscall))))
clean:
rm -f $(OBJ)
check: tidy check-format
tidy:
clang-tidy *.c
check-format:
tools/check-format
format:
clang-format -i *.c *.h
#include <aio.h>
#include <err.h>
#include <semaphore.h>
#include <signal.h>
#include <stdatomic.h>
#include <stdint.h>
#include <stdlib.h>
#include "rdtsc.h"
#include "common.h"
#include "stopwatch.h"
int64_t clock_before, clock_after;
struct aiocb aiocb;
sem_t sem;
atomic_int done;
void callback(int sig, siginfo_t* info, void* context) {
clock_after = rdtsc_s();
if (info->si_value.sival_int != 42)
errx(EXIT_FAILURE, "got unexpected sigval value");
void callback(int sig, siginfo_t *info, void *context) {
if (unlikely(info->si_value.sival_int != 42)) errx(EXIT_FAILURE, "got unexpected sigval value");
sem_post(&sem);
atomic_store(&done, 1);
}
void init(int fd) {
if (sem_init(&sem, 0, 0) == -1)
err(EXIT_FAILURE, "sem_init failed");
aiocb.aio_fildes = fd;
aiocb.aio_sigevent.sigev_notify = SIGEV_SIGNAL;
aiocb.aio_sigevent.sigev_signo = SIGUSR1;
......@@ -33,20 +28,20 @@ void init(int fd) {
sa.sa_sigaction = callback;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
if (sigaction(SIGUSR1, &sa, NULL) == -1)
err(EXIT_FAILURE, "sigaction failed");
if (sigaction(SIGUSR1, &sa, NULL) == -1) err(EXIT_FAILURE, "sigaction failed");
}
int64_t do_write(int fd, const void* buf, size_t count) {
aiocb.aio_buf = (void*)buf;
void do_write(int fd, const void *buf, size_t count) {
aiocb.aio_buf = (void *)buf;
aiocb.aio_nbytes = count;
clock_before = rdtsc_s();
start_watch();
int res = aio_write(&aiocb);
sem_wait(&sem);
if (res == -1)
err(EXIT_FAILURE, "aio_write failed");
if (unlikely(res == -1)) err(EXIT_FAILURE, "aio_write failed");
return clock_after - clock_before;
while (!atomic_load(&done)) {
}
stop_watch();
atomic_store(&done, 1);
}
#include <aio.h>
#include <err.h>
#include <semaphore.h>
#include <signal.h>
#include <stdatomic.h>
#include <stdint.h>
#include <stdlib.h>
#include "rdtsc.h"
#include "stopwatch.h"
int64_t clock_before, clock_after;
struct aiocb aiocb;
sem_t sem;
atomic_int done;
struct aiocb aiocb;
void callback(union sigval sigval) {
clock_after = rdtsc_s();
stop_watch();
if (sigval.sival_int != 42)
errx(EXIT_FAILURE, "got unexpected sigval value");
if (sigval.sival_int != 42) errx(EXIT_FAILURE, "got unexpected sigval value");
sem_post(&sem);
atomic_store(&done, 1);
}
void init(int fd) {
if (sem_init(&sem, 0, 0) == -1)
err(EXIT_FAILURE, "sem_init failed");
aiocb.aio_fildes = fd;
aiocb.aio_sigevent.sigev_notify = SIGEV_THREAD;
aiocb.aio_sigevent.sigev_notify_function = callback;
aiocb.aio_sigevent.sigev_value.sival_int = 42;
}
int64_t do_write(int fd, void* buf, size_t count) {
void do_write(int fd, void *buf, size_t count) {
aiocb.aio_buf = buf;
aiocb.aio_nbytes = count;
clock_before = rdtsc_s();
start_watch();
int res = aio_write(&aiocb);
sem_wait(&sem);
if (res == -1)
err(EXIT_FAILURE, "aio_write failed");
while (!atomic_load(&done)) {
}
atomic_store(&done, 0);
return clock_after - clock_before;
if (res == -1) err(EXIT_FAILURE, "aio_write failed");
}
......@@ -5,22 +5,16 @@
#include <stdlib.h>
#include <sys/eventfd.h>
#include "stopwatch.h"
void init(int fd);
int64_t do_write(int fd, const void* buf, size_t count);
void do_write(int fd, const void *buf, size_t count);
const size_t warmup = 10000;
const size_t iterations = 1000000;
#define BUFSIZE 64
/* static int open_dev_zero() { */
/* int fd = open("/dev/zero", O_RDONLY); */
/* if (fd == -1) { */
/* err(EXIT_FAILURE, "opening /dev/zero failed"); */
/* } */
/* return fd; */
/* } */
static int create_eventfd() {
int fd = eventfd(0, 0);
if (fd == -1) {
......@@ -30,25 +24,30 @@ static int create_eventfd() {
}
int main() {
double avg_cycles = 0;
uint64_t cycles_sum = 0;
uint64_t nanos_sum = 0;
uint64_t write_buf = 1;
/* int fd = open_dev_zero(); */
int fd = create_eventfd();
init(fd);
/* char read_buf[BUFSIZE]; */
uint64_t write_buf = 1;
for (size_t i = 0; i < warmup; ++i) do_write(fd, &write_buf, sizeof(write_buf));
for (size_t i = 0; i < warmup; ++i)
for (int64_t i = 1; i <= iterations; ++i) {
do_write(fd, &write_buf, sizeof(write_buf));
for (size_t i = 1; i <= iterations; ++i) {
ssize_t cycles = do_write(fd, &write_buf, sizeof(write_buf));
avg_cycles += ((double)cycles - avg_cycles) / i;
if (__builtin_add_overflow(nanos_sum, clock_diff_nanos(), &nanos_sum))
errx(EXIT_FAILURE, "nanos overflowed at %ld", i);
if (__builtin_add_overflow(cycles_sum, clock_diff_cycles(), &cycles_sum))
errx(EXIT_FAILURE, "cycles overflowed at %ld", i);
}
printf("avg_cycles: %lf\n", avg_cycles);
// Since uint64_t <-> double conversion are not well defined
// and we use really small units (cycles and nanoseconds) I am willing
// to accept that we throw away anything after the decimal point.
uint64_t avg_nanos = nanos_sum / iterations;
uint64_t avg_cycles = cycles_sum / iterations;
printf("%lu ns, %lu cycles\n", avg_nanos, avg_cycles);
return 0;
}
......@@ -2,19 +2,14 @@
#include <stdlib.h>
#include <unistd.h>
#include "rdtsc.h"
#include "stopwatch.h"
void init(__attribute__((unused)) int fd) {}
int64_t do_write(int fd, const void* buf, size_t count) {
int64_t clock_before, clock_after;
clock_before = rdtsc_s();
void do_write(int fd, const void *buf, size_t count) {
start_watch();
ssize_t res = write(fd, buf, count);
clock_after = rdtsc_s();
if (res == -1)
err(EXIT_FAILURE, "write failed");
stop_watch();
return clock_after - clock_before;
if (res == -1) err(EXIT_FAILURE, "write failed");
}
#include <err.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdlib.h>
#pragma once
#define BUFSIZE 64
int64_t do_write(int fd, const void* buf, size_t count);
__inline__ int64_t rdtsc_s(void) {
unsigned a, d;
asm volatile("cpuid" ::: "%rax", "%rbx", "%rcx", "%rdx");
asm volatile("rdtsc" : "=a" (a), "=d" (d));
return ((unsigned long)a) | (((unsigned long)d) << 32);
}
__inline__ int64_t rdtsc_e(void) {
unsigned a, d;
asm volatile("rdtscp" : "=a" (a), "=d" (d));
asm volatile("cpuid" ::: "%rax", "%rbx", "%rcx", "%rdx");
return ((unsigned long)a) | (((unsigned long)d) << 32);
}
#define unlikely(x) __builtin_expect(!!(x), 0)
......@@ -3,40 +3,30 @@
#include <sys/epoll.h>
#include <unistd.h>
#include "rdtsc.h"
#include "stopwatch.h"
struct epoll_event ev;
int nfds, epollfd;
void init(int fd) {
epollfd = epoll_create1(0);
if (epollfd == -1)
err(EXIT_FAILURE, "creating epoll failed");
if (epollfd == -1) err(EXIT_FAILURE, "creating epoll failed");
ev.events = EPOLLOUT;
ev.data.fd = fd;
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1)
err(EXIT_FAILURE, "epoll_ctl failed");
if (epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev) == -1) err(EXIT_FAILURE, "epoll_ctl failed");
}
int64_t do_write(int fd, const void* buf, size_t count) {
int64_t clock_before, clock_after;
clock_before = rdtsc_s();
void do_write(int fd, const void *buf, size_t count) {
start_watch();
nfds = epoll_wait(epollfd, &ev, 1, -1);
size_t res = write(fd, buf, count);
clock_after = rdtsc_s();
if (nfds == -1)
err(EXIT_FAILURE, "epoll_wait failed");
stop_watch();
if (ev.data.fd != fd)
errx(EXIT_FAILURE, "got unexpected fd from epoll");
if (nfds == -1) err(EXIT_FAILURE, "epoll_wait failed");
if (res == -1)
err(EXIT_FAILURE, "write failed");
if (ev.data.fd != fd) errx(EXIT_FAILURE, "got unexpected fd from epoll");
return clock_after - clock_before;
if (res == -1) err(EXIT_FAILURE, "write failed");
}
#include <err.h>
#include <errno.h>
#include <liburing.h>
#include <stdlib.h>
#include "common.h"
#include "stopwatch.h"
struct io_uring ring;
void init(__attribute__((unused)) int fd) {
int res = io_uring_queue_init(16, &ring, IORING_SETUP_SQPOLL);
if (res < 0) {
errno = res;
err(EXIT_FAILURE, "io_uring_setup failed");
}
}
void do_write(int fd, const void *buf, size_t count) {
start_watch();
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
while (unlikely(!sqe)) {
sqe = io_uring_get_sqe(&ring);
}
io_uring_prep_write(sqe, fd, buf, count, 0);
int res = io_uring_submit(&ring);
struct io_uring_cqe *cqe;
while (io_uring_peek_cqe(&ring, &cqe) == -EAGAIN) {
}
stop_watch();
if (res < 0) {
err(EXIT_FAILURE, "io_submit failed");
}
if (cqe->res < 0) {
err(EXIT_FAILURE, "write request failed");
}
}
......@@ -3,9 +3,8 @@
#include <liburing.h>
#include <stdlib.h>
#define unlikely(x) __builtin_expect(!!(x), 0)
#include "rdtsc.h"
#include "common.h"
#include "stopwatch.h"
struct io_uring ring;
......@@ -17,9 +16,8 @@ void init(__attribute__((unused)) int fd) {
}
}
int64_t do_write(int fd, const void* buf, size_t count) {
int64_t clock_before, clock_after;
clock_before = rdtsc_s();
void do_write(int fd, const void *buf, size_t count) {
start_watch();
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
while (unlikely(!sqe)) {
......@@ -29,13 +27,13 @@ int64_t do_write(int fd, const void* buf, size_t count) {
int res = io_uring_submit_and_wait(&ring, 1);
clock_after = rdtsc_e();
stop_watch();
if (res < 0) {
err(EXIT_FAILURE, "io_uring_submit_and_wait failed");
}
struct io_uring_cqe* cqe;
struct io_uring_cqe *cqe;
res = io_uring_peek_cqe(&ring, &cqe);
if (res < 0) {
err(EXIT_FAILURE, "io_uring_peek_cqe failed");
......@@ -44,6 +42,4 @@ int64_t do_write(int fd, const void* buf, size_t count) {
if (cqe->res < 0) {
err(EXIT_FAILURE, "write request failed");
}
return clock_after - clock_before;
}
......@@ -3,7 +3,7 @@
#include <liburing.h>
#include <stdlib.h>
#include "rdtsc.h"
#include "stopwatch.h"
struct io_uring ring;
......@@ -15,30 +15,21 @@ void init(__attribute__((unused)) int fd) {
}
}
int64_t do_write(int fd, const void* buf, size_t count) {
int64_t clock_before, clock_after;
clock_before = rdtsc_s();
void do_write(int fd, const void *buf, size_t count) {
start_watch();
struct io_uring_sqe *sqe = io_uring_get_sqe(&ring);
io_uring_prep_write(sqe, fd, buf, count, 0);
int res = io_uring_submit_and_wait(&ring, 1);
clock_after = rdtsc_e();
stop_watch();
if (res < 0) {
err(EXIT_FAILURE, "io_uring_submit_and_wait failed");
}
if (res < 0) err(EXIT_FAILURE, "io_uring_submit_and_wait failed");
struct io_uring_cqe* cqe;
struct io_uring_cqe *cqe;
res = io_uring_peek_cqe(&ring, &cqe);
if (res < 0) {
err(EXIT_FAILURE, "io_uring_peek_cqe failed");
}
if (cqe->res < 0) {
err(EXIT_FAILURE, "write request failed");
}
if (res < 0) err(EXIT_FAILURE, "io_uring_peek_cqe failed");
return clock_after - clock_before;
if (cqe->res < 0) err(EXIT_FAILURE, "write request failed");
}
#include "stopwatch.h"
uint64_t cycles_start, cycles_stop;
struct timespec start, stop;
int64_t sec_to_nanos(int64_t sec) { return sec * 1000 * 1000 * 1000; }
double nanos_to_millis(int64_t nanos) { return ((double)nanos) / (1000 * 1000); }
int64_t clock_diff_nanos() {
int64_t nanos = sec_to_nanos(stop.tv_sec - start.tv_sec);
nanos += (stop.tv_nsec - start.tv_nsec);
return nanos;
}
uint64_t clock_diff_cycles() { return cycles_stop - cycles_start; }
#pragma once
#include <stdint.h>
#include <time.h>
extern uint64_t cycles_start, cycles_stop;
extern struct timespec start, stop;
static __inline__ int64_t rdtsc_s(void) {
static __inline__ uint64_t rdtsc_s(void) {
unsigned a, d;
asm volatile("cpuid" ::: "%rax", "%rbx", "%rcx", "%rdx");
asm volatile("rdtsc" : "=a" (a), "=d" (d));
asm volatile("rdtsc" : "=a"(a), "=d"(d));
return ((unsigned long)a) | (((unsigned long)d) << 32);
}
static __inline__ int64_t rdtsc_e(void) {
static __inline__ uint64_t rdtsc_e(void) {
unsigned a, d;
asm volatile("rdtscp" : "=a" (a), "=d" (d));
asm volatile("rdtscp" : "=a"(a), "=d"(d));
asm volatile("cpuid" ::: "%rax", "%rbx", "%rcx", "%rdx");
return ((unsigned long)a) | (((unsigned long)d) << 32);
}
static inline void start_watch() {
clock_gettime(CLOCK_MONOTONIC, &start);
cycles_start = rdtsc_s();
}
static inline void stop_watch() {
cycles_stop = rdtsc_e();
clock_gettime(CLOCK_MONOTONIC, &stop);
}
uint64_t clock_diff_cycles();
int64_t clock_diff_nanos();
double nanos_to_millis(int64_t nanos);
int64_t sec_to_nanos(int64_t sec);
#!/usr/bin/env bash
set -euo pipefail
# Pretty fancy method to get reliable the absolute path of a shell
# script, *even if it is sourced*. Credits go to GreenFox on
# stackoverflow: http://stackoverflow.com/a/12197518/194894
pushd . > /dev/null
SCRIPTDIR="${BASH_SOURCE[0]}";
while([ -h "${SCRIPTDIR}" ]); do
cd "`dirname "${SCRIPTDIR}"`"
SCRIPTDIR="$(readlink "`basename "${SCRIPTDIR}"`")";
done
cd "`dirname "${SCRIPTDIR}"`" > /dev/null
SCRIPTDIR="`pwd`";
popd > /dev/null
DEBUG=false
while getopts d OPT; do
case $OPT in
d)
set -x
DEBUG=true
;;
*)
echo "usage: ${0##*/} [-dq} [--] ARGS..."
exit 2
esac
done
shift $(( OPTIND - 1 ))
OPTIND=1
ROOTDIR=$(readlink -f "${SCRIPTDIR}/..")
MAX_PROCS=$(nproc)