From bc1bf4cb53341c8ad9bf3e866e1c1a488cc9d0d5 Mon Sep 17 00:00:00 2001 From: LI Qing Date: Wed, 15 May 2024 12:00:14 +0800 Subject: [PATCH] Add the file_io microbenchmark --- regression/apps/Makefile | 3 +- regression/apps/file_io/Makefile | 5 ++ regression/apps/file_io/file_io.c | 134 ++++++++++++++++++++++++++++++ 3 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 regression/apps/file_io/Makefile create mode 100644 regression/apps/file_io/file_io.c diff --git a/regression/apps/Makefile b/regression/apps/Makefile index 85852d35e..0c8eba9a2 100644 --- a/regression/apps/Makefile +++ b/regression/apps/Makefile @@ -10,8 +10,9 @@ REGRESSION_BUILD_DIR ?= $(INITRAMFS)/regression # These test apps are sorted by name TEST_APPS := \ - execve \ eventfd2 \ + execve \ + file_io \ fork \ fork_c \ getpid \ diff --git a/regression/apps/file_io/Makefile b/regression/apps/file_io/Makefile new file mode 100644 index 000000000..d9048d1cd --- /dev/null +++ b/regression/apps/file_io/Makefile @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: MPL-2.0 + +include ../test_common.mk + +EXTRA_C_FLAGS := -Wno-incompatible-pointer-types diff --git a/regression/apps/file_io/file_io.c b/regression/apps/file_io/file_io.c new file mode 100644 index 000000000..082916ac9 --- /dev/null +++ b/regression/apps/file_io/file_io.c @@ -0,0 +1,134 @@ +// SPDX-License-Identifier: MPL-2.0 + +#include +#include +#include +#include +#include +#include +#include + +#define KB 1024 +#define MB (1024 * KB) +#define BUFFER_SIZE (4 * KB) +#define FILE_SIZE (256 * MB) +#define NUM_OF_CALLS 1000000 + +int fill_file(int fd) +{ + ssize_t bytes_write, offset = 0; + char buffer[BUFFER_SIZE]; + + memset(buffer, 0, BUFFER_SIZE); + lseek(fd, 0, SEEK_SET); + + while (offset < FILE_SIZE) { + bytes_write = write(fd, buffer, BUFFER_SIZE); + if (bytes_write == -1) { + fprintf(stderr, "Failed to write the file.\n"); + return -1; + } + offset += bytes_write; + } + + return 0; +} + +long calc_duration(struct timespec *start, struct timespec *end) +{ + return (end->tv_sec - start->tv_sec) * 1e9 + + (end->tv_nsec - start->tv_nsec); +} + +int perform_sequential_io(int fd, ssize_t (*io_func)(int, void *, size_t), + const char *op_name) +{ + struct timespec start, end; + char buffer[BUFFER_SIZE]; + ssize_t ret, offset = 0; + long total_nanoseconds = 0, avg_latency; + + memset(buffer, 0, BUFFER_SIZE); + lseek(fd, 0, SEEK_SET); + + for (int i = 0; i < NUM_OF_CALLS; i++) { + if (offset >= FILE_SIZE) { + offset = lseek(fd, 0, SEEK_SET); + } + clock_gettime(CLOCK_MONOTONIC, &start); + ret = io_func(fd, buffer, BUFFER_SIZE); + clock_gettime(CLOCK_MONOTONIC, &end); + if (ret == -1) { + fprintf(stderr, "Failed to %s the file.\n", op_name); + return -1; + } + offset += ret; + total_nanoseconds += calc_duration(&start, &end); + } + + avg_latency = total_nanoseconds / NUM_OF_CALLS; + printf("Executed the sequential %s (buffer size: %dKB, file size: %dMB) syscall %d times.\n", + op_name, BUFFER_SIZE / KB, FILE_SIZE / MB, NUM_OF_CALLS); + printf("Syscall average latency: %ld nanoseconds.\n", avg_latency); + + return 0; +} + +int sequential_read(int fd) +{ + return perform_sequential_io(fd, read, "read"); +} + +int sequential_write(int fd) +{ + return perform_sequential_io(fd, write, "write"); +} + +int main(int argc, char *argv[]) +{ + if (argc < 2) { + fprintf(stderr, "Usage: %s \n", argv[0]); + return -1; + } + + int fd = open(argv[1], O_RDWR | O_CREAT, 00666); + if (fd == -1) { + fprintf(stderr, "Failed to open the file: %s.\n", argv[1]); + return -1; + } + if (ftruncate(fd, FILE_SIZE) < 0) { + fprintf(stderr, + "Failed to truncate the file: %s to size: %dMB.\n", + argv[1], FILE_SIZE / MB); + return -1; + } + + // Warm up by filling the file. + if (fill_file(fd) < 0) { + fprintf(stderr, "Failed to fill the file: %s.\n", argv[1]); + return -1; + } + + if (sequential_read(fd) < 0) { + fprintf(stderr, + "Failed to do sequential read on the file: %s.\n", + argv[1]); + return -1; + } + if (sequential_write(fd) < 0) { + fprintf(stderr, + "Failed to do sequential write on the file: %s.\n", + argv[1]); + return -1; + } + + // TODO: Add more test cases such as random read and random write. + + close(fd); + if (unlink(argv[1]) < 0) { + fprintf(stderr, "Failed to delete the file: %s.\n", argv[1]); + return -1; + } + + return 0; +} \ No newline at end of file