pkg.re/essentialkaos/ek.10@v12.41.0+incompatible/system/process/process_memory.go (about)

     1  //go:build linux
     2  // +build linux
     3  
     4  package process
     5  
     6  // ////////////////////////////////////////////////////////////////////////////////// //
     7  //                                                                                    //
     8  //                         Copyright (c) 2022 ESSENTIAL KAOS                          //
     9  //      Apache License, Version 2.0 <https://www.apache.org/licenses/LICENSE-2.0>     //
    10  //                                                                                    //
    11  // ////////////////////////////////////////////////////////////////////////////////// //
    12  
    13  import (
    14  	"bufio"
    15  	"errors"
    16  	"os"
    17  	"strconv"
    18  
    19  	"pkg.re/essentialkaos/ek.v12/strutil"
    20  )
    21  
    22  // ////////////////////////////////////////////////////////////////////////////////// //
    23  
    24  // MemInfo contains process memory usage stats
    25  type MemInfo struct {
    26  	VmPeak uint64 `json:"peak"` // Peak virtual memory size
    27  	VmSize uint64 `json:"size"` // Virtual memory size
    28  	VmLck  uint64 `json:"lck"`  // Locked memory size
    29  	VmPin  uint64 `json:"pin"`  // Pinned memory size (since Linux 3.2)
    30  	VmHWM  uint64 `json:"hwm"`  // Peak resident set size ("high water mark")
    31  	VmRSS  uint64 `json:"rss"`  // Resident set size
    32  	VmData uint64 `json:"data"` // Size of data
    33  	VmStk  uint64 `json:"stk"`  // Size of stack
    34  	VmExe  uint64 `json:"exe"`  // Size of text segments
    35  	VmLib  uint64 `json:"lib"`  // Shared library code size
    36  	VmPTE  uint64 `json:"pte"`  // Page table entries size (since Linux 2.6.10)
    37  	VmSwap uint64 `json:"swap"` // Swap size
    38  }
    39  
    40  // ////////////////////////////////////////////////////////////////////////////////// //
    41  
    42  // codebeat:disable[LOC,ABC]
    43  
    44  // GetMemInfo returns info about process memory usage
    45  func GetMemInfo(pid int) (*MemInfo, error) {
    46  	fd, err := os.OpenFile(procFS+"/"+strconv.Itoa(pid)+"/status", os.O_RDONLY, 0)
    47  
    48  	if err != nil {
    49  		return nil, err
    50  	}
    51  
    52  	defer fd.Close()
    53  
    54  	r := bufio.NewReader(fd)
    55  	s := bufio.NewScanner(r)
    56  
    57  	info := &MemInfo{}
    58  
    59  	for s.Scan() {
    60  		text := s.Text()
    61  
    62  		if len(text) < 2 || text[:2] != "Vm" {
    63  			continue
    64  		}
    65  
    66  		switch strutil.ReadField(text, 0, true) {
    67  		case "VmPeak:":
    68  			info.VmPeak, err = parseSize(strutil.ReadField(text, 1, true))
    69  		case "VmSize:":
    70  			info.VmSize, err = parseSize(strutil.ReadField(text, 1, true))
    71  		case "VmLck:":
    72  			info.VmLck, err = parseSize(strutil.ReadField(text, 1, true))
    73  		case "VmPin:":
    74  			info.VmPin, err = parseSize(strutil.ReadField(text, 1, true))
    75  		case "VmHWM:":
    76  			info.VmHWM, err = parseSize(strutil.ReadField(text, 1, true))
    77  		case "VmRSS:":
    78  			info.VmRSS, err = parseSize(strutil.ReadField(text, 1, true))
    79  		case "VmData:":
    80  			info.VmData, err = parseSize(strutil.ReadField(text, 1, true))
    81  		case "VmStk:":
    82  			info.VmStk, err = parseSize(strutil.ReadField(text, 1, true))
    83  		case "VmExe:":
    84  			info.VmExe, err = parseSize(strutil.ReadField(text, 1, true))
    85  		case "VmLib:":
    86  			info.VmLib, err = parseSize(strutil.ReadField(text, 1, true))
    87  		case "VmPTE:":
    88  			info.VmPTE, err = parseSize(strutil.ReadField(text, 1, true))
    89  		case "VmSwap:":
    90  			info.VmSwap, err = parseSize(strutil.ReadField(text, 1, true))
    91  		}
    92  
    93  		if err != nil {
    94  			return nil, errors.New("Can't parse status file for given process")
    95  		}
    96  	}
    97  
    98  	if info.VmPeak+info.VmSize == 0 {
    99  		return nil, errors.New("Can't parse status file for given process")
   100  	}
   101  
   102  	return info, nil
   103  }
   104  
   105  // codebeat:enable[LOC,ABC]
   106  
   107  // ////////////////////////////////////////////////////////////////////////////////// //
   108  
   109  // parseSize parse size in kB
   110  func parseSize(v string) (uint64, error) {
   111  	size, err := strconv.ParseUint(v, 10, 64)
   112  
   113  	if err != nil {
   114  		return 0, err
   115  	}
   116  
   117  	return size * 1024, nil
   118  }