Read the proc status file when PID is given for metrics purpose.
To measure the MaxRSS memory correctly, read the proc status file
under /proc/<pid>/status and extract the MaxRSS value from it. The
implementation is only available for Linux based distributions.
Bug: b/169453825
Test: go test
Change-Id: I32e3068fee7447f9ef5dfb5a8d8dcb6934e0af23
diff --git a/ui/metrics/proc/status.go b/ui/metrics/proc/status.go
new file mode 100644
index 0000000..f8b734c
--- /dev/null
+++ b/ui/metrics/proc/status.go
@@ -0,0 +1,128 @@
+// package proc contains functionality to read proc status files.
+package proc
+
+import (
+ "strconv"
+ "strings"
+)
+
+// ProcStatus holds information regarding the memory usage of
+// an executing process. The memory sizes in each of the field
+// is in bytes.
+type ProcStatus struct {
+ // Process PID.
+ pid int
+
+ // Peak virtual memory size.
+ VmPeak uint64
+
+ // Virtual memory size.
+ VmSize uint64
+
+ // Locked Memory size.
+ VmLck uint64
+
+ // Pinned memory size.
+ VmPin uint64
+
+ // Peak resident set size.
+ VmHWM uint64
+
+ // Resident set size (sum of RssAnon, RssFile and RssShmem).
+ VmRss uint64
+
+ // Size of resident anonymous memory.
+ RssAnon uint64
+
+ // Size of resident shared memory.
+ RssShmem uint64
+
+ // Size of data segments.
+ VmData uint64
+
+ // Size of stack segments.
+ VmStk uint64
+
+ //Size of text segments.
+ VmExe uint64
+
+ //Shared library code size.
+ VmLib uint64
+
+ // Page table entries size.
+ VmPTE uint64
+
+ // Size of second-level page tables.
+ VmPMD uint64
+
+ // Swapped-out virtual memory size by anonymous private.
+ VmSwap uint64
+
+ // Size of hugetlb memory page size.
+ HugetlbPages uint64
+}
+
+// fillProcStatus takes the key and value, converts the value
+// to the proper size unit and is stored in the ProcStatus.
+func fillProcStatus(s *ProcStatus, key, value string) {
+ v := strToUint64(value)
+ switch key {
+ case "VmPeak":
+ s.VmPeak = v
+ case "VmSize":
+ s.VmSize = v
+ case "VmLck":
+ s.VmLck = v
+ case "VmPin":
+ s.VmPin = v
+ case "VmHWM":
+ s.VmHWM = v
+ case "VmRSS":
+ s.VmRss = v
+ case "RssAnon":
+ s.RssAnon = v
+ case "RssShmem":
+ s.RssShmem = v
+ case "VmData":
+ s.VmData = v
+ case "VmStk":
+ s.VmStk = v
+ case "VmExe":
+ s.VmExe = v
+ case "VmLib":
+ s.VmLib = v
+ case "VmPTE":
+ s.VmPTE = v
+ case "VmPMD":
+ s.VmPMD = v
+ case "VmSwap":
+ s.VmSwap = v
+ case "HugetlbPages":
+ s.HugetlbPages = v
+ }
+}
+
+// strToUint64 takes the string and converts to unsigned 64-bit integer.
+// If the string contains a memory unit such as kB and is converted to
+// bytes.
+func strToUint64(v string) uint64 {
+ // v could be "1024 kB" so scan for the empty space and
+ // split between the value and the unit.
+ var separatorIndex int
+ if separatorIndex = strings.IndexAny(v, " "); separatorIndex < 0 {
+ separatorIndex = len(v)
+ }
+ value, err := strconv.ParseUint(v[:separatorIndex], 10, 64)
+ if err != nil {
+ return 0
+ }
+
+ var scale uint64 = 1
+ switch strings.TrimSpace(v[separatorIndex:]) {
+ case "kB", "KB":
+ scale = 1024
+ case "mB", "MB":
+ scale = 1024 * 1024
+ }
+ return value * scale
+}