From 7c386ca6d27fc76f8e9608b19067c5d32e068ad5 Mon Sep 17 00:00:00 2001 From: Will Norris Date: Wed, 19 Apr 2023 12:56:52 -0700 Subject: [PATCH] net/sockstats: fix calculation of radio power usage When splitting the radio monitor usage array, we were splitting at now % 3600 to get values into chronological order. This caused the value for the final second to be included at the beginning of the ordered slice rather than the end. If there was activity during that final second, an extra five seconds of high power usage would get recorded in some cases. This could result in a final calculation of greater than 100% usage. This corrects that by splitting values at (now+1 % 3600). This also simplifies the percentage calculation by always rounding values down, which is sufficient for our usage. Signed-off-by: Will Norris --- net/sockstats/sockstats_tsgo.go | 14 +++++++++----- net/sockstats/sockstats_tsgo_test.go | 12 ++++++++++-- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/net/sockstats/sockstats_tsgo.go b/net/sockstats/sockstats_tsgo.go index c243b8161..80ff7084a 100644 --- a/net/sockstats/sockstats_tsgo.go +++ b/net/sockstats/sockstats_tsgo.go @@ -8,7 +8,6 @@ package sockstats import ( "context" "fmt" - "math" "net" "strings" "sync" @@ -347,10 +346,12 @@ func (rm *radioMonitor) radioHighPercent() int64 { } periodStart := now - periodLength // start of current reporting period - // slices of radio usage, with values in chronological order + // split into slices of radio usage, with values in chronological order. + // split at now+1 so that the current second is in the second slice. + split := (now + 1) % radioSampleSize slices := [2][]int64{ - rm.usage[now%radioSampleSize:], - rm.usage[:now%radioSampleSize], + rm.usage[split:], + rm.usage[:split], } var highPowerSec int64 // total seconds radio was in high power (active or idle) var c int // counter @@ -369,5 +370,8 @@ func (rm *radioMonitor) radioHighPercent() int64 { } } - return int64(math.Round(float64(highPowerSec) / float64(periodLength) * 100)) + if highPowerSec == 0 { + return 0 + } + return highPowerSec * 100 / periodLength } diff --git a/net/sockstats/sockstats_tsgo_test.go b/net/sockstats/sockstats_tsgo_test.go index 5f4c04d92..f85ab9fca 100644 --- a/net/sockstats/sockstats_tsgo_test.go +++ b/net/sockstats/sockstats_tsgo_test.go @@ -39,7 +39,7 @@ func TestRadioMonitor(t *testing.T) { rm.active() tt.Add(10 * time.Second) }, - 50, // radio on 5 seconds of every 10 seconds + 50, // radio on 5 seconds of 10 seconds }, { "400 iterations: 2 sec active, 1 min idle", @@ -49,11 +49,19 @@ func TestRadioMonitor(t *testing.T) { rm.active() tt.Add(1 * time.Second) rm.active() - tt.Add(1 * time.Minute) + tt.Add(59 * time.Second) } }, 10, // radio on 6 seconds of every minute }, + { + "activity at end of time window", + func(tt *testTime, rm *radioMonitor) { + tt.Add(2 * time.Second) + rm.active() + }, + 50, + }, } for _, tt := range tests {