Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r71128:3f23bbb810db Date: 2014-05-01 11:16 +0200 http://bitbucket.org/pypy/pypy/changeset/3f23bbb810db/
Log: More tweaks: pass a (w_func, w_type) pair to the elidable function instead of a string, and make the function @elidable_promote as it should be what we want anyway. Use a new small container, W_DelayedBuiltinStr; see docstring. diff --git a/pypy/module/_lsprof/interp_lsprof.py b/pypy/module/_lsprof/interp_lsprof.py --- a/pypy/module/_lsprof/interp_lsprof.py +++ b/pypy/module/_lsprof/interp_lsprof.py @@ -59,7 +59,7 @@ self.tt, self.it, calls_repr)) def get_code(self, space): - return self.frame + return returns_code(space, self.frame) W_StatsEntry.typedef = TypeDef( 'StatsEntry', @@ -86,7 +86,7 @@ frame_repr, self.callcount, self.reccallcount, self.tt, self.it)) def get_code(self, space): - return self.frame + return returns_code(space, self.frame) W_StatsSubEntry.typedef = TypeDef( 'SubStatsEntry', @@ -215,18 +215,55 @@ return '<%s>' % w_func.name -def create_spec_for_object(space, w_obj): - class_name = space.type(w_obj).getname(space) +def create_spec_for_object(space, w_type): + class_name = w_type.getname(space) return "<'%s' object>" % (class_name,) -def create_spec(space, w_arg): +class W_DelayedBuiltinStr(W_Root): + # This class should not be seen at app-level, but is useful to + # contain a (w_func, w_type) pair returned by prepare_spec(). + # Turning this pair into a string cannot be done eagerly in + # an @elidable function because of space.str_w(), but it can + # be done lazily when we really want it. + + _immutable_fields_ = ['w_func', 'w_type'] + + def __init__(self, w_func, w_type): + self.w_func = w_func + self.w_type = w_type + self.w_string = None + + def wrap_string(self, space): + if self.w_string is None: + if self.w_type is None: + s = create_spec_for_function(space, self.w_func) + elif self.w_func is None: + s = create_spec_for_object(space, self.w_type) + else: + s = create_spec_for_method(space, self.w_func, self.w_type) + self.w_string = space.wrap(s) + return self.w_string + +W_DelayedBuiltinStr.typedef = TypeDef( + 'DelayedBuiltinStr', + __str__ = interp2app(W_DelayedBuiltinStr.wrap_string), +) + +def returns_code(space, w_frame): + if isinstance(w_frame, W_DelayedBuiltinStr): + return w_frame.wrap_string(space) + return w_frame # actually a PyCode object + + +def prepare_spec(w_arg): if isinstance(w_arg, Method): - return create_spec_for_method(space, w_arg.w_function, w_arg.w_class) + return (w_arg.w_function, w_arg.w_class) elif isinstance(w_arg, Function): - return create_spec_for_function(space, w_arg) + return (w_arg, None) else: - return create_spec_for_object(space, w_arg) + return (None, space.type(w_arg)) +prepare_spec._always_inline_ = True def lsprof_call(space, w_self, frame, event, w_arg): @@ -239,12 +276,10 @@ w_self._enter_return(code) elif event == 'c_call': if w_self.builtins: - key = create_spec(space, w_arg) - w_self._enter_builtin_call(key) + w_self._enter_builtin_call(w_arg) elif event == 'c_return' or event == 'c_exception': if w_self.builtins: - key = create_spec(space, w_arg) - w_self._enter_builtin_return(key) + w_self._enter_builtin_return(w_arg) else: # ignore or raise an exception??? pass @@ -307,13 +342,14 @@ return entry raise - @jit.elidable - def _get_or_make_builtin_entry(self, key, make=True): + @jit.elidable_promote() + def _get_or_make_builtin_entry(self, w_func, w_type, make): + key = (w_func, w_type) try: return self.builtin_data[key] except KeyError: if make: - entry = ProfilerEntry(self.space.wrap(key)) + entry = ProfilerEntry(W_DelayedBuiltinStr(w_func, w_type)) self.builtin_data[key] = entry return entry raise @@ -337,20 +373,18 @@ context._stop(self, entry) self.current_context = context.previous - def _enter_builtin_call(self, key): - self = jit.promote(self) - key = jit.promote_string(key) - entry = self._get_or_make_builtin_entry(key) + def _enter_builtin_call(self, w_arg): + w_func, w_type = prepare_spec(w_arg) + entry = self._get_or_make_builtin_entry(w_func, w_type, True) self.current_context = ProfilerContext(self, entry) - def _enter_builtin_return(self, key): + def _enter_builtin_return(self, w_arg): context = self.current_context if context is None: return - self = jit.promote(self) - key = jit.promote_string(key) + w_func, w_type = prepare_spec(w_arg) try: - entry = self._get_or_make_builtin_entry(key, False) + entry = self._get_or_make_builtin_entry(w_func, w_type, False) except KeyError: pass else: diff --git a/pypy/module/_lsprof/test/test_cprofile.py b/pypy/module/_lsprof/test/test_cprofile.py --- a/pypy/module/_lsprof/test/test_cprofile.py +++ b/pypy/module/_lsprof/test/test_cprofile.py @@ -27,6 +27,32 @@ for entry in stats: assert entry.code in expected + def test_builtins_callers(self): + import _lsprof + prof = _lsprof.Profiler(subcalls=True) + lst = [] + def f1(): + lst.append(len(lst)) + prof.enable(subcalls=True) + f1() + prof.disable() + stats = prof.getstats() + expected = ( + "<len>", + "<method 'append' of 'list' objects>", + ) + by_id = set() + for entry in stats: + if entry.code == f1.func_code: + assert len(entry.calls) == 2 + for subentry in entry.calls: + assert subentry.code in expected + by_id.add(id(subentry.code)) + elif entry.code in expected: + by_id.add(id(entry.code)) + # :-( cProfile.py relies on the id() of the strings... + assert len(by_id) == len(expected) + def test_direct(self): import _lsprof def getticks(): _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit