diff --git a/Makefile b/Makefile
index bded315..5fbf4d4 100644
--- a/Makefile
+++ b/Makefile
@@ -27,3 +27,5 @@ test-win:
cover:
go tool cover -html=./coverage/coverage.out
+benchmark:
+ go run redis_benchmark.go $(if $(commands),-commands="$(commands)") $(if $(use_local_server),-use_local_server)
diff --git a/README.md b/README.md
index 488c97b..5d0d33e 100644
--- a/README.md
+++ b/README.md
@@ -155,31 +155,17 @@ Redis clients.
# Benchmarks
-The following benchmark only applies to the TCP client-server mode.
+To compare command performance with Redis, benchmarks can be run with:
-Hardware: MacBook Pro 14in, M1 chip, 16GB RAM, 8 Cores
-Command: `redis-benchmark -h localhost -p 7480 -q -t ping,set,get,incr,lpush,rpush,lpop,rpop,sadd,hset,zpopmin,lrange,mset`
-Result:
-```
-PING_INLINE: 89285.71 requests per second, p50=0.247 msec
-PING_MBULK: 85543.20 requests per second, p50=0.239 msec
-SET: 65573.77 requests per second, p50=0.455 msec
-GET: 79176.56 requests per second, p50=0.295 msec
-INCR: 68870.52 requests per second, p50=0.439 msec
-LPUSH: 27601.44 requests per second, p50=1.567 msec
-RPUSH: 61842.92 requests per second, p50=0.519 msec
-LPOP: 58548.01 requests per second, p50=0.567 msec
-RPOP: 68681.32 requests per second, p50=0.439 msec
-SADD: 67613.25 requests per second, p50=0.479 msec
-HSET: 56561.09 requests per second, p50=0.599 msec
-ZPOPMIN: 70972.32 requests per second, p50=0.359 msec
-LPUSH (needed to benchmark LRANGE): 26434.05 requests per second, p50=1.623 msec
-LRANGE_100 (first 100 elements): 26939.66 requests per second, p50=1.263 msec
-LRANGE_300 (first 300 elements): 5081.82 requests per second, p50=9.095 msec
-LRANGE_500 (first 500 elements): 2554.87 requests per second, p50=18.191 msec
-LRANGE_600 (first 600 elements): 1903.96 requests per second, p50=24.607 msec
-MSET (10 keys): 56022.41 requests per second, p50=0.463 msec
-```
+`make benchmark`
+
+Prerequisites:
+- `brew install redis` to run the Redis server and benchmark script
+- `brew tap echovault/sugardb` & `brew install echovault/echovault/sugardb` to run the SugarDB Client-Server
+
+Benchmark script options:
+- `make benchmark use_local_server=true` runs on your local SugarDB Client-Server
+- `make benchmark commands=ping,set,get...` runs the benchmark script on the specified commands
# Supported Commands
diff --git a/docs/docs/intro.md b/docs/docs/intro.md
index 7f5373c..69f76d7 100644
--- a/docs/docs/intro.md
+++ b/docs/docs/intro.md
@@ -70,8 +70,8 @@ if err != nil {
### Homebrew
To install via homebrew, run:
-1) `brew tap echovault/echovault`
-2) `brew install echovault/echovault/echovault`
+1) `brew tap echovault/sugardb`
+2) `brew install echovault/echovault/sugardb`
Once installed, you can run the server with the following command:
`echovault --bind-addr=localhost --data-dir="path/to/persistence/directory"`
diff --git a/redis_benchmark.go b/redis_benchmark.go
new file mode 100644
index 0000000..4454f07
--- /dev/null
+++ b/redis_benchmark.go
@@ -0,0 +1,141 @@
+package main
+
+import (
+ "flag"
+ "fmt"
+ "os"
+ "os/exec"
+ "strings"
+ "text/tabwriter"
+ "time"
+)
+
+const (
+ Host = "localhost"
+ SugarDBPort = "7480"
+ RedisPort = "6379"
+)
+
+type Metrics struct {
+ CommandName string
+ RequestsPerSecond string
+ P50Latency string
+}
+
+func getCommandArgs() (string, bool) {
+ defaultCommands := "ping,set,get,incr,lpush,rpush,lpop,rpop,sadd,hset,zpopmin,lrange,mset"
+ commands := flag.String("commands", defaultCommands, "Commands to run")
+ useLocal := flag.Bool("use_local_server", false, "Run benchamark using local SugarDB server")
+ flag.Parse()
+ fmt.Printf("Provided commands: %s\n", *commands)
+ if *useLocal {
+ fmt.Println("Using local running SugarDB server")
+ }
+ return *commands, *useLocal
+}
+
+func runBenchmark(port string, commands string) ([]Metrics, error) {
+ var results []Metrics
+
+ // Run redis-benchmark
+ cmd := exec.Command("redis-benchmark", "-h", Host, "-p", port, "-q", "-t", commands)
+ output, err := cmd.CombinedOutput()
+ if err != nil {
+ return nil, err
+ }
+
+ strOutput := string(output)
+ fmt.Println(strOutput)
+ lines := strings.Split(strOutput, "\n")
+ for _, line := range lines {
+ if !strings.HasPrefix(line, "WARNING") && line != "" {
+ // Get command name
+ colonIndex := strings.Index(line, ":")
+ commandName := line[:colonIndex]
+
+ // Get requests per second
+ reqSecIndex := strings.Index(line, " requests per second")
+ spaceIndex := strings.LastIndex(line[:reqSecIndex], " ")
+ requestsPerSecond := line[spaceIndex+1 : reqSecIndex]
+
+ // Get p50 latency
+ p50Index := strings.Index(line, "p50=")
+ spaceAfterP50 := strings.Index(line[p50Index:], " ")
+ p50Latency := line[p50Index+4 : p50Index+spaceAfterP50]
+
+ results = append(results, Metrics{
+ CommandName: commandName,
+ RequestsPerSecond: requestsPerSecond,
+ P50Latency: p50Latency,
+ })
+ }
+ }
+
+ return results, nil
+}
+
+func createDisplayTable(redisResults []Metrics, sugarDBResults []Metrics) {
+ if len(sugarDBResults) != len(redisResults) {
+ fmt.Println("Error: Number of commands in Redis and SugarDB do not match")
+ }
+
+ fmt.Println("Benchmark Performance Results:")
+ w := tabwriter.NewWriter(os.Stdout, 0, 0, 3, ' ', 0)
+ fmt.Fprint(w, "Command\tRedis (req/sec)\tRedis p50 Latency (msec)\tSugarDB (req/sec)\tSugarDB p50 Latency (msec)\t\n")
+ for i := 0; i < len(redisResults); i++ {
+ command := redisResults[i].CommandName
+ redisReqSec := redisResults[i].RequestsPerSecond
+ redisLatency := redisResults[i].P50Latency
+ sugarDBReqSec := sugarDBResults[i].RequestsPerSecond
+ sugarDBLatency := sugarDBResults[i].P50Latency
+
+ fmt.Fprintf(w, "%s\t%s\t%s\t%s\t%s\t\n", command, redisReqSec, redisLatency, sugarDBReqSec, sugarDBLatency)
+ }
+ w.Flush()
+}
+
+func main() {
+
+ commands, useLocal := getCommandArgs()
+
+ // Start a local Redis server, wait a few seconds for it to start
+ exec.Command("redis-server", "--port", RedisPort).Start()
+ time.Sleep(2 * time.Second)
+
+ // Run benchmark on local Redis server
+ fmt.Println("-------Running Redis Benchmarks------")
+ redisResults, err := runBenchmark(RedisPort, commands)
+ if err != nil {
+ fmt.Println("Error running benchmark on Redis server:", err)
+ return
+ }
+
+ if !useLocal {
+ // Run the packaged SugarDB server, wait a few seconds for it to start
+ exec.Command("echovault", "--bind-addr=localhost", "--data-dir=persistence").Start()
+ time.Sleep(5 * time.Second)
+ }
+
+ // Run benchmark on SugarDB server
+ fmt.Println("-------Running SugarDB Benchmarks------")
+ sugarDBResults, err := runBenchmark(SugarDBPort, commands)
+ if err != nil {
+ fmt.Println("Error running benchmark on SugarDB server:", err)
+ fmt.Println("Check that the SugarDB server is running")
+ return
+ }
+
+ // Display results in a table format
+ createDisplayTable(redisResults, sugarDBResults)
+
+ // Kill the local Redis server
+ exec.Command("pkill", "-f", "redis-server").Run()
+
+ if !useLocal {
+ // Kill the packaged SugarDB server
+ exec.Command("pkill", "-f", "echovault").Run()
+ if err := os.RemoveAll("persistence"); err != nil { // Remove persistence directory
+ fmt.Println("Error removing persistence directory:", err)
+ }
+ }
+}