1. Pypy
  2. Untitled project
  3. pypy

Commits

Brian Kearns  committed 61c0f89

Backed out changeset 992e29624c5f

  • Participants
  • Parent commits f28b866
  • Branches default

Comments (0)

Files changed (2)

File rpython/rlib/rmmap.py

View file
     # constants, look in sys/mman.h and platform docs for the meaning
     # some constants are linux only so they will be correctly exposed outside
     # depending on the OS
-    constant_names = ['MAP_SHARED', 'MAP_PRIVATE', 'MAP_FIXED',
+    constant_names = ['MAP_SHARED', 'MAP_PRIVATE',
                       'PROT_READ', 'PROT_WRITE',
                       'MS_SYNC']
     opt_constant_names = ['MAP_ANON', 'MAP_ANONYMOUS', 'MAP_NORESERVE',
         return m
 
     def alloc_hinted(hintp, map_size):
-        flags = NonConstant(MAP_PRIVATE | MAP_ANONYMOUS)
-        prot = NonConstant(PROT_EXEC | PROT_READ | PROT_WRITE)
+        flags = MAP_PRIVATE | MAP_ANONYMOUS
+        prot = PROT_EXEC | PROT_READ | PROT_WRITE
         return c_mmap_safe(hintp, map_size, prot, flags, -1, 0)
 
-    def clear_large_memory_chunk_aligned(addr, map_size):
-        addr = rffi.cast(PTR, addr)
-        flags = NonConstant(MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS)
-        prot = NonConstant(PROT_READ | PROT_WRITE)
-        res = c_mmap_safe(addr, map_size, prot, flags, -1, 0)
-        return res == addr
-
     # XXX is this really necessary?
     class Hint:
         pos = -0x4fff0000   # for reproducible results

File rpython/rtyper/lltypesystem/llarena.py

View file
 
 MEMORY_ALIGNMENT = memory_alignment()
 
-if os.name == 'posix':
-    # The general Posix solution to clear a large range of memory that
-    # was obtained with mmap() is to call mmap() again with MAP_FIXED.
+if sys.platform.startswith('linux'):
+    # This only works with linux's madvise(), which is really not a memory
+    # usage hint but a real command.  It guarantees that after MADV_DONTNEED
+    # the pages are cleared again.
 
-    legacy_getpagesize = rffi.llexternal('getpagesize', [], rffi.INT,
-                                         sandboxsafe=True, _nowrapper=True)
+    # Note that the trick of the general 'posix' section below, i.e.
+    # reading /dev/zero, does not seem to have the correct effect of
+    # lazily-allocating pages on all Linux systems.
 
-    class PosixPageSize:
+    from rpython.rtyper.tool import rffi_platform
+    from rpython.translator.tool.cbuild import ExternalCompilationInfo
+    _eci = ExternalCompilationInfo(includes=['sys/mman.h'])
+    MADV_DONTNEED = rffi_platform.getconstantinteger('MADV_DONTNEED',
+                                                     '#include <sys/mman.h>')
+    linux_madvise = rffi.llexternal('madvise',
+                                    [llmemory.Address, rffi.SIZE_T, rffi.INT],
+                                    rffi.INT,
+                                    sandboxsafe=True, _nowrapper=True,
+                                    compilation_info=_eci)
+    linux_getpagesize = rffi.llexternal('getpagesize', [], rffi.INT,
+                                        sandboxsafe=True, _nowrapper=True,
+                                        compilation_info=_eci)
+
+    class LinuxPageSize:
         def __init__(self):
             self.pagesize = 0
         def _cleanup_(self):
             self.pagesize = 0
-    posixpagesize = PosixPageSize()
+    linuxpagesize = LinuxPageSize()
 
     def clear_large_memory_chunk(baseaddr, size):
-        from rpython.rlib import rmmap
-
-        pagesize = posixpagesize.pagesize
+        pagesize = linuxpagesize.pagesize
         if pagesize == 0:
-            pagesize = rffi.cast(lltype.Signed, legacy_getpagesize())
-            posixpagesize.pagesize = pagesize
-
+            pagesize = rffi.cast(lltype.Signed, linux_getpagesize())
+            linuxpagesize.pagesize = pagesize
         if size > 2 * pagesize:
             lowbits = rffi.cast(lltype.Signed, baseaddr) & (pagesize - 1)
             if lowbits:     # clear the initial misaligned part, if any
                 baseaddr += partpage
                 size -= partpage
             length = size & -pagesize
-            if rmmap.clear_large_memory_chunk_aligned(baseaddr, length):
-                baseaddr += length     # clearing worked
+            madv_length = rffi.cast(rffi.SIZE_T, length)
+            madv_flags = rffi.cast(rffi.INT, MADV_DONTNEED)
+            err = linux_madvise(baseaddr, madv_length, madv_flags)
+            if rffi.cast(lltype.Signed, err) == 0:
+                baseaddr += length     # madvise() worked
                 size -= length
+        if size > 0:    # clear the final misaligned part, if any
+            llmemory.raw_memclear(baseaddr, size)
 
-        if size > 0:    # clear the final misaligned part, if any
+elif os.name == 'posix':
+    READ_MAX = (sys.maxint//4) + 1    # upper bound on reads to avoid surprises
+    raw_os_open = rffi.llexternal('open',
+                                  [rffi.CCHARP, rffi.INT, rffi.MODE_T],
+                                  rffi.INT,
+                                  sandboxsafe=True, _nowrapper=True)
+    raw_os_read = rffi.llexternal('read',
+                                  [rffi.INT, llmemory.Address, rffi.SIZE_T],
+                                  rffi.SIZE_T,
+                                  sandboxsafe=True, _nowrapper=True)
+    raw_os_close = rffi.llexternal('close',
+                                   [rffi.INT],
+                                   rffi.INT,
+                                   sandboxsafe=True, _nowrapper=True)
+    _dev_zero = rffi.str2charp('/dev/zero')   # prebuilt
+    lltype.render_immortal(_dev_zero)
+
+    def clear_large_memory_chunk(baseaddr, size):
+        # on some Unixy platforms, reading from /dev/zero is the fastest way
+        # to clear arenas, because the kernel knows that it doesn't
+        # need to even allocate the pages before they are used.
+
+        # NB.: careful, don't do anything that could malloc here!
+        # this code is called during GC initialization.
+        fd = raw_os_open(_dev_zero,
+                         rffi.cast(rffi.INT, os.O_RDONLY),
+                         rffi.cast(rffi.MODE_T, 0644))
+        if rffi.cast(lltype.Signed, fd) != -1:
+            while size > 0:
+                size1 = rffi.cast(rffi.SIZE_T, min(READ_MAX, size))
+                count = raw_os_read(fd, baseaddr, size1)
+                count = rffi.cast(lltype.Signed, count)
+                if count <= 0:
+                    break
+                size -= count
+                baseaddr += count
+            raw_os_close(fd)
+
+        if size > 0:     # reading from /dev/zero failed, fallback
             llmemory.raw_memclear(baseaddr, size)
 
 else: