aboutsummaryrefslogtreecommitdiff
path: root/libgfortran
diff options
context:
space:
mode:
authorThomas Koenig <tkoenig@gcc.gnu.org>2019-07-21 15:55:49 +0000
committerThomas Koenig <tkoenig@gcc.gnu.org>2019-07-21 15:55:49 +0000
commitc37b0163fe5307ab508489926114de9cf7e240c1 (patch)
tree205699e71034f0bc8b7603c02225124f390c4073 /libgfortran
parent037455d49c2c19521bf60253c098d0e1e48d68fa (diff)
downloadgcc-c37b0163fe5307ab508489926114de9cf7e240c1.zip
gcc-c37b0163fe5307ab508489926114de9cf7e240c1.tar.gz
gcc-c37b0163fe5307ab508489926114de9cf7e240c1.tar.bz2
re PR libfortran/91030 (Poor performance of I/O -fconvert=big-endian)
2019-07-21 Thomas König <tkoenig@gcc.gnu.org> PR libfortran/91030 * gfortran.texi (GFORTRAN_FORMATTED_BUFFER_SIZE): Document (GFORTRAN_UNFORMATTED_BUFFER_SIZE): Likewise. 2019-07-21 Thomas König <tkoenig@gcc.gnu.org> PR libfortran/91030 * io/unix.c (BUFFER_SIZE): Delete. (BUFFER_FORMATTED_SIZE_DEFAULT): New variable. (BUFFER_UNFORMATTED_SIZE_DEFAULT): New variable. (unix_stream): Add buffer_size. (buf_read): Use s->buffer_size instead of BUFFER_SIZE. (buf_write): Likewise. (buf_init): Add argument unformatted. Handle block sizes for unformatted vs. formatted, using defaults if provided. (fd_to_stream): Add argument unformatted in call to buf_init. * libgfortran.h (options_t): Add buffer_size_formatted and buffer_size_unformatted. * runtime/environ.c (variable_table): Add GFORTRAN_UNFORMATTED_BUFFER_SIZE and GFORTRAN_FORMATTED_BUFFER_SIZE. From-SVN: r273643
Diffstat (limited to 'libgfortran')
-rw-r--r--libgfortran/ChangeLog18
-rw-r--r--libgfortran/io/unix.c47
-rw-r--r--libgfortran/libgfortran.h1
-rw-r--r--libgfortran/runtime/environ.c8
4 files changed, 62 insertions, 12 deletions
diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog
index 71fe27b..b4e3fe7 100644
--- a/libgfortran/ChangeLog
+++ b/libgfortran/ChangeLog
@@ -1,3 +1,21 @@
+2019-07-21 Thomas König <tkoenig@gcc.gnu.org>
+
+ PR libfortran/91030
+ * io/unix.c (BUFFER_SIZE): Delete.
+ (BUFFER_FORMATTED_SIZE_DEFAULT): New variable.
+ (BUFFER_UNFORMATTED_SIZE_DEFAULT): New variable.
+ (unix_stream): Add buffer_size.
+ (buf_read): Use s->buffer_size instead of BUFFER_SIZE.
+ (buf_write): Likewise.
+ (buf_init): Add argument unformatted. Handle block sizes
+ for unformatted vs. formatted, using defaults if provided.
+ (fd_to_stream): Add argument unformatted in call to buf_init.
+ * libgfortran.h (options_t): Add buffer_size_formatted and
+ buffer_size_unformatted.
+ * runtime/environ.c (variable_table): Add
+ GFORTRAN_UNFORMATTED_BUFFER_SIZE and
+ GFORTRAN_FORMATTED_BUFFER_SIZE.
+
2019-06-25 Kwok Cheung Yeung <kcy@codesourcery.com>
Andrew Stubbs <ams@codesourcery.com>
diff --git a/libgfortran/io/unix.c b/libgfortran/io/unix.c
index c2fc674..4279297 100644
--- a/libgfortran/io/unix.c
+++ b/libgfortran/io/unix.c
@@ -193,7 +193,8 @@ fallback_access (const char *path, int mode)
/* Unix and internal stream I/O module */
-static const int BUFFER_SIZE = 8192;
+static const int FORMATTED_BUFFER_SIZE_DEFAULT = 8192;
+static const int UNFORMATTED_BUFFER_SIZE_DEFAULT = 128*1024;
typedef struct
{
@@ -205,6 +206,7 @@ typedef struct
gfc_offset file_length; /* Length of the file. */
char *buffer; /* Pointer to the buffer. */
+ ssize_t buffer_size; /* Length of the buffer. */
int fd; /* The POSIX file descriptor. */
int active; /* Length of valid bytes in the buffer */
@@ -592,9 +594,9 @@ buf_read (unix_stream *s, void *buf, ssize_t nbyte)
&& raw_seek (s, new_logical, SEEK_SET) < 0)
return -1;
s->buffer_offset = s->physical_offset = new_logical;
- if (to_read <= BUFFER_SIZE/2)
+ if (to_read <= s->buffer_size/2)
{
- did_read = raw_read (s, s->buffer, BUFFER_SIZE);
+ did_read = raw_read (s, s->buffer, s->buffer_size);
if (likely (did_read >= 0))
{
s->physical_offset += did_read;
@@ -632,11 +634,11 @@ buf_write (unix_stream *s, const void *buf, ssize_t nbyte)
s->buffer_offset = s->logical_offset;
/* Does the data fit into the buffer? As a special case, if the
- buffer is empty and the request is bigger than BUFFER_SIZE/2,
+ buffer is empty and the request is bigger than s->buffer_size/2,
write directly. This avoids the case where the buffer would have
to be flushed at every write. */
- if (!(s->ndirty == 0 && nbyte > BUFFER_SIZE/2)
- && s->logical_offset + nbyte <= s->buffer_offset + BUFFER_SIZE
+ if (!(s->ndirty == 0 && nbyte > s->buffer_size/2)
+ && s->logical_offset + nbyte <= s->buffer_offset + s->buffer_size
&& s->buffer_offset <= s->logical_offset
&& s->buffer_offset + s->ndirty >= s->logical_offset)
{
@@ -651,7 +653,7 @@ buf_write (unix_stream *s, const void *buf, ssize_t nbyte)
the request is bigger than the buffer size, write directly
bypassing the buffer. */
buf_flush (s);
- if (nbyte <= BUFFER_SIZE/2)
+ if (nbyte <= s->buffer_size/2)
{
memcpy (s->buffer, buf, nbyte);
s->buffer_offset = s->logical_offset;
@@ -688,7 +690,7 @@ buf_write (unix_stream *s, const void *buf, ssize_t nbyte)
static int
buf_markeor (unix_stream *s)
{
- if (s->unbuffered || s->ndirty >= BUFFER_SIZE / 2)
+ if (s->unbuffered || s->ndirty >= s->buffer_size / 2)
return buf_flush (s);
return 0;
}
@@ -765,11 +767,32 @@ static const struct stream_vtable buf_vtable = {
};
static int
-buf_init (unix_stream *s)
+buf_init (unix_stream *s, bool unformatted)
{
s->st.vptr = &buf_vtable;
- s->buffer = xmalloc (BUFFER_SIZE);
+ /* Try to guess a good value for the buffer size. For formatted
+ I/O, we use so many CPU cycles converting the data that there is
+ more sense in converving memory and especially cache. For
+ unformatted, a bigger block can have a large impact in some
+ environments. */
+
+ if (unformatted)
+ {
+ if (options.unformatted_buffer_size > 0)
+ s->buffer_size = options.unformatted_buffer_size;
+ else
+ s->buffer_size = UNFORMATTED_BUFFER_SIZE_DEFAULT;
+ }
+ else
+ {
+ if (options.formatted_buffer_size > 0)
+ s->buffer_size = options.formatted_buffer_size;
+ else
+ s->buffer_size = FORMATTED_BUFFER_SIZE_DEFAULT;
+ }
+
+ s->buffer = xmalloc (s->buffer_size);
return 0;
}
@@ -1120,13 +1143,13 @@ fd_to_stream (int fd, bool unformatted)
(s->fd == STDIN_FILENO
|| s->fd == STDOUT_FILENO
|| s->fd == STDERR_FILENO)))
- buf_init (s);
+ buf_init (s, unformatted);
else
{
if (unformatted)
{
s->unbuffered = true;
- buf_init (s);
+ buf_init (s, unformatted);
}
else
raw_init (s);
diff --git a/libgfortran/libgfortran.h b/libgfortran/libgfortran.h
index 433b204..c0db96f 100644
--- a/libgfortran/libgfortran.h
+++ b/libgfortran/libgfortran.h
@@ -540,6 +540,7 @@ typedef struct
int all_unbuffered, unbuffered_preconnected;
int fpe, backtrace;
+ int unformatted_buffer_size, formatted_buffer_size;
}
options_t;
diff --git a/libgfortran/runtime/environ.c b/libgfortran/runtime/environ.c
index e3e7d24..5817d19 100644
--- a/libgfortran/runtime/environ.c
+++ b/libgfortran/runtime/environ.c
@@ -198,6 +198,14 @@ static variable variable_table[] = {
/* Print out a backtrace if possible on runtime error */
{ "GFORTRAN_ERROR_BACKTRACE", -1, &options.backtrace, init_boolean },
+ /* Buffer size for unformatted files. */
+ { "GFORTRAN_UNFORMATTED_BUFFER_SIZE", 0, &options.unformatted_buffer_size,
+ init_integer },
+
+ /* Buffer size for formatted files. */
+ { "GFORTRAN_FORMATTED_BUFFER_SIZE", 0, &options.formatted_buffer_size,
+ init_integer },
+
{ NULL, 0, NULL, NULL }
};