Author: Armin Rigo <[email protected]>
Branch: use-madv-free
Changeset: r85684:abadb1536a6c
Date: 2016-07-14 00:02 +0200
http://bitbucket.org/pypy/pypy/changeset/abadb1536a6c/
Log: madvise_free(), which will call madvise() with either MADV_FREE or
MADV_DONTNEED. The first option is better but doesn't exist
everywhere (it does exist on OS/X and BSDs and Linux >= 4.5)
diff --git a/rpython/rlib/rmmap.py b/rpython/rlib/rmmap.py
--- a/rpython/rlib/rmmap.py
+++ b/rpython/rlib/rmmap.py
@@ -70,7 +70,13 @@
CConfig.MREMAP_MAYMOVE = (
rffi_platform.DefinedConstantInteger("MREMAP_MAYMOVE"))
CConfig.has_mremap = rffi_platform.Has('mremap(NULL, 0, 0, 0)')
- # a dirty hack, this is probably a macro
+ CConfig.has_madvise = rffi_platform.Has('madvise(NULL, 0, 0)')
+ # ^^ both are a dirty hack, this is probably a macro
+
+ CConfig.MADV_DONTNEED = (
+ rffi_platform.DefinedConstantInteger('MADV_DONTNEED'))
+ CConfig.MADV_FREE = (
+ rffi_platform.DefinedConstantInteger('MADV_FREE'))
elif _MS_WINDOWS:
constant_names = ['PAGE_READONLY', 'PAGE_READWRITE', 'PAGE_WRITECOPY',
@@ -144,6 +150,7 @@
if _POSIX:
has_mremap = cConfig['has_mremap']
+ has_madvise = cConfig['has_madvise']
c_mmap, c_mmap_safe = external('mmap', [PTR, size_t, rffi.INT, rffi.INT,
rffi.INT, off_t], PTR, macro=True,
save_err_on_unsafe=rffi.RFFI_SAVE_ERRNO)
@@ -154,6 +161,9 @@
if has_mremap:
c_mremap, _ = external('mremap',
[PTR, size_t, size_t, rffi.ULONG], PTR)
+ if has_madvise:
+ _, c_madvise_safe = external('madvise', [PTR, size_t, rffi.INT],
+ rffi.INT, _nowrapper=True)
# this one is always safe
_pagesize = rffi_platform.getintegerfunctionresult('getpagesize',
@@ -755,6 +765,39 @@
else:
free = c_munmap_safe
+ if sys.platform.startswith('linux'):
+ assert has_madvise
+ assert MADV_DONTNEED is not None
+ if MADV_FREE is None:
+ MADV_FREE = 8 # from the kernel sources of Linux >= 4.5
+ class CanUseMadvFree:
+ ok = -1
+ can_use_madv_free = CanUseMadvFree()
+ def madvise_free(addr, map_size):
+ # We don't know if we are running on a recent enough kernel
+ # that supports MADV_FREE. Check that at runtime: if the
+ # first call to madvise(MADV_FREE) fails, we assume it's
+ # because of EINVAL and we fall back to MADV_DONTNEED.
+ if can_use_madv_free.ok != 0:
+ res = c_madvise_safe(rffi.cast(PTR, addr),
+ rffi.cast(size_t, map_size),
+ rffi.cast(rffi.INT, MADV_FREE))
+ if can_use_madv_free.ok == -1:
+ can_use_madv_free.ok = (rffi.cast(lltype.Signed, res) == 0)
+ if can_use_madv_free.ok == 0:
+ c_madvise_safe(rffi.cast(PTR, addr),
+ rffi.cast(size_t, map_size),
+ rffi.cast(rffi.INT, MADV_DONTNEED))
+ elif has_madvise and not (MADV_FREE is MADV_DONTNEED is None):
+ use_flag = MADV_FREE if MADV_FREE is not None else MADV_DONTNEED
+ def madvise_free(addr, map_size):
+ c_madvise_safe(rffi.cast(PTR, addr),
+ rffi.cast(size_t, map_size),
+ rffi.cast(rffi.INT, use_flag))
+ else:
+ def madvice_free(addr, map_size):
+ "No madvice() on this platform"
+
elif _MS_WINDOWS:
def mmap(fileno, length, tagname="", access=_ACCESS_DEFAULT, offset=0):
# XXX flags is or-ed into access by now.
@@ -907,4 +950,9 @@
def free(ptr, map_size):
VirtualFree_safe(ptr, 0, MEM_RELEASE)
+ def madvice_free(addr, map_size):
+ """XXX find a Windows equivalent?
+ 'addr' is in the middle of memory obtained with the C malloc()...
+ """
+
# register_external here?
diff --git a/rpython/rlib/test/test_rmmap.py b/rpython/rlib/test/test_rmmap.py
--- a/rpython/rlib/test/test_rmmap.py
+++ b/rpython/rlib/test/test_rmmap.py
@@ -5,6 +5,7 @@
from rpython.rlib.rarithmetic import intmask
from rpython.rlib import rmmap as mmap
from rpython.rlib.rmmap import RTypeError, RValueError, alloc, free
+from rpython.rlib.rmmap import madvise_free
class TestMMap:
def setup_class(cls):
@@ -490,6 +491,7 @@
data[i] = chr(i & 0xff)
for i in range(0, map_size, 171):
assert data[i] == chr(i & 0xff)
+ madvise_free(data, map_size)
free(data, map_size)
def test_compile_alloc_free():
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit