Author: Antonio Cuni <[email protected]>
Branch:
Changeset: r65304:cffbba0d1078
Date: 2013-07-09 21:35 +0200
http://bitbucket.org/pypy/pypy/changeset/cffbba0d1078/
Log: merge the improve-str2charp branch: now operations like str2charp
and get_nonmovingbuffer are implemented by calling memcpy instead of
copying char-by-char explicitly. The results is that str2charp is
now 31x faster (31, it's not a typo) and I/O bound benchmarks like
twisted_tcp and raytrace-simple are ~15% faster
diff --git a/rpython/jit/codewriter/effectinfo.py
b/rpython/jit/codewriter/effectinfo.py
--- a/rpython/jit/codewriter/effectinfo.py
+++ b/rpython/jit/codewriter/effectinfo.py
@@ -79,6 +79,9 @@
#
OS_RAW_MALLOC_VARSIZE_CHAR = 110
OS_RAW_FREE = 111
+ #
+ OS_STR_COPY_TO_RAW = 112
+ OS_UNI_COPY_TO_RAW = 113
OS_JIT_FORCE_VIRTUAL = 120
diff --git a/rpython/jit/codewriter/jtransform.py
b/rpython/jit/codewriter/jtransform.py
--- a/rpython/jit/codewriter/jtransform.py
+++ b/rpython/jit/codewriter/jtransform.py
@@ -1665,12 +1665,14 @@
dict = {"stroruni.concat": EffectInfo.OS_STR_CONCAT,
"stroruni.slice": EffectInfo.OS_STR_SLICE,
"stroruni.equal": EffectInfo.OS_STR_EQUAL,
+ "stroruni.copy_string_to_raw":
EffectInfo.OS_STR_COPY_TO_RAW,
}
CHR = lltype.Char
elif SoU.TO == rstr.UNICODE:
dict = {"stroruni.concat": EffectInfo.OS_UNI_CONCAT,
"stroruni.slice": EffectInfo.OS_UNI_SLICE,
"stroruni.equal": EffectInfo.OS_UNI_EQUAL,
+ "stroruni.copy_string_to_raw":
EffectInfo.OS_UNI_COPY_TO_RAW
}
CHR = lltype.UniChar
else:
diff --git a/rpython/rtyper/lltypesystem/rffi.py
b/rpython/rtyper/lltypesystem/rffi.py
--- a/rpython/rtyper/lltypesystem/rffi.py
+++ b/rpython/rtyper/lltypesystem/rffi.py
@@ -677,7 +677,8 @@
def make_string_mappings(strtype):
if strtype is str:
- from rpython.rtyper.lltypesystem.rstr import STR as STRTYPE
+ from rpython.rtyper.lltypesystem.rstr import (STR as STRTYPE,
+ copy_string_to_raw)
from rpython.rtyper.annlowlevel import llstr as llstrtype
from rpython.rtyper.annlowlevel import hlstr as hlstrtype
TYPEP = CCHARP
@@ -685,7 +686,9 @@
lastchar = '\x00'
builder_class = StringBuilder
else:
- from rpython.rtyper.lltypesystem.rstr import UNICODE as STRTYPE
+ from rpython.rtyper.lltypesystem.rstr import (
+ UNICODE as STRTYPE,
+ copy_unicode_to_raw as copy_string_to_raw)
from rpython.rtyper.annlowlevel import llunicode as llstrtype
from rpython.rtyper.annlowlevel import hlunicode as hlstrtype
TYPEP = CWCHARP
@@ -702,11 +705,9 @@
else:
array = lltype.malloc(TYPEP.TO, len(s) + 1, flavor='raw',
track_allocation=False)
i = len(s)
+ ll_s = llstrtype(s)
+ copy_string_to_raw(ll_s, array, 0, i)
array[i] = lastchar
- i -= 1
- while i >= 0:
- array[i] = s[i]
- i -= 1
return array
str2charp._annenforceargs_ = [strtype, bool]
@@ -739,14 +740,14 @@
string is already nonmovable. Must be followed by a
free_nonmovingbuffer call.
"""
+ lldata = llstrtype(data)
if rgc.can_move(data):
count = len(data)
buf = lltype.malloc(TYPEP.TO, count, flavor='raw')
- for i in range(count):
- buf[i] = data[i]
+ copy_string_to_raw(lldata, buf, 0, count)
return buf
else:
- data_start = cast_ptr_to_adr(llstrtype(data)) + \
+ data_start = cast_ptr_to_adr(lldata) + \
offsetof(STRTYPE, 'chars') + itemoffsetof(STRTYPE.chars, 0)
return cast(TYPEP, data_start)
get_nonmovingbuffer._annenforceargs_ = [strtype]
diff --git a/rpython/rtyper/lltypesystem/rstr.py
b/rpython/rtyper/lltypesystem/rstr.py
--- a/rpython/rtyper/lltypesystem/rstr.py
+++ b/rpython/rtyper/lltypesystem/rstr.py
@@ -49,16 +49,18 @@
def emptyunicodefun():
return emptyunicode
-def _new_copy_contents_fun(SRC_TP, DST_TP, CHAR_TP, name):
- def _str_ofs_src(item):
- return (llmemory.offsetof(SRC_TP, 'chars') +
- llmemory.itemoffsetof(SRC_TP.chars, 0) +
+def _new_copy_contents_fun(STR_TP, CHAR_TP, name):
+ def _str_ofs(item):
+ return (llmemory.offsetof(STR_TP, 'chars') +
+ llmemory.itemoffsetof(STR_TP.chars, 0) +
llmemory.sizeof(CHAR_TP) * item)
- def _str_ofs_dst(item):
- return (llmemory.offsetof(DST_TP, 'chars') +
- llmemory.itemoffsetof(DST_TP.chars, 0) +
- llmemory.sizeof(CHAR_TP) * item)
+ @signature(types.any(), types.int(), returns=types.any())
+ def _get_raw_buf(src, ofs):
+ assert typeOf(src).TO == STR_TP
+ assert ofs >= 0
+ return llmemory.cast_ptr_to_adr(src) + _str_ofs(ofs)
+ _get_raw_buf._always_inline_ = True
@jit.oopspec('stroruni.copy_contents(src, dst, srcstart, dststart,
length)')
@signature(types.any(), types.any(), types.int(), types.int(),
types.int(), returns=types.none())
@@ -71,22 +73,38 @@
# because it might move the strings. The keepalive_until_here()
# are obscurely essential to make sure that the strings stay alive
# longer than the raw_memcopy().
- assert typeOf(src).TO == SRC_TP
- assert typeOf(dst).TO == DST_TP
- assert srcstart >= 0
- assert dststart >= 0
assert length >= 0
- src = llmemory.cast_ptr_to_adr(src) + _str_ofs_src(srcstart)
- dst = llmemory.cast_ptr_to_adr(dst) + _str_ofs_dst(dststart)
+ src = _get_raw_buf(src, srcstart)
+ dst = _get_raw_buf(dst, dststart)
llmemory.raw_memcopy(src, dst, llmemory.sizeof(CHAR_TP) * length)
keepalive_until_here(src)
keepalive_until_here(dst)
copy_string_contents._always_inline_ = True
- return func_with_new_name(copy_string_contents, 'copy_%s_contents' % name)
+ copy_string_contents = func_with_new_name(copy_string_contents,
+ 'copy_%s_contents' % name)
-copy_string_contents = _new_copy_contents_fun(STR, STR, Char, 'string')
-copy_unicode_contents = _new_copy_contents_fun(UNICODE, UNICODE, UniChar,
- 'unicode')
+ @jit.oopspec('stroruni.copy_string_to_raw(src, ptrdst, srcstart, length)')
+ def copy_string_to_raw(src, ptrdst, srcstart, length):
+ """
+ Copies 'length' characters from the 'src' string to the 'ptrdst'
+ buffer, starting at position 'srcstart'.
+ 'ptrdst' must be a non-gc Array of Char.
+ """
+ # xxx Warning: same note as above apply: don't do this at home
+ assert length >= 0
+ src = _get_raw_buf(src, srcstart)
+ adr = llmemory.cast_ptr_to_adr(ptrdst)
+ dstbuf = adr + llmemory.itemoffsetof(typeOf(ptrdst).TO, 0)
+ llmemory.raw_memcopy(src, dstbuf, llmemory.sizeof(CHAR_TP) * length)
+ keepalive_until_here(src)
+ copy_string_to_raw._always_inline_ = True
+ copy_string_to_raw = func_with_new_name(copy_string_to_raw,
'copy_%s_to_raw' % name)
+
+ return copy_string_to_raw, copy_string_contents
+
+copy_string_to_raw, copy_string_contents = _new_copy_contents_fun(STR, Char,
'string')
+copy_unicode_to_raw, copy_unicode_contents = _new_copy_contents_fun(UNICODE,
+ UniChar,
'unicode')
CONST_STR_CACHE = WeakValueDictionary()
CONST_UNICODE_CACHE = WeakValueDictionary()
diff --git a/rpython/rtyper/test/test_rstr.py b/rpython/rtyper/test/test_rstr.py
--- a/rpython/rtyper/test/test_rstr.py
+++ b/rpython/rtyper/test/test_rstr.py
@@ -1118,6 +1118,26 @@
res = self.interpret(f, [5])
assert res == 0
+ def test_copy_string_to_raw(self):
+ from rpython.rtyper.lltypesystem import lltype, llmemory
+ from rpython.rtyper.annlowlevel import llstr
+ from rpython.rtyper.lltypesystem.rstr import copy_string_to_raw
+
+ def f(buf, n):
+ s = 'abc' * n
+ ll_s = llstr(s)
+ copy_string_to_raw(ll_s, buf, 0, n*3)
+
+ TP = lltype.Array(lltype.Char)
+ array = lltype.malloc(TP, 12, flavor='raw')
+ f(array, 4)
+ assert list(array) == list('abc'*4)
+ lltype.free(array, flavor='raw')
+
+ array = lltype.malloc(TP, 12, flavor='raw')
+ self.interpret(f, [array, 4])
+ assert list(array) == list('abc'*4)
+ lltype.free(array, flavor='raw')
class TestOOtype(BaseTestRstr, OORtypeMixin):
pass
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit