瀏覽代碼

Explore go unique package string interning benchmarks.

Matt Bolt 1 年之前
父節點
當前提交
f3fe18986b
共有 2 個文件被更改,包括 73 次插入53 次删除
  1. 9 0
      core/pkg/util/stringutil/stringutil.go
  2. 64 53
      core/pkg/util/stringutil/stringutil_test.go

+ 9 - 0
core/pkg/util/stringutil/stringutil.go

@@ -103,6 +103,15 @@ func RandSeq(n int) string {
 	return string(b)
 }
 
+// RandSeq generates a pseudo-random alphabetic string of the given length
+func RandSeqWith(r *rand.Rand, n int) string {
+	b := make([]rune, n)
+	for i := range b {
+		b[i] = alpha[r.Intn(len(alpha))] // #nosec No need for a cryptographic strength random here
+	}
+	return string(b)
+}
+
 // FormatBytes takes a number of bytes and formats it as a string
 func FormatBytes(numBytes int64) string {
 	if numBytes > TiB {

+ 64 - 53
core/pkg/util/stringutil/stringutil_test.go

@@ -1,16 +1,37 @@
-package stringutil
+package stringutil_test
 
 import (
 	"fmt"
 	"math/rand"
-	"runtime"
-	"runtime/debug"
+	"strings"
 	"sync"
 	"testing"
+
+	"github.com/opencost/opencost/core/pkg/util/stringutil"
 )
 
 var oldBank sync.Map
 
+type bankTest struct {
+	Bank     func(string) string
+	BankFunc func(string, func() string) string
+	Clear    func()
+}
+
+var (
+	legacyTest = bankTest{
+		Bank:     BankLegacy,
+		BankFunc: func(s string, f func() string) string { return s },
+		Clear:    ClearBankLegacy,
+	}
+
+	standardBankTest = bankTest{
+		Bank:     stringutil.Bank,
+		BankFunc: stringutil.BankFunc,
+		Clear:    stringutil.ClearBank,
+	}
+)
+
 // This is the old implementation of the string bank to use for comparison benchmarks
 func BankLegacy(s string) string {
 	ss, _ := oldBank.LoadOrStore(s, s)
@@ -27,118 +48,108 @@ func copyString(s string) string {
 
 func generateBenchData(totalStrings, totalUnique int) []string {
 	randStrings := make([]string, 0, totalStrings)
+	r := rand.New(rand.NewSource(27644437))
 
 	// create totalUnique unique strings
-	for i := 0; i < totalUnique; i++ {
-		randStrings = append(randStrings, fmt.Sprintf("%s/%s/%s", RandSeq(10), RandSeq(10), RandSeq(10)))
+	for range totalUnique {
+		randStrings = append(
+			randStrings,
+			fmt.Sprintf("%s/%s/%s", stringutil.RandSeqWith(r, 10), stringutil.RandSeqWith(r, 10), stringutil.RandSeqWith(r, 10)),
+		)
 	}
 
 	// set the seed such that the resulting "remainder" strings are deterministic for each bench
-	rand.Seed(1523942)
+	r = rand.New(rand.NewSource(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)]))
+	for range totalStrings - totalUnique {
+		randStrings = append(randStrings, strings.Clone(randStrings[r.Intn(totalUnique)]))
 	}
 
 	// shuffle the list of strings
-	rand.Shuffle(totalStrings, func(i, j int) { randStrings[i], randStrings[j] = randStrings[j], randStrings[i] })
+	r.Shuffle(totalStrings, func(i, j int) { randStrings[i], randStrings[j] = randStrings[j], randStrings[i] })
 
 	return randStrings
 }
 
-func benchmarkLegacyStringBank(b *testing.B, totalStrings, totalUnique int) {
+func benchmarkStringBank(b *testing.B, bt bankTest, 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++ {
-			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.Run(b.Name(), func(b *testing.B) {
+		for i := 0; i < b.N; i++ {
+			b.StartTimer()
+			for bb := 0; bb < totalStrings; bb++ {
+				if useBankFunc {
+					bt.BankFunc(randStrings[bb], func() string { return randStrings[bb] })
+				} else {
+					bt.Bank(randStrings[bb])
+				}
 			}
+			b.StopTimer()
+			bt.Clear()
+			//runtime.GC()
+			//debug.FreeOSMemory()
 		}
-		b.StopTimer()
-		ClearBank()
-		runtime.GC()
-		debug.FreeOSMemory()
-	}
+	})
 }
 
 func BenchmarkLegacyStringBank90PercentDuplicate(b *testing.B) {
-	benchmarkLegacyStringBank(b, 1_000_000, 100_000)
+	benchmarkStringBank(b, legacyTest, 1_000_000, 100_000, false)
 }
 
 func BenchmarkLegacyStringBank75PercentDuplicate(b *testing.B) {
-	benchmarkLegacyStringBank(b, 1_000_000, 250_000)
+	benchmarkStringBank(b, legacyTest, 1_000_000, 250_000, false)
 }
 
 func BenchmarkLegacyStringBank50PercentDuplicate(b *testing.B) {
-	benchmarkLegacyStringBank(b, 1_000_000, 100_000)
+	benchmarkStringBank(b, legacyTest, 1_000_000, 100_000, false)
 }
 
 func BenchmarkLegacyStringBank25PercentDuplicate(b *testing.B) {
-	benchmarkLegacyStringBank(b, 1_000_000, 750_000)
+	benchmarkStringBank(b, legacyTest, 1_000_000, 750_000, false)
 }
 
 func BenchmarkLegacyStringBankNoDuplicate(b *testing.B) {
-	benchmarkLegacyStringBank(b, 1_000_000, 1_000_000)
+	benchmarkStringBank(b, legacyTest, 1_000_000, 1_000_000, false)
 }
 
 func BenchmarkStringBank90PercentDuplicate(b *testing.B) {
-	benchmarkStringBank(b, 1_000_000, 100_000, false)
+	benchmarkStringBank(b, standardBankTest, 1_000_000, 100_000, false)
 }
 
 func BenchmarkStringBank75PercentDuplicate(b *testing.B) {
-	benchmarkStringBank(b, 1_000_000, 250_000, false)
+	benchmarkStringBank(b, standardBankTest, 1_000_000, 250_000, false)
 }
 
 func BenchmarkStringBank50PercentDuplicate(b *testing.B) {
-	benchmarkStringBank(b, 1_000_000, 100_000, false)
+	benchmarkStringBank(b, standardBankTest, 1_000_000, 100_000, false)
 }
 
 func BenchmarkStringBank25PercentDuplicate(b *testing.B) {
-	benchmarkStringBank(b, 1_000_000, 750_000, false)
+	benchmarkStringBank(b, standardBankTest, 1_000_000, 750_000, false)
 }
 
 func BenchmarkStringBankNoDuplicate(b *testing.B) {
-	benchmarkStringBank(b, 1_000_000, 1_000_000, false)
+	benchmarkStringBank(b, standardBankTest, 1_000_000, 1_000_000, false)
 }
 
 func BenchmarkStringBankFunc90PercentDuplicate(b *testing.B) {
-	benchmarkStringBank(b, 1_000_000, 100_000, false)
+	benchmarkStringBank(b, standardBankTest, 1_000_000, 100_000, true)
 }
 
 func BenchmarkStringBankFunc75PercentDuplicate(b *testing.B) {
-	benchmarkStringBank(b, 1_000_000, 250_000, false)
+	benchmarkStringBank(b, standardBankTest, 1_000_000, 250_000, true)
 }
 
 func BenchmarkStringBankFunc50PercentDuplicate(b *testing.B) {
-	benchmarkStringBank(b, 1_000_000, 100_000, false)
+	benchmarkStringBank(b, standardBankTest, 1_000_000, 100_000, true)
 }
 
 func BenchmarkStringBankFunc25PercentDuplicate(b *testing.B) {
-	benchmarkStringBank(b, 1_000_000, 750_000, false)
+	benchmarkStringBank(b, standardBankTest, 1_000_000, 750_000, true)
 }
 
 func BenchmarkStringBankFuncNoDuplicate(b *testing.B) {
-	benchmarkStringBank(b, 1_000_000, 1_000_000, false)
+	benchmarkStringBank(b, standardBankTest, 1_000_000, 1_000_000, true)
 }