1 // Copyright 2012 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
14 // Strings and slices that don't escape and fit into tmpBuf are stack allocated,
15 // which defeats using AllocsPerRun to test other optimizations.
16 const sizeNoStack
= 100
18 func BenchmarkCompareStringEqual(b
*testing
.B
) {
19 bytes
:= []byte("Hello Gophers!")
20 s1
, s2
:= string(bytes
), string(bytes
)
21 for i
:= 0; i
< b
.N
; i
++ {
28 func BenchmarkCompareStringIdentical(b
*testing
.B
) {
29 s1
:= "Hello Gophers!"
31 for i
:= 0; i
< b
.N
; i
++ {
38 func BenchmarkCompareStringSameLength(b
*testing
.B
) {
39 s1
:= "Hello Gophers!"
40 s2
:= "Hello, Gophers"
41 for i
:= 0; i
< b
.N
; i
++ {
48 func BenchmarkCompareStringDifferentLength(b
*testing
.B
) {
49 s1
:= "Hello Gophers!"
50 s2
:= "Hello, Gophers!"
51 for i
:= 0; i
< b
.N
; i
++ {
58 func BenchmarkCompareStringBigUnaligned(b
*testing
.B
) {
59 bytes
:= make([]byte, 0, 1<<20)
60 for len(bytes
) < 1<<20 {
61 bytes
= append(bytes
, "Hello Gophers!"...)
63 s1
, s2
:= string(bytes
), "hello"+string(bytes
)
64 for i
:= 0; i
< b
.N
; i
++ {
65 if s1
!= s2
[len("hello"):] {
69 b
.SetBytes(int64(len(s1
)))
72 func BenchmarkCompareStringBig(b
*testing
.B
) {
73 bytes
:= make([]byte, 0, 1<<20)
74 for len(bytes
) < 1<<20 {
75 bytes
= append(bytes
, "Hello Gophers!"...)
77 s1
, s2
:= string(bytes
), string(bytes
)
78 for i
:= 0; i
< b
.N
; i
++ {
83 b
.SetBytes(int64(len(s1
)))
86 func BenchmarkConcatStringAndBytes(b
*testing
.B
) {
87 s1
:= []byte("Gophers!")
88 for i
:= 0; i
< b
.N
; i
++ {
89 _
= "Hello " + string(s1
)
93 var escapeString
string
95 func BenchmarkSliceByteToString(b
*testing
.B
) {
97 for n
:= 0; n
< 8; n
++ {
98 b
.Run(strconv
.Itoa(len(buf
)), func(b
*testing
.B
) {
99 for i
:= 0; i
< b
.N
; i
++ {
100 escapeString
= string(buf
)
103 buf
= append(buf
, buf
...)
107 var stringdata
= []struct{ name
, data
string }{
108 {"ASCII", "01234567890"},
109 {"Japanese", "日本語日本語日本語"},
110 {"MixedLength", "$Ѐࠀက퀀𐀀\U00040000\U0010FFFF"},
113 func BenchmarkRuneIterate(b
*testing
.B
) {
114 b
.Run("range", func(b
*testing
.B
) {
115 for _
, sd
:= range stringdata
{
116 b
.Run(sd
.name
, func(b
*testing
.B
) {
117 for i
:= 0; i
< b
.N
; i
++ {
124 b
.Run("range1", func(b
*testing
.B
) {
125 for _
, sd
:= range stringdata
{
126 b
.Run(sd
.name
, func(b
*testing
.B
) {
127 for i
:= 0; i
< b
.N
; i
++ {
128 for _
= range sd
.data
{
134 b
.Run("range2", func(b
*testing
.B
) {
135 for _
, sd
:= range stringdata
{
136 b
.Run(sd
.name
, func(b
*testing
.B
) {
137 for i
:= 0; i
< b
.N
; i
++ {
138 for _
, _
= range sd
.data
{
146 func BenchmarkArrayEqual(b
*testing
.B
) {
147 a1
:= [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
148 a2
:= [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
150 for i
:= 0; i
< b
.N
; i
++ {
158 func TestStringW(t *testing.T) {
164 for _, s := range strings {
166 for _, c := range s {
167 b = append(b, uint16(c))
168 if c != rune(uint16(c)) {
169 t.Errorf("bad test: stringW can't handle >16 bit runes")
173 r := runtime.GostringW(b)
175 t.Errorf("gostringW(%v) = %s, want %s", b, r, s)
181 func TestLargeStringConcat(t
*testing
.T
) {
182 output
:= runTestProg(t
, "testprog", "stringconcat")
183 want
:= "panic: " + strings
.Repeat("0", 1<<10) + strings
.Repeat("1", 1<<10) +
184 strings
.Repeat("2", 1<<10) + strings
.Repeat("3", 1<<10)
185 if !strings
.HasPrefix(output
, want
) {
186 t
.Fatalf("output does not start with %q:\n%s", want
, output
)
190 func TestCompareTempString(t
*testing
.T
) {
191 s
:= strings
.Repeat("x", sizeNoStack
)
193 n
:= testing
.AllocsPerRun(1000, func() {
195 t
.Fatalf("strings are not equal: '%v' and '%v'", string(b
), s
)
199 t
.Fatalf("strings are not equal: '%v' and '%v'", string(b
), s
)
202 // was n != 0, changed for gccgo.
204 t
.Fatalf("want 0 allocs, got %v", n
)
208 func TestStringOnStack(t
*testing
.T
) {
210 for i
:= 0; i
< 3; i
++ {
211 s
= "a" + s
+ "b" + s
+ "c"
214 if want
:= "aaabcbabccbaabcbabccc"; s
!= want
{
215 t
.Fatalf("want: '%v', got '%v'", want
, s
)
219 func TestIntString(t
*testing
.T
) {
220 // Non-escaping result of intstring.
222 for i
:= 0; i
< 4; i
++ {
223 s
+= string(i
+'0') + string(i
+'0'+1)
225 if want
:= "01122334"; s
!= want
{
226 t
.Fatalf("want '%v', got '%v'", want
, s
)
229 // Escaping result of intstring.
231 for i
:= 0; i
< 4; i
++ {
232 a
[i
] = string(i
+ '0')
234 s
= a
[0] + a
[1] + a
[2] + a
[3]
235 if want
:= "0123"; s
!= want
{
236 t
.Fatalf("want '%v', got '%v'", want
, s
)
240 func TestIntStringAllocs(t
*testing
.T
) {
242 n
:= testing
.AllocsPerRun(1000, func() {
243 s1
:= string(unknown
)
244 s2
:= string(unknown
+ 1)
249 // was n != 0, changed for gccgo, which currently does one
250 // allocation for each call to string(unknown).
252 t
.Fatalf("want 0 allocs, got %v", n
)
256 func TestRangeStringCast(t
*testing
.T
) {
257 s
:= strings
.Repeat("x", sizeNoStack
)
258 n
:= testing
.AllocsPerRun(1000, func() {
259 for i
, c
:= range []byte(s
) {
261 t
.Fatalf("want '%c' at pos %v, got '%c'", s
[i
], i
, c
)
265 // was n != 0, changed for gccgo.
267 t
.Fatalf("want 0 allocs, got %v", n
)
271 func isZeroed(b
[]byte) bool {
272 for _
, x
:= range b
{
280 func isZeroedR(r
[]rune
) bool {
281 for _
, x
:= range r
{
289 func TestString2Slice(t
*testing
.T
) {
290 // Make sure we don't return slices that expose
291 // an unzeroed section of stack-allocated temp buf
292 // between len and cap. See issue 14232.
295 if !isZeroed(b
[len(b
):cap(b
)]) {
296 t
.Errorf("extra bytes not zeroed")
299 if !isZeroedR(r
[len(r
):cap(r
)]) {
300 t
.Errorf("extra runes not zeroed")
304 const intSize
= 32 << (^uint(0) >> 63)
306 type atoi64Test
struct {
312 var atoi64tests
= []atoi64Test
{
318 {"12345", 12345, true},
319 {"-12345", -12345, true},
320 {"012345", 12345, true},
321 {"-012345", -12345, true},
322 {"12345x", 0, false},
323 {"-12345x", 0, false},
324 {"98765432100", 98765432100, true},
325 {"-98765432100", -98765432100, true},
326 {"20496382327982653440", 0, false},
327 {"-20496382327982653440", 0, false},
328 {"9223372036854775807", 1<<63 - 1, true},
329 {"-9223372036854775807", -(1<<63 - 1), true},
330 {"9223372036854775808", 0, false},
331 {"-9223372036854775808", -1 << 63, true},
332 {"9223372036854775809", 0, false},
333 {"-9223372036854775809", 0, false},
336 func TestAtoi(t
*testing
.T
) {
339 for i
:= range atoi32tests
{
340 test
:= &atoi32tests
[i
]
341 out
, ok
:= runtime
.Atoi(test
.in
)
342 if test
.out
!= int32(out
) || test
.ok
!= ok
{
343 t
.Errorf("atoi(%q) = (%v, %v) want (%v, %v)",
344 test
.in
, out
, ok
, test
.out
, test
.ok
)
348 for i
:= range atoi64tests
{
349 test
:= &atoi64tests
[i
]
350 out
, ok
:= runtime
.Atoi(test
.in
)
351 if test
.out
!= int64(out
) || test
.ok
!= ok
{
352 t
.Errorf("atoi(%q) = (%v, %v) want (%v, %v)",
353 test
.in
, out
, ok
, test
.out
, test
.ok
)
359 type atoi32Test
struct {
365 var atoi32tests
= []atoi32Test
{
371 {"12345", 12345, true},
372 {"-12345", -12345, true},
373 {"012345", 12345, true},
374 {"-012345", -12345, true},
375 {"12345x", 0, false},
376 {"-12345x", 0, false},
377 {"987654321", 987654321, true},
378 {"-987654321", -987654321, true},
379 {"2147483647", 1<<31 - 1, true},
380 {"-2147483647", -(1<<31 - 1), true},
381 {"2147483648", 0, false},
382 {"-2147483648", -1 << 31, true},
383 {"2147483649", 0, false},
384 {"-2147483649", 0, false},
387 func TestAtoi32(t
*testing
.T
) {
388 for i
:= range atoi32tests
{
389 test
:= &atoi32tests
[i
]
390 out
, ok
:= runtime
.Atoi32(test
.in
)
391 if test
.out
!= out || test
.ok
!= ok
{
392 t
.Errorf("atoi32(%q) = (%v, %v) want (%v, %v)",
393 test
.in
, out
, ok
, test
.out
, test
.ok
)