Author: Carl Friedrich Bolz <[email protected]>
Branch: 
Changeset: r80416:e96988647017
Date: 2015-10-23 20:21 +0200
http://bitbucket.org/pypy/pypy/changeset/e96988647017/

Log:    merge lazy-fast2locals

        improve the performance of simple trace functions by lazily calling
        fast2locals and locals2fast only if f_locals is actually accessed.

diff --git a/pypy/interpreter/executioncontext.py 
b/pypy/interpreter/executioncontext.py
--- a/pypy/interpreter/executioncontext.py
+++ b/pypy/interpreter/executioncontext.py
@@ -327,10 +327,14 @@
                 w_arg = space.newtuple([operr.w_type, w_value,
                                      space.wrap(operr.get_traceback())])
 
-            frame.fast2locals()
+            d = frame.getorcreatedebug()
+            if d.w_locals is not None:
+                # only update the w_locals dict if it exists
+                # if it does not exist yet and the tracer accesses it via
+                # frame.f_locals, it is filled by PyFrame.getdictscope
+                frame.fast2locals()
             self.is_tracing += 1
             try:
-                d = frame.getorcreatedebug()
                 try:
                     w_result = space.call_function(w_callback, 
space.wrap(frame), space.wrap(event), w_arg)
                     if space.is_w(w_result, space.w_None):
@@ -343,7 +347,8 @@
                     raise
             finally:
                 self.is_tracing -= 1
-                frame.locals2fast()
+                if d.w_locals is not None:
+                    frame.locals2fast()
 
         # Profile cases
         if self.profilefunc is not None:
diff --git a/pypy/interpreter/test/test_pyframe.py 
b/pypy/interpreter/test/test_pyframe.py
--- a/pypy/interpreter/test/test_pyframe.py
+++ b/pypy/interpreter/test/test_pyframe.py
@@ -1,10 +1,14 @@
 from rpython.tool import udir
 from pypy.conftest import option
+from pypy.interpreter.gateway import interp2app
 
+def check_no_w_locals(space, w_frame):
+    return space.wrap(w_frame.getorcreatedebug().w_locals is None)
 
 class AppTestPyFrame:
 
     def setup_class(cls):
+        space = cls.space
         cls.w_udir = cls.space.wrap(str(udir.udir))
         cls.w_tempfile1 = cls.space.wrap(str(udir.udir.join('tempfile1')))
         if not option.runappdirect:
@@ -17,6 +21,8 @@
             w_call_further.code.hidden_applevel = True       # hack
             cls.w_call_further = w_call_further
 
+            cls.w_check_no_w_locals = space.wrap(interp2app(check_no_w_locals))
+
     # test for the presence of the attributes, not functionality
 
     def test_f_locals(self):
@@ -493,6 +499,25 @@
         sys.settrace(None)
         assert res == 42
 
+    def test_fast2locals_called_lazily(self):
+        import sys
+        class FrameHolder:
+            pass
+        fh = FrameHolder()
+        def trace(frame, what, arg):
+            # trivial trace function, does not access f_locals
+            fh.frame = frame
+            return trace
+        def f(x):
+            x += 1
+            return x
+        sys.settrace(trace)
+        res = f(1)
+        sys.settrace(None)
+        assert res == 2
+        if hasattr(self, "check_no_w_locals"): # not appdirect
+            assert self.check_no_w_locals(fh.frame)
+
     def test_set_unset_f_trace(self):
         import sys
         seen = []
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to