diff options
Diffstat (limited to 'examples/cmd')
-rw-r--r-- | examples/cmd/perf-bench/perf-bench.go | 162 | ||||
-rw-r--r-- | examples/cmd/stats-client/stats_client.go | 76 |
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) } } |