Skip to content

Commit

Permalink
Make GC comparisons more realistic
Browse files Browse the repository at this point in the history
This change generates the keys and values in advance.
This means the measurements of the GC impact of the cache algorithms
is no longer tainted by key/value creation, which comes with a lot of
heap allocations.
  • Loading branch information
rockdaboot committed Dec 21, 2023
1 parent 08dc779 commit 9e756d2
Showing 1 changed file with 54 additions and 30 deletions.
84 changes: 54 additions & 30 deletions caches_gc_overhead_comparison.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func main() {
fmt.Println("Number of repeats: ", repeat)
fmt.Println("Value size: ", valueSize)

var benchFunc func(entries, valueSize int)
var benchFunc func(kv *keyValueStore)

switch c {
case "freecache":
Expand All @@ -55,74 +55,98 @@ func main() {
os.Exit(1)
}

benchFunc(entries, valueSize)
kv := newKeyValueStore(entries, valueSize)

benchFunc(kv)
fmt.Println("GC pause for startup: ", gcPause())
for i := 0; i < repeat; i++ {
benchFunc(entries, valueSize)
benchFunc(kv)
}

fmt.Printf("GC pause for %s: %s\n", c, gcPause())
}

func stdMap(entries, valueSize int) {
func stdMap(kv *keyValueStore) {
mapCache := make(map[string][]byte)
for i := 0; i < entries; i++ {
key, val := generateKeyValue(i, valueSize)
mapCache[key] = val
for i := 0; i < kv.Size(); i++ {
mapCache[kv.Key(i)] = kv.Value(i)
}
}

func freeCache(entries, valueSize int) {
freeCache := freecache.NewCache(entries * 200) //allocate entries * 200 bytes
for i := 0; i < entries; i++ {
key, val := generateKeyValue(i, valueSize)
if err := freeCache.Set([]byte(key), val, 0); err != nil {
func freeCache(kv *keyValueStore) {
freeCache := freecache.NewCache(kv.Size() * 200) //allocate entries * 200 bytes
for i := 0; i < kv.Size(); i++ {
if err := freeCache.Set([]byte(kv.Key(i)), kv.Value(i), 0); err != nil {
fmt.Println("Error in set: ", err.Error())
}
}

firstKey, _ := generateKeyValue(1, valueSize)
v, err := freeCache.Get([]byte(firstKey))
checkFirstElement(valueSize, v, err)
v, err := freeCache.Get([]byte(kv.Key(1)))
checkFirstElement(kv.Value(1), v, err)

if freeCache.OverwriteCount() != 0 {
fmt.Println("Overwritten: ", freeCache.OverwriteCount())
}
}

func bigCache(entries, valueSize int) {
func bigCache(kv *keyValueStore) {
config := bigcache.Config{
Shards: 256,
LifeWindow: 100 * time.Minute,
MaxEntriesInWindow: entries,
MaxEntriesInWindow: kv.Size(),
MaxEntrySize: 200,
Verbose: true,
}

bigcache, _ := bigcache.NewBigCache(config)
for i := 0; i < entries; i++ {
key, val := generateKeyValue(i, valueSize)
bigcache.Set(key, val)
for i := 0; i < kv.Size(); i++ {
bigcache.Set(kv.Key(i), kv.Value(i))
}

firstKey, _ := generateKeyValue(1, valueSize)
v, err := bigcache.Get(firstKey)
checkFirstElement(valueSize, v, err)
v, err := bigcache.Get(kv.Key(1))
checkFirstElement(kv.Value(1), v, err)
}

func checkFirstElement(valueSize int, val []byte, err error) {
_, expectedVal := generateKeyValue(1, valueSize)
func checkFirstElement(expectedVal []byte, val []byte, err error) {
if err != nil {
fmt.Println("Error in get: ", err.Error())
} else if string(val) != string(expectedVal) {
fmt.Println("Wrong first element: ", string(val))
}
}

func generateKeyValue(index int, valSize int) (string, []byte) {
key := fmt.Sprintf("key-%010d", index)
fixedNumber := []byte(fmt.Sprintf("%010d", index))
val := append(make([]byte, valSize-10), fixedNumber...)
type keyValueStore struct {
valueSize int
keys []string
values []byte
}

func newKeyValueStore(entries int, valueSize int) *keyValueStore {
keys := make([]string, entries)
values := make([]byte, entries*valueSize)

for i := 0; i < entries; i++ {
keys[i] = fmt.Sprintf("key-%010d", i)
// Reuse the underlying data of key to generate the value without allocating more memory.
value := (([]byte)(keys[i]))[4:]
copy(values[(i+1)*valueSize-len(value):], value)
}

return &keyValueStore{
valueSize: valueSize,
keys: keys,
values: values,
}
}

func (store *keyValueStore) Size() int {
return len(store.keys)
}

func (store *keyValueStore) Key(index int) string {
return store.keys[index]
}

return key, val
func (store *keyValueStore) Value(index int) []byte {
return store.values[index*store.valueSize : (index+1)*store.valueSize]
}

0 comments on commit 9e756d2

Please sign in to comment.