Skip to content

Commit

Permalink
Add dynamic buffers to f3write
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
AltraMayor committed Nov 8, 2022
1 parent 3b015a5 commit 1d166e3
Showing 1 changed file with 62 additions and 5 deletions.
67 changes: 62 additions & 5 deletions f3write.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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);
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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);

Expand Down

0 comments on commit 1d166e3

Please sign in to comment.