From 2bd33492f06a020578dd18208ea8756639bbb014 Mon Sep 17 00:00:00 2001 From: Pierre Fersing Date: Mon, 6 Apr 2020 10:35:48 +0200 Subject: [PATCH 1/3] Add proportional resident & swap memory size --- README.md | 9 + cmd/process-exporter/main.go | 16 +- go.mod | 2 +- go.sum | 4 +- proc/grouper.go | 2 + proc/grouper_test.go | 42 +- proc/read.go | 41 +- proc/tracker_test.go | 8 +- .../github.com/prometheus/procfs/cpuinfo.go | 203 ++++++++- .../prometheus/procfs/cpuinfo_amd64.go | 19 + .../prometheus/procfs/cpuinfo_arm64.go | 19 + .../prometheus/procfs/cpuinfo_ppc64.go | 19 + .../prometheus/procfs/cpuinfo_s390x.go | 19 + .../prometheus/procfs/fixtures.ttar | 421 ++++++++++++++++++ .../prometheus/procfs/proc_smaps.go | 165 +++++++ vendor/modules.txt | 2 +- 16 files changed, 942 insertions(+), 49 deletions(-) create mode 100644 vendor/github.com/prometheus/procfs/cpuinfo_amd64.go create mode 100644 vendor/github.com/prometheus/procfs/cpuinfo_arm64.go create mode 100644 vendor/github.com/prometheus/procfs/cpuinfo_ppc64.go create mode 100644 vendor/github.com/prometheus/procfs/cpuinfo_s390x.go create mode 100644 vendor/github.com/prometheus/procfs/proc_smaps.go diff --git a/README.md b/README.md index 11e3720..0942d03 100644 --- a/README.md +++ b/README.md @@ -263,6 +263,15 @@ Number of bytes of memory used. The extra label `memtype` can have three values *swapped*: Field VmSwap from /proc/[pid]/status, translated from KB to bytes. +If gathering smaps file is enabled, two additional values for `memtype` are added: + +*proportionalResident*: Sum of "Pss" fields from /proc/[pid]/smaps, whose doc says: + +> The "proportional set size" (PSS) of a process is the count of pages it has +> in memory, where each page is divided by the number of processes sharing it. + +*proportionalSwapped*: Sum of "SwapPss" fields from /proc/[pid]/smaps + ### open_filedesc gauge Number of file descriptors, based on counting how many entries are in the directory diff --git a/cmd/process-exporter/main.go b/cmd/process-exporter/main.go index c2d9cf5..0a8f343 100644 --- a/cmd/process-exporter/main.go +++ b/cmd/process-exporter/main.go @@ -293,6 +293,8 @@ func main() { "if a proc is tracked, track with it any children that aren't part of their own group") threads = flag.Bool("threads", true, "report on per-threadname metrics as well") + smaps = flag.Bool("gather-smaps", false, + "gather metrics from smaps file, which contains proportional resident memory size") man = flag.Bool("man", false, "print manual") configPath = flag.String("config.path", "", @@ -355,7 +357,7 @@ func main() { matchnamer = namemapper } - pc, err := NewProcessCollector(*procfsPath, *children, *threads, matchnamer, *recheck, *debug) + pc, err := NewProcessCollector(*procfsPath, *children, *threads, *smaps, matchnamer, *recheck, *debug) if err != nil { log.Fatalf("Error initializing: %v", err) } @@ -399,6 +401,7 @@ type ( scrapeChan chan scrapeRequest *proc.Grouper threads bool + smaps bool source proc.Source scrapeErrors int scrapeProcReadErrors int @@ -411,6 +414,7 @@ func NewProcessCollector( procfsPath string, children bool, threads bool, + smaps bool, n common.MatchNamer, recheck bool, debug bool, @@ -419,11 +423,14 @@ func NewProcessCollector( if err != nil { return nil, err } + + fs.GatherSMaps = smaps p := &NamedProcessCollector{ scrapeChan: make(chan scrapeRequest), Grouper: proc.NewGrouper(n, children, threads, recheck, debug), source: fs, threads: threads, + smaps: smaps, debug: debug, } @@ -540,6 +547,13 @@ func (p *NamedProcessCollector) scrape(ch chan<- prometheus.Metric) { prometheus.GaugeValue, float64(count), gname, wchan) } + if p.smaps { + ch <- prometheus.MustNewConstMetric(membytesDesc, + prometheus.GaugeValue, float64(gcounts.Memory.ProportionalBytes), gname, "proportionalResident") + ch <- prometheus.MustNewConstMetric(membytesDesc, + prometheus.GaugeValue, float64(gcounts.Memory.ProportionalSwapBytes), gname, "proportionalSwapped") + } + if p.threads { for _, thr := range gcounts.Threads { ch <- prometheus.MustNewConstMetric(threadCountDesc, diff --git a/go.mod b/go.mod index e254fba..d813180 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,7 @@ require ( github.com/prometheus/client_golang v0.8.0 github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 // indirect github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e // indirect - github.com/prometheus/procfs v0.0.12-0.20200430211241-ea64cd222793 + github.com/prometheus/procfs v0.0.12-0.20200505152635-9654394ca94a gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 gopkg.in/yaml.v2 v2.2.1 ) diff --git a/go.sum b/go.sum index a614e1e..a0decb8 100644 --- a/go.sum +++ b/go.sum @@ -21,8 +21,8 @@ github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910 h1:idejC8f github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e h1:n/3MEhJQjQxrOUCzh1Y3Re6aJUUWRp2M9+Oc3eVn/54= github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= -github.com/prometheus/procfs v0.0.12-0.20200430211241-ea64cd222793 h1:eaK6XvR/+8o6UtStUEOJNg0WOO0WfgnAbhnuokPfnrY= -github.com/prometheus/procfs v0.0.12-0.20200430211241-ea64cd222793/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= +github.com/prometheus/procfs v0.0.12-0.20200505152635-9654394ca94a h1:zTuAihdFbve/GW/PAf5sLu2vEO5kRYKLxasyYn53o8c= +github.com/prometheus/procfs v0.0.12-0.20200505152635-9654394ca94a/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e h1:vcxGaoTs7kV8m5Np9uUNQin4BrLOthgV7252N8V+FwY= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e h1:LwyF2AFISC9nVbS6MgzsaQNSUsRXI49GS+YQ5KX/QH0= diff --git a/proc/grouper.go b/proc/grouper.go index 970f682..7fe76fc 100644 --- a/proc/grouper.go +++ b/proc/grouper.go @@ -66,6 +66,8 @@ func groupadd(grp Group, ts Update) Group { grp.Memory.ResidentBytes += ts.Memory.ResidentBytes grp.Memory.VirtualBytes += ts.Memory.VirtualBytes grp.Memory.VmSwapBytes += ts.Memory.VmSwapBytes + grp.Memory.ProportionalBytes += ts.Memory.ProportionalBytes + grp.Memory.ProportionalSwapBytes += ts.Memory.ProportionalSwapBytes if ts.Filedesc.Open != -1 { grp.OpenFDs += uint64(ts.Filedesc.Open) } diff --git a/proc/grouper_test.go b/proc/grouper_test.go index 758dc27..5b3f10f 100644 --- a/proc/grouper_test.go +++ b/proc/grouper_test.go @@ -45,30 +45,30 @@ func TestGrouperBasic(t *testing.T) { }{ { []IDInfo{ - piinfost(p1, n1, Counts{1, 2, 3, 4, 5, 6, 0, 0}, Memory{7, 8, 0}, + piinfost(p1, n1, Counts{1, 2, 3, 4, 5, 6, 0, 0}, Memory{7, 8, 0, 0, 0}, Filedesc{4, 400}, 2, States{Other: 1}), - piinfost(p2, n2, Counts{2, 3, 4, 5, 6, 7, 0, 0}, Memory{8, 9, 0}, + piinfost(p2, n2, Counts{2, 3, 4, 5, 6, 7, 0, 0}, Memory{8, 9, 0, 0, 0}, Filedesc{40, 400}, 3, States{Waiting: 1}), }, GroupByName{ - "g1": Group{Counts{}, States{Other: 1}, msi{}, 1, Memory{7, 8, 0}, starttime, + "g1": Group{Counts{}, States{Other: 1}, msi{}, 1, Memory{7, 8, 0, 0, 0}, starttime, 4, 0.01, 2, nil}, - "g2": Group{Counts{}, States{Waiting: 1}, msi{}, 1, Memory{8, 9, 0}, starttime, + "g2": Group{Counts{}, States{Waiting: 1}, msi{}, 1, Memory{8, 9, 0, 0, 0}, starttime, 40, 0.1, 3, nil}, }, }, { []IDInfo{ piinfost(p1, n1, Counts{2, 3, 4, 5, 6, 7, 0, 0}, - Memory{6, 7, 0}, Filedesc{100, 400}, 4, States{Zombie: 1}), + Memory{6, 7, 0, 0, 0}, Filedesc{100, 400}, 4, States{Zombie: 1}), piinfost(p2, n2, Counts{4, 5, 6, 7, 8, 9, 0, 0}, - Memory{9, 8, 0}, Filedesc{400, 400}, 2, States{Running: 1}), + Memory{9, 8, 0, 0, 0}, Filedesc{400, 400}, 2, States{Running: 1}), }, GroupByName{ "g1": Group{Counts{1, 1, 1, 1, 1, 1, 0, 0}, States{Zombie: 1}, msi{}, 1, - Memory{6, 7, 0}, starttime, 100, 0.25, 4, nil}, + Memory{6, 7, 0, 0, 0}, starttime, 100, 0.25, 4, nil}, "g2": Group{Counts{2, 2, 2, 2, 2, 2, 0, 0}, States{Running: 1}, msi{}, 1, - Memory{9, 8, 0}, starttime, 400, 1, 2, nil}, + Memory{9, 8, 0, 0, 0}, starttime, 400, 1, 2, nil}, }, }, } @@ -95,10 +95,10 @@ func TestGrouperProcJoin(t *testing.T) { }{ { []IDInfo{ - piinfo(p1, n1, Counts{1, 2, 3, 4, 5, 6, 0, 0}, Memory{3, 4, 0}, Filedesc{4, 400}, 2), + piinfo(p1, n1, Counts{1, 2, 3, 4, 5, 6, 0, 0}, Memory{3, 4, 0, 0, 0}, Filedesc{4, 400}, 2), }, GroupByName{ - "g1": Group{Counts{}, States{}, msi{}, 1, Memory{3, 4, 0}, starttime, 4, 0.01, 2, nil}, + "g1": Group{Counts{}, States{}, msi{}, 1, Memory{3, 4, 0, 0, 0}, starttime, 4, 0.01, 2, nil}, }, }, { // The counts for pid2 won't be factored into the total yet because we only add @@ -106,24 +106,24 @@ func TestGrouperProcJoin(t *testing.T) { // affected though. []IDInfo{ piinfost(p1, n1, Counts{3, 4, 5, 6, 7, 8, 0, 0}, - Memory{3, 4, 0}, Filedesc{4, 400}, 2, States{Running: 1}), + Memory{3, 4, 0, 0, 0}, Filedesc{4, 400}, 2, States{Running: 1}), piinfost(p2, n2, Counts{1, 1, 1, 1, 1, 1, 0, 0}, - Memory{1, 2, 0}, Filedesc{40, 400}, 3, States{Sleeping: 1}), + Memory{1, 2, 0, 0, 0}, Filedesc{40, 400}, 3, States{Sleeping: 1}), }, GroupByName{ "g1": Group{Counts{2, 2, 2, 2, 2, 2, 0, 0}, States{Running: 1, Sleeping: 1}, msi{}, 2, - Memory{4, 6, 0}, starttime, 44, 0.1, 5, nil}, + Memory{4, 6, 0, 0, 0}, starttime, 44, 0.1, 5, nil}, }, }, { []IDInfo{ piinfost(p1, n1, Counts{4, 5, 6, 7, 8, 9, 0, 0}, - Memory{1, 5, 0}, Filedesc{4, 400}, 2, States{Running: 1}), + Memory{1, 5, 0, 0, 0}, Filedesc{4, 400}, 2, States{Running: 1}), piinfost(p2, n2, Counts{2, 2, 2, 2, 2, 2, 0, 0}, - Memory{2, 4, 0}, Filedesc{40, 400}, 3, States{Running: 1}), + Memory{2, 4, 0, 0, 0}, Filedesc{40, 400}, 3, States{Running: 1}), }, GroupByName{ "g1": Group{Counts{4, 4, 4, 4, 4, 4, 0, 0}, States{Running: 2}, msi{}, 2, - Memory{3, 9, 0}, starttime, 44, 0.1, 5, nil}, + Memory{3, 9, 0, 0, 0}, starttime, 44, 0.1, 5, nil}, }, }, } @@ -150,18 +150,18 @@ func TestGrouperNonDecreasing(t *testing.T) { }{ { []IDInfo{ - piinfo(p1, n1, Counts{3, 4, 5, 6, 7, 8, 0, 0}, Memory{3, 4, 0}, Filedesc{4, 400}, 2), - piinfo(p2, n2, Counts{1, 1, 1, 1, 1, 1, 0, 0}, Memory{1, 2, 0}, Filedesc{40, 400}, 3), + piinfo(p1, n1, Counts{3, 4, 5, 6, 7, 8, 0, 0}, Memory{3, 4, 0, 0, 0}, Filedesc{4, 400}, 2), + piinfo(p2, n2, Counts{1, 1, 1, 1, 1, 1, 0, 0}, Memory{1, 2, 0, 0, 0}, Filedesc{40, 400}, 3), }, GroupByName{ - "g1": Group{Counts{}, States{}, msi{}, 2, Memory{4, 6, 0}, starttime, 44, 0.1, 5, nil}, + "g1": Group{Counts{}, States{}, msi{}, 2, Memory{4, 6, 0, 0, 0}, starttime, 44, 0.1, 5, nil}, }, }, { []IDInfo{ - piinfo(p1, n1, Counts{4, 5, 6, 7, 8, 9, 0, 0}, Memory{1, 5, 0}, Filedesc{4, 400}, 2), + piinfo(p1, n1, Counts{4, 5, 6, 7, 8, 9, 0, 0}, Memory{1, 5, 0, 0, 0}, Filedesc{4, 400}, 2), }, GroupByName{ - "g1": Group{Counts{1, 1, 1, 1, 1, 1, 0, 0}, States{}, msi{}, 1, Memory{1, 5, 0}, starttime, 4, 0.01, 2, nil}, + "g1": Group{Counts{1, 1, 1, 1, 1, 1, 0, 0}, States{}, msi{}, 1, Memory{1, 5, 0, 0, 0}, starttime, 4, 0.01, 2, nil}, }, }, { []IDInfo{}, diff --git a/proc/read.go b/proc/read.go index bae7301..2b004bd 100644 --- a/proc/read.go +++ b/proc/read.go @@ -49,9 +49,11 @@ type ( // Memory describes a proc's memory usage. Memory struct { - ResidentBytes uint64 - VirtualBytes uint64 - VmSwapBytes uint64 + ResidentBytes uint64 + VirtualBytes uint64 + VmSwapBytes uint64 + ProportionalBytes uint64 + ProportionalSwapBytes uint64 } // Filedesc describes a proc's file descriptor usage and soft limit. @@ -187,9 +189,10 @@ type ( // FS implements Source. FS struct { procfs.FS - BootTime uint64 - MountPoint string - debug bool + BootTime uint64 + MountPoint string + GatherSMaps bool + debug bool } ) @@ -474,13 +477,25 @@ func (p proc) GetMetrics() (Metrics, int, error) { softerrors |= 1 } + memory := Memory{ + ResidentBytes: uint64(stat.ResidentMemory()), + VirtualBytes: uint64(stat.VirtualMemory()), + VmSwapBytes: uint64(status.VmSwap), + } + + if p.proccache.fs.GatherSMaps { + smaps, err := p.Proc.ProcSMapsRollup() + if err != nil { + softerrors |= 1 + } else { + memory.ProportionalBytes = smaps.Pss + memory.ProportionalSwapBytes = smaps.SwapPss + } + } + return Metrics{ Counts: counts, - Memory: Memory{ - ResidentBytes: uint64(stat.ResidentMemory()), - VirtualBytes: uint64(stat.VirtualMemory()), - VmSwapBytes: uint64(status.VmSwap), - }, + Memory: memory, Filedesc: Filedesc{ Open: int64(numfds), Limit: uint64(limits.OpenFiles), @@ -554,7 +569,7 @@ func NewFS(mountPoint string, debug bool) (*FS, error) { if err != nil { return nil, err } - return &FS{fs, stat.BootTime, mountPoint, debug}, nil + return &FS{fs, stat.BootTime, mountPoint, false, debug}, nil } func (fs *FS) threadFs(pid int) (*FS, error) { @@ -563,7 +578,7 @@ func (fs *FS) threadFs(pid int) (*FS, error) { if err != nil { return nil, err } - return &FS{tfs, fs.BootTime, mountPoint, false}, nil + return &FS{tfs, fs.BootTime, mountPoint, fs.GatherSMaps, false}, nil } // AllProcs implements Source. diff --git a/proc/tracker_test.go b/proc/tracker_test.go index e28a148..cd5993c 100644 --- a/proc/tracker_test.go +++ b/proc/tracker_test.go @@ -99,15 +99,15 @@ func TestTrackerMetrics(t *testing.T) { want Update }{ { - piinfost(p, n, Counts{1, 2, 3, 4, 5, 6, 0, 0}, Memory{7, 8, 0}, + piinfost(p, n, Counts{1, 2, 3, 4, 5, 6, 0, 0}, Memory{7, 8, 0, 0, 0}, Filedesc{1, 10}, 9, States{Sleeping: 1}), - Update{n, Delta{}, Memory{7, 8, 0}, Filedesc{1, 10}, tm, + Update{n, Delta{}, Memory{7, 8, 0, 0, 0}, Filedesc{1, 10}, tm, 9, States{Sleeping: 1}, msi{}, nil}, }, { - piinfost(p, n, Counts{2, 3, 4, 5, 6, 7, 0, 0}, Memory{1, 2, 0}, + piinfost(p, n, Counts{2, 3, 4, 5, 6, 7, 0, 0}, Memory{1, 2, 0, 0, 0}, Filedesc{2, 20}, 1, States{Running: 1}), - Update{n, Delta{1, 1, 1, 1, 1, 1, 0, 0}, Memory{1, 2, 0}, + Update{n, Delta{1, 1, 1, 1, 1, 1, 0, 0}, Memory{1, 2, 0, 0, 0}, Filedesc{2, 20}, tm, 1, States{Running: 1}, msi{}, nil}, }, } diff --git a/vendor/github.com/prometheus/procfs/cpuinfo.go b/vendor/github.com/prometheus/procfs/cpuinfo.go index 2e02215..bb3be99 100644 --- a/vendor/github.com/prometheus/procfs/cpuinfo.go +++ b/vendor/github.com/prometheus/procfs/cpuinfo.go @@ -11,11 +11,15 @@ // See the License for the specific language governing permissions and // limitations under the License. +// +build linux + package procfs import ( "bufio" "bytes" + "errors" + "regexp" "strconv" "strings" @@ -52,6 +56,11 @@ type CPUInfo struct { PowerManagement string } +var ( + cpuinfoClockRegexp = regexp.MustCompile(`([\d.]+)`) + cpuinfoS390XProcessorRegexp = regexp.MustCompile(`^processor\s+(\d+):.*`) +) + // CPUInfo returns information about current system CPUs. // See https://www.kernel.org/doc/Documentation/filesystems/proc.txt func (fs FS) CPUInfo() ([]CPUInfo, error) { @@ -62,14 +71,26 @@ func (fs FS) CPUInfo() ([]CPUInfo, error) { return parseCPUInfo(data) } -// parseCPUInfo parses data from /proc/cpuinfo -func parseCPUInfo(info []byte) ([]CPUInfo, error) { - cpuinfo := []CPUInfo{} - i := -1 +func parseCPUInfoX86(info []byte) ([]CPUInfo, error) { scanner := bufio.NewScanner(bytes.NewReader(info)) + + // find the first "processor" line + firstLine := firstNonEmptyLine(scanner) + if !strings.HasPrefix(firstLine, "processor") || !strings.Contains(firstLine, ":") { + return nil, errors.New("invalid cpuinfo file: " + firstLine) + } + field := strings.SplitN(firstLine, ": ", 2) + v, err := strconv.ParseUint(field[1], 0, 32) + if err != nil { + return nil, err + } + firstcpu := CPUInfo{Processor: uint(v)} + cpuinfo := []CPUInfo{firstcpu} + i := 0 + for scanner.Scan() { line := scanner.Text() - if strings.TrimSpace(line) == "" { + if !strings.Contains(line, ":") { continue } field := strings.SplitN(line, ": ", 2) @@ -82,7 +103,7 @@ func parseCPUInfo(info []byte) ([]CPUInfo, error) { return nil, err } cpuinfo[i].Processor = uint(v) - case "vendor_id": + case "vendor", "vendor_id": cpuinfo[i].VendorID = field[1] case "cpu family": cpuinfo[i].CPUFamily = field[1] @@ -163,5 +184,175 @@ func parseCPUInfo(info []byte) ([]CPUInfo, error) { } } return cpuinfo, nil +} + +func parseCPUInfoARM(info []byte) ([]CPUInfo, error) { + scanner := bufio.NewScanner(bytes.NewReader(info)) + + firstLine := firstNonEmptyLine(scanner) + if !strings.HasPrefix(firstLine, "Processor") || !strings.Contains(firstLine, ":") { + return nil, errors.New("invalid cpuinfo file: " + firstLine) + } + field := strings.SplitN(firstLine, ": ", 2) + commonCPUInfo := CPUInfo{VendorID: field[1]} + + cpuinfo := []CPUInfo{} + i := -1 + featuresLine := "" + + for scanner.Scan() { + line := scanner.Text() + if !strings.Contains(line, ":") { + continue + } + field := strings.SplitN(line, ": ", 2) + switch strings.TrimSpace(field[0]) { + case "processor": + cpuinfo = append(cpuinfo, commonCPUInfo) // start of the next processor + i++ + v, err := strconv.ParseUint(field[1], 0, 32) + if err != nil { + return nil, err + } + cpuinfo[i].Processor = uint(v) + case "BogoMIPS": + v, err := strconv.ParseFloat(field[1], 64) + if err != nil { + return nil, err + } + cpuinfo[i].BogoMips = v + case "Features": + featuresLine = line + } + } + fields := strings.SplitN(featuresLine, ": ", 2) + for i := range cpuinfo { + cpuinfo[i].Flags = strings.Fields(fields[1]) + } + return cpuinfo, nil +} + +func parseCPUInfoS390X(info []byte) ([]CPUInfo, error) { + scanner := bufio.NewScanner(bytes.NewReader(info)) + firstLine := firstNonEmptyLine(scanner) + if !strings.HasPrefix(firstLine, "vendor_id") || !strings.Contains(firstLine, ":") { + return nil, errors.New("invalid cpuinfo file: " + firstLine) + } + field := strings.SplitN(firstLine, ": ", 2) + cpuinfo := []CPUInfo{} + commonCPUInfo := CPUInfo{VendorID: field[1]} + + for scanner.Scan() { + line := scanner.Text() + if !strings.Contains(line, ":") { + continue + } + field := strings.SplitN(line, ": ", 2) + switch strings.TrimSpace(field[0]) { + case "bogomips per cpu": + v, err := strconv.ParseFloat(field[1], 64) + if err != nil { + return nil, err + } + commonCPUInfo.BogoMips = v + case "features": + commonCPUInfo.Flags = strings.Fields(field[1]) + } + if strings.HasPrefix(line, "processor") { + match := cpuinfoS390XProcessorRegexp.FindStringSubmatch(line) + if len(match) < 2 { + return nil, errors.New("Invalid line found in cpuinfo: " + line) + } + cpu := commonCPUInfo + v, err := strconv.ParseUint(match[1], 0, 32) + if err != nil { + return nil, err + } + cpu.Processor = uint(v) + cpuinfo = append(cpuinfo, cpu) + } + if strings.HasPrefix(line, "cpu number") { + break + } + } + + i := 0 + for scanner.Scan() { + line := scanner.Text() + if !strings.Contains(line, ":") { + continue + } + field := strings.SplitN(line, ": ", 2) + switch strings.TrimSpace(field[0]) { + case "cpu number": + i++ + case "cpu MHz dynamic": + clock := cpuinfoClockRegexp.FindString(strings.TrimSpace(field[1])) + v, err := strconv.ParseFloat(clock, 64) + if err != nil { + return nil, err + } + cpuinfo[i].CPUMHz = v + } + } + + return cpuinfo, nil +} + +func parseCPUInfoPPC(info []byte) ([]CPUInfo, error) { + scanner := bufio.NewScanner(bytes.NewReader(info)) + + firstLine := firstNonEmptyLine(scanner) + if !strings.HasPrefix(firstLine, "processor") || !strings.Contains(firstLine, ":") { + return nil, errors.New("invalid cpuinfo file: " + firstLine) + } + field := strings.SplitN(firstLine, ": ", 2) + v, err := strconv.ParseUint(field[1], 0, 32) + if err != nil { + return nil, err + } + firstcpu := CPUInfo{Processor: uint(v)} + cpuinfo := []CPUInfo{firstcpu} + i := 0 + + for scanner.Scan() { + line := scanner.Text() + if !strings.Contains(line, ":") { + continue + } + field := strings.SplitN(line, ": ", 2) + switch strings.TrimSpace(field[0]) { + case "processor": + cpuinfo = append(cpuinfo, CPUInfo{}) // start of the next processor + i++ + v, err := strconv.ParseUint(field[1], 0, 32) + if err != nil { + return nil, err + } + cpuinfo[i].Processor = uint(v) + case "cpu": + cpuinfo[i].VendorID = field[1] + case "clock": + clock := cpuinfoClockRegexp.FindString(strings.TrimSpace(field[1])) + v, err := strconv.ParseFloat(clock, 64) + if err != nil { + return nil, err + } + cpuinfo[i].CPUMHz = v + } + } + return cpuinfo, nil +} + +// firstNonEmptyLine advances the scanner to the first non-empty line +// and returns the contents of that line +func firstNonEmptyLine(scanner *bufio.Scanner) string { + for scanner.Scan() { + line := scanner.Text() + if strings.TrimSpace(line) != "" { + return line + } + } + return "" } diff --git a/vendor/github.com/prometheus/procfs/cpuinfo_amd64.go b/vendor/github.com/prometheus/procfs/cpuinfo_amd64.go new file mode 100644 index 0000000..42e995e --- /dev/null +++ b/vendor/github.com/prometheus/procfs/cpuinfo_amd64.go @@ -0,0 +1,19 @@ +// Copyright 2020 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build linux +// +build amd64 + +package procfs + +var parseCPUInfo = parseCPUInfoX86 diff --git a/vendor/github.com/prometheus/procfs/cpuinfo_arm64.go b/vendor/github.com/prometheus/procfs/cpuinfo_arm64.go new file mode 100644 index 0000000..4f5d172 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/cpuinfo_arm64.go @@ -0,0 +1,19 @@ +// Copyright 2020 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build linux +// +build arm64 + +package procfs + +var parseCPUInfo = parseCPUInfoARM diff --git a/vendor/github.com/prometheus/procfs/cpuinfo_ppc64.go b/vendor/github.com/prometheus/procfs/cpuinfo_ppc64.go new file mode 100644 index 0000000..3184151 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/cpuinfo_ppc64.go @@ -0,0 +1,19 @@ +// Copyright 2020 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build linux +// +build ppc64,ppc64le + +package procfs + +var parseCPUInfo = parseCPUInfoPPC diff --git a/vendor/github.com/prometheus/procfs/cpuinfo_s390x.go b/vendor/github.com/prometheus/procfs/cpuinfo_s390x.go new file mode 100644 index 0000000..1d7019d --- /dev/null +++ b/vendor/github.com/prometheus/procfs/cpuinfo_s390x.go @@ -0,0 +1,19 @@ +// Copyright 2020 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build linux +// +build s390x + +package procfs + +var parseCPUInfo = parseCPUInfoS390x diff --git a/vendor/github.com/prometheus/procfs/fixtures.ttar b/vendor/github.com/prometheus/procfs/fixtures.ttar index bc01da5..8eb32f7 100644 --- a/vendor/github.com/prometheus/procfs/fixtures.ttar +++ b/vendor/github.com/prometheus/procfs/fixtures.ttar @@ -173,6 +173,283 @@ Lines: 1 411605849 93680043 79 Mode: 644 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/proc/26231/smaps +Lines: 252 +00400000-00cb1000 r-xp 00000000 fd:01 952273 /bin/alertmanager +Size: 8900 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Rss: 2952 kB +Pss: 2952 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 2952 kB +Private_Dirty: 0 kB +Referenced: 2864 kB +Anonymous: 0 kB +LazyFree: 0 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 0 kB +SwapPss: 0 kB +Locked: 0 kB +VmFlags: rd ex mr mw me dw sd +00cb1000-016b0000 r--p 008b1000 fd:01 952273 /bin/alertmanager +Size: 10236 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Rss: 6152 kB +Pss: 6152 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 6152 kB +Private_Dirty: 0 kB +Referenced: 5308 kB +Anonymous: 0 kB +LazyFree: 0 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 0 kB +SwapPss: 0 kB +Locked: 0 kB +VmFlags: rd mr mw me dw sd +016b0000-0171a000 rw-p 012b0000 fd:01 952273 /bin/alertmanager +Size: 424 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Rss: 176 kB +Pss: 176 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 84 kB +Private_Dirty: 92 kB +Referenced: 176 kB +Anonymous: 92 kB +LazyFree: 0 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 12 kB +SwapPss: 12 kB +Locked: 0 kB +VmFlags: rd wr mr mw me dw ac sd +0171a000-0173f000 rw-p 00000000 00:00 0 +Size: 148 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Rss: 76 kB +Pss: 76 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 76 kB +Referenced: 76 kB +Anonymous: 76 kB +LazyFree: 0 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 0 kB +SwapPss: 0 kB +Locked: 0 kB +VmFlags: rd wr mr mw me ac sd +c000000000-c000400000 rw-p 00000000 00:00 0 +Size: 4096 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Rss: 2564 kB +Pss: 2564 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 20 kB +Private_Dirty: 2544 kB +Referenced: 2544 kB +Anonymous: 2564 kB +LazyFree: 0 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 1100 kB +SwapPss: 1100 kB +Locked: 0 kB +VmFlags: rd wr mr mw me ac sd +c000400000-c001600000 rw-p 00000000 00:00 0 +Size: 18432 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Rss: 16024 kB +Pss: 16024 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 5864 kB +Private_Dirty: 10160 kB +Referenced: 11944 kB +Anonymous: 16024 kB +LazyFree: 5848 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 440 kB +SwapPss: 440 kB +Locked: 0 kB +VmFlags: rd wr mr mw me ac sd nh +c001600000-c004000000 rw-p 00000000 00:00 0 +Size: 43008 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +LazyFree: 0 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 0 kB +SwapPss: 0 kB +Locked: 0 kB +VmFlags: rd wr mr mw me ac sd +7f0ab95ca000-7f0abbb7b000 rw-p 00000000 00:00 0 +Size: 38596 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Rss: 1992 kB +Pss: 1992 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 476 kB +Private_Dirty: 1516 kB +Referenced: 1828 kB +Anonymous: 1992 kB +LazyFree: 0 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 384 kB +SwapPss: 384 kB +Locked: 0 kB +VmFlags: rd wr mr mw me ac sd +7ffc07ecf000-7ffc07ef0000 rw-p 00000000 00:00 0 [stack] +Size: 132 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Rss: 8 kB +Pss: 8 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 8 kB +Referenced: 8 kB +Anonymous: 8 kB +LazyFree: 0 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 4 kB +SwapPss: 4 kB +Locked: 0 kB +VmFlags: rd wr mr mw me gd ac +7ffc07f9e000-7ffc07fa1000 r--p 00000000 00:00 0 [vvar] +Size: 12 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +LazyFree: 0 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 0 kB +SwapPss: 0 kB +Locked: 0 kB +VmFlags: rd mr pf io de dd sd +7ffc07fa1000-7ffc07fa3000 r-xp 00000000 00:00 0 [vdso] +Size: 8 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Rss: 4 kB +Pss: 0 kB +Shared_Clean: 4 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 4 kB +Anonymous: 0 kB +LazyFree: 0 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 0 kB +SwapPss: 0 kB +Locked: 0 kB +VmFlags: rd ex mr mw me de sd +ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] +Size: 4 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Rss: 0 kB +Pss: 0 kB +Shared_Clean: 0 kB +Shared_Dirty: 0 kB +Private_Clean: 0 kB +Private_Dirty: 0 kB +Referenced: 0 kB +Anonymous: 0 kB +LazyFree: 0 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 0 kB +SwapPss: 0 kB +Locked: 0 kB +VmFlags: rd ex +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/proc/26231/smaps_rollup +Lines: 17 +00400000-ffffffffff601000 ---p 00000000 00:00 0 [rollup] +Rss: 29948 kB +Pss: 29944 kB +Shared_Clean: 4 kB +Shared_Dirty: 0 kB +Private_Clean: 15548 kB +Private_Dirty: 14396 kB +Referenced: 24752 kB +Anonymous: 20756 kB +LazyFree: 5848 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 1940 kB +SwapPss: 1940 kB +Locked: 0 kB +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Path: fixtures/proc/26231/stat Lines: 1 26231 (vim) R 5392 7446 5392 34835 7446 4218880 32533 309516 26 82 1677 44 158 99 20 0 1 0 82375 56274944 1981 18446744073709551615 4194304 6294284 140736914091744 140736914087944 139965136429984 0 0 12288 1870679807 0 0 0 17 0 0 0 31 0 0 8391624 8481048 16420864 140736914093252 140736914093279 140736914093279 140736914096107 0 @@ -2575,6 +2852,140 @@ Mode: 664 Directory: fixtures/sys/class Mode: 775 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/class/fc_host +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/class/fc_host/host0 +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/fc_host/host0/dev_loss_tmo +Lines: 1 +30 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/fc_host/host0/fabric_name +Lines: 1 +0x0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/fc_host/host0/node_name +Lines: 1 +0x2000e0071bce95f2 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/fc_host/host0/port_id +Lines: 1 +0x000002 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/fc_host/host0/port_name +Lines: 1 +0x1000e0071bce95f2 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/fc_host/host0/port_state +Lines: 1 +Online +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/fc_host/host0/port_type +Lines: 1 +Point-To-Point (direct nport connection) +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/fc_host/host0/speed +Lines: 1 +16 Gbit +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Directory: fixtures/sys/class/fc_host/host0/statistics +Mode: 755 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/fc_host/host0/statistics/dumped_frames +Lines: 1 +0xffffffffffffffff +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/fc_host/host0/statistics/error_frames +Lines: 1 +0x0 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/fc_host/host0/statistics/fcp_packet_aborts +Lines: 1 +0x13 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/fc_host/host0/statistics/invalid_crc_count +Lines: 1 +0x2 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/fc_host/host0/statistics/invalid_tx_word_count +Lines: 1 +0x8 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/fc_host/host0/statistics/link_failure_count +Lines: 1 +0x9 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/fc_host/host0/statistics/loss_of_signal_count +Lines: 1 +0x11 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/fc_host/host0/statistics/loss_of_sync_count +Lines: 1 +0x10 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/fc_host/host0/statistics/nos_count +Lines: 1 +0x12 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/fc_host/host0/statistics/rx_frames +Lines: 1 +0x3 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/fc_host/host0/statistics/rx_words +Lines: 1 +0x4 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/fc_host/host0/statistics/seconds_since_last_reset +Lines: 1 +0x7 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/fc_host/host0/statistics/tx_frames +Lines: 1 +0x5 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/fc_host/host0/statistics/tx_words +Lines: 1 +0x6 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/fc_host/host0/supported_classes +Lines: 1 +Class 3 +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/fc_host/host0/supported_speeds +Lines: 1 +4 Gbit, 8 Gbit, 16 Gbit +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/fc_host/host0/symbolic_name +Lines: 1 +Emulex SN1100E2P FV12.4.270.3 DV12.4.0.0. HN:gotest. OS:Linux +Mode: 644 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Directory: fixtures/sys/class/infiniband Mode: 755 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -2605,6 +3016,11 @@ Mode: 755 Directory: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters Mode: 755 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/VL15_dropped +Lines: 1 +0 +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Path: fixtures/sys/class/infiniband/mlx4_0/ports/1/counters/excessive_buffer_overrun_errors Lines: 1 0 @@ -2706,6 +3122,11 @@ Mode: 755 Directory: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters Mode: 755 # ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/VL15_dropped +Lines: 1 +0 +Mode: 664 +# ttar - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Path: fixtures/sys/class/infiniband/mlx4_0/ports/2/counters/excessive_buffer_overrun_errors Lines: 1 0 diff --git a/vendor/github.com/prometheus/procfs/proc_smaps.go b/vendor/github.com/prometheus/procfs/proc_smaps.go new file mode 100644 index 0000000..a576a72 --- /dev/null +++ b/vendor/github.com/prometheus/procfs/proc_smaps.go @@ -0,0 +1,165 @@ +// Copyright 2020 The Prometheus Authors +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +// +build !windows + +package procfs + +import ( + "bufio" + "errors" + "fmt" + "os" + "regexp" + "strconv" + "strings" + + "github.com/prometheus/procfs/internal/util" +) + +var ( + // match the header line before each mapped zone in /proc/pid/smaps + procSMapsHeaderLine = regexp.MustCompile(`^[a-f0-9].*$`) +) + +type ProcSMapsRollup struct { + // Amount of the mapping that is currently resident in RAM + Rss uint64 + // Process's proportional share of this mapping + Pss uint64 + // Size in bytes of clean shared pages + SharedClean uint64 + // Size in bytes of dirty shared pages + SharedDirty uint64 + // Size in bytes of clean private pages + PrivateClean uint64 + // Size in bytes of dirty private pages + PrivateDirty uint64 + // Amount of memory currently marked as referenced or accessed + Referenced uint64 + // Amount of memory that does not belong to any file + Anonymous uint64 + // Amount would-be-anonymous memory currently on swap + Swap uint64 + // Process's proportional memory on swap + SwapPss uint64 +} + +// ProcSMapsRollup reads from /proc/[pid]/smaps_rollup to get summed memory information of the +// process. +// +// If smaps_rollup does not exists (require kernel >= 4.15), the content of /proc/pid/smaps will +// we read and summed. +func (p Proc) ProcSMapsRollup() (ProcSMapsRollup, error) { + data, err := util.ReadFileNoStat(p.path("smaps_rollup")) + if err != nil && os.IsNotExist(err) { + return p.procSMapsRollupManual() + } + if err != nil { + return ProcSMapsRollup{}, err + } + + lines := strings.Split(string(data), "\n") + smaps := ProcSMapsRollup{} + + // skip first line which don't contains information we need + lines = lines[1:] + for _, line := range lines { + if line == "" { + continue + } + + if err := smaps.parseLine(line); err != nil { + return ProcSMapsRollup{}, err + } + } + + return smaps, nil +} + +// Read /proc/pid/smaps and do the roll-up in Go code. +func (p Proc) procSMapsRollupManual() (ProcSMapsRollup, error) { + file, err := os.Open(p.path("smaps")) + if err != nil { + return ProcSMapsRollup{}, err + } + defer file.Close() + + smaps := ProcSMapsRollup{} + scan := bufio.NewScanner(file) + + for scan.Scan() { + line := scan.Text() + + if procSMapsHeaderLine.MatchString(line) { + continue + } + + if err := smaps.parseLine(line); err != nil { + return ProcSMapsRollup{}, err + } + } + + return smaps, nil +} + +func (s *ProcSMapsRollup) parseLine(line string) error { + kv := strings.SplitN(line, ":", 2) + if len(kv) != 2 { + fmt.Println(line) + return errors.New("invalid net/dev line, missing colon") + } + + k := kv[0] + if k == "VmFlags" { + return nil + } + + v := strings.TrimSpace(kv[1]) + v = strings.TrimRight(v, " kB") + + vKBytes, err := strconv.ParseUint(v, 10, 64) + if err != nil { + return err + } + vBytes := vKBytes * 1024 + + s.addValue(k, v, vKBytes, vBytes) + + return nil +} + +func (s *ProcSMapsRollup) addValue(k string, vString string, vUint uint64, vUintBytes uint64) { + switch k { + case "Rss": + s.Rss += vUintBytes + case "Pss": + s.Pss += vUintBytes + case "Shared_Clean": + s.SharedClean += vUintBytes + case "Shared_Dirty": + s.SharedDirty += vUintBytes + case "Private_Clean": + s.PrivateClean += vUintBytes + case "Private_Dirty": + s.PrivateDirty += vUintBytes + case "Referenced": + s.Referenced += vUintBytes + case "Anonymous": + s.Anonymous += vUintBytes + case "Swap": + s.Swap += vUintBytes + case "SwapPss": + s.SwapPss += vUintBytes + } +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 9b5615f..65566a8 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -27,7 +27,7 @@ github.com/prometheus/client_model/go github.com/prometheus/common/expfmt github.com/prometheus/common/model github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg -# github.com/prometheus/procfs v0.0.12-0.20200430211241-ea64cd222793 +# github.com/prometheus/procfs v0.0.12-0.20200505152635-9654394ca94a github.com/prometheus/procfs github.com/prometheus/procfs/internal/fs github.com/prometheus/procfs/internal/util From 15803b62ead013de0ce189e30800a312b6aeed00 Mon Sep 17 00:00:00 2001 From: Pierre Fersing Date: Sun, 17 May 2020 22:58:21 +0200 Subject: [PATCH 2/3] Enable proportional memory reporting by default --- cmd/process-exporter/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/process-exporter/main.go b/cmd/process-exporter/main.go index 0a8f343..c778064 100644 --- a/cmd/process-exporter/main.go +++ b/cmd/process-exporter/main.go @@ -293,7 +293,7 @@ func main() { "if a proc is tracked, track with it any children that aren't part of their own group") threads = flag.Bool("threads", true, "report on per-threadname metrics as well") - smaps = flag.Bool("gather-smaps", false, + smaps = flag.Bool("gather-smaps", true, "gather metrics from smaps file, which contains proportional resident memory size") man = flag.Bool("man", false, "print manual") From 06487c9a300a6f28a61873c5f419f1c37cfe323e Mon Sep 17 00:00:00 2001 From: Pierre Fersing Date: Sun, 17 May 2020 23:11:00 +0200 Subject: [PATCH 3/3] Use ProcessCollectorOption to reduce number of arguments --- cmd/process-exporter/main.go | 46 +++++++++++++++++++++++------------- 1 file changed, 29 insertions(+), 17 deletions(-) diff --git a/cmd/process-exporter/main.go b/cmd/process-exporter/main.go index c778064..8e803d8 100644 --- a/cmd/process-exporter/main.go +++ b/cmd/process-exporter/main.go @@ -357,7 +357,17 @@ func main() { matchnamer = namemapper } - pc, err := NewProcessCollector(*procfsPath, *children, *threads, *smaps, matchnamer, *recheck, *debug) + pc, err := NewProcessCollector( + ProcessCollectorOption{ + ProcFSPath: *procfsPath, + Children: *children, + Threads: *threads, + GatherSMaps: *smaps, + Namer: matchnamer, + Recheck: *recheck, + Debug: *debug, + }, + ) if err != nil { log.Fatalf("Error initializing: %v", err) } @@ -397,6 +407,16 @@ type ( done chan struct{} } + ProcessCollectorOption struct { + ProcFSPath string + Children bool + Threads bool + GatherSMaps bool + Namer common.MatchNamer + Recheck bool + Debug bool + } + NamedProcessCollector struct { scrapeChan chan scrapeRequest *proc.Grouper @@ -410,33 +430,25 @@ type ( } ) -func NewProcessCollector( - procfsPath string, - children bool, - threads bool, - smaps bool, - n common.MatchNamer, - recheck bool, - debug bool, -) (*NamedProcessCollector, error) { - fs, err := proc.NewFS(procfsPath, debug) +func NewProcessCollector(options ProcessCollectorOption) (*NamedProcessCollector, error) { + fs, err := proc.NewFS(options.ProcFSPath, options.Debug) if err != nil { return nil, err } - fs.GatherSMaps = smaps + fs.GatherSMaps = options.GatherSMaps p := &NamedProcessCollector{ scrapeChan: make(chan scrapeRequest), - Grouper: proc.NewGrouper(n, children, threads, recheck, debug), + Grouper: proc.NewGrouper(options.Namer, options.Children, options.Threads, options.Recheck, options.Debug), source: fs, - threads: threads, - smaps: smaps, - debug: debug, + threads: options.Threads, + smaps: options.GatherSMaps, + debug: options.Debug, } colErrs, _, err := p.Update(p.source.AllProcs()) if err != nil { - if debug { + if options.Debug { log.Print(err) } return nil, err