1
0
mirror of https://github.com/adtools/clib2.git synced 2025-12-08 14:59:05 +00:00

Optimizations for better read performance.

If the buffer mode is set to "no buffering" then fread() will always bypass the buffer and call read() instead.

If there is enough data waiting to be read from the buffer, fread() will now copy it directly, refilling the buffer as needed.

If the read buffer happens to be empty, buffering is enabled for the stream, and the number of bytes to read is at least as large as the buffer size,  then fread() will directly call read(), which should improve performance significantly.
This commit is contained in:
obarthel
2019-08-24 13:53:48 +02:00
parent 3f21e90fca
commit ae13cd77fc

View File

@ -1,10 +1,8 @@
/*
* $Id: stdio_fread.c,v 1.7 2006-01-08 12:04:24 obarthel Exp $
*
* :ts=4
*
* Portable ISO 'C' (1994) runtime library for the Amiga computer
* Copyright (c) 2002-2015 by Olaf Barthel <obarthel (at) gmx.net>
* Copyright (c) 2002-2019 by Olaf Barthel <obarthel (at) gmx.net>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -102,6 +100,9 @@ fread(void *ptr,size_t element_size,size_t count,FILE *stream)
goto out;
}
/* So that we can tell error and 'end of file' conditions apart. */
clearerr(stream);
if(element_size > 0 && count > 0)
{
size_t total_bytes_read = 0;
@ -116,15 +117,87 @@ fread(void *ptr,size_t element_size,size_t count,FILE *stream)
SHOWVALUE(total_size);
while(total_size-- > 0)
if((file->iob_Flags & IOBF_BUFFER_MODE) == IOBF_BUFFER_MODE_NONE)
{
c = __getc(file);
if(c == EOF)
break;
ssize_t num_bytes_read;
(*data++) = c;
/* We bypass the buffer entirely. */
num_bytes_read = read(file->iob_Descriptor, data, total_size);
if(num_bytes_read == -1)
{
SET_FLAG(file->iob_Flags,IOBF_ERROR);
goto out;
}
total_bytes_read++;
if(num_bytes_read == 0)
SET_FLAG(file->iob_Flags,IOBF_EOF_REACHED);
total_bytes_read = num_bytes_read;
}
else
{
while(total_size > 0)
{
/* If there is more data to be read and the read buffer is empty
anyway, we'll bypass the buffer entirely. */
if(file->iob_BufferReadBytes == 0 && total_size >= (size_t)file->iob_BufferSize)
{
ssize_t num_bytes_read;
/* We bypass the buffer entirely. */
num_bytes_read = read(file->iob_Descriptor, data, total_size);
if(num_bytes_read == -1)
{
SET_FLAG(file->iob_Flags,IOBF_ERROR);
goto out;
}
if(num_bytes_read == 0)
SET_FLAG(file->iob_Flags,IOBF_EOF_REACHED);
total_bytes_read += num_bytes_read;
break;
}
/* If there is data in the read buffer, try to copy it directly
into the output buffer. */
if(file->iob_BufferPosition < file->iob_BufferReadBytes)
{
const unsigned char * buffer = &file->iob_Buffer[file->iob_BufferPosition];
size_t num_bytes_in_buffer;
/* Copy as much data as will fit. */
num_bytes_in_buffer = file->iob_BufferReadBytes - file->iob_BufferPosition;
if(total_size < num_bytes_in_buffer)
num_bytes_in_buffer = total_size;
memmove(data, buffer, num_bytes_in_buffer);
data += num_bytes_in_buffer;
file->iob_BufferPosition += num_bytes_in_buffer;
total_bytes_read += num_bytes_in_buffer;
/* Stop if the string buffer has been filled. */
total_size -= num_bytes_in_buffer;
if(total_size == 0)
break;
/* If the read buffer is now empty and there is still enough data
to be read, try to optimize the read operation. */
if(file->iob_BufferReadBytes == 0 && total_size >= (size_t)file->iob_BufferSize)
continue;
}
c = __getc(file);
if(c == EOF)
break;
(*data++) = c;
total_size--;
total_bytes_read++;
}
}
SHOWVALUE(total_bytes_read);
@ -137,9 +210,6 @@ fread(void *ptr,size_t element_size,size_t count,FILE *stream)
SHOWVALUE(count);
SHOWMSG("either element size or count is zero");
/* Don't let this appear like an EOF or error. */
clearerr((FILE *)file);
}
D(("total number of elements read = %ld",result));