mirror of https://github.com/golang/go.git
runtime: faster string equality.
benchmark old ns/op new ns/op delta BenchmarkCompareStringEqual 51 35 -30.20% BenchmarkCompareStringIdentical 51 7 -85.71% BenchmarkCompareStringSameLength 25 18 -28.29% BenchmarkCompareStringDifferentLength 2 2 +1.46% R=golang-dev, rsc CC=golang-dev, remy https://golang.org/cl/6450092
This commit is contained in:
parent
ab058b3540
commit
77f3e189d2
|
|
@ -27,6 +27,7 @@ char *runtimeimport =
|
|||
"func @\"\".appendslice(@\"\".typ *byte, @\"\".x any, @\"\".y []any) (? any)\n"
|
||||
"func @\"\".appendstr(@\"\".typ *byte, @\"\".x []byte, @\"\".y string) (? []byte)\n"
|
||||
"func @\"\".cmpstring(? string, ? string) (? int)\n"
|
||||
"func @\"\".eqstring(? string, ? string) (? bool)\n"
|
||||
"func @\"\".slicestring(? string, ? int, ? int) (? string)\n"
|
||||
"func @\"\".slicestring1(? string, ? int) (? string)\n"
|
||||
"func @\"\".intstring(? int64) (? string)\n"
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ func appendslice(typ *byte, x any, y []any) any
|
|||
func appendstr(typ *byte, x []byte, y string) []byte
|
||||
|
||||
func cmpstring(string, string) int
|
||||
func eqstring(string, string) bool
|
||||
func slicestring(string, int, int) string
|
||||
func slicestring1(string, int) string
|
||||
func intstring(int64) string
|
||||
|
|
|
|||
|
|
@ -1021,27 +1021,34 @@ walkexpr(Node **np, NodeList **init)
|
|||
goto ret;
|
||||
}
|
||||
|
||||
// prepare for rewrite below
|
||||
if(n->etype == OEQ || n->etype == ONE) {
|
||||
// prepare for rewrite below
|
||||
n->left = cheapexpr(n->left, init);
|
||||
n->right = cheapexpr(n->right, init);
|
||||
}
|
||||
|
||||
// sys_cmpstring(s1, s2) :: 0
|
||||
r = mkcall("cmpstring", types[TINT], init,
|
||||
conv(n->left, types[TSTRING]),
|
||||
conv(n->right, types[TSTRING]));
|
||||
r = nod(n->etype, r, nodintconst(0));
|
||||
r = mkcall("eqstring", types[TBOOL], init,
|
||||
conv(n->left, types[TSTRING]),
|
||||
conv(n->right, types[TSTRING]));
|
||||
|
||||
// quick check of len before full compare for == or !=
|
||||
if(n->etype == OEQ || n->etype == ONE) {
|
||||
if(n->etype == OEQ)
|
||||
// quick check of len before full compare for == or !=
|
||||
if(n->etype == OEQ) {
|
||||
// len(left) == len(right) && eqstring(left, right)
|
||||
r = nod(OANDAND, nod(OEQ, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r);
|
||||
else
|
||||
} else {
|
||||
// len(left) != len(right) || !eqstring(left, right)
|
||||
r = nod(ONOT, r, N);
|
||||
r = nod(OOROR, nod(ONE, nod(OLEN, n->left, N), nod(OLEN, n->right, N)), r);
|
||||
}
|
||||
typecheck(&r, Erv);
|
||||
walkexpr(&r, nil);
|
||||
} else {
|
||||
// sys_cmpstring(s1, s2) :: 0
|
||||
r = mkcall("cmpstring", types[TINT], init,
|
||||
conv(n->left, types[TSTRING]),
|
||||
conv(n->right, types[TSTRING]));
|
||||
r = nod(n->etype, r, nodintconst(0));
|
||||
}
|
||||
|
||||
typecheck(&r, Erv);
|
||||
if(n->type->etype != TBOOL) fatal("cmp %T", n->type);
|
||||
r->type = n->type;
|
||||
|
|
|
|||
|
|
@ -324,6 +324,10 @@ runtime·strequal(bool *eq, uintptr s, void *a, void *b)
|
|||
*eq = false;
|
||||
return;
|
||||
}
|
||||
if(((String*)a)->str == ((String*)b)->str) {
|
||||
*eq = true;
|
||||
return;
|
||||
}
|
||||
runtime·memequal(eq, alen, ((String*)a)->str, ((String*)b)->str);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -204,6 +204,26 @@ func cmpstring(s1 String, s2 String) (v int32) {
|
|||
v = cmpstring(s1, s2);
|
||||
}
|
||||
|
||||
func eqstring(s1 String, s2 String) (v bool) {
|
||||
uint32 i, l;
|
||||
|
||||
if(s1.len != s2.len) {
|
||||
v = false;
|
||||
return;
|
||||
}
|
||||
if(s1.str == s2.str) {
|
||||
v = true;
|
||||
return;
|
||||
}
|
||||
l = s1.len;
|
||||
for(i=0; i<l; i++)
|
||||
if(s1.str[i] != s2.str[i]) {
|
||||
v = false;
|
||||
return;
|
||||
}
|
||||
v = true;
|
||||
}
|
||||
|
||||
int32
|
||||
runtime·strcmp(byte *s1, byte *s2)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,45 @@
|
|||
package runtime_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func BenchmarkCompareStringEqual(b *testing.B) {
|
||||
bytes := []byte("Hello Gophers!")
|
||||
s1, s2 := string(bytes), string(bytes)
|
||||
for i := 0; i < b.N; i++ {
|
||||
if s1 != s2 {
|
||||
b.Fatal("s1 != s2")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCompareStringIdentical(b *testing.B) {
|
||||
s1 := "Hello Gophers!"
|
||||
s2 := s1
|
||||
for i := 0; i < b.N; i++ {
|
||||
if s1 != s2 {
|
||||
b.Fatal("s1 != s2")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCompareStringSameLength(b *testing.B) {
|
||||
s1 := "Hello Gophers!"
|
||||
s2 := "Hello, Gophers"
|
||||
for i := 0; i < b.N; i++ {
|
||||
if s1 == s2 {
|
||||
b.Fatal("s1 == s2")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkCompareStringDifferentLength(b *testing.B) {
|
||||
s1 := "Hello Gophers!"
|
||||
s2 := "Hello, Gophers!"
|
||||
for i := 0; i < b.N; i++ {
|
||||
if s1 == s2 {
|
||||
b.Fatal("s1 == s2")
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue