1// +build windows
2
3package mem
4
5import (
6	"context"
7	"unsafe"
8
9	"github.com/shirou/gopsutil/internal/common"
10	"golang.org/x/sys/windows"
11)
12
13var (
14	procGlobalMemoryStatusEx = common.Modkernel32.NewProc("GlobalMemoryStatusEx")
15	procGetPerformanceInfo   = common.ModPsapi.NewProc("GetPerformanceInfo")
16)
17
18type memoryStatusEx struct {
19	cbSize                  uint32
20	dwMemoryLoad            uint32
21	ullTotalPhys            uint64 // in bytes
22	ullAvailPhys            uint64
23	ullTotalPageFile        uint64
24	ullAvailPageFile        uint64
25	ullTotalVirtual         uint64
26	ullAvailVirtual         uint64
27	ullAvailExtendedVirtual uint64
28}
29
30func VirtualMemory() (*VirtualMemoryStat, error) {
31	return VirtualMemoryWithContext(context.Background())
32}
33
34func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
35	var memInfo memoryStatusEx
36	memInfo.cbSize = uint32(unsafe.Sizeof(memInfo))
37	mem, _, _ := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&memInfo)))
38	if mem == 0 {
39		return nil, windows.GetLastError()
40	}
41
42	ret := &VirtualMemoryStat{
43		Total:       memInfo.ullTotalPhys,
44		Available:   memInfo.ullAvailPhys,
45		Free:        memInfo.ullAvailPhys,
46		UsedPercent: float64(memInfo.dwMemoryLoad),
47	}
48
49	ret.Used = ret.Total - ret.Available
50	return ret, nil
51}
52
53type performanceInformation struct {
54	cb                uint32
55	commitTotal       uint64
56	commitLimit       uint64
57	commitPeak        uint64
58	physicalTotal     uint64
59	physicalAvailable uint64
60	systemCache       uint64
61	kernelTotal       uint64
62	kernelPaged       uint64
63	kernelNonpaged    uint64
64	pageSize          uint64
65	handleCount       uint32
66	processCount      uint32
67	threadCount       uint32
68}
69
70func SwapMemory() (*SwapMemoryStat, error) {
71	return SwapMemoryWithContext(context.Background())
72}
73
74func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
75	var perfInfo performanceInformation
76	perfInfo.cb = uint32(unsafe.Sizeof(perfInfo))
77	mem, _, _ := procGetPerformanceInfo.Call(uintptr(unsafe.Pointer(&perfInfo)), uintptr(perfInfo.cb))
78	if mem == 0 {
79		return nil, windows.GetLastError()
80	}
81	tot := perfInfo.commitLimit * perfInfo.pageSize
82	used := perfInfo.commitTotal * perfInfo.pageSize
83	free := tot - used
84	var usedPercent float64
85	if tot == 0 {
86		usedPercent = 0
87	} else {
88		usedPercent = float64(used) / float64(tot) * 100
89	}
90	ret := &SwapMemoryStat{
91		Total:       tot,
92		Used:        used,
93		Free:        free,
94		UsedPercent: usedPercent,
95	}
96
97	return ret, nil
98}
99