support for shm prefixes
[govpp.git] / examples / cmd / 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         "os"
24         "sync"
25         "time"
26
27         "github.com/pkg/profile"
28         "github.com/sirupsen/logrus"
29
30         "git.fd.io/govpp.git"
31         "git.fd.io/govpp.git/api"
32         "git.fd.io/govpp.git/core"
33         "git.fd.io/govpp.git/core/bin_api/vpe"
34 )
35
36 const (
37         defaultSyncRequestCount  = 1000
38         defaultAsyncRequestCount = 1000000
39 )
40
41 func main() {
42         // parse optional flags
43         var sync, prof bool
44         var cnt int
45         flag.BoolVar(&sync, "sync", false, "run synchronous perf test")
46         flag.IntVar(&cnt, "cnt", 0, "count of requests to be sent to VPP")
47         flag.BoolVar(&prof, "prof", false, "generate profile data")
48         flag.Parse()
49
50         if cnt == 0 {
51                 // no specific count defined - use defaults
52                 if sync {
53                         cnt = defaultSyncRequestCount
54                 } else {
55                         cnt = defaultAsyncRequestCount
56                 }
57         }
58
59         if prof {
60                 defer profile.Start().Stop()
61         }
62
63         // log only errors
64         core.SetLogger(&logrus.Logger{Level: logrus.ErrorLevel})
65
66         // connect to VPP
67         conn, err := govpp.Connect("")
68         if err != nil {
69                 log.Println("Error:", err)
70                 os.Exit(1)
71         }
72         defer conn.Disconnect()
73
74         // create an API channel
75         ch, err := conn.NewAPIChannelBuffered(cnt, cnt)
76         if err != nil {
77                 log.Println("Error:", err)
78                 os.Exit(1)
79         }
80         defer ch.Close()
81
82         // run the test & measure the time
83         start := time.Now()
84
85         if sync {
86                 // run synchronous test
87                 syncTest(ch, cnt)
88         } else {
89                 // run asynchronous test
90                 asyncTest(ch, cnt)
91         }
92
93         elapsed := time.Since(start)
94         fmt.Println("Test took:", elapsed)
95         fmt.Printf("Requests per second: %.0f\n", float64(cnt)/elapsed.Seconds())
96 }
97
98 func syncTest(ch *api.Channel, cnt int) {
99         fmt.Printf("Running synchronous perf test with %d requests...\n", cnt)
100
101         for i := 0; i < cnt; i++ {
102                 req := &vpe.ControlPing{}
103                 reply := &vpe.ControlPingReply{}
104
105                 err := ch.SendRequest(req).ReceiveReply(reply)
106                 if err != nil {
107                         log.Println("Error in reply:", err)
108                         os.Exit(1)
109                 }
110         }
111 }
112
113 func asyncTest(ch *api.Channel, cnt int) {
114         fmt.Printf("Running asynchronous perf test with %d requests...\n", cnt)
115
116         // start a new go routine that reads the replies
117         var wg sync.WaitGroup
118         wg.Add(1)
119         go readAsyncReplies(ch, cnt, &wg)
120
121         // send asynchronous requests
122         sendAsyncRequests(ch, cnt)
123
124         // wait until all replies are recieved
125         wg.Wait()
126 }
127
128 func sendAsyncRequests(ch *api.Channel, cnt int) {
129         for i := 0; i < cnt; i++ {
130                 ch.ReqChan <- &api.VppRequest{
131                         Message: &vpe.ControlPing{},
132                 }
133         }
134 }
135
136 func readAsyncReplies(ch *api.Channel, expectedCnt int, wg *sync.WaitGroup) {
137         cnt := 0
138
139         for {
140                 // receive a reply
141                 reply := <-ch.ReplyChan
142                 if reply.Error != nil {
143                         log.Println("Error in reply:", reply.Error)
144                         os.Exit(1)
145                 }
146
147                 // decode the message
148                 msg := &vpe.ControlPingReply{}
149                 err := ch.MsgDecoder.DecodeMsg(reply.Data, msg)
150                 if reply.Error != nil {
151                         log.Println("Error by decoding:", err)
152                         os.Exit(1)
153                 }
154
155                 // count and return if done
156                 cnt++
157                 if cnt >= expectedCnt {
158                         wg.Done()
159                         return
160                 }
161         }
162 }