unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
* the page size bug
@ 2017-03-08 20:42 Andy Wingo
  2017-03-08 21:32 ` Mike Gran
  0 siblings, 1 reply; 3+ messages in thread
From: Andy Wingo @ 2017-03-08 20:42 UTC (permalink / raw)
  To: guile-devel

Hi,

Guile 2.2 uses ELF to format its object files.  ELF objects are composed
of *sections* and *segments*.  Sections are things like .data, .strtab,
and so on; segments contain sections with similar permissions
(read-only, read-write, etc).  See
https://www.gnu.org/software/guile/docs/master/guile.html/Object-File-Format.html
for more details.

Parts of different sections refer to each other.  For example the
read-only .rtl-text code section refers to mutable values in the .data
section, by relative offset.  It's the linker's job to make all of these
connections, and the loader's job to ensure they are valid when the file
is loaded.

The loader has two paths: an mmap path and a malloc path.  The malloc
path just slurps the file into memory; the relative references in the
file correspond to relative references in memory.  With the malloc path,
everything is mutable from the operating system's point of view.

The problem with the malloc path is that not only is it a bit slower, as
it has to page in data that might not be needed, it doesn't share memory
between processes.  So if the system supports mmap, Guile will use mmap
to load its ELF images (.go files).

The mmap path likewise just mmaps the file into memory.  The operating
system will lazily page in data from disk as needed.  Writable segments
ends up being process-local, but read-only segments can share memory
between different processes.  This lowers Guile's resident memory
footprint, especially when many Guile processes are live.

What ends up happening in the mmap case is that the whole file is mapped
into memory, then the writable segments are made writable via
mprotect().  This only works if the writable segments are page-aligned.

And with that prelude out of the way, here's the bug: Guile currently
assumes that 4096 is a multiple of the page size.  So the mprotect fails
to make the segment writable, and runtime relocations that mutate the
segment cause segmentation faults.

One solution to this issue would be to choose target-specific page
sizes.  This is still a little tricky; on amd64 for example, systems
commonly have 4KB pages, but they are allowed by the ABI to have any
multiple-of-2 page size up to 64 KB.  On Cygwin, pages are 4kB but they
can only be allocated 16 at a time.  MIPS and ARM64 can use 64K pages
too and that's not uncommon.

At the current time, in Guile we would like to reduce the number of
binaries we ship to the existing 32-or-64-bit and big-or-little-endian
variants, if possible.  It would seem that with the
least-common-multiple of 64 KB pages, we can do that.

See https://github.com/golang/go/issues/10180 for a discussion of this
issue in the Go context.

So my proposal is to increase the page size to which we align our
segments to 64KB.  This will increase the size of our .go files, but not
the prebuilt/ part of the tarball as that part of the file will be
zeroes and compress well.  Additionally on a system with 4KB pages, the
extra padding will never be paged in, nor read from disk (though it
causes more seeking etc so on spinning metal it's a bit of a lose).

On many 64-bit platforms, binutils currently defaults to aligning
segments on 2MB boundaries.  It does so by making the file and the
memory images not the same: the pages are all together on disk, but then
when loading, the loader will mmap a region "memsz" large which might be
greater than the file size, then map segments into that region.  I would
like to avoid this complication for now.  We can consider adding it in
the future in a compatible way in 2.2 if it is important.

Thoughts welcome :)  I am going to give this a go now.

Andy



^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: the page size bug
  2017-03-08 20:42 the page size bug Andy Wingo
@ 2017-03-08 21:32 ` Mike Gran
  2017-03-08 21:58   ` Andy Wingo
  0 siblings, 1 reply; 3+ messages in thread
From: Mike Gran @ 2017-03-08 21:32 UTC (permalink / raw)
  To: Andy Wingo, guile-devel@gnu.org




On Wednesday, March 8, 2017 12:42 PM, Andy Wingo <wingo@pobox.com> wrote:
Hi,

> The problem with the malloc path is that not only is it a bit slower, as
> it has to page in data that might not be needed, it doesn't share memory
> between processes.  So if the system supports mmap, Guile will use mmap
> to load its ELF images (.go files).


In trying to get Guile to work on Cygwin, I've reverted to the
malloc path by #undef'ing HAVE_SYS_MMAN_H.  The mmap path is broken,
as you note.

> One solution to this issue would be to choose target-specific page
> sizes.  This is still a little tricky; on amd64 for example, systems
> commonly have 4KB pages, but they are allowed by the ABI to have any
> multiple-of-2 page size up to 64 KB.  On Cygwin, pages are 4kB but they
> can only be allocated 16 at a time.  MIPS and ARM64 can use 64K pages
> too and that's not uncommon.


Cygwin wants its users to not second-guess the 64k pagesize it
provides as its interface.  It sees the 16x 4k pagesize as an internal
detail that it is trying to abstract away.


Regards,
Mike Gran



^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: the page size bug
  2017-03-08 21:32 ` Mike Gran
@ 2017-03-08 21:58   ` Andy Wingo
  0 siblings, 0 replies; 3+ messages in thread
From: Andy Wingo @ 2017-03-08 21:58 UTC (permalink / raw)
  To: Mike Gran; +Cc: guile-devel@gnu.org

On Wed 08 Mar 2017 22:32, Mike Gran <spk121@yahoo.com> writes:

> On Wednesday, March 8, 2017 12:42 PM, Andy Wingo <wingo@pobox.com> wrote:
> Hi,
>
>> The problem with the malloc path is that not only is it a bit slower, as
>> it has to page in data that might not be needed, it doesn't share memory
>> between processes.  So if the system supports mmap, Guile will use mmap
>> to load its ELF images (.go files).
>
> In trying to get Guile to work on Cygwin, I've reverted to the
> malloc path by #undef'ing HAVE_SYS_MMAN_H.  The mmap path is broken,
> as you note.
>
>> One solution to this issue would be to choose target-specific page
>> sizes.  This is still a little tricky; on amd64 for example, systems
>> commonly have 4KB pages, but they are allowed by the ABI to have any
>> multiple-of-2 page size up to 64 KB.  On Cygwin, pages are 4kB but they
>> can only be allocated 16 at a time.  MIPS and ARM64 can use 64K pages
>> too and that's not uncommon.
>
> Cygwin wants its users to not second-guess the 64k pagesize it
> provides as its interface.  It sees the 16x 4k pagesize as an internal
> detail that it is trying to abstract away.

Thanks for the notes.  With the patch I just pushed to change to 64 KB
segment alignment I hope cygwin is fixed (among other targets).
If you are able to try again, great; otherwise we can test tomorrow's
tarball.

Cheers,

Andy



^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2017-03-08 21:58 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-03-08 20:42 the page size bug Andy Wingo
2017-03-08 21:32 ` Mike Gran
2017-03-08 21:58   ` Andy Wingo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).