[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