mirror of https://github.com/tidwall/tile38.git
Updated benchmark tool
This commit is contained in:
parent
6a6f4b67c6
commit
f0209c8aad
|
@ -295,11 +295,11 @@
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
digest = "1:630381558bc538e831db8468dd0dc2702d81789f79b8ddf665eeebc729e2a055"
|
digest = "1:e84d0aa788bd55e938ebbaa62782385ca4da00b63c1d6bf23270c031a2ae9a88"
|
||||||
name = "github.com/tidwall/redbench"
|
name = "github.com/tidwall/redbench"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
pruneopts = ""
|
pruneopts = ""
|
||||||
revision = "637a608ebec1acbf049c2e4a5eda6c2d72aa3af1"
|
revision = "17c5b5b864a4b072481036ac689913156f5bb81c"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
branch = "master"
|
branch = "master"
|
||||||
|
|
|
@ -2,6 +2,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
|
@ -23,7 +24,7 @@ var (
|
||||||
pipeline = 1
|
pipeline = 1
|
||||||
csv = false
|
csv = false
|
||||||
json = false
|
json = false
|
||||||
tests = "PING,SET,GET,SEARCH,EVAL"
|
tests = "PING,SET,GET,INTERSECTS,WITHIN,NEARBY,EVAL"
|
||||||
redis = false
|
redis = false
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -146,15 +147,23 @@ func randPoint() (lat, lon float64) {
|
||||||
return rand.Float64()*180 - 90, rand.Float64()*360 - 180
|
return rand.Float64()*180 - 90, rand.Float64()*360 - 180
|
||||||
}
|
}
|
||||||
|
|
||||||
func randRect() (minlat, minlon, maxlat, maxlon float64) {
|
func isValidRect(minlat, minlon, maxlat, maxlon float64) bool {
|
||||||
|
return minlat > -90 && maxlat < 90 && minlon > -180 && maxlon < 180
|
||||||
|
}
|
||||||
|
|
||||||
|
func randRect(meters float64) (minlat, minlon, maxlat, maxlon float64) {
|
||||||
for {
|
for {
|
||||||
minlat, minlon = randPoint()
|
lat, lon := randPoint()
|
||||||
maxlat, maxlon = minlat+1, minlon+1
|
maxlat, _ = destinationPoint(lat, lon, meters, 0)
|
||||||
if maxlat <= 180 && maxlon <= 180 {
|
_, maxlon = destinationPoint(lat, lon, meters, 90)
|
||||||
|
minlat, _ = destinationPoint(lat, lon, meters, 180)
|
||||||
|
_, minlon = destinationPoint(lat, lon, meters, 270)
|
||||||
|
if isValidRect(minlat, minlon, maxlat, maxlon) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepFn(conn net.Conn) bool {
|
func prepFn(conn net.Conn) bool {
|
||||||
if json {
|
if json {
|
||||||
conn.Write([]byte("output json\r\n"))
|
conn.Write([]byte("output json\r\n"))
|
||||||
|
@ -222,7 +231,7 @@ func main() {
|
||||||
redbench.Bench("SET (rect)", addr, opts, prepFn,
|
redbench.Bench("SET (rect)", addr, opts, prepFn,
|
||||||
func(buf []byte) []byte {
|
func(buf []byte) []byte {
|
||||||
i := atomic.AddInt64(&i, 1)
|
i := atomic.AddInt64(&i, 1)
|
||||||
minlat, minlon, maxlat, maxlon := randRect()
|
minlat, minlon, maxlat, maxlon := randRect(10000)
|
||||||
return redbench.AppendCommand(buf, "SET", "key:bench", "id:"+strconv.FormatInt(i, 10), "BOUNDS",
|
return redbench.AppendCommand(buf, "SET", "key:bench", "id:"+strconv.FormatInt(i, 10), "BOUNDS",
|
||||||
strconv.FormatFloat(minlat, 'f', 5, 64),
|
strconv.FormatFloat(minlat, 'f', 5, 64),
|
||||||
strconv.FormatFloat(minlon, 'f', 5, 64),
|
strconv.FormatFloat(minlon, 'f', 5, 64),
|
||||||
|
@ -270,36 +279,270 @@ func main() {
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
case "SEARCH":
|
case "INTERSECTS",
|
||||||
if !redis {
|
"INTERSECTS-RECT", "INTERSECTS-RECT-1000", "INTERSECTS-RECT-10000", "INTERSECTS-RECT-100000",
|
||||||
redbench.Bench("SEARCH (nearby 1km)", addr, opts, prepFn,
|
"INTERSECTS-CIRCLE", "INTERSECTS-CIRCLE-1000", "INTERSECTS-CIRCLE-10000", "INTERSECTS-CIRCLE-100000":
|
||||||
|
if redis {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
switch strings.ToUpper(strings.TrimSpace(test)) {
|
||||||
|
case "INTERSECTS", "INTERSECTS-CIRCLE", "INTERSECTS-CIRCLE-1000":
|
||||||
|
redbench.Bench("INTERSECTS (intersects-circle 1km)", addr, opts, prepFn,
|
||||||
func(buf []byte) []byte {
|
func(buf []byte) []byte {
|
||||||
lat, lon := randPoint()
|
lat, lon := randPoint()
|
||||||
return redbench.AppendCommand(buf, "NEARBY", "key:bench", "COUNT", "POINT",
|
return redbench.AppendCommand(buf,
|
||||||
|
"INTERSECTS", "key:bench", "COUNT", "CIRCLE",
|
||||||
strconv.FormatFloat(lat, 'f', 5, 64),
|
strconv.FormatFloat(lat, 'f', 5, 64),
|
||||||
strconv.FormatFloat(lon, 'f', 5, 64),
|
strconv.FormatFloat(lon, 'f', 5, 64),
|
||||||
"1000")
|
"1000")
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
redbench.Bench("SEARCH (nearby 10km)", addr, opts, prepFn,
|
}
|
||||||
|
switch strings.ToUpper(strings.TrimSpace(test)) {
|
||||||
|
case "INTERSECTS", "INTERSECTS-CIRCLE", "INTERSECTS-CIRCLE-10000":
|
||||||
|
redbench.Bench("INTERSECTS (intersects-circle 10km)", addr, opts, prepFn,
|
||||||
func(buf []byte) []byte {
|
func(buf []byte) []byte {
|
||||||
lat, lon := randPoint()
|
lat, lon := randPoint()
|
||||||
return redbench.AppendCommand(buf, "NEARBY", "key:bench", "COUNT", "POINT",
|
return redbench.AppendCommand(buf,
|
||||||
|
"INTERSECTS", "key:bench", "COUNT", "CIRCLE",
|
||||||
strconv.FormatFloat(lat, 'f', 5, 64),
|
strconv.FormatFloat(lat, 'f', 5, 64),
|
||||||
strconv.FormatFloat(lon, 'f', 5, 64),
|
strconv.FormatFloat(lon, 'f', 5, 64),
|
||||||
"10000")
|
"10000")
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
redbench.Bench("SEARCH (nearby 100km)", addr, opts, prepFn,
|
}
|
||||||
|
switch strings.ToUpper(strings.TrimSpace(test)) {
|
||||||
|
case "INTERSECTS", "INTERSECTS-CIRCLE", "INTERSECTS-CIRCLE-100000":
|
||||||
|
redbench.Bench("INTERSECTS (intersects-circle 100km)", addr, opts, prepFn,
|
||||||
func(buf []byte) []byte {
|
func(buf []byte) []byte {
|
||||||
lat, lon := randPoint()
|
lat, lon := randPoint()
|
||||||
return redbench.AppendCommand(buf, "NEARBY", "key:bench", "COUNT", "POINT",
|
return redbench.AppendCommand(buf,
|
||||||
|
"INTERSECTS", "key:bench", "COUNT", "CIRCLE",
|
||||||
strconv.FormatFloat(lat, 'f', 5, 64),
|
strconv.FormatFloat(lat, 'f', 5, 64),
|
||||||
strconv.FormatFloat(lon, 'f', 5, 64),
|
strconv.FormatFloat(lon, 'f', 5, 64),
|
||||||
"100000")
|
"100000")
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
// INTERSECTS-BOUNDS
|
||||||
|
switch strings.ToUpper(strings.TrimSpace(test)) {
|
||||||
|
case "INTERSECTS", "INTERSECTS-BOUNDS", "INTERSECTS-BOUNDS-1000":
|
||||||
|
minlat, minlon, maxlat, maxlon := randRect(1000)
|
||||||
|
redbench.Bench("INTERSECTS (intersects-bounds 1km)", addr, opts, prepFn,
|
||||||
|
func(buf []byte) []byte {
|
||||||
|
return redbench.AppendCommand(buf,
|
||||||
|
"INTERSECTS", "key:bench", "COUNT", "BOUNDS",
|
||||||
|
strconv.FormatFloat(minlat, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(minlon, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(maxlat, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(maxlon, 'f', 5, 64))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
switch strings.ToUpper(strings.TrimSpace(test)) {
|
||||||
|
case "INTERSECTS", "INTERSECTS-BOUNDS", "INTERSECTS-BOUNDS-10000":
|
||||||
|
minlat, minlon, maxlat, maxlon := randRect(10000)
|
||||||
|
redbench.Bench("INTERSECTS (intersects-bounds 10km)", addr, opts, prepFn,
|
||||||
|
func(buf []byte) []byte {
|
||||||
|
return redbench.AppendCommand(buf,
|
||||||
|
"INTERSECTS", "key:bench", "COUNT", "BOUNDS",
|
||||||
|
strconv.FormatFloat(minlat, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(minlon, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(maxlat, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(maxlon, 'f', 5, 64))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
switch strings.ToUpper(strings.TrimSpace(test)) {
|
||||||
|
case "INTERSECTS", "INTERSECTS-BOUNDS", "INTERSECTS-BOUNDS-100000":
|
||||||
|
minlat, minlon, maxlat, maxlon := randRect(10000)
|
||||||
|
redbench.Bench("INTERSECTS (intersects-bounds 100km)", addr, opts, prepFn,
|
||||||
|
func(buf []byte) []byte {
|
||||||
|
return redbench.AppendCommand(buf,
|
||||||
|
"INTERSECTS", "key:bench", "COUNT", "BOUNDS",
|
||||||
|
strconv.FormatFloat(minlat, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(minlon, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(maxlat, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(maxlon, 'f', 5, 64))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
case "WITHIN",
|
||||||
|
"WITHIN-RECT", "WITHIN-RECT-1000", "WITHIN-RECT-10000", "WITHIN-RECT-100000",
|
||||||
|
"WITHIN-CIRCLE", "WITHIN-CIRCLE-1000", "WITHIN-CIRCLE-10000", "WITHIN-CIRCLE-100000":
|
||||||
|
if redis {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
switch strings.ToUpper(strings.TrimSpace(test)) {
|
||||||
|
case "WITHIN", "WITHIN-CIRCLE", "WITHIN-CIRCLE-1000":
|
||||||
|
redbench.Bench("WITHIN (within-circle 1km)", addr, opts, prepFn,
|
||||||
|
func(buf []byte) []byte {
|
||||||
|
lat, lon := randPoint()
|
||||||
|
return redbench.AppendCommand(buf,
|
||||||
|
"WITHIN", "key:bench", "COUNT", "CIRCLE",
|
||||||
|
strconv.FormatFloat(lat, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(lon, 'f', 5, 64),
|
||||||
|
"1000")
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
switch strings.ToUpper(strings.TrimSpace(test)) {
|
||||||
|
case "WITHIN", "WITHIN-CIRCLE", "WITHIN-CIRCLE-10000":
|
||||||
|
redbench.Bench("WITHIN (within-circle 10km)", addr, opts, prepFn,
|
||||||
|
func(buf []byte) []byte {
|
||||||
|
lat, lon := randPoint()
|
||||||
|
return redbench.AppendCommand(buf,
|
||||||
|
"WITHIN", "key:bench", "COUNT", "CIRCLE",
|
||||||
|
strconv.FormatFloat(lat, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(lon, 'f', 5, 64),
|
||||||
|
"10000")
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
switch strings.ToUpper(strings.TrimSpace(test)) {
|
||||||
|
case "WITHIN", "WITHIN-CIRCLE", "WITHIN-CIRCLE-100000":
|
||||||
|
redbench.Bench("WITHIN (within-circle 100km)", addr, opts, prepFn,
|
||||||
|
func(buf []byte) []byte {
|
||||||
|
lat, lon := randPoint()
|
||||||
|
return redbench.AppendCommand(buf,
|
||||||
|
"WITHIN", "key:bench", "COUNT", "CIRCLE",
|
||||||
|
strconv.FormatFloat(lat, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(lon, 'f', 5, 64),
|
||||||
|
"100000")
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
// WITHIN-BOUNDS
|
||||||
|
switch strings.ToUpper(strings.TrimSpace(test)) {
|
||||||
|
case "WITHIN", "WITHIN-BOUNDS", "WITHIN-BOUNDS-1000":
|
||||||
|
minlat, minlon, maxlat, maxlon := randRect(1000)
|
||||||
|
redbench.Bench("WITHIN (within-bounds 1km)", addr, opts, prepFn,
|
||||||
|
func(buf []byte) []byte {
|
||||||
|
return redbench.AppendCommand(buf,
|
||||||
|
"WITHIN", "key:bench", "COUNT", "BOUNDS",
|
||||||
|
strconv.FormatFloat(minlat, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(minlon, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(maxlat, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(maxlon, 'f', 5, 64))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
switch strings.ToUpper(strings.TrimSpace(test)) {
|
||||||
|
case "WITHIN", "WITHIN-BOUNDS", "WITHIN-BOUNDS-10000":
|
||||||
|
minlat, minlon, maxlat, maxlon := randRect(10000)
|
||||||
|
redbench.Bench("WITHIN (within-bounds 10km)", addr, opts, prepFn,
|
||||||
|
func(buf []byte) []byte {
|
||||||
|
return redbench.AppendCommand(buf,
|
||||||
|
"WITHIN", "key:bench", "COUNT", "BOUNDS",
|
||||||
|
strconv.FormatFloat(minlat, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(minlon, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(maxlat, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(maxlon, 'f', 5, 64))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
switch strings.ToUpper(strings.TrimSpace(test)) {
|
||||||
|
case "WITHIN", "WITHIN-BOUNDS", "WITHIN-BOUNDS-100000":
|
||||||
|
minlat, minlon, maxlat, maxlon := randRect(10000)
|
||||||
|
redbench.Bench("WITHIN (within-bounds 100km)", addr, opts, prepFn,
|
||||||
|
func(buf []byte) []byte {
|
||||||
|
return redbench.AppendCommand(buf,
|
||||||
|
"WITHIN", "key:bench", "COUNT", "BOUNDS",
|
||||||
|
strconv.FormatFloat(minlat, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(minlon, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(maxlat, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(maxlon, 'f', 5, 64))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
case "NEARBY",
|
||||||
|
"NEARBY-KNN", "NEARBY-KNN-1", "NEARBY-KNN-10", "NEARBY-KNN-100",
|
||||||
|
"NEARBY-POINT", "NEARBY-POINT-1000", "NEARBY-POINT-10000", "NEARBY-POINT-100000":
|
||||||
|
if redis {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
switch strings.ToUpper(strings.TrimSpace(test)) {
|
||||||
|
case "NEARBY", "NEARBY-KNN", "NEARBY-KNN-1":
|
||||||
|
redbench.Bench("NEARBY (limit 1)", addr, opts, prepFn,
|
||||||
|
func(buf []byte) []byte {
|
||||||
|
lat, lon := randPoint()
|
||||||
|
return redbench.AppendCommand(buf,
|
||||||
|
"NEARBY", "key:bench", "LIMIT", "1", "COUNT", "POINT",
|
||||||
|
strconv.FormatFloat(lat, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(lon, 'f', 5, 64),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
switch strings.ToUpper(strings.TrimSpace(test)) {
|
||||||
|
case "NEARBY", "NEARBY-KNN", "NEARBY-KNN-10":
|
||||||
|
redbench.Bench("NEARBY (limit 10)", addr, opts, prepFn,
|
||||||
|
func(buf []byte) []byte {
|
||||||
|
lat, lon := randPoint()
|
||||||
|
return redbench.AppendCommand(buf,
|
||||||
|
"NEARBY", "key:bench", "LIMIT", "10", "COUNT", "POINT",
|
||||||
|
strconv.FormatFloat(lat, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(lon, 'f', 5, 64),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
switch strings.ToUpper(strings.TrimSpace(test)) {
|
||||||
|
case "NEARBY", "NEARBY-KNN", "NEARBY-KNN-100":
|
||||||
|
redbench.Bench("NEARBY (limit 100)", addr, opts, prepFn,
|
||||||
|
func(buf []byte) []byte {
|
||||||
|
lat, lon := randPoint()
|
||||||
|
return redbench.AppendCommand(buf,
|
||||||
|
"NEARBY", "key:bench", "LIMIT", "100", "COUNT", "POINT",
|
||||||
|
strconv.FormatFloat(lat, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(lon, 'f', 5, 64),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
switch strings.ToUpper(strings.TrimSpace(test)) {
|
||||||
|
case "NEARBY", "NEARBY-POINT", "NEARBY-POINT-1000":
|
||||||
|
redbench.Bench("NEARBY (point 1km)", addr, opts, prepFn,
|
||||||
|
func(buf []byte) []byte {
|
||||||
|
lat, lon := randPoint()
|
||||||
|
return redbench.AppendCommand(buf,
|
||||||
|
"NEARBY", "key:bench", "COUNT", "POINT",
|
||||||
|
strconv.FormatFloat(lat, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(lon, 'f', 5, 64),
|
||||||
|
"1000",
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
switch strings.ToUpper(strings.TrimSpace(test)) {
|
||||||
|
case "NEARBY", "NEARBY-POINT", "NEARBY-POINT-10000":
|
||||||
|
redbench.Bench("NEARBY (point 10km)", addr, opts, prepFn,
|
||||||
|
func(buf []byte) []byte {
|
||||||
|
lat, lon := randPoint()
|
||||||
|
return redbench.AppendCommand(buf,
|
||||||
|
"NEARBY", "key:bench", "COUNT", "POINT",
|
||||||
|
strconv.FormatFloat(lat, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(lon, 'f', 5, 64),
|
||||||
|
"10000",
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
switch strings.ToUpper(strings.TrimSpace(test)) {
|
||||||
|
case "NEARBY", "NEARBY-POINT", "NEARBY-POINT-100000":
|
||||||
|
redbench.Bench("NEARBY (point 100km)", addr, opts, prepFn,
|
||||||
|
func(buf []byte) []byte {
|
||||||
|
lat, lon := randPoint()
|
||||||
|
return redbench.AppendCommand(buf,
|
||||||
|
"NEARBY", "key:bench", "COUNT", "POINT",
|
||||||
|
strconv.FormatFloat(lat, 'f', 5, 64),
|
||||||
|
strconv.FormatFloat(lon, 'f', 5, 64),
|
||||||
|
"100000",
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
case "EVAL":
|
case "EVAL":
|
||||||
if !redis {
|
if !redis {
|
||||||
var i int64
|
var i int64
|
||||||
|
@ -371,3 +614,21 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const earthRadius = 6371e3
|
||||||
|
|
||||||
|
func toRadians(deg float64) float64 { return deg * math.Pi / 180 }
|
||||||
|
func toDegrees(rad float64) float64 { return rad * 180 / math.Pi }
|
||||||
|
|
||||||
|
// destinationPoint return the destination from a point based on a distance and bearing.
|
||||||
|
func destinationPoint(lat, lon, meters, bearingDegrees float64) (destLat, destLon float64) {
|
||||||
|
// see http://williams.best.vwh.net/avform.htm#LL
|
||||||
|
δ := meters / earthRadius // angular distance in radians
|
||||||
|
θ := toRadians(bearingDegrees)
|
||||||
|
φ1 := toRadians(lat)
|
||||||
|
λ1 := toRadians(lon)
|
||||||
|
φ2 := math.Asin(math.Sin(φ1)*math.Cos(δ) + math.Cos(φ1)*math.Sin(δ)*math.Cos(θ))
|
||||||
|
λ2 := λ1 + math.Atan2(math.Sin(θ)*math.Sin(δ)*math.Cos(φ1), math.Cos(δ)-math.Sin(φ1)*math.Sin(φ2))
|
||||||
|
λ2 = math.Mod(λ2+3*math.Pi, 2*math.Pi) - math.Pi // normalise to -180..+180°
|
||||||
|
return toDegrees(φ2), toDegrees(λ2)
|
||||||
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func readResp(rd *bufio.Reader, n int) error {
|
func readResp(rd *bufio.Reader, n int, opts *Options) error {
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
line, err := rd.ReadBytes('\n')
|
line, err := rd.ReadBytes('\n')
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -25,6 +25,7 @@ func readResp(rd *bufio.Reader, n int) error {
|
||||||
return errors.New("invalid server response")
|
return errors.New("invalid server response")
|
||||||
case '+', ':':
|
case '+', ':':
|
||||||
case '-':
|
case '-':
|
||||||
|
opts.Stderr.Write(line)
|
||||||
case '$':
|
case '$':
|
||||||
n, err := strconv.ParseInt(string(line[1:len(line)-2]), 10, 64)
|
n, err := strconv.ParseInt(string(line[1:len(line)-2]), 10, 64)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -40,7 +41,7 @@ func readResp(rd *bufio.Reader, n int) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
readResp(rd, int(n))
|
readResp(rd, int(n), opts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -155,7 +156,7 @@ func Bench(
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := readResp(rd, n); err != nil {
|
if err := readResp(rd, n, opts); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
stop := time.Since(start)
|
stop := time.Since(start)
|
||||||
|
|
Loading…
Reference in New Issue