func()

in internal/ps/ps_linux.go [168:229]


func (p linuxClient) Memory(pid int) (int, error) {
	baseProcDir := filepath.Join(p.procDir, strconv.Itoa(pid))

	var stats []byte
	var readErrors error
	var readFile bool
	var openFile string

	// Read the smaps file. This is where the memory usage of the process is
	// stored.
	for _, fpath := range []string{"smaps", "smaps_rollup"} {
		var err error
		openFile = filepath.Join(baseProcDir, fpath)
		stats, err = os.ReadFile(openFile) // NOLINT
		if err != nil {
			// If the error is not "not exist" means we failed to read it, in that
			// case we don't fallback to other files.
			if !os.IsNotExist(err) {
				return 0, fmt.Errorf("error reading %s file: %w", fpath, err)
			}

			// If the error is "not exist", we fallback to other files and keep track
			// of the errors.
			if readErrors == nil {
				readErrors = err
			} else {
				readErrors = fmt.Errorf("%w; %w", readErrors, err)
			}
		}

		readFile = true
		if err == nil {
			break
		}
	}

	if !readFile && readErrors != nil {
		return 0, fmt.Errorf("error reading smaps/smaps_rollup file: %w", readErrors)
	}

	statsLines := strings.Split(string(stats), "\n")
	foundRss := false
	var memUsage int

	// Now find the memory line. This line is the RSS line.
	for _, line := range statsLines {
		if strings.HasPrefix(line, "Rss") {
			foundRss = true
			partial, err := strconv.Atoi(strings.Fields(line)[1])
			if err != nil {
				return 0, fmt.Errorf("error parsing RSS line: %w", err)
			}
			memUsage += partial
		}
	}

	if !foundRss {
		return 0, fmt.Errorf("no RSS line found in %s file", openFile)
	}

	return memUsage, nil
}