github.com/haalcala/mattermost-server-change-repo@v0.0.0-20210713015153-16753fbeee5f/services/cache/lru_striped_bench_test.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package cache_test
     5  
     6  import (
     7  	"fmt"
     8  	"runtime"
     9  	"sync"
    10  	"testing"
    11  
    12  	"github.com/cespare/xxhash/v2"
    13  
    14  	"github.com/mattermost/mattermost-server/v5/services/cache"
    15  )
    16  
    17  const (
    18  	m = 500_000
    19  )
    20  
    21  func BenchmarkLRUStriped(b *testing.B) {
    22  	opts := cache.LRUOptions{
    23  		Name:                   "",
    24  		Size:                   128,
    25  		DefaultExpiry:          0,
    26  		InvalidateClusterEvent: "",
    27  		StripedBuckets:         runtime.NumCPU() - 1,
    28  	}
    29  
    30  	cache, err := cache.NewLRUStriped(opts)
    31  	if err != nil {
    32  		panic(err)
    33  	}
    34  	// prepare keys and initial cache values and set routine
    35  	keys := make([]string, 0, m)
    36  	// bucketKeys is to demonstrate that splitted locks is working correctly
    37  	// by assigning one sequence of key for each bucket.
    38  	bucketKeys := make([][]string, opts.StripedBuckets)
    39  	for i := 0; i < m; i++ {
    40  		key := fmt.Sprintf("%d-key-%d", i, i)
    41  		keys = append(keys, key)
    42  		bucketKey := xxhash.Sum64String(key) % uint64(opts.StripedBuckets)
    43  		bucketKeys[bucketKey] = append(bucketKeys[bucketKey], key)
    44  	}
    45  	for i := 0; i < opts.Size; i++ {
    46  		cache.Set(keys[i], "preflight")
    47  	}
    48  
    49  	wgGet := &sync.WaitGroup{}
    50  	wgSet := &sync.WaitGroup{}
    51  	// need buffered chan because if the set routine finished before we write into the chan,
    52  	// we're left without any consumer, making any write to the chan waiting forever.
    53  	stopSet := make(chan bool, 1)
    54  	set := func() {
    55  		defer wgSet.Done()
    56  		for i := 0; i < m; i++ {
    57  			select {
    58  			case <-stopSet:
    59  				return
    60  			default:
    61  				_ = cache.Set(keys[i], "ignored")
    62  			}
    63  		}
    64  	}
    65  
    66  	get := func(bucket int) {
    67  		defer wgGet.Done()
    68  		var out string
    69  		for i := 0; i < m; i++ {
    70  			_ = cache.Get(bucketKeys[bucket][i%opts.Size], &out)
    71  		}
    72  	}
    73  
    74  	b.StopTimer()
    75  	b.ResetTimer()
    76  	for i := 0; i < b.N; i++ {
    77  		wgSet.Add(1)
    78  		go set()
    79  		for j := 0; j < opts.StripedBuckets; j++ {
    80  			wgGet.Add(1)
    81  			go get(j)
    82  		}
    83  
    84  		b.StartTimer()
    85  		wgGet.Wait()
    86  		b.StopTimer()
    87  
    88  		stopSet <- true
    89  		wgSet.Wait()
    90  	}
    91  }