Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

govpp: add rpc-service test to example perf-bench #253

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 54 additions & 4 deletions examples/perf-bench/perf-bench.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,13 +44,14 @@
var sync bool
var cnt int
var sock, prof string
var testV2, debugOn bool
var testRPC, testV2, debugOn bool
flag.BoolVar(&sync, "sync", false, "run synchronous perf test")
flag.StringVar(&sock, "api-socket", socketclient.DefaultSocketName, "Path to VPP API socket")
flag.String("stats-socket", statsclient.DefaultSocketName, "Path to VPP stats socket")
flag.IntVar(&cnt, "count", 0, "count of requests to be sent to VPP")
flag.StringVar(&prof, "prof", "", "enable profiling mode [mem, cpu]")
flag.BoolVar(&testV2, "v2", false, "Use test function v2")
flag.BoolVar(&testRPC, "rpc", false, "Use test function rpc")
flag.BoolVar(&debugOn, "debug", false, "Enable debug mode")
flag.Parse()

Expand Down Expand Up @@ -85,7 +86,7 @@
defer conn.Disconnect()

// create an API channel
ch, err := conn.NewAPIChannelBuffered(cnt, cnt)
ch, err := conn.NewAPIChannel()
if err != nil {
log.Fatalln("Error:", err)
}
Expand All @@ -101,7 +102,9 @@
// run the test & measure the time
start := time.Now()

if testV2 {
if testRPC {
rpcTest(conn, cnt)
} else if testV2 {
if sync {
syncTest2(conn, cnt)
} else {
Expand All @@ -122,6 +125,46 @@
time.Sleep(time.Second)
}

func rpcTest(conn api.Connection, cnt int) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function syncTest2 is optimized way to use stream. It does basically the same thing ControlPing RPC call does, but reused the same stream which makes it more performant.

Copy link
Member

@ondrej-fabry ondrej-fabry Jan 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I recommend reading Sending API messages from our GoVPP User Guide and RPC services and Stream API for more in-depth documentation of how it works.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are using RPC services in our private application and can't change the whole code base to stream APIs. I have benchmarked them and got different results from stream APIs and RPC services API.
Thanks for the reading list. I have already read them.
The point here is to improve the overall performance of stream APIs and RPC service APIs.

fmt.Printf("Running RPC perf test with %d requests...\n", cnt)

for i := 0; i < cnt; i++ {
c := memclnt.NewServiceClient(conn)

_, err := c.ControlPing(context.Background(), &memclnt.ControlPing{})
if err != nil {
log.Fatalln("Error in reply:", err)
}
}
}

func rpcTestAsync(conn api.Connection, cnt int) {
fmt.Printf("Running async RPC perf test with %d requests...\n", cnt)

ctxChan := make(chan memclnt.RPCService, cnt)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is wrong. The memclnt.RPCService is a an interface of RPC service client that is needed to be created only once.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ignore rpcTestAsync function. It should have been deleted. you can check this function has never been called.

var index int

c := memclnt.NewServiceClient(conn)
go func() {

for i := 0; i < cnt; i++ {
ctxChan <- c.ControlPing(context.Background(), &memclnt.ControlPing{})

Check failure on line 151 in examples/perf-bench/perf-bench.go

View workflow job for this annotation

GitHub Actions / VPP Integration master

multiple-value c.ControlPing(context.Background(), &memclnt.ControlPing{}) (value of type (*memclnt.ControlPingReply, error)) in single-value context

Check failure on line 151 in examples/perf-bench/perf-bench.go

View workflow job for this annotation

GitHub Actions / VPP Integration master

multiple-value c.ControlPing(context.Background(), &memclnt.ControlPing{}) (value of type (*memclnt.ControlPingReply, error)) in single-value context

Check failure on line 151 in examples/perf-bench/perf-bench.go

View workflow job for this annotation

GitHub Actions / VPP Integration 2406

multiple-value c.ControlPing(context.Background(), &memclnt.ControlPing{}) (value of type (*memclnt.ControlPingReply, error)) in single-value context

Check failure on line 151 in examples/perf-bench/perf-bench.go

View workflow job for this annotation

GitHub Actions / VPP Integration 2406

multiple-value c.ControlPing(context.Background(), &memclnt.ControlPing{}) (value of type (*memclnt.ControlPingReply, error)) in single-value context

Check failure on line 151 in examples/perf-bench/perf-bench.go

View workflow job for this annotation

GitHub Actions / Build and test (1.22, ubuntu-latest)

multiple-value c.ControlPing(context.Background(), &memclnt.ControlPing{}) (value of type (*memclnt.ControlPingReply, error)) in single-value context

Check failure on line 151 in examples/perf-bench/perf-bench.go

View workflow job for this annotation

GitHub Actions / VPP Integration 2402

multiple-value c.ControlPing(context.Background(), &memclnt.ControlPing{}) (value of type (*memclnt.ControlPingReply, error)) in single-value context

Check failure on line 151 in examples/perf-bench/perf-bench.go

View workflow job for this annotation

GitHub Actions / VPP Integration 2402

multiple-value c.ControlPing(context.Background(), &memclnt.ControlPing{}) (value of type (*memclnt.ControlPingReply, error)) in single-value context

Check failure on line 151 in examples/perf-bench/perf-bench.go

View workflow job for this annotation

GitHub Actions / VPP Integration 2310

multiple-value c.ControlPing(context.Background(), &memclnt.ControlPing{}) (value of type (*memclnt.ControlPingReply, error)) in single-value context

Check failure on line 151 in examples/perf-bench/perf-bench.go

View workflow job for this annotation

GitHub Actions / VPP Integration 2310

multiple-value c.ControlPing(context.Background(), &memclnt.ControlPing{}) (value of type (*memclnt.ControlPingReply, error)) in single-value context

Check failure on line 151 in examples/perf-bench/perf-bench.go

View workflow job for this annotation

GitHub Actions / GolangCI (1.22)

multiple-value c.ControlPing(context.Background(), &memclnt.ControlPing{}) (value of type (*memclnt.ControlPingReply, error)) in single-value context
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This won't even compile. The ControlPing returns two values.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please Ignore it....

}
close(ctxChan)
fmt.Printf("Sending asynchronous requests finished\n")
}()

index = 0
for ctx := range ctxChan {
err := ctx.error

Check failure on line 159 in examples/perf-bench/perf-bench.go

View workflow job for this annotation

GitHub Actions / VPP Integration master

ctx.error undefined (type memclnt.RPCService has no field or method error)

Check failure on line 159 in examples/perf-bench/perf-bench.go

View workflow job for this annotation

GitHub Actions / VPP Integration master

ctx.error undefined (type memclnt.RPCService has no field or method error)

Check failure on line 159 in examples/perf-bench/perf-bench.go

View workflow job for this annotation

GitHub Actions / VPP Integration 2406

ctx.error undefined (type memclnt.RPCService has no field or method error)

Check failure on line 159 in examples/perf-bench/perf-bench.go

View workflow job for this annotation

GitHub Actions / VPP Integration 2406

ctx.error undefined (type memclnt.RPCService has no field or method error)

Check failure on line 159 in examples/perf-bench/perf-bench.go

View workflow job for this annotation

GitHub Actions / Build and test (1.22, ubuntu-latest)

ctx.error undefined (type memclnt.RPCService has no field or method error)

Check failure on line 159 in examples/perf-bench/perf-bench.go

View workflow job for this annotation

GitHub Actions / VPP Integration 2402

ctx.error undefined (type memclnt.RPCService has no field or method error)

Check failure on line 159 in examples/perf-bench/perf-bench.go

View workflow job for this annotation

GitHub Actions / VPP Integration 2402

ctx.error undefined (type memclnt.RPCService has no field or method error)

Check failure on line 159 in examples/perf-bench/perf-bench.go

View workflow job for this annotation

GitHub Actions / VPP Integration 2310

ctx.error undefined (type memclnt.RPCService has no field or method error)

Check failure on line 159 in examples/perf-bench/perf-bench.go

View workflow job for this annotation

GitHub Actions / VPP Integration 2310

ctx.error undefined (type memclnt.RPCService has no field or method error)

Check failure on line 159 in examples/perf-bench/perf-bench.go

View workflow job for this annotation

GitHub Actions / GolangCI (1.22)

ctx.error undefined (type memclnt.RPCService has no field or method error) (typecheck)
if err != nil {
log.Fatalln("Error in reply:", err)
}
index++
}
fmt.Printf("Sending %d Receiving %d\n", cnt, index)
}

func syncTest(ch api.Channel, cnt int) {
fmt.Printf("Running synchronous perf test with %d requests...\n", cnt)

Expand Down Expand Up @@ -160,7 +203,7 @@
fmt.Printf("Running asynchronous perf test with %d requests...\n", cnt)

ctxChan := make(chan api.RequestCtx, cnt)

var index int
go func() {
for i := 0; i < cnt; i++ {
ctxChan <- ch.SendRequest(&memclnt.ControlPing{})
Expand All @@ -169,18 +212,22 @@
fmt.Printf("Sending asynchronous requests finished\n")
}()

index = 0
for ctx := range ctxChan {
reply := &memclnt.ControlPingReply{}
if err := ctx.ReceiveReply(reply); err != nil {
log.Fatalln("Error in reply:", err)
}
index++
}
fmt.Printf("Sending %d Receiving %d\n", cnt, index)
}

func asyncTest2(conn api.Connection, cnt int) {
fmt.Printf("Running asynchronous perf test with %d requests...\n", cnt)

ctxChan := make(chan api.Stream, cnt)
var index int

go func() {
for i := 0; i < cnt; i++ {
Expand All @@ -197,6 +244,7 @@
fmt.Printf("Sending asynchronous requests finished\n")
}()

index = 0
for ctx := range ctxChan {
if msg, err := ctx.RecvMsg(); err != nil {
log.Fatalln("Error RecvMsg:", err)
Expand All @@ -208,5 +256,7 @@
if err := ctx.Close(); err != nil {
log.Fatalf("Stream.Close error: %v", err)
}
index++
}
fmt.Printf("Sending %d Receiving %d\n", cnt, index)
}
Loading