...

Source file src/github.com/shirou/gopsutil/mem/mem_windows.go

Documentation: github.com/shirou/gopsutil/mem

     1  // +build windows
     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 // in bytes
    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  // system type as defined in https://docs.microsoft.com/en-us/windows/win32/api/psapi/ns-psapi-enum_page_file_information
   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  	// the following system call invokes the supplied callback function once for each page file before returning
   144  	// see https://docs.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumpagefilesw
   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  // system callback as defined in https://docs.microsoft.com/en-us/windows/win32/api/psapi/nc-psapi-penum_page_file_callbackw
   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  	// return true to continue enumerating page files
   163  	ret := true
   164  	return &ret
   165  }
   166  

View as plain text