From af06aeb71651413ad59e2dd9c40fdf8d8eef0cf8 Mon Sep 17 00:00:00 2001
From: Florian Fischer <florian.fischer@muhq.space>
Date: Fri, 30 Jul 2021 17:49:11 +0200
Subject: [PATCH] work work work

---
 Makefile              |  4 ++--
 aio-sig.c             | 23 ++++++++++-------------
 aio-thrd.c            | 27 +++++++++++----------------
 bench.c               | 28 +++++++++-------------------
 blocking.c            | 12 ++++--------
 common.h              | 22 ----------------------
 epoll.c               | 12 ++++--------
 io-uring-no-syscall.c | 42 ++++++++++++++++++++++++++++++++++++++++++
 io-uring-sqpoll.c     | 11 ++++-------
 io-uring.c            | 20 +++++++-------------
 rdtsc.h               | 15 ---------------
 stopwatch.c           | 18 ++++++++++++++++++
 stopwatch.h           | 18 ++++++++++++++++++
 13 files changed, 129 insertions(+), 123 deletions(-)
 delete mode 100644 common.h
 create mode 100644 io-uring-no-syscall.c
 delete mode 100644 rdtsc.h
 create mode 100644 stopwatch.c
 create mode 100644 stopwatch.h

diff --git a/Makefile b/Makefile
index 0e6ff8c..139ebf0 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,5 @@
 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))
 
@@ -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
 
diff --git a/aio-sig.c b/aio-sig.c
index fda8c73..408aa6f 100644
--- a/aio-sig.c
+++ b/aio-sig.c
@@ -1,29 +1,25 @@
 #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;
 
 void callback(int sig, siginfo_t* info, void* context) {
-	clock_after = rdtsc_s();
+	stop_watch();
 	if (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;
@@ -37,16 +33,17 @@ void init(int fd) {
 		err(EXIT_FAILURE, "sigaction failed");
 }
 
-int64_t do_write(int fd, const void* buf, size_t count) {
+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");
 
-	return clock_after - clock_before;
+	while(!atomic_load(&done)) {}
+	atomic_store(&done, 1);
+
 }
diff --git a/aio-thrd.c b/aio-thrd.c
index 422917f..7e03762 100644
--- a/aio-thrd.c
+++ b/aio-thrd.c
@@ -1,46 +1,41 @@
 #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");
 
-	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);
+
+	while(!atomic_load(&done)) {}
+	atomic_store(&done, 0);
 
 	if (res == -1)
 		err(EXIT_FAILURE, "aio_write failed");
-
-	return clock_after - clock_before;
 }
diff --git a/bench.c b/bench.c
index 861ea70..38c2828 100644
--- a/bench.c
+++ b/bench.c
@@ -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,21 @@ static int create_eventfd() {
 }
 
 int main() {
-	double avg_cycles = 0;
+	int64_t avg_nanos = 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 = 1; i <= iterations; ++i) {
-		ssize_t cycles = do_write(fd, &write_buf, sizeof(write_buf));
-		avg_cycles += ((double)cycles - avg_cycles) / i;
+	for (int64_t i = 1; i <= iterations; ++i) {
+		do_write(fd, &write_buf, sizeof(write_buf));
+		avg_nanos += (clock_diff_nanos() - avg_nanos) / i;
 	}
 
-	printf("avg_cycles: %lf\n", avg_cycles);
-
+	printf("%ld ns\n", avg_nanos);
 	return 0;
 }
diff --git a/blocking.c b/blocking.c
index 9e05714..513e621 100644
--- a/blocking.c
+++ b/blocking.c
@@ -2,19 +2,15 @@
 #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();
+	stop_watch();
 
 	if (res == -1)
 		err(EXIT_FAILURE, "write failed");
-
-	return clock_after - clock_before;
 }
diff --git a/common.h b/common.h
deleted file mode 100644
index 909aa54..0000000
--- a/common.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#include <err.h>
-#include <fcntl.h>
-#include <stdint.h>
-#include <stdlib.h>
-
-#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);
-}
diff --git a/epoll.c b/epoll.c
index d898734..a4ef79a 100644
--- a/epoll.c
+++ b/epoll.c
@@ -3,7 +3,7 @@
 #include <sys/epoll.h>
 #include <unistd.h>
 
-#include "rdtsc.h"
+#include "stopwatch.h"
 
 struct epoll_event ev;
 int nfds, epollfd;
@@ -21,13 +21,11 @@ void init(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();
 	nfds = epoll_wait(epollfd, &ev, 1, -1);
 	size_t res = write(fd, buf, count);
-	clock_after = rdtsc_s();
+	stop_watch();
 
 	if (nfds == -1)
 		err(EXIT_FAILURE, "epoll_wait failed");
@@ -37,6 +35,4 @@ int64_t do_write(int fd, const void* buf, size_t count) {
 
 	if (res == -1)
 		err(EXIT_FAILURE, "write failed");
-
-	return clock_after - clock_before;
 }
diff --git a/io-uring-no-syscall.c b/io-uring-no-syscall.c
new file mode 100644
index 0000000..aa0cef0
--- /dev/null
+++ b/io-uring-no-syscall.c
@@ -0,0 +1,42 @@
+#include <err.h>
+#include <errno.h>
+#include <liburing.h>
+#include <stdlib.h>
+
+#define unlikely(x) __builtin_expect(!!(x), 0)
+
+#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");
+	}
+}
diff --git a/io-uring-sqpoll.c b/io-uring-sqpoll.c
index e46e517..7ea1e11 100644
--- a/io-uring-sqpoll.c
+++ b/io-uring-sqpoll.c
@@ -5,7 +5,7 @@
 
 #define unlikely(x) __builtin_expect(!!(x), 0)
 
-#include "rdtsc.h"
+#include "stopwatch.h"
 
 struct io_uring ring;
 
@@ -17,9 +17,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,7 +28,7 @@ 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");
@@ -44,6 +43,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;
 }
diff --git a/io-uring.c b/io-uring.c
index 53f16f1..51afb7d 100644
--- a/io-uring.c
+++ b/io-uring.c
@@ -3,7 +3,7 @@
 #include <liburing.h>
 #include <stdlib.h>
 
-#include "rdtsc.h"
+#include "stopwatch.h"
 
 struct io_uring ring;
 
@@ -15,30 +15,24 @@ 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) {
+	if (res < 0)
 		err(EXIT_FAILURE, "io_uring_submit_and_wait failed");
-	}
 
 	struct io_uring_cqe* cqe;
 	res = io_uring_peek_cqe(&ring, &cqe);
-	if (res < 0) {
+	if (res < 0)
 		err(EXIT_FAILURE, "io_uring_peek_cqe failed");
-	}
 
-	if (cqe->res < 0) {
+	if (cqe->res < 0)
 		err(EXIT_FAILURE, "write request failed");
-	}
-
-	return clock_after - clock_before;
 }
diff --git a/rdtsc.h b/rdtsc.h
deleted file mode 100644
index ac687bb..0000000
--- a/rdtsc.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#include <stdint.h>
-
-static __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);
-}
-
-static __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);
-}
diff --git a/stopwatch.c b/stopwatch.c
new file mode 100644
index 0000000..f781b7b
--- /dev/null
+++ b/stopwatch.c
@@ -0,0 +1,18 @@
+#include "stopwatch.h"
+
+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;
+}
+
diff --git a/stopwatch.h b/stopwatch.h
new file mode 100644
index 0000000..0743b11
--- /dev/null
+++ b/stopwatch.h
@@ -0,0 +1,18 @@
+#pragma once 
+
+#include <stdint.h>
+#include <time.h>
+
+extern struct timespec start, stop;
+
+static inline void start_watch() {
+	clock_gettime(CLOCK_MONOTONIC, &start);
+}
+
+static inline void stop_watch() {
+	clock_gettime(CLOCK_MONOTONIC, &stop);
+}
+
+int64_t clock_diff_nanos();
+double nanos_to_millis(int64_t nanos);
+int64_t sec_to_nanos(int64_t sec);
-- 
GitLab