251 lines
6.7 KiB
Go
251 lines
6.7 KiB
Go
package gocache
|
|
|
|
import (
|
|
"fmt"
|
|
"math/rand"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func BenchmarkMap_Get(b *testing.B) {
|
|
m := make(map[string]any)
|
|
for n := 0; n < b.N; n++ {
|
|
_, _ = m[strconv.Itoa(n)]
|
|
}
|
|
b.ReportAllocs()
|
|
}
|
|
|
|
func BenchmarkMap_Set(b *testing.B) {
|
|
values := map[string]string{
|
|
"small": "a",
|
|
"medium": strings.Repeat("a", 1024),
|
|
"large": strings.Repeat("a", 1024*100),
|
|
}
|
|
for name, value := range values {
|
|
b.Run(fmt.Sprintf("%s value", name), func(b *testing.B) {
|
|
m := make(map[string]any)
|
|
for n := 0; n < b.N; n++ {
|
|
m[strconv.Itoa(n)] = value
|
|
}
|
|
b.ReportAllocs()
|
|
})
|
|
}
|
|
}
|
|
|
|
func BenchmarkCache_Get(b *testing.B) {
|
|
evictionPolicies := []EvictionPolicy{FirstInFirstOut, LeastRecentlyUsed}
|
|
for _, evictionPolicy := range evictionPolicies {
|
|
cache := NewCache().WithMaxSize(NoMaxSize).WithMaxMemoryUsage(NoMaxMemoryUsage)
|
|
b.Run(string(evictionPolicy), func(b *testing.B) {
|
|
for n := 0; n < b.N; n++ {
|
|
cache.Get(strconv.Itoa(n))
|
|
}
|
|
b.ReportAllocs()
|
|
})
|
|
}
|
|
}
|
|
|
|
func BenchmarkCache_Set(b *testing.B) {
|
|
values := map[string]string{
|
|
"small": "a",
|
|
"medium": strings.Repeat("a", 1024),
|
|
"large": strings.Repeat("a", 1024*100),
|
|
}
|
|
evictionPolicies := []EvictionPolicy{FirstInFirstOut, LeastRecentlyUsed}
|
|
for _, evictionPolicy := range evictionPolicies {
|
|
for name, value := range values {
|
|
b.Run(fmt.Sprintf("%s %s value", evictionPolicy, name), func(b *testing.B) {
|
|
cache := NewCache().WithMaxSize(NoMaxSize).WithMaxMemoryUsage(NoMaxMemoryUsage).WithEvictionPolicy(evictionPolicy)
|
|
for n := 0; n < b.N; n++ {
|
|
cache.Set(strconv.Itoa(n), value)
|
|
}
|
|
b.ReportAllocs()
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
// BenchmarkCache_SetUsingMaxMemoryUsage does NOT test evictions, it tests the overhead of the extra work
|
|
// automatically performed when using MaxMemoryUsage
|
|
func BenchmarkCache_SetUsingMaxMemoryUsage(b *testing.B) {
|
|
values := map[string]string{
|
|
"small": "a",
|
|
"medium": strings.Repeat("a", 1024),
|
|
"large": strings.Repeat("a", 1024*100),
|
|
}
|
|
for name, value := range values {
|
|
b.Run(fmt.Sprintf("%s value", name), func(b *testing.B) {
|
|
cache := NewCache().WithMaxSize(NoMaxSize).WithMaxMemoryUsage(999 * Gigabyte)
|
|
for n := 0; n < b.N; n++ {
|
|
cache.Set(strconv.Itoa(n), value)
|
|
}
|
|
b.ReportAllocs()
|
|
})
|
|
}
|
|
}
|
|
|
|
func BenchmarkCache_SetWithMaxSize(b *testing.B) {
|
|
values := map[string]string{
|
|
"small": "a",
|
|
"medium": strings.Repeat("a", 1024),
|
|
"large": strings.Repeat("a", 1024*100),
|
|
}
|
|
maxSizes := []int{100, 10000, 100000}
|
|
for name, value := range values {
|
|
for _, maxSize := range maxSizes {
|
|
b.Run(fmt.Sprintf("%d %s value", maxSize, name), func(b *testing.B) {
|
|
cache := NewCache().WithMaxSize(maxSize)
|
|
for n := 0; n < b.N; n++ {
|
|
cache.Set(strconv.Itoa(n), value)
|
|
}
|
|
b.ReportAllocs()
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkCache_SetWithMaxSizeAndLRU(b *testing.B) {
|
|
values := map[string]string{
|
|
"small": "a",
|
|
"medium": strings.Repeat("a", 1024),
|
|
"large": strings.Repeat("a", 1024*100),
|
|
}
|
|
maxSizes := []int{100, 10000, 100000}
|
|
for name, value := range values {
|
|
for _, maxSize := range maxSizes {
|
|
b.Run(fmt.Sprintf("%d %s value", maxSize, name), func(b *testing.B) {
|
|
cache := NewCache().WithMaxSize(maxSize).WithEvictionPolicy(LeastRecentlyUsed)
|
|
for n := 0; n < b.N; n++ {
|
|
cache.Set(strconv.Itoa(n), value)
|
|
}
|
|
b.ReportAllocs()
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkCache_GetSetMultipleConcurrent(b *testing.B) {
|
|
data := map[string]string{
|
|
"k1": "v1",
|
|
"k2": "v2",
|
|
"k3": "v3",
|
|
"k4": "v4",
|
|
"k5": "v5",
|
|
"k6": "v6",
|
|
"k7": "v7",
|
|
"k8": "v8",
|
|
}
|
|
cache := NewCache().WithMaxSize(NoMaxSize)
|
|
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
for k, v := range data {
|
|
cache.Set(k, v)
|
|
cache.Get(k)
|
|
}
|
|
}
|
|
})
|
|
b.ReportAllocs()
|
|
}
|
|
|
|
func BenchmarkCache_GetSetConcurrentWithFrequentEviction(b *testing.B) {
|
|
value := strings.Repeat("a", 256)
|
|
evictionPolicies := []EvictionPolicy{FirstInFirstOut, LeastRecentlyUsed}
|
|
for _, evictionPolicy := range evictionPolicies {
|
|
b.Run(string(evictionPolicy), func(b *testing.B) {
|
|
cache := NewCache().WithEvictionPolicy(LeastRecentlyUsed).WithMaxSize(3).WithMaxMemoryUsage(NoMaxMemoryUsage)
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
k := strconv.Itoa(rand.Intn(15))
|
|
cache.Set(k, value)
|
|
_, _ = cache.Get(k)
|
|
}
|
|
})
|
|
b.ReportAllocs()
|
|
})
|
|
|
|
}
|
|
}
|
|
|
|
func BenchmarkCache_GetConcurrently(b *testing.B) {
|
|
value := strings.Repeat("a", 256)
|
|
for _, evictionPolicy := range []EvictionPolicy{FirstInFirstOut, LeastRecentlyUsed} {
|
|
b.Run(string(evictionPolicy), func(b *testing.B) {
|
|
cache := NewCache().WithMaxSize(100000)
|
|
for i := 0; i < 100000; i++ {
|
|
cache.Set(strconv.Itoa(i), value)
|
|
}
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
key := strconv.Itoa(rand.Intn(100000))
|
|
val, ok := cache.Get(key)
|
|
if !ok {
|
|
b.Errorf("key: %v; value: %v", key, val)
|
|
}
|
|
if val != value {
|
|
b.Errorf("expected: %v; got: %v", val, value)
|
|
}
|
|
}
|
|
})
|
|
b.ReportAllocs()
|
|
})
|
|
}
|
|
}
|
|
|
|
// Note: The default value for Cache.forceNilInterfaceOnNilPointer is true
|
|
func BenchmarkCache_WithForceNilInterfaceOnNilPointer(b *testing.B) {
|
|
const (
|
|
Min = 10000
|
|
Max = 99999
|
|
)
|
|
type Struct struct {
|
|
Value string
|
|
}
|
|
forceNilInterfaceOnNilPointerValues := []bool{true, false}
|
|
values := []*Struct{nil, {Value: "value"}}
|
|
for _, forceNilInterfaceOnNilPointer := range forceNilInterfaceOnNilPointerValues {
|
|
for _, value := range values {
|
|
name := fmt.Sprintf("%v", forceNilInterfaceOnNilPointer)
|
|
if value == nil {
|
|
name += " with nil struct pointer"
|
|
}
|
|
b.Run(name, func(b *testing.B) {
|
|
cache := NewCache().WithMaxSize(NoMaxSize).WithMaxMemoryUsage(NoMaxMemoryUsage).WithForceNilInterfaceOnNilPointer(forceNilInterfaceOnNilPointer)
|
|
for n := 0; n < b.N; n++ {
|
|
cache.Set(strconv.Itoa(rand.Intn(Max-Min)+Min), value)
|
|
}
|
|
b.ReportAllocs()
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func BenchmarkCache_WithForceNilInterfaceOnNilPointerWithConcurrency(b *testing.B) {
|
|
const (
|
|
Min = 10000
|
|
Max = 99999
|
|
)
|
|
type Struct struct {
|
|
Value string
|
|
}
|
|
forceNilInterfaceOnNilPointerValues := []bool{true, false}
|
|
values := []*Struct{nil, {Value: "value"}}
|
|
for _, forceNilInterfaceOnNilPointer := range forceNilInterfaceOnNilPointerValues {
|
|
for _, value := range values {
|
|
name := fmt.Sprintf("%v", forceNilInterfaceOnNilPointer)
|
|
if value == nil {
|
|
name += " with nil struct pointer"
|
|
}
|
|
b.Run(name, func(b *testing.B) {
|
|
cache := NewCache().WithMaxSize(NoMaxSize).WithMaxMemoryUsage(NoMaxMemoryUsage).WithForceNilInterfaceOnNilPointer(forceNilInterfaceOnNilPointer)
|
|
b.RunParallel(func(pb *testing.PB) {
|
|
for pb.Next() {
|
|
cache.Set(strconv.Itoa(rand.Intn(Max-Min)+Min), value)
|
|
}
|
|
})
|
|
b.ReportAllocs()
|
|
})
|
|
}
|
|
}
|
|
}
|