[pypy-commit] pypy vmprof-native: remove allocated libunwind info for dynamic code regions as soon as the loop token goes out of scope
plan_rich
pypy.commits at gmail.com
Sat Feb 11 10:58:40 EST 2017
Author: Richard Plangger <planrichi at gmail.com>
Branch: vmprof-native
Changeset: r90050:fd79187556df
Date: 2017-02-11 16:58 +0100
http://bitbucket.org/pypy/pypy/changeset/fd79187556df/
Log: remove allocated libunwind info for dynamic code regions as soon as
the loop token goes out of scope
diff --git a/rpython/jit/backend/x86/assembler.py b/rpython/jit/backend/x86/assembler.py
--- a/rpython/jit/backend/x86/assembler.py
+++ b/rpython/jit/backend/x86/assembler.py
@@ -491,7 +491,6 @@
if not we_are_translated():
# Arguments should be unique
assert len(set(inputargs)) == len(inputargs)
-
self.setup(looptoken)
if self.cpu.HAS_CODEMAP:
self.codemap_builder.enter_portal_frame(jd_id, unique_id,
diff --git a/rpython/jit/metainterp/compile.py b/rpython/jit/metainterp/compile.py
--- a/rpython/jit/metainterp/compile.py
+++ b/rpython/jit/metainterp/compile.py
@@ -160,9 +160,10 @@
jitcell_token.outermost_jitdriver_sd = jitdriver_sd
return jitcell_token
-def record_loop_or_bridge(metainterp_sd, loop):
+def record_loop_or_bridge(metainterp_sd, loop, asminfo):
"""Do post-backend recordings and cleanups on 'loop'.
"""
+ from rpython.rlib.rvmprof import rvmprof
# get the original jitcell token corresponding to jitcell form which
# this trace starts
original_jitcell_token = loop.original_jitcell_token
@@ -172,6 +173,11 @@
wref = weakref.ref(original_jitcell_token)
clt = original_jitcell_token.compiled_loop_token
clt.loop_token_wref = wref
+
+ rvmprof.dyn_register_jit_page(original_jitcell_token, asminfo.asmaddr,
+ asminfo.asmaddr+asminfo.asmlen)
+
+
for op in loop.operations:
descr = op.getdescr()
# not sure what descr.index is about
@@ -242,9 +248,9 @@
if not we_are_translated():
loop.check_consistency()
jitcell_token.target_tokens = [target_token]
- send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, "loop",
- runtime_args, metainterp.box_names_memo)
- record_loop_or_bridge(metainterp_sd, loop)
+ asminfo = send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd,
+ loop, "loop", runtime_args, metainterp.box_names_memo)
+ record_loop_or_bridge(metainterp_sd, loop, asminfo)
return target_token
def compile_loop(metainterp, greenkey, start, inputargs, jumpargs,
@@ -337,9 +343,9 @@
loop_info.extra_before_label + [loop_info.label_op] + loop_ops)
if not we_are_translated():
loop.check_consistency()
- send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd, loop, "loop",
- inputargs, metainterp.box_names_memo)
- record_loop_or_bridge(metainterp_sd, loop)
+ asminfo = send_loop_to_backend(greenkey, jitdriver_sd, metainterp_sd,
+ loop, "loop", inputargs, metainterp.box_names_memo)
+ record_loop_or_bridge(metainterp_sd, loop, asminfo)
loop_info.post_loop_compilation(loop, jitdriver_sd, metainterp, jitcell_token)
return start_descr
@@ -414,9 +420,9 @@
loop.quasi_immutable_deps = quasi_immutable_deps
target_token = loop.operations[-1].getdescr()
- resumekey.compile_and_attach(metainterp, loop, inputargs)
+ asminfo = resumekey.compile_and_attach(metainterp, loop, inputargs)
- record_loop_or_bridge(metainterp_sd, loop)
+ record_loop_or_bridge(metainterp_sd, loop, asminfo)
return target_token
def get_box_replacement(op, allow_none=False):
@@ -506,11 +512,6 @@
jd_id=jd_id, unique_id=unique_id,
log=log, name=name, logger=metainterp_sd.jitlog)
- vmprof = metainterp_sd.vmprof
- if vmprof:
- vmprof.dyn_register_jit_page(asminfo.asmaddr,
- asminfo.asmaddr+asminfo.asmlen, 1)
-
return asminfo
def do_compile_bridge(metainterp_sd, faildescr, inputargs, operations,
@@ -524,10 +525,6 @@
asminfo = metainterp_sd.cpu.compile_bridge(faildescr, inputargs, operations,
original_loop_token, log=log,
logger=metainterp_sd.jitlog)
- vmprof = metainterp_sd.vmprof
- if vmprof:
- vmprof.dyn_register_jit_page(asminfo.asmaddr,
- asminfo.asmaddr+asminfo.asmlen, 0)
return asminfo
def forget_optimization_info(lst, reset_values=False):
@@ -598,6 +595,8 @@
if metainterp_sd.warmrunnerdesc is not None: # for tests
metainterp_sd.warmrunnerdesc.memory_manager.keep_loop_alive(original_jitcell_token)
+ return asminfo
+
def send_bridge_to_backend(jitdriver_sd, metainterp_sd, faildescr, inputargs,
operations, original_loop_token, memo):
forget_optimization_info(operations)
@@ -843,10 +842,10 @@
self._debug_subinputargs = new_loop.inputargs
self._debug_suboperations = new_loop.operations
propagate_original_jitcell_token(new_loop)
- send_bridge_to_backend(metainterp.jitdriver_sd, metainterp.staticdata,
- self, inputargs, new_loop.operations,
- new_loop.original_jitcell_token,
- metainterp.box_names_memo)
+ return send_bridge_to_backend(metainterp.jitdriver_sd,
+ metainterp.staticdata, self, inputargs,
+ new_loop.operations, new_loop.original_jitcell_token,
+ metainterp.box_names_memo)
def make_a_counter_per_value(self, guard_value_op, index):
assert guard_value_op.getopnum() == rop.GUARD_VALUE
@@ -1047,13 +1046,14 @@
jitdriver_sd = metainterp.jitdriver_sd
new_loop.original_jitcell_token = jitcell_token = make_jitcell_token(jitdriver_sd)
propagate_original_jitcell_token(new_loop)
- send_loop_to_backend(self.original_greenkey, metainterp.jitdriver_sd,
- metainterp_sd, new_loop, "entry bridge",
- orig_inputargs, metainterp.box_names_memo)
+ asminfo = send_loop_to_backend(self.original_greenkey,
+ metainterp.jitdriver_sd, metainterp_sd, new_loop,
+ "entry bridge", orig_inputargs, metainterp.box_names_memo)
# send the new_loop to warmspot.py, to be called directly the next time
jitdriver_sd.warmstate.attach_procedure_to_interp(
self.original_greenkey, jitcell_token)
metainterp_sd.stats.add_jitcell_token(jitcell_token)
+ return asminfo
def compile_trace(metainterp, resumekey, runtime_boxes):
@@ -1115,8 +1115,8 @@
if info.final():
new_trace.inputargs = info.inputargs
target_token = new_trace.operations[-1].getdescr()
- resumekey.compile_and_attach(metainterp, new_trace, inputargs)
- record_loop_or_bridge(metainterp_sd, new_trace)
+ asminfo = resumekey.compile_and_attach(metainterp, new_trace, inputargs)
+ record_loop_or_bridge(metainterp_sd, new_trace, asminfo)
return target_token
new_trace.inputargs = info.renamed_inputargs
metainterp.retrace_needed(new_trace, info)
diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py
--- a/rpython/jit/metainterp/history.py
+++ b/rpython/jit/metainterp/history.py
@@ -419,6 +419,14 @@
def __init__(self):
# For memory management of assembled loops
self._keepalive_jitcell_tokens = {} # set of other JitCellToken
+ self._rvmprof_references = []
+
+ def rvmprof_register(self, ref):
+ """ Call this method for every loop or bridge that hangs on this
+ token. Otherwise the information tracked by libunwind will
+ not be freed.
+ """
+ self._rvmprof_references.append(ref)
def record_jump_to(self, jitcell_token):
assert isinstance(jitcell_token, JitCellToken)
diff --git a/rpython/jit/metainterp/memmgr.py b/rpython/jit/metainterp/memmgr.py
--- a/rpython/jit/metainterp/memmgr.py
+++ b/rpython/jit/metainterp/memmgr.py
@@ -2,6 +2,7 @@
from rpython.rlib.rarithmetic import r_int64
from rpython.rlib.debug import debug_start, debug_print, debug_stop
from rpython.rlib.objectmodel import we_are_translated
+from rpython.rlib.rvmprof import rvmprof
#
# Logic to decide which loops are old and not used any more.
@@ -70,6 +71,7 @@
for looptoken in self.alive_loops.keys():
if (0 <= looptoken.generation < max_generation or
looptoken.invalidated):
+ rvmprof.vmp_dyn_cancel(looptoken)
del self.alive_loops[looptoken]
newtotal = len(self.alive_loops)
debug_print("Loop tokens freed: ", oldtotal - newtotal)
diff --git a/rpython/rlib/rvmprof/cintf.py b/rpython/rlib/rvmprof/cintf.py
--- a/rpython/rlib/rvmprof/cintf.py
+++ b/rpython/rlib/rvmprof/cintf.py
@@ -54,6 +54,7 @@
SHARED.join('machine.c'),
SHARED.join('symboltable.c'),
SHARED.join('vmp_stack.c'),
+ SHARED.join('vmp_dynamic.c'),
# udis86
SHARED.join('libudis86/decode.c'),
SHARED.join('libudis86/itab.c'),
@@ -96,6 +97,19 @@
lltype.Signed, compilation_info=eci,
_nowrapper=True)
+ vmp_dyn_register_jit_page = rffi.llexternal("vmp_dyn_register_jit_page",
+ [lltype.Signed, lltype.Signed, rffi.CCHARP],
+ rffi.INT, compilation_info=eci,
+ _nowrapper=True)
+
+ vmp_dyn_cancel = rffi.llexternal("vmp_dyn_cancel", [rffi.INT],
+ lltype.Void, compilation_info=eci,
+ _nowrapper=True)
+
+ vmp_dyn_cancel = rffi.llexternal("vmp_dyn_teardown", [lltype.Void],
+ rffi.INT, compilation_info=eci,
+ _nowrapper=True)
+
return CInterface(locals())
diff --git a/rpython/rlib/rvmprof/rvmprof.py b/rpython/rlib/rvmprof/rvmprof.py
--- a/rpython/rlib/rvmprof/rvmprof.py
+++ b/rpython/rlib/rvmprof/rvmprof.py
@@ -161,16 +161,6 @@
raise VMProfError(os.strerror(rposix.get_saved_errno()))
- def dyn_register_jit_page(self, addr, end_addr, loop, name=None):
- if name is None:
- cname = rffi.cast(rffi.CHARP, 0)
- else:
- cname = rffi.str2charp(name)
- return self.cintf.vmp_dyn_register_jit_page(addr, end_addr, cname)
-
- def dyn_cancel(self, ref):
- self.cintf.vmp_dyn_cancel(ref)
-
def _write_code_registration(self, uid, name):
assert name.count(':') == 3 and len(name) <= MAX_FUNC_NAME, (
"the name must be 'class:func_name:func_line:filename' "
@@ -257,6 +247,26 @@
return decorate
+def dyn_register_jit_page(token, addr, end_addr):
+ try:
+ c = _get_vmprof().cintf
+ cname = lltype.nullptr(rffi.CCHARP.TO)
+ ref = c.vmp_dyn_register_jit_page(addr, end_addr, cname)
+ token.rvmprof_register(ref)
+ return True
+ except cintf.VMProfPlatformUnsupported:
+ return False
+
+def dyn_cancel(token):
+ try:
+ c = _get_vmprof().cintf
+ for ref in token._rvmprof_references:
+ c.vmp_dyn_cancel(ref)
+ token._rvmprof_references = []
+ return True
+ except cintf.VMProfPlatformUnsupported:
+ return False
+
@specialize.memo()
def _was_registered(CodeClass):
return hasattr(CodeClass, '_vmprof_unique_id')
diff --git a/rpython/rlib/rvmprof/src/shared/vmp_dynamic.c b/rpython/rlib/rvmprof/src/shared/vmp_dynamic.c
--- a/rpython/rlib/rvmprof/src/shared/vmp_dynamic.c
+++ b/rpython/rlib/rvmprof/src/shared/vmp_dynamic.c
@@ -9,8 +9,17 @@
static int g_dyn_entry_count_max = 0;
static unw_dyn_info_t ** g_dyn_entries = 0;
+RPY_EXTERN
int vmp_dyn_teardown(void)
{
+ int i;
+ for (i = 0; i < g_dyn_entry_count; i++) {
+ unw_dyn_info_t * u = g_dyn_entries[i];
+ if (u != NULL) {
+ free(u);
+ g_dyn_entries[i] = NULL;
+ }
+ }
if (g_dyn_entries != NULL) {
free(g_dyn_entries);
}
@@ -30,7 +39,7 @@
g_dyn_entry_count_max *= 2;
g_dyn_entries = (unw_dyn_info_t**)realloc(g_dyn_entries, sizeof(unw_dyn_info_t*) * g_dyn_entry_count_max);
memset(g_dyn_entries + g_dyn_entry_count, 0,
- sizeof(unw_dyn_info_t*)*g_dyn_entry_count_max - g_dyn_entry_count);
+ sizeof(unw_dyn_info_t*)*(g_dyn_entry_count_max - g_dyn_entry_count));
}
}
@@ -72,6 +81,7 @@
free(u);
}
+RPY_EXTERN
int vmp_dyn_register_jit_page(intptr_t addr, intptr_t end_addr,
const char * name)
{
@@ -98,6 +108,7 @@
return ref;
}
+RPY_EXTERN
int vmp_dyn_cancel(int ref) {
unw_dyn_info_t * u;
diff --git a/rpython/rlib/rvmprof/src/shared/vmp_dynamic.h b/rpython/rlib/rvmprof/src/shared/vmp_dynamic.h
--- a/rpython/rlib/rvmprof/src/shared/vmp_dynamic.h
+++ b/rpython/rlib/rvmprof/src/shared/vmp_dynamic.h
@@ -3,8 +3,10 @@
#include <stdint.h>
#include <libunwind.h>
-int vmp_dyn_register_jit_page(intptr_t addr, intptr_t end_addr,
+#include "rvmprof.h"
+
+RPY_EXTERN int vmp_dyn_register_jit_page(intptr_t addr, intptr_t end_addr,
const char * name);
-int vmp_dyn_cancel(int ref);
-int vmp_dyn_teardown(void);
+RPY_EXTERN int vmp_dyn_cancel(int ref);
+RPY_EXTERN int vmp_dyn_teardown(void);
diff --git a/rpython/rlib/rvmprof/test/test_dynamic.py b/rpython/rlib/rvmprof/test/test_dynamic.py
--- a/rpython/rlib/rvmprof/test/test_dynamic.py
+++ b/rpython/rlib/rvmprof/test/test_dynamic.py
@@ -16,11 +16,12 @@
ffi.cdef("""
int vmp_dyn_register_jit_page(intptr_t addr, intptr_t end_addr, const char * name);
int vmp_dyn_cancel(int ref);
+ int vmp_dyn_teardown(void);
""")
with open(str(srcdir.join("shared/vmp_dynamic.c"))) as fd:
ffi.set_source("rpython.rlib.rvmprof.test._test_dynamic", fd.read(),
- include_dirs=[str(srcdir.join('shared'))],
+ include_dirs=[str(srcdir), str(srcdir.join('shared'))],
libraries=['unwind'])
ffi.compile(verbose=True)
@@ -44,4 +45,28 @@
lib.vmp_dyn_cancel(0)
lib.vmp_dyn_cancel(1)
+ def test_register_dynamic_code_many(self):
+ lib = self.lib
+ ffi = self.ffi
+ refs = []
+ for i in range(5000):
+ ref = lib.vmp_dyn_register_jit_page(0x100*i, 0x200*i, ffi.NULL)
+ refs.append(ref)
+
+ for i in range(1000, 4000):
+ ref = refs[i]
+ lib.vmp_dyn_cancel(ref)
+
+ refs = refs[:1000] + refs[4000:]
+
+ for i in range(5000):
+ ref = lib.vmp_dyn_register_jit_page(0x100*i, 0x200*i, ffi.NULL)
+ refs.append(ref)
+
+ while refs:
+ ref = refs.pop()
+ lib.vmp_dyn_cancel(ref)
+
+ lib.vmp_dyn_teardown()
+
More information about the pypy-commit
mailing list