Copyright 2020 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
Functions to collect memory information from a variety of places.

package worker

import (
	
	
	
	
	
	
	
	

	
)
systemMemStats holds values from the /proc/meminfo file, which describes the total system memory. All values are in bytes.
getSystemMemStats reads the /proc/meminfo file to get information about the machine.
func () (systemMemStats, error) {
	,  := os.Open("/proc/meminfo")
	if  != nil {
		return systemMemStats{}, 
	}
	defer .Close()
Read the number, convert kibibytes to bytes, and set p.
	 := func( *uint64,  []string) {
		if len() != 3 || [2] != "kB" {
			 = fmt.Errorf("got %+v, want 3 words, third is 'kB'", )
			return
		}
		var  uint64
		,  = strconv.ParseUint([1], 10, 64)
		if  == nil {
			* =  * 1024
		}
	}

	 := bufio.NewScanner()
	var  systemMemStats
	for .Scan() {
		 := strings.Fields(.Text())
		switch [0] {
		case "MemTotal:":
			(&.Total, )
		case "MemFree:":
			(&.Free, )
		case "MemAvailable:":
			(&.Available, )
		case "Buffers:":
			(&.Buffers, )
		case "Cached:":
			(&.Cached, )
		}
	}
	if  == nil {
		 = .Err()
	}
	if  != nil {
		return systemMemStats{}, 
	}
	.Used = .Total - .Free - .Buffers - .Cached // see `man free`
	return , nil
}
processMemStats holds values that describe the current process's memory. All values are in bytes.
type processMemStats struct {
	VSize uint64 // virtual memory size
	RSS   uint64 // resident set size (physical memory in use)
}

func () (processMemStats, error) {
	,  := os.Open("/proc/self/stat")
	if  != nil {
		return processMemStats{}, 
	}
Values from `man proc`.
	var (
		          int
		          string
		          byte
		,  uint64
	)
	_,  = fmt.Fscanf(, "%d %s %c %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d",
		&, &, &, &, &, &, &, &, &, &, &, &, &, &, &, &, &, &, &, &, &, &, &, &)
	if  != nil {
		return processMemStats{}, 
	}
	const  = 4 * 1024 // Linux page size, from `getconf PAGESIZE`
	return processMemStats{
		VSize: ,
		RSS:    * ,
	}, nil
}
Read memory information for the current cgroup. (A cgroup is the sandbox in which a docker container runs.) All values are in bytes. Returns nil on any error.
func () map[string]uint64 {
	,  := getCgroupMemStatsErr()
	if  != nil {
		log.Warningf(context.Background(), "getCgroupMemStats: %v", )
		return nil
k8s's definition of container memory, as shown by `kubectl top pods`. See https://www.magalix.com/blog/memory_working_set-vs-memory_rss.
	 := ["usage"]
	 := ["total_inactive_file"]
	if  >  {
		 = 0
	} else {
		 -= 
	}
True RSS. See note on https://lwn.net/Articles/432224.
	["trueRSS"] = ["rss"] + ["mapped_file"]
	return 
}

func () (map[string]uint64, error) {
	const  = "/sys/fs/cgroup/memory"

	 := func( string) (uint64, error) {
		,  := ioutil.ReadFile(filepath.Join(, ))
		if  != nil {
			return 0, 
		}
		,  := strconv.ParseUint(strings.TrimSpace(string()), 10, 64)
		if  != nil {
			return 0, 
		}
		return , nil
	}

	 := map[string]uint64{}
	var  error
	["limit"],  = ("memory.limit_in_bytes")
	if  != nil {
		return nil, 
	}
	["usage"],  = ("memory.usage_in_bytes")
	if  != nil {
		return nil, 
	}
	,  := os.Open(filepath.Join(, "memory.stat"))
	if  != nil {
		return nil, 
	}
	defer .Close()
	 := bufio.NewScanner()
	for .Scan() {
		 := strings.Fields(.Text())
		if len() != 2 {
			return nil, fmt.Errorf("memory.stat: %q: not two fields", .Text())
		}
		,  := strconv.ParseUint([1], 10, 64)
		if  != nil {
			return nil, 
		}
		[[0]] = 
	}
	if  := .Err();  != nil {
		return nil, 
	}
	return , nil