1
0
mirror of https://github.com/shirou/gopsutil.git synced 2025-04-24 13:48:56 +08:00

Merge pull request #1579 from shirou/feature/enable_cache_on_host_boottime

[host]: add EnableBootTimeCache function
This commit is contained in:
shirou 2024-01-14 18:13:05 +09:00 committed by GitHub
commit 9627f199e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 82 additions and 13 deletions

View File

@ -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.
### 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
See https://pkg.go.dev/github.com/shirou/gopsutil/v3 or https://godocs.io/github.com/shirou/gopsutil/v3

View File

@ -62,6 +62,13 @@ func (t TemperatureStat) String() string {
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) {
return InfoWithContext(context.Background())
}

View File

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

View File

@ -71,7 +71,7 @@ func numProcs(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) {

View File

@ -195,3 +195,17 @@ func TestPlatformInformation(t *testing.T) {
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()
}
}

View File

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

View File

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

View File

@ -171,6 +171,13 @@ func (p NumCtxSwitchesStat) String() string {
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.
func Pids() ([]int32, error) {
return PidsWithContext(context.Background())

View File

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