From ea84fc9ad2532f6a8a43863d5caaa090cdb32833 Mon Sep 17 00:00:00 2001 From: Will Norris Date: Tue, 9 May 2023 09:40:55 -0700 Subject: [PATCH] net/sockstats: wait before reporting battery usage Wait 2 minutes before we start reporting battery usage. There is always radio activity on initial startup, which gets reported as 100% high power usage. Let that settle before we report usage data. Updates tailscale/corp#9230 Signed-off-by: Will Norris --- net/sockstats/sockstats_tsgo.go | 8 ++++++-- net/sockstats/sockstats_tsgo_test.go | 22 +++++++++++++++++----- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/net/sockstats/sockstats_tsgo.go b/net/sockstats/sockstats_tsgo.go index 26211958f..37edddddf 100644 --- a/net/sockstats/sockstats_tsgo.go +++ b/net/sockstats/sockstats_tsgo.go @@ -325,6 +325,10 @@ type radioMonitor struct { // Usage is measured once per second, so this is the number of seconds of history to track. const radioSampleSize = 3600 // 1 hour +// initStallPeriod is the minimum amount of time in seconds to collect data before reporting. +// Otherwise, all clients will report 100% radio usage on startup. +var initStallPeriod int64 = 120 // 2 minutes + var radio = &radioMonitor{ now: time.Now, startTime: time.Now().Unix(), @@ -375,7 +379,7 @@ func (rm *radioMonitor) radioHighPercent() int64 { } }) - if periodLength == 0 { + if periodLength < initStallPeriod { return 0 } @@ -386,7 +390,7 @@ func (rm *radioMonitor) radioHighPercent() int64 { } // forEachSample calls f for each sample in the past hour (or less if less time -// has passed -- the evaluated period is returned) +// has passed -- the evaluated period is returned, measured in seconds) func (rm *radioMonitor) forEachSample(f func(c int, isActive bool)) (periodLength int64) { now := rm.now().Unix() periodLength = radioSampleSize diff --git a/net/sockstats/sockstats_tsgo_test.go b/net/sockstats/sockstats_tsgo_test.go index 9e3a5a86a..9887d6680 100644 --- a/net/sockstats/sockstats_tsgo_test.go +++ b/net/sockstats/sockstats_tsgo_test.go @@ -33,6 +33,14 @@ func TestRadioMonitor(t *testing.T) { func(_ *testTime, _ *radioMonitor) {}, 0, }, + { + "active less than init stall period", + func(tt *testTime, rm *radioMonitor) { + rm.active() + tt.Add(1 * time.Second) + }, + 0, // radio on, but not long enough to report data + }, { "active, 10 sec idle", func(tt *testTime, rm *radioMonitor) { @@ -42,13 +50,13 @@ func TestRadioMonitor(t *testing.T) { 50, // radio on 5 seconds of 10 seconds }, { - "active, spanning two seconds", + "active, spanning three seconds", func(tt *testTime, rm *radioMonitor) { rm.active() - tt.Add(1100 * time.Millisecond) + tt.Add(2100 * time.Millisecond) rm.active() }, - 100, // radio on for 2 seconds + 100, // radio on for 3 seconds }, { "400 iterations: 2 sec active, 1 min idle", @@ -66,13 +74,17 @@ func TestRadioMonitor(t *testing.T) { { "activity at end of time window", func(tt *testTime, rm *radioMonitor) { - tt.Add(1 * time.Second) + tt.Add(3 * time.Second) rm.active() }, - 50, + 25, }, } + oldStallPeriod := initStallPeriod + initStallPeriod = 3 + t.Cleanup(func() { initStallPeriod = oldStallPeriod }) + for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { tm := &testTime{time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC)}