From 92aac7b7ca55da66e212ce5f71557f6d5d0b2c49 Mon Sep 17 00:00:00 2001 From: Julian Kornberger Date: Thu, 14 Jul 2016 01:19:03 +0200 Subject: [PATCH] Calculate channel utilization --- data/airtime.go | 51 ++++++++++++++++++++++++++++++++++++++++++++ data/airtime_test.go | 46 +++++++++++++++++++++++++++++++++++++++ data/breminale.go | 25 ---------------------- data/statistics.go | 4 ++++ main.go | 6 +++--- models/nodes.go | 10 ++++++++- stats_db.go | 42 +++++++++++++++++++----------------- 7 files changed, 136 insertions(+), 48 deletions(-) create mode 100644 data/airtime.go create mode 100644 data/airtime_test.go delete mode 100644 data/breminale.go diff --git a/data/airtime.go b/data/airtime.go new file mode 100644 index 0000000..caecb46 --- /dev/null +++ b/data/airtime.go @@ -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 + } +} diff --git a/data/airtime_test.go b/data/airtime_test.go new file mode 100644 index 0000000..c438848 --- /dev/null +++ b/data/airtime_test.go @@ -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) +} diff --git a/data/breminale.go b/data/breminale.go deleted file mode 100644 index f1da47d..0000000 --- a/data/breminale.go +++ /dev/null @@ -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"` -} diff --git a/data/statistics.go b/data/statistics.go index 45c04c8..1a7fae8 100644 --- a/data/statistics.go +++ b/data/statistics.go @@ -62,3 +62,7 @@ type Memory struct { Buffers uint32 `json:"buffers"` Free uint32 `json:"free"` } + +type SwitchPort struct { + Speed uint32 `json:"speed"` +} diff --git a/main.go b/main.go index 7edcbf2..f10e0a9 100644 --- a/main.go +++ b/main.go @@ -94,9 +94,9 @@ func onReceive(addr net.UDPAddr, res *data.ResponseData) { return } - nodes.Update(nodeId, res) + node := nodes.Update(nodeId, res) - if val := res.Statistics; val != nil && statsDb != nil { - statsDb.Add(val, res.NodeInfo) + if statsDb != nil && node.Statistics != nil { + statsDb.Add(nodeId, node) } } diff --git a/models/nodes.go b/models/nodes.go index 2f816b7..ac9eb92 100644 --- a/models/nodes.go +++ b/models/nodes.go @@ -49,7 +49,7 @@ func NewNodes(config *Config) *Nodes { } // 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() nodes.Lock() @@ -86,8 +86,16 @@ func (nodes *Nodes) Update(nodeID string, res *data.ResponseData) { // Update statistics 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 } + + return node } // GetNodesMini get meshviewer valide JSON diff --git a/stats_db.go b/stats_db.go index 80b17f8..781efe7 100644 --- a/stats_db.go +++ b/stats_db.go @@ -7,6 +7,7 @@ import ( "time" "github.com/FreifunkBremen/respond-collector/data" + "github.com/FreifunkBremen/respond-collector/models" "github.com/influxdata/influxdb/client/v2" ) @@ -44,14 +45,19 @@ func NewStatsDb() *StatsDb { 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{ - "nodeid": stats.NodeId, + "nodeid": nodeId, } - // Maybe a If - if owner := node.Owner; owner != nil { - tags["owner"] = owner.Contact + + if nodeinfo := node.Nodeinfo; nodeinfo != nil { + if owner := nodeinfo.Owner; owner != nil { + tags["owner"] = owner.Contact + } } + fields := map[string]interface{}{ "load": stats.LoadAverage, "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 } 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 { - fields["airtime24.active"] = time.Active - 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)) + addAirtime("24", w.Airtime24) + } if time := w.Airtime5; time != nil { - fields["airtime5.active"] = time.Active - 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)) + addAirtime("5", w.Airtime5) } }