From: Janne Blomqvist Date: Mon, 29 Apr 2013 08:42:00 +0000 (+0300) Subject: PR 56981 Improve unbuffered performance on special files. X-Git-Tag: releases/gcc-4.9.0~6159 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c033f5ae3270e34c40c7ef9e7168b9884e39b75a;p=thirdparty%2Fgcc.git PR 56981 Improve unbuffered performance on special files. 2013-04-29 Janne Blomqvist PR fortran/56981 * io/transfer.c (next_record_w_unf): First fix head marker, then write tail. (next_record): Call flush_if_unbuffered. * io/unix.c (struct unix_stream): Add field unbuffered. (flush_if_unbuffered): New function. (fd_to_stream): New argument. (open_external): Fix fd_to_stream call. (input_stream): Likewise. (output_stream): Likewise. (error_stream): Likewise. * io/unix.h (flush_if_unbuffered): New prototype. From-SVN: r198390 --- diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog index 3f2e9d1c7c74..b7d6fe1152ed 100644 --- a/libgfortran/ChangeLog +++ b/libgfortran/ChangeLog @@ -1,3 +1,18 @@ +2013-04-29 Janne Blomqvist + + PR fortran/56981 + * io/transfer.c (next_record_w_unf): First fix head marker, then + write tail. + (next_record): Call flush_if_unbuffered. + * io/unix.c (struct unix_stream): Add field unbuffered. + (flush_if_unbuffered): New function. + (fd_to_stream): New argument. + (open_external): Fix fd_to_stream call. + (input_stream): Likewise. + (output_stream): Likewise. + (error_stream): Likewise. + * io/unix.h (flush_if_unbuffered): New prototype. + 2013-04-28 Janne Blomqvist * intrinsics/system_clock.c (system_clock_4): Fix sign error in diff --git a/libgfortran/io/transfer.c b/libgfortran/io/transfer.c index bb93009f59fe..52b1da6330a5 100644 --- a/libgfortran/io/transfer.c +++ b/libgfortran/io/transfer.c @@ -3207,17 +3207,6 @@ next_record_w_unf (st_parameter_dt *dtp, int next_subrecord) m = dtp->u.p.current_unit->recl_subrecord - dtp->u.p.current_unit->bytes_left_subrecord; - /* Write the length tail. If we finish a record containing - subrecords, we write out the negative length. */ - - if (dtp->u.p.current_unit->continued) - m_write = -m; - else - m_write = m; - - if (unlikely (write_us_marker (dtp, m_write) < 0)) - goto io_error; - if (compile_options.record_marker == 0) record_marker = sizeof (GFC_INTEGER_4); else @@ -3226,7 +3215,7 @@ next_record_w_unf (st_parameter_dt *dtp, int next_subrecord) /* Seek to the head and overwrite the bogus length with the real length. */ - if (unlikely (sseek (dtp->u.p.current_unit->s, - m - 2 * record_marker, + if (unlikely (sseek (dtp->u.p.current_unit->s, - m - record_marker, SEEK_CUR) < 0)) goto io_error; @@ -3240,8 +3229,18 @@ next_record_w_unf (st_parameter_dt *dtp, int next_subrecord) /* Seek past the end of the current record. */ - if (unlikely (sseek (dtp->u.p.current_unit->s, m + record_marker, - SEEK_CUR) < 0)) + if (unlikely (sseek (dtp->u.p.current_unit->s, m, SEEK_CUR) < 0)) + goto io_error; + + /* Write the length tail. If we finish a record containing + subrecords, we write out the negative length. */ + + if (dtp->u.p.current_unit->continued) + m_write = -m; + else + m_write = m; + + if (unlikely (write_us_marker (dtp, m_write) < 0)) goto io_error; return; @@ -3503,6 +3502,7 @@ next_record (st_parameter_dt *dtp, int done) pre_position (dtp); fbuf_flush (dtp->u.p.current_unit, dtp->u.p.mode); + flush_if_unbuffered (dtp->u.p.current_unit->s); } diff --git a/libgfortran/io/unix.c b/libgfortran/io/unix.c index 8b9d7a773425..08fe4fe5212e 100644 --- a/libgfortran/io/unix.c +++ b/libgfortran/io/unix.c @@ -212,6 +212,8 @@ typedef struct /* Cached stat(2) values. */ dev_t st_dev; ino_t st_ino; + + bool unbuffered; /* Buffer should be flushed after each I/O statement. */ } unix_stream; @@ -442,7 +444,7 @@ raw_init (unix_stream * s) Buffered I/O functions. These functions have the same semantics as the raw I/O functions above, except that they are buffered in order to improve performance. The buffer must be flushed when switching from -reading to writing and vice versa. Only supported for regular files. +reading to writing and vice versa. *********************************************************************/ static int @@ -968,11 +970,26 @@ open_internal4 (char *base, int length, gfc_offset offset) } +/* "Unbuffered" really means I/O statement buffering. For formatted + I/O, the fbuf manages this, and then uses raw I/O. For unformatted + I/O, buffered I/O is used, and the buffer is flushed at the end of + each I/O statement, where this function is called. */ + +int +flush_if_unbuffered (stream* s) +{ + unix_stream* us = (unix_stream*) s; + if (us->unbuffered) + return sflush (s); + return 0; +} + + /* fd_to_stream()-- Given an open file descriptor, build a stream * around it. */ static stream * -fd_to_stream (int fd) +fd_to_stream (int fd, bool unformatted) { struct stat statbuf; unix_stream *s; @@ -998,7 +1015,15 @@ fd_to_stream (int fd) || s->fd == STDERR_FILENO))) buf_init (s); else - raw_init (s); + { + if (unformatted) + { + s->unbuffered = true; + buf_init (s); + } + else + raw_init (s); + } return (stream *) s; } @@ -1364,7 +1389,7 @@ open_external (st_parameter_open *opp, unit_flags *flags) return NULL; fd = fix_fd (fd); - return fd_to_stream (fd); + return fd_to_stream (fd, flags->form == FORM_UNFORMATTED); } @@ -1374,7 +1399,7 @@ open_external (st_parameter_open *opp, unit_flags *flags) stream * input_stream (void) { - return fd_to_stream (STDIN_FILENO); + return fd_to_stream (STDIN_FILENO, false); } @@ -1390,7 +1415,7 @@ output_stream (void) setmode (STDOUT_FILENO, O_BINARY); #endif - s = fd_to_stream (STDOUT_FILENO); + s = fd_to_stream (STDOUT_FILENO, false); return s; } @@ -1407,7 +1432,7 @@ error_stream (void) setmode (STDERR_FILENO, O_BINARY); #endif - s = fd_to_stream (STDERR_FILENO); + s = fd_to_stream (STDERR_FILENO, false); return s; } diff --git a/libgfortran/io/unix.h b/libgfortran/io/unix.h index bf59a8ee1fcd..cc82d4573977 100644 --- a/libgfortran/io/unix.h +++ b/libgfortran/io/unix.h @@ -167,6 +167,9 @@ internal_proto(inquire_readwrite); extern void flush_if_preconnected (stream *); internal_proto(flush_if_preconnected); +extern int flush_if_unbuffered (stream*); +internal_proto(flush_if_unbuffered); + extern int stream_isatty (stream *); internal_proto(stream_isatty);