prometheusmetricshost-metricsmachine-metricsnode-metricsprocfsprometheus-exportersystem-informationsystem-metrics
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
259 lines
5.5 KiB
259 lines
5.5 KiB
// Copyright 2019 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. |
|
|
|
//go:build !noperf |
|
// +build !noperf |
|
|
|
package collector |
|
|
|
import ( |
|
"io" |
|
"log/slog" |
|
"os" |
|
"runtime" |
|
"strconv" |
|
"strings" |
|
"testing" |
|
|
|
"github.com/prometheus/client_golang/prometheus" |
|
) |
|
|
|
func canTestPerf(t *testing.T) { |
|
paranoidBytes, err := os.ReadFile("/proc/sys/kernel/perf_event_paranoid") |
|
if err != nil { |
|
t.Skip("Procfs not mounted, skipping perf tests") |
|
} |
|
paranoidStr := strings.Replace(string(paranoidBytes), "\n", "", -1) |
|
paranoid, err := strconv.Atoi(paranoidStr) |
|
if err != nil { |
|
t.Fatalf("Expected perf_event_paranoid to be an int, got: %s", paranoidStr) |
|
} |
|
if paranoid >= 1 { |
|
t.Skip("Skipping perf tests, set perf_event_paranoid to 0") |
|
} |
|
} |
|
|
|
func TestPerfCollector(t *testing.T) { |
|
canTestPerf(t) |
|
collector, err := NewPerfCollector(slog.New(slog.NewTextHandler(io.Discard, nil))) |
|
if err != nil { |
|
t.Fatal(err) |
|
} |
|
|
|
// Setup background goroutine to capture metrics. |
|
metrics := make(chan prometheus.Metric) |
|
defer close(metrics) |
|
go func() { |
|
i := 0 |
|
for range metrics { |
|
i++ |
|
} |
|
}() |
|
if err := collector.Update(metrics); err != nil { |
|
t.Fatal(err) |
|
} |
|
} |
|
|
|
func TestPerfCollectorStride(t *testing.T) { |
|
canTestPerf(t) |
|
|
|
tests := []struct { |
|
name string |
|
flag string |
|
exCPUs []int |
|
}{ |
|
{ |
|
name: "valid single CPU", |
|
flag: "1", |
|
exCPUs: []int{1}, |
|
}, |
|
{ |
|
name: "valid range CPUs", |
|
flag: "1-5", |
|
exCPUs: []int{1, 2, 3, 4, 5}, |
|
}, |
|
{ |
|
name: "valid stride", |
|
flag: "1-8:2", |
|
exCPUs: []int{1, 3, 5, 7}, |
|
}, |
|
} |
|
|
|
for _, test := range tests { |
|
t.Run(test.name, func(t *testing.T) { |
|
ncpu := runtime.NumCPU() |
|
for _, cpu := range test.exCPUs { |
|
if cpu > ncpu { |
|
t.Skipf("Skipping test because runtime.NumCPU < %d", cpu) |
|
} |
|
} |
|
perfCPUsFlag = &test.flag |
|
collector, err := NewPerfCollector(slog.New(slog.NewTextHandler(io.Discard, nil))) |
|
if err != nil { |
|
t.Fatal(err) |
|
} |
|
|
|
c := collector.(*perfCollector) |
|
for _, cpu := range test.exCPUs { |
|
if _, ok := c.perfHwProfilers[cpu]; !ok { |
|
t.Fatalf("Expected CPU %v in hardware profilers", cpu) |
|
} |
|
if _, ok := c.perfSwProfilers[cpu]; !ok { |
|
t.Fatalf("Expected CPU %v in software profilers", cpu) |
|
} |
|
if _, ok := c.perfCacheProfilers[cpu]; !ok { |
|
t.Fatalf("Expected CPU %v in cache profilers", cpu) |
|
} |
|
} |
|
}) |
|
} |
|
} |
|
|
|
func TestPerfCPUFlagToCPUs(t *testing.T) { |
|
tests := []struct { |
|
name string |
|
flag string |
|
exCpus []int |
|
errStr string |
|
}{ |
|
{ |
|
name: "valid single CPU", |
|
flag: "1", |
|
exCpus: []int{1}, |
|
}, |
|
{ |
|
name: "valid range CPUs", |
|
flag: "1-5", |
|
exCpus: []int{1, 2, 3, 4, 5}, |
|
}, |
|
{ |
|
name: "valid double digit", |
|
flag: "10", |
|
exCpus: []int{10}, |
|
}, |
|
{ |
|
name: "valid double digit range", |
|
flag: "10-12", |
|
exCpus: []int{10, 11, 12}, |
|
}, |
|
{ |
|
name: "valid double digit stride", |
|
flag: "10-20:5", |
|
exCpus: []int{10, 15, 20}, |
|
}, |
|
} |
|
|
|
for _, test := range tests { |
|
t.Run(test.name, func(t *testing.T) { |
|
cpus, err := perfCPUFlagToCPUs(test.flag) |
|
if test.errStr != "" { |
|
if err != nil { |
|
t.Fatal("expected error to not be nil") |
|
} |
|
if test.errStr != err.Error() { |
|
t.Fatalf( |
|
"expected error %q, got %q", |
|
test.errStr, |
|
err.Error(), |
|
) |
|
} |
|
return |
|
} |
|
if err != nil { |
|
t.Fatal(err) |
|
} |
|
if len(cpus) != len(test.exCpus) { |
|
t.Fatalf( |
|
"expected CPUs %v, got %v", |
|
test.exCpus, |
|
cpus, |
|
) |
|
} |
|
for i := range cpus { |
|
if test.exCpus[i] != cpus[i] { |
|
t.Fatalf( |
|
"expected CPUs %v, got %v", |
|
test.exCpus[i], |
|
cpus[i], |
|
) |
|
} |
|
} |
|
}) |
|
} |
|
} |
|
|
|
func TestPerfTracepointFlagToTracepoints(t *testing.T) { |
|
tests := []struct { |
|
name string |
|
flag []string |
|
exTracepoints []*perfTracepoint |
|
errStr string |
|
}{ |
|
{ |
|
name: "valid single tracepoint", |
|
flag: []string{"sched:sched_kthread_stop"}, |
|
exTracepoints: []*perfTracepoint{ |
|
{ |
|
subsystem: "sched", |
|
event: "sched_kthread_stop", |
|
}, |
|
}, |
|
}, |
|
{ |
|
name: "valid multiple tracepoints", |
|
flag: []string{"sched:sched_kthread_stop", "sched:sched_process_fork"}, |
|
exTracepoints: []*perfTracepoint{ |
|
{ |
|
subsystem: "sched", |
|
event: "sched_kthread_stop", |
|
}, |
|
{ |
|
subsystem: "sched", |
|
event: "sched_process_fork", |
|
}, |
|
}, |
|
}, |
|
} |
|
|
|
for _, test := range tests { |
|
t.Run(test.name, func(t *testing.T) { |
|
tracepoints, err := perfTracepointFlagToTracepoints(test.flag) |
|
if test.errStr != "" { |
|
if err != nil { |
|
t.Fatal("expected error to not be nil") |
|
} |
|
if test.errStr != err.Error() { |
|
t.Fatalf( |
|
"expected error %q, got %q", |
|
test.errStr, |
|
err.Error(), |
|
) |
|
} |
|
return |
|
} |
|
if err != nil { |
|
t.Fatal(err) |
|
} |
|
for i := range tracepoints { |
|
if test.exTracepoints[i].event != tracepoints[i].event && |
|
test.exTracepoints[i].subsystem != tracepoints[i].subsystem { |
|
t.Fatalf( |
|
"expected tracepoint %v, got %v", |
|
test.exTracepoints[i], |
|
tracepoints[i], |
|
) |
|
} |
|
} |
|
}) |
|
} |
|
}
|
|
|