]> Cypherpunks repositories - gostls13.git/commitdiff
runtime: special-case append([]byte, string) for small strings
authorRob Pike <r@golang.org>
Sat, 2 Mar 2013 00:41:39 +0000 (16:41 -0800)
committerRob Pike <r@golang.org>
Sat, 2 Mar 2013 00:41:39 +0000 (16:41 -0800)
Also make the crossover point an architecture-dependent constant,
although it's the same everywhere for now.

BenchmarkAppendStr1Byte            416          145  -65.14%
BenchmarkAppendStr4Bytes           743          217  -70.79%
BenchmarkAppendStr8Bytes           421          270  -35.87%
BenchmarkAppendStr16Bytes          415          403   -2.89%
BenchmarkAppendStr32Bytes          415          391   -5.78%

R=golang-dev, iant
CC=golang-dev
https://golang.org/cl/7459044

src/pkg/runtime/append_test.go
src/pkg/runtime/arch_386.h
src/pkg/runtime/arch_amd64.h
src/pkg/runtime/arch_arm.h
src/pkg/runtime/slice.c

index e9fc4a7901e427b72ed8e390cb01b58f511d8401..6eb901699b8ed8d302a0830fb8ce871ae2710c4b 100644 (file)
@@ -52,6 +52,38 @@ func BenchmarkAppend32Bytes(b *testing.B) {
        benchmarkAppendBytes(b, 32)
 }
 
+func benchmarkAppendStr(b *testing.B, str string) {
+       b.StopTimer()
+       x := make([]byte, 0, N)
+       b.StartTimer()
+       for i := 0; i < b.N; i++ {
+               x = x[0:0]
+               for j := 0; j < N; j++ {
+                       x = append(x, str...)
+               }
+       }
+}
+
+func BenchmarkAppendStr1Byte(b *testing.B) {
+       benchmarkAppendStr(b, "1")
+}
+
+func BenchmarkAppendStr4Bytes(b *testing.B) {
+       benchmarkAppendStr(b, "1234")
+}
+
+func BenchmarkAppendStr8Bytes(b *testing.B) {
+       benchmarkAppendStr(b, "12345678")
+}
+
+func BenchmarkAppendStr16Bytes(b *testing.B) {
+       benchmarkAppendStr(b, "1234567890123456")
+}
+
+func BenchmarkAppendStr32Bytes(b *testing.B) {
+       benchmarkAppendStr(b, "12345678901234567890123456789012")
+}
+
 func BenchmarkAppendSpecialCase(b *testing.B) {
        b.StopTimer()
        x := make([]int, 0, N)
index cb9d64a70cfa64404414cb58884e4c09bfa26ac3..4df795f712cd422da5abed062573a5882b4f5e4c 100644 (file)
@@ -1,5 +1,6 @@
 enum {
        thechar = '8',
        BigEndian = 0,
-       CacheLineSize = 64
+       CacheLineSize = 64,
+       appendCrossover = 16
 };
index 35ed1560a277416fa34d905b590fa9f9282c2c71..e83dc91056175860631f2ebdbebb27d87e26d91f 100644 (file)
@@ -1,5 +1,6 @@
 enum {
        thechar = '6',
        BigEndian = 0,
-       CacheLineSize = 64
+       CacheLineSize = 64,
+       appendCrossover = 16
 };
index 21dc1a692cddee74d522e5c351af6ace8a7f3f9c..f6af58514fcf4d702e532b59e6c607751ef1d999 100644 (file)
@@ -1,5 +1,6 @@
 enum {
        thechar = '5',
        BigEndian = 0,
-       CacheLineSize = 32
+       CacheLineSize = 32,
+       appendCrossover = 16
 };
index b517c3aa33f7d3bfaf8640282e583280a392e874..354c54c865fbe9c91c2419d92a8eecc1a48d3dcd 100644 (file)
@@ -110,8 +110,7 @@ runtime·appendslice(SliceType *t, Slice x, Slice y, Slice ret)
        p = ret.array+ret.len*w;
        q = y.array;
        w *= y.len;
-       // TODO: make 16 an architecture-dependent constant.
-       if(w <= 16) { // 16 empirically tested as approximate crossover on amd64.
+       if(w <= appendCrossover) {
                if(p <= q || w <= p-q) // No overlap.
                        while(w-- > 0)
                                *p++ = *q++;
@@ -136,6 +135,8 @@ runtime·appendstr(SliceType *t, Slice x, String y, Slice ret)
 {
        intgo m;
        void *pc;
+       uintptr w;
+       uint8 *p, *q;
 
        m = x.len+y.len;
 
@@ -158,7 +159,16 @@ runtime·appendstr(SliceType *t, Slice x, String y, Slice ret)
                        runtime·racewriterangepc(ret.array+ret.len, y.len, 1, pc, runtime·appendstr);
        }
 
-       runtime·memmove(ret.array + ret.len, y.str, y.len);
+       // Small appends can avoid the overhead of memmove.
+       w = y.len;
+       p = ret.array+ret.len;
+       q = y.str;
+       if(w <= appendCrossover) {
+               while(w-- > 0)
+                       *p++ = *q++;
+       } else {
+               runtime·memmove(p, q, w);
+       }
        ret.len += y.len;
        FLUSH(&ret);
 }