From 1d166e3be16fe62de80d93e4c113892ba7d74dfe Mon Sep 17 00:00:00 2001 From: Michel Machado Date: Tue, 8 Nov 2022 09:49:03 -0500 Subject: [PATCH] Add dynamic buffers to f3write The write buffer passed to the operating system has previously been limited to MAX_BUFFER_SIZE. This commit makes it dynamically sized in order to reach maximum writing speeds. See details on issue #188. --- f3write.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 5 deletions(-) diff --git a/f3write.c b/f3write.c index 8942dc5..15893c1 100644 --- a/f3write.c +++ b/f3write.c @@ -150,13 +150,67 @@ static int write_all(int fd, const char *buf, size_t count) return 0; } -static int write_chunk(int fd, size_t chunk_size, uint64_t *poffset) +struct dynamic_buffer { + char *buf; + size_t len; + bool max_buf; + char backup_buf[MAX_BUFFER_SIZE]; +}; + +static inline void dbuf_init(struct dynamic_buffer *dbuf) +{ + dbuf->buf = NULL; + dbuf->len = 0; + dbuf->max_buf = false; +} + +static inline void dbuf_free(struct dynamic_buffer *dbuf) +{ + free(dbuf->buf); + dbuf_init(dbuf); +} + +static char *dbuf_get_buf(struct dynamic_buffer *dbuf, size_t size) +{ + /* If enough buffer, or it's already the largest buffer, return it. */ + if (size <= dbuf->len || dbuf->max_buf) + return dbuf->buf; + + /* + * Allocate a new buffer. + */ + + free(dbuf->buf); + do { + dbuf->buf = malloc(size); + if (dbuf->buf != NULL) { + dbuf->len = size; + return dbuf->buf; + } else { + dbuf->max_buf = true; + } + size /= 2; + } while (size > sizeof(dbuf->backup_buf)); + + /* A larger buffer is not available; failsafe. */ + dbuf->buf = dbuf->backup_buf; + dbuf->len = sizeof(dbuf->backup_buf); + return dbuf->buf; +} + +static inline size_t dbuf_get_len(const struct dynamic_buffer *dbuf) +{ + return dbuf->len; +} + +static int write_chunk(struct dynamic_buffer *dbuf, int fd, size_t chunk_size, + uint64_t *poffset) { - char buf[MAX_BUFFER_SIZE]; + char *buf = dbuf_get_buf(dbuf, chunk_size); + size_t len = dbuf_get_len(dbuf); while (chunk_size > 0) { - size_t turn_size = chunk_size <= MAX_BUFFER_SIZE - ? chunk_size : MAX_BUFFER_SIZE; + size_t turn_size = chunk_size <= len ? chunk_size : len; int ret; chunk_size -= turn_size; *poffset = fill_buffer(buf, turn_size, *poffset); @@ -177,6 +231,7 @@ static int create_and_fill_file(const char *path, long number, size_t size, int fd, saved_errno; size_t remaining; uint64_t offset; + struct dynamic_buffer dbuf; assert(size > 0); assert(size % fw->block_size == 0); @@ -198,6 +253,7 @@ static int create_and_fill_file(const char *path, long number, size_t size, assert(fd >= 0); /* Write content. */ + dbuf_init(&dbuf); saved_errno = 0; offset = (uint64_t)number * GIGABYTES; remaining = size; @@ -206,7 +262,7 @@ static int create_and_fill_file(const char *path, long number, size_t size, uint64_t write_size = get_rem_chunk_size(fw); if (write_size > remaining) write_size = remaining; - saved_errno = write_chunk(fd, write_size, &offset); + saved_errno = write_chunk(&dbuf, fd, write_size, &offset); if (saved_errno) break; remaining -= write_size; @@ -220,6 +276,7 @@ static int create_and_fill_file(const char *path, long number, size_t size, if (!saved_errno) saved_errno = errno; } + dbuf_free(&dbuf); close(fd); free(full_fn);