...
1
2
3 package mem
4
5 import (
6 "context"
7 "sync"
8 "syscall"
9 "unsafe"
10
11 "github.com/shirou/gopsutil/internal/common"
12 "golang.org/x/sys/windows"
13 )
14
15 var (
16 procEnumPageFilesW = common.ModPsapi.NewProc("EnumPageFilesW")
17 procGetNativeSystemInfo = common.Modkernel32.NewProc("GetNativeSystemInfo")
18 procGetPerformanceInfo = common.ModPsapi.NewProc("GetPerformanceInfo")
19 procGlobalMemoryStatusEx = common.Modkernel32.NewProc("GlobalMemoryStatusEx")
20 )
21
22 type memoryStatusEx struct {
23 cbSize uint32
24 dwMemoryLoad uint32
25 ullTotalPhys uint64
26 ullAvailPhys uint64
27 ullTotalPageFile uint64
28 ullAvailPageFile uint64
29 ullTotalVirtual uint64
30 ullAvailVirtual uint64
31 ullAvailExtendedVirtual uint64
32 }
33
34 func VirtualMemory() (*VirtualMemoryStat, error) {
35 return VirtualMemoryWithContext(context.Background())
36 }
37
38 func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
39 var memInfo memoryStatusEx
40 memInfo.cbSize = uint32(unsafe.Sizeof(memInfo))
41 mem, _, _ := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&memInfo)))
42 if mem == 0 {
43 return nil, windows.GetLastError()
44 }
45
46 ret := &VirtualMemoryStat{
47 Total: memInfo.ullTotalPhys,
48 Available: memInfo.ullAvailPhys,
49 Free: memInfo.ullAvailPhys,
50 UsedPercent: float64(memInfo.dwMemoryLoad),
51 }
52
53 ret.Used = ret.Total - ret.Available
54 return ret, nil
55 }
56
57 type performanceInformation struct {
58 cb uint32
59 commitTotal uint64
60 commitLimit uint64
61 commitPeak uint64
62 physicalTotal uint64
63 physicalAvailable uint64
64 systemCache uint64
65 kernelTotal uint64
66 kernelPaged uint64
67 kernelNonpaged uint64
68 pageSize uint64
69 handleCount uint32
70 processCount uint32
71 threadCount uint32
72 }
73
74 func SwapMemory() (*SwapMemoryStat, error) {
75 return SwapMemoryWithContext(context.Background())
76 }
77
78 func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
79 var perfInfo performanceInformation
80 perfInfo.cb = uint32(unsafe.Sizeof(perfInfo))
81 mem, _, _ := procGetPerformanceInfo.Call(uintptr(unsafe.Pointer(&perfInfo)), uintptr(perfInfo.cb))
82 if mem == 0 {
83 return nil, windows.GetLastError()
84 }
85 tot := perfInfo.commitLimit * perfInfo.pageSize
86 used := perfInfo.commitTotal * perfInfo.pageSize
87 free := tot - used
88 var usedPercent float64
89 if tot == 0 {
90 usedPercent = 0
91 } else {
92 usedPercent = float64(used) / float64(tot) * 100
93 }
94 ret := &SwapMemoryStat{
95 Total: tot,
96 Used: used,
97 Free: free,
98 UsedPercent: usedPercent,
99 }
100
101 return ret, nil
102 }
103
104 var (
105 pageSize uint64
106 pageSizeOnce sync.Once
107 )
108
109 type systemInfo struct {
110 wProcessorArchitecture uint16
111 wReserved uint16
112 dwPageSize uint32
113 lpMinimumApplicationAddress uintptr
114 lpMaximumApplicationAddress uintptr
115 dwActiveProcessorMask uintptr
116 dwNumberOfProcessors uint32
117 dwProcessorType uint32
118 dwAllocationGranularity uint32
119 wProcessorLevel uint16
120 wProcessorRevision uint16
121 }
122
123
124 type enumPageFileInformation struct {
125 cb uint32
126 reserved uint32
127 totalSize uint64
128 totalInUse uint64
129 peakUsage uint64
130 }
131
132 func SwapDevices() ([]*SwapDevice, error) {
133 return SwapDevicesWithContext(context.Background())
134 }
135
136 func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) {
137 pageSizeOnce.Do(func() {
138 var sysInfo systemInfo
139 procGetNativeSystemInfo.Call(uintptr(unsafe.Pointer(&sysInfo)))
140 pageSize = uint64(sysInfo.dwPageSize)
141 })
142
143
144
145 var swapDevices []*SwapDevice
146 result, _, _ := procEnumPageFilesW.Call(windows.NewCallback(pEnumPageFileCallbackW), uintptr(unsafe.Pointer(&swapDevices)))
147 if result == 0 {
148 return nil, windows.GetLastError()
149 }
150
151 return swapDevices, nil
152 }
153
154
155 func pEnumPageFileCallbackW(swapDevices *[]*SwapDevice, enumPageFileInfo *enumPageFileInformation, lpFilenamePtr *[syscall.MAX_LONG_PATH]uint16) *bool {
156 *swapDevices = append(*swapDevices, &SwapDevice{
157 Name: syscall.UTF16ToString((*lpFilenamePtr)[:]),
158 UsedBytes: enumPageFileInfo.totalInUse * pageSize,
159 FreeBytes: (enumPageFileInfo.totalSize - enumPageFileInfo.totalInUse) * pageSize,
160 })
161
162
163 ret := true
164 return &ret
165 }
166
View as plain text