Skip to content

Instantly share code, notes, and snippets.

@maciej
Created May 30, 2019 12:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save maciej/f2f3145f4b0ad8bd66380446fe622c0b to your computer and use it in GitHub Desktop.
Save maciej/f2f3145f4b0ad8bd66380446fe622c0b to your computer and use it in GitHub Desktop.
package main
import (
"bufio"
"github.com/mediocregopher/radix/v3"
"github.com/mediocregopher/radix/v3/resp"
"net"
"testing"
)
// Benchmarked on macOS Mojave, 2017 MacBook Pro
// CPU: Intel(R) Core(TM) i7-7700HQ CPU @ 2.80GHz
// ⨯ go test -benchmem -bench 'BenchmarkSingleSet' | prettybench
// goos: darwin
// goarch: amd64
// pkg: github.com/maciej/redis_playground
// PASS
// benchmark iter time/iter bytes alloc allocs
// --------- ---- --------- ----------- ------
// BenchmarkSingleSet-8 30000 41519.00 ns/op 32 B/op 1 allocs/op
// BenchmarkSingleSetWithNoReply-8 200000 7561.00 ns/op 32 B/op 1 allocs/op
// BenchmarkSingleSetWithNoReplyManualFlush-8 1000000 1001.00 ns/op 32 B/op 1 allocs/op
// BenchmarkSingleSetWithNoReplyManualFlushNoDecode-8 1000000 1021.00 ns/op 144 B/op 2 allocs/op
// BenchmarkSingleSetManual-8 2000000 997.00 ns/op 0 B/op 0 allocs/op
func BenchmarkSingleSet(b *testing.B) {
b.StopTimer()
conn, err := radix.Dial("tcp", redisAddr)
if err != nil {
b.Fatal(err)
}
defer conn.Close()
b.StartTimer()
for i := 0; i < b.N; i++ {
err := conn.Do(radix.Cmd(nil, "SET", "foo", "bar"))
if err != nil {
b.Fail()
}
}
}
func BenchmarkSingleSetWithNoReply(b *testing.B) {
b.StopTimer()
conn, err := radix.Dial("tcp", redisAddr)
if err != nil {
b.Fatal(err)
}
defer conn.Close()
nu := new(noopUnmarshaller)
// first set client reply to "no"
var res string
err = conn.Encode(radix.Cmd(&res, "CLIENT", "REPLY", "OFF"))
b.StartTimer()
for i := 0; i < b.N; i++ {
cmd := radix.Cmd(nu, "SET", "foo", "bar")
err := conn.Encode(cmd)
if err != nil {
b.Fail()
}
err = cmd.UnmarshalRESP(nil)
if err != nil {
b.Fatal(err)
}
}
// make sure everything got written
err = conn.Do(radix.Cmd(&res, "CLIENT", "REPLY", "ON"))
if err != nil || res != "OK" {
b.Fail()
}
}
func BenchmarkSingleSetWithNoReplyManualFlush(b *testing.B) {
b.StopTimer()
netConn, err := net.Dial("tcp", redisAddr)
if err != nil {
b.Fatal(err)
}
conn := NewConnWrapWithEncodeNoFlush(netConn)
defer conn.Close()
nu := new(noopUnmarshaller)
// first set client reply to "no"
var res string
err = conn.Encode(radix.Cmd(&res, "CLIENT", "REPLY", "OFF"))
b.StartTimer()
for i := 0; i < b.N; i++ {
cmd := radix.Cmd(nu, "SET", "foo", "bar")
err := conn.EncodeNoFlush(cmd)
if err != nil {
b.Fail()
}
err = cmd.UnmarshalRESP(nil)
if err != nil {
b.Fatal(err)
}
}
// make sure everything got written
err = conn.Do(radix.Cmd(&res, "CLIENT", "REPLY", "ON"))
if err != nil || res != "OK" {
b.Fail()
}
}
func BenchmarkSingleSetWithNoReplyManualFlushNoDecode(b *testing.B) {
b.StopTimer()
netConn, err := net.Dial("tcp", redisAddr)
if err != nil {
b.Fatal(err)
}
conn := NewConnWrapWithEncodeNoFlush(netConn)
defer conn.Close()
// first set client reply to "no"
var res string
err = conn.Encode(radix.Cmd(&res, "CLIENT", "REPLY", "OFF"))
b.StartTimer()
for i := 0; i < b.N; i++ {
cmd := radix.Cmd(nil, "SET", "foo", "bar")
err := conn.EncodeNoFlush(cmd)
if err != nil {
b.Fail()
}
}
// make sure everything got written
err = conn.Do(radix.Cmd(&res, "CLIENT", "REPLY", "ON"))
if err != nil || res != "OK" {
b.Fail()
}
}
func BenchmarkSingleSetManual(b *testing.B) {
b.StopTimer()
netConn, err := net.Dial("tcp", redisAddr)
if err != nil {
b.Fatal(err)
}
conn := radix.NewConn(netConn)
defer conn.Close()
// first set client reply to "no"
err = conn.Encode(radix.Cmd(nil, "CLIENT", "REPLY", "OFF"))
buf := bufio.NewReadWriter(bufio.NewReader(netConn), bufio.NewWriter(netConn))
b.StartTimer()
for i := 0; i < b.N; i++ {
_, err := buf.WriteString("*3\r\n$3\r\nSET\r\n$3\r\nfoo\r\n$3\r\nbar\r\n")
if err != nil {
b.Fatal(err)
}
}
if err := buf.Flush(); err != nil {
b.Fatal(err)
}
// make sure everything got written
var res string
if err = conn.Do(radix.Cmd(&res, "CLIENT", "REPLY", "ON")); err != nil || res != "OK" {
b.Fatal(err)
}
}
type noopUnmarshaller struct{}
func (*noopUnmarshaller) UnmarshalRESP(*bufio.Reader) error {
return nil
}
func NewConnWrapWithEncodeNoFlush(conn net.Conn) *connWrapWithEncodeNoFlush {
return &connWrapWithEncodeNoFlush{
Conn: conn,
brw: bufio.NewReadWriter(bufio.NewReader(conn), bufio.NewWriter(conn)),
}
}
type connWrapWithEncodeNoFlush struct {
net.Conn
brw *bufio.ReadWriter
}
func (conn *connWrapWithEncodeNoFlush) Flush() error {
return conn.brw.Flush()
}
func (conn *connWrapWithEncodeNoFlush) Do(a radix.Action) error {
return a.Run(conn)
}
func (conn *connWrapWithEncodeNoFlush) Close() error {
if err := conn.brw.Flush(); err != nil {
return err
}
return conn.Conn.Close()
}
func (conn *connWrapWithEncodeNoFlush) Encode(m resp.Marshaler) error {
if err := m.MarshalRESP(conn.brw); err != nil {
return err
}
return conn.brw.Flush()
}
func (conn *connWrapWithEncodeNoFlush) EncodeNoFlush(m resp.Marshaler) error {
return m.MarshalRESP(conn.brw)
}
func (conn *connWrapWithEncodeNoFlush) Decode(u resp.Unmarshaler) error {
return u.UnmarshalRESP(conn.brw.Reader)
}
func (conn *connWrapWithEncodeNoFlush) NetConn() net.Conn {
return conn.Conn
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment