Author: Richard Plangger <planri...@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() + _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit