benchmark_test.go raw
1 package text
2
3 import (
4 "testing"
5
6 "next.orly.dev/pkg/nostr/encoders/hex"
7 "github.com/minio/sha256-simd"
8 "lukechampine.com/frand"
9 )
10
11 func createTestData() []byte {
12 return []byte(`some text content with line breaks and tabs and other stuff, and also some < > & " ' / \ control chars \u0000 \u001f`)
13 }
14
15 func createTestDataLarge() []byte {
16 data := make([]byte, 8192)
17 for i := range data {
18 data[i] = byte(i % 256)
19 }
20 return data
21 }
22
23 func createTestHexArray() [][]byte {
24 ha := make([][]byte, 20)
25 h := make([]byte, sha256.Size)
26 frand.Read(h)
27 for i := range ha {
28 hh := sha256.Sum256(h)
29 h = hh[:]
30 ha[i] = make([]byte, sha256.Size)
31 copy(ha[i], h)
32 }
33 return ha
34 }
35
36 func BenchmarkNostrEscape(b *testing.B) {
37 b.Run(
38 "Small", func(b *testing.B) {
39 b.ReportAllocs()
40 src := createTestData()
41 dst := make([]byte, 0, len(src)*2)
42 for i := 0; i < b.N; i++ {
43 dst = NostrEscape(dst[:0], src)
44 }
45 },
46 )
47 b.Run(
48 "Large", func(b *testing.B) {
49 b.ReportAllocs()
50 src := createTestDataLarge()
51 dst := make([]byte, 0, len(src)*2)
52 for i := 0; i < b.N; i++ {
53 dst = NostrEscape(dst[:0], src)
54 }
55 },
56 )
57 b.Run(
58 "NoEscapes", func(b *testing.B) {
59 b.ReportAllocs()
60 src := []byte("this is a normal string with no special characters")
61 dst := make([]byte, 0, len(src))
62 for i := 0; i < b.N; i++ {
63 dst = NostrEscape(dst[:0], src)
64 }
65 },
66 )
67 b.Run(
68 "ManyEscapes", func(b *testing.B) {
69 b.ReportAllocs()
70 src := []byte("\"test\"\n\t\r\b\f\\control\x00\x01\x02")
71 dst := make([]byte, 0, len(src)*3)
72 for i := 0; i < b.N; i++ {
73 dst = NostrEscape(dst[:0], src)
74 }
75 },
76 )
77 }
78
79 func BenchmarkNostrUnescape(b *testing.B) {
80 b.Run(
81 "Small", func(b *testing.B) {
82 b.ReportAllocs()
83 src := createTestData()
84 escaped := NostrEscape(nil, src)
85 for i := 0; i < b.N; i++ {
86 escapedCopy := make([]byte, len(escaped))
87 copy(escapedCopy, escaped)
88 _ = NostrUnescape(escapedCopy)
89 }
90 },
91 )
92 b.Run(
93 "Large", func(b *testing.B) {
94 b.ReportAllocs()
95 src := createTestDataLarge()
96 escaped := NostrEscape(nil, src)
97 for i := 0; i < b.N; i++ {
98 escapedCopy := make([]byte, len(escaped))
99 copy(escapedCopy, escaped)
100 _ = NostrUnescape(escapedCopy)
101 }
102 },
103 )
104 }
105
106 func BenchmarkRoundTripEscape(b *testing.B) {
107 b.Run(
108 "Small", func(b *testing.B) {
109 b.ReportAllocs()
110 src := createTestData()
111 for i := 0; i < b.N; i++ {
112 escaped := NostrEscape(nil, src)
113 escapedCopy := make([]byte, len(escaped))
114 copy(escapedCopy, escaped)
115 _ = NostrUnescape(escapedCopy)
116 }
117 },
118 )
119 b.Run(
120 "Large", func(b *testing.B) {
121 b.ReportAllocs()
122 src := createTestDataLarge()
123 for i := 0; i < b.N; i++ {
124 escaped := NostrEscape(nil, src)
125 escapedCopy := make([]byte, len(escaped))
126 copy(escapedCopy, escaped)
127 _ = NostrUnescape(escapedCopy)
128 }
129 },
130 )
131 }
132
133 func BenchmarkJSONKey(b *testing.B) {
134 b.ReportAllocs()
135 key := []byte("testkey")
136 dst := make([]byte, 0, 20)
137 for i := 0; i < b.N; i++ {
138 dst = JSONKey(dst[:0], key)
139 }
140 }
141
142 func BenchmarkUnmarshalHex(b *testing.B) {
143 b.Run(
144 "Small", func(b *testing.B) {
145 b.ReportAllocs()
146 h := make([]byte, sha256.Size)
147 frand.Read(h)
148 hexStr := hex.EncAppend(nil, h)
149 quoted := AppendQuote(nil, hexStr, Noop)
150 for i := 0; i < b.N; i++ {
151 _, _, _ = UnmarshalHex(quoted)
152 }
153 },
154 )
155 b.Run(
156 "Large", func(b *testing.B) {
157 b.ReportAllocs()
158 h := make([]byte, 1024)
159 frand.Read(h)
160 hexStr := hex.EncAppend(nil, h)
161 quoted := AppendQuote(nil, hexStr, Noop)
162 for i := 0; i < b.N; i++ {
163 _, _, _ = UnmarshalHex(quoted)
164 }
165 },
166 )
167 }
168
169 func BenchmarkUnmarshalQuoted(b *testing.B) {
170 b.Run(
171 "Small", func(b *testing.B) {
172 b.ReportAllocs()
173 src := createTestData()
174 quoted := AppendQuote(nil, src, NostrEscape)
175 for i := 0; i < b.N; i++ {
176 quotedCopy := make([]byte, len(quoted))
177 copy(quotedCopy, quoted)
178 _, _, _ = UnmarshalQuoted(quotedCopy)
179 }
180 },
181 )
182 b.Run(
183 "Large", func(b *testing.B) {
184 b.ReportAllocs()
185 src := createTestDataLarge()
186 quoted := AppendQuote(nil, src, NostrEscape)
187 for i := 0; i < b.N; i++ {
188 quotedCopy := make([]byte, len(quoted))
189 copy(quotedCopy, quoted)
190 _, _, _ = UnmarshalQuoted(quotedCopy)
191 }
192 },
193 )
194 }
195
196 func BenchmarkMarshalHexArray(b *testing.B) {
197 b.Run(
198 "Small", func(b *testing.B) {
199 b.ReportAllocs()
200 ha := createTestHexArray()
201 dst := make([]byte, 0, len(ha)*sha256.Size*3)
202 for i := 0; i < b.N; i++ {
203 dst = MarshalHexArray(dst[:0], ha)
204 }
205 },
206 )
207 b.Run(
208 "Large", func(b *testing.B) {
209 b.ReportAllocs()
210 ha := make([][]byte, 100)
211 h := make([]byte, sha256.Size)
212 frand.Read(h)
213 for i := range ha {
214 hh := sha256.Sum256(h)
215 h = hh[:]
216 ha[i] = make([]byte, sha256.Size)
217 copy(ha[i], h)
218 }
219 dst := make([]byte, 0, len(ha)*sha256.Size*3)
220 for i := 0; i < b.N; i++ {
221 dst = MarshalHexArray(dst[:0], ha)
222 }
223 },
224 )
225 }
226
227 func BenchmarkUnmarshalHexArray(b *testing.B) {
228 b.Run(
229 "Small", func(b *testing.B) {
230 b.ReportAllocs()
231 ha := createTestHexArray()
232 marshaled := MarshalHexArray(nil, ha)
233 for i := 0; i < b.N; i++ {
234 marshaledCopy := make([]byte, len(marshaled))
235 copy(marshaledCopy, marshaled)
236 _, _, _ = UnmarshalHexArray(marshaledCopy, sha256.Size)
237 }
238 },
239 )
240 b.Run(
241 "Large", func(b *testing.B) {
242 b.ReportAllocs()
243 ha := make([][]byte, 100)
244 h := make([]byte, sha256.Size)
245 frand.Read(h)
246 for i := range ha {
247 hh := sha256.Sum256(h)
248 h = hh[:]
249 ha[i] = make([]byte, sha256.Size)
250 copy(ha[i], h)
251 }
252 marshaled := MarshalHexArray(nil, ha)
253 for i := 0; i < b.N; i++ {
254 marshaledCopy := make([]byte, len(marshaled))
255 copy(marshaledCopy, marshaled)
256 _, _, _ = UnmarshalHexArray(marshaledCopy, sha256.Size)
257 }
258 },
259 )
260 }
261
262 func BenchmarkUnmarshalStringArray(b *testing.B) {
263 b.Run(
264 "Small", func(b *testing.B) {
265 b.ReportAllocs()
266 strings := [][]byte{
267 []byte("string1"),
268 []byte("string2"),
269 []byte("string3"),
270 }
271 dst := make([]byte, 0, 100)
272 dst = append(dst, '[')
273 for i, s := range strings {
274 dst = AppendQuote(dst, s, NostrEscape)
275 if i < len(strings)-1 {
276 dst = append(dst, ',')
277 }
278 }
279 dst = append(dst, ']')
280 for i := 0; i < b.N; i++ {
281 dstCopy := make([]byte, len(dst))
282 copy(dstCopy, dst)
283 _, _, _ = UnmarshalStringArray(dstCopy)
284 }
285 },
286 )
287 b.Run(
288 "Large", func(b *testing.B) {
289 b.ReportAllocs()
290 strings := make([][]byte, 100)
291 for i := range strings {
292 strings[i] = []byte("test string " + string(rune(i)))
293 }
294 dst := make([]byte, 0, 2000)
295 dst = append(dst, '[')
296 for i, s := range strings {
297 dst = AppendQuote(dst, s, NostrEscape)
298 if i < len(strings)-1 {
299 dst = append(dst, ',')
300 }
301 }
302 dst = append(dst, ']')
303 for i := 0; i < b.N; i++ {
304 dstCopy := make([]byte, len(dst))
305 copy(dstCopy, dst)
306 _, _, _ = UnmarshalStringArray(dstCopy)
307 }
308 },
309 )
310 }
311
312 func BenchmarkAppendQuote(b *testing.B) {
313 b.Run(
314 "Small", func(b *testing.B) {
315 b.ReportAllocs()
316 src := createTestData()
317 dst := make([]byte, 0, len(src)*2)
318 for i := 0; i < b.N; i++ {
319 dst = AppendQuote(dst[:0], src, NostrEscape)
320 }
321 },
322 )
323 b.Run(
324 "Large", func(b *testing.B) {
325 b.ReportAllocs()
326 src := createTestDataLarge()
327 dst := make([]byte, 0, len(src)*2)
328 for i := 0; i < b.N; i++ {
329 dst = AppendQuote(dst[:0], src, NostrEscape)
330 }
331 },
332 )
333 b.Run(
334 "NoEscape", func(b *testing.B) {
335 b.ReportAllocs()
336 src := []byte("normal string")
337 dst := make([]byte, 0, len(src)+2)
338 for i := 0; i < b.N; i++ {
339 dst = AppendQuote(dst[:0], src, Noop)
340 }
341 },
342 )
343 }
344
345 func BenchmarkAppendList(b *testing.B) {
346 b.Run(
347 "Small", func(b *testing.B) {
348 b.ReportAllocs()
349 src := [][]byte{
350 []byte("item1"),
351 []byte("item2"),
352 []byte("item3"),
353 }
354 dst := make([]byte, 0, 50)
355 for i := 0; i < b.N; i++ {
356 dst = AppendList(dst[:0], src, ',', NostrEscape)
357 }
358 },
359 )
360 b.Run(
361 "Large", func(b *testing.B) {
362 b.ReportAllocs()
363 src := make([][]byte, 100)
364 for i := range src {
365 src[i] = []byte("item" + string(rune(i)))
366 }
367 dst := make([]byte, 0, 2000)
368 for i := 0; i < b.N; i++ {
369 dst = AppendList(dst[:0], src, ',', NostrEscape)
370 }
371 },
372 )
373 }
374
375 func BenchmarkMarshalBool(b *testing.B) {
376 b.ReportAllocs()
377 dst := make([]byte, 0, 10)
378 for i := 0; i < b.N; i++ {
379 dst = MarshalBool(dst[:0], i%2 == 0)
380 }
381 }
382
383 func BenchmarkUnmarshalBool(b *testing.B) {
384 b.Run(
385 "True", func(b *testing.B) {
386 b.ReportAllocs()
387 src := []byte("true")
388 for i := 0; i < b.N; i++ {
389 srcCopy := make([]byte, len(src))
390 copy(srcCopy, src)
391 _, _, _ = UnmarshalBool(srcCopy)
392 }
393 },
394 )
395 b.Run(
396 "False", func(b *testing.B) {
397 b.ReportAllocs()
398 src := []byte("false")
399 for i := 0; i < b.N; i++ {
400 srcCopy := make([]byte, len(src))
401 copy(srcCopy, src)
402 _, _, _ = UnmarshalBool(srcCopy)
403 }
404 },
405 )
406 }
407