aboutsummaryrefslogtreecommitdiffstats
path: root/core
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 /core
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 'core')
-rw-r--r--core/connection.go6
-rw-r--r--core/stats.go493
2 files changed, 242 insertions, 257 deletions
diff --git a/core/connection.go b/core/connection.go
index 8b8c7b1..6f82616 100644
--- a/core/connection.go
+++ b/core/connection.go
@@ -89,7 +89,6 @@ type ConnectionEvent struct {
// Connection represents a shared memory connection to VPP via vppAdapter.
type Connection struct {
vppClient adapter.VppAPI // VPP binary API client
- //statsClient adapter.StatsAPI // VPP stats API client
maxAttempts int // interval for reconnect attempts
recInterval time.Duration // maximum number of reconnect attempts
@@ -177,7 +176,9 @@ func (c *Connection) connectVPP() error {
log.Debugf("Connected to VPP")
if err := c.retrieveMessageIDs(); err != nil {
- c.vppClient.Disconnect()
+ if err := c.vppClient.Disconnect(); err != nil {
+ log.Debugf("disconnecting vpp client failed: %v", err)
+ }
return fmt.Errorf("VPP is incompatible: %v", err)
}
@@ -192,7 +193,6 @@ func (c *Connection) Disconnect() {
if c == nil {
return
}
-
if c.vppClient != nil {
c.disconnectVPP()
}
diff --git a/core/stats.go b/core/stats.go
index e935888..23b3848 100644
--- a/core/stats.go
+++ b/core/stats.go
@@ -1,22 +1,29 @@
package core
import (
- "fmt"
"path"
"strings"
"sync/atomic"
+ "time"
"git.fd.io/govpp.git/adapter"
"git.fd.io/govpp.git/api"
)
+var (
+ RetryUpdateCount = 10
+ RetryUpdateDelay = time.Millisecond * 10
+)
+
const (
- SystemStatsPrefix = "/sys/"
- SystemStats_VectorRate = SystemStatsPrefix + "vector_rate"
- SystemStats_InputRate = SystemStatsPrefix + "input_rate"
- SystemStats_LastUpdate = SystemStatsPrefix + "last_update"
- SystemStats_LastStatsClear = SystemStatsPrefix + "last_stats_clear"
- SystemStats_Heartbeat = SystemStatsPrefix + "heartbeat"
+ SystemStatsPrefix = "/sys/"
+ SystemStats_VectorRate = SystemStatsPrefix + "vector_rate"
+ SystemStats_NumWorkerThreads = SystemStatsPrefix + "num_worker_threads"
+ SystemStats_VectorRatePerWorker = SystemStatsPrefix + "vector_rate_per_worker"
+ SystemStats_InputRate = SystemStatsPrefix + "input_rate"
+ SystemStats_LastUpdate = SystemStatsPrefix + "last_update"
+ SystemStats_LastStatsClear = SystemStatsPrefix + "last_stats_clear"
+ SystemStats_Heartbeat = SystemStatsPrefix + "heartbeat"
NodeStatsPrefix = "/sys/node/"
NodeStats_Names = NodeStatsPrefix + "names"
@@ -42,11 +49,13 @@ const (
InterfaceStats_RxMiss = InterfaceStatsPrefix + "rx-miss"
InterfaceStats_RxError = InterfaceStatsPrefix + "rx-error"
InterfaceStats_TxError = InterfaceStatsPrefix + "tx-error"
+ InterfaceStats_Mpls = InterfaceStatsPrefix + "mpls"
InterfaceStats_Rx = InterfaceStatsPrefix + "rx"
InterfaceStats_RxUnicast = InterfaceStatsPrefix + "rx-unicast"
InterfaceStats_RxMulticast = InterfaceStatsPrefix + "rx-multicast"
InterfaceStats_RxBroadcast = InterfaceStatsPrefix + "rx-broadcast"
InterfaceStats_Tx = InterfaceStatsPrefix + "tx"
+ InterfaceStats_TxUnicast = InterfaceStatsPrefix + "tx-unicast"
InterfaceStats_TxUnicastMiss = InterfaceStatsPrefix + "tx-unicast-miss"
InterfaceStats_TxMulticast = InterfaceStatsPrefix + "tx-multicast"
InterfaceStats_TxBroadcast = InterfaceStatsPrefix + "tx-broadcast"
@@ -63,7 +72,14 @@ const (
type StatsConnection struct {
statsClient adapter.StatsAPI
- connected uint32 // non-zero if the adapter is connected to VPP
+ // connected is true if the adapter is connected to VPP
+ connected uint32
+
+ errorStatsData *adapter.StatDir
+ nodeStatsData *adapter.StatDir
+ ifaceStatsData *adapter.StatDir
+ sysStatsData *adapter.StatDir
+ bufStatsData *adapter.StatDir
}
func newStatsConnection(stats adapter.StatsAPI) *StatsConnection {
@@ -105,7 +121,6 @@ func (c *StatsConnection) Disconnect() {
if c == nil {
return
}
-
if c.statsClient != nil {
c.disconnectClient()
}
@@ -113,301 +128,314 @@ func (c *StatsConnection) Disconnect() {
func (c *StatsConnection) disconnectClient() {
if atomic.CompareAndSwapUint32(&c.connected, 1, 0) {
- c.statsClient.Disconnect()
+ if err := c.statsClient.Disconnect(); err != nil {
+ log.Debugf("disconnecting stats client failed: %v", err)
+ }
}
}
-// GetSystemStats retrieves VPP system stats.
-func (c *StatsConnection) GetSystemStats() (*api.SystemStats, error) {
- stats, err := c.statsClient.DumpStats(SystemStatsPrefix)
- if err != nil {
- return nil, err
+func (c *StatsConnection) updateStats(statDir **adapter.StatDir, patterns ...string) error {
+ if statDir == nil {
+ panic("statDir must not nil")
}
+ try := func() error {
+ if (*statDir) == nil {
+ dir, err := c.statsClient.PrepareDir(patterns...)
+ if err != nil {
+ log.Debugln("preparing dir failed:", err)
+ return err
+ }
+ *statDir = dir
+ } else {
+ if err := c.statsClient.UpdateDir(*statDir); err != nil {
+ log.Debugln("updating dir failed:", err)
+ *statDir = nil
+ return err
+ }
+ }
- sysStats := &api.SystemStats{}
+ return nil
+ }
+ var err error
+ for r := 0; r < RetryUpdateCount; r++ {
+ if err = try(); err == nil {
+ if r > 0 {
+ log.Debugf("retry successfull (r=%d)", r)
+ }
+ return nil
+ } else if err == adapter.ErrStatsDirStale || err == adapter.ErrStatsDataBusy {
+ // retrying
+ if r > 1 {
+ log.Debugln("sleeping for %v before next try", RetryUpdateDelay)
+ time.Sleep(RetryUpdateDelay)
+ }
+ } else {
+ // error is not retryable
+ break
+ }
+ }
+ return err
+}
- for _, stat := range stats {
- switch stat.Name {
+// UpdateSystemStats retrieves VPP system stats.
+func (c *StatsConnection) GetSystemStats(sysStats *api.SystemStats) (err error) {
+ if err := c.updateStats(&c.sysStatsData, SystemStatsPrefix); err != nil {
+ return err
+ }
+
+ for _, stat := range c.sysStatsData.Entries {
+ var val uint64
+ if s, ok := stat.Data.(adapter.ScalarStat); ok {
+ val = uint64(s)
+ }
+ switch string(stat.Name) {
case SystemStats_VectorRate:
- sysStats.VectorRate = scalarStatToFloat64(stat.Data)
+ sysStats.VectorRate = val
+ case SystemStats_NumWorkerThreads:
+ sysStats.NumWorkerThreads = val
+ case SystemStats_VectorRatePerWorker:
+ var vals []uint64
+ if ss, ok := stat.Data.(adapter.SimpleCounterStat); ok {
+ vals = make([]uint64, len(ss))
+ for w := range ss {
+ vals[w] = uint64(ss[w][0])
+ }
+ }
+ sysStats.VectorRatePerWorker = vals
case SystemStats_InputRate:
- sysStats.InputRate = scalarStatToFloat64(stat.Data)
+ sysStats.InputRate = val
case SystemStats_LastUpdate:
- sysStats.LastUpdate = scalarStatToFloat64(stat.Data)
+ sysStats.LastUpdate = val
case SystemStats_LastStatsClear:
- sysStats.LastStatsClear = scalarStatToFloat64(stat.Data)
+ sysStats.LastStatsClear = val
case SystemStats_Heartbeat:
- sysStats.Heartbeat = scalarStatToFloat64(stat.Data)
+ sysStats.Heartbeat = val
}
}
- return sysStats, nil
+ return nil
}
// GetErrorStats retrieves VPP error stats.
-func (c *StatsConnection) GetErrorStats(names ...string) (*api.ErrorStats, error) {
- var patterns []string
- if len(names) > 0 {
- patterns = make([]string, len(names))
- for i, name := range names {
- patterns[i] = CounterStatsPrefix + name
- }
- } else {
- // retrieve all error counters by default
- patterns = []string{CounterStatsPrefix}
+func (c *StatsConnection) GetErrorStats(errorStats *api.ErrorStats) (err error) {
+ if err := c.updateStats(&c.errorStatsData, CounterStatsPrefix); err != nil {
+ return err
}
- stats, err := c.statsClient.DumpStats(patterns...)
- if err != nil {
- return nil, err
+
+ if errorStats.Errors == nil || len(errorStats.Errors) != len(c.errorStatsData.Entries) {
+ errorStats.Errors = make([]api.ErrorCounter, len(c.errorStatsData.Entries))
+ for i := 0; i < len(c.errorStatsData.Entries); i++ {
+ errorStats.Errors[i].CounterName = string(c.errorStatsData.Entries[i].Name)
+ }
}
- var errorStats = &api.ErrorStats{}
-
- for _, stat := range stats {
- statName := strings.TrimPrefix(stat.Name, CounterStatsPrefix)
-
- /* TODO: deal with stats that contain '/' in node/counter name
- parts := strings.Split(statName, "/")
- var nodeName, counterName string
- switch len(parts) {
- case 2:
- nodeName = parts[0]
- counterName = parts[1]
- case 3:
- nodeName = parts[0] + parts[1]
- counterName = parts[2]
- }*/
-
- errorStats.Errors = append(errorStats.Errors, api.ErrorCounter{
- CounterName: statName,
- Value: errorStatToUint64(stat.Data),
- })
+ for i, stat := range c.errorStatsData.Entries {
+ if stat.Type != adapter.ErrorIndex {
+ continue
+ }
+ if errStat, ok := stat.Data.(adapter.ErrorStat); ok {
+ errorStats.Errors[i].Value = uint64(errStat)
+ }
}
- return errorStats, nil
+ return nil
}
-// GetNodeStats retrieves VPP per node stats.
-func (c *StatsConnection) GetNodeStats() (*api.NodeStats, error) {
- stats, err := c.statsClient.DumpStats(NodeStatsPrefix)
- if err != nil {
- return nil, err
+func (c *StatsConnection) GetNodeStats(nodeStats *api.NodeStats) (err error) {
+ if err := c.updateStats(&c.nodeStatsData, NodeStatsPrefix); err != nil {
+ return err
}
- nodeStats := &api.NodeStats{}
-
- var setPerNode = func(perNode []uint64, fn func(c *api.NodeCounters, v uint64)) {
- if nodeStats.Nodes == nil {
- nodeStats.Nodes = make([]api.NodeCounters, len(perNode))
- for i := range perNode {
+ prepNodes := func(l int) {
+ if nodeStats.Nodes == nil || len(nodeStats.Nodes) != l {
+ nodeStats.Nodes = make([]api.NodeCounters, l)
+ for i := 0; i < l; i++ {
nodeStats.Nodes[i].NodeIndex = uint32(i)
}
}
- for i, v := range perNode {
- if len(nodeStats.Nodes) <= i {
- break
- }
- nodeCounters := nodeStats.Nodes[i]
- fn(&nodeCounters, v)
- nodeStats.Nodes[i] = nodeCounters
+ }
+ perNode := func(stat adapter.StatEntry, fn func(*api.NodeCounters, uint64)) {
+ s := stat.Data.(adapter.SimpleCounterStat)
+ prepNodes(len(s[0]))
+ for i := range nodeStats.Nodes {
+ val := adapter.ReduceSimpleCounterStatIndex(s, i)
+ fn(&nodeStats.Nodes[i], val)
}
}
- for _, stat := range stats {
- switch stat.Name {
+ for _, stat := range c.nodeStatsData.Entries {
+ switch string(stat.Name) {
case NodeStats_Names:
- if names, ok := stat.Data.(adapter.NameStat); !ok {
- return nil, fmt.Errorf("invalid stat type for %s", stat.Name)
- } else {
- if nodeStats.Nodes == nil {
- nodeStats.Nodes = make([]api.NodeCounters, len(names))
- for i := range names {
- nodeStats.Nodes[i].NodeIndex = uint32(i)
- }
- }
- for i, name := range names {
- nodeStats.Nodes[i].NodeName = string(name)
+ stat := stat.Data.(adapter.NameStat)
+ prepNodes(len(stat))
+ for i, nc := range nodeStats.Nodes {
+ if nc.NodeName != string(stat[i]) {
+ nc.NodeName = string(stat[i])
+ nodeStats.Nodes[i] = nc
}
}
case NodeStats_Clocks:
- setPerNode(reduceSimpleCounterStat(stat.Data), func(c *api.NodeCounters, v uint64) {
- c.Clocks = v
+ perNode(stat, func(node *api.NodeCounters, val uint64) {
+ node.Clocks = val
})
case NodeStats_Vectors:
- setPerNode(reduceSimpleCounterStat(stat.Data), func(c *api.NodeCounters, v uint64) {
- c.Vectors = v
+ perNode(stat, func(node *api.NodeCounters, val uint64) {
+ node.Vectors = val
})
case NodeStats_Calls:
- setPerNode(reduceSimpleCounterStat(stat.Data), func(c *api.NodeCounters, v uint64) {
- c.Calls = v
+ perNode(stat, func(node *api.NodeCounters, val uint64) {
+ node.Calls = val
})
case NodeStats_Suspends:
- setPerNode(reduceSimpleCounterStat(stat.Data), func(c *api.NodeCounters, v uint64) {
- c.Suspends = v
+ perNode(stat, func(node *api.NodeCounters, val uint64) {
+ node.Suspends = val
})
}
}
- return nodeStats, nil
+ return nil
}
// GetInterfaceStats retrieves VPP per interface stats.
-func (c *StatsConnection) GetInterfaceStats() (*api.InterfaceStats, error) {
- stats, err := c.statsClient.DumpStats(InterfaceStatsPrefix)
- if err != nil {
- return nil, err
+func (c *StatsConnection) GetInterfaceStats(ifaceStats *api.InterfaceStats) (err error) {
+ if err := c.updateStats(&c.ifaceStatsData, InterfaceStatsPrefix); err != nil {
+ return err
}
- ifStats := &api.InterfaceStats{}
-
- var setPerIf = func(perIf []uint64, fn func(c *api.InterfaceCounters, v uint64)) {
- if ifStats.Interfaces == nil {
- ifStats.Interfaces = make([]api.InterfaceCounters, len(perIf))
- for i := range perIf {
- ifStats.Interfaces[i].InterfaceIndex = uint32(i)
+ prep := func(l int) {
+ if ifaceStats.Interfaces == nil || len(ifaceStats.Interfaces) != l {
+ ifaceStats.Interfaces = make([]api.InterfaceCounters, l)
+ for i := 0; i < l; i++ {
+ ifaceStats.Interfaces[i].InterfaceIndex = uint32(i)
}
}
- for i, v := range perIf {
- if len(ifStats.Interfaces) <= i {
- break
- }
- ifCounters := ifStats.Interfaces[i]
- fn(&ifCounters, v)
- ifStats.Interfaces[i] = ifCounters
+ }
+ perNode := func(stat adapter.StatEntry, fn func(*api.InterfaceCounters, uint64)) {
+ s := stat.Data.(adapter.SimpleCounterStat)
+ prep(len(s[0]))
+ for i := range ifaceStats.Interfaces {
+ val := adapter.ReduceSimpleCounterStatIndex(s, i)
+ fn(&ifaceStats.Interfaces[i], val)
+ }
+ }
+ perNodeComb := func(stat adapter.StatEntry, fn func(*api.InterfaceCounters, [2]uint64)) {
+ s := stat.Data.(adapter.CombinedCounterStat)
+ prep(len(s[0]))
+ for i := range ifaceStats.Interfaces {
+ val := adapter.ReduceCombinedCounterStatIndex(s, i)
+ fn(&ifaceStats.Interfaces[i], val)
}
}
- for _, stat := range stats {
- switch stat.Name {
+ for _, stat := range c.ifaceStatsData.Entries {
+ switch string(stat.Name) {
case InterfaceStats_Names:
- if names, ok := stat.Data.(adapter.NameStat); !ok {
- return nil, fmt.Errorf("invalid stat type for %s", stat.Name)
- } else {
- if ifStats.Interfaces == nil {
- ifStats.Interfaces = make([]api.InterfaceCounters, len(names))
- for i := range names {
- ifStats.Interfaces[i].InterfaceIndex = uint32(i)
- }
- }
- for i, name := range names {
- ifStats.Interfaces[i].InterfaceName = string(name)
+ stat := stat.Data.(adapter.NameStat)
+ prep(len(stat))
+ for i, nc := range ifaceStats.Interfaces {
+ if nc.InterfaceName != string(stat[i]) {
+ nc.InterfaceName = string(stat[i])
+ ifaceStats.Interfaces[i] = nc
}
}
case InterfaceStats_Drops:
- setPerIf(reduceSimpleCounterStat(stat.Data), func(c *api.InterfaceCounters, v uint64) {
- c.Drops = v
+ perNode(stat, func(iface *api.InterfaceCounters, val uint64) {
+ iface.Drops = val
})
case InterfaceStats_Punt:
- setPerIf(reduceSimpleCounterStat(stat.Data), func(c *api.InterfaceCounters, v uint64) {
- c.Punts = v
+ perNode(stat, func(iface *api.InterfaceCounters, val uint64) {
+ iface.Punts = val
})
case InterfaceStats_IP4:
- setPerIf(reduceSimpleCounterStat(stat.Data), func(c *api.InterfaceCounters, v uint64) {
- c.IP4 = v
+ perNode(stat, func(iface *api.InterfaceCounters, val uint64) {
+ iface.IP4 = val
})
case InterfaceStats_IP6:
- setPerIf(reduceSimpleCounterStat(stat.Data), func(c *api.InterfaceCounters, v uint64) {
- c.IP6 = v
+ perNode(stat, func(iface *api.InterfaceCounters, val uint64) {
+ iface.IP6 = val
})
case InterfaceStats_RxNoBuf:
- setPerIf(reduceSimpleCounterStat(stat.Data), func(c *api.InterfaceCounters, v uint64) {
- c.RxNoBuf = v
+ perNode(stat, func(iface *api.InterfaceCounters, val uint64) {
+ iface.RxNoBuf = val
})
case InterfaceStats_RxMiss:
- setPerIf(reduceSimpleCounterStat(stat.Data), func(c *api.InterfaceCounters, v uint64) {
- c.RxMiss = v
+ perNode(stat, func(iface *api.InterfaceCounters, val uint64) {
+ iface.RxMiss = val
})
case InterfaceStats_RxError:
- setPerIf(reduceSimpleCounterStat(stat.Data), func(c *api.InterfaceCounters, v uint64) {
- c.RxErrors = v
+ perNode(stat, func(iface *api.InterfaceCounters, val uint64) {
+ iface.RxErrors = val
})
case InterfaceStats_TxError:
- setPerIf(reduceSimpleCounterStat(stat.Data), func(c *api.InterfaceCounters, v uint64) {
- c.TxErrors = v
+ perNode(stat, func(iface *api.InterfaceCounters, val uint64) {
+ iface.TxErrors = val
})
- case InterfaceStats_Rx:
- per := reduceCombinedCounterStat(stat.Data)
- setPerIf(per[0], func(c *api.InterfaceCounters, v uint64) {
- c.RxPackets = v
+ case InterfaceStats_Mpls:
+ perNode(stat, func(iface *api.InterfaceCounters, val uint64) {
+ iface.Mpls = val
})
- setPerIf(per[1], func(c *api.InterfaceCounters, v uint64) {
- c.RxBytes = v
+ case InterfaceStats_Rx:
+ perNodeComb(stat, func(iface *api.InterfaceCounters, val [2]uint64) {
+ iface.Rx.Packets = val[0]
+ iface.Rx.Bytes = val[1]
})
case InterfaceStats_RxUnicast:
- per := reduceCombinedCounterStat(stat.Data)
- setPerIf(per[0], func(c *api.InterfaceCounters, v uint64) {
- c.RxUnicast[0] = v
- })
- setPerIf(per[1], func(c *api.InterfaceCounters, v uint64) {
- c.RxUnicast[1] = v
+ perNodeComb(stat, func(iface *api.InterfaceCounters, val [2]uint64) {
+ iface.RxUnicast.Packets = val[0]
+ iface.RxUnicast.Bytes = val[1]
})
case InterfaceStats_RxMulticast:
- per := reduceCombinedCounterStat(stat.Data)
- setPerIf(per[0], func(c *api.InterfaceCounters, v uint64) {
- c.RxMulticast[0] = v
- })
- setPerIf(per[1], func(c *api.InterfaceCounters, v uint64) {
- c.RxMulticast[1] = v
+ perNodeComb(stat, func(iface *api.InterfaceCounters, val [2]uint64) {
+ iface.RxMulticast.Packets = val[0]
+ iface.RxMulticast.Bytes = val[1]
})
case InterfaceStats_RxBroadcast:
- per := reduceCombinedCounterStat(stat.Data)
- setPerIf(per[0], func(c *api.InterfaceCounters, v uint64) {
- c.RxBroadcast[0] = v
- })
- setPerIf(per[1], func(c *api.InterfaceCounters, v uint64) {
- c.RxBroadcast[1] = v
+ perNodeComb(stat, func(iface *api.InterfaceCounters, val [2]uint64) {
+ iface.RxBroadcast.Packets = val[0]
+ iface.RxBroadcast.Bytes = val[1]
})
case InterfaceStats_Tx:
- per := reduceCombinedCounterStat(stat.Data)
- setPerIf(per[0], func(c *api.InterfaceCounters, v uint64) {
- c.TxPackets = v
- })
- setPerIf(per[1], func(c *api.InterfaceCounters, v uint64) {
- c.TxBytes = v
+ perNodeComb(stat, func(iface *api.InterfaceCounters, val [2]uint64) {
+ iface.Tx.Packets = val[0]
+ iface.Tx.Bytes = val[1]
})
case InterfaceStats_TxUnicastMiss:
- per := reduceCombinedCounterStat(stat.Data)
- setPerIf(per[0], func(c *api.InterfaceCounters, v uint64) {
- c.TxUnicastMiss[0] = v
- })
- setPerIf(per[1], func(c *api.InterfaceCounters, v uint64) {
- c.TxUnicastMiss[1] = v
+ // tx-unicast-miss was a spelling mistake in older versions
+ //
+ fallthrough
+ case InterfaceStats_TxUnicast:
+ perNodeComb(stat, func(iface *api.InterfaceCounters, val [2]uint64) {
+ iface.TxUnicast.Packets = val[0]
+ iface.TxUnicast.Bytes = val[1]
})
case InterfaceStats_TxMulticast:
- per := reduceCombinedCounterStat(stat.Data)
- setPerIf(per[0], func(c *api.InterfaceCounters, v uint64) {
- c.TxMulticast[0] = v
- })
- setPerIf(per[1], func(c *api.InterfaceCounters, v uint64) {
- c.TxMulticast[1] = v
+ perNodeComb(stat, func(iface *api.InterfaceCounters, val [2]uint64) {
+ iface.TxMulticast.Packets = val[0]
+ iface.TxMulticast.Bytes = val[1]
})
case InterfaceStats_TxBroadcast:
- per := reduceCombinedCounterStat(stat.Data)
- setPerIf(per[0], func(c *api.InterfaceCounters, v uint64) {
- c.TxBroadcast[0] = v
- })
- setPerIf(per[1], func(c *api.InterfaceCounters, v uint64) {
- c.TxBroadcast[1] = v
+ perNodeComb(stat, func(iface *api.InterfaceCounters, val [2]uint64) {
+ iface.TxBroadcast.Packets = val[0]
+ iface.TxBroadcast.Bytes = val[1]
})
}
}
- return ifStats, nil
+ return nil
}
// GetBufferStats retrieves VPP buffer pools stats.
-func (c *StatsConnection) GetBufferStats() (*api.BufferStats, error) {
- stats, err := c.statsClient.DumpStats(BufferStatsPrefix)
- if err != nil {
- return nil, err
+func (c *StatsConnection) GetBufferStats(bufStats *api.BufferStats) (err error) {
+ if err := c.updateStats(&c.bufStatsData, BufferStatsPrefix); err != nil {
+ return err
}
- bufStats := &api.BufferStats{
- Buffer: map[string]api.BufferPool{},
+ if bufStats.Buffer == nil {
+ bufStats.Buffer = make(map[string]api.BufferPool)
}
- for _, stat := range stats {
- d, f := path.Split(stat.Name)
+ for _, stat := range c.bufStatsData.Entries {
+ d, f := path.Split(string(stat.Name))
d = strings.TrimSuffix(d, "/")
name := strings.TrimPrefix(d, BufferStatsPrefix)
@@ -416,65 +444,22 @@ func (c *StatsConnection) GetBufferStats() (*api.BufferStats, error) {
b.PoolName = name
}
+ var val float64
+ s, ok := stat.Data.(adapter.ScalarStat)
+ if ok {
+ val = float64(s)
+ }
switch f {
case BufferStats_Cached:
- b.Cached = scalarStatToFloat64(stat.Data)
+ b.Cached = val
case BufferStats_Used:
- b.Used = scalarStatToFloat64(stat.Data)
+ b.Used = val
case BufferStats_Available:
- b.Available = scalarStatToFloat64(stat.Data)
+ b.Available = val
}
bufStats.Buffer[name] = b
}
- return bufStats, nil
-}
-
-func scalarStatToFloat64(stat adapter.Stat) float64 {
- if s, ok := stat.(adapter.ScalarStat); ok {
- return float64(s)
- }
- return 0
-}
-
-func errorStatToUint64(stat adapter.Stat) uint64 {
- if s, ok := stat.(adapter.ErrorStat); ok {
- return uint64(s)
- }
- return 0
-}
-
-func reduceSimpleCounterStat(stat adapter.Stat) []uint64 {
- if s, ok := stat.(adapter.SimpleCounterStat); ok {
- if len(s) == 0 {
- return []uint64{}
- }
- var per = make([]uint64, len(s[0]))
- for _, w := range s {
- for i, n := range w {
- per[i] += uint64(n)
- }
- }
- return per
- }
return nil
}
-
-func reduceCombinedCounterStat(stat adapter.Stat) [2][]uint64 {
- if s, ok := stat.(adapter.CombinedCounterStat); ok {
- if len(s) == 0 {
- return [2][]uint64{{}, {}}
- }
- var perPackets = make([]uint64, len(s[0]))
- var perBytes = make([]uint64, len(s[0]))
- for _, w := range s {
- for i, n := range w {
- perPackets[i] += uint64(n.Packets)
- perBytes[i] += uint64(n.Bytes)
- }
- }
- return [2][]uint64{perPackets, perBytes}
- }
- return [2][]uint64{}
-}