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.
13 // Strings and slices that don't escape and fit into tmpBuf are stack allocated,
14 // which defeats using AllocsPerRun to test other optimizations.
15 const sizeNoStack
= 100
17 func BenchmarkCompareStringEqual(b
*testing
.B
) {
18 bytes
:= []byte("Hello Gophers!")
19 s1
, s2
:= string(bytes
), string(bytes
)
20 for i
:= 0; i
< b
.N
; i
++ {
27 func BenchmarkCompareStringIdentical(b
*testing
.B
) {
28 s1
:= "Hello Gophers!"
30 for i
:= 0; i
< b
.N
; i
++ {
37 func BenchmarkCompareStringSameLength(b
*testing
.B
) {
38 s1
:= "Hello Gophers!"
39 s2
:= "Hello, Gophers"
40 for i
:= 0; i
< b
.N
; i
++ {
47 func BenchmarkCompareStringDifferentLength(b
*testing
.B
) {
48 s1
:= "Hello Gophers!"
49 s2
:= "Hello, Gophers!"
50 for i
:= 0; i
< b
.N
; i
++ {
57 func BenchmarkCompareStringBigUnaligned(b
*testing
.B
) {
58 bytes
:= make([]byte, 0, 1<<20)
59 for len(bytes
) < 1<<20 {
60 bytes
= append(bytes
, "Hello Gophers!"...)
62 s1
, s2
:= string(bytes
), "hello"+string(bytes
)
63 for i
:= 0; i
< b
.N
; i
++ {
64 if s1
!= s2
[len("hello"):] {
68 b
.SetBytes(int64(len(s1
)))
71 func BenchmarkCompareStringBig(b
*testing
.B
) {
72 bytes
:= make([]byte, 0, 1<<20)
73 for len(bytes
) < 1<<20 {
74 bytes
= append(bytes
, "Hello Gophers!"...)
76 s1
, s2
:= string(bytes
), string(bytes
)
77 for i
:= 0; i
< b
.N
; i
++ {
82 b
.SetBytes(int64(len(s1
)))
85 func BenchmarkConcatStringAndBytes(b
*testing
.B
) {
86 s1
:= []byte("Gophers!")
87 for i
:= 0; i
< b
.N
; i
++ {
88 _
= "Hello " + string(s1
)
92 var stringdata
= []struct{ name
, data
string }{
93 {"ASCII", "01234567890"},
94 {"Japanese", "日本語日本語日本語"},
95 {"MixedLength", "$Ѐࠀက퀀𐀀\U00040000\U0010FFFF"},
98 func BenchmarkRuneIterate(b
*testing
.B
) {
99 b
.Run("range", func(b
*testing
.B
) {
100 for _
, sd
:= range stringdata
{
101 b
.Run(sd
.name
, func(b
*testing
.B
) {
102 for i
:= 0; i
< b
.N
; i
++ {
109 b
.Run("range1", func(b
*testing
.B
) {
110 for _
, sd
:= range stringdata
{
111 b
.Run(sd
.name
, func(b
*testing
.B
) {
112 for i
:= 0; i
< b
.N
; i
++ {
113 for _
= range sd
.data
{
119 b
.Run("range2", func(b
*testing
.B
) {
120 for _
, sd
:= range stringdata
{
121 b
.Run(sd
.name
, func(b
*testing
.B
) {
122 for i
:= 0; i
< b
.N
; i
++ {
123 for _
, _
= range sd
.data
{
131 func BenchmarkArrayEqual(b
*testing
.B
) {
132 a1
:= [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
133 a2
:= [16]byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}
135 for i
:= 0; i
< b
.N
; i
++ {
143 func TestStringW(t *testing.T) {
149 for _, s := range strings {
151 for _, c := range s {
152 b = append(b, uint16(c))
153 if c != rune(uint16(c)) {
154 t.Errorf("bad test: stringW can't handle >16 bit runes")
158 r := runtime.GostringW(b)
160 t.Errorf("gostringW(%v) = %s, want %s", b, r, s)
166 func TestLargeStringConcat(t
*testing
.T
) {
167 output
:= runTestProg(t
, "testprog", "stringconcat")
168 want
:= "panic: " + strings
.Repeat("0", 1<<10) + strings
.Repeat("1", 1<<10) +
169 strings
.Repeat("2", 1<<10) + strings
.Repeat("3", 1<<10)
170 if !strings
.HasPrefix(output
, want
) {
171 t
.Fatalf("output does not start with %q:\n%s", want
, output
)
175 func TestCompareTempString(t
*testing
.T
) {
176 s
:= strings
.Repeat("x", sizeNoStack
)
178 n
:= testing
.AllocsPerRun(1000, func() {
180 t
.Fatalf("strings are not equal: '%v' and '%v'", string(b
), s
)
184 t
.Fatalf("strings are not equal: '%v' and '%v'", string(b
), s
)
187 // was n != 0, changed for gccgo.
189 t
.Fatalf("want 0 allocs, got %v", n
)
193 func TestStringOnStack(t
*testing
.T
) {
195 for i
:= 0; i
< 3; i
++ {
196 s
= "a" + s
+ "b" + s
+ "c"
199 if want
:= "aaabcbabccbaabcbabccc"; s
!= want
{
200 t
.Fatalf("want: '%v', got '%v'", want
, s
)
204 func TestIntString(t
*testing
.T
) {
205 // Non-escaping result of intstring.
207 for i
:= 0; i
< 4; i
++ {
208 s
+= string(i
+'0') + string(i
+'0'+1)
210 if want
:= "01122334"; s
!= want
{
211 t
.Fatalf("want '%v', got '%v'", want
, s
)
214 // Escaping result of intstring.
216 for i
:= 0; i
< 4; i
++ {
217 a
[i
] = string(i
+ '0')
219 s
= a
[0] + a
[1] + a
[2] + a
[3]
220 if want
:= "0123"; s
!= want
{
221 t
.Fatalf("want '%v', got '%v'", want
, s
)
225 func TestIntStringAllocs(t
*testing
.T
) {
227 n
:= testing
.AllocsPerRun(1000, func() {
228 s1
:= string(unknown
)
229 s2
:= string(unknown
+ 1)
234 // was n != 0, changed for gccgo, which currently does one
235 // allocation for each call to string(unknown).
237 t
.Fatalf("want 0 allocs, got %v", n
)
241 func TestRangeStringCast(t
*testing
.T
) {
242 s
:= strings
.Repeat("x", sizeNoStack
)
243 n
:= testing
.AllocsPerRun(1000, func() {
244 for i
, c
:= range []byte(s
) {
246 t
.Fatalf("want '%c' at pos %v, got '%c'", s
[i
], i
, c
)
250 // was n != 0, changed for gccgo.
252 t
.Fatalf("want 0 allocs, got %v", n
)
256 func isZeroed(b
[]byte) bool {
257 for _
, x
:= range b
{
265 func isZeroedR(r
[]rune
) bool {
266 for _
, x
:= range r
{
274 func TestString2Slice(t
*testing
.T
) {
275 // Make sure we don't return slices that expose
276 // an unzeroed section of stack-allocated temp buf
277 // between len and cap. See issue 14232.
280 if !isZeroed(b
[len(b
):cap(b
)]) {
281 t
.Errorf("extra bytes not zeroed")
284 if !isZeroedR(r
[len(r
):cap(r
)]) {
285 t
.Errorf("extra runes not zeroed")
289 const intSize
= 32 << (^uint(0) >> 63)
291 type atoi64Test
struct {
297 var atoi64tests
= []atoi64Test
{
303 {"12345", 12345, true},
304 {"-12345", -12345, true},
305 {"012345", 12345, true},
306 {"-012345", -12345, true},
307 {"12345x", 0, false},
308 {"-12345x", 0, false},
309 {"98765432100", 98765432100, true},
310 {"-98765432100", -98765432100, true},
311 {"20496382327982653440", 0, false},
312 {"-20496382327982653440", 0, false},
313 {"9223372036854775807", 1<<63 - 1, true},
314 {"-9223372036854775807", -(1<<63 - 1), true},
315 {"9223372036854775808", 0, false},
316 {"-9223372036854775808", -1 << 63, true},
317 {"9223372036854775809", 0, false},
318 {"-9223372036854775809", 0, false},
321 func TestAtoi(t
*testing
.T
) {
324 for i
:= range atoi32tests
{
325 test
:= &atoi32tests
[i
]
326 out
, ok
:= runtime
.Atoi(test
.in
)
327 if test
.out
!= int32(out
) || test
.ok
!= ok
{
328 t
.Errorf("atoi(%q) = (%v, %v) want (%v, %v)",
329 test
.in
, out
, ok
, test
.out
, test
.ok
)
333 for i
:= range atoi64tests
{
334 test
:= &atoi64tests
[i
]
335 out
, ok
:= runtime
.Atoi(test
.in
)
336 if test
.out
!= int64(out
) || test
.ok
!= ok
{
337 t
.Errorf("atoi(%q) = (%v, %v) want (%v, %v)",
338 test
.in
, out
, ok
, test
.out
, test
.ok
)
344 type atoi32Test
struct {
350 var atoi32tests
= []atoi32Test
{
356 {"12345", 12345, true},
357 {"-12345", -12345, true},
358 {"012345", 12345, true},
359 {"-012345", -12345, true},
360 {"12345x", 0, false},
361 {"-12345x", 0, false},
362 {"987654321", 987654321, true},
363 {"-987654321", -987654321, true},
364 {"2147483647", 1<<31 - 1, true},
365 {"-2147483647", -(1<<31 - 1), true},
366 {"2147483648", 0, false},
367 {"-2147483648", -1 << 31, true},
368 {"2147483649", 0, false},
369 {"-2147483649", 0, false},
372 func TestAtoi32(t
*testing
.T
) {
373 for i
:= range atoi32tests
{
374 test
:= &atoi32tests
[i
]
375 out
, ok
:= runtime
.Atoi32(test
.in
)
376 if test
.out
!= out || test
.ok
!= ok
{
377 t
.Errorf("atoi32(%q) = (%v, %v) want (%v, %v)",
378 test
.in
, out
, ok
, test
.out
, test
.ok
)