File: mem_freebsd.go

package info (click to toggle)
golang-github-shirou-gopsutil 4.25.2-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental, forky, sid, trixie
  • size: 1,824 kB
  • sloc: makefile: 76; ansic: 19; sh: 11
file content (167 lines) | stat: -rw-r--r-- 4,003 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
// SPDX-License-Identifier: BSD-3-Clause
//go:build freebsd

package mem

import (
	"context"
	"errors"
	"unsafe"

	"golang.org/x/sys/unix"

	"github.com/shirou/gopsutil/v4/internal/common"
)

func VirtualMemory() (*VirtualMemoryStat, error) {
	return VirtualMemoryWithContext(context.Background())
}

func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
	pageSize, err := common.SysctlUint("vm.stats.vm.v_page_size")
	if err != nil {
		return nil, err
	}
	physmem, err := common.SysctlUint("hw.physmem")
	if err != nil {
		return nil, err
	}

	free, err := common.SysctlUint("vm.stats.vm.v_free_count")
	if err != nil {
		return nil, err
	}
	active, err := common.SysctlUint("vm.stats.vm.v_active_count")
	if err != nil {
		return nil, err
	}
	inactive, err := common.SysctlUint("vm.stats.vm.v_inactive_count")
	if err != nil {
		return nil, err
	}
	buffers, err := common.SysctlUint("vfs.bufspace")
	if err != nil {
		return nil, err
	}
	wired, err := common.SysctlUint("vm.stats.vm.v_wire_count")
	if err != nil {
		return nil, err
	}
	var cached, laundry uint64
	osreldate, _ := common.SysctlUint("kern.osreldate")
	if osreldate < 1102000 {
		cached, err = common.SysctlUint("vm.stats.vm.v_cache_count")
		if err != nil {
			return nil, err
		}
	} else {
		laundry, err = common.SysctlUint("vm.stats.vm.v_laundry_count")
		if err != nil {
			return nil, err
		}
	}

	p := pageSize
	ret := &VirtualMemoryStat{
		Total:    physmem,
		Free:     free * p,
		Active:   active * p,
		Inactive: inactive * p,
		Cached:   cached * p,
		Buffers:  buffers,
		Wired:    wired * p,
		Laundry:  laundry * p,
	}

	ret.Available = ret.Inactive + ret.Cached + ret.Free + ret.Laundry
	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
const (
	XSWDEV_VERSION11 = 1
	XSWDEV_VERSION   = 2
)

// Types from vm/vm_param.h
type xswdev struct {
	Version uint32 // Version is the version
	Dev     uint64 // 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
}

// xswdev11 is a compatibility for under FreeBSD 11
// sys/vm/swap_pager.c
type xswdev11 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 := common.SysctlUint("vm.nswapdev")
	if err != nil {
		return nil, err
	}

	if i == 0 {
		return nil, errors.New("no swap devices found")
	}

	c := int(i)

	i, err = common.SysctlUint("vm.stats.vm.v_page_size")
	if err != nil {
		return nil, err
	}
	pageSize := 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
		}

		// first, try to parse with version 2
		xsw := (*xswdev)(unsafe.Pointer(&buf[0]))
		if xsw.Version == XSWDEV_VERSION11 {
			// this is version 1, so try to parse again
			xsw := (*xswdev11)(unsafe.Pointer(&buf[0]))
			if xsw.Version != XSWDEV_VERSION11 {
				return nil, errors.New("xswdev version mismatch(11)")
			}
			s.Total += uint64(xsw.NBlks)
			s.Used += uint64(xsw.Used)
		} else if xsw.Version != XSWDEV_VERSION {
			return nil, errors.New("xswdev version mismatch")
		} else {
			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
}