From 74bad908a52fd2713c72c9f42f2b053369ec53d2 Mon Sep 17 00:00:00 2001
From: zhaolongquan1 <zhaolongquan1@huawei.com>
Date: Wed, 12 Jun 2019 12:37:08 -0400
Subject: [PATCH] docker:  add hugetlb limit option to docker

reason:add hugetlb limit option to docker

Change-Id: I418c65fd050d3740da6997589df45b08355fed80
Signed-off-by: zhaolongquan1 <zhaolongquan1@huawei.com>
---
 components/cli/cli/command/container/opts.go       |   5 +
 components/cli/cli/command/system/info.go          |   1 +
 components/cli/contrib/completion/bash/docker      |   1 +
 components/cli/opts/hugetlb.go                     | 109 +++++++++++++
 .../docker/api/types/container/host_config.go      |   8 +
 .../github.com/docker/docker/api/types/types.go    |   1 +
 .../engine/api/types/container/host_config.go      |   8 +
 components/engine/api/types/types.go               |   1 +
 components/engine/daemon/daemon_unix.go            |  66 ++++++++
 components/engine/daemon/info.go                   |   1 +
 components/engine/daemon/oci_linux.go              |   2 +
 components/engine/pkg/sysinfo/sysinfo.go           |   6 +
 components/engine/pkg/sysinfo/sysinfo_linux.go     |  30 ++++
 components/engine/pkg/sysinfo/utils_linux.go       | 169 +++++++++++++++++++++
 14 files changed, 408 insertions(+)
 create mode 100644 components/cli/opts/hugetlb.go
 create mode 100644 components/engine/pkg/sysinfo/utils_linux.go

diff --git a/components/cli/cli/command/container/opts.go b/components/cli/cli/command/container/opts.go
index 00da8fc..d729a3c 100644
--- a/components/cli/cli/command/container/opts.go
+++ b/components/cli/cli/command/container/opts.go
@@ -66,6 +66,7 @@ type containerOptions struct {
 	storageOpt         opts.ListOpts
 	labelsFile         opts.ListOpts
 	loggingOpts        opts.ListOpts
+	hugetlb		   opts.HugetlbOpt
 	privileged         bool
 	pidMode            string
 	utsMode            string
@@ -166,6 +167,7 @@ func addFlags(flags *pflag.FlagSet) *containerOptions {
 		ulimits:           opts.NewUlimitOpt(nil),
 		volumes:           opts.NewListOpts(nil),
 		volumesFrom:       opts.NewListOpts(nil),
+		hugetlb:           opts.NewHugetlbOpt(opts.ValidateHugetlb),
 	}
 
 	// General purpose flags
@@ -295,6 +297,8 @@ func addFlags(flags *pflag.FlagSet) *containerOptions {
 
 	flags.BoolVar(&copts.init, "init", false, "Run an init inside the container that forwards signals and reaps processes")
 	flags.SetAnnotation("init", "version", []string{"1.25"})
+
+	flags.Var(&copts.hugetlb, "hugetlb-limit", "Huge page limit (format: [size:]<limit>, e.g. --hugetlb-limit 2MB:32MB)")
 	return copts
 }
 
@@ -538,6 +542,7 @@ func parse(flags *pflag.FlagSet, copts *containerOptions) (*containerConfig, err
 
 	resources := container.Resources{
 		CgroupParent:         copts.cgroupParent,
+		Hugetlbs:             copts.hugetlb.GetAll(),
 		Memory:               copts.memory.Value(),
 		MemoryReservation:    copts.memoryReservation.Value(),
 		MemorySwap:           copts.memorySwap.Value(),
diff --git a/components/cli/cli/command/system/info.go b/components/cli/cli/command/system/info.go
index 17ccc14..7399d10 100644
--- a/components/cli/cli/command/system/info.go
+++ b/components/cli/cli/command/system/info.go
@@ -74,6 +74,7 @@ func prettyPrintInfo(dockerCli command.Cli, info types.Info) error {
 	}
 	fprintlnNonEmpty(dockerCli.Out(), "Logging Driver:", info.LoggingDriver)
 	fprintlnNonEmpty(dockerCli.Out(), "Cgroup Driver:", info.CgroupDriver)
+	fprintlnNonEmpty(dockerCli.Out(), "Hugetlb Pagesize:", info.HugetlbPageSize)
 
 	fmt.Fprintln(dockerCli.Out(), "Plugins:")
 	fmt.Fprintln(dockerCli.Out(), " Volume:", strings.Join(info.Plugins.Volume, " "))
diff --git a/components/cli/contrib/completion/bash/docker b/components/cli/contrib/completion/bash/docker
index 64f7fe0..330804d 100644
--- a/components/cli/contrib/completion/bash/docker
+++ b/components/cli/contrib/completion/bash/docker
@@ -1792,6 +1792,7 @@ _docker_container_run_and_create() {
 		--files-limit
 		--group-add
 		--hook-spec
+		--hugetlb-limit
 		--health-cmd
 		--health-interval
 		--health-retries
diff --git a/components/cli/opts/hugetlb.go b/components/cli/opts/hugetlb.go
new file mode 100644
index 0000000..48cfeff
--- /dev/null
+++ b/components/cli/opts/hugetlb.go
@@ -0,0 +1,109 @@
+package opts
+
+import (
+	"fmt"
+	"strings"
+
+	"github.com/docker/docker/api/types/container"
+	"github.com/docker/go-units"
+)
+
+// ValidatorHugetlbType defines a validator function that returns a validated struct and/or an error.
+type ValidatorHugetlbType func(val string) (container.Hugetlb, error)
+
+// ValidateHugetlb validates that the specified string has a valid hugetlb format.
+func ValidateHugetlb(htlb string) (container.Hugetlb, error) {
+	var size, limit string
+	var hugetlb container.Hugetlb
+
+	ss := strings.Split(htlb, ":")
+	if len(ss) == 1 {
+		size = ""
+		limit = ss[0]
+	} else if len(ss) == 2 {
+		if ss[0] == "" {
+			size = ""
+		} else {
+			size = formatHugepageSize(ss[0])
+		}
+		limit = ss[1]
+	} else {
+		return hugetlb, fmt.Errorf("Invalid arguments for hugetlb-limit, too many colons")
+	}
+
+	ilimit, err := units.RAMInBytes(limit)
+	if err != nil {
+		return hugetlb, fmt.Errorf("Invalid hugetlb limit:%s", limit)
+	}
+	ulimit := uint64(ilimit)
+	hugetlb = container.Hugetlb{
+		PageSize: size,
+		Limit:    ulimit,
+	}
+	return hugetlb, nil
+}
+
+// HugetlbOpt defines a map of Hugetlbs
+type HugetlbOpt struct {
+	values    []container.Hugetlb
+	validator ValidatorHugetlbType
+}
+
+// NewHugetlbOpt creates a new HugetlbOpt
+func NewHugetlbOpt(validator ValidatorHugetlbType) HugetlbOpt {
+	values := []container.Hugetlb{}
+	return HugetlbOpt{
+		values:    values,
+		validator: validator,
+	}
+}
+
+// Set validates a Hugetlb and sets its name as a key in HugetlbOpt
+func (opt *HugetlbOpt) Set(val string) error {
+	var value container.Hugetlb
+	if opt.validator != nil {
+		v, err := opt.validator(val)
+		if err != nil {
+			return err
+		}
+		value = v
+	}
+	(opt.values) = append((opt.values), value)
+	return nil
+}
+
+// String returns HugetlbOpt values as a string.
+func (opt *HugetlbOpt) String() string {
+	var out []string
+	for _, v := range opt.values {
+		out = append(out, fmt.Sprintf("%v", v))
+	}
+
+	return fmt.Sprintf("%v", out)
+}
+
+// GetList returns a slice of pointers to Hugetlbs.
+func (opt *HugetlbOpt) GetAll() []container.Hugetlb {
+	var hugetlbs []container.Hugetlb
+	for _, v := range opt.values {
+		hugetlbs = append(hugetlbs, v)
+	}
+
+	return hugetlbs
+}
+
+// Type returns the option type
+func (opt *HugetlbOpt) Type() string {
+	return "hugetlb"
+}
+
+func formatHugepageSize(s string) string {
+	// make sure size get all 'b/k/m/g' replaced with "B/K/M/G"
+	s = strings.ToUpper(s)
+	// make sure size hase suffix "B"
+	if !strings.HasSuffix(s, "B") {
+		s = s + "B"
+	}
+
+	return s
+}
diff --git a/components/cli/vendor/github.com/docker/docker/api/types/container/host_config.go b/components/cli/vendor/github.com/docker/docker/api/types/container/host_config.go
index 701cae5..6989b2b 100644
--- a/components/cli/vendor/github.com/docker/docker/api/types/container/host_config.go
+++ b/components/cli/vendor/github.com/docker/docker/api/types/container/host_config.go
@@ -342,6 +342,14 @@ type Resources struct {
 	CPUPercent         int64  `json:"CpuPercent"` // CPU percent
 	IOMaximumIOps      uint64 // Maximum IOps for the container system drive
 	IOMaximumBandwidth uint64 // Maximum IO in bytes per second for the container system drive
+
+	// Hugetlb setting
+	Hugetlbs []Hugetlb
+}
+
+type Hugetlb struct {
+	PageSize string
+	Limit    uint64
 }
 
 // UpdateConfig holds the mutable attributes of a Container.
diff --git a/components/cli/vendor/github.com/docker/docker/api/types/types.go b/components/cli/vendor/github.com/docker/docker/api/types/types.go
index 56f556c..cfcfd4a 100644
--- a/components/cli/vendor/github.com/docker/docker/api/types/types.go
+++ b/components/cli/vendor/github.com/docker/docker/api/types/types.go
@@ -173,6 +173,7 @@ type Info struct {
 	SystemTime         string
 	LoggingDriver      string
 	CgroupDriver       string
+	HugetlbPageSize    string
 	NEventsListener    int
 	KernelVersion      string
 	OperatingSystem    string
diff --git a/components/engine/api/types/container/host_config.go b/components/engine/api/types/container/host_config.go
index 701cae5..6989b2b 100644
--- a/components/engine/api/types/container/host_config.go
+++ b/components/engine/api/types/container/host_config.go
@@ -342,6 +342,14 @@ type Resources struct {
 	CPUPercent         int64  `json:"CpuPercent"` // CPU percent
 	IOMaximumIOps      uint64 // Maximum IOps for the container system drive
 	IOMaximumBandwidth uint64 // Maximum IO in bytes per second for the container system drive
+
+	// Hugetlb setting
+	Hugetlbs []Hugetlb
+}
+
+type Hugetlb struct {
+	PageSize string
+	Limit    uint64
 }
 
 // UpdateConfig holds the mutable attributes of a Container.
diff --git a/components/engine/api/types/types.go b/components/engine/api/types/types.go
index 78e97da..55955f2 100644
--- a/components/engine/api/types/types.go
+++ b/components/engine/api/types/types.go
@@ -174,6 +174,7 @@ type Info struct {
 	SystemTime         string
 	LoggingDriver      string
 	CgroupDriver       string
+	HugetlbPageSize    string
 	NEventsListener    int
 	KernelVersion      string
 	OperatingSystem    string
diff --git a/components/engine/daemon/daemon_unix.go b/components/engine/daemon/daemon_unix.go
index 9abc9a3..5a59b32 100644
--- a/components/engine/daemon/daemon_unix.go
+++ b/components/engine/daemon/daemon_unix.go
@@ -187,6 +187,21 @@ func getBlkioWeightDevices(config containertypes.Resources) ([]specs.LinuxWeight
 	return blkioWeightDevices, nil
 }
 
+func getHugetlbResources(config containertypes.Resources) []specs.LinuxHugepageLimit {
+	var hpLimits []specs.LinuxHugepageLimit
+
+	for _, hpl := range config.Hugetlbs {
+		size := hpl.PageSize
+		limit := uint64(hpl.Limit)
+		hpLimits = append(hpLimits, specs.LinuxHugepageLimit{
+			Pagesize: size,
+			Limit:    limit,
+		})
+	}
+
+	return hpLimits
+}
+
 func (daemon *Daemon) parseSecurityOpt(container *container.Container, hostConfig *containertypes.HostConfig) error {
 	container.NoNewPrivileges = daemon.configStore.NoNewPrivileges
 	return parseSecurityOpt(container, hostConfig)
@@ -553,9 +568,51 @@ func (daemon *Daemon) verifyContainerResources(hostConfig *containertypes.HostCo
 		resources.BlkioDeviceWriteIOps = []*pblkiodev.ThrottleDevice{}
 	}
 
+	// hugetlb size checks
+	if len(resources.Hugetlbs) > 0 && !sysInfo.HugetlbLimit {
+		warnings = append(warnings, "Your kernel does not support hugetlb limit.")
+		logrus.Warnf("Your kernel does not support hugetlb limit. --hugetlb-limit discarded.")
+		resources.Hugetlbs = []containertypes.Hugetlb{}
+	}
+	newHugetlbs, warning, err := validateHugetlbs(resources.Hugetlbs)
+	warnings = append(warnings, warning...)
+	if err != nil {
+		return warnings, err
+	}
+	resources.Hugetlbs = newHugetlbs
+
 	return warnings, nil
 }
 
+func validateHugetlbs(hgtlbs []containertypes.Hugetlb) ([]containertypes.Hugetlb, []string, error) {
+	warnings := []string{}
+	htbMap := make(map[string]uint64)
+
+	for _, hpl := range hgtlbs {
+		size, warning, err := sysinfo.ValidateHugetlb(hpl.PageSize, hpl.Limit)
+		warnings = append(warnings, warning...)
+		if err != nil {
+			return nil, warnings, err
+		}
+
+		if l, ok := htbMap[size]; ok {
+			warnings = append(warnings, fmt.Sprintf("hugetlb-limit setting of %s is repeated, former setting %d will be replaced with %d", size, l, hpl.Limit))
+		}
+		htbMap[size] = hpl.Limit
+	}
+
+	newHgtlbs := []containertypes.Hugetlb{}
+	for k, v := range htbMap {
+		hugetlb := containertypes.Hugetlb{
+			PageSize: k,
+			Limit:    v,
+		}
+		newHgtlbs = append(newHgtlbs, hugetlb)
+	}
+
+	return newHgtlbs, warnings, nil
+}
+
 func (daemon *Daemon) getCgroupDriver() string {
 	cgroupDriver := cgroupFsDriver
 
@@ -565,6 +622,15 @@ func (daemon *Daemon) getCgroupDriver() string {
 	return cgroupDriver
 }
 
+func (daemon *Daemon) getHugetlbPageSize() string {
+	size, err := sysinfo.GetHugepageSize()
+	if err != nil {
+		logrus.Errorf("Failed to get default hugetlb pagesize: %v", err)
+		return ""
+	}
+	return size
+}
+
 // getCD gets the raw value of the native.cgroupdriver option, if set.
 func getCD(config *config.Config) string {
 	for _, option := range config.ExecOptions {
diff --git a/components/engine/daemon/info.go b/components/engine/daemon/info.go
index 4acad11..2ecff72 100644
--- a/components/engine/daemon/info.go
+++ b/components/engine/daemon/info.go
@@ -47,6 +47,7 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
 		SystemTime:         time.Now().Format(time.RFC3339Nano),
 		LoggingDriver:      daemon.defaultLogConfig.Type,
 		CgroupDriver:       daemon.getCgroupDriver(),
+		HugetlbPageSize:	daemon.getHugetlbPageSize(),
 		NEventsListener:    daemon.EventsService.SubscribersCount(),
 		KernelVersion:      kernelVersion(),
 		OperatingSystem:    operatingSystem(),
diff --git a/components/engine/daemon/oci_linux.go b/components/engine/daemon/oci_linux.go
index f5270bd..6d3bc16 100644
--- a/components/engine/daemon/oci_linux.go
+++ b/components/engine/daemon/oci_linux.go
@@ -49,6 +49,7 @@ func setResources(s *specs.Spec, r containertypes.Resources) error {
 		return err
 	}
 
+	hpRes := getHugetlbResources(r)
 	memoryRes := getMemoryResources(r)
 	cpuRes, err := getCPUResources(r)
 	if err != nil {
@@ -73,6 +74,7 @@ func setResources(s *specs.Spec, r containertypes.Resources) error {
 		Files: &specs.Files{
 			Limit: &r.FilesLimit,
 		},
+		HugepageLimits: hpRes,
 	}
 
 	if s.Linux.Resources != nil && len(s.Linux.Resources.Devices) > 0 {
diff --git a/components/engine/pkg/sysinfo/sysinfo.go b/components/engine/pkg/sysinfo/sysinfo.go
index 7ea1be5..139ad61 100644
--- a/components/engine/pkg/sysinfo/sysinfo.go
+++ b/components/engine/pkg/sysinfo/sysinfo.go
@@ -17,6 +17,7 @@ type SysInfo struct {
 	Seccomp bool
 
 	cgroupMemInfo
+	cgroupHugetlbInfo
 	cgroupCPUInfo
 	cgroupBlkioInfo
 	cgroupCpusetInfo
@@ -56,6 +57,11 @@ type cgroupMemInfo struct {
 	KernelMemory bool
 }
 
+type cgroupHugetlbInfo struct {
+	// Whether hugetlb limit is supported or not
+	HugetlbLimit bool
+}
+
 type cgroupCPUInfo struct {
 	// Whether CPU shares is supported or not
 	CPUShares bool
diff --git a/components/engine/pkg/sysinfo/sysinfo_linux.go b/components/engine/pkg/sysinfo/sysinfo_linux.go
index c0bf280..b4473ee 100644
--- a/components/engine/pkg/sysinfo/sysinfo_linux.go
+++ b/components/engine/pkg/sysinfo/sysinfo_linux.go
@@ -36,6 +36,7 @@ func New(quiet bool) *SysInfo {
 		logrus.Warnf("Failed to parse cgroup information: %v", err)
 	} else {
 		sysInfo.cgroupMemInfo = checkCgroupMem(cgMounts, quiet)
+		sysInfo.cgroupHugetlbInfo = checkCgroupHugetlb(cgMounts, quiet)
 		sysInfo.cgroupCPUInfo = checkCgroupCPU(cgMounts, quiet)
 		sysInfo.cgroupBlkioInfo = checkCgroupBlkioInfo(cgMounts, quiet)
 		sysInfo.cgroupCpusetInfo = checkCgroupCpusetInfo(cgMounts, quiet)
@@ -66,6 +67,35 @@ func New(quiet bool) *SysInfo {
 	return sysInfo
 }
 
+// checkCgroupHugetlb reads the hugetlb information from the hugetlb cgroup mount point.
+func checkCgroupHugetlb(cgMounts map[string]string, quiet bool) cgroupHugetlbInfo {
+	var (
+		dSize string
+		err   error
+		c     cgroupHugetlbInfo
+	)
+	mountPoint, ok := cgMounts["hugetlb"]
+	if !ok {
+		if !quiet {
+			logrus.Warnf("Your kernel does not support cgroup hugetlb limit")
+		}
+		return c
+	}
+	dSize, err = GetDefaultHugepageSize()
+	if err != nil {
+		logrus.Warnf("Your kernel does not support cgroup hugetlb limit")
+		return c
+	}
+
+	hugetlbLimit := cgroupEnabled(mountPoint, fmt.Sprintf("hugetlb.%s.limit_in_bytes", dSize))
+	if !quiet && !hugetlbLimit {
+		logrus.Warn("Your kernel does not support hugetlb limit.")
+	}
+
+	c.HugetlbLimit = hugetlbLimit
+	return c
+}
+
 // checkCgroupMem reads the memory information from the memory cgroup mount point.
 func checkCgroupMem(cgMounts map[string]string, quiet bool) cgroupMemInfo {
 	mountPoint, ok := cgMounts["memory"]
diff --git a/components/engine/pkg/sysinfo/utils_linux.go b/components/engine/pkg/sysinfo/utils_linux.go
new file mode 100644
index 0000000..905d0b7
--- /dev/null
+++ b/components/engine/pkg/sysinfo/utils_linux.go
@@ -0,0 +1,169 @@
+// +build linux
+
+package sysinfo
+
+import (
+	"bufio"
+	"fmt"
+	"os"
+	"strings"
+
+	"github.com/docker/go-units"
+	"github.com/opencontainers/runc/libcontainer/cgroups"
+)
+
+// GetHugepageSize returns system supported hugepage sizes
+func GetHugepageSize() (string, error) {
+	hps, err := getHugepageSizes()
+	if err != nil {
+		return "", err
+	}
+
+	dhp, err := GetDefaultHugepageSize()
+	if err != nil {
+		return "", err
+	}
+
+	hpsString := strings.Join(hps, ", ")
+	if len(hps) > 1 {
+		hpsString += fmt.Sprintf(" (default is %s)", dhp)
+	}
+	return hpsString, nil
+}
+
+// ValidateHugetlb check whether hugetlb pagesize and limit legal
+func ValidateHugetlb(pageSize string, limit uint64) (string, []string, error) {
+	var err error
+	warnings := []string{}
+	if pageSize != "" {
+		sizeInt, _ := units.RAMInBytes(pageSize)
+		pageSize = humanSize(sizeInt)
+		if err := isHugepageSizeValid(pageSize); err != nil {
+			return "", warnings, err
+		}
+	} else {
+		pageSize, err = GetDefaultHugepageSize()
+		if err != nil {
+			return "", warnings, fmt.Errorf("Failed to get system hugepage size")
+		}
+	}
+
+	warn, err := isHugeLimitValid(pageSize, limit)
+	warnings = append(warnings, warn...)
+	if err != nil {
+		return "", warnings, err
+	}
+
+	return pageSize, warnings, nil
+}
+
+// isHugeLimitValid check whether input hugetlb limit legal
+// it will check whether the limit size is times of size
+func isHugeLimitValid(size string, limit uint64) ([]string, error) {
+	warnings := []string{}
+	sizeInt, err := units.RAMInBytes(size)
+	if err != nil || sizeInt < 0 {
+		return warnings, fmt.Errorf("Invalid hugepage size:%s -- %s", size, err)
+	}
+	sizeUint := uint64(sizeInt)
+
+	if limit%sizeUint != 0 {
+		warnings = append(warnings, "HugeTlb limit should be times of hugepage size. "+
+			"cgroup will down round to the nearest multiple")
+	}
+
+	return warnings, nil
+}
+
+// isHugepageSizeValid check whether input size legal
+// it will compare size with all system supported hugepage size
+func isHugepageSizeValid(size string) error {
+	hps, err := getHugepageSizes()
+	if err != nil {
+		return err
+	}
+
+	for _, hp := range hps {
+		if size == hp {
+			return nil
+		}
+	}
+	return fmt.Errorf("Invalid hugepage size:%s, shoud be one of %v", size, hps)
+}
+
+func humanSize(i int64) string {
+	// hugetlb may not surpass GB
+	uf := []string{"B", "KB", "MB", "GB"}
+	ui := 0
+	for {
+		if i < 1024 || ui >= 3 {
+			break
+		}
+		i = int64(i / 1024)
+		ui = ui + 1
+	}
+
+	return fmt.Sprintf("%d%s", i, uf[ui])
+}
+
+func getHugepageSizes() ([]string, error) {
+	var hps []string
+
+	hgtlbMp, err := cgroups.FindCgroupMountpoint("hugetlb")
+	if err != nil {
+		return nil, fmt.Errorf("Hugetlb cgroup not supported")
+	}
+
+	f, err := os.Open(hgtlbMp)
+	if err != nil {
+		return nil, fmt.Errorf("Failed to open hugetlb cgroup directory")
+	}
+	defer f.Close()
+	// -1 here means to read all the fileInfo from the directory, could be any negative number
+	fi, err := f.Readdir(-1)
+	if err != nil {
+		return nil, fmt.Errorf("Failed to read hugetlb cgroup directory")
+	}
+
+	for _, finfo := range fi {
+		if strings.Contains(finfo.Name(), "limit_in_bytes") {
+			sres := strings.SplitN(finfo.Name(), ".", 3)
+			if len(sres) != 3 {
+				continue
+			}
+			hps = append(hps, sres[1])
+		}
+	}
+
+	if len(hps) == 0 {
+		return nil, fmt.Errorf("Hugetlb pagesize not found in cgroup")
+	}
+
+	return hps, nil
+}
+
+// GetDefaultHugepageSize returns system default hugepage size
+func GetDefaultHugepageSize() (string, error) {
+	f, err := os.Open("/proc/meminfo")
+	if err != nil {
+		return "", fmt.Errorf("Failed to get hugepage size, cannot open /proc/meminfo")
+	}
+	defer f.Close()
+
+	s := bufio.NewScanner(f)
+	for s.Scan() {
+		if strings.Contains(s.Text(), "Hugepagesize") {
+			sres := strings.SplitN(s.Text(), ":", 2)
+			if len(sres) != 2 {
+				return "", fmt.Errorf("Failed to get hugepage size, weird /proc/meminfo format")
+			}
+
+			// return strings.TrimSpace(sres[1]), nil
+			size := strings.Replace(sres[1], " ", "", -1)
+			// transform 2048k to 2M
+			sizeInt, _ := units.RAMInBytes(size)
+			return humanSize(sizeInt), nil
+		}
+	}
+	return "", fmt.Errorf("Failed to get hugepage size")
+}
-- 
1.8.3.1

