aboutsummaryrefslogtreecommitdiff
path: root/src/pkg/runtime
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2014-04-03 19:05:17 -0400
committerRuss Cox <rsc@golang.org>2014-04-03 19:05:17 -0400
commitf5f5a8b6209f84961687d993b93ea0d397f5d5bf (patch)
tree69a2398e1615a1d8d7c4aac5725274a414eb3eaf /src/pkg/runtime
parent0e1b6bb5470701090cd8dadacc6eb5074a86cf82 (diff)
downloadgo-f5f5a8b6209f84961687d993b93ea0d397f5d5bf.tar.xz
cmd/gc, runtime: optimize map[string] lookup from []byte key
Brad has been asking for this for a while. I have resisted because I wanted to find a more general way to do this, one that would keep the performance of code introducing variables the same as the performance of code that did not. (See golang.org/issue/3512#c20). I have not found the more general way, and recent changes to remove ambiguously live temporaries have blown away the property I was trying to preserve, so that's no longer a reason not to make the change. Fixes #3512. LGTM=iant R=iant CC=bradfitz, golang-codereviews, khr, r https://golang.org/cl/83740044
Diffstat (limited to 'src/pkg/runtime')
-rw-r--r--src/pkg/runtime/map_test.go37
-rw-r--r--src/pkg/runtime/string.goc19
2 files changed, 56 insertions, 0 deletions
diff --git a/src/pkg/runtime/map_test.go b/src/pkg/runtime/map_test.go
index 9c703ba362..e4e8383493 100644
--- a/src/pkg/runtime/map_test.go
+++ b/src/pkg/runtime/map_test.go
@@ -438,3 +438,40 @@ func TestMapIterOrder(t *testing.T) {
}
}
}
+
+func TestMapStringBytesLookup(t *testing.T) {
+ // Use large string keys to avoid small-allocation coalescing,
+ // which can cause AllocsPerRun to report lower counts than it should.
+ m := map[string]int{
+ "1000000000000000000000000000000000000000000000000": 1,
+ "2000000000000000000000000000000000000000000000000": 2,
+ }
+ buf := []byte("1000000000000000000000000000000000000000000000000")
+ if x := m[string(buf)]; x != 1 {
+ t.Errorf(`m[string([]byte("1"))] = %d, want 1`, x)
+ }
+ buf[0] = '2'
+ if x := m[string(buf)]; x != 2 {
+ t.Errorf(`m[string([]byte("2"))] = %d, want 2`, x)
+ }
+
+ var x int
+ n := testing.AllocsPerRun(100, func() {
+ x += m[string(buf)]
+ })
+ if n != 0 {
+ t.Errorf("AllocsPerRun for m[string(buf)] = %v, want 0", n)
+ }
+
+ x = 0
+ n = testing.AllocsPerRun(100, func() {
+ y, ok := m[string(buf)]
+ if !ok {
+ panic("!ok")
+ }
+ x += y
+ })
+ if n != 0 {
+ t.Errorf("AllocsPerRun for x,ok = m[string(buf)] = %v, want 0", n)
+ }
+}
diff --git a/src/pkg/runtime/string.goc b/src/pkg/runtime/string.goc
index 89b9130c08..97a69d07b1 100644
--- a/src/pkg/runtime/string.goc
+++ b/src/pkg/runtime/string.goc
@@ -294,6 +294,25 @@ func slicebytetostring(b Slice) (s String) {
runtime·memmove(s.str, b.array, s.len);
}
+func slicebytetostringtmp(b Slice) (s String) {
+ void *pc;
+
+ if(raceenabled) {
+ pc = runtime·getcallerpc(&b);
+ runtime·racereadrangepc(b.array, b.len, pc, runtime·slicebytetostringtmp);
+ }
+
+ // Return a "string" referring to the actual []byte bytes.
+ // This is only for use by internal compiler optimizations
+ // that know that the string form will be discarded before
+ // the calling goroutine could possibly modify the original
+ // slice or synchronize with another goroutine.
+ // Today, the only such case is a m[string(k)] lookup where
+ // m is a string-keyed map and k is a []byte.
+ s.str = b.array;
+ s.len = b.len;
+}
+
func stringtoslicebyte(s String) (b Slice) {
uintptr cap;