| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256 |
- package stringutil_test
- import (
- "fmt"
- "math/rand"
- "strings"
- "sync"
- "testing"
- "time"
- "unsafe"
- "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)
- return ss.(string)
- }
- func ClearBankLegacy() {
- oldBank = sync.Map{}
- }
- func copyString(s string) string {
- return string([]byte(s))
- }
- func generateBenchData(totalStrings, totalUnique int) [][]byte {
- randStrings := make([]string, 0, totalStrings)
- r := rand.New(rand.NewSource(27644437))
- // create totalUnique unique strings
- 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
- r = rand.New(rand.NewSource(1523942))
- // append a random selection from 0-totalUnique to the list.
- for range totalStrings - totalUnique {
- randStrings = append(randStrings, strings.Clone(randStrings[r.Intn(totalUnique)]))
- }
- // shuffle the list of strings
- r.Shuffle(totalStrings, func(i, j int) { randStrings[i], randStrings[j] = randStrings[j], randStrings[i] })
- stringBytes := make([][]byte, 0, totalStrings)
- for _, str := range randStrings {
- stringBytes = append(stringBytes, []byte(str))
- }
- return stringBytes
- }
- func benchmarkStringBank(b *testing.B, bt bankTest, totalStrings, totalUnique int, useBankFunc bool) {
- b.StopTimer()
- randStrings := generateBenchData(totalStrings, totalUnique)
- b.Run(b.Name(), func(b *testing.B) {
- for i := 0; i < b.N; i++ {
- b.StartTimer()
- for bb := 0; bb < totalStrings; bb++ {
- bytes := randStrings[bb]
- if useBankFunc {
- str := unsafe.String(unsafe.SliceData(bytes), len(bytes))
- bt.BankFunc(str, func() string {
- return string(bytes)
- })
- } else {
- bt.Bank(string(bytes))
- }
- }
- b.StopTimer()
- bt.Clear()
- //runtime.GC()
- //debug.FreeOSMemory()
- }
- })
- }
- func BenchmarkLegacyStringBank90PercentDuplicate(b *testing.B) {
- benchmarkStringBank(b, legacyTest, 1_000_000, 100_000, false)
- }
- func BenchmarkLegacyStringBank75PercentDuplicate(b *testing.B) {
- benchmarkStringBank(b, legacyTest, 1_000_000, 250_000, false)
- }
- func BenchmarkLegacyStringBank50PercentDuplicate(b *testing.B) {
- benchmarkStringBank(b, legacyTest, 1_000_000, 100_000, false)
- }
- func BenchmarkLegacyStringBank25PercentDuplicate(b *testing.B) {
- benchmarkStringBank(b, legacyTest, 1_000_000, 750_000, false)
- }
- func BenchmarkLegacyStringBankNoDuplicate(b *testing.B) {
- benchmarkStringBank(b, legacyTest, 1_000_000, 1_000_000, false)
- }
- func BenchmarkStringBank90PercentDuplicate(b *testing.B) {
- benchmarkStringBank(b, standardBankTest, 1_000_000, 100_000, false)
- }
- func BenchmarkStringBank75PercentDuplicate(b *testing.B) {
- benchmarkStringBank(b, standardBankTest, 1_000_000, 250_000, false)
- }
- func BenchmarkStringBank50PercentDuplicate(b *testing.B) {
- benchmarkStringBank(b, standardBankTest, 1_000_000, 100_000, false)
- }
- func BenchmarkStringBank25PercentDuplicate(b *testing.B) {
- benchmarkStringBank(b, standardBankTest, 1_000_000, 750_000, false)
- }
- func BenchmarkStringBankNoDuplicate(b *testing.B) {
- benchmarkStringBank(b, standardBankTest, 1_000_000, 1_000_000, false)
- }
- func BenchmarkStringBankFunc90PercentDuplicate(b *testing.B) {
- benchmarkStringBank(b, standardBankTest, 1_000_000, 100_000, true)
- }
- func BenchmarkStringBankFunc75PercentDuplicate(b *testing.B) {
- benchmarkStringBank(b, standardBankTest, 1_000_000, 250_000, true)
- }
- func BenchmarkStringBankFunc50PercentDuplicate(b *testing.B) {
- benchmarkStringBank(b, standardBankTest, 1_000_000, 100_000, true)
- }
- func BenchmarkStringBankFunc25PercentDuplicate(b *testing.B) {
- benchmarkStringBank(b, standardBankTest, 1_000_000, 750_000, true)
- }
- func BenchmarkStringBankFuncNoDuplicate(b *testing.B) {
- benchmarkStringBank(b, standardBankTest, 1_000_000, 1_000_000, true)
- }
- const LruCapacity = 500_000
- const LruEvictInterval = 5 * time.Second
- func BenchmarkLruStringBankFunc90PercentDuplicate(b *testing.B) {
- prevBank := stringutil.GetStringBank()
- defer func() {
- stringutil.UpdateStringBank(prevBank)
- }()
- sb := stringutil.NewLruStringBank(LruCapacity, LruEvictInterval)
- defer func() {
- if lruBank, ok := sb.(interface{ Stop() }); ok {
- lruBank.Stop()
- }
- }()
- stringutil.UpdateStringBank(sb)
- benchmarkStringBank(b, standardBankTest, 1_000_000, 100_000, true)
- }
- func BenchmarkLruStringBankFunc75PercentDuplicate(b *testing.B) {
- prevBank := stringutil.GetStringBank()
- defer func() {
- stringutil.UpdateStringBank(prevBank)
- }()
- sb := stringutil.NewLruStringBank(LruCapacity, LruEvictInterval)
- defer func() {
- if lruBank, ok := sb.(interface{ Stop() }); ok {
- lruBank.Stop()
- }
- }()
- stringutil.UpdateStringBank(sb)
- benchmarkStringBank(b, standardBankTest, 1_000_000, 250_000, true)
- }
- func BenchmarkLruStringBankFunc50PercentDuplicate(b *testing.B) {
- prevBank := stringutil.GetStringBank()
- defer func() {
- stringutil.UpdateStringBank(prevBank)
- }()
- sb := stringutil.NewLruStringBank(LruCapacity, LruEvictInterval)
- defer func() {
- if lruBank, ok := sb.(interface{ Stop() }); ok {
- lruBank.Stop()
- }
- }()
- stringutil.UpdateStringBank(sb)
- benchmarkStringBank(b, standardBankTest, 1_000_000, 100_000, true)
- }
- func BenchmarkLruStringBankFunc25PercentDuplicate(b *testing.B) {
- prevBank := stringutil.GetStringBank()
- defer func() {
- stringutil.UpdateStringBank(prevBank)
- }()
- sb := stringutil.NewLruStringBank(LruCapacity, LruEvictInterval)
- defer func() {
- if lruBank, ok := sb.(interface{ Stop() }); ok {
- lruBank.Stop()
- }
- }()
- stringutil.UpdateStringBank(sb)
- benchmarkStringBank(b, standardBankTest, 1_000_000, 750_000, true)
- }
- func BenchmarkLruStringBankFuncNoDuplicate(b *testing.B) {
- prevBank := stringutil.GetStringBank()
- defer func() {
- stringutil.UpdateStringBank(prevBank)
- }()
- sb := stringutil.NewLruStringBank(LruCapacity, LruEvictInterval)
- defer func() {
- if lruBank, ok := sb.(interface{ Stop() }); ok {
- lruBank.Stop()
- }
- }()
- stringutil.UpdateStringBank(sb)
- benchmarkStringBank(b, standardBankTest, 1_000_000, 1_000_000, true)
- }
|