[PATCH v1 4/4] liburing: add unit test for io_uring_register_iowait()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: David Wei <davidhwei@xxxxxxxx>

Add a unit test for io_uring_register_iowait() by creating a thread that
writes into a pipe after a delay, checking iowait before and after.

Signed-off-by: David Wei <davidhwei@xxxxxxxx>
---
 test/Makefile |   1 +
 test/iowait.c | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 158 insertions(+)
 create mode 100644 test/iowait.c

diff --git a/test/Makefile b/test/Makefile
index b09228f..779a7db 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -107,6 +107,7 @@ test_srcs := \
 	io_uring_passthrough.c \
 	io_uring_register.c \
 	io_uring_setup.c \
+	iowait.c \
 	lfs-openat.c \
 	lfs-openat-write.c \
 	link.c \
diff --git a/test/iowait.c b/test/iowait.c
new file mode 100644
index 0000000..fcd4004
--- /dev/null
+++ b/test/iowait.c
@@ -0,0 +1,157 @@
+/* SPDX-License-Identifier: MIT */
+/*
+ * Description: Test that waiting for CQ is accounted as iowait if enabled via
+ * io_uring_register_iowait(), and vice versa.
+ *
+ */
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/time.h>
+#include <pthread.h>
+#include <linux/kernel.h>
+
+#include "liburing.h"
+#include "helpers.h"
+
+struct data {
+	pthread_barrier_t startup;
+	int out_fd;
+};
+
+static unsigned long long get_iowait()
+{
+	FILE *fp;
+	char buf[256];
+	unsigned long long user, nice, system, idle, iowait;
+
+	fp = fopen("/proc/stat", "r");
+	if (!fp) {
+		perror("fopen");
+		exit(T_EXIT_FAIL);
+	}
+
+	if (fgets(buf, sizeof(buf), fp) == NULL) {
+		perror("fgets");
+		fclose(fp);
+		exit(T_EXIT_FAIL);
+	}
+	fclose(fp);
+
+	sscanf(buf, "cpu %llu %llu %llu %llu %llu", &user, &nice, &system,
+						    &idle, &iowait);
+
+	return iowait;
+}
+
+static void *pipe_write(void *data)
+{
+	struct data *d = data;
+	char buf[32];
+	int ret;
+
+	memset(buf, 0x55, sizeof(buf));
+	pthread_barrier_wait(&d->startup);
+	usleep(100000);
+
+	ret = write(d->out_fd, buf, sizeof(buf));
+	if (ret < 0) {
+		perror("write");
+		return NULL;
+	}
+
+	return NULL;
+}
+
+static int test_iowait(struct io_uring *ring, bool enabled)
+{
+	unsigned long long iowait_pre, iowait_post, iowait;
+	double iowait_ms_max_diff;
+	struct io_uring_cqe *cqe;
+	struct io_uring_sqe *sqe;
+	pthread_t thread;
+	double iowait_ms;
+	int ret, fds[2];
+	struct data d;
+	char buf[32];
+	void *tret;
+
+	if (pipe(fds) < 0) {
+		perror("pipe");
+		return T_EXIT_FAIL;
+	}
+	d.out_fd = fds[1];
+
+	pthread_barrier_init(&d.startup, NULL, 2);
+	pthread_create(&thread, NULL, pipe_write, &d);
+	pthread_barrier_wait(&d.startup);
+
+	io_uring_register_iowait(ring, enabled);
+
+	sqe = io_uring_get_sqe(ring);
+	io_uring_prep_read(sqe, fds[0], buf, sizeof(buf), 0);
+
+	io_uring_submit(ring);
+
+	iowait_pre = get_iowait();
+	ret = io_uring_wait_cqe(ring, &cqe);
+	if (ret) {
+		fprintf(stderr, "wait_cqe: %d\n", ret);
+		return T_EXIT_FAIL;
+	}
+	io_uring_cq_advance(ring, 1);
+
+	iowait_post = get_iowait();
+
+	/* 
+	 * writer sleeps for 100 ms, so max diff is 100 plus a tolerance of
+	 * 10 ms
+	 */
+	iowait_ms_max_diff = (enabled ? 100.0 : 0.0) + 10.0;
+
+	if (iowait_post > iowait_pre)
+		iowait = iowait_post - iowait_pre;
+	else
+		iowait = iowait_pre - iowait_post;
+	iowait_ms = ((double)iowait / sysconf(_SC_CLK_TCK)) * 1000;
+
+	if (iowait_ms > iowait_ms_max_diff)
+		ret = T_EXIT_FAIL;
+	else
+		ret = T_EXIT_PASS;
+
+	pthread_join(thread, &tret);
+	close(fds[0]);
+	close(fds[1]);
+	return ret;
+}
+
+int main(int argc, char *argv[])
+{
+	struct io_uring ring;
+	struct io_uring_params p = { };
+	int ret;
+
+	if (argc > 1)
+		return 0;
+
+	ret = t_create_ring_params(8, &ring, &p);
+	if (ret == T_SETUP_SKIP)
+		return T_EXIT_SKIP;
+	else if (ret != T_SETUP_OK)
+		return ret;
+
+	ret = test_iowait(&ring, false);
+	if (ret == T_EXIT_FAIL || ret == T_EXIT_SKIP)
+		return ret;
+
+	ret = test_iowait(&ring, true);
+	if (ret == T_EXIT_FAIL || ret == T_EXIT_SKIP)
+		return ret;
+
+	io_uring_queue_exit(&ring);
+	return T_EXIT_PASS;
+}
-- 
2.43.0





[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux