f48c154a342ac1b46b63a7cc4b7edbaa813ef400
[govpp.git] / examples / perf-bench / perf-bench.go
1 // Copyright (c) 2017 Cisco and/or its affiliates.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at:
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 // Binary simple-client is an example VPP management application that exercises the
16 // govpp API on real-world use-cases.
17 package main
18
19 import (
20         "flag"
21         "fmt"
22         "log"
23         "time"
24
25         "github.com/pkg/profile"
26         "github.com/sirupsen/logrus"
27
28         "git.fd.io/govpp.git/adapter/socketclient"
29         "git.fd.io/govpp.git/adapter/statsclient"
30         "git.fd.io/govpp.git/api"
31         "git.fd.io/govpp.git/core"
32         "git.fd.io/govpp.git/examples/binapi/vpe"
33 )
34
35 const (
36         defaultSyncRequestCount  = 1000
37         defaultAsyncRequestCount = 10000
38 )
39
40 func main() {
41         // parse optional flags
42         var sync, prof bool
43         var cnt int
44         var sock string
45         flag.BoolVar(&sync, "sync", false, "run synchronous perf test")
46         flag.StringVar(&sock, "socket", socketclient.DefaultSocketName, "Path to VPP API socket")
47         flag.String("socket", statsclient.DefaultSocketName, "Path to VPP stats socket")
48         flag.IntVar(&cnt, "count", 0, "count of requests to be sent to VPP")
49         flag.BoolVar(&prof, "prof", false, "generate profile data")
50         flag.Parse()
51
52         if cnt == 0 {
53                 // no specific count defined - use defaults
54                 if sync {
55                         cnt = defaultSyncRequestCount
56                 } else {
57                         cnt = defaultAsyncRequestCount
58                 }
59         }
60
61         if prof {
62                 defer profile.Start().Stop()
63         }
64
65         a := socketclient.NewVppClient(sock)
66
67         // connect to VPP
68         conn, err := core.Connect(a)
69         if err != nil {
70                 log.Fatalln("Error:", err)
71         }
72         defer conn.Disconnect()
73
74         // create an API channel
75         ch, err := conn.NewAPIChannelBuffered(cnt, cnt)
76         if err != nil {
77                 log.Fatalln("Error:", err)
78         }
79         defer ch.Close()
80
81         ch.SetReplyTimeout(time.Second * 2)
82
83         // log only errors
84         core.SetLogger(&logrus.Logger{Level: logrus.ErrorLevel})
85
86         // run the test & measure the time
87         start := time.Now()
88
89         if sync {
90                 // run synchronous test
91                 syncTest(ch, cnt)
92         } else {
93                 // run asynchronous test
94                 asyncTest(ch, cnt)
95         }
96
97         elapsed := time.Since(start)
98         fmt.Println("Test took:", elapsed)
99         fmt.Printf("Requests per second: %.0f\n", float64(cnt)/elapsed.Seconds())
100
101         time.Sleep(time.Second)
102 }
103
104 func syncTest(ch api.Channel, cnt int) {
105         fmt.Printf("Running synchronous perf test with %d requests...\n", cnt)
106
107         for i := 0; i < cnt; i++ {
108                 req := &vpe.ControlPing{}
109                 reply := &vpe.ControlPingReply{}
110
111                 if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
112                         log.Fatalln("Error in reply:", err)
113                 }
114         }
115 }
116
117 func asyncTest(ch api.Channel, cnt int) {
118         fmt.Printf("Running asynchronous perf test with %d requests...\n", cnt)
119
120         ctxChan := make(chan api.RequestCtx, cnt)
121
122         go func() {
123                 for i := 0; i < cnt; i++ {
124                         ctxChan <- ch.SendRequest(&vpe.ControlPing{})
125                 }
126                 close(ctxChan)
127                 fmt.Printf("Sending asynchronous requests finished\n")
128         }()
129
130         for ctx := range ctxChan {
131                 reply := &vpe.ControlPingReply{}
132                 if err := ctx.ReceiveReply(reply); err != nil {
133                         log.Fatalln("Error in reply:", err)
134                 }
135         }
136 }