diff --git a/pkg/kubelet/winstats/perfcounter_nodestats.go b/pkg/kubelet/winstats/perfcounter_nodestats.go index b6855df401..9777d88745 100644 --- a/pkg/kubelet/winstats/perfcounter_nodestats.go +++ b/pkg/kubelet/winstats/perfcounter_nodestats.go @@ -23,18 +23,32 @@ import ( "os" "runtime" "sync" - "syscall" "time" "unsafe" "github.com/golang/glog" cadvisorapi "github.com/google/cadvisor/info/v1" + "golang.org/x/sys/windows" "k8s.io/apimachinery/pkg/util/wait" ) +// MemoryStatusEx is the same as Windows structure MEMORYSTATUSEX +// https://msdn.microsoft.com/en-us/library/windows/desktop/aa366770(v=vs.85).aspx +type MemoryStatusEx struct { + Length uint32 + MemoryLoad uint32 + TotalPhys uint64 + AvailPhys uint64 + TotalPageFile uint64 + AvailPageFile uint64 + TotalVirtual uint64 + AvailVirtual uint64 + AvailExtendedVirtual uint64 +} + var ( - modkernel32 = syscall.NewLazyDLL("kernel32.dll") - procGetPhysicallyInstalledSystemMemory = modkernel32.NewProc("GetPhysicallyInstalledSystemMemory") + modkernel32 = windows.NewLazySystemDLL("kernel32.dll") + procGlobalMemoryStatusEx = modkernel32.NewProc("GlobalMemoryStatusEx") ) // NewPerfCounterClient creates a client using perf counters @@ -163,20 +177,24 @@ func (p *perfCounterNodeStatsClient) convertCPUValue(cpuValue uint64) uint64 { } func getPhysicallyInstalledSystemMemoryBytes() (uint64, error) { - var physicalMemoryKiloBytes uint64 + // We use GlobalMemoryStatusEx instead of GetPhysicallyInstalledSystemMemory + // on Windows node for the following reasons: + // 1. GetPhysicallyInstalledSystemMemory retrieves the amount of physically + // installed RAM from the computer's SMBIOS firmware tables. + // https://msdn.microsoft.com/en-us/library/windows/desktop/cc300158(v=vs.85).aspx + // On some VM, it is unable to read data from SMBIOS and fails with ERROR_INVALID_DATA. + // 2. On Linux node, total physical memory is read from MemTotal in /proc/meminfo. + // GlobalMemoryStatusEx returns the amount of physical memory that is available + // for the operating system to use. The amount returned by GlobalMemoryStatusEx + // is closer in parity with Linux + // https://www.kernel.org/doc/Documentation/filesystems/proc.txt + var statex MemoryStatusEx + statex.Length = uint32(unsafe.Sizeof(statex)) + ret, _, _ := procGlobalMemoryStatusEx.Call(uintptr(unsafe.Pointer(&statex))) - if ok := getPhysicallyInstalledSystemMemory(&physicalMemoryKiloBytes); !ok { + if ret == 0 { return 0, errors.New("unable to read physical memory") } - return physicalMemoryKiloBytes * 1024, nil // convert kilobytes to bytes -} - -func getPhysicallyInstalledSystemMemory(totalMemoryInKilobytes *uint64) bool { - ret, _, _ := syscall.Syscall(procGetPhysicallyInstalledSystemMemory.Addr(), 1, - uintptr(unsafe.Pointer(totalMemoryInKilobytes)), - 0, - 0) - - return ret != 0 + return statex.TotalPhys, nil }