diff options
author | Thomas Koenig <tkoenig@gcc.gnu.org> | 2019-07-21 15:55:49 +0000 |
---|---|---|
committer | Thomas Koenig <tkoenig@gcc.gnu.org> | 2019-07-21 15:55:49 +0000 |
commit | c37b0163fe5307ab508489926114de9cf7e240c1 (patch) | |
tree | 205699e71034f0bc8b7603c02225124f390c4073 /libgfortran | |
parent | 037455d49c2c19521bf60253c098d0e1e48d68fa (diff) | |
download | gcc-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/ChangeLog | 18 | ||||
-rw-r--r-- | libgfortran/io/unix.c | 47 | ||||
-rw-r--r-- | libgfortran/libgfortran.h | 1 | ||||
-rw-r--r-- | libgfortran/runtime/environ.c | 8 |
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 } }; |