From patchwork Mon Feb 13 18:20:04 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Janne Blomqvist X-Patchwork-Id: 140956 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id C0F521007D2 for ; Tue, 14 Feb 2012 05:20:33 +1100 (EST) Comment: DKIM? See http://www.dkim.org DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d=gcc.gnu.org; s=default; x=1329762034; h=Comment: DomainKey-Signature:Received:Received:Received:Received: MIME-Version:Received:Received:Date:Message-ID:Subject:From:To: Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe: List-Archive:List-Post:List-Help:Sender:Delivered-To; bh=yzvg+SZ CFxINmOkX8NPB4dSL7Zc=; b=XhbEbk/NGsWUqYvYEIKqSrsVaVBMj9eiv/q5pFj 0/j0uBfliL7pb+awnPNNPbex+OMvxvMrdbS/ca7Sa0TgPfS4G6527Qx4bMZn5M4w /B9ZTUcBpuKHHHwGS77tHdN5Gt9JZnyQEtUifFwttzNuvm2ncrbpJKcTakDKSAoc DVak= Comment: DomainKeys? See http://antispam.yahoo.com/domainkeys DomainKey-Signature: a=rsa-sha1; q=dns; c=nofws; s=default; d=gcc.gnu.org; h=Received:Received:X-SWARE-Spam-Status:X-Spam-Check-By:Received:Received:MIME-Version:Received:Received:Date:Message-ID:Subject:From:To:Content-Type:Mailing-List:Precedence:List-Id:List-Unsubscribe:List-Archive:List-Post:List-Help:Sender:Delivered-To; b=JjOQJ2asQNDLAfP88CQU8iRbDhj2Du/X21TXMAymKDDpeYqcetKtOOjO0P9sO7 S03CcaBhM3l/2xQYhgDzUTZfifd5uFyAbEinqA1u5Ch7yifOONFC19LHXTjV4PQ8 hsO6doPiSjLbXASqL0TpHMS/QFoUfJMR3o7M04pQlJf74=; Received: (qmail 19087 invoked by alias); 13 Feb 2012 18:20:26 -0000 Received: (qmail 19066 invoked by uid 22791); 13 Feb 2012 18:20:24 -0000 X-SWARE-Spam-Status: No, hits=-2.0 required=5.0 tests=AWL, BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, FREEMAIL_FROM, RCVD_IN_DNSWL_NONE, TW_BG X-Spam-Check-By: sourceware.org Received: from mail-lpp01m020-f175.google.com (HELO mail-lpp01m020-f175.google.com) (209.85.217.175) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 13 Feb 2012 18:20:07 +0000 Received: by lbol12 with SMTP id l12so2784218lbo.20 for ; Mon, 13 Feb 2012 10:20:05 -0800 (PST) MIME-Version: 1.0 Received: by 10.112.88.10 with SMTP id bc10mr6132752lbb.60.1329157204332; Mon, 13 Feb 2012 10:20:04 -0800 (PST) Received: by 10.152.29.132 with HTTP; Mon, 13 Feb 2012 10:20:04 -0800 (PST) Date: Mon, 13 Feb 2012 20:20:04 +0200 Message-ID: Subject: [Patch, libfortran] RFC: Shared vtables, constification From: Janne Blomqvist To: Fortran List , GCC Patches Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Hi, the attached patch changes the low-level libgfortran IO dispatching mechanism to use shared vtables for each stream type, instead of all the function pointers being replicated for each unit. This is similar to e.g. how the C++ frontend implements vtables. The benefits are: - Slightly smaller heap memory overhead for each unit as only the vtable pointer needs to be stored, and slightly faster unit initialization as only the vtable pointer needs to be setup instead of all the function pointers in the stream struct. - Looking at unix.o with readelf, one sees Relocation section '.rela.data.rel.ro.local.mem_vtable' at offset 0x15550 contains 8 entries: and similarly for the other vtables; according to http://www.airs.com/blog/archives/189 this means that after relocation the page where this data resides may be marked read-only. The downside is that the sizes of the .text and .data sections are increased. Before: text data bss dec hex filename 1116991 6664 592 1124247 112797 ./x86_64-unknown-linux-gnu/libgfortran/.libs/libgfortran.so After: text data bss dec hex filename 1117487 6936 592 1125015 112a97 ./x86_64-unknown-linux-gnu/libgfortran/.libs/libgfortran.so The data section increase is due to the vtables, the text increase is, I guess, due to the extra pointer dereference when calling the IO functions. Regtested on x86_64-unknown-linux-gnu, Ok for trunk, or 4.8? 2012-02-13 Janne Blomqvist * io/unix.h (struct stream): Rename to stream_vtable. (struct stream): New struct definition. (sread): Dereference vtable pointer. (swrite): Likewise. (sseek): Likewise. (struncate): Likewise. (sflush): Likewise. (sclose): Likewise. * io/unix.c (raw_vtable): New variable. (buf_vtable): Likewise. (mem_vtable): Likewise. (mem4_vtable): Likewise. (raw_init): Assign vtable pointer. (buf_init): Likewise. (open_internal): Likewise. (open_internal4): Likewise. diff --git a/libgfortran/io/unix.c b/libgfortran/io/unix.c index 6eef3f9..978c3ff 100644 --- a/libgfortran/io/unix.c +++ b/libgfortran/io/unix.c @@ -401,17 +401,21 @@ raw_close (unix_stream * s) return retval; } +static const struct stream_vtable raw_vtable = { + .read = (void *) raw_read, + .write = (void *) raw_write, + .seek = (void *) raw_seek, + .tell = (void *) raw_tell, + .size = (void *) raw_size, + .trunc = (void *) raw_truncate, + .close = (void *) raw_close, + .flush = (void *) raw_flush +}; + static int raw_init (unix_stream * s) { - s->st.read = (void *) raw_read; - s->st.write = (void *) raw_write; - s->st.seek = (void *) raw_seek; - s->st.tell = (void *) raw_tell; - s->st.size = (void *) raw_size; - s->st.trunc = (void *) raw_truncate; - s->st.close = (void *) raw_close; - s->st.flush = (void *) raw_flush; + s->st.vptr = &raw_vtable; s->buffer = NULL; return 0; @@ -619,17 +623,21 @@ buf_close (unix_stream * s) return raw_close (s); } +static const struct stream_vtable buf_vtable = { + .read = (void *) buf_read, + .write = (void *) buf_write, + .seek = (void *) buf_seek, + .tell = (void *) buf_tell, + .size = (void *) buf_size, + .trunc = (void *) buf_truncate, + .close = (void *) buf_close, + .flush = (void *) buf_flush +}; + static int buf_init (unix_stream * s) { - s->st.read = (void *) buf_read; - s->st.write = (void *) buf_write; - s->st.seek = (void *) buf_seek; - s->st.tell = (void *) buf_tell; - s->st.size = (void *) buf_size; - s->st.trunc = (void *) buf_truncate; - s->st.close = (void *) buf_close; - s->st.flush = (void *) buf_flush; + s->st.vptr = &buf_vtable; s->buffer = get_mem (BUFFER_SIZE); return 0; @@ -872,6 +880,31 @@ mem_close (unix_stream * s) return 0; } +static const struct stream_vtable mem_vtable = { + .read = (void *) mem_read, + .write = (void *) mem_write, + .seek = (void *) mem_seek, + .tell = (void *) mem_tell, + /* buf_size is not a typo, we just reuse an identical + implementation. */ + .size = (void *) buf_size, + .trunc = (void *) mem_truncate, + .close = (void *) mem_close, + .flush = (void *) mem_flush +}; + +static const struct stream_vtable mem4_vtable = { + .read = (void *) mem_read4, + .write = (void *) mem_write4, + .seek = (void *) mem_seek, + .tell = (void *) mem_tell, + /* buf_size is not a typo, we just reuse an identical + implementation. */ + .size = (void *) buf_size, + .trunc = (void *) mem_truncate, + .close = (void *) mem_close, + .flush = (void *) mem_flush +}; /********************************************************************* Public functions -- A reimplementation of this module needs to @@ -895,16 +928,7 @@ open_internal (char *base, int length, gfc_offset offset) s->logical_offset = 0; s->active = s->file_length = length; - s->st.close = (void *) mem_close; - s->st.seek = (void *) mem_seek; - s->st.tell = (void *) mem_tell; - /* buf_size is not a typo, we just reuse an identical - implementation. */ - s->st.size = (void *) buf_size; - s->st.trunc = (void *) mem_truncate; - s->st.read = (void *) mem_read; - s->st.write = (void *) mem_write; - s->st.flush = (void *) mem_flush; + s->st.vptr = &mem_vtable; return (stream *) s; } @@ -926,16 +950,7 @@ open_internal4 (char *base, int length, gfc_offset offset) s->logical_offset = 0; s->active = s->file_length = length; - s->st.close = (void *) mem_close; - s->st.seek = (void *) mem_seek; - s->st.tell = (void *) mem_tell; - /* buf_size is not a typo, we just reuse an identical - implementation. */ - s->st.size = (void *) buf_size; - s->st.trunc = (void *) mem_truncate; - s->st.read = (void *) mem_read4; - s->st.write = (void *) mem_write4; - s->st.flush = (void *) mem_flush; + s->st.vptr = &mem4_vtable; return (stream *) s; } diff --git a/libgfortran/io/unix.h b/libgfortran/io/unix.h index 52f3e0c..f4f3ab6 100644 --- a/libgfortran/io/unix.h +++ b/libgfortran/io/unix.h @@ -28,68 +28,71 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see #include "io.h" - -struct stream +struct stream_vtable { - ssize_t (*read) (struct stream *, void *, ssize_t); - ssize_t (*write) (struct stream *, const void *, ssize_t); - gfc_offset (*seek) (struct stream *, gfc_offset, int); - gfc_offset (*tell) (struct stream *); - gfc_offset (*size) (struct stream *); + ssize_t (* const read) (struct stream *, void *, ssize_t); + ssize_t (* const write) (struct stream *, const void *, ssize_t); + gfc_offset (* const seek) (struct stream *, gfc_offset, int); + gfc_offset (* const tell) (struct stream *); + gfc_offset (* const size) (struct stream *); /* Avoid keyword truncate due to AIX namespace collision. */ - int (*trunc) (struct stream *, gfc_offset); - int (*flush) (struct stream *); - int (*close) (struct stream *); + int (* const trunc) (struct stream *, gfc_offset); + int (* const flush) (struct stream *); + int (* const close) (struct stream *); }; +struct stream +{ + const struct stream_vtable *vptr; +}; /* Inline functions for doing file I/O given a stream. */ static inline ssize_t sread (stream * s, void * buf, ssize_t nbyte) { - return s->read (s, buf, nbyte); + return s->vptr->read (s, buf, nbyte); } static inline ssize_t swrite (stream * s, const void * buf, ssize_t nbyte) { - return s->write (s, buf, nbyte); + return s->vptr->write (s, buf, nbyte); } static inline gfc_offset sseek (stream * s, gfc_offset offset, int whence) { - return s->seek (s, offset, whence); + return s->vptr->seek (s, offset, whence); } static inline gfc_offset stell (stream * s) { - return s->tell (s); + return s->vptr->tell (s); } static inline gfc_offset ssize (stream * s) { - return s->size (s); + return s->vptr->size (s); } static inline int struncate (stream * s, gfc_offset length) { - return s->trunc (s, length); + return s->vptr->trunc (s, length); } static inline int sflush (stream * s) { - return s->flush (s); + return s->vptr->flush (s); } static inline int sclose (stream * s) { - return s->close (s); + return s->vptr->close (s); }