Author: Armin Rigo <ar...@tunes.org> Branch: Changeset: r92618:120728f3d439 Date: 2017-10-06 02:58 +0200 http://bitbucket.org/pypy/pypy/changeset/120728f3d439/
Log: Optimize the case of siphash computing the hash of a latin1 unicode string diff --git a/rpython/rlib/rsiphash.py b/rpython/rlib/rsiphash.py --- a/rpython/rlib/rsiphash.py +++ b/rpython/rlib/rsiphash.py @@ -11,6 +11,7 @@ from rpython.rlib.objectmodel import not_rpython, always_inline from rpython.rlib.objectmodel import we_are_translated, dont_inline from rpython.rlib.objectmodel import keepalive_until_here +from rpython.rlib.objectmodel import specialize from rpython.rlib import rgc, jit, rposix from rpython.rlib.rarithmetic import r_uint64, r_uint32, r_uint from rpython.rlib.rawstorage import misaligned_is_fine @@ -26,9 +27,11 @@ return x def _le32toh(x): return x + BIG_ENDIAN = False else: _le64toh = rarithmetic.byteswap _le32toh = rarithmetic.byteswap + BIG_ENDIAN = True def _decode64(s): return (r_uint64(ord(s[0])) | @@ -151,23 +154,20 @@ else: # NOTE: a latin-1 unicode string must have the same hash as the # corresponding byte string. If the unicode is all within - # 0-255, then we need to allocate a byte buffer and copy the - # latin-1 encoding in it manually. Note also that we give a + # 0-255, then we call _siphash24() with a special argument that + # will make it load only one byte for every unicode char. + # Note also that we give a # different hash result than CPython on ucs4 platforms, for # unicode strings where CPython uses 2 bytes per character. + addr = rstr._get_raw_buf_unicode(rstr.UNICODE, ll_s, 0) + SZ = rffi.sizeof(rstr.UNICODE.chars.OF) for i in range(length): if ord(ll_s.chars[i]) > 0xFF: - addr = rstr._get_raw_buf_unicode(rstr.UNICODE, ll_s, 0) - length *= rffi.sizeof(rstr.UNICODE.chars.OF) + length *= SZ break else: - p = lltype.malloc(rffi.CCHARP.TO, length, flavor='raw') - i = 0 - while i < length: - p[i] = chr(ord(ll_s.chars[i])) - i += 1 - x = _siphash24(llmemory.cast_ptr_to_adr(p), length) - lltype.free(p, flavor='raw') + x = _siphash24(addr, length, SZ) + keepalive_until_here(ll_s) return intmask(x) x = _siphash24(addr, length) keepalive_until_here(ll_s) @@ -215,7 +215,8 @@ @rgc.no_collect -def _siphash24(addr_in, size): +@specialize.arg(2) +def _siphash24(addr_in, size, SZ=1): """Takes an address pointer and a size. Returns the hash as a r_uint64, which can then be casted to the expected type.""" @@ -227,10 +228,14 @@ v2 = k0 ^ magic2 v3 = k1 ^ magic3 - direct = (misaligned_is_fine or + direct = (SZ == 1) and (misaligned_is_fine or (rffi.cast(lltype.Signed, addr_in) & 7) == 0) - index = 0 + if BIG_ENDIAN: + index = SZ - 1 + else: + index = 0 if direct: + assert SZ == 1 while size >= 8: mi = llop.raw_load(rffi.ULONGLONG, addr_in, index) mi = _le64toh(mi) @@ -242,30 +247,30 @@ else: while size >= 8: mi = ( - r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index)) | - r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 1)) << 8 | - r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 2)) << 16 | - r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 3)) << 24 | - r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 4)) << 32 | - r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 5)) << 40 | - r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 6)) << 48 | - r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 7)) << 56 + r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index)) | + r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 1*SZ)) << 8 | + r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 2*SZ)) << 16 | + r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 3*SZ)) << 24 | + r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 4*SZ)) << 32 | + r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 5*SZ)) << 40 | + r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 6*SZ)) << 48 | + r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 7*SZ)) << 56 ) size -= 8 - index += 8 + index += 8*SZ v3 ^= mi v0, v1, v2, v3 = _double_round(v0, v1, v2, v3) v0 ^= mi t = r_uint64(0) if size == 7: - t = r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 6)) << 48 + t = r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 6*SZ)) << 48 size = 6 if size == 6: - t |= r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 5)) << 40 + t |= r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 5*SZ)) << 40 size = 5 if size == 5: - t |= r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 4)) << 32 + t |= r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 4*SZ)) << 32 size = 4 if size == 4: if direct: @@ -273,13 +278,13 @@ t |= r_uint64(v) size = 0 else: - t |= r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 3)) << 24 + t |= r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 3*SZ))<< 24 size = 3 if size == 3: - t |= r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 2)) << 16 + t |= r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 2*SZ)) << 16 size = 2 if size == 2: - t |= r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 1)) << 8 + t |= r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index + 1*SZ)) << 8 size = 1 if size == 1: t |= r_uint64(llop.raw_load(rffi.UCHAR, addr_in, index)) _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit