the page size bug

2017-03-08 Thread Andy Wingo
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



Re: the page size bug

2017-03-08 Thread Andy Wingo
On Wed 08 Mar 2017 22:32, Mike Gran  writes:

> On Wednesday, March 8, 2017 12:42 PM, Andy Wingo  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



Re: The status of JIT compiler of Guile

2017-03-08 Thread Nala Ginrut
Hi Andy!
Sorry for late replay, it seems I've filtered your mail to another TAG
in my mailbox.


On Thu, Mar 2, 2017 at 4:31 PM, Andy Wingo  wrote:
> Heya Nala :-)
>
> And hello Atsuro!  I don't think I have had the chance of expressing to
> you how impressive your work is.  Awesome stuff!!!
>
> What do you all think is the way forward for this work?  Is it something
> that you see being integrated eventually into Guile git?  Is it a
> project that should be maintained separately?  If the latter, what
> interfaces do you need from Guile?

I'm not going to fork Guile and maintain it separately.
What I concern is if the current design is suitable to integrate
directly. And the origianl
repo can't be compiled in my machine. So I'm trying to rebase with the
latest master and
research Atsuro's paper. The point is that after ICFP meeting, no one
have tried it successfully.
Then I choose to fix it to work.

I've discussed with @Ludo, I think it's better to integrate it as a
plugin, and could be maintained separately.
It is possible to have some hooks in Guile VM to enable certain
optimizing, but I don't think we have it now, right?

it's just my idea. It's possible to integrate it directly, since it's
working with the latest Guile smoothly.
But there maybe some trivial issues need to be tweaked.

Another pointer I have to mention is that I'm not sure if the tracing
JIT concerned delimited-continuation capturing properly.
This is one of the questions on the meeting, and Atsuro said he has no
idea about that issue. That's another reason I prefer
to do some research before any conclusion or patches.

What do you think?
Are you can't wait to integrate it at once? Or make more flexible
things in Guile VM to hold pluginable optimizing sutffs?
For me, it's fine, after all, I use it everyday now. ;-P


> I think this test is a bignum/allocation test, not a compiler test.
> Still, good to see some results.

Yes it is, I just want to show something. Unfortunately, I'm not good
at benchmark. ;-)

> Andy