Calculate channel utilization

This commit is contained in:
Julian Kornberger 2016-07-14 01:19:03 +02:00
parent 8a99cb2bd7
commit 92aac7b7ca
7 changed files with 136 additions and 48 deletions

51
data/airtime.go Normal file
View File

@ -0,0 +1,51 @@
package data
type Wireless struct {
TxPower24 uint32 `json:"txpower24,omitempty"`
Channel24 uint32 `json:"channel24,omitempty"`
TxPower5 uint32 `json:"txpower5,omitempty"`
Channel5 uint32 `json:"channel5,omitempty"`
}
type WirelessStatistics struct {
Airtime24 *WirelessAirtime `json:"airtime24,omitempty"`
Airtime5 *WirelessAirtime `json:"airtime5,omitempty"`
}
type WirelessAirtime struct {
ChanUtil float32 // Channel utilization
RxUtil float32 // Receive utilization
TxUtil float32 // Transmit utilization
Active_time uint64 `json:"active"`
Busy_time uint64 `json:"busy"`
Rx_time uint64 `json:"rx"`
Tx_time uint64 `json:"tx"`
Noise uint32 `json:"noise"`
Frequency uint32 `json:"frequency"`
}
// Calculates the utilization values in regard to the previous values
func (cur *WirelessStatistics) SetUtilization(prev *WirelessStatistics) {
cur.Airtime24.SetUtilization(prev.Airtime24)
cur.Airtime5.SetUtilization(prev.Airtime5)
}
// Calculates the utilization values in regard to the previous values
func (cur *WirelessAirtime) SetUtilization(prev *WirelessAirtime) {
if prev == nil || cur.Active_time <= prev.Active_time {
return
}
active := float32(cur.Active_time) - float32(prev.Active_time)
busy := float32(cur.Busy_time) - float32(prev.Busy_time)
rx := float32(cur.Tx_time) - float32(prev.Tx_time)
tx := float32(cur.Rx_time) - float32(prev.Rx_time)
// Calculate utilizations
if active > 0 {
cur.ChanUtil = (busy + rx + tx) / active
cur.RxUtil = rx / active
cur.TxUtil = tx / active
}
}

46
data/airtime_test.go Normal file
View File

@ -0,0 +1,46 @@
package data
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestUtilization(t *testing.T) {
assert := assert.New(t)
t1 := &WirelessAirtime{
Active_time: 20,
Busy_time: 0,
Tx_time: 5,
Rx_time: 0,
}
t2 := &WirelessAirtime{
Active_time: 120,
Busy_time: 10,
Tx_time: 25,
Rx_time: 15,
}
t3 := &WirelessAirtime{
Active_time: 200,
Busy_time: 40,
Tx_time: 35,
Rx_time: 15,
}
t1.SetUtilization(t2)
assert.Zero(t1.ChanUtil)
assert.Zero(t1.TxUtil)
assert.Zero(t1.RxUtil)
t2.SetUtilization(t1)
assert.NotZero(t2.ChanUtil)
assert.EqualValues(0.45, t2.ChanUtil)
assert.EqualValues(0.2, t2.RxUtil)
assert.EqualValues(0.15, t2.TxUtil)
t3.SetUtilization(t2)
assert.EqualValues(0.5, t3.ChanUtil)
assert.EqualValues(0.125, t3.RxUtil)
assert.EqualValues(0, t3.TxUtil)
}

View File

@ -1,25 +0,0 @@
package data
type Wireless struct {
TxPower24 uint32 `json:"txpower24,omitempty"`
Channel24 uint32 `json:"channel24,omitempty"`
TxPower5 uint32 `json:"txpower5,omitempty"`
Channel5 uint32 `json:"channel5,omitempty"`
}
type SwitchPort struct {
Speed uint32 `json:"speed"`
}
type WirelessStatistics struct {
Airtime24 *WirelessAirtime `json:"airtime24,omitempty"`
Airtime5 *WirelessAirtime `json:"airtime5,omitempty"`
}
type WirelessAirtime struct {
Active uint64 `json:"active"`
Busy uint64 `json:"busy"`
Rx uint64 `json:"rx"`
Tx uint64 `json:"tx"`
Noise uint32 `json:"noise"`
Frequency uint32 `json:"frequency"`
}

View File

@ -62,3 +62,7 @@ type Memory struct {
Buffers uint32 `json:"buffers"` Buffers uint32 `json:"buffers"`
Free uint32 `json:"free"` Free uint32 `json:"free"`
} }
type SwitchPort struct {
Speed uint32 `json:"speed"`
}

View File

@ -94,9 +94,9 @@ func onReceive(addr net.UDPAddr, res *data.ResponseData) {
return return
} }
nodes.Update(nodeId, res) node := nodes.Update(nodeId, res)
if val := res.Statistics; val != nil && statsDb != nil { if statsDb != nil && node.Statistics != nil {
statsDb.Add(val, res.NodeInfo) statsDb.Add(nodeId, node)
} }
} }

View File

@ -49,7 +49,7 @@ func NewNodes(config *Config) *Nodes {
} }
// Update a Node // Update a Node
func (nodes *Nodes) Update(nodeID string, res *data.ResponseData) { func (nodes *Nodes) Update(nodeID string, res *data.ResponseData) *Node {
now := jsontime.Now() now := jsontime.Now()
nodes.Lock() nodes.Lock()
@ -86,8 +86,16 @@ func (nodes *Nodes) Update(nodeID string, res *data.ResponseData) {
// Update statistics // Update statistics
if val := res.Statistics; val != nil { if val := res.Statistics; val != nil {
// Update channel utilization if previous statistics are present
if node.Statistics != nil && node.Statistics.Wireless != nil && val.Wireless != nil {
val.Wireless.SetUtilization(node.Statistics.Wireless)
}
node.Statistics = val node.Statistics = val
} }
return node
} }
// GetNodesMini get meshviewer valide JSON // GetNodesMini get meshviewer valide JSON

View File

@ -7,6 +7,7 @@ import (
"time" "time"
"github.com/FreifunkBremen/respond-collector/data" "github.com/FreifunkBremen/respond-collector/data"
"github.com/FreifunkBremen/respond-collector/models"
"github.com/influxdata/influxdb/client/v2" "github.com/influxdata/influxdb/client/v2"
) )
@ -44,14 +45,19 @@ func NewStatsDb() *StatsDb {
return db return db
} }
func (c *StatsDb) Add(stats *data.Statistics, node *data.NodeInfo) { func (c *StatsDb) Add(nodeId string, node *models.Node) {
stats := node.Statistics
tags := map[string]string{ tags := map[string]string{
"nodeid": stats.NodeId, "nodeid": nodeId,
} }
// Maybe a If
if owner := node.Owner; owner != nil { if nodeinfo := node.Nodeinfo; nodeinfo != nil {
if owner := nodeinfo.Owner; owner != nil {
tags["owner"] = owner.Contact tags["owner"] = owner.Contact
} }
}
fields := map[string]interface{}{ fields := map[string]interface{}{
"load": stats.LoadAverage, "load": stats.LoadAverage,
"idletime": int64(stats.Idletime), "idletime": int64(stats.Idletime),
@ -89,23 +95,21 @@ func (c *StatsDb) Add(stats *data.Statistics, node *data.NodeInfo) {
fields["traffic.mgmt_tx.packets"] = t.Packets fields["traffic.mgmt_tx.packets"] = t.Packets
} }
if w := stats.Wireless; w != nil { if w := stats.Wireless; w != nil {
addAirtime := func(suffix string, time *data.WirelessAirtime) {
fields["airtime"+suffix+".chan_util"] = time.ChanUtil
fields["airtime"+suffix+".rx_util"] = time.RxUtil
fields["airtime"+suffix+".tx_util"] = time.TxUtil
fields["airtime"+suffix+".noise"] = time.Noise
fields["airtime"+suffix+".frequency"] = time.Frequency
tags["frequency"+suffix+""] = strconv.Itoa(int(time.Frequency))
}
if time := w.Airtime24; time != nil { if time := w.Airtime24; time != nil {
fields["airtime24.active"] = time.Active addAirtime("24", w.Airtime24)
fields["airtime24.busy"] = time.Busy
fields["airtime24.tx"] = time.Tx
fields["airtime24.rx"] = time.Rx
fields["airtime24.noise"] = time.Noise
fields["airtime24.frequency"] = time.Frequency
tags["frequency24"] = strconv.Itoa(int(time.Frequency))
} }
if time := w.Airtime5; time != nil { if time := w.Airtime5; time != nil {
fields["airtime5.active"] = time.Active addAirtime("5", w.Airtime5)
fields["airtime5.busy"] = time.Busy
fields["airtime5.tx"] = time.Tx
fields["airtime5.rx"] = time.Rx
fields["airtime5.noise"] = time.Noise
fields["airtime5.frequency"] = time.Frequency
tags["frequency5"] = strconv.Itoa(int(time.Frequency))
} }
} }