Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Determine total physical memory from sysfs for linux as primary method #198

Merged
merged 1 commit into from
Sep 11, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 26 additions & 24 deletions pkg/linuxpath/path_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,36 +13,38 @@ import (
)

type Paths struct {
VarLog string
ProcMeminfo string
ProcCpuinfo string
SysKernelMMHugepages string
EtcMtab string
SysBlock string
SysDevicesSystemNode string
SysBusPciDevices string
SysClassDRM string
SysClassDMI string
SysClassNet string
RunUdevData string
VarLog string
ProcMeminfo string
ProcCpuinfo string
SysKernelMMHugepages string
EtcMtab string
SysBlock string
SysDevicesSystemNode string
SysDevicesSystemMemory string
SysBusPciDevices string
SysClassDRM string
SysClassDMI string
SysClassNet string
RunUdevData string
}

// New returns a new Paths struct containing filepath fields relative to the
// supplied Context
func New(ctx *context.Context) *Paths {
return &Paths{
VarLog: filepath.Join(ctx.Chroot, "var", "log"),
ProcMeminfo: filepath.Join(ctx.Chroot, "proc", "meminfo"),
ProcCpuinfo: filepath.Join(ctx.Chroot, "proc", "cpuinfo"),
SysKernelMMHugepages: filepath.Join(ctx.Chroot, "sys", "kernel", "mm", "hugepages"),
EtcMtab: filepath.Join(ctx.Chroot, "etc", "mtab"),
SysBlock: filepath.Join(ctx.Chroot, "sys", "block"),
SysDevicesSystemNode: filepath.Join(ctx.Chroot, "sys", "devices", "system", "node"),
SysBusPciDevices: filepath.Join(ctx.Chroot, "sys", "bus", "pci", "devices"),
SysClassDRM: filepath.Join(ctx.Chroot, "sys", "class", "drm"),
SysClassDMI: filepath.Join(ctx.Chroot, "sys", "class", "dmi"),
SysClassNet: filepath.Join(ctx.Chroot, "sys", "class", "net"),
RunUdevData: filepath.Join(ctx.Chroot, "run", "udev", "data"),
VarLog: filepath.Join(ctx.Chroot, "var", "log"),
ProcMeminfo: filepath.Join(ctx.Chroot, "proc", "meminfo"),
ProcCpuinfo: filepath.Join(ctx.Chroot, "proc", "cpuinfo"),
SysKernelMMHugepages: filepath.Join(ctx.Chroot, "sys", "kernel", "mm", "hugepages"),
EtcMtab: filepath.Join(ctx.Chroot, "etc", "mtab"),
SysBlock: filepath.Join(ctx.Chroot, "sys", "block"),
SysDevicesSystemNode: filepath.Join(ctx.Chroot, "sys", "devices", "system", "node"),
SysDevicesSystemMemory: filepath.Join(ctx.Chroot, "sys", "devices", "system", "memory"),
SysBusPciDevices: filepath.Join(ctx.Chroot, "sys", "bus", "pci", "devices"),
SysClassDRM: filepath.Join(ctx.Chroot, "sys", "class", "drm"),
SysClassDMI: filepath.Join(ctx.Chroot, "sys", "class", "dmi"),
SysClassNet: filepath.Join(ctx.Chroot, "sys", "class", "net"),
RunUdevData: filepath.Join(ctx.Chroot, "run", "udev", "data"),
}
}

Expand Down
57 changes: 53 additions & 4 deletions pkg/memory/memory_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ const (
_WARN_CANNOT_DETERMINE_PHYSICAL_MEMORY = `
Could not determine total physical bytes of memory. This may
be due to the host being a virtual machine or container with no
/var/log/syslog file, or the current user may not have necessary
privileges to read the syslog. We are falling back to setting the
total physical amount of memory to the total usable amount of memory
/var/log/syslog file or /sys/devices/system/memory directory, or
the current user may not have necessary privileges to read the syslog.
We are falling back to setting the total physical amount of memory to
the total usable amount of memory
`
)

Expand All @@ -55,7 +56,55 @@ func (i *Info) load() error {
return nil
}

func memTotalPhysicalBytes(paths *linuxpath.Paths) int64 {
func memTotalPhysicalBytes(paths *linuxpath.Paths) (total int64) {
defer func() {
// fallback to the syslog file approach in case of error
if total < 0 {
total = memTotalPhysicalBytesFromSyslog(paths)
}
}()

// detect physical memory from /sys/devices/system/memory
dir := paths.SysDevicesSystemMemory

// get the memory block size in byte in hexadecimal notation
blockSize := filepath.Join(dir, "block_size_bytes")

d, err := ioutil.ReadFile(blockSize)
if err != nil {
return -1
}
blockSizeBytes, err := strconv.ParseUint(strings.TrimSpace(string(d)), 16, 64)
if err != nil {
return -1
}

// iterate over memory's block /sys/devices/system/memory/memory*,
// if the memory block state is 'online' we increment the total
// with the memory block size to determine the amount of physical
// memory available on this system
sysMemory, err := filepath.Glob(filepath.Join(dir, "memory*"))
if err != nil {
return -1
} else if sysMemory == nil {
return -1
}

for _, path := range sysMemory {
s, err := ioutil.ReadFile(filepath.Join(path, "state"))
if err != nil {
return -1
}
if strings.TrimSpace(string(s)) != "online" {
continue
}
total += int64(blockSizeBytes)
}

return total
}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very, very nice. 👍


func memTotalPhysicalBytesFromSyslog(paths *linuxpath.Paths) int64 {
// In Linux, the total physical memory can be determined by looking at the
// output of dmidecode, however dmidecode requires root privileges to run,
// so instead we examine the system logs for startup information containing
Expand Down