81d183cab23b8554be4831efc9db8f30c1fb18d0
[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         "os"
24         "time"
25
26         "github.com/pkg/profile"
27         "github.com/sirupsen/logrus"
28
29         "git.fd.io/govpp.git/adapter/socketclient"
30         "git.fd.io/govpp.git/adapter/statsclient"
31         "git.fd.io/govpp.git/api"
32         "git.fd.io/govpp.git/core"
33         "git.fd.io/govpp.git/examples/binapi/vpe"
34 )
35
36 const (
37         defaultSyncRequestCount  = 1000
38         defaultAsyncRequestCount = 10000
39 )
40
41 func main() {
42         // parse optional flags
43         var sync bool
44         var cnt int
45         var sock, prof string
46         flag.BoolVar(&sync, "sync", false, "run synchronous perf test")
47         flag.StringVar(&sock, "api-socket", socketclient.DefaultSocketName, "Path to VPP API socket")
48         flag.String("stats-socket", statsclient.DefaultSocketName, "Path to VPP stats socket")
49         flag.IntVar(&cnt, "count", 0, "count of requests to be sent to VPP")
50         flag.StringVar(&prof, "prof", "", "enable profiling mode [mem, cpu]")
51         flag.Parse()
52
53         if cnt == 0 {
54                 // no specific count defined - use defaults
55                 if sync {
56                         cnt = defaultSyncRequestCount
57                 } else {
58                         cnt = defaultAsyncRequestCount
59                 }
60         }
61
62         switch prof {
63         case "mem":
64                 defer profile.Start(profile.MemProfile, profile.MemProfileRate(1)).Stop()
65         case "cpu":
66                 defer profile.Start(profile.CPUProfile).Stop()
67         case "":
68         default:
69                 fmt.Printf("invalid profiling mode: %q\n", prof)
70                 flag.Usage()
71                 os.Exit(1)
72         }
73
74         a := socketclient.NewVppClient(sock)
75
76         // connect to VPP
77         conn, err := core.Connect(a)
78         if err != nil {
79                 log.Fatalln("Error:", err)
80         }
81         defer conn.Disconnect()
82
83         // create an API channel
84         ch, err := conn.NewAPIChannelBuffered(cnt, cnt)
85         if err != nil {
86                 log.Fatalln("Error:", err)
87         }
88         defer ch.Close()
89
90         ch.SetReplyTimeout(time.Second * 2)
91
92         // log only errors
93         core.SetLogger(&logrus.Logger{Level: logrus.ErrorLevel})
94
95         // run the test & measure the time
96         start := time.Now()
97
98         if sync {
99                 // run synchronous test
100                 syncTest(ch, cnt)
101         } else {
102                 // run asynchronous test
103                 asyncTest(ch, cnt)
104         }
105
106         elapsed := time.Since(start)
107         fmt.Println("Test took:", elapsed)
108         fmt.Printf("Requests per second: %.0f\n", float64(cnt)/elapsed.Seconds())
109
110         time.Sleep(time.Second)
111 }
112
113 func syncTest(ch api.Channel, cnt int) {
114         fmt.Printf("Running synchronous perf test with %d requests...\n", cnt)
115
116         for i := 0; i < cnt; i++ {
117                 req := &vpe.ControlPing{}
118                 reply := &vpe.ControlPingReply{}
119
120                 if err := ch.SendRequest(req).ReceiveReply(reply); err != nil {
121                         log.Fatalln("Error in reply:", err)
122                 }
123         }
124 }
125
126 func asyncTest(ch api.Channel, cnt int) {
127         fmt.Printf("Running asynchronous perf test with %d requests...\n", cnt)
128
129         ctxChan := make(chan api.RequestCtx, cnt)
130
131         go func() {
132                 for i := 0; i < cnt; i++ {
133                         ctxChan <- ch.SendRequest(&vpe.ControlPing{})
134                 }
135                 close(ctxChan)
136                 fmt.Printf("Sending asynchronous requests finished\n")
137         }()
138
139         for ctx := range ctxChan {
140                 reply := &vpe.ControlPingReply{}
141                 if err := ctx.ReceiveReply(reply); err != nil {
142                         log.Fatalln("Error in reply:", err)
143                 }
144         }
145 }