From 2dbf046a3a846e408d902552c743c831314eb937 Mon Sep 17 00:00:00 2001 From: smallnest Date: Sun, 9 Jul 2023 15:24:09 +0800 Subject: [PATCH] add io_uring support --- client/connection.go | 11 +++--- client/connection_iouring.go | 10 +++++ client/connection_iouring_test.go | 46 +++++++++++++++++++++ go.mod | 2 + go.sum | 5 +++ log/logger.go | 4 ++ server/listener_linux.go | 66 +++++++++++++++++++++++++++++++ 7 files changed, 139 insertions(+), 5 deletions(-) create mode 100644 client/connection_iouring.go create mode 100644 client/connection_iouring_test.go create mode 100644 server/listener_linux.go diff --git a/client/connection.go b/client/connection.go index 7b8c3e8..806ce01 100644 --- a/client/connection.go +++ b/client/connection.go @@ -18,11 +18,12 @@ import ( type ConnFactoryFn func(c *Client, network, address string) (net.Conn, error) var ConnFactories = map[string]ConnFactoryFn{ - "http": newDirectHTTPConn, - "kcp": newDirectKCPConn, - "quic": newDirectQuicConn, - "unix": newDirectConn, - "memu": newMemuConn, + "http": newDirectHTTPConn, + "kcp": newDirectKCPConn, + "quic": newDirectQuicConn, + "unix": newDirectConn, + "memu": newMemuConn, + "iouring": newIOUringConn, } // Connect connects the server via specified network. diff --git a/client/connection_iouring.go b/client/connection_iouring.go new file mode 100644 index 0000000..58902c9 --- /dev/null +++ b/client/connection_iouring.go @@ -0,0 +1,10 @@ +package client + +import ( + "net" +) + +// experimental +func newIOUringConn(c *Client, network, address string) (net.Conn, error) { + return newDirectConn(c, "tcp", address) +} diff --git a/client/connection_iouring_test.go b/client/connection_iouring_test.go new file mode 100644 index 0000000..448bf5b --- /dev/null +++ b/client/connection_iouring_test.go @@ -0,0 +1,46 @@ +//go:build linux +// +build linux + +package client + +import ( + "context" + "testing" + "time" + + "github.com/smallnest/rpcx/server" +) + +func TestXClient_IOUring(t *testing.T) { + s := server.NewServer() + s.RegisterName("Arith", new(Arith), "") + go s.Serve("iouring", "127.0.0.1:8972") + defer s.Close() + time.Sleep(500 * time.Millisecond) + + addr := s.Address().String() + + d, err := NewPeer2PeerDiscovery("iouring@"+addr, "desc=a test service") + if err != nil { + t.Fatalf("failed to NewPeer2PeerDiscovery: %v", err) + } + + xclient := NewXClient("Arith", Failtry, RandomSelect, d, DefaultOption) + + defer xclient.Close() + + args := &Args{ + A: 10, + B: 20, + } + + reply := &Reply{} + err = xclient.Call(context.Background(), "Mul", args, reply) + if err != nil { + t.Fatalf("failed to call: %v", err) + } + + if reply.C != 200 { + t.Fatalf("expect 200 but got %d", reply.C) + } +} diff --git a/go.mod b/go.mod index 099fd0d..6049753 100644 --- a/go.mod +++ b/go.mod @@ -50,6 +50,7 @@ require ( github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a // indirect github.com/fsnotify/fsnotify v1.6.0 // indirect github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect + github.com/godzie44/go-uring v0.0.0-20220926161041-69611e8b13d5 // indirect github.com/golang/mock v1.6.0 // indirect github.com/google/pprof v0.0.0-20230228050547-1710fef4ab10 // indirect github.com/google/uuid v1.3.0 // indirect @@ -57,6 +58,7 @@ require ( github.com/klauspost/cpuid/v2 v2.2.4 // indirect github.com/klauspost/reedsolomon v1.11.7 // indirect github.com/kr/text v0.1.0 // indirect + github.com/libp2p/go-sockaddr v0.1.1 // indirect github.com/lucas-clemente/quic-go v0.31.1 // indirect github.com/marten-seemann/qtls-go1-18 v0.1.4 // indirect github.com/marten-seemann/qtls-go1-19 v0.1.2 // indirect diff --git a/go.sum b/go.sum index 0b25987..ce20e6c 100644 --- a/go.sum +++ b/go.sum @@ -93,6 +93,8 @@ github.com/go-redis/redis_rate/v9 v9.1.2/go.mod h1:oam2de2apSgRG8aJzwJddXbNu91Iy github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 h1:p104kn46Q8WdvHunIJ9dAyjPVtrBPhSr3KT2yUst43I= github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= +github.com/godzie44/go-uring v0.0.0-20220926161041-69611e8b13d5 h1:5zELAgnSz0gqmr4Q5DWCoOzNHoeBAxVUXB7LS1eG+sw= +github.com/godzie44/go-uring v0.0.0-20220926161041-69611e8b13d5/go.mod h1:ermjEDUoT/fS+3Ona5Vd6t6mZkw1eHp99ILO5jGRBkM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -201,6 +203,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/libp2p/go-sockaddr v0.1.1 h1:yD80l2ZOdGksnOyHrhxDdTDFrf7Oy+v3FMVArIRgZxQ= +github.com/libp2p/go-sockaddr v0.1.1/go.mod h1:syPvOmNs24S3dFVGJA1/mrqdeijPxLV2Le3BRLKd68k= github.com/lucas-clemente/quic-go v0.28.0/go.mod h1:oGz5DKK41cJt5+773+BSO9BXDsREY4HLf7+0odGAPO0= github.com/lucas-clemente/quic-go v0.31.1 h1:O8Od7hfioqq0PMYHDyBkxU2aA7iZ2W9pjbrWuja2YR4= github.com/lucas-clemente/quic-go v0.31.1/go.mod h1:0wFbizLgYzqHqtlyxyCaJKlE7bYgE6JQ+54TLd/Dq2g= @@ -486,6 +490,7 @@ golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190228124157-a34e9553db1e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190316082340-a2f829d7f35f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/log/logger.go b/log/logger.go index f197a5f..d6e001f 100644 --- a/log/logger.go +++ b/log/logger.go @@ -35,6 +35,10 @@ func SetLogger(logger Logger) { l = logger } +func GetLogger() Logger { + return l +} + func SetDummyLogger() { l = &dummyLogger{} } diff --git a/server/listener_linux.go b/server/listener_linux.go new file mode 100644 index 0000000..f409d6f --- /dev/null +++ b/server/listener_linux.go @@ -0,0 +1,66 @@ +//go:build linux +// +build linux + +package server + +import ( + "net" + "runtime" + "time" + + uringnet "github.com/godzie44/go-uring/net" + "github.com/godzie44/go-uring/reactor" + "github.com/godzie44/go-uring/uring" + "github.com/smallnest/rpcx/log" +) + +func init() { + makeListeners["iouring"] = iouringMakeListener +} + +// iouringMakeListener creates a new listener using io_uring. +// You can use RegisterMakeListener to register a customized iouring Listener creator. +// experimental +func iouringMakeListener(s *Server, address string) (ln net.Listener, err error) { + n := runtime.GOMAXPROCS(-1) + + var opts []uring.SetupOption + opts = append(opts, uring.WithSQPoll(time.Millisecond*100)) + + rings, closeRings, err := uring.CreateMany(n, uring.MaxEntries>>3, n, opts...) + if err != nil { + return nil, err + } + + netReactor, err := reactor.NewNet(rings, reactor.WithLogger(&uringLogger{log.GetLogger()})) + if err != nil { + return nil, err + } + + ln, err = uringnet.NewListener(net.ListenConfig{}, address, netReactor) + if err != nil { + return nil, err + } + + return &uringnetListener{Listener: ln, closeRings: closeRings}, nil +} + +type uringnetListener struct { + net.Listener + closeRings uring.Defer +} + +func (cl *uringnetListener) Close() error { + cl.Listener.Close() + cl.closeRings() + + return nil +} + +type uringLogger struct { + log.Logger +} + +func (l *uringLogger) Log(keyvals ...interface{}) { + l.Logger.Info(keyvals...) +}