good morning!!!!

Skip to content
Snippets Groups Projects
Commit de3f4000 authored by a's avatar a
Browse files

small performance increase

parent 005289ac
Branches
Tags
No related merge requests found
package jrpc
import (
"testing"
"golang.org/x/sync/errgroup"
)
func BenchmarkClientHTTPEcho(b *testing.B) {
server := newTestServer()
defer server.Stop()
client, hs := httpTestClient(server, "http", nil)
defer hs.Close()
defer client.Close()
// Launch concurrent requests.
wantBack := map[string]any{
"one": map[string]any{"two": "three"},
"e": map[string]any{"two": "three"},
"oe": map[string]any{"two": "three"},
"on": map[string]any{"two": "three"},
}
b.StartTimer()
for n := 0; n < b.N; n++ {
eg := &errgroup.Group{}
for i := 0; i < 1000; i++ {
eg.Go(func() error {
return client.Call(nil, "test_echoAny", []any{1, 2, 3, 4, 56, 6, wantBack, wantBack, wantBack})
})
}
eg.Wait()
}
}
func BenchmarkClientHTTPEchoEmpty(b *testing.B) {
server := newTestServer()
defer server.Stop()
client, hs := httpTestClient(server, "http", nil)
defer hs.Close()
defer client.Close()
// Launch concurrent requests.
b.StartTimer()
for n := 0; n < b.N; n++ {
eg := &errgroup.Group{}
for i := 0; i < 1000; i++ {
eg.Go(func() error {
return client.Call(nil, "test_echoAny", 0)
})
}
eg.Wait()
}
}
func BenchmarkClientWebsocketEcho(b *testing.B) {
server := newTestServer()
defer server.Stop()
client, hs := httpTestClient(server, "ws", nil)
defer hs.Close()
defer client.Close()
// Launch concurrent requests.
wantBack := map[string]any{
"one": map[string]any{"two": "three"},
"e": map[string]any{"two": "three"},
"oe": map[string]any{"two": "three"},
"on": map[string]any{"two": "three"},
}
b.StartTimer()
for n := 0; n < b.N; n++ {
eg := &errgroup.Group{}
for i := 0; i < 1000; i++ {
eg.Go(func() error {
return client.Call(nil, "test_echoAny", []any{1, 2, 3, 4, 56, 6, wantBack, wantBack, wantBack})
})
}
eg.Wait()
}
}
func BenchmarkClientWebsocketEchoEmpty(b *testing.B) {
server := newTestServer()
defer server.Stop()
client, hs := httpTestClient(server, "ws", nil)
defer hs.Close()
defer client.Close()
// Launch concurrent requests.
b.StartTimer()
for n := 0; n < b.N; n++ {
eg := &errgroup.Group{}
for i := 0; i < 1000; i++ {
eg.Go(func() error {
return client.Call(nil, "test_echoAny", 0)
})
}
eg.Wait()
}
}
...@@ -18,7 +18,6 @@ package jrpc ...@@ -18,7 +18,6 @@ package jrpc
import ( import (
"context" "context"
"encoding/json"
"fmt" "fmt"
"math/rand" "math/rand"
"net" "net"
...@@ -335,86 +334,6 @@ func TestClientHTTP(t *testing.T) { ...@@ -335,86 +334,6 @@ func TestClientHTTP(t *testing.T) {
} }
} }
func BenchmarkClientHTTPEcho(b *testing.B) {
server := newTestServer()
defer server.Stop()
client, hs := httpTestClient(server, "http", nil)
defer hs.Close()
defer client.Close()
// Launch concurrent requests.
b.StartTimer()
wantBack := map[string]any{
"one": map[string]any{"two": "three"},
"e": map[string]any{"two": "three"},
"oe": map[string]any{"two": "three"},
"on": map[string]any{"two": "three"},
}
var res json.RawMessage
for n := 0; n < b.N; n++ {
for i := 0; i < 100; i++ {
err := client.Call(&res, "test_echoAny", []any{1, 2, 3, 4, 56, 6, wantBack, wantBack, wantBack})
if err != nil {
panic(err)
}
}
}
}
func BenchmarkClientHTTPEchoEmpty(b *testing.B) {
server := newTestServer()
defer server.Stop()
client, hs := httpTestClient(server, "http", nil)
defer hs.Close()
defer client.Close()
// Launch concurrent requests.
b.StartTimer()
var res json.RawMessage
for n := 0; n < b.N; n++ {
for i := 0; i < 100; i++ {
client.Call(&res, "test_echoAny", 0)
}
}
}
func BenchmarkClientWebsocketEcho(b *testing.B) {
server := newTestServer()
defer server.Stop()
client, hs := httpTestClient(server, "ws", nil)
defer hs.Close()
defer client.Close()
// Launch concurrent requests.
b.StartTimer()
wantBack := map[string]any{
"one": map[string]any{"two": "three"},
"e": map[string]any{"two": "three"},
"oe": map[string]any{"two": "three"},
"on": map[string]any{"two": "three"},
}
var res json.RawMessage
for n := 0; n < b.N; n++ {
for i := 0; i < 100; i++ {
client.Call(&res, "test_echoAny", []any{1, 2, 3, 4, 56, 6, wantBack, wantBack, wantBack})
}
}
}
func BenchmarkClientWebsocketEchoEmpty(b *testing.B) {
server := newTestServer()
defer server.Stop()
client, hs := httpTestClient(server, "ws", nil)
defer hs.Close()
defer client.Close()
// Launch concurrent requests.
b.StartTimer()
var res json.RawMessage
for n := 0; n < b.N; n++ {
for i := 0; i < 100; i++ {
client.Call(&res, "test_echoAny", 0)
}
}
}
func TestClientReconnect(t *testing.T) { func TestClientReconnect(t *testing.T) {
startServer := func(addr string) (*Server, net.Listener) { startServer := func(addr string) (*Server, net.Listener) {
srv := newTestServer() srv := newTestServer()
......
cpu.out 0 → 100644
File added
cpu2.out 0 → 100644
File added
cpu4.out 0 → 100644
File added
cpu5.out 0 → 100644
File added
cpu6.out 0 → 100644
File added
cpu7.out 0 → 100644
File added
...@@ -14,6 +14,7 @@ require ( ...@@ -14,6 +14,7 @@ require (
github.com/imdario/mergo v0.3.13 github.com/imdario/mergo v0.3.13
github.com/json-iterator/go v1.1.12 github.com/json-iterator/go v1.1.12
github.com/test-go/testify v1.1.4 github.com/test-go/testify v1.1.4
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce
nhooyr.io/websocket v1.8.7 nhooyr.io/websocket v1.8.7
sigs.k8s.io/yaml v1.3.0 sigs.k8s.io/yaml v1.3.0
......
jrpc.test 0 → 100755
File added
...@@ -24,11 +24,13 @@ import ( ...@@ -24,11 +24,13 @@ import (
"fmt" "fmt"
"io" "io"
"reflect" "reflect"
"strconv"
"strings" "strings"
"sync" "sync"
"time" "time"
"gfx.cafe/open/jrpc/wsjson" "gfx.cafe/open/jrpc/wsjson"
jsoniter "github.com/json-iterator/go"
) )
var jzon = wsjson.JZON var jzon = wsjson.JZON
...@@ -143,7 +145,7 @@ type JsonError = jsonError ...@@ -143,7 +145,7 @@ type JsonError = jsonError
func (err *jsonError) Error() string { func (err *jsonError) Error() string {
if err.Message == "" { if err.Message == "" {
return fmt.Sprintf("json-rpc error %d", err.Code) return "json-rpc error " + strconv.Itoa(err.Code)
} }
return err.Message return err.Message
} }
...@@ -298,18 +300,13 @@ func isBatch(raw json.RawMessage) bool { ...@@ -298,18 +300,13 @@ func isBatch(raw json.RawMessage) bool {
// given types. It returns the parsed values or an error when the args could not be // given types. It returns the parsed values or an error when the args could not be
// parsed. Missing optional arguments are returned as reflect.Zero values. // parsed. Missing optional arguments are returned as reflect.Zero values.
func parsePositionalArguments(rawArgs json.RawMessage, types []reflect.Type) ([]reflect.Value, error) { func parsePositionalArguments(rawArgs json.RawMessage, types []reflect.Type) ([]reflect.Value, error) {
dec := json.NewDecoder(bytes.NewReader(rawArgs))
var args []reflect.Value var args []reflect.Value
tok, err := dec.Token()
switch { switch {
case err == io.EOF || tok == nil && err == nil: case len(rawArgs) == 0:
// "params" is optional and may be empty. Also allow "params":null even though it's case rawArgs[0] == '[':
// not in the spec because our own client used to send it.
case err != nil:
return nil, err
case tok == json.Delim('['):
// Read argument array. // Read argument array.
if args, err = parseArgumentArray(dec, types); err != nil { var err error
if args, err = parseArgumentArray(rawArgs, types); err != nil {
return nil, err return nil, err
} }
default: default:
...@@ -325,14 +322,17 @@ func parsePositionalArguments(rawArgs json.RawMessage, types []reflect.Type) ([] ...@@ -325,14 +322,17 @@ func parsePositionalArguments(rawArgs json.RawMessage, types []reflect.Type) ([]
return args, nil return args, nil
} }
func parseArgumentArray(dec *json.Decoder, types []reflect.Type) ([]reflect.Value, error) { func parseArgumentArray(p json.RawMessage, types []reflect.Type) ([]reflect.Value, error) {
dec := jsoniter.NewIterator(jzon)
dec.ResetBytes(p)
args := make([]reflect.Value, 0, len(types)) args := make([]reflect.Value, 0, len(types))
for i := 0; dec.More(); i++ { for i := 0; dec.ReadArray(); i++ {
if i >= len(types) { if i >= len(types) {
return args, fmt.Errorf("too many arguments, want at most %d", len(types)) return args, fmt.Errorf("too many arguments, want at most %d", len(types))
} }
argval := reflect.New(types[i]) argval := reflect.New(types[i])
if err := dec.Decode(argval.Interface()); err != nil { dec.ReadVal(argval.Interface())
if err := dec.Error; err != nil {
return args, fmt.Errorf("invalid argument %d: %v", i, err) return args, fmt.Errorf("invalid argument %d: %v", i, err)
} }
if argval.IsNil() && types[i].Kind() != reflect.Ptr { if argval.IsNil() && types[i].Kind() != reflect.Ptr {
...@@ -340,9 +340,7 @@ func parseArgumentArray(dec *json.Decoder, types []reflect.Type) ([]reflect.Valu ...@@ -340,9 +340,7 @@ func parseArgumentArray(dec *json.Decoder, types []reflect.Type) ([]reflect.Valu
} }
args = append(args, argval.Elem()) args = append(args, argval.Elem())
} }
// Read end of args array. return args, nil
_, err := dec.Token()
return args, err
} }
// parseSubscriptionName extracts the subscription name from an encoded argument array. // parseSubscriptionName extracts the subscription name from an encoded argument array.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment