Add bench tests for knn

This commit is contained in:
Mike Poindexter 2020-04-08 11:36:37 -07:00
parent 2a4272c95f
commit fe6e3863ba
3 changed files with 121 additions and 9 deletions

View File

@ -2,6 +2,7 @@ package tests
import (
"fmt"
"math/rand"
"sort"
"testing"
)
@ -429,3 +430,19 @@ func match(expectIn string) func(org, v interface{}) (resp, expect interface{})
return fmt.Sprintf("%v", org), expectIn
}
}
func subBenchSearch(b *testing.B, mc *mockServer) {
runBenchStep(b, mc, "KNN", keys_KNN_bench)
}
func keys_KNN_bench(mc *mockServer) error {
lat := rand.Float64()*180 - 90
lon := rand.Float64()*360 - 180
_, err := mc.conn.Do("NEARBY",
"mykey",
"LIMIT", 50,
"DISTANCE",
"POINTS",
"POINT", lat, lon)
return err
}

View File

@ -20,16 +20,20 @@ import (
var errTimeout = errors.New("timeout")
func mockCleanup() {
func mockCleanup(silent bool) {
if !silent {
fmt.Printf("Cleanup: may take some time... ")
}
files, _ := ioutil.ReadDir(".")
for _, file := range files {
if strings.HasPrefix(file.Name(), "data-mock-") {
os.RemoveAll(file.Name())
}
}
if !silent {
fmt.Printf("OK\n")
}
}
type mockServer struct {
port int
@ -39,11 +43,13 @@ type mockServer struct {
conn redis.Conn
}
func mockOpenServer() (*mockServer, error) {
func mockOpenServer(silent bool) (*mockServer, error) {
rand.Seed(time.Now().UnixNano())
port := rand.Int()%20000 + 20000
dir := fmt.Sprintf("data-mock-%d", port)
if !silent {
fmt.Printf("Starting test server at port %d\n", port)
}
logOutput := ioutil.Discard
if os.Getenv("PRINTLOG") == "1" {
logOutput = os.Stderr

View File

@ -2,10 +2,14 @@ package tests
import (
"fmt"
"math/rand"
"os"
"os/signal"
"syscall"
"testing"
"time"
"github.com/gomodule/redigo/redis"
)
const (
@ -23,18 +27,18 @@ const (
)
func TestAll(t *testing.T) {
mockCleanup()
defer mockCleanup()
mockCleanup(false)
defer mockCleanup(false)
ch := make(chan os.Signal)
signal.Notify(ch, os.Interrupt, syscall.SIGTERM)
go func() {
<-ch
mockCleanup()
mockCleanup(false)
os.Exit(1)
}()
mc, err := mockOpenServer()
mc, err := mockOpenServer(false)
if err != nil {
t.Fatal(err)
}
@ -83,3 +87,88 @@ func runStep(t *testing.T, mc *mockServer, name string, step func(mc *mockServer
fmt.Printf("["+green+"ok"+clear+"]: %s\n", name)
})
}
func BenchmarkAll(b *testing.B) {
mockCleanup(true)
defer mockCleanup(true)
ch := make(chan os.Signal)
signal.Notify(ch, os.Interrupt, syscall.SIGTERM)
go func() {
<-ch
mockCleanup(true)
os.Exit(1)
}()
mc, err := mockOpenServer(true)
if err != nil {
b.Fatal(err)
}
defer mc.Close()
runSubBenchmark(b, "search", mc, subBenchSearch)
}
func loadBenchmarkPoints(b *testing.B, mc *mockServer) (err error) {
const nPoints = 200000
rand.Seed(time.Now().UnixNano())
// add a bunch of points
for i := 0; i < nPoints; i++ {
val := fmt.Sprintf("val:%d", i)
var resp string
var lat, lon, fval float64
fval = rand.Float64()
lat = rand.Float64()*180 - 90
lon = rand.Float64()*360 - 180
resp, err = redis.String(mc.conn.Do("SET",
"mykey", val,
"FIELD", "foo", fval,
"POINT", lat, lon))
if err != nil {
return
}
if resp != "OK" {
err = fmt.Errorf("expected 'OK', got '%s'", resp)
return
}
}
return
}
func runSubBenchmark(b *testing.B, name string, mc *mockServer, bench func(t *testing.B, mc *mockServer)) {
b.Run(name, func(b *testing.B) {
bench(b, mc)
})
}
func runBenchStep(b *testing.B, mc *mockServer, name string, step func(mc *mockServer) error) {
b.Helper()
b.Run(name, func(b *testing.B) {
b.Helper()
if err := func() error {
// reset the current server
mc.ResetConn()
defer mc.ResetConn()
// clear the database so the test is consistent
if err := mc.DoBatch([][]interface{}{
{"OUTPUT", "resp"}, {"OK"},
{"FLUSHDB"}, {"OK"},
}); err != nil {
return err
}
err := loadBenchmarkPoints(b, mc)
if err != nil {
return err
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
if err := step(mc); err != nil {
return err
}
}
return nil
}(); err != nil {
b.Fatal(err)
}
})
}