|
|
@@ -0,0 +1,144 @@
|
|
|
+package stringutil
|
|
|
+
|
|
|
+import (
|
|
|
+ "fmt"
|
|
|
+ "math/rand"
|
|
|
+ "runtime"
|
|
|
+ "runtime/debug"
|
|
|
+ "sync"
|
|
|
+ "testing"
|
|
|
+)
|
|
|
+
|
|
|
+var oldBank sync.Map
|
|
|
+
|
|
|
+// This is the old implementation of the string bank to use for comparison benchmarks
|
|
|
+func BankLegacy(s string) string {
|
|
|
+ ss, _ := oldBank.LoadOrStore(s, s)
|
|
|
+ return ss.(string)
|
|
|
+}
|
|
|
+
|
|
|
+func ClearBankLegacy() {
|
|
|
+ oldBank = sync.Map{}
|
|
|
+}
|
|
|
+
|
|
|
+func copyString(s string) string {
|
|
|
+ return string([]byte(s))
|
|
|
+}
|
|
|
+
|
|
|
+func generateBenchData(totalStrings, totalUnique int) []string {
|
|
|
+ randStrings := make([]string, 0, totalStrings)
|
|
|
+
|
|
|
+ // create totalUnique unique strings
|
|
|
+ for i := 0; i < totalUnique; i++ {
|
|
|
+ randStrings = append(randStrings, fmt.Sprintf("%s/%s/%s", RandSeq(10), RandSeq(10), RandSeq(10)))
|
|
|
+ }
|
|
|
+
|
|
|
+ // set the seed such that the resulting "remainder" strings are deterministic for each bench
|
|
|
+ rand.Seed(1523942)
|
|
|
+
|
|
|
+ // append a random selection from 0-totalUnique to the list.
|
|
|
+ for i := 0; i < totalStrings-totalUnique; i++ {
|
|
|
+ randStrings = append(randStrings, copyString(randStrings[rand.Intn(totalUnique)]))
|
|
|
+ }
|
|
|
+
|
|
|
+ // shuffle the list of strings
|
|
|
+ rand.Shuffle(totalStrings, func(i, j int) { randStrings[i], randStrings[j] = randStrings[j], randStrings[i] })
|
|
|
+
|
|
|
+ return randStrings
|
|
|
+}
|
|
|
+
|
|
|
+func benchmarkLegacyStringBank(b *testing.B, totalStrings, totalUnique int) {
|
|
|
+ b.StopTimer()
|
|
|
+ randStrings := generateBenchData(totalStrings, totalUnique)
|
|
|
+
|
|
|
+ for i := 0; i < b.N; i++ {
|
|
|
+ b.StartTimer()
|
|
|
+ for b := 0; b < totalStrings; b++ {
|
|
|
+ BankLegacy(randStrings[b])
|
|
|
+ }
|
|
|
+ b.StopTimer()
|
|
|
+ ClearBankLegacy()
|
|
|
+ runtime.GC()
|
|
|
+ debug.FreeOSMemory()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func benchmarkStringBank(b *testing.B, totalStrings, totalUnique int, useBankFunc bool) {
|
|
|
+ b.StopTimer()
|
|
|
+ randStrings := generateBenchData(totalStrings, totalUnique)
|
|
|
+
|
|
|
+ for i := 0; i < b.N; i++ {
|
|
|
+ b.StartTimer()
|
|
|
+ for b := 0; b < totalStrings; b++ {
|
|
|
+ if useBankFunc {
|
|
|
+ BankFunc(randStrings[b], func() string { return randStrings[b] })
|
|
|
+ } else {
|
|
|
+ Bank(randStrings[b])
|
|
|
+ }
|
|
|
+ }
|
|
|
+ b.StopTimer()
|
|
|
+ ClearBank()
|
|
|
+ runtime.GC()
|
|
|
+ debug.FreeOSMemory()
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func BenchmarkLegacyStringBank90PercentDuplicate(b *testing.B) {
|
|
|
+ benchmarkLegacyStringBank(b, 1_000_000, 100_000)
|
|
|
+}
|
|
|
+
|
|
|
+func BenchmarkLegacyStringBank75PercentDuplicate(b *testing.B) {
|
|
|
+ benchmarkLegacyStringBank(b, 1_000_000, 250_000)
|
|
|
+}
|
|
|
+
|
|
|
+func BenchmarkLegacyStringBank50PercentDuplicate(b *testing.B) {
|
|
|
+ benchmarkLegacyStringBank(b, 1_000_000, 100_000)
|
|
|
+}
|
|
|
+
|
|
|
+func BenchmarkLegacyStringBank25PercentDuplicate(b *testing.B) {
|
|
|
+ benchmarkLegacyStringBank(b, 1_000_000, 750_000)
|
|
|
+}
|
|
|
+
|
|
|
+func BenchmarkLegacyStringBankNoDuplicate(b *testing.B) {
|
|
|
+ benchmarkLegacyStringBank(b, 1_000_000, 1_000_000)
|
|
|
+}
|
|
|
+
|
|
|
+func BenchmarkStringBank90PercentDuplicate(b *testing.B) {
|
|
|
+ benchmarkStringBank(b, 1_000_000, 100_000, false)
|
|
|
+}
|
|
|
+
|
|
|
+func BenchmarkStringBank75PercentDuplicate(b *testing.B) {
|
|
|
+ benchmarkStringBank(b, 1_000_000, 250_000, false)
|
|
|
+}
|
|
|
+
|
|
|
+func BenchmarkStringBank50PercentDuplicate(b *testing.B) {
|
|
|
+ benchmarkStringBank(b, 1_000_000, 100_000, false)
|
|
|
+}
|
|
|
+
|
|
|
+func BenchmarkStringBank25PercentDuplicate(b *testing.B) {
|
|
|
+ benchmarkStringBank(b, 1_000_000, 750_000, false)
|
|
|
+}
|
|
|
+
|
|
|
+func BenchmarkStringBankNoDuplicate(b *testing.B) {
|
|
|
+ benchmarkStringBank(b, 1_000_000, 1_000_000, false)
|
|
|
+}
|
|
|
+
|
|
|
+func BenchmarkStringBankFunc90PercentDuplicate(b *testing.B) {
|
|
|
+ benchmarkStringBank(b, 1_000_000, 100_000, false)
|
|
|
+}
|
|
|
+
|
|
|
+func BenchmarkStringBankFunc75PercentDuplicate(b *testing.B) {
|
|
|
+ benchmarkStringBank(b, 1_000_000, 250_000, false)
|
|
|
+}
|
|
|
+
|
|
|
+func BenchmarkStringBankFunc50PercentDuplicate(b *testing.B) {
|
|
|
+ benchmarkStringBank(b, 1_000_000, 100_000, false)
|
|
|
+}
|
|
|
+
|
|
|
+func BenchmarkStringBankFunc25PercentDuplicate(b *testing.B) {
|
|
|
+ benchmarkStringBank(b, 1_000_000, 750_000, false)
|
|
|
+}
|
|
|
+
|
|
|
+func BenchmarkStringBankFuncNoDuplicate(b *testing.B) {
|
|
|
+ benchmarkStringBank(b, 1_000_000, 1_000_000, false)
|
|
|
+}
|