aboutsummaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
authorOndrej Fabry <ofabry@cisco.com>2019-09-17 12:41:47 +0200
committerOndrej Fabry <ofabry@cisco.com>2019-10-03 12:54:22 +0200
commit809b69ea4a90455445c34bbad7d8e5fea5cf3462 (patch)
treeba4b94339ac83908e2d9933692dc373929380aa7 /examples
parent48198748bdfcc7d30c794cdac19de822da53f840 (diff)
Optimizations for statsclient
- this dramatically improves performance for stats data collection - memory allocation is now done only when stat dirs change - updating prepared stat dir does not need to allocate memory - created integration test for testing stats client - added NumWorkerThreads and VectorRatePerWorker to SystemStats - added ReduceSimpleCounterStatIndex, ReduceCombinedCounterStatIndex for aggregating specific index Change-Id: I702731a69024ab5dd0832bb5cfe2773a987359e5 Signed-off-by: Ondrej Fabry <ofabry@cisco.com>
Diffstat (limited to 'examples')
-rw-r--r--examples/perf-bench/perf-bench.go16
-rw-r--r--examples/stats-client/README.md (renamed from examples/stats-api/README.md)2
-rw-r--r--examples/stats-client/stats_api.go (renamed from examples/stats-api/stats_api.go)169
3 files changed, 118 insertions, 69 deletions
diff --git a/examples/perf-bench/perf-bench.go b/examples/perf-bench/perf-bench.go
index b246e6c..f48c154 100644
--- a/examples/perf-bench/perf-bench.go
+++ b/examples/perf-bench/perf-bench.go
@@ -25,9 +25,8 @@ import (
"github.com/pkg/profile"
"github.com/sirupsen/logrus"
- "git.fd.io/govpp.git/adapter"
"git.fd.io/govpp.git/adapter/socketclient"
- "git.fd.io/govpp.git/adapter/vppapiclient"
+ "git.fd.io/govpp.git/adapter/statsclient"
"git.fd.io/govpp.git/api"
"git.fd.io/govpp.git/core"
"git.fd.io/govpp.git/examples/binapi/vpe"
@@ -40,10 +39,12 @@ const (
func main() {
// parse optional flags
- var sync, prof, sock bool
+ var sync, prof bool
var cnt int
+ var sock string
flag.BoolVar(&sync, "sync", false, "run synchronous perf test")
- flag.BoolVar(&sock, "sock", false, "use socket client for VPP API")
+ flag.StringVar(&sock, "socket", socketclient.DefaultSocketName, "Path to VPP API socket")
+ flag.String("socket", statsclient.DefaultSocketName, "Path to VPP stats socket")
flag.IntVar(&cnt, "count", 0, "count of requests to be sent to VPP")
flag.BoolVar(&prof, "prof", false, "generate profile data")
flag.Parse()
@@ -61,12 +62,7 @@ func main() {
defer profile.Start().Stop()
}
- var a adapter.VppAPI
- if sock {
- a = socketclient.NewVppClient("/run/vpp-api.sock")
- } else {
- a = vppapiclient.NewVppClient("")
- }
+ a := socketclient.NewVppClient(sock)
// connect to VPP
conn, err := core.Connect(a)
diff --git a/examples/stats-api/README.md b/examples/stats-client/README.md
index f3d33b1..0a44a55 100644
--- a/examples/stats-api/README.md
+++ b/examples/stats-client/README.md
@@ -1,4 +1,4 @@
-# Stats API Example
+# Stats Client Example
This example demonstrates how to retrieve statistics from VPP using [the new Stats API](https://github.com/FDio/vpp/blob/master/src/vpp/stats/stats.md).
diff --git a/examples/stats-api/stats_api.go b/examples/stats-client/stats_api.go
index 175bb27..288caea 100644
--- a/examples/stats-api/stats_api.go
+++ b/examples/stats-client/stats_api.go
@@ -20,10 +20,11 @@ import (
"log"
"os"
"strings"
+ "time"
"git.fd.io/govpp.git/adapter"
"git.fd.io/govpp.git/adapter/statsclient"
- "git.fd.io/govpp.git/adapter/vppapiclient"
+ "git.fd.io/govpp.git/api"
"git.fd.io/govpp.git/core"
)
@@ -37,12 +38,12 @@ import (
var (
statsSocket = flag.String("socket", statsclient.DefaultSocketName, "Path to VPP stats socket")
dumpAll = flag.Bool("all", false, "Dump all stats including ones with zero values")
- oldclient = flag.Bool("oldclient", false, "Use old client for stats API (vppapiclient)")
+ pollPeriod = flag.Duration("period", time.Second*5, "Polling interval period")
)
func init() {
flag.Usage = func() {
- fmt.Fprintf(os.Stderr, "%s: usage [ls|dump|errors|interfaces|nodes|system|buffers] <patterns>...\n", os.Args[0])
+ fmt.Fprintf(os.Stderr, "%s: usage [ls|dump|poll|errors|interfaces|nodes|system|buffers] <patterns>...\n", os.Args[0])
flag.PrintDefaults()
os.Exit(1)
}
@@ -52,26 +53,12 @@ func main() {
flag.Parse()
skipZeros := !*dumpAll
- cmd := flag.Arg(0)
- switch cmd {
- case "", "ls", "dump", "errors", "interfaces", "nodes", "system", "buffers":
- default:
- flag.Usage()
- }
-
var patterns []string
if flag.NArg() > 0 {
patterns = flag.Args()[1:]
}
- var client adapter.StatsAPI
- if *oldclient {
- client = vppapiclient.NewStatClient(*statsSocket)
- } else {
- client = statsclient.NewStatsClient(*statsSocket)
- }
-
- fmt.Printf("Connecting to stats socket: %s\n", *statsSocket)
+ client := statsclient.NewStatsClient(*statsSocket)
c, err := core.ConnectStats(client)
if err != nil {
@@ -79,22 +66,26 @@ func main() {
}
defer c.Disconnect()
- switch cmd {
+ switch cmd := flag.Arg(0); cmd {
case "system":
- stats, err := c.GetSystemStats()
- if err != nil {
+ stats := new(api.SystemStats)
+ if err := c.GetSystemStats(stats); err != nil {
log.Fatalln("getting system stats failed:", err)
}
fmt.Printf("System stats: %+v\n", stats)
+ case "poll-system":
+ pollSystem(c)
+
case "nodes":
fmt.Println("Listing node stats..")
- stats, err := c.GetNodeStats()
- if err != nil {
+ stats := new(api.NodeStats)
+ if err := c.GetNodeStats(stats); err != nil {
log.Fatalln("getting node stats failed:", err)
}
+
for _, node := range stats.Nodes {
- if node.Calls == 0 && node.Suspends == 0 && node.Clocks == 0 && node.Vectors == 0 && skipZeros {
+ if skipZeros && node.Calls == 0 && node.Suspends == 0 && node.Clocks == 0 && node.Vectors == 0 {
continue
}
fmt.Printf(" - %+v\n", node)
@@ -103,8 +94,8 @@ func main() {
case "interfaces":
fmt.Println("Listing interface stats..")
- stats, err := c.GetInterfaceStats()
- if err != nil {
+ stats := new(api.InterfaceStats)
+ if err := c.GetInterfaceStats(stats); err != nil {
log.Fatalln("getting interface stats failed:", err)
}
for _, iface := range stats.Interfaces {
@@ -112,15 +103,18 @@ func main() {
}
fmt.Printf("Listed %d interface counters\n", len(stats.Interfaces))
+ case "poll-interfaces":
+ pollInterfaces(c)
+
case "errors":
fmt.Printf("Listing error stats.. %s\n", strings.Join(patterns, " "))
- stats, err := c.GetErrorStats(patterns...)
- if err != nil {
+ stats := new(api.ErrorStats)
+ if err := c.GetErrorStats(stats); err != nil {
log.Fatalln("getting error stats failed:", err)
}
n := 0
for _, counter := range stats.Errors {
- if counter.Value == 0 && skipZeros {
+ if skipZeros && counter.Value == 0 {
continue
}
fmt.Printf(" - %v\n", counter)
@@ -129,23 +123,33 @@ func main() {
fmt.Printf("Listed %d (%d) error counters\n", n, len(stats.Errors))
case "buffers":
- stats, err := c.GetBufferStats()
- if err != nil {
+ stats := new(api.BufferStats)
+ if err := c.GetBufferStats(stats); err != nil {
log.Fatalln("getting buffer stats failed:", err)
}
fmt.Printf("Buffer stats: %+v\n", stats)
case "dump":
+ fmt.Printf("Dumping stats.. %s\n", strings.Join(patterns, " "))
+
dumpStats(client, patterns, skipZeros)
- default:
+ case "poll":
+ fmt.Printf("Polling stats.. %s\n", strings.Join(patterns, " "))
+
+ pollStats(client, patterns, skipZeros)
+
+ case "list", "ls", "":
+ fmt.Printf("Listing stats.. %s\n", strings.Join(patterns, " "))
+
listStats(client, patterns)
+
+ default:
+ fmt.Printf("invalid command: %q\n", cmd)
}
}
func listStats(client adapter.StatsAPI, patterns []string) {
- fmt.Printf("Listing stats.. %s\n", strings.Join(patterns, " "))
-
list, err := client.ListStats(patterns...)
if err != nil {
log.Fatalln("listing stats failed:", err)
@@ -159,8 +163,6 @@ func listStats(client adapter.StatsAPI, patterns []string) {
}
func dumpStats(client adapter.StatsAPI, patterns []string, skipZeros bool) {
- fmt.Printf("Dumping stats.. %s\n", strings.Join(patterns, " "))
-
stats, err := client.DumpStats(patterns...)
if err != nil {
log.Fatalln("dumping stats failed:", err)
@@ -168,40 +170,91 @@ func dumpStats(client adapter.StatsAPI, patterns []string, skipZeros bool) {
n := 0
for _, stat := range stats {
- if isZero(stat.Data) && skipZeros {
+ if skipZeros && (stat.Data == nil || stat.Data.IsZero()) {
continue
}
- fmt.Printf(" - %-25s %25v %+v\n", stat.Name, stat.Type, stat.Data)
+ fmt.Printf(" - %-50s %25v %+v\n", stat.Name, stat.Type, stat.Data)
n++
}
fmt.Printf("Dumped %d (%d) stats\n", n, len(stats))
}
-func isZero(stat adapter.Stat) bool {
- switch s := stat.(type) {
- case adapter.ScalarStat:
- return s == 0
- case adapter.ErrorStat:
- return s == 0
- case adapter.SimpleCounterStat:
- for _, ss := range s {
- for _, sss := range ss {
- if sss != 0 {
- return false
- }
+func pollStats(client adapter.StatsAPI, patterns []string, skipZeros bool) {
+ dir, err := client.PrepareDir(patterns...)
+ if err != nil {
+ log.Fatalln("preparing dir failed:", err)
+ }
+
+ tick := time.Tick(*pollPeriod)
+ for {
+ n := 0
+ fmt.Println(time.Now().Format(time.Stamp))
+ for _, stat := range dir.Entries {
+ if skipZeros && (stat.Data == nil || stat.Data.IsZero()) {
+ continue
}
+ fmt.Printf("%-50s %+v\n", stat.Name, stat.Data)
+ n++
}
- return true
- case adapter.CombinedCounterStat:
- for _, ss := range s {
- for _, sss := range ss {
- if sss.Bytes != 0 || sss.Packets != 0 {
- return false
+ fmt.Println()
+
+ select {
+ case <-tick:
+ if err := client.UpdateDir(dir); err != nil {
+ if err == adapter.ErrStatsDirStale {
+ if dir, err = client.PrepareDir(patterns...); err != nil {
+ log.Fatalln("preparing dir failed:", err)
+ }
+ continue
}
+ log.Fatalln("updating dir failed:", err)
+ }
+ }
+ }
+}
+
+func pollSystem(client api.StatsProvider) {
+ stats := new(api.SystemStats)
+
+ if err := client.GetSystemStats(stats); err != nil {
+ log.Fatalln("updating system stats failed:", err)
+ }
+
+ tick := time.Tick(*pollPeriod)
+ for {
+ fmt.Printf("System stats: %+v\n", stats)
+ fmt.Println()
+
+ select {
+ case <-tick:
+ if err := client.GetSystemStats(stats); err != nil {
+ log.Println("updating system stats failed:", err)
+ }
+ }
+ }
+}
+
+func pollInterfaces(client api.StatsProvider) {
+ stats := new(api.InterfaceStats)
+
+ if err := client.GetInterfaceStats(stats); err != nil {
+ log.Fatalln("updating system stats failed:", err)
+ }
+
+ tick := time.Tick(*pollPeriod)
+ for {
+ fmt.Printf("Interface stats (%d interfaces)\n", len(stats.Interfaces))
+ for i := range stats.Interfaces {
+ fmt.Printf(" - %+v\n", stats.Interfaces[i])
+ }
+ fmt.Println()
+
+ select {
+ case <-tick:
+ if err := client.GetInterfaceStats(stats); err != nil {
+ log.Println("updating system stats failed:", err)
}
}
- return true
}
- return false
}