Author: Carl Friedrich Bolz <[email protected]>
Branch:
Changeset: r60425:11342bf4b34e
Date: 2013-01-24 17:17 +0100
http://bitbucket.org/pypy/pypy/changeset/11342bf4b34e/
Log: improve the JITting of thread-local storage
use a slightly hacky workaround because we can use a loop invariant
function: we only support loop-invariant functions without arguments
atm. Instead have last-used cache on the local object. This helps in
a lot of cases.
diff --git a/pypy/module/pypyjit/test_pypy_c/test_thread.py
b/pypy/module/pypyjit/test_pypy_c/test_thread.py
--- a/pypy/module/pypyjit/test_pypy_c/test_thread.py
+++ b/pypy/module/pypyjit/test_pypy_c/test_thread.py
@@ -40,27 +40,11 @@
assert round(log.result, 6) == round(main(500), 6)
loop, = log.loops_by_filename(self.filepath)
assert loop.match("""
- i60 = int_lt(i55, i27)
- guard_true(i60, descr=...)
- i61 =
call(ConstClass(ll_dict_lookup_trampoline__v1134___simple_call__function_),
p33, p32, i35, descr=...)
- guard_no_exception(descr=...)
- i62 = int_and(i61, -2147483648)
- i63 = int_is_true(i62)
- guard_false(i63, descr=...)
- p64 = getinteriorfield_gc(p41, i61, descr=...)
- guard_nonnull_class(p64, ConstClass(W_DictMultiObject), descr=...)
- p65 = getfield_gc(p64, descr=...)
- guard_class(p65, 176132160, descr=...)
- p66 = getfield_gc(p64, descr=...)
- guard_class(p66, 175975744, descr=...)
- p67 = getfield_gc(p66, descr=...)
- guard_value(p67, ConstPtr(ptr49), descr=...)
- p68 = getfield_gc(p66, descr=...)
- p69 = getarrayitem_gc(p68, 0, descr=...)
- guard_nonnull_class(p69, ConstClass(W_IntObject), descr=...)
- i70 = getfield_gc_pure(p69, descr=...)
- i71 = int_add_ovf(i55, i70)
+ i53 = int_lt(i48, i27)
+ guard_true(i53, descr=...)
+ i54 = int_add_ovf(i48, i47)
guard_no_overflow(descr=...)
--TICK--
- jump(p0, p1, p3, p5, p10, p12, p14, i71, i27, p33, p32, i35, p41,
descr=...)
+ i58 = arraylen_gc(p43, descr=...)
+ jump(p0, p1, p3, p5, p10, p12, p14, i54, i27, i47, p45, p43,
descr=...)
""")
diff --git a/pypy/module/thread/os_local.py b/pypy/module/thread/os_local.py
--- a/pypy/module/thread/os_local.py
+++ b/pypy/module/thread/os_local.py
@@ -30,6 +30,9 @@
w_dict = space.newdict(instance=True)
self.dicts[ec] = w_dict
self._register_in_ec(ec)
+ # cache the last seen dict, works because we are protected by the GIL
+ self.last_dict = w_dict
+ self.last_ec = ec
def _register_in_ec(self, ec):
if not ec.space.config.translation.rweakref:
@@ -60,10 +63,14 @@
def getdict(self, space):
ec = space.getexecutioncontext()
+ if ec is self.last_ec:
+ return self.last_dict
try:
w_dict = self.dicts[ec]
except KeyError:
w_dict = self.create_new_dict(ec)
+ self.last_ec = ec
+ self.last_dict = w_dict
return w_dict
def descr_local__new__(space, w_subtype, __args__):
@@ -91,3 +98,5 @@
local = wref()
if local is not None:
del local.dicts[ec]
+ local.last_dict = None
+ local.last_ec = None
diff --git a/pypy/module/thread/test/test_local.py
b/pypy/module/thread/test/test_local.py
--- a/pypy/module/thread/test/test_local.py
+++ b/pypy/module/thread/test/test_local.py
@@ -108,3 +108,54 @@
gc.collect()
assert done == ['ok', 'del']
done.append('shutdown')
+
+def test_local_caching():
+ from pypy.module.thread.os_local import Local
+ class FakeSpace:
+ def getexecutioncontext(self):
+ return self.ec
+
+ def getattr(*args):
+ pass
+ def call_obj_args(*args):
+ pass
+ def newdict(*args, **kwargs):
+ return {}
+ def wrap(self, obj):
+ return obj
+ def type(self, obj):
+ return type(obj)
+ class config:
+ class translation:
+ rweakref = True
+
+ class FakeEC:
+ def __init__(self, space):
+ self.space = space
+ self._thread_local_objs = None
+ space = FakeSpace()
+ ec1 = FakeEC(space)
+ space.ec = ec1
+
+ l = Local(space, None)
+ assert l.last_dict is l.dicts[ec1]
+ assert l.last_ec is ec1
+ d1 = l.getdict(space)
+ assert d1 is l.last_dict
+
+ ec2 = space.ec = FakeEC(space)
+ d2 = l.getdict(space)
+ assert l.last_dict is d2
+ assert d2 is l.dicts[ec2]
+ assert l.last_ec is ec2
+ dicts = l.dicts
+ l.dicts = "nope"
+ assert l.getdict(space) is d2
+ l.dicts = dicts
+
+ space.ec = ec1
+ assert l.getdict(space) is d1
+ l.dicts = "nope"
+ assert l.getdict(space) is d1
+ l.dicts = dicts
+
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit