mirror of
https://github.com/shirou/gopsutil.git
synced 2025-04-28 13:48:49 +08:00

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.
133 lines
2.9 KiB
Go
133 lines
2.9 KiB
Go
// +build freebsd
|
|
|
|
package mem
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"unsafe"
|
|
|
|
"golang.org/x/sys/unix"
|
|
)
|
|
|
|
func VirtualMemory() (*VirtualMemoryStat, error) {
|
|
return VirtualMemoryWithContext(context.Background())
|
|
}
|
|
|
|
func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
|
|
pageSize, err := unix.SysctlUint32("vm.stats.vm.v_page_size")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
pageCount, err := unix.SysctlUint32("vm.stats.vm.v_page_count")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
free, err := unix.SysctlUint32("vm.stats.vm.v_free_count")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
active, err := unix.SysctlUint32("vm.stats.vm.v_active_count")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
inactive, err := unix.SysctlUint32("vm.stats.vm.v_inactive_count")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
cached, err := unix.SysctlUint32("vm.stats.vm.v_cache_count")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
buffers, err := unix.SysctlUint32("vfs.bufspace")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
wired, err := unix.SysctlUint32("vm.stats.vm.v_wire_count")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
p := uint64(pageSize)
|
|
ret := &VirtualMemoryStat{
|
|
Total: uint64(pageCount) * p,
|
|
Free: uint64(free) * p,
|
|
Active: uint64(active) * p,
|
|
Inactive: uint64(inactive) * p,
|
|
Cached: uint64(cached) * p,
|
|
Buffers: uint64(buffers),
|
|
Wired: uint64(wired) * p,
|
|
}
|
|
|
|
ret.Available = ret.Inactive + ret.Cached + ret.Free
|
|
ret.Used = ret.Total - ret.Available
|
|
ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0
|
|
|
|
return ret, nil
|
|
}
|
|
|
|
// Return swapinfo
|
|
func SwapMemory() (*SwapMemoryStat, error) {
|
|
return SwapMemoryWithContext(context.Background())
|
|
}
|
|
|
|
// Constants from vm/vm_param.h
|
|
// nolint: golint
|
|
const (
|
|
XSWDEV_VERSION = 1
|
|
)
|
|
|
|
// Types from vm/vm_param.h
|
|
type xswdev struct {
|
|
Version uint32 // Version is the version
|
|
Dev uint32 // Dev is the device identifier
|
|
Flags int32 // Flags is the swap flags applied to the device
|
|
NBlks int32 // NBlks is the total number of blocks
|
|
Used int32 // Used is the number of blocks used
|
|
}
|
|
|
|
func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
|
|
// FreeBSD can have multiple swap devices so we total them up
|
|
i, err := unix.SysctlUint32("vm.nswapdev")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if i == 0 {
|
|
return nil, errors.New("no swap devices found")
|
|
}
|
|
|
|
c := int(i)
|
|
|
|
i, err = unix.SysctlUint32("vm.stats.vm.v_page_size")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
pageSize := uint64(i)
|
|
|
|
var buf []byte
|
|
s := &SwapMemoryStat{}
|
|
for n := 0; n < c; n++ {
|
|
buf, err = unix.SysctlRaw("vm.swap_info", n)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
xsw := (*xswdev)(unsafe.Pointer(&buf[0]))
|
|
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
|
|
}
|