From 8860ada0a6afd6adb2b26d5b0ab161bfe66c6019 Mon Sep 17 00:00:00 2001 From: Tom Clegg Date: Tue, 25 Oct 2022 14:00:38 -0400 Subject: [PATCH] 19563: Report process size in bytes, not pages. Arvados-DCO-1.1-Signed-off-by: Tom Clegg --- lib/crunchstat/crunchstat.go | 32 +++++++++++++++++++++++++++++-- lib/crunchstat/crunchstat_test.go | 10 +++++++++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/lib/crunchstat/crunchstat.go b/lib/crunchstat/crunchstat.go index 443d2202ce..3a473cab87 100644 --- a/lib/crunchstat/crunchstat.go +++ b/lib/crunchstat/crunchstat.go @@ -14,6 +14,7 @@ import ( "io" "io/ioutil" "os" + "regexp" "sort" "strconv" "strings" @@ -52,6 +53,7 @@ type Reporter struct { Printf(fmt string, args ...interface{}) } + kernelPageSize int64 reportedStatFile map[string]string lastNetSample map[string]ioSample lastDiskIOSample map[string]ioSample @@ -274,6 +276,32 @@ func (r *Reporter) doMemoryStats() { } r.Logger.Printf("mem%s\n", outstat.String()) + if r.kernelPageSize == 0 { + // assign "don't try again" value in case we give up + // and return without assigning the real value + r.kernelPageSize = -1 + buf, err := os.ReadFile("/proc/self/smaps") + if err != nil { + r.Logger.Printf("error reading /proc/self/smaps: %s", err) + return + } + m := regexp.MustCompile(`\nKernelPageSize:\s*(\d+) kB\n`).FindSubmatch(buf) + if len(m) != 2 { + r.Logger.Printf("error parsing /proc/self/smaps: KernelPageSize not found") + return + } + size, err := strconv.ParseInt(string(m[1]), 10, 64) + if err != nil { + r.Logger.Printf("error parsing /proc/self/smaps: KernelPageSize %q: %s", m[1], err) + return + } + r.kernelPageSize = size * 1024 + } else if r.kernelPageSize < 0 { + // already failed to determine page size, don't keep + // trying/logging + return + } + r.reportPIDsMu.Lock() defer r.reportPIDsMu.Unlock() procnames := make([]string, 0, len(r.reportPIDs)) @@ -303,11 +331,11 @@ func (r *Reporter) doMemoryStats() { // rss is the 24th field in .../stat, and fields[0] // here is the last char ')' of the 2nd field, so // rss is fields[22] - rss, err := strconv.Atoi(string(fields[22])) + rss, err := strconv.ParseInt(string(fields[22]), 10, 64) if err != nil { continue } - procmem += fmt.Sprintf(" %d %s", rss, procname) + procmem += fmt.Sprintf(" %d %s", rss*r.kernelPageSize, procname) } if procmem != "" { r.Logger.Printf("procmem%s\n", procmem) diff --git a/lib/crunchstat/crunchstat_test.go b/lib/crunchstat/crunchstat_test.go index 922aa369ba..5e8e93de6c 100644 --- a/lib/crunchstat/crunchstat_test.go +++ b/lib/crunchstat/crunchstat_test.go @@ -9,6 +9,7 @@ import ( "log" "os" "regexp" + "strconv" "testing" "time" @@ -69,7 +70,14 @@ func (s *suite) TestReportPIDs(c *C) { c.Error("timed out") break } - if regexp.MustCompile(`(?ms).*procmem \d+ init \d+ test_process.*`).MatchString(logbuf.String()) { + if m := regexp.MustCompile(`(?ms).*procmem \d+ init (\d+) test_process.*`).FindSubmatch(logbuf.Bytes()); len(m) > 0 { + size, err := strconv.ParseInt(string(m[1]), 10, 64) + c.Check(err, IsNil) + // Expect >1 MiB and <100 MiB -- otherwise we + // are probably misinterpreting /proc/N/stat + // or multiplying by the wrong page size. + c.Check(size > 1000000, Equals, true) + c.Check(size < 100000000, Equals, true) break } } -- 2.30.2