| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 |
- // +build windows
- package mem
- import (
- "context"
- "sync"
- "syscall"
- "unsafe"
- "github.com/shirou/gopsutil/internal/common"
- "golang.org/x/sys/windows"
- )
- var (
- procEnumPageFilesW = common.ModPsapi.NewProc("EnumPageFilesW")
- procGetNativeSystemInfo = common.Modkernel32.NewProc("GetNativeSystemInfo")
- procGetPerformanceInfo = common.ModPsapi.NewProc("GetPerformanceInfo")
- procGlobalMemoryStatusEx = common.Modkernel32.NewProc("GlobalMemoryStatusEx")
- )
- type memoryStatusEx struct {
- cbSize uint32
- dwMemoryLoad uint32
- ullTotalPhys uint64 // in bytes
- ullAvailPhys uint64
- ullTotalPageFile uint64
- ullAvailPageFile uint64
- ullTotalVirtual uint64
- ullAvailVirtual uint64
- ullAvailExtendedVirtual uint64
- }
- func VirtualMemory() (*VirtualMemoryStat, error) {
- return VirtualMemoryWithContext(context.Background())
- }
- func VirtualMemoryWithContext(ctx context.Context) (*VirtualMemoryStat, error) {
- var memInfo memoryStatusEx
- memInfo.cbSize = uint32(unsafe.Sizeof(memInfo))
- mem, _, _ := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&memInfo)))
- if mem == 0 {
- return nil, windows.GetLastError()
- }
- ret := &VirtualMemoryStat{
- Total: memInfo.ullTotalPhys,
- Available: memInfo.ullAvailPhys,
- Free: memInfo.ullAvailPhys,
- UsedPercent: float64(memInfo.dwMemoryLoad),
- }
- ret.Used = ret.Total - ret.Available
- return ret, nil
- }
- type performanceInformation struct {
- cb uint32
- commitTotal uint64
- commitLimit uint64
- commitPeak uint64
- physicalTotal uint64
- physicalAvailable uint64
- systemCache uint64
- kernelTotal uint64
- kernelPaged uint64
- kernelNonpaged uint64
- pageSize uint64
- handleCount uint32
- processCount uint32
- threadCount uint32
- }
- func SwapMemory() (*SwapMemoryStat, error) {
- return SwapMemoryWithContext(context.Background())
- }
- func SwapMemoryWithContext(ctx context.Context) (*SwapMemoryStat, error) {
- var perfInfo performanceInformation
- perfInfo.cb = uint32(unsafe.Sizeof(perfInfo))
- mem, _, _ := procGetPerformanceInfo.Call(uintptr(unsafe.Pointer(&perfInfo)), uintptr(perfInfo.cb))
- if mem == 0 {
- return nil, windows.GetLastError()
- }
- tot := perfInfo.commitLimit * perfInfo.pageSize
- used := perfInfo.commitTotal * perfInfo.pageSize
- free := tot - used
- var usedPercent float64
- if tot == 0 {
- usedPercent = 0
- } else {
- usedPercent = float64(used) / float64(tot) * 100
- }
- ret := &SwapMemoryStat{
- Total: tot,
- Used: used,
- Free: free,
- UsedPercent: usedPercent,
- }
- return ret, nil
- }
- var (
- pageSize uint64
- pageSizeOnce sync.Once
- )
- type systemInfo struct {
- wProcessorArchitecture uint16
- wReserved uint16
- dwPageSize uint32
- lpMinimumApplicationAddress uintptr
- lpMaximumApplicationAddress uintptr
- dwActiveProcessorMask uintptr
- dwNumberOfProcessors uint32
- dwProcessorType uint32
- dwAllocationGranularity uint32
- wProcessorLevel uint16
- wProcessorRevision uint16
- }
- // system type as defined in https://docs.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-enum_page_file_information
- type enumPageFileInformation struct {
- cb uint32
- reserved uint32
- totalSize uint64
- totalInUse uint64
- peakUsage uint64
- }
- func SwapDevices() ([]*SwapDevice, error) {
- return SwapDevicesWithContext(context.Background())
- }
- func SwapDevicesWithContext(ctx context.Context) ([]*SwapDevice, error) {
- pageSizeOnce.Do(func() {
- var sysInfo systemInfo
- procGetNativeSystemInfo.Call(uintptr(unsafe.Pointer(&sysInfo)))
- pageSize = uint64(sysInfo.dwPageSize)
- })
- // the following system call invokes the supplied callback function once for each page file before returning
- // see https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumpagefilesw
- var swapDevices []*SwapDevice
- result, _, _ := procEnumPageFilesW.Call(windows.NewCallback(pEnumPageFileCallbackW), uintptr(unsafe.Pointer(&swapDevices)))
- if result == 0 {
- return nil, windows.GetLastError()
- }
- return swapDevices, nil
- }
- // system callback as defined in https://docs.microsoft.com/en-us/windows/win32/api/psapi/nc-psapi-penum_page_file_callbackw
- func pEnumPageFileCallbackW(swapDevices *[]*SwapDevice, enumPageFileInfo *enumPageFileInformation, lpFilenamePtr *[syscall.MAX_LONG_PATH]uint16) *bool {
- *swapDevices = append(*swapDevices, &SwapDevice{
- Name: syscall.UTF16ToString((*lpFilenamePtr)[:]),
- UsedBytes: enumPageFileInfo.totalInUse * pageSize,
- FreeBytes: (enumPageFileInfo.totalSize - enumPageFileInfo.totalInUse) * pageSize,
- })
- // return true to continue enumerating page files
- ret := true
- return &ret
- }
|