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