Skip to content

Commit 64de25d

Browse files
Add view benchmarks
Signed-off-by: Marcus Brandenburger <bur@zurich.ibm.com>
1 parent 1b3fd78 commit 64de25d

17 files changed

+1158
-0
lines changed

integration/benchmark/README.md

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# FSC Benchmarks
2+
3+
This package contains useful micro benchmarks for the FSC runtime.
4+
5+
## Benchmarking
6+
7+
### Background material
8+
9+
There are many useful articles about go benchmarks available online. Here just a few good starting points:
10+
- https://gobyexample.com/testing-and-benchmarking
11+
- https://blog.cloudflare.com/go-dont-collect-my-garbage/
12+
- https://mcclain.sh/posts/go-benchmarking/
13+
14+
### Run them all
15+
16+
We can run all benchmarks in this package as follows:
17+
18+
```bash
19+
go test -bench=. -benchmem -count=10 -timeout=20m -cpu=1,2,4,8,16 -run=^$ ./... > plots/benchmark_gc_100.txt
20+
```
21+
22+
#### Garbage Collection
23+
24+
Some code, in particular, allocation-intensive operations may benefit from tweaking the garbage collector settings.
25+
There is a highly recommended read about go's GC https://go.dev/doc/gc-guide.
26+
27+
```bash
28+
# Default
29+
GOGC=100
30+
31+
# No garbage collection, use this setting only for testing! :)
32+
GOGC=off
33+
```
34+
35+
If we want to study the impact of different GC settings we can run the following, for example:
36+
37+
```bash
38+
GOGC=100 go test -bench=. -benchmem -count=10 -timeout=20m -cpu=1,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,48,64 -run=^$ ./... > plots/benchmark_gc_100.txt
39+
GOGC=off go test -bench=. -benchmem -count=10 -timeout=20m -cpu=1,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,48,64 -run=^$ ./... > plots/benchmark_gc_100.txt
40+
GOGC=8000 go test -bench=. -benchmem -count=10 -timeout=20m -cpu=1,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,34,36,38,40,42,48,64 -run=^$ ./... > plots/benchmark_gc_8000.txt
41+
```
42+
43+
44+
## Plotting
45+
46+
The `plot/` directory contains a python script to visualize the benchmark results.
47+
48+
### Install
49+
50+
```bash
51+
python3 -m venv env
52+
source env/bin/activate
53+
pip3 install -r requirements.txt
54+
```
55+
56+
### Plot
57+
58+
Run the python script and provide the input file and the output file as arguments.
59+
60+
```bash
61+
python3 plot.py benchmark_gc_off.txt benchmark_gc_off.pdf
62+
```
63+
64+
This will generate the graph as pdf (`result_<timestamp>.pdf`).
65+
66+
### Example
67+
68+
Let's run the `ECDSASignView` benchmark as an example.
69+
We turn garbage collection off using with `GOGC=off`, set the number of benchmark iteration with `-count=10`, and set the number of workers with `-cpu=1,2,4,8,16`.
70+
We save the results in `benchmark_gc_off.txt`, which we use later to plot our graphs.
71+
72+
Once the benchmark is finished, we use `plot/plot.py` to create the result graphs as `pdf`.
73+
74+
```bash
75+
GOGC=off go test -bench='ECDSASignView' -benchmem -count=10 -cpu=1,2,4,8,16 -run=^$ ./... > plots/benchmark_gc_off.txt
76+
cd plots; python3 plot.py benchmark_gc_off.txt benchmark_gc_off.pdf
77+
```
78+
79+
Happy benchmarking!

integration/benchmark/benchmark.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/*
2+
Copyright IBM Corp All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package benchmark
8+
9+
import (
10+
"testing"
11+
)
12+
13+
func ReportTPS(b *testing.B) {
14+
b.ReportMetric(float64(b.N)/b.Elapsed().Seconds(), "TPS")
15+
}
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/*
2+
Copyright IBM Corp All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package test
8+
9+
import (
10+
"encoding/json"
11+
"testing"
12+
"time"
13+
14+
"github.com/hyperledger-labs/fabric-smart-client/integration/benchmark"
15+
benchviews "github.com/hyperledger-labs/fabric-smart-client/integration/benchmark/views"
16+
"github.com/hyperledger-labs/fabric-smart-client/platform/view/services/grpc"
17+
"github.com/hyperledger-labs/fabric-smart-client/platform/view/services/metrics/disabled"
18+
"github.com/hyperledger-labs/fabric-smart-client/platform/view/services/view/grpc/server"
19+
"github.com/hyperledger-labs/fabric-smart-client/platform/view/services/view/grpc/server/protos"
20+
"github.com/hyperledger-labs/fabric-smart-client/platform/view/view"
21+
"github.com/stretchr/testify/assert"
22+
"github.com/stretchr/testify/require"
23+
"go.opentelemetry.io/otel/trace/noop"
24+
)
25+
26+
func BenchmarkGRPC(b *testing.B) {
27+
srvEndpoint := setupServer(b)
28+
29+
// we share a single connection among all client goroutines
30+
cli, closeF := setupClient(b, srvEndpoint)
31+
defer closeF()
32+
33+
b.RunParallel(func(pb *testing.PB) {
34+
for pb.Next() {
35+
resp, err := cli.CallViewWithContext(b.Context(), "fid", nil)
36+
require.NoError(b, err)
37+
require.NotNil(b, resp)
38+
}
39+
})
40+
benchmark.ReportTPS(b)
41+
}
42+
43+
func setupServer(tb testing.TB) string {
44+
tb.Helper()
45+
46+
mDefaultIdentity := view.Identity("server identity")
47+
mSigner := &benchmark.MockSigner{
48+
SerializeFunc: func() ([]byte, error) {
49+
return mDefaultIdentity.Bytes(), nil
50+
},
51+
SignFunc: func(bytes []byte) ([]byte, error) {
52+
return bytes, nil
53+
},
54+
}
55+
mIdentityProvider := &benchmark.MockIdentityProvider{DefaultSigner: mDefaultIdentity}
56+
mSigService := &benchmark.MockSignerProvider{DefaultSigner: mSigner}
57+
58+
// marshaller
59+
tm, err := server.NewResponseMarshaler(mIdentityProvider, mSigService)
60+
require.NoError(tb, err)
61+
require.NotNil(tb, tm)
62+
63+
// setup server
64+
grpcSrv, err := grpc.NewGRPCServer("localhost:0", grpc.ServerConfig{
65+
ConnectionTimeout: 0,
66+
SecOpts: grpc.SecureOptions{
67+
Certificate: certPEM,
68+
Key: keyPEM,
69+
UseTLS: true,
70+
},
71+
KaOpts: grpc.KeepaliveOptions{},
72+
Logger: nil,
73+
HealthCheckEnabled: false,
74+
})
75+
76+
require.NoError(tb, err)
77+
require.NotNil(tb, grpcSrv)
78+
79+
srv, err := server.NewViewServiceServer(tm, &server.YesPolicyChecker{}, server.NewMetrics(&disabled.Provider{}), noop.NewTracerProvider())
80+
require.NoError(tb, err)
81+
require.NotNil(tb, srv)
82+
83+
parms := &benchviews.CPUParams{N: 200000}
84+
input, _ := json.Marshal(parms)
85+
factory := &benchviews.CPUViewFactory{}
86+
v, _ := factory.NewView(input)
87+
88+
// our view manager
89+
vm := &benchmark.MockViewManager{Constructor: func() view.View {
90+
return v
91+
}}
92+
93+
// register view manager wit grpc impl
94+
server.InstallViewHandler(vm, srv, noop.NewTracerProvider())
95+
96+
// register grpc impl with grpc server
97+
protos.RegisterViewServiceServer(grpcSrv.Server(), srv)
98+
99+
// start the actual grpc server
100+
go func() {
101+
_ = grpcSrv.Start()
102+
}()
103+
tb.Cleanup(grpcSrv.Stop)
104+
105+
return grpcSrv.Address()
106+
}
107+
108+
func setupClient(tb testing.TB, srvEndpoint string) (*benchmark.ViewClient, func()) {
109+
tb.Helper()
110+
111+
mDefaultIdentity := view.Identity("client identity")
112+
mSigner := &benchmark.MockSigner{
113+
SerializeFunc: func() ([]byte, error) {
114+
return mDefaultIdentity.Bytes(), nil
115+
},
116+
SignFunc: func(bytes []byte) ([]byte, error) {
117+
return bytes, nil
118+
}}
119+
120+
signerIdentity, err := mSigner.Serialize()
121+
require.NoError(tb, err)
122+
123+
grpcClient, err := grpc.NewGRPCClient(grpc.ClientConfig{
124+
SecOpts: grpc.SecureOptions{
125+
ServerRootCAs: [][]byte{certPEM},
126+
UseTLS: true,
127+
},
128+
KaOpts: grpc.KeepaliveOptions{},
129+
Timeout: 5 * time.Second,
130+
AsyncConnect: false,
131+
})
132+
require.NoError(tb, err)
133+
require.NotNil(tb, grpcClient)
134+
135+
conn, err := grpcClient.NewConnection(srvEndpoint)
136+
require.NoError(tb, err)
137+
require.NotNil(tb, conn)
138+
139+
tlsCert := grpcClient.Certificate()
140+
tlsCertHash, err := grpc.GetTLSCertHash(&tlsCert)
141+
require.NoError(tb, err)
142+
143+
cli := &benchmark.ViewClient{
144+
SignF: mSigner.Sign,
145+
Creator: signerIdentity,
146+
TLSCertHash: tlsCertHash,
147+
Client: protos.NewViewServiceClient(conn),
148+
}
149+
150+
return cli, func() {
151+
assert.NoError(tb, conn.Close())
152+
}
153+
}

0 commit comments

Comments
 (0)