[PATCH, libgfortran] PR 56981 Flush buffer at record boundaries
Janne Blomqvist
blomqvist.janne@gmail.com
Tue May 27 20:50:00 GMT 2014
Hi,
the attached patch implements the idea in
https://gcc.gnu.org/ml/fortran/2013-04/msg00258.html ; though it
turned out it was much simpler than what I envisaged back then. With
this patch, we no longer seek back and forth when writing small
records with sequential unformatted, which previously happened due to
the buffer filling up when not on record boundaries.
Performance-wise, I didn't really see any difference on Linux/tmpfs,
but maybe it makes a difference in other circumstances. And of course,
as a side-effect, it makes sequential unformatted work on unseekable
devices such as pipes as long as the records are small, although I'm
not sure this is something we want to advertise to users.
Regtested on x86_64-unknown-linux-gnu, Ok for trunk?
2014-05-27 Janne Blomqvist <jb@gcc.gnu.org>
PR libfortran/56981
* io/unix.h (struct stream_vtable): Add new member function,
markeor.
(smarkeor): New inline function.
(flush_if_unbuffered): Remove prototype.
* io/unix.c (raw_markeor): New function.
(raw_vtable): Initialize markeor member.
(buf_markeor): New function.
(buf_vtable): Initialize markeor member.
(mem_vtable): Likewise.
(mem4_vtable): Likewise.
(flush_if_unbuffered): Remove function.
* io/transfer.c (next_record): Call smarkeor instead of
flush_if_unbuffered.
--
Janne Blomqvist
-------------- next part --------------
diff --git a/libgfortran/io/transfer.c b/libgfortran/io/transfer.c
index cfe92ca..cc0132c8 100644
--- a/libgfortran/io/transfer.c
+++ b/libgfortran/io/transfer.c
@@ -3512,7 +3512,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);
+ smarkeor (dtp->u.p.current_unit->s);
}
diff --git a/libgfortran/io/unix.c b/libgfortran/io/unix.c
index 3721b71..c9866d3 100644
--- a/libgfortran/io/unix.c
+++ b/libgfortran/io/unix.c
@@ -421,6 +421,12 @@ raw_close (unix_stream * s)
return retval;
}
+static int
+raw_markeor (unix_stream * s __attribute__ ((unused)))
+{
+ return 0;
+}
+
static const struct stream_vtable raw_vtable = {
.read = (void *) raw_read,
.write = (void *) raw_write,
@@ -429,7 +435,8 @@ static const struct stream_vtable raw_vtable = {
.size = (void *) raw_size,
.trunc = (void *) raw_truncate,
.close = (void *) raw_close,
- .flush = (void *) raw_flush
+ .flush = (void *) raw_flush,
+ .markeor = (void *) raw_markeor
};
static int
@@ -584,6 +591,23 @@ buf_write (unix_stream * s, const void * buf, ssize_t nbyte)
return nbyte;
}
+
+/* "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. Alternatively,
+ the buffer is flushed at the end of the record if the buffer is
+ more than half full; this prevents needless seeking back and forth
+ when writing sequential unformatted. */
+
+static int
+buf_markeor (unix_stream * s)
+{
+ if (s->unbuffered || s->ndirty >= BUFFER_SIZE / 2)
+ return buf_flush (s);
+ return 0;
+}
+
static gfc_offset
buf_seek (unix_stream * s, gfc_offset offset, int whence)
{
@@ -651,7 +675,8 @@ static const struct stream_vtable buf_vtable = {
.size = (void *) buf_size,
.trunc = (void *) buf_truncate,
.close = (void *) buf_close,
- .flush = (void *) buf_flush
+ .flush = (void *) buf_flush,
+ .markeor = (void *) buf_markeor
};
static int
@@ -910,7 +935,8 @@ static const struct stream_vtable mem_vtable = {
.size = (void *) buf_size,
.trunc = (void *) mem_truncate,
.close = (void *) mem_close,
- .flush = (void *) mem_flush
+ .flush = (void *) mem_flush,
+ .markeor = (void *) raw_markeor
};
static const struct stream_vtable mem4_vtable = {
@@ -923,7 +949,8 @@ static const struct stream_vtable mem4_vtable = {
.size = (void *) buf_size,
.trunc = (void *) mem_truncate,
.close = (void *) mem_close,
- .flush = (void *) mem_flush
+ .flush = (void *) mem_flush,
+ .markeor = (void *) raw_markeor
};
/*********************************************************************
@@ -972,21 +999,6 @@ 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. */
diff --git a/libgfortran/io/unix.h b/libgfortran/io/unix.h
index 910f2c2..0f696df 100644
--- a/libgfortran/io/unix.h
+++ b/libgfortran/io/unix.h
@@ -38,6 +38,7 @@ struct stream_vtable
int (* const trunc) (struct stream *, gfc_offset);
int (* const flush) (struct stream *);
int (* const close) (struct stream *);
+ int (* const markeor) (struct stream *);
};
struct stream
@@ -94,6 +95,12 @@ sclose (stream * s)
return s->vptr->close (s);
}
+static inline int
+smarkeor (stream * s)
+{
+ return s->vptr->markeor (s);
+}
+
extern int compare_files (stream *, stream *);
internal_proto(compare_files);
@@ -167,9 +174,6 @@ 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);
More information about the Gcc-patches
mailing list