1
0
mirror of https://github.com/shirou/gopsutil.git synced 2025-05-04 22:17:34 +08:00

Eliminate call to swapinfo on FreeBSD

Improve performance by eliminating the fork out to swapinfo on FreeBSD which also helps prevent crashes / hangs due to the outstanding fork crash bug:
golang/go#15658

This also fixes the value reported by SwapMemory and SwapMemoryWithContext on FreeBSD which previously only included the first swap device and also reported the values in terms of 1K blocks instead of bytes.
This commit is contained in:
Steven Hartland 2018-03-11 22:10:31 +00:00
parent 5776ff9c7c
commit d968f63e51

View File

@ -5,9 +5,7 @@ package mem
import ( import (
"context" "context"
"errors" "errors"
"os/exec" "unsafe"
"strconv"
"strings"
"golang.org/x/sys/unix" "golang.org/x/sys/unix"
) )
@ -69,53 +67,66 @@ func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
} }
// Return swapinfo // Return swapinfo
// FreeBSD can have multiple swap devices. but use only first device
func SwapMemory() (*SwapMemoryStat, error) { func SwapMemory() (*SwapMemoryStat, error) {
return SwapMemoryWithContext(context.Background()) return SwapMemoryWithContext(context.Background())
} }
func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) { // Constants from vm/vm_param.h
swapinfo, err := exec.LookPath("swapinfo") // nolint: golint
if err != nil { const (
return nil, err XSWDEV_VERSION = 1
} )
out, err := invoke.Command(swapinfo) // Types from vm/vm_param.h
if err != nil { type xswdev struct {
return nil, err Version uint32 // Version is the version
} Dev uint32 // Dev is the device identifier
for _, line := range strings.Split(string(out), "\n") { Flags int32 // Flags is the swap flags applied to the device
values := strings.Fields(line) NBlks int32 // NBlks is the total number of blocks
// skip title line Used int32 // Used is the number of blocks used
if len(values) == 0 || values[0] == "Device" { }
continue
} func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
// FreeBSD can have multiple swap devices so we total them up
u := strings.Replace(values[4], "%", "", 1) i, err := unix.SysctlUint32("vm.nswapdev")
total_v, err := strconv.ParseUint(values[1], 10, 64) if err != nil {
if err != nil { return nil, err
return nil, err }
}
used_v, err := strconv.ParseUint(values[2], 10, 64) if i == 0 {
if err != nil { return nil, errors.New("no swap devices found")
return nil, err }
}
free_v, err := strconv.ParseUint(values[3], 10, 64) c := int(i)
if err != nil {
return nil, err i, err = unix.SysctlUint32("vm.stats.vm.v_page_size")
} if err != nil {
up_v, err := strconv.ParseFloat(u, 64) return nil, err
if err != nil { }
return nil, err pageSize := uint64(i)
}
var buf []byte
return &SwapMemoryStat{ s := &SwapMemoryStat{}
Total: total_v, for n := 0; n < c; n++ {
Used: used_v, buf, err = unix.SysctlRaw("vm.swap_info", n)
Free: free_v, if err != nil {
UsedPercent: up_v, return nil, err
}, nil }
}
xsw := (*xswdev)(unsafe.Pointer(&buf[0]))
return nil, errors.New("no swap devices found") if xsw.Version != XSWDEV_VERSION {
return nil, errors.New("xswdev version mismatch")
}
s.Total += uint64(xsw.NBlks)
s.Used += uint64(xsw.Used)
}
if s.Total != 0 {
s.UsedPercent = float64(s.Used) / float64(s.Total) * 100
}
s.Total *= pageSize
s.Used *= pageSize
s.Free = s.Total - s.Used
return s, nil
} }