forked from mia/Aegisub
lj_str.c: Remove special-case string interning fastpath
lj_str_new() had a separate fast-path and slow-path. This was bad because (a) the fast-path was complex and (b) the fast-path was actually slower than the slow-path in practice and (c) in practice it could cause confusing performance problems depending on the memory alignment of any often-reused string buffers in a program. This change specifically makes the 'life' benchmark faster and more robust to memory layout.
This commit is contained in:
parent
29fd12258f
commit
45cd713ef9
3 changed files with 90 additions and 41 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -22,7 +22,6 @@
|
||||||
*.obj
|
*.obj
|
||||||
*.opensdf
|
*.opensdf
|
||||||
*.orig
|
*.orig
|
||||||
*.patch
|
|
||||||
*.pch
|
*.pch
|
||||||
*.pdb
|
*.pdb
|
||||||
*.profdata
|
*.profdata
|
||||||
|
|
83
vendor/luajit/0001-lj_str.c-Remove-special-case-string-interning-fastpa.patch
vendored
Normal file
83
vendor/luajit/0001-lj_str.c-Remove-special-case-string-interning-fastpa.patch
vendored
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
From fcf86b84772735a3195af034d0bc7ed0f4106337 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Luke Gorrie <luke@snabb.co>
|
||||||
|
Date: Wed, 3 Jan 2018 13:04:56 +0000
|
||||||
|
Subject: [PATCH] lj_str.c: Remove special-case string interning fastpath
|
||||||
|
|
||||||
|
lj_str_new() had a separate fast-path and slow-path. This was bad
|
||||||
|
because (a) the fast-path was complex and (b) the fast-path was
|
||||||
|
actually slower than the slow-path in practice and (c) in practice it
|
||||||
|
could cause confusing performance problems depending on the memory
|
||||||
|
alignment of any often-reused string buffers in a program.
|
||||||
|
|
||||||
|
This change specifically makes the 'life' benchmark faster and more
|
||||||
|
robust to memory layout.
|
||||||
|
---
|
||||||
|
src/lj_str.c | 47 +++++++----------------------------------------
|
||||||
|
1 file changed, 7 insertions(+), 40 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/src/lj_str.c b/src/lj_str.c
|
||||||
|
index b32d1398..d8f314ae 100644
|
||||||
|
--- a/src/lj_str.c
|
||||||
|
+++ b/src/lj_str.c
|
||||||
|
@@ -37,27 +37,6 @@ int32_t lj_str_cmp(GCstr *a, GCstr *b)
|
||||||
|
return (int32_t)(a->len - b->len);
|
||||||
|
}
|
||||||
|
|
||||||
|
-/* Fast string data comparison. Caveat: unaligned access to 1st string! */
|
||||||
|
-static LJ_AINLINE int str_fastcmp(const char *a, const char *b, MSize len)
|
||||||
|
-{
|
||||||
|
- MSize i = 0;
|
||||||
|
- lua_assert(len > 0);
|
||||||
|
- lua_assert((((uintptr_t)a+len-1) & (LJ_PAGESIZE-1)) <= LJ_PAGESIZE-4);
|
||||||
|
- do { /* Note: innocuous access up to end of string + 3. */
|
||||||
|
- uint32_t v = lj_getu32(a+i) ^ *(const uint32_t *)(b+i);
|
||||||
|
- if (v) {
|
||||||
|
- i -= len;
|
||||||
|
-#if LJ_LE
|
||||||
|
- return (int32_t)i >= -3 ? (v << (32+(i<<3))) : 1;
|
||||||
|
-#else
|
||||||
|
- return (int32_t)i >= -3 ? (v >> (32+(i<<3))) : 1;
|
||||||
|
-#endif
|
||||||
|
- }
|
||||||
|
- i += 4;
|
||||||
|
- } while (i < len);
|
||||||
|
- return 0;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
/* Find fixed string p inside string s. */
|
||||||
|
const char *lj_str_find(const char *s, const char *p, MSize slen, MSize plen)
|
||||||
|
{
|
||||||
|
@@ -149,26 +128,14 @@ GCstr *lj_str_new(lua_State *L, const char *str, size_t lenx)
|
||||||
|
h ^= b; h -= lj_rol(b, 16);
|
||||||
|
/* Check if the string has already been interned. */
|
||||||
|
o = gcref(g->strhash[h & g->strmask]);
|
||||||
|
- if (LJ_LIKELY((((uintptr_t)str+len-1) & (LJ_PAGESIZE-1)) <= LJ_PAGESIZE-4)) {
|
||||||
|
- while (o != NULL) {
|
||||||
|
- GCstr *sx = gco2str(o);
|
||||||
|
- if (sx->len == len && str_fastcmp(str, strdata(sx), len) == 0) {
|
||||||
|
- /* Resurrect if dead. Can only happen with fixstring() (keywords). */
|
||||||
|
- if (isdead(g, o)) flipwhite(o);
|
||||||
|
- return sx; /* Return existing string. */
|
||||||
|
- }
|
||||||
|
- o = gcnext(o);
|
||||||
|
- }
|
||||||
|
- } else { /* Slow path: end of string is too close to a page boundary. */
|
||||||
|
- while (o != NULL) {
|
||||||
|
- GCstr *sx = gco2str(o);
|
||||||
|
- if (sx->len == len && memcmp(str, strdata(sx), len) == 0) {
|
||||||
|
- /* Resurrect if dead. Can only happen with fixstring() (keywords). */
|
||||||
|
- if (isdead(g, o)) flipwhite(o);
|
||||||
|
- return sx; /* Return existing string. */
|
||||||
|
- }
|
||||||
|
- o = gcnext(o);
|
||||||
|
+ while (o != NULL) {
|
||||||
|
+ GCstr *sx = gco2str(o);
|
||||||
|
+ if (sx->len == len && memcmp(str, strdata(sx), len) == 0) {
|
||||||
|
+ /* Resurrect if dead. Can only happen with fixstring() (keywords). */
|
||||||
|
+ if (isdead(g, o)) flipwhite(o);
|
||||||
|
+ return sx; /* Return existing string. */
|
||||||
|
}
|
||||||
|
+ o = gcnext(o);
|
||||||
|
}
|
||||||
|
/* Nope, create a new string. */
|
||||||
|
s = lj_mem_newt(L, sizeof(GCstr)+len+1, GCstr);
|
33
vendor/luajit/src/lj_str.c
vendored
33
vendor/luajit/src/lj_str.c
vendored
|
@ -43,27 +43,6 @@ int32_t LJ_FASTCALL lj_str_cmp(GCstr *a, GCstr *b)
|
||||||
return (int32_t)(a->len - b->len);
|
return (int32_t)(a->len - b->len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Fast string data comparison. Caveat: unaligned access to 1st string! */
|
|
||||||
static LJ_AINLINE int str_fastcmp(const char *a, const char *b, MSize len)
|
|
||||||
{
|
|
||||||
MSize i = 0;
|
|
||||||
lua_assert(len > 0);
|
|
||||||
lua_assert((((uintptr_t)a+len-1) & (LJ_PAGESIZE-1)) <= LJ_PAGESIZE-4);
|
|
||||||
do { /* Note: innocuous access up to end of string + 3. */
|
|
||||||
uint32_t v = lj_getu32(a+i) ^ *(const uint32_t *)(b+i);
|
|
||||||
if (v) {
|
|
||||||
i -= len;
|
|
||||||
#if LJ_LE
|
|
||||||
return (int32_t)i >= -3 ? (v << (32+(i<<3))) : 1;
|
|
||||||
#else
|
|
||||||
return (int32_t)i >= -3 ? (v >> (32+(i<<3))) : 1;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
i += 4;
|
|
||||||
} while (i < len);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Resize the string hash table (grow and shrink). */
|
/* Resize the string hash table (grow and shrink). */
|
||||||
void lj_str_resize(lua_State *L, MSize newmask)
|
void lj_str_resize(lua_State *L, MSize newmask)
|
||||||
{
|
{
|
||||||
|
@ -121,17 +100,6 @@ GCstr *lj_str_new(lua_State *L, const char *str, size_t lenx)
|
||||||
h ^= b; h -= lj_rol(b, 16);
|
h ^= b; h -= lj_rol(b, 16);
|
||||||
/* Check if the string has already been interned. */
|
/* Check if the string has already been interned. */
|
||||||
o = gcref(g->strhash[h & g->strmask]);
|
o = gcref(g->strhash[h & g->strmask]);
|
||||||
if (LJ_LIKELY((((uintptr_t)str+len-1) & (LJ_PAGESIZE-1)) <= LJ_PAGESIZE-4)) {
|
|
||||||
while (o != NULL) {
|
|
||||||
GCstr *sx = gco2str(o);
|
|
||||||
if (sx->len == len && str_fastcmp(str, strdata(sx), len) == 0) {
|
|
||||||
/* Resurrect if dead. Can only happen with fixstring() (keywords). */
|
|
||||||
if (isdead(g, o)) flipwhite(o);
|
|
||||||
return sx; /* Return existing string. */
|
|
||||||
}
|
|
||||||
o = gcnext(o);
|
|
||||||
}
|
|
||||||
} else { /* Slow path: end of string is too close to a page boundary. */
|
|
||||||
while (o != NULL) {
|
while (o != NULL) {
|
||||||
GCstr *sx = gco2str(o);
|
GCstr *sx = gco2str(o);
|
||||||
if (sx->len == len && memcmp(str, strdata(sx), len) == 0) {
|
if (sx->len == len && memcmp(str, strdata(sx), len) == 0) {
|
||||||
|
@ -141,7 +109,6 @@ GCstr *lj_str_new(lua_State *L, const char *str, size_t lenx)
|
||||||
}
|
}
|
||||||
o = gcnext(o);
|
o = gcnext(o);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
/* Nope, create a new string. */
|
/* Nope, create a new string. */
|
||||||
s = lj_mem_newt(L, sizeof(GCstr)+len+1, GCstr);
|
s = lj_mem_newt(L, sizeof(GCstr)+len+1, GCstr);
|
||||||
newwhite(g, s);
|
newwhite(g, s);
|
||||||
|
|
Loading…
Reference in a new issue