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