Skip to content

Commit

Permalink
[Chore] Add a description of throughput benchmarks
Browse files Browse the repository at this point in the history
  • Loading branch information
maypok86 committed Jan 10, 2024
1 parent aa5896c commit 3c4bc38
Showing 1 changed file with 64 additions and 50 deletions.
114 changes: 64 additions & 50 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,35 +74,35 @@ Otter uses a builder pattern that allows you to conveniently create a cache obje
package main

import (
"github.com/maypok86/otter"
"github.com/maypok86/otter"
)

func main() {
// NewBuilder creates a builder and sets the future cache capacity to 1000 elements.
// Returns an error if capacity <= 0.
builder, err := otter.NewBuilder[string, string](1000)
if err != nil {
panic(err)
}

// StatsEnabled determines whether statistics should be calculated when the cache is running.
// By default, statistics calculating is disabled.
builder.StatsEnabled(true)

// Cost sets a function to dynamically calculate the weight of a key-value pair.
// By default this function always returns 1.
builder.Cost(func(key string, value string) uint32 {
return uint32(len(value))
})

// Build creates a new cache object or
// returns an error if invalid parameters were passed to the builder.
cache, err := builder.Build()
if err != nil {
panic(err)
}

cache.Close()
// NewBuilder creates a builder and sets the future cache capacity to 1000 elements.
// Returns an error if capacity <= 0.
builder, err := otter.NewBuilder[string, string](1000)
if err != nil {
panic(err)
}

// StatsEnabled determines whether statistics should be calculated when the cache is running.
// By default, statistics calculating is disabled.
builder.StatsEnabled(true)

// Cost sets a function to dynamically calculate the weight of a key-value pair.
// By default this function always returns 1.
builder.Cost(func(key string, value string) uint32 {
return uint32(len(value))
})

// Build creates a new cache object or
// returns an error if invalid parameters were passed to the builder.
cache, err := builder.Build()
if err != nil {
panic(err)
}

cache.Close()
}
```

Expand All @@ -111,34 +111,34 @@ func main() {
package main

import (
"fmt"
"time"
"fmt"
"time"

"github.com/maypok86/otter"
"github.com/maypok86/otter"
)

func main() {
// create a cache with capacity equal to 10000 elements
cache, err := otter.MustBuilder[string, string](10_000).Build()
if err != nil {
panic(err)
}

// set key-value pair with ttl (1 hour)
cache.SetWithTTL("key", "value", time.Hour)

// get value from cache
value, ok := cache.Get("key")
if !ok {
panic("not found key")
}
fmt.Println(value)

// delete key-value pair from cache
cache.Delete("key")

// delete data and stop goroutines
cache.Close()
// create a cache with capacity equal to 10000 elements
cache, err := otter.MustBuilder[string, string](10_000).Build()
if err != nil {
panic(err)
}

// set key-value pair with ttl (1 hour)
cache.SetWithTTL("key", "value", time.Hour)

// get value from cache
value, ok := cache.Get("key")
if !ok {
panic("not found key")
}
fmt.Println(value)

// delete key-value pair from cache
cache.Delete("key")

// delete data and stop goroutines
cache.Close()
}
```

Expand All @@ -148,26 +148,40 @@ The benchmark code can be found [here](https://github.com/maypok86/benchmarks)

### 🚀 Performance <a id="performance" />

Throughput benchmarks are a port of the caffeine [benchmarks](https://github.com/ben-manes/caffeine/blob/master/caffeine/src/jmh/java/com/github/benmanes/caffeine/cache/GetPutBenchmark.java) in Golang.

#### Read (100%)

In this [benchmark](https://github.com/maypok86/benchmarks/blob/main/perf/bench_test.go) **8 threads** concurrently read from a cache configured with a maximum size.

<img width="60%" src="assets/results/reads=100,writes=0.png" alt="reads=100%,writes=0%" />

#### Read (75%) / Write (25%)

In this [benchmark](https://github.com/maypok86/benchmarks/blob/main/perf/bench_test.go) **6 threads** concurrently read from and **2 threads** write to a cache configured with a maximum size.

<img width="60%" src="assets/results/reads=75,writes=25.png" alt="reads=75%,writes=25%" />

#### Read (50%) / Write (50%)

In this [benchmark](https://github.com/maypok86/benchmarks/blob/main/perf/bench_test.go) **4 threads** concurrently read from and **4 threads** write to a cache configured with a maximum size.

<img width="60%" src="assets/results/reads=50,writes=50.png" alt="reads=50%,writes=50%" />

#### Read (25%) / Write (75%)

In this [benchmark](https://github.com/maypok86/benchmarks/blob/main/perf/bench_test.go) **2 threads** concurrently read from and **6 threads** write to a cache configured with a maximum size.

<img width="60%" src="assets/results/reads=25,writes=75.png" alt="reads=25%,writes=75%" />

#### Write (100%)

In this [benchmark](https://github.com/maypok86/benchmarks/blob/main/perf/bench_test.go) **8 threads** concurrently write to a cache configured with a maximum size.

<img width="60%" src="assets/results/reads=0,writes=100.png" alt="reads=0%,writes=100%" />

Otter shows fantastic speed under all loads except extreme write-heavy, but such a load is very rare for caches and usually indicates that the cache has a very small hit ratio.

### 🎯 Hit ratio <a id="hit-ratio" />

#### Zipf
Expand Down

0 comments on commit 3c4bc38

Please # to comment.