@ -288,6 +288,19 @@ func setLinkMonitor(lm LinkMonitor) {
} )
} )
}
}
func debugInfo ( ) string {
var b strings . Builder
fmt . Fprintf ( & b , "radio high percent: %d\n" , radio . radioHighPercent ( ) )
fmt . Fprintf ( & b , "radio activity for the last hour (one minute per line):\n" )
for i , a := range radio . radioActive ( ) {
fmt . Fprintf ( & b , "%d" , a )
if i % 60 == 59 {
fmt . Fprintf ( & b , "\n" )
}
}
return b . String ( )
}
func isLikelyCellularInterface ( ifName string ) bool {
func isLikelyCellularInterface ( ifName string ) bool {
return strings . HasPrefix ( ifName , "rmnet" ) || // Android
return strings . HasPrefix ( ifName , "rmnet" ) || // Android
strings . HasPrefix ( ifName , "ww" ) || // systemd naming scheme for WWAN
strings . HasPrefix ( ifName , "ww" ) || // systemd naming scheme for WWAN
@ -331,18 +344,56 @@ const (
radioLowIdle = 12 // seconds radio idles in low power state before transitioning to off
radioLowIdle = 12 // seconds radio idles in low power state before transitioning to off
)
)
// radioActive returns a slice of 1s samples (one per second) for the past hour
// indicating whether the radio was active (1) or idle (0).
func ( rm * radioMonitor ) radioActive ( ) ( active [ radioSampleSize ] int64 ) {
rm . forEachSample ( func ( c int , isActive bool ) {
if isActive {
active [ c ] = 1
}
} )
return
}
// radioHighPercent returns the percentage of time (as an int from 0 to 100)
// radioHighPercent returns the percentage of time (as an int from 0 to 100)
// that the cellular radio was in high power mode during the past hour.
// that the cellular radio was in high power mode during the past hour.
// If the radio has been monitored for less than an hour,
// If the radio has been monitored for less than an hour,
// the percentage is calculated based on the time monitored.
// the percentage is calculated based on the time monitored.
func ( rm * radioMonitor ) radioHighPercent ( ) int64 {
func ( rm * radioMonitor ) radioHighPercent ( ) int64 {
var highPowerSec int64 // total seconds radio was in high power (active or idle)
lastActive := - 1 // counter when radio was last active
periodLength := rm . forEachSample ( func ( c int , isActive bool ) {
if isActive {
// radio on and active
highPowerSec ++
lastActive = c
} else if lastActive != - 1 && c - lastActive < radioHighIdle {
// radio on but idle
highPowerSec ++
}
} )
if periodLength == 0 {
return 0
}
if highPowerSec == 0 {
return 0
}
return highPowerSec * 100 / periodLength
}
// forEachSample calls f for each sample in the past hour (or less if less time
// has passed -- the evaluated period is returned)
func ( rm * radioMonitor ) forEachSample ( f func ( c int , isActive bool ) ) ( periodLength int64 ) {
now := rm . now ( ) . Unix ( )
now := rm . now ( ) . Unix ( )
var periodLength int64 = radioSampleSize
periodLength = radioSampleSize
if t := now - rm . startTime ; t < periodLength {
if t := now - rm . startTime ; t < periodLength {
if t <= 0 {
if t <= 0 {
return 0
return 0
}
}
periodLength = t
periodLength = t + 1 // we want an inclusive range (with the current second)
}
}
periodStart := now - periodLength // start of current reporting period
periodStart := now - periodLength // start of current reporting period
@ -353,25 +404,14 @@ func (rm *radioMonitor) radioHighPercent() int64 {
rm . usage [ split : ] ,
rm . usage [ split : ] ,
rm . usage [ : split ] ,
rm . usage [ : split ] ,
}
}
var highPowerSec int64 // total seconds radio was in high power (active or idle)
var c int // counter
var c int // counter
var lastActive int // counter when radio was last active
for _ , slice := range slices {
for _ , slice := range slices {
for _ , v := range slice {
for _ , v := range slice {
c ++ // increment first so we don't have zero values
f ( c , v >= periodStart )
if v >= periodStart {
c ++
// radio on and active
highPowerSec ++
lastActive = c
} else if lastActive > 0 && c - lastActive < radioHighIdle {
// radio on but idle
highPowerSec ++
}
}
}
}
}
if highPowerSec == 0 {
return periodLength
return 0
}
return highPowerSec * 100 / periodLength
}
}