aboutsummaryrefslogtreecommitdiffstats
path: root/examples/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'examples/cmd')
-rw-r--r--examples/cmd/perf-bench/perf-bench.go162
-rw-r--r--examples/cmd/stats-client/stats_client.go76
2 files changed, 206 insertions, 32 deletions
diff --git a/examples/cmd/perf-bench/perf-bench.go b/examples/cmd/perf-bench/perf-bench.go
new file mode 100644
index 0000000..e414b20
--- /dev/null
+++ b/examples/cmd/perf-bench/perf-bench.go
@@ -0,0 +1,162 @@
+// Copyright (c) 2017 Cisco and/or its affiliates.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at:
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Binary simple-client is an example VPP management application that exercises the
+// govpp API on real-world use-cases.
+package main
+
+import (
+ "flag"
+ "fmt"
+ "log"
+ "os"
+ "sync"
+ "time"
+
+ "github.com/Sirupsen/logrus"
+ "github.com/pkg/profile"
+
+ "git.fd.io/govpp.git"
+ "git.fd.io/govpp.git/api"
+ "git.fd.io/govpp.git/core"
+ "git.fd.io/govpp.git/core/bin_api/vpe"
+)
+
+const (
+ defaultSyncRequestCount = 1000
+ defaultAsyncRequestCount = 1000000
+)
+
+func main() {
+ // parse optional flags
+ var sync, prof bool
+ var cnt int
+ flag.BoolVar(&sync, "sync", false, "run synchronous perf test")
+ flag.IntVar(&cnt, "cnt", 0, "count of requests to be sent to VPP")
+ flag.BoolVar(&prof, "prof", false, "generate profile data")
+ flag.Parse()
+
+ if cnt == 0 {
+ // no specific count defined - use defaults
+ if sync {
+ cnt = defaultSyncRequestCount
+ } else {
+ cnt = defaultAsyncRequestCount
+ }
+ }
+
+ if prof {
+ defer profile.Start().Stop()
+ }
+
+ // log only errors
+ core.SetLogger(&logrus.Logger{Level: logrus.ErrorLevel})
+
+ // connect to VPP
+ conn, err := govpp.Connect()
+ if err != nil {
+ log.Println("Error:", err)
+ os.Exit(1)
+ }
+ defer conn.Disconnect()
+
+ // create an API channel
+ ch, err := conn.NewAPIChannelBuffered(cnt, cnt)
+ if err != nil {
+ log.Println("Error:", err)
+ os.Exit(1)
+ }
+ defer ch.Close()
+
+ // run the test & measure the time
+ start := time.Now()
+
+ if sync {
+ // run synchronous test
+ syncTest(ch, cnt)
+ } else {
+ // run asynchronous test
+ asyncTest(ch, cnt)
+ }
+
+ elapsed := time.Since(start)
+ fmt.Println("Test took:", elapsed)
+ fmt.Printf("Requests per second: %.0f\n", float64(cnt)/elapsed.Seconds())
+}
+
+func syncTest(ch *api.Channel, cnt int) {
+ fmt.Printf("Running synchronous perf test with %d requests...\n", cnt)
+
+ for i := 0; i < cnt; i++ {
+ req := &vpe.ControlPing{}
+ reply := &vpe.ControlPingReply{}
+
+ err := ch.SendRequest(req).ReceiveReply(reply)
+ if err != nil {
+ log.Println("Error in reply:", err)
+ os.Exit(1)
+ }
+ }
+}
+
+func asyncTest(ch *api.Channel, cnt int) {
+ fmt.Printf("Running asynchronous perf test with %d requests...\n", cnt)
+
+ // start a new go routine that reads the replies
+ var wg sync.WaitGroup
+ wg.Add(1)
+ go readAsyncReplies(ch, cnt, &wg)
+
+ // send asynchronous requests
+ sendAsyncRequests(ch, cnt)
+
+ // wait until all replies are recieved
+ wg.Wait()
+}
+
+func sendAsyncRequests(ch *api.Channel, cnt int) {
+ for i := 0; i < cnt; i++ {
+ ch.ReqChan <- &api.VppRequest{
+ Message: &vpe.ControlPing{},
+ }
+ }
+}
+
+func readAsyncReplies(ch *api.Channel, expectedCnt int, wg *sync.WaitGroup) {
+ cnt := 0
+
+ for {
+ // receive a reply
+ reply := <-ch.ReplyChan
+ if reply.Error != nil {
+ log.Println("Error in reply:", reply.Error)
+ os.Exit(1)
+ }
+
+ // decode the message
+ msg := &vpe.ControlPingReply{}
+ err := ch.MsgDecoder.DecodeMsg(reply.Data, msg)
+ if reply.Error != nil {
+ log.Println("Error by decoding:", err)
+ os.Exit(1)
+ }
+
+ // count and return if done
+ cnt++
+ if cnt >= expectedCnt {
+ wg.Done()
+ return
+ }
+ }
+}
diff --git a/examples/cmd/stats-client/stats_client.go b/examples/cmd/stats-client/stats_client.go
index fc40b24..ac2176d 100644
--- a/examples/cmd/stats-client/stats_client.go
+++ b/examples/cmd/stats-client/stats_client.go
@@ -26,7 +26,6 @@ import (
"git.fd.io/govpp.git"
"git.fd.io/govpp.git/api"
- "git.fd.io/govpp.git/api/ifcounters"
"git.fd.io/govpp.git/core"
"git.fd.io/govpp.git/core/bin_api/vpe"
"git.fd.io/govpp.git/examples/bin_api/interfaces"
@@ -55,7 +54,8 @@ func main() {
sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, os.Interrupt)
- var subs *api.NotifSubscription
+ var simpleCountersSubs *api.NotifSubscription
+ var combinedCountersSubs *api.NotifSubscription
var notifChan chan api.Message
// loop until Interrupt signal is received
@@ -68,8 +68,8 @@ loop:
switch connEvent.State {
case core.Connected:
fmt.Println("VPP connected.")
- if subs == nil {
- subs, notifChan = subscribeNotification(ch)
+ if simpleCountersSubs == nil {
+ simpleCountersSubs, combinedCountersSubs, notifChan = subscribeNotifications(ch)
}
requestStatistics(ch)
@@ -77,9 +77,17 @@ loop:
fmt.Println("VPP disconnected.")
}
- case notifMsg := <-notifChan:
- // counter notification received
- processCounters(notifMsg.(*interfaces.VnetInterfaceCounters))
+ case msg := <-notifChan:
+ switch notif := msg.(type) {
+ case *interfaces.VnetInterfaceSimpleCounters:
+ // simple counter notification received
+ processSimpleCounters(notif)
+ case *interfaces.VnetInterfaceCombinedCounters:
+ // combined counter notification received
+ processCombinedCounters(notif)
+ default:
+ fmt.Println("Ignoring unknown VPP notification")
+ }
case <-sigChan:
// interrupt received
@@ -88,16 +96,18 @@ loop:
}
}
- ch.UnsubscribeNotification(subs)
+ ch.UnsubscribeNotification(simpleCountersSubs)
+ ch.UnsubscribeNotification(combinedCountersSubs)
}
-// subscribeNotification subscribes for interface counters notifications.
-func subscribeNotification(ch *api.Channel) (*api.NotifSubscription, chan api.Message) {
+// subscribeNotifications subscribes for interface counters notifications.
+func subscribeNotifications(ch *api.Channel) (*api.NotifSubscription, *api.NotifSubscription, chan api.Message) {
notifChan := make(chan api.Message, 100)
- subs, _ := ch.SubscribeNotification(notifChan, interfaces.NewVnetInterfaceCounters)
+ simpleCountersSubs, _ := ch.SubscribeNotification(notifChan, interfaces.NewVnetInterfaceSimpleCounters)
+ combinedCountersSubs, _ := ch.SubscribeNotification(notifChan, interfaces.NewVnetInterfaceCombinedCounters)
- return subs, notifChan
+ return simpleCountersSubs, combinedCountersSubs, notifChan
}
// requestStatistics requests interface counters notifications from VPP.
@@ -108,25 +118,27 @@ func requestStatistics(ch *api.Channel) {
}).ReceiveReply(&vpe.WantStatsReply{})
}
-// processCounters processes a counter message received from VPP.
-func processCounters(msg *interfaces.VnetInterfaceCounters) {
- fmt.Printf("%+v\n", msg)
-
- if msg.IsCombined == 0 {
- // simple counter
- counters, err := ifcounters.DecodeCounters(ifcounters.VnetInterfaceCounters(*msg))
- if err != nil {
- fmt.Println("Error:", err)
- } else {
- fmt.Printf("%+v\n", counters)
- }
- } else {
- // combined counter
- counters, err := ifcounters.DecodeCombinedCounters(ifcounters.VnetInterfaceCounters(*msg))
- if err != nil {
- fmt.Println("Error:", err)
- } else {
- fmt.Printf("%+v\n", counters)
- }
+// processSimpleCounters processes simple counters received from VPP.
+func processSimpleCounters(counters *interfaces.VnetInterfaceSimpleCounters) {
+ fmt.Printf("%+v\n", counters)
+
+ counterNames := []string{"Drop", "Punt", "IPv4", "IPv6", "RxNoBuf", "RxMiss", "RxError", "TxError", "MPLS"}
+
+ for i := uint32(0); i < counters.Count; i++ {
+ fmt.Printf("Interface '%d': %s = %d\n",
+ counters.FirstSwIfIndex+i, counterNames[counters.VnetCounterType], counters.Data[i])
+ }
+}
+
+// processCombinedCounters processes combined counters received from VPP.
+func processCombinedCounters(counters *interfaces.VnetInterfaceCombinedCounters) {
+ fmt.Printf("%+v\n", counters)
+
+ counterNames := []string{"Rx", "Tx"}
+
+ for i := uint32(0); i < counters.Count; i++ {
+ fmt.Printf("Interface '%d': %s packets = %d, %s bytes = %d\n",
+ counters.FirstSwIfIndex+i, counterNames[counters.VnetCounterType], counters.Data[i].Packets,
+ counterNames[counters.VnetCounterType], counters.Data[i].Bytes)
}
}