1
2
3 package mem
4
5 import (
6 "bytes"
7 "context"
8 "encoding/binary"
9 "errors"
10 "fmt"
11 "os/exec"
12
13 "github.com/shirou/gopsutil/internal/common"
14 "golang.org/x/sys/unix"
15 )
16
17 func GetPageSize() (uint64, error) {
18 return GetPageSizeWithContext(context.Background())
19 }
20
21 func GetPageSizeWithContext(ctx context.Context) (uint64, error) {
22 uvmexp, err := unix.SysctlUvmexp("vm.uvmexp")
23 if err != nil {
24 return 0, err
25 }
26 return uint64(uvmexp.Pagesize), nil
27 }
28
29 func VirtualMemory() (*VirtualMemoryStat, error) {
30 return VirtualMemoryWithContext(context.Background())
31 }
32
33 func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
34 uvmexp, err := unix.SysctlUvmexp("vm.uvmexp")
35 if err != nil {
36 return nil, err
37 }
38 p := uint64(uvmexp.Pagesize)
39
40 ret := &VirtualMemoryStat{
41 Total: uint64(uvmexp.Npages) * p,
42 Free: uint64(uvmexp.Free) * p,
43 Active: uint64(uvmexp.Active) * p,
44 Inactive: uint64(uvmexp.Inactive) * p,
45 Cached: 0,
46 Wired: uint64(uvmexp.Wired) * p,
47 }
48
49 ret.Available = ret.Inactive + ret.Cached + ret.Free
50 ret.Used = ret.Total - ret.Available
51 ret.UsedPercent = float64(ret.Used) / float64(ret.Total) * 100.0
52
53 mib := []int32{CTLVfs, VfsGeneric, VfsBcacheStat}
54 buf, length, err := common.CallSyscall(mib)
55 if err != nil {
56 return nil, err
57 }
58 if length < sizeOfBcachestats {
59 return nil, fmt.Errorf("short syscall ret %d bytes", length)
60 }
61 var bcs Bcachestats
62 br := bytes.NewReader(buf)
63 err = common.Read(br, binary.LittleEndian, &bcs)
64 if err != nil {
65 return nil, err
66 }
67 ret.Buffers = uint64(bcs.Numbufpages) * p
68
69 return ret, nil
70 }
71
72
73 func SwapMemory() (*SwapMemoryStat, error) {
74 return SwapMemoryWithContext(context.Background())
75 }
76
77 func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
78 swapctl, err := exec.LookPath("swapctl")
79 if err != nil {
80 return nil, err
81 }
82
83 out, err := invoke.CommandWithContext(ctx, swapctl, "-sk")
84 if err != nil {
85 return &SwapMemoryStat{}, nil
86 }
87
88 line := string(out)
89 var total, used, free uint64
90
91 _, err = fmt.Sscanf(line,
92 "total: %d 1K-blocks allocated, %d used, %d available",
93 &total, &used, &free)
94 if err != nil {
95 return nil, errors.New("failed to parse swapctl output")
96 }
97
98 percent := float64(used) / float64(total) * 100
99 return &SwapMemoryStat{
100 Total: total * 1024,
101 Used: used * 1024,
102 Free: free * 1024,
103 UsedPercent: percent,
104 }, nil
105 }
106
View as plain text