Commit 77f3e189 authored by Rémy Oudompheng's avatar Rémy Oudompheng

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
parent ab058b35
......@@ -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)
{
......
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")
}
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment