From b846085174d68ae5dfd27f276424d41a43649be3 Mon Sep 17 00:00:00 2001
From: Daniel Hodges <hodges.daniel.scott@gmail.com>
Date: Sun, 31 Oct 2021 20:00:31 -0400
Subject: Refactor perf collector to better handle failures and warn on open
 file limits

Origin: https://github.com/prometheus/node_exporter/pull/2190
Signed-off-by: Daniel Hodges <hodges.daniel.scott@gmail.com>
---
 collector/perf_linux.go | 46 ++++++++++++++++++++---------------------
 go.mod                  |  2 +-
 go.sum                  |  6 +++---
 3 files changed, 27 insertions(+), 27 deletions(-)

diff --git a/collector/perf_linux.go b/collector/perf_linux.go
index 76883523..dbe578a6 100644
--- a/collector/perf_linux.go
+++ b/collector/perf_linux.go
@@ -161,8 +161,8 @@ func (c *perfTracepointCollector) update(ch chan<- prometheus.Metric) error {
 // updateCPU is used to update metrics per CPU profiler.
 func (c *perfTracepointCollector) updateCPU(cpu int, ch chan<- prometheus.Metric) error {
 	profiler := c.profilers[cpu]
-	p, err := profiler.Profile()
-	if err != nil {
+	p := &perf.GroupProfileValue{}
+	if err := profiler.Profile(p); err != nil {
 		level.Error(c.logger).Log("msg", "Failed to collect tracepoint profile", "err", err)
 		return err
 	}
@@ -286,8 +286,12 @@ func NewPerfCollector(logger log.Logger) (Collector, error) {
 	for _, cpu := range cpus {
 		// Use -1 to profile all processes on the CPU, see:
 		// man perf_event_open
-		hwProf, err := perf.NewHardwareProfiler(-1, cpu)
-		if err != nil {
+		hwProf, err := perf.NewHardwareProfiler(
+			-1,
+			cpu,
+			perf.AllHardwareProfilers,
+		)
+		if err != nil && !hwProf.HasProfilers() {
 			return nil, err
 		}
 		if err := hwProf.Start(); err != nil {
@@ -296,8 +300,8 @@ func NewPerfCollector(logger log.Logger) (Collector, error) {
 		collector.perfHwProfilers[cpu] = &hwProf
 		collector.hwProfilerCPUMap[&hwProf] = cpu
 
-		swProf, err := perf.NewSoftwareProfiler(-1, cpu)
-		if err != nil {
+		swProf, err := perf.NewSoftwareProfiler(-1, cpu, perf.AllSoftwareProfilers)
+		if err != nil && !swProf.HasProfilers() {
 			return nil, err
 		}
 		if err := swProf.Start(); err != nil {
@@ -306,8 +310,13 @@ func NewPerfCollector(logger log.Logger) (Collector, error) {
 		collector.perfSwProfilers[cpu] = &swProf
 		collector.swProfilerCPUMap[&swProf] = cpu
 
-		cacheProf, err := perf.NewCacheProfiler(-1, cpu)
-		if err != nil {
+		cacheProfilers := perf.L1DataReadHitProfiler & perf.L1DataReadMissProfiler & perf.L1DataWriteHitProfiler & perf.L1InstrReadMissProfiler & perf.InstrTLBReadHitProfiler & perf.InstrTLBReadMissProfiler & perf.LLReadHitProfiler & perf.LLReadMissProfiler & perf.LLWriteHitProfiler & perf.LLWriteMissProfiler & perf.BPUReadHitProfiler & perf.BPUReadMissProfiler
+		cacheProf, err := perf.NewCacheProfiler(
+			-1,
+			cpu,
+			cacheProfilers,
+		)
+		if err != nil && !cacheProf.HasProfilers() {
 			return nil, err
 		}
 		if err := cacheProf.Start(); err != nil {
@@ -585,13 +594,10 @@ func (c *perfCollector) Update(ch chan<- prometheus.Metric) error {
 
 func (c *perfCollector) updateHardwareStats(ch chan<- prometheus.Metric) error {
 	for _, profiler := range c.perfHwProfilers {
-		hwProfile, err := (*profiler).Profile()
-		if err != nil {
+		hwProfile := &perf.HardwareProfile{}
+		if err := (*profiler).Profile(hwProfile); err != nil {
 			return err
 		}
-		if hwProfile == nil {
-			continue
-		}
 
 		cpuid := strconv.Itoa(c.hwProfilerCPUMap[profiler])
 
@@ -657,13 +663,10 @@ func (c *perfCollector) updateHardwareStats(ch chan<- prometheus.Metric) error {
 
 func (c *perfCollector) updateSoftwareStats(ch chan<- prometheus.Metric) error {
 	for _, profiler := range c.perfSwProfilers {
-		swProfile, err := (*profiler).Profile()
-		if err != nil {
+		swProfile := &perf.SoftwareProfile{}
+		if err := (*profiler).Profile(swProfile); err != nil {
 			return err
 		}
-		if swProfile == nil {
-			continue
-		}
 
 		cpuid := strconv.Itoa(c.swProfilerCPUMap[profiler])
 
@@ -713,13 +716,10 @@ func (c *perfCollector) updateSoftwareStats(ch chan<- prometheus.Metric) error {
 
 func (c *perfCollector) updateCacheStats(ch chan<- prometheus.Metric) error {
 	for _, profiler := range c.perfCacheProfilers {
-		cacheProfile, err := (*profiler).Profile()
-		if err != nil {
+		cacheProfile := &perf.CacheProfile{}
+		if err := (*profiler).Profile(cacheProfile); err != nil {
 			return err
 		}
-		if cacheProfile == nil {
-			continue
-		}
 
 		cpuid := strconv.Itoa(c.cacheProfilerCPUMap[profiler])
 
diff --git a/go.mod b/go.mod
index eabe1780..1ac15263 100644
--- a/go.mod
+++ b/go.mod
@@ -7,7 +7,7 @@ require (
 	github.com/go-kit/log v0.2.0
 	github.com/godbus/dbus v0.0.0-20190402143921-271e53dc4968
 	github.com/hashicorp/go-envparse v0.0.0-20200406174449-d9cfd743a15e
-	github.com/hodgesds/perf-utils v0.4.0
+	github.com/hodgesds/perf-utils v0.5.1
 	github.com/illumos/go-kstat v0.0.0-20210513183136-173c9b0a9973
 	github.com/jsimonetti/rtnetlink v0.0.0-20211022192332-93da33804786
 	github.com/lufia/iostat v1.2.0
diff --git a/go.sum b/go.sum
index 84ae5c12..440a0e5e 100644
--- a/go.sum
+++ b/go.sum
@@ -144,8 +144,8 @@ github.com/hashicorp/go-envparse v0.0.0-20200406174449-d9cfd743a15e h1:v1d9+AJMP
 github.com/hashicorp/go-envparse v0.0.0-20200406174449-d9cfd743a15e/go.mod h1:/NlxCzN2D4C4L2uDE6ux/h6jM+n98VFQM14nnCIfHJU=
 github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
 github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
-github.com/hodgesds/perf-utils v0.4.0 h1:onWrAGy6RYr7938qNXtSsTr54K4BLx8Hh3EXAr+xy+U=
-github.com/hodgesds/perf-utils v0.4.0/go.mod h1:wpXb8IDP3gn1iCsHuql0e9fyARRjRPvxN7lRPDihOds=
+github.com/hodgesds/perf-utils v0.5.1 h1:Dlk4yYRQAzLnqiFqvwKj9+a1XysINFuHmRfcIduuXxo=
+github.com/hodgesds/perf-utils v0.5.1/go.mod h1:LAklqfDadNKpkxoAJNHpD5tkY0rkZEVdnCEWN5k4QJY=
 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
 github.com/illumos/go-kstat v0.0.0-20210513183136-173c9b0a9973 h1:hk4LPqXIY/c9XzRbe7dA6qQxaT6Axcbny0L/G5a4owQ=
 github.com/illumos/go-kstat v0.0.0-20210513183136-173c9b0a9973/go.mod h1:PoK3ejP3LJkGTzKqRlpvCIFas3ncU02v8zzWDW+g0FY=
@@ -416,7 +416,7 @@ golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211023085530-d6a326fbbf70/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211031064116-611d5d643895/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1 h1:kwrAHlwJ0DUBZwQ238v+Uod/3eZ8B2K5rYsUHBQvzmI=
 golang.org/x/sys v0.0.0-20211117180635-dee7805ff2e1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-- 
2.32.0

