1
+ /**
2
+ * Copyright 2025 ByteDance Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * https://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ package alg
18
+
19
+ import (
20
+ "bytes"
21
+ "encoding/json"
22
+ "math/rand"
23
+ "strconv"
24
+ "strings"
25
+ "testing"
26
+
27
+ "github.com/bytedance/sonic/testdata"
28
+ )
29
+
30
+ func BenchmarkU64toa (b * testing.B ) {
31
+ b .ReportAllocs ()
32
+ buf := make ([]byte , 0 , 64 )
33
+ for x := 0 ;x <= 62 ; x += 4 {
34
+ d := 1 << x
35
+ b .Run ("sonic-" + strconv .Itoa (d ), func (b * testing.B ) {
36
+ b .ResetTimer ()
37
+ for i := 0 ; i < b .N ; i ++ {
38
+ _ = U64toa (buf , uint64 (d ))
39
+ }
40
+ })
41
+ b .Run ("std-" + strconv .Itoa (d ), func (b * testing.B ) {
42
+ b .ResetTimer ()
43
+ for i := 0 ; i < b .N ; i ++ {
44
+ _ = strconv .AppendUint (buf , uint64 (d ), 10 )
45
+ }
46
+ })
47
+ }
48
+ }
49
+
50
+ func BenchmarkI64toa (b * testing.B ) {
51
+ b .ReportAllocs ()
52
+ buf := make ([]byte , 0 , 64 )
53
+ for x := 0 ;x <= 62 ; x += 4 {
54
+ d := 1 << x
55
+ b .Run ("sonic-" + strconv .Itoa (d ), func (b * testing.B ) {
56
+ b .ResetTimer ()
57
+ for i := 0 ; i < b .N ; i ++ {
58
+ _ = I64toa (buf , int64 (d ))
59
+ }
60
+ })
61
+ b .Run ("std-" + strconv .Itoa (d ), func (b * testing.B ) {
62
+ b .ResetTimer ()
63
+ for i := 0 ; i < b .N ; i ++ {
64
+ _ = strconv .AppendInt (buf , int64 (d ), 10 )
65
+ }
66
+ })
67
+ }
68
+ }
69
+
70
+ func BenchmarkF64toa (b * testing.B ) {
71
+ b .ReportAllocs ()
72
+ buf := make ([]byte , 0 , 64 )
73
+ for x := 0 ;x <= 62 ; x += 4 {
74
+ d := 1 << x
75
+ f := float64 (d )+ rand .Float64 ()
76
+ b .Run ("sonic-" + strconv .FormatFloat (f , 'g' , - 1 , 64 ), func (b * testing.B ) {
77
+ b .ResetTimer ()
78
+ for i := 0 ; i < b .N ; i ++ {
79
+ _ = F64toa (buf , f )
80
+ }
81
+ })
82
+ b .Run ("std-" + strconv .FormatFloat (f , 'g' , - 1 , 64 ), func (b * testing.B ) {
83
+ b .ResetTimer ()
84
+ for i := 0 ; i < b .N ; i ++ {
85
+ _ = strconv .AppendFloat (buf , f , 'g' , - 1 , 64 )
86
+ }
87
+ })
88
+ }
89
+ }
90
+
91
+ func BenchmarkF32toa (b * testing.B ) {
92
+ b .ReportAllocs ()
93
+ buf := make ([]byte , 0 , 64 )
94
+ for x := 0 ;x <= 30 ; x += 2 {
95
+ d := 1 << x
96
+ f := float32 (d )+ rand .Float32 ()
97
+ b .Run ("sonic-" + strconv .FormatFloat (float64 (f ), 'g' , - 1 , 32 ), func (b * testing.B ) {
98
+ b .ResetTimer ()
99
+ for i := 0 ; i < b .N ; i ++ {
100
+ _ = F32toa (buf , f )
101
+ }
102
+ })
103
+ b .Run ("std-" + strconv .FormatFloat (float64 (f ), 'g' , - 1 , 32 ), func (b * testing.B ) {
104
+ b .ResetTimer ()
105
+ for i := 0 ; i < b .N ; i ++ {
106
+ _ = strconv .AppendFloat (buf , float64 (f ), 'g' , - 1 , 32 )
107
+ }
108
+ })
109
+ }
110
+ }
111
+
112
+ func BenchmarkQuote (b * testing.B ) {
113
+ b .ReportAllocs ()
114
+ var runner = func (seed string ) func (b * testing.B ) {
115
+ return func (b * testing.B ) {
116
+ buf := make ([]byte , 0 , len (seed )* 1024 * 1024 )
117
+ for l := 1 ; l < cap (buf )* 10 ; l *= 10 {
118
+ src := strings .Repeat (seed , l )
119
+ b .Run ("sonic-" + strconv .Itoa (len (src )), func (b * testing.B ) {
120
+ b .ResetTimer ()
121
+ for i := 0 ; i < b .N ; i ++ {
122
+ _ = Quote (buf , src , false )
123
+ }
124
+ })
125
+ b .Run ("std-" + strconv .Itoa (len (src )), func (b * testing.B ) {
126
+ b .ResetTimer ()
127
+ for i := 0 ; i < b .N ; i ++ {
128
+ _ = strconv .AppendQuote (buf , src )
129
+ }
130
+ })
131
+ }
132
+ }
133
+ }
134
+
135
+ b .Run ("no quote" , runner ("abcdefghij" ))
136
+ b .Run ("1/10 quote" , runner ("abcdefghi\n " ))
137
+ b .Run ("1/5 quote" , runner ("abcd\n fghi\n " ))
138
+ }
139
+
140
+ func BenchmarkValid (b * testing.B ) {
141
+ b .ReportAllocs ()
142
+ var runner = func (seed []byte ) func (b * testing.B ) {
143
+ return func (b * testing.B ) {
144
+ b .Run ("sonic" , func (b * testing.B ) {
145
+ b .ResetTimer ()
146
+ for i := 0 ; i < b .N ; i ++ {
147
+ _ , _ = Valid (seed )
148
+ }
149
+ })
150
+ b .Run ("std" , func (b * testing.B ) {
151
+ b .ResetTimer ()
152
+ for i := 0 ; i < b .N ; i ++ {
153
+ _ = json .Valid (seed )
154
+ }
155
+ })
156
+ }
157
+ }
158
+ b .Run ("valid-small" , runner ([]byte (`{"a":1}` )))
159
+ b .Run ("invalid-small" , runner ([]byte (`{"a":1>` )))
160
+ b .Run ("valid-large" , runner ([]byte (testdata .TwitterJson )))
161
+ b .Run ("invalid-large" , runner ([]byte (strings .ReplaceAll (testdata .TwitterJson , "}" , ">" ))))
162
+ }
163
+
164
+ func BenchmarkEscapeHTML (b * testing.B ) {
165
+ b .ReportAllocs ()
166
+ var runner = func (seed []byte ) func (b * testing.B ) {
167
+ return func (b * testing.B ) {
168
+ buf := make ([]byte , 0 , len (seed )* 10 )
169
+ b .Run ("sonic" , func (b * testing.B ) {
170
+ b .ResetTimer ()
171
+ for i := 0 ; i < b .N ; i ++ {
172
+ _ = HtmlEscape (buf , seed )
173
+ }
174
+ })
175
+ b .Run ("std" , func (b * testing.B ) {
176
+ b .ResetTimer ()
177
+ for i := 0 ; i < b .N ; i ++ {
178
+ bf := bytes .NewBuffer (buf )
179
+ json .HTMLEscape (bf , seed )
180
+ }
181
+ })
182
+ }
183
+ }
184
+
185
+ b .Run ("small" , runner ([]byte (`{"a":"<>"}` )))
186
+ b .Run ("large" , runner ([]byte (testdata .TwitterJson )))
187
+ }
0 commit comments