Vladimir Kuzmin would like Matthew Dempsky and Giovanni Bajo to review this change.
net/ip: IPv4 ip.net.String() is not efficient
Fixes #24306
On a scale 1000 IPs, pprof reported it as a one of the most expensive operation.
This is why I started to look at implementation and found that it can be
more efficient. This is optimiztion only for IPv4. It allocates buffer only once
and writes converted octets into given buffer.
../bin/go test -bench=BenchmarkIPString -run=^ip ./net/
Before fix:
pkg: net
BenchmarkIPString/IPv4-8 5000000 271 ns/op
BenchmarkIPString/IPv6-8 1000000 1287 ns/op
PASS
ok net 2.986s
After fix:
pkg: net
BenchmarkIPString/IPv4-8 10000000 155 ns/op
BenchmarkIPString/IPv6-8 1000000 1189 ns/op
PASS
ok net 2.938s
Change-Id: I4e2d30d364e78183d55a42907d277744494b6df3
---
M src/net/ip.go
M src/net/ip_test.go
2 files changed, 46 insertions(+), 5 deletions(-)
diff --git a/src/net/ip.go b/src/net/ip.go
index 6b7ba4c..03c3bf6 100644
--- a/src/net/ip.go
+++ b/src/net/ip.go
@@ -260,6 +260,25 @@
return out
}
+// ubtoa converts unsigned byte to integer string. It writes result to destination
+// buffer and returns number of written bytes. Caller guarante that dst has enough size
+// and start is valid start index.
+func ubtoa(dst []byte, start uint, v byte) uint {
+ if v < 10 {
+ dst[start] = byte(v + '0')
+ return 1
+ } else if v < 100 {
+ dst[start+1] = byte(v%10 + '0')
+ dst[start] = byte(v/10 + '0')
+ return 2
+ }
+
+ dst[start+2] = byte(v%10 + '0')
+ dst[start+1] = byte((v/10)%10 + '0')
+ dst[start] = byte(v/100 + '0')
+ return 3
+}
+
// String returns the string form of the IP address ip.
// It returns one of 4 forms:
// - "<nil>", if ip has length 0
@@ -275,10 +294,23 @@
// If IPv4, use dotted notation.
if p4 := p.To4(); len(p4) == IPv4len {
- return uitoa(uint(p4[0])) + "." +
- uitoa(uint(p4[1])) + "." +
- uitoa(uint(p4[2])) + "." +
- uitoa(uint(p4[3]))
+ const maxIPv4StringLen = len("255.255.255.255")
+ byteArray := make([]byte, maxIPv4StringLen)
+
+ n := ubtoa(byteArray, 0, p4[0])
+ byteArray[n] = '.'
+ n++
+
+ n += ubtoa(byteArray, n, p4[1])
+ byteArray[n] = '.'
+ n++
+
+ n += ubtoa(byteArray, n, p4[2])
+ byteArray[n] = '.'
+ n++
+
+ n += ubtoa(byteArray, n, p4[3])
+ return string(byteArray[:n])
}
if len(p) != IPv6len {
return "?" + hexString(ip)
diff --git a/src/net/ip_test.go b/src/net/ip_test.go
index ad13388..044dc0f 100644
--- a/src/net/ip_test.go
+++ b/src/net/ip_test.go
@@ -252,9 +252,18 @@
func BenchmarkIPString(b *testing.B) {
testHookUninstaller.Do(uninstallTestHooks)
+ b.Run("IPv4", func(b *testing.B) {
+ benchmarkIPString(b, IPv4len)
+ })
+ b.Run("IPv6", func(b *testing.B) {
+ benchmarkIPString(b, IPv6len)
+ })
+}
+
+func benchmarkIPString(b *testing.B, size int) {
for i := 0; i < b.N; i++ {
for _, tt := range ipStringTests {
- if tt.in != nil {
+ if tt.in != nil && len(tt.in) == size {
sink = tt.in.String()
}
}
To view, visit change 99395. To unsubscribe, or for help writing mail filters, visit settings.
3 comments:
Patch Set #1, Line 7: IPv4 ip.net.String() is not efficient
this doesn’t accurately describe what this change does.
On a scale 1000 IPs, pprof reported it as a one of the most expensive operation.
This is why I started to look at implementation and found that it can be
more efficient.
This part isn’t necessary.
I would describe what it currently does and what you are doing to make it more efficient. Also why uitoa can’t be optimized in favor of adding a new function.
Patch Set #1, Line 298: byteArray
this is a byte slice, not a byte array.
I would rename this just `b`
To view, visit change 99395. To unsubscribe, or for help writing mail filters, visit settings.
2 comments:
On a scale 1000 IPs, pprof reported it as a one of the most expensive operation.
This is why I started to look at implementation and found that it can be
more efficient.
This part isn’t necessary. […]
Will fix the comment and title. uitoa doesn't accept destination buffer and returns string. It means it can't be optimized for this case. This is pretty specific case, I want function that works with byte array and uses caller's buffer.
Patch Set #1, Line 298: byteArray
this is a byte slice, not a byte array. […]
Done
To view, visit change 99395. To unsubscribe, or for help writing mail filters, visit settings.
Vladimir Kuzmin uploaded patch set #2 to this change.
net/ip: Optimize ip.net.String() for IPv4
This is optimization only for IPv4. It allocates result buffer as array
of bytes only once and writes octets as dotted decimal into given buffer.
At the end it converts given array to string.
Benchmark shows 75% performance improvement:
../bin/go test -bench=BenchmarkIPString -run=^ip ./net/
Before fix:
pkg: net
BenchmarkIPString/IPv4-8 5000000 271 ns/op
BenchmarkIPString/IPv6-8 1000000 1287 ns/op
PASS
ok net 2.986s
After fix:
pkg: net
BenchmarkIPString/IPv4-8 10000000 155 ns/op
BenchmarkIPString/IPv6-8 1000000 1189 ns/op
PASS
ok net 2.938s
Fixes #24306
Change-Id: I4e2d30d364e78183d55a42907d277744494b6df3
---
M src/net/ip.go
M src/net/ip_test.go
2 files changed, 46 insertions(+), 5 deletions(-)
To view, visit change 99395. To unsubscribe, or for help writing mail filters, visit settings.
2 comments:
Patch Set #1, Line 7: Optimize ip.net.String() for IPv4
this doesn’t accurately describe what this change does.
Done
At the end it converts given array to string.
Benchmark shows
Will fix the comment and title. uitoa doesn't accept destination buffer and returns string. […]
Done
To view, visit change 99395. To unsubscribe, or for help writing mail filters, visit settings.
For optimization changes we usually run each benchmark multiple times before and after the CL using -count, to reduce noise. You can put the results into a file, like this:
go test -bench=BenchmarkIPString -count 20 > old.txt
go test -bench=BenchmarkIPString -count 20 > new.txt
and then compare the results using benchstat:
$ benchstat old.txt new.txt
and finally put the benchstat output in the commit message.
Patch Set 2:
$ benchstat old.txt new.txt
and finally put the benchstat output in the commit message.
Thanks, this is exactly what I wanted to have.
benchstat oldip2str.txt newip2str.txt
name old time/op new time/op delta
IPString/IPv4-8 273ns ± 8% 143ns ± 8% -47.83% (p=0.000 n=20+20)
IPString/IPv6-8 1.30µs ± 6% 1.11µs ± 3% -14.55% (p=0.000 n=20+18)
15% improvement for IPv6 is not expected. I can explain it that both are running in the same Benchmark and reduced allocation improvement/GC for IPv4 has positive impact on IPv6.
Vladimir Kuzmin uploaded patch set #3 to this change.
net/ip: Optimize ip.net.String() for IPv4
This is optimization only for IPv4. It allocates result buffer as array
of bytes only once and writes octets as dotted decimal into given buffer.
At the end it converts given array to string.
Benchmark shows performance improvement:
../bin/go test -bench=BenchmarkIPString -run=^ip ./net/ -count 20
benchstat oldip2str.txt newip2str.txt
name old time/op new time/op delta
IPString/IPv4-8 273ns ± 8% 143ns ± 8% -47.83% (p=0.000 n=20+20)
IPString/IPv6-8 1.30µs ± 6% 1.11µs ± 3% -14.55% (p=0.000 n=20+18)
Fixes #24306
Change-Id: I4e2d30d364e78183d55a42907d277744494b6df3
---
M src/net/ip.go
M src/net/ip_test.go
2 files changed, 46 insertions(+), 5 deletions(-)
To view, visit change 99395. To unsubscribe, or for help writing mail filters, visit settings.
3 comments:
Patch Set #3, Line 7: net/ip: Optimize ip.net.String() for IPv4
Per https://github.com/golang/go/wiki/CommitMessage this would be:
net: optimize IP.String
(The package is "net")
Patch Set #3, Line 15: ../bin/go test -bench=BenchmarkIPString -run=^ip ./net/ -count 20
no need for this line.
IPString/IPv4-8 273ns ± 8% 143ns ± 8% -47.83% (p=0.000 n=20+20)
IPString/IPv6-8 1.30µs ± 6% 1.11µs ± 3% -14.55% (p=0.000 n=20+18)
can you include allocation numbers?
Add b.ReportAllocs() to the benchmark.
To view, visit change 99395. To unsubscribe, or for help writing mail filters, visit settings.
3 comments:
Patch Set #3, Line 264: // buffer and returns number of written bytes. Caller guarante that dst has enough size
typo: guarantees
Patch Set #3, Line 266: func ubtoa(dst []byte, start uint, v byte) uint {
Don't use uint. It's rarely used in Go. Just change both to "int".
For docs, I'd just write:
// ubtoa encodes the string form of the integer v to dst[start:] and
// returns the number of bytes written to dst. The caller must ensure
// that dst has sufficient length.
Patch Set #3, Line 300: n := ubtoa(b, 0, p4[0])
you could be consistent here, like:
var n int
n += ubtoa(b, n, p4[0])
Like the lines below.
To view, visit change 99395. To unsubscribe, or for help writing mail filters, visit settings.
Vladimir Kuzmin uploaded patch set #4 to this change.
net/ip: Optimize ip.net.String() for IPv4
This is optimization only for IPv4. It allocates result buffer as array
of bytes only once and writes octets as dotted decimal into given buffer.
At the end it converts given array to string.
Benchmark shows performance improvement:
name old time/op new time/op delta
IPString/IPv4-8 284ns ± 4% 144ns ± 6% -49.35% (p=0.000 n=19+17)
IPString/IPv6-8 1.34µs ± 5% 1.14µs ± 5% -14.37% (p=0.000 n=19+20)
name old alloc/op new alloc/op delta
IPString/IPv4-8 24.0B ± 0% 16.0B ± 0% -33.33% (p=0.000 n=20+20)
IPString/IPv6-8 232B ± 0% 224B ± 0% -3.45% (p=0.000 n=20+20)
name old allocs/op new allocs/op delta
IPString/IPv4-8 3.00 ± 0% 2.00 ± 0% -33.33% (p=0.000 n=20+20)
IPString/IPv6-8 12.0 ± 0% 11.0 ± 0% -8.33% (p=0.000 n=20+20)
Fixes #24306
Change-Id: I4e2d30d364e78183d55a42907d277744494b6df3
---
M src/net/ip.go
M src/net/ip_test.go
2 files changed, 49 insertions(+), 5 deletions(-)
To view, visit change 99395. To unsubscribe, or for help writing mail filters, visit settings.
4 comments:
name old alloc/op new alloc/op delta
IPString/IPv4-8 24.0B ± 0% 16.0B ± 0% -33.33% (p=0.000 n=20
can you include allocation numbers? […]
Done
Patch Set #3, Line 264: // returns the number of bytes written to dst. The caller must ensure
typo: guarantees
Done
Patch Set #3, Line 266: func ubtoa(dst []byte, start int, v byte) int {
Don't use uint. It's rarely used in Go. Just change both to "int". […]
I like your word flow.
Patch Set #3, Line 300: n := ubtoa(b, 0, p4[0])
you could be consistent here, like: […]
I considered it when wrote the code, but the version I have hides type of "n", this is deducted by compiler from context. And for instance, after I changed start and return type of ubtoa to `int' (as you suggested), this code is not affected. So, in fact we could even change it to uint8 if need extra efficiency and again, this part is not affected.
Let me know if you have concern though.
To view, visit change 99395. To unsubscribe, or for help writing mail filters, visit settings.
1 comment:
Patch Set #4, Line 266: func ubtoa(dst []byte, start int, v byte) int {
strconv/itoa.go uses lookup "table" for small integers, have you testes something similar?
If this is faster, perhaps we should update itoa?
To view, visit change 99395. To unsubscribe, or for help writing mail filters, visit settings.
Vladimir Kuzmin uploaded patch set #5 to this change.
net: Optimize ip.net.String() for IPv4
This is optimization only for IPv4. It allocates result buffer as array
of bytes only once and writes octets as dotted decimal into given buffer.
At the end it converts given array to string.
Benchmark shows performance improvement:
name old time/op new time/op delta
IPString/IPv4-8 284ns ± 4% 144ns ± 6% -49.35% (p=0.000 n=19+17)
IPString/IPv6-8 1.34µs ± 5% 1.14µs ± 5% -14.37% (p=0.000 n=19+20)
name old alloc/op new alloc/op delta
IPString/IPv4-8 24.0B ± 0% 16.0B ± 0% -33.33% (p=0.000 n=20+20)
IPString/IPv6-8 232B ± 0% 224B ± 0% -3.45% (p=0.000 n=20+20)
name old allocs/op new allocs/op delta
IPString/IPv4-8 3.00 ± 0% 2.00 ± 0% -33.33% (p=0.000 n=20+20)
IPString/IPv6-8 12.0 ± 0% 11.0 ± 0% -8.33% (p=0.000 n=20+20)
Fixes #24306
Change-Id: I4e2d30d364e78183d55a42907d277744494b6df3
---
M src/net/ip.go
M src/net/ip_test.go
2 files changed, 49 insertions(+), 5 deletions(-)
To view, visit change 99395. To unsubscribe, or for help writing mail filters, visit settings.
3 comments:
Patch Set #3, Line 7: net: Optimize ip.net.String() for IPv4
Per https://github.com/golang/go/wiki/CommitMessage this would be: […]
Done
Patch Set #3, Line 15: name old time/op new time/op delta
no need for this line.
Patch Set #4, Line 266: func ubtoa(dst []byte, start int, v byte) int {
strconv/itoa.go uses lookup "table" for small integers, have you testes something similar? […]
ubtoa covers a specific case and use single buffer for 4 numbers in a range 0-255 separated with "." as separator. This is why this is faster than any other standard-generic function that doesn't work with external buffer.
Table for 0-255 could be a little bit faster than (v/10)%10 +'0') by the cost of memory. During implementation I looked at itoa and its tables:
// small returns the string for an i with 0 <= i < nSmalls.
func small(i int) string {
off := 0
if i < 10 {
off = 1
}
return smallsString[i*2+off : i*2+2]
}
I don't think namely this is a something that can give a gain for ip.String(). Anyway, for this CL I don't want to use table, but code optimization only.
Looking at itoa - probably we could optimize something there as well but as a separate issue. The net.IP optimization is from my real-life project problem, I found with pprof that it was too expensive (more than I expected) and I found that original implementation was too naive for standard method.
To view, visit change 99395. To unsubscribe, or for help writing mail filters, visit settings.
1 comment:
Patch Set #4, Line 266: func ubtoa(dst []byte, start int, v byte) int {
ubtoa covers a specific case and use single buffer for 4 numbers in a range 0-255 separated with ". […]
I also don’t think a lookup table is necessary at this stage.
The code that Vladimir has written already gives a substantial improvement in performance with a reduction in allocs. I’d say this is a win for now.
Nice work.
To view, visit change 99395. To unsubscribe, or for help writing mail filters, visit settings.
1 comment:
Patch Set #4, Line 266: func ubtoa(dst []byte, start int, v byte) int {
I also don’t think a lookup table is necessary at this stage. […]
btw, I tried to adopt smallsString string from itoa, it works only for numbers <100. In my case, I need bytes, not a string and this is why I read it as: smallsString[v*2] and smallsString[v*2 +1], it's 15% slower.
Frankly, I don't follow how appeared that smallsString are good for itoa, maybe smallsString[i*2+off : i*2+2] is doing some copy on write and avoids new string allocation. Anyway, on this particular case this is useless.
To view, visit change 99395. To unsubscribe, or for help writing mail filters, visit settings.
1 comment:
Patch Set #5, Line 298: b := make([]byte, maxIPv4StringLen)
How about strings.Builder?
You allocate the []byte here, and then again below when converting to string.
To view, visit change 99395. To unsubscribe, or for help writing mail filters, visit settings.
1 comment:
Patch Set #5, Line 298: b := make([]byte, maxIPv4StringLen)
How about strings.Builder? […]
Hmm. I see the compiler has gotten smart enough now that it realizes b does not escape and does the string conversation without allocating+copying.
Disregard my comment.
To view, visit change 99395. To unsubscribe, or for help writing mail filters, visit settings.
1 comment:
Patch Set #5, Line 298: b := make([]byte, maxIPv4StringLen)
Hmm. […]
The net package is low in the dependency chart, so it can't depend on many things we otherwise take for granted (like strconv).
To view, visit change 99395. To unsubscribe, or for help writing mail filters, visit settings.
Please advise who can run "Run-TryBot", necessary step as I understand. Thanks you all for a useful feedback, I learn from it!
1 comment:
Patch Set #5, Line 298: b := make([]byte, maxIPv4StringLen)
The net package is low in the dependency chart, so it can't depend on many things we otherwise take […]
I would be happy to see the better solution, even it means external dependency, we may always extract (copy-paste:) idea from the good package. But as Joe mentioned, compiler likes "local make". To confirm, I tried [15]bytes buffer at method (and then pointer to buffer at ubtoa), it was slower. Joe's observation that conversion to string uses buffer w/o copy explains it.
To view, visit change 99395. To unsubscribe, or for help writing mail filters, visit settings.
Patch set 5:Run-TryBot +1
TryBots are happy.
Patch set 5:TryBot-Result +1
Patch set 5:Code-Review +2
Brad Fitzpatrick uploaded patch set #6 to the change originally created by Vladimir Kuzmin.
net: optimize IP.String for IPv4
This is optimization only for IPv4. It allocates result buffer as array
of bytes only once and writes octets as dotted decimal into given buffer.
At the end it converts given array to string.
Benchmark shows performance improvement:
name old time/op new time/op delta
IPString/IPv4-8 284ns ± 4% 144ns ± 6% -49.35% (p=0.000 n=19+17)
IPString/IPv6-8 1.34µs ± 5% 1.14µs ± 5% -14.37% (p=0.000 n=19+20)
name old alloc/op new alloc/op delta
IPString/IPv4-8 24.0B ± 0% 16.0B ± 0% -33.33% (p=0.000 n=20+20)
IPString/IPv6-8 232B ± 0% 224B ± 0% -3.45% (p=0.000 n=20+20)
name old allocs/op new allocs/op delta
IPString/IPv4-8 3.00 ± 0% 2.00 ± 0% -33.33% (p=0.000 n=20+20)
IPString/IPv6-8 12.0 ± 0% 11.0 ± 0% -8.33% (p=0.000 n=20+20)
Fixes #24306
Change-Id: I4e2d30d364e78183d55a42907d277744494b6df3
---
M src/net/ip.go
M src/net/ip_test.go
2 files changed, 49 insertions(+), 5 deletions(-)
To view, visit change 99395. To unsubscribe, or for help writing mail filters, visit settings.
Brad Fitzpatrick uploaded patch set #7 to the change originally created by Vladimir Kuzmin.
net: optimize IP.String for IPv4
This is optimization is only for IPv4. It allocates a result buffer and
writes the IPv4 octets as dotted decimal into it before converting
it to a string just once, reducing allocations.
Benchmark shows performance improvement:
name old time/op new time/op delta
IPString/IPv4-8 284ns ± 4% 144ns ± 6% -49.35% (p=0.000 n=19+17)
IPString/IPv6-8 1.34µs ± 5% 1.14µs ± 5% -14.37% (p=0.000 n=19+20)
name old alloc/op new alloc/op delta
IPString/IPv4-8 24.0B ± 0% 16.0B ± 0% -33.33% (p=0.000 n=20+20)
IPString/IPv6-8 232B ± 0% 224B ± 0% -3.45% (p=0.000 n=20+20)
name old allocs/op new allocs/op delta
IPString/IPv4-8 3.00 ± 0% 2.00 ± 0% -33.33% (p=0.000 n=20+20)
IPString/IPv6-8 12.0 ± 0% 11.0 ± 0% -8.33% (p=0.000 n=20+20)
Fixes #24306
Change-Id: I4e2d30d364e78183d55a42907d277744494b6df3
---
M src/net/ip.go
M src/net/ip_test.go
2 files changed, 49 insertions(+), 5 deletions(-)
To view, visit change 99395. To unsubscribe, or for help writing mail filters, visit settings.
Brad Fitzpatrick merged this change.
net: optimize IP.String for IPv4
This is optimization is only for IPv4. It allocates a result buffer and
writes the IPv4 octets as dotted decimal into it before converting
it to a string just once, reducing allocations.
Benchmark shows performance improvement:
name old time/op new time/op delta
IPString/IPv4-8 284ns ± 4% 144ns ± 6% -49.35% (p=0.000 n=19+17)
IPString/IPv6-8 1.34µs ± 5% 1.14µs ± 5% -14.37% (p=0.000 n=19+20)
name old alloc/op new alloc/op delta
IPString/IPv4-8 24.0B ± 0% 16.0B ± 0% -33.33% (p=0.000 n=20+20)
IPString/IPv6-8 232B ± 0% 224B ± 0% -3.45% (p=0.000 n=20+20)
name old allocs/op new allocs/op delta
IPString/IPv4-8 3.00 ± 0% 2.00 ± 0% -33.33% (p=0.000 n=20+20)
IPString/IPv6-8 12.0 ± 0% 11.0 ± 0% -8.33% (p=0.000 n=20+20)
Fixes #24306
Change-Id: I4e2d30d364e78183d55a42907d277744494b6df3
Reviewed-on: https://go-review.googlesource.com/99395
Reviewed-by: Brad Fitzpatrick <brad...@golang.org>
---
M src/net/ip.go
M src/net/ip_test.go
2 files changed, 49 insertions(+), 5 deletions(-)
diff --git a/src/net/ip.go b/src/net/ip.go
index 6b7ba4c..a94ff73 100644
--- a/src/net/ip.go
+++ b/src/net/ip.go
@@ -260,6 +260,25 @@
return out
}
+// ubtoa encodes the string form of the integer v to dst[start:] and
+// returns the number of bytes written to dst. The caller must ensure
+// that dst has sufficient length.
+func ubtoa(dst []byte, start int, v byte) int {
+ if v < 10 {
+ dst[start] = byte(v + '0')
+ return 1
+ } else if v < 100 {
+ dst[start+1] = byte(v%10 + '0')
+ dst[start] = byte(v/10 + '0')
+ return 2
+ }
+
+ dst[start+2] = byte(v%10 + '0')
+ dst[start+1] = byte((v/10)%10 + '0')
+ dst[start] = byte(v/100 + '0')
+ return 3
+}
+
// String returns the string form of the IP address ip.
// It returns one of 4 forms:
// - "<nil>", if ip has length 0
@@ -275,10 +294,23 @@
// If IPv4, use dotted notation.
if p4 := p.To4(); len(p4) == IPv4len {
- return uitoa(uint(p4[0])) + "." +
- uitoa(uint(p4[1])) + "." +
- uitoa(uint(p4[2])) + "." +
- uitoa(uint(p4[3]))
+ const maxIPv4StringLen = len("255.255.255.255")
+ b := make([]byte, maxIPv4StringLen)
+
+ n := ubtoa(b, 0, p4[0])
+ b[n] = '.'
+ n++
+
+ n += ubtoa(b, n, p4[1])
+ b[n] = '.'
+ n++
+
+ n += ubtoa(b, n, p4[2])
+ b[n] = '.'
+ n++
+
+ n += ubtoa(b, n, p4[3])
+ return string(b[:n])
}
if len(p) != IPv6len {
return "?" + hexString(ip)
diff --git a/src/net/ip_test.go b/src/net/ip_test.go
index ad13388..60329e9 100644
--- a/src/net/ip_test.go
+++ b/src/net/ip_test.go
@@ -252,9 +252,21 @@
func BenchmarkIPString(b *testing.B) {
testHookUninstaller.Do(uninstallTestHooks)
+ b.Run("IPv4", func(b *testing.B) {
+ benchmarkIPString(b, IPv4len)
+ })
+
+ b.Run("IPv6", func(b *testing.B) {
+ benchmarkIPString(b, IPv6len)
+ })
+}
+
+func benchmarkIPString(b *testing.B, size int) {
+ b.ReportAllocs()
+ b.ResetTimer()
for i := 0; i < b.N; i++ {
for _, tt := range ipStringTests {
- if tt.in != nil {
+ if tt.in != nil && len(tt.in) == size {
sink = tt.in.String()
}
}
To view, visit change 99395. To unsubscribe, or for help writing mail filters, visit settings.