-
-
Save jochumdev/6168792 to your computer and use it in GitHub Desktop.
// Copyright 2013 René Kistl. All rights reserved. | |
// Use of this source code is governed by a BSD-style | |
// license that can be found in the LICENSE file. | |
package srpc | |
import ( | |
"errors" | |
"fmt" | |
"github.com/pcdummy/skynet2/rpc/bsonrpc" | |
"github.com/ugorji/go/codec" | |
"log" | |
"net" | |
"net/rpc" | |
"net/rpc/jsonrpc" | |
"runtime" | |
"sync" | |
"sync/atomic" | |
"testing" | |
) | |
var ( | |
serverBSON, serverGob, serverMsgPack, serverBinc, serverJSON string | |
) | |
type Args struct { | |
A, B int | |
} | |
type Reply struct { | |
C int | |
} | |
type Arith int | |
// Some of Arith's methods have value args, some have pointer args. That's deliberate. | |
func (t *Arith) Add(args Args, reply *Reply) error { | |
reply.C = args.A + args.B | |
return nil | |
} | |
func (t *Arith) Mul(args *Args, reply *Reply) error { | |
reply.C = args.A * args.B | |
return nil | |
} | |
func (t *Arith) Div(args Args, reply *Reply) error { | |
if args.B == 0 { | |
return errors.New("divide by zero") | |
} | |
reply.C = args.A / args.B | |
return nil | |
} | |
func (t *Arith) String(args *Args, reply *string) error { | |
*reply = fmt.Sprintf("%d+%d=%d", args.A, args.B, args.A+args.B) | |
return nil | |
} | |
func (t *Arith) Scan(args string, reply *Reply) (err error) { | |
_, err = fmt.Sscan(args, &reply.C) | |
return | |
} | |
func (t *Arith) Error(args *Args, reply *Reply) error { | |
panic("ERROR") | |
} | |
func listenTCP() (net.Listener, string) { | |
l, e := net.Listen("tcp", "127.0.0.1:0") // any available address | |
if e != nil { | |
log.Fatalf("net.Listen tcp :0: %v", e) | |
} | |
return l, l.Addr().String() | |
} | |
func TestStartServers(t *testing.T) { | |
startBSONServer() | |
startMsgPackServer() | |
startGobServer() | |
startBincServer() | |
startJSONServer() | |
} | |
func startBSONServer() { | |
rpc.Register(new(Arith)) | |
var l net.Listener | |
l, serverBSON = listenTCP() | |
// log.Println("Test BSON RPC server listening on", serverAddr) | |
go func() { | |
for { | |
conn, err := l.Accept() | |
if err != nil { | |
log.Fatal("accept error:", err) | |
} | |
codec := bsonrpc.NewServerCodec(conn) | |
go rpc.ServeCodec(codec) | |
} | |
}() | |
} | |
func startMsgPackServer() { | |
var l net.Listener | |
l, serverMsgPack = listenTCP() | |
// log.Println("Test MsgPack RPC server listening on", serverAddr2) | |
go func() { | |
for { | |
conn, err := l.Accept() | |
if err != nil { | |
log.Fatal("accept error:", err) | |
} | |
codec := codec.GoRpc.ServerCodec(conn, &codec.MsgpackHandle{}) | |
go rpc.ServeCodec(codec) | |
} | |
}() | |
} | |
func startGobServer() { | |
var l net.Listener | |
l, serverGob = listenTCP() | |
// log.Println("Test MsgPack RPC server listening on", serverAddr2) | |
go func() { | |
for { | |
conn, err := l.Accept() | |
if err != nil { | |
log.Fatal("accept error:", err) | |
} | |
go rpc.ServeConn(conn) | |
} | |
}() | |
} | |
func startBincServer() { | |
var l net.Listener | |
l, serverBinc = listenTCP() | |
// log.Println("Test MsgPack RPC server listening on", serverAddr2) | |
go func() { | |
for { | |
conn, err := l.Accept() | |
if err != nil { | |
log.Fatal("accept error:", err) | |
} | |
codec := codec.GoRpc.ServerCodec(conn, &codec.BincHandle{}) | |
go rpc.ServeCodec(codec) | |
} | |
}() | |
} | |
func startJSONServer() { | |
var l net.Listener | |
l, serverJSON = listenTCP() | |
// log.Println("Test MsgPack RPC server listening on", serverAddr2) | |
go func() { | |
for { | |
conn, err := l.Accept() | |
if err != nil { | |
log.Fatal("accept error:", err) | |
} | |
codec := jsonrpc.NewServerCodec(conn) | |
go rpc.ServeCodec(codec) | |
} | |
}() | |
} | |
func benchmarkClient(client *rpc.Client, b *testing.B) { | |
// Synchronous calls | |
args := &Args{7, 8} | |
procs := runtime.GOMAXPROCS(-1) | |
N := int32(b.N) | |
var wg sync.WaitGroup | |
wg.Add(procs) | |
b.StartTimer() | |
for p := 0; p < procs; p++ { | |
go func() { | |
reply := new(Reply) | |
for atomic.AddInt32(&N, -1) >= 0 { | |
err := client.Call("Arith.Add", args, reply) | |
if err != nil { | |
b.Fatalf("rpc error: Add: expected no error but got string %q", err.Error()) | |
} | |
if reply.C != args.A+args.B { | |
b.Fatalf("rpc error: Add: expected %d got %d", reply.C, args.A+args.B) | |
} | |
} | |
wg.Done() | |
}() | |
} | |
wg.Wait() | |
} | |
func BenchmarkEndToEndBSON(b *testing.B) { | |
b.StopTimer() | |
conn, err := net.Dial("tcp", serverBSON) | |
if err != nil { | |
log.Fatal("error dialing:", err) | |
} | |
client := bsonrpc.NewClient(conn) | |
defer client.Close() | |
benchmarkClient(client, b) | |
} | |
func BenchmarkEndToEndMsgPack(b *testing.B) { | |
b.StopTimer() | |
conn, err := net.Dial("tcp", serverMsgPack) | |
if err != nil { | |
log.Fatal("error dialing:", err) | |
} | |
rpcCodec := codec.GoRpc.ClientCodec(conn, &codec.MsgpackHandle{}) | |
client := rpc.NewClientWithCodec(rpcCodec) | |
defer client.Close() | |
benchmarkClient(client, b) | |
} | |
func BenchmarkEndToEndGob(b *testing.B) { | |
b.StopTimer() | |
conn, err := net.Dial("tcp", serverGob) | |
if err != nil { | |
log.Fatal("error dialing:", err) | |
} | |
client := rpc.NewClient(conn) | |
defer client.Close() | |
benchmarkClient(client, b) | |
} | |
func BenchmarkEndToEndBinc(b *testing.B) { | |
b.StopTimer() | |
conn, err := net.Dial("tcp", serverBinc) | |
if err != nil { | |
log.Fatal("error dialing:", err) | |
} | |
rpcCodec := codec.GoRpc.ClientCodec(conn, &codec.BincHandle{}) | |
client := rpc.NewClientWithCodec(rpcCodec) | |
defer client.Close() | |
benchmarkClient(client, b) | |
} | |
func BenchmarkEndToEndJSON(b *testing.B) { | |
b.StopTimer() | |
conn, err := net.Dial("tcp", serverJSON) | |
if err != nil { | |
log.Fatal("error dialing:", err) | |
} | |
rpcCodec := jsonrpc.NewClientCodec(conn) | |
client := rpc.NewClientWithCodec(rpcCodec) | |
defer client.Close() | |
benchmarkClient(client, b) | |
} |
Please sync and try again. This should now be fixed. RPC had to perform input reader buffering, which is what gob and json do internally.
Yes, ugorji adding a buffer fixes it.
pcdummy@ThinkPad-T410 ~/Projekte/golang/src/rpc_test $ go test -test.bench=".*" bson_bench_test.go
PASS
BenchmarkEndToEndBSON 50000 66116 ns/op
BenchmarkEndToEndMsgPack 50000 45132 ns/op
BenchmarkEndToEndGob 50000 39081 ns/op
BenchmarkEndToEndBinc 50000 45951 ns/op
BenchmarkEndToEndJSON 50000 59995 ns/op
ok command-line-arguments 15.419s
New Test results, added bufio to BSON RPC.
pcdummy@ThinkPad-T410 ~/Projekte/golang/src/rpc_test $ go test -test.bench=".*" bson_bench_test.go
PASS
BenchmarkEndToEndBSON 50000 46393 ns/op
BenchmarkEndToEndMsgPack 50000 43229 ns/op
BenchmarkEndToEndGob 50000 39441 ns/op
BenchmarkEndToEndBinc 50000 45499 ns/op
BenchmarkEndToEndJSON 50000 61448 ns/op
ok command-line-arguments 14.225s
New results with a faster MsgPack, thx to ugorji
BenchmarkEndToEndBSON 50000 45805 ns/op
BenchmarkEndToEndMsgPack 50000 41245 ns/op
BenchmarkEndToEndGob 50000 39104 ns/op
BenchmarkEndToEndBinc 50000 42863 ns/op
BenchmarkEndToEndJSON 50000 61911 ns/op
pcdummy@ThinkPad-T410 ~/Projekte/golang/src/rpc_test $ go test -test.bench=".*" bson_bench_test.go
PASS
BenchmarkEndToEndBSON 20000 79669 ns/op
BenchmarkEndToEndMsgPack 10000 105534 ns/op
BenchmarkEndToEndGob 50000 45514 ns/op
BenchmarkEndToEndBinc 10000 103352 ns/op
BenchmarkEndToEndJSON 50000 71928 ns/op
ok command-line-arguments 11.593s
My Results on a Thinkpad T410