diff options
| author | Brad Fitzpatrick <bradfitz@golang.org> | 2014-01-10 12:19:36 -0800 |
|---|---|---|
| committer | Brad Fitzpatrick <bradfitz@golang.org> | 2014-01-10 12:19:36 -0800 |
| commit | 258ed3f2265a41a46e936e884d8afd6e6f646973 (patch) | |
| tree | 3b57fa17c1c5e297a2c676804009709b9ea14bb8 /src/pkg/database/sql/convert_test.go | |
| parent | 3b8dfc32b3e75f128fa896c1bb9a70fca2da6dcb (diff) | |
| download | go-258ed3f2265a41a46e936e884d8afd6e6f646973.tar.xz | |
database/sql: avoiding fmt.Sprintf while scanning, avoid allocs with RawBytes
A user reported heavy contention on fmt's printer cache. Avoid
fmt.Sprint. We have to do reflection anyway, and there was
already an asString function to use strconv, so use it.
This CL also eliminates a redundant allocation + copy when
scanning into *[]byte (avoiding the intermediate string)
and avoids an extra alloc when assigning to a caller's RawBytes
(trying to reuse the caller's memory).
Fixes #7086
R=golang-codereviews, nightlyone
CC=golang-codereviews
https://golang.org/cl/50240044
Diffstat (limited to 'src/pkg/database/sql/convert_test.go')
| -rw-r--r-- | src/pkg/database/sql/convert_test.go | 48 |
1 files changed, 48 insertions, 0 deletions
diff --git a/src/pkg/database/sql/convert_test.go b/src/pkg/database/sql/convert_test.go index a39c2c54fb..aa0b6f116a 100644 --- a/src/pkg/database/sql/convert_test.go +++ b/src/pkg/database/sql/convert_test.go @@ -279,3 +279,51 @@ func TestValueConverters(t *testing.T) { } } } + +// Tests that assigning to RawBytes doesn't allocate (and also works). +func TestRawBytesAllocs(t *testing.T) { + buf := make(RawBytes, 10) + test := func(name string, in interface{}, want string) { + if err := convertAssign(&buf, in); err != nil { + t.Fatalf("%s: convertAssign = %v", name, err) + } + match := len(buf) == len(want) + if match { + for i, b := range buf { + if want[i] != b { + match = false + break + } + } + } + if !match { + t.Fatalf("%s: got %q (len %d); want %q (len %d)", name, buf, len(buf), want, len(want)) + } + } + n := testing.AllocsPerRun(100, func() { + test("uint64", uint64(12345678), "12345678") + test("uint32", uint32(1234), "1234") + test("uint16", uint16(12), "12") + test("uint8", uint8(1), "1") + test("uint", uint(123), "123") + test("int", int(123), "123") + test("int8", int8(1), "1") + test("int16", int16(12), "12") + test("int32", int32(1234), "1234") + test("int64", int64(12345678), "12345678") + test("float32", float32(1.5), "1.5") + test("float64", float64(64), "64") + test("bool", false, "false") + }) + if n > 0.5 { + t.Fatalf("allocs = %v; want 0", n) + } + + // This one involves a convT2E allocation, string -> interface{} + n = testing.AllocsPerRun(100, func() { + test("string", "foo", "foo") + }) + if n > 1.5 { + t.Fatalf("allocs = %v; want max 1", n) + } +} |
