Merge pull request #1579 from shirou/feature/enable_cache_on_host_boottime

[host]: add EnableBootTimeCache function
pull/1558/head
shirou 1 year ago committed by GitHub
commit 9627f199e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -109,6 +109,17 @@ As of v3.23.6, it is now possible to pass a path location using `context`: impor
First priority is given to the value set in `context`, then the value from the environment variable, and finally the default location. First priority is given to the value set in `context`, then the value from the environment variable, and finally the default location.
### Caching
As of v3.24.1, it is now possible to cached some values. These values default to false, not cached.
Be very careful that enabling the cache may cause inconsistencies. For example, if you enable caching of boottime on Linux, be aware that unintended values may be returned if [the boottime is changed by NTP after booted](https://github.com/shirou/gopsutil/issues/1070#issuecomment-842512782).
- `host`
- EnableBootTimeCache
- `process`
- EnableBootTimeCache
## Documentation ## Documentation
See https://pkg.go.dev/github.com/shirou/gopsutil/v3 or https://godocs.io/github.com/shirou/gopsutil/v3 See https://pkg.go.dev/github.com/shirou/gopsutil/v3 or https://godocs.io/github.com/shirou/gopsutil/v3

@ -62,6 +62,13 @@ func (t TemperatureStat) String() string {
return string(s) return string(s)
} }
var enableBootTimeCache bool
// EnableBootTimeCache change cache behavior of BootTime. If true, cache BootTime value. Default is false.
func EnableBootTimeCache(enable bool) {
enableBootTimeCache = enable
}
func Info() (*InfoStat, error) { func Info() (*InfoStat, error) {
return InfoWithContext(context.Background()) return InfoWithContext(context.Background())
} }

@ -14,16 +14,20 @@ import (
var cachedBootTime uint64 var cachedBootTime uint64
func BootTimeWithContext(ctx context.Context) (uint64, error) { func BootTimeWithContext(ctx context.Context) (uint64, error) {
if enableBootTimeCache {
t := atomic.LoadUint64(&cachedBootTime) t := atomic.LoadUint64(&cachedBootTime)
if t != 0 { if t != 0 {
return t, nil return t, nil
} }
}
tv, err := unix.SysctlTimeval("kern.boottime") tv, err := unix.SysctlTimeval("kern.boottime")
if err != nil { if err != nil {
return 0, err return 0, err
} }
if enableBootTimeCache {
atomic.StoreUint64(&cachedBootTime, uint64(tv.Sec)) atomic.StoreUint64(&cachedBootTime, uint64(tv.Sec))
}
return uint64(tv.Sec), nil return uint64(tv.Sec), nil
} }

@ -71,7 +71,7 @@ func numProcs(ctx context.Context) (uint64, error) {
} }
func BootTimeWithContext(ctx context.Context) (uint64, error) { func BootTimeWithContext(ctx context.Context) (uint64, error) {
return common.BootTimeWithContext(ctx) return common.BootTimeWithContext(ctx, enableBootTimeCache)
} }
func UptimeWithContext(ctx context.Context) (uint64, error) { func UptimeWithContext(ctx context.Context) (uint64, error) {

@ -195,3 +195,17 @@ func TestPlatformInformation(t *testing.T) {
t.Logf("PlatformInformation(): %v, %v, %v", platform, family, version) t.Logf("PlatformInformation(): %v, %v, %v", platform, family, version)
} }
func BenchmarkBootTimeWithCache(b *testing.B) {
EnableBootTimeCache(true)
for i := 0; i < b.N; i++ {
BootTime()
}
}
func BenchmarkBootTimeWithoutCache(b *testing.B) {
EnableBootTimeCache(false)
for i := 0; i < b.N; i++ {
BootTime()
}
}

@ -127,16 +127,20 @@ func uptimeMillis() (uint64, error) {
var cachedBootTime uint64 var cachedBootTime uint64
func BootTimeWithContext(ctx context.Context) (uint64, error) { func BootTimeWithContext(ctx context.Context) (uint64, error) {
if enableBootTimeCache {
t := atomic.LoadUint64(&cachedBootTime) t := atomic.LoadUint64(&cachedBootTime)
if t != 0 { if t != 0 {
return t, nil return t, nil
} }
}
up, err := uptimeMillis() up, err := uptimeMillis()
if err != nil { if err != nil {
return 0, err return 0, err
} }
t = uint64((time.Duration(timeSinceMillis(up)) * time.Millisecond).Seconds()) t := uint64((time.Duration(timeSinceMillis(up)) * time.Millisecond).Seconds())
if enableBootTimeCache {
atomic.StoreUint64(&cachedBootTime, t) atomic.StoreUint64(&cachedBootTime, t)
}
return t, nil return t, nil
} }

@ -12,10 +12,14 @@ import (
"strconv" "strconv"
"strings" "strings"
"sync" "sync"
"sync/atomic"
"syscall" "syscall"
"time" "time"
) )
// cachedBootTime must be accessed via atomic.Load/StoreUint64
var cachedBootTime uint64
func DoSysctrl(mib string) ([]string, error) { func DoSysctrl(mib string) ([]string, error) {
cmd := exec.Command("sysctl", "-n", mib) cmd := exec.Command("sysctl", "-n", mib)
cmd.Env = getSysctrlEnv(os.Environ()) cmd.Env = getSysctrlEnv(os.Environ())
@ -56,7 +60,14 @@ func NumProcsWithContext(ctx context.Context) (uint64, error) {
return cnt, nil return cnt, nil
} }
func BootTimeWithContext(ctx context.Context) (uint64, error) { func BootTimeWithContext(ctx context.Context, enableCache bool) (uint64, error) {
if enableCache {
t := atomic.LoadUint64(&cachedBootTime)
if t != 0 {
return t, nil
}
}
system, role, err := VirtualizationWithContext(ctx) system, role, err := VirtualizationWithContext(ctx)
if err != nil { if err != nil {
return 0, err return 0, err
@ -72,7 +83,13 @@ func BootTimeWithContext(ctx context.Context) (uint64, error) {
} }
if useStatFile { if useStatFile {
return readBootTimeStat(ctx) t, err := readBootTimeStat(ctx)
if err != nil {
return 0, err
}
if enableCache {
atomic.StoreUint64(&cachedBootTime, t)
}
} }
filename := HostProcWithContext(ctx, "uptime") filename := HostProcWithContext(ctx, "uptime")
@ -90,6 +107,11 @@ func BootTimeWithContext(ctx context.Context) (uint64, error) {
} }
currentTime := float64(time.Now().UnixNano()) / float64(time.Second) currentTime := float64(time.Now().UnixNano()) / float64(time.Second)
t := currentTime - b t := currentTime - b
if enableCache {
atomic.StoreUint64(&cachedBootTime, uint64(t))
}
return uint64(t), nil return uint64(t), nil
} }

@ -171,6 +171,13 @@ func (p NumCtxSwitchesStat) String() string {
return string(s) return string(s)
} }
var enableBootTimeCache bool
// EnableBootTimeCache change cache behavior of BootTime. If true, cache BootTime value. Default is false.
func EnableBootTimeCache(enable bool) {
enableBootTimeCache = enable
}
// Pids returns a slice of process ID list which are running now. // Pids returns a slice of process ID list which are running now.
func Pids() ([]int32, error) { func Pids() ([]int32, error) {
return PidsWithContext(context.Background()) return PidsWithContext(context.Background())

@ -1071,7 +1071,7 @@ func (p *Process) fillFromTIDStatWithContext(ctx context.Context, tid int32) (ui
Iowait: iotime / float64(clockTicks), Iowait: iotime / float64(clockTicks),
} }
bootTime, _ := common.BootTimeWithContext(ctx) bootTime, _ := common.BootTimeWithContext(ctx, enableBootTimeCache)
t, err := strconv.ParseUint(fields[22], 10, 64) t, err := strconv.ParseUint(fields[22], 10, 64)
if err != nil { if err != nil {
return 0, 0, nil, 0, 0, 0, nil, err return 0, 0, nil, 0, 0, 0, nil, err

Loading…
Cancel
Save