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 }