stringutil_test.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. package stringutil
  2. import (
  3. "fmt"
  4. "math/rand"
  5. "runtime"
  6. "runtime/debug"
  7. "sync"
  8. "testing"
  9. )
  10. var oldBank sync.Map
  11. // This is the old implementation of the string bank to use for comparison benchmarks
  12. func BankLegacy(s string) string {
  13. ss, _ := oldBank.LoadOrStore(s, s)
  14. return ss.(string)
  15. }
  16. func ClearBankLegacy() {
  17. oldBank = sync.Map{}
  18. }
  19. func copyString(s string) string {
  20. return string([]byte(s))
  21. }
  22. func generateBenchData(totalStrings, totalUnique int) []string {
  23. randStrings := make([]string, 0, totalStrings)
  24. // create totalUnique unique strings
  25. for i := 0; i < totalUnique; i++ {
  26. randStrings = append(randStrings, fmt.Sprintf("%s/%s/%s", RandSeq(10), RandSeq(10), RandSeq(10)))
  27. }
  28. // set the seed such that the resulting "remainder" strings are deterministic for each bench
  29. rand.Seed(1523942)
  30. // append a random selection from 0-totalUnique to the list.
  31. for i := 0; i < totalStrings-totalUnique; i++ {
  32. randStrings = append(randStrings, copyString(randStrings[rand.Intn(totalUnique)]))
  33. }
  34. // shuffle the list of strings
  35. rand.Shuffle(totalStrings, func(i, j int) { randStrings[i], randStrings[j] = randStrings[j], randStrings[i] })
  36. return randStrings
  37. }
  38. func benchmarkLegacyStringBank(b *testing.B, totalStrings, totalUnique int) {
  39. b.StopTimer()
  40. randStrings := generateBenchData(totalStrings, totalUnique)
  41. for i := 0; i < b.N; i++ {
  42. b.StartTimer()
  43. for b := 0; b < totalStrings; b++ {
  44. BankLegacy(randStrings[b])
  45. }
  46. b.StopTimer()
  47. ClearBankLegacy()
  48. runtime.GC()
  49. debug.FreeOSMemory()
  50. }
  51. }
  52. func benchmarkStringBank(b *testing.B, totalStrings, totalUnique int, useBankFunc bool) {
  53. b.StopTimer()
  54. randStrings := generateBenchData(totalStrings, totalUnique)
  55. for i := 0; i < b.N; i++ {
  56. b.StartTimer()
  57. for b := 0; b < totalStrings; b++ {
  58. if useBankFunc {
  59. BankFunc(randStrings[b], func() string { return randStrings[b] })
  60. } else {
  61. Bank(randStrings[b])
  62. }
  63. }
  64. b.StopTimer()
  65. ClearBank()
  66. runtime.GC()
  67. debug.FreeOSMemory()
  68. }
  69. }
  70. func BenchmarkLegacyStringBank90PercentDuplicate(b *testing.B) {
  71. benchmarkLegacyStringBank(b, 1_000_000, 100_000)
  72. }
  73. func BenchmarkLegacyStringBank75PercentDuplicate(b *testing.B) {
  74. benchmarkLegacyStringBank(b, 1_000_000, 250_000)
  75. }
  76. func BenchmarkLegacyStringBank50PercentDuplicate(b *testing.B) {
  77. benchmarkLegacyStringBank(b, 1_000_000, 100_000)
  78. }
  79. func BenchmarkLegacyStringBank25PercentDuplicate(b *testing.B) {
  80. benchmarkLegacyStringBank(b, 1_000_000, 750_000)
  81. }
  82. func BenchmarkLegacyStringBankNoDuplicate(b *testing.B) {
  83. benchmarkLegacyStringBank(b, 1_000_000, 1_000_000)
  84. }
  85. func BenchmarkStringBank90PercentDuplicate(b *testing.B) {
  86. benchmarkStringBank(b, 1_000_000, 100_000, false)
  87. }
  88. func BenchmarkStringBank75PercentDuplicate(b *testing.B) {
  89. benchmarkStringBank(b, 1_000_000, 250_000, false)
  90. }
  91. func BenchmarkStringBank50PercentDuplicate(b *testing.B) {
  92. benchmarkStringBank(b, 1_000_000, 100_000, false)
  93. }
  94. func BenchmarkStringBank25PercentDuplicate(b *testing.B) {
  95. benchmarkStringBank(b, 1_000_000, 750_000, false)
  96. }
  97. func BenchmarkStringBankNoDuplicate(b *testing.B) {
  98. benchmarkStringBank(b, 1_000_000, 1_000_000, false)
  99. }
  100. func BenchmarkStringBankFunc90PercentDuplicate(b *testing.B) {
  101. benchmarkStringBank(b, 1_000_000, 100_000, false)
  102. }
  103. func BenchmarkStringBankFunc75PercentDuplicate(b *testing.B) {
  104. benchmarkStringBank(b, 1_000_000, 250_000, false)
  105. }
  106. func BenchmarkStringBankFunc50PercentDuplicate(b *testing.B) {
  107. benchmarkStringBank(b, 1_000_000, 100_000, false)
  108. }
  109. func BenchmarkStringBankFunc25PercentDuplicate(b *testing.B) {
  110. benchmarkStringBank(b, 1_000_000, 750_000, false)
  111. }
  112. func BenchmarkStringBankFuncNoDuplicate(b *testing.B) {
  113. benchmarkStringBank(b, 1_000_000, 1_000_000, false)
  114. }