[pypy-commit] pypy stringbuilder3-perf: Add some special cases for the JIT
arigo
noreply at buildbot.pypy.org
Fri Jun 20 16:59:29 CEST 2014
Author: Armin Rigo <arigo at tunes.org>
Branch: stringbuilder3-perf
Changeset: r72107:ba9a90a5473b
Date: 2014-06-20 16:58 +0200
http://bitbucket.org/pypy/pypy/changeset/ba9a90a5473b/
Log: Add some special cases for the JIT
diff --git a/rpython/jit/metainterp/test/test_string.py b/rpython/jit/metainterp/test/test_string.py
--- a/rpython/jit/metainterp/test/test_string.py
+++ b/rpython/jit/metainterp/test/test_string.py
@@ -688,7 +688,9 @@
return n
res = self.meta_interp(f, [10], backendopt=True)
assert res == 0
- self.check_resops(call=2) # (ll_shrink_array) * 2 unroll
+ self.check_resops(call=6, # (ll_append_res0, ll_append_0_2, ll_build)
+ # * 2 unroll
+ cond_call=0)
def test_stringbuilder_append_len2_2(self):
jitdriver = JitDriver(reds=['n', 'str1'], greens=[])
@@ -708,7 +710,8 @@
return n
res = self.meta_interp(f, [10], backendopt=True)
assert res == 0
- self.check_resops(call=2) # (ll_shrink_array) * 2 unroll
+ self.check_resops(call=4, # (ll_append_res0, ll_build) * 2 unroll
+ cond_call=0)
def test_stringbuilder_append_slice_1(self):
jitdriver = JitDriver(reds=['n'], greens=[])
@@ -724,8 +727,8 @@
return n
res = self.meta_interp(f, [10], backendopt=True)
assert res == 0
- self.check_resops(call=2, # (ll_shrink_array) * 2 unroll
- copyunicodecontent=4)
+ self.check_resops(call=6, cond_call=0,
+ copyunicodecontent=0)
def test_stringbuilder_append_slice_2(self):
jitdriver = JitDriver(reds=['n'], greens=[])
@@ -751,12 +754,14 @@
while n > 0:
jitdriver.jit_merge_point(n=n)
sb = UnicodeBuilder()
- sb.append_multiple_char(u"x", 3)
+ sb.append_multiple_char(u"x", 5)
s = sb.build()
- if len(s) != 3: raise ValueError
+ if len(s) != 5: raise ValueError
if s[0] != u"x": raise ValueError
if s[1] != u"x": raise ValueError
if s[2] != u"x": raise ValueError
+ if s[3] != u"x": raise ValueError
+ if s[4] != u"x": raise ValueError
n -= 1
return n
res = self.meta_interp(f, [10], backendopt=True)
@@ -770,19 +775,17 @@
while n > 0:
jitdriver.jit_merge_point(n=n)
sb = UnicodeBuilder()
- sb.append_multiple_char(u"x", 5)
+ sb.append_multiple_char(u"x", 35)
s = sb.build()
- if len(s) != 5: raise ValueError
- if s[0] != u"x": raise ValueError
- if s[1] != u"x": raise ValueError
- if s[2] != u"x": raise ValueError
- if s[3] != u"x": raise ValueError
- if s[4] != u"x": raise ValueError
+ if len(s) != 35: raise ValueError
+ for c in s:
+ if c != u"x":
+ raise ValueError
n -= 1
return n
res = self.meta_interp(f, [10], backendopt=True)
assert res == 0
- self.check_resops(call=4) # (append, build) * 2 unroll
+ self.check_resops(call=4) # (_ll_append_multiple_char, build) * 2
def test_stringbuilder_bug1(self):
jitdriver = JitDriver(reds=['n', 's1'], greens=[])
diff --git a/rpython/rtyper/lltypesystem/rbuilder.py b/rpython/rtyper/lltypesystem/rbuilder.py
--- a/rpython/rtyper/lltypesystem/rbuilder.py
+++ b/rpython/rtyper/lltypesystem/rbuilder.py
@@ -220,13 +220,36 @@
unroll_func_for_size = unrolling_iterable([make_func_for_size(_n)
for _n in range(2, MAX_N + 1)])
+ at jit.unroll_safe
def ll_jit_try_append_slice(ll_builder, ll_str, start, size):
if jit.isconstant(size):
if size == 0:
return True
+ # a special case: if the builder's pos and end are still contants
+ # (typically if the builder is still virtual), and if 'size' fits,
+ # then we don't need any reallocation and can just set the
+ # characters in the buffer, in a way that won't force anything.
+ if (jit.isconstant(ll_builder.current_pos) and
+ jit.isconstant(ll_builder.current_end) and
+ size <= (ll_builder.current_end - ll_builder.current_pos) and
+ size <= 16):
+ pos = ll_builder.current_pos
+ buf = ll_builder.current_buf
+ stop = pos + size
+ ll_builder.current_pos = stop
+ while pos < stop:
+ buf.chars[pos] = ll_str.chars[start]
+ pos += 1
+ start += 1
+ return True
+ # turn appends of length 1 into ll_append_char().
if size == 1:
ll_append_char(ll_builder, ll_str.chars[start])
return True
+ # turn appends of length 2 to 10 into residual calls to
+ # specialized functions, for the lengths 2 to 10, where
+ # gcc will optimize the known-length copy_string_contents()
+ # as much as possible.
for func0, funcstart, for_size in unroll_func_for_size:
if size == for_size:
if jit.isconstant(start) and start == 0:
@@ -263,10 +286,27 @@
for i in xrange(pos, end):
buf.chars[i] = char
+ at jit.unroll_safe
def ll_jit_try_append_multiple_char(ll_builder, char, size):
if jit.isconstant(size):
if size == 0:
return True
+ # a special case: if the builder's pos and end are still contants
+ # (typically if the builder is still virtual), and if 'size' fits,
+ # then we don't need any reallocation and can just set the
+ # characters in the buffer, in a way that won't force anything.
+ if (jit.isconstant(ll_builder.current_pos) and
+ jit.isconstant(ll_builder.current_end) and
+ size <= (ll_builder.current_end - ll_builder.current_pos) and
+ size <= 16):
+ pos = ll_builder.current_pos
+ buf = ll_builder.current_buf
+ stop = pos + size
+ ll_builder.current_pos = stop
+ while pos < stop:
+ buf.chars[pos] = char
+ pos += 1
+ return True
if size == 1:
ll_append_char(ll_builder, char)
return True
More information about the pypy-commit
mailing list