1
0
Fork 0
telegraf/plugins/inputs/intel_pmu/reader_test.go
Daniel Baumann 4978089aab
Adding upstream version 1.34.4.
Signed-off-by: Daniel Baumann <daniel@debian.org>
2025-05-24 07:26:29 +02:00

522 lines
18 KiB
Go

//go:build linux && amd64
package intel_pmu
import (
"errors"
"fmt"
"math"
"testing"
"time"
ia "github.com/intel/iaevents"
"github.com/stretchr/testify/require"
)
type moonClock struct{}
func (moonClock) now() time.Time {
return time.Date(1969, 7, 20, 20, 17, 0, 0, time.UTC)
}
type eventWithValues struct {
activeEvent *ia.ActiveEvent
values ia.CounterValue
}
func TestReadCoreEvents(t *testing.T) {
mReader := &mockValuesReader{}
mTimer := &moonClock{}
mEntitiesReader := &iaEntitiesValuesReader{mReader, mTimer}
t.Run("event reader is nil", func(t *testing.T) {
metrics, err := (&iaEntitiesValuesReader{timer: moonClock{}}).readCoreEvents(nil)
require.Error(t, err)
require.Contains(t, err.Error(), "event values reader or timer is nil")
require.Nil(t, metrics)
})
t.Run("timer is nil", func(t *testing.T) {
metrics, err := (&iaEntitiesValuesReader{eventReader: &iaValuesReader{}}).readCoreEvents(nil)
require.Error(t, err)
require.Contains(t, err.Error(), "event values reader or timer is nil")
require.Nil(t, metrics)
})
t.Run("entity is nil", func(t *testing.T) {
metrics, err := (&iaEntitiesValuesReader{eventReader: &iaValuesReader{}, timer: moonClock{}}).readCoreEvents(nil)
require.Error(t, err)
require.Contains(t, err.Error(), "entity is nil")
require.Nil(t, metrics)
})
t.Run("nil events", func(t *testing.T) {
entity := &coreEventEntity{}
entity.activeEvents = append(entity.activeEvents, nil)
metrics, err := mEntitiesReader.readCoreEvents(entity)
require.Error(t, err)
require.Contains(t, err.Error(), "active event or corresponding perf event is nil")
require.Nil(t, metrics)
})
t.Run("reading failed", func(t *testing.T) {
errMock := errors.New("mock error")
event := &ia.ActiveEvent{PerfEvent: &ia.PerfEvent{Name: "event1"}}
entity := &coreEventEntity{}
entity.activeEvents = append(entity.activeEvents, event)
mReader.On("readValue", event).Return(ia.CounterValue{}, errMock).Once()
metrics, err := mEntitiesReader.readCoreEvents(entity)
require.Error(t, err)
require.Contains(t, err.Error(), fmt.Sprintf("failed to read core event %q values: %v", event, errMock))
require.Nil(t, metrics)
mReader.AssertExpectations(t)
})
t.Run("read active events values", func(t *testing.T) {
entity := &coreEventEntity{}
var expected []coreMetric
tEvents := []eventWithValues{
{&ia.ActiveEvent{PerfEvent: &ia.PerfEvent{Name: "event1"}}, ia.CounterValue{Raw: 316, Enabled: 182060524, Running: 182060524}},
{&ia.ActiveEvent{PerfEvent: &ia.PerfEvent{Name: "event2"}}, ia.CounterValue{Raw: 1238901, Enabled: 18234123, Running: 18234123}},
{&ia.ActiveEvent{PerfEvent: &ia.PerfEvent{Name: "event3"}}, ia.CounterValue{Raw: 412323, Enabled: 1823132, Running: 1823180}},
}
for _, tc := range tEvents {
entity.activeEvents = append(entity.activeEvents, tc.activeEvent)
cpu, _ := tc.activeEvent.PMUPlacement()
newMetric := coreMetric{
values: tc.values,
tag: entity.EventsTag,
cpu: cpu,
name: tc.activeEvent.PerfEvent.Name,
time: mTimer.now(),
}
expected = append(expected, newMetric)
mReader.On("readValue", tc.activeEvent).Return(tc.values, nil).Once()
}
metrics, err := mEntitiesReader.readCoreEvents(entity)
require.NoError(t, err)
require.Equal(t, expected, metrics)
mReader.AssertExpectations(t)
})
}
func TestReadMultiEventSeparately(t *testing.T) {
mReader := &mockValuesReader{}
mTimer := &moonClock{}
mEntitiesReader := &iaEntitiesValuesReader{mReader, mTimer}
t.Run("event reader is nil", func(t *testing.T) {
event := multiEvent{}
metrics, err := (&iaEntitiesValuesReader{timer: moonClock{}}).readMultiEventSeparately(event)
require.Error(t, err)
require.Contains(t, err.Error(), "event values reader or timer is nil")
require.Nil(t, metrics)
})
t.Run("timer is nil", func(t *testing.T) {
event := multiEvent{}
metrics, err := (&iaEntitiesValuesReader{eventReader: &iaValuesReader{}}).readMultiEventSeparately(event)
require.Error(t, err)
require.Contains(t, err.Error(), "event values reader or timer is nil")
require.Nil(t, metrics)
})
t.Run("multi event is nil", func(t *testing.T) {
event := multiEvent{}
metrics, err := (&iaEntitiesValuesReader{&iaValuesReader{}, moonClock{}}).readMultiEventSeparately(event)
require.Error(t, err)
require.Contains(t, err.Error(), "no active events or perf event is nil")
require.Nil(t, metrics)
})
t.Run("reading failed", func(t *testing.T) {
errMock := errors.New("mock error")
perfEvent := &ia.PerfEvent{Name: "event"}
event := &ia.ActiveEvent{PerfEvent: perfEvent}
multi := multiEvent{perfEvent: perfEvent, activeEvents: []*ia.ActiveEvent{event}}
mReader.On("readValue", event).Return(ia.CounterValue{}, errMock).Once()
metrics, err := mEntitiesReader.readMultiEventSeparately(multi)
require.Error(t, err)
require.Contains(t, err.Error(), fmt.Sprintf("failed to read uncore event %q values: %v", event, errMock))
require.Nil(t, metrics)
mReader.AssertExpectations(t)
})
t.Run("read active events values", func(t *testing.T) {
perfEvent := &ia.PerfEvent{Name: "event", PMUName: "pmu name"}
multi := multiEvent{perfEvent: perfEvent}
var expected []uncoreMetric
tEvents := []eventWithValues{
{&ia.ActiveEvent{PerfEvent: perfEvent}, ia.CounterValue{Raw: 316, Enabled: 182060524, Running: 182060524}},
{&ia.ActiveEvent{PerfEvent: perfEvent}, ia.CounterValue{Raw: 1238901, Enabled: 18234123, Running: 18234123}},
{&ia.ActiveEvent{PerfEvent: perfEvent}, ia.CounterValue{Raw: 412323, Enabled: 1823132, Running: 1823180}},
}
for _, tc := range tEvents {
multi.activeEvents = append(multi.activeEvents, tc.activeEvent)
newMetric := uncoreMetric{
values: tc.values,
socket: multi.socket,
unitType: multi.perfEvent.PMUName,
name: multi.perfEvent.Name,
unit: tc.activeEvent.PMUName(),
time: mTimer.now(),
}
expected = append(expected, newMetric)
mReader.On("readValue", tc.activeEvent).Return(tc.values, nil).Once()
}
metrics, err := mEntitiesReader.readMultiEventSeparately(multi)
require.NoError(t, err)
require.Equal(t, expected, metrics)
mReader.AssertExpectations(t)
})
}
func TestReadMultiEventAgg(t *testing.T) {
mReader := &mockValuesReader{}
mTimer := &moonClock{}
mEntitiesReader := &iaEntitiesValuesReader{mReader, mTimer}
errMock := errors.New("mock error")
t.Run("event reader is nil", func(t *testing.T) {
event := multiEvent{}
_, err := (&iaEntitiesValuesReader{timer: moonClock{}}).readMultiEventAgg(event)
require.Error(t, err)
require.Contains(t, err.Error(), "event values reader or timer is nil")
})
t.Run("timer is nil", func(t *testing.T) {
event := multiEvent{}
_, err := (&iaEntitiesValuesReader{eventReader: &iaValuesReader{}}).readMultiEventAgg(event)
require.Error(t, err)
require.Contains(t, err.Error(), "event values reader or timer is nil")
})
perfEvent := &ia.PerfEvent{Name: "event", PMUName: "pmu name"}
tests := []struct {
name string
multi multiEvent
events []eventWithValues
result ia.CounterValue
readFail bool
errMsg string
}{
{
name: "no events",
multi: multiEvent{perfEvent: perfEvent},
events: nil,
result: ia.CounterValue{},
errMsg: "no active events or perf event is nil",
},
{
name: "no perf event",
multi: multiEvent{perfEvent: nil, activeEvents: []*ia.ActiveEvent{{}, {}}},
events: nil,
result: ia.CounterValue{},
errMsg: "no active events or perf event is nil",
},
{
name: "successful reading and aggregation",
multi: multiEvent{perfEvent: perfEvent},
events: []eventWithValues{
{&ia.ActiveEvent{PerfEvent: perfEvent}, ia.CounterValue{Raw: 5123, Enabled: 1231242, Running: 41123}},
{&ia.ActiveEvent{PerfEvent: perfEvent}, ia.CounterValue{Raw: 4500, Enabled: 1823423, Running: 182343}},
},
result: ia.CounterValue{Raw: 9623, Enabled: 3054665, Running: 223466},
errMsg: "",
},
{
name: "to big numbers",
multi: multiEvent{perfEvent: perfEvent},
events: []eventWithValues{
{&ia.ActiveEvent{PerfEvent: perfEvent}, ia.CounterValue{Raw: math.MaxUint64, Enabled: 0, Running: 0}},
{&ia.ActiveEvent{PerfEvent: perfEvent}, ia.CounterValue{Raw: 1, Enabled: 0, Running: 0}},
},
result: ia.CounterValue{},
errMsg: fmt.Sprintf("cannot aggregate %q values, uint64 exceeding", perfEvent),
},
{
name: "reading fail",
multi: multiEvent{perfEvent: perfEvent},
events: []eventWithValues{
{&ia.ActiveEvent{PerfEvent: perfEvent}, ia.CounterValue{Raw: 0, Enabled: 0, Running: 0}},
},
readFail: true,
result: ia.CounterValue{},
errMsg: "failed to read uncore event",
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
for _, eventWithValue := range test.events {
test.multi.activeEvents = append(test.multi.activeEvents, eventWithValue.activeEvent)
if test.readFail {
mReader.On("readValue", eventWithValue.activeEvent).Return(ia.CounterValue{}, errMock).Once()
continue
}
mReader.On("readValue", eventWithValue.activeEvent).Return(eventWithValue.values, nil).Once()
}
metric, err := mEntitiesReader.readMultiEventAgg(test.multi)
mReader.AssertExpectations(t)
if len(test.errMsg) > 0 {
require.Error(t, err)
require.Contains(t, err.Error(), test.errMsg)
return
}
expected := uncoreMetric{
values: test.result,
socket: test.multi.socket,
unitType: test.multi.perfEvent.PMUName,
name: test.multi.perfEvent.Name,
time: mTimer.now(),
}
require.NoError(t, err)
require.Equal(t, expected, metric)
})
}
}
func TestReadUncoreEvents(t *testing.T) {
errMock := errors.New("mock error")
t.Run("entity is nil", func(t *testing.T) {
metrics, err := (&iaEntitiesValuesReader{}).readUncoreEvents(nil)
require.Error(t, err)
require.Contains(t, err.Error(), "entity is nil")
require.Nil(t, metrics)
})
t.Run("read aggregated entities", func(t *testing.T) {
mReader := &mockValuesReader{}
mTimer := &moonClock{}
mEntitiesReader := &iaEntitiesValuesReader{mReader, mTimer}
perfEvent := &ia.PerfEvent{Name: "mock event", PMUName: "cbox", PMUTypes: []ia.NamedPMUType{{Name: "cbox"}}}
perfEvent2 := &ia.PerfEvent{Name: "mock event2", PMUName: "rad", PMUTypes: []ia.NamedPMUType{{Name: "rad2"}}}
multi := multiEvent{perfEvent: perfEvent}
events := []eventWithValues{
{&ia.ActiveEvent{PerfEvent: perfEvent}, ia.CounterValue{Raw: 2003}},
{&ia.ActiveEvent{PerfEvent: perfEvent}, ia.CounterValue{Raw: 4005}},
}
multi2 := multiEvent{perfEvent: perfEvent2}
events2 := []eventWithValues{
{&ia.ActiveEvent{PerfEvent: perfEvent2}, ia.CounterValue{Raw: 2003}},
{&ia.ActiveEvent{PerfEvent: perfEvent2}, ia.CounterValue{Raw: 123005}},
}
for _, event := range events {
multi.activeEvents = append(multi.activeEvents, event.activeEvent)
mReader.On("readValue", event.activeEvent).Return(event.values, nil).Once()
}
for _, event := range events2 {
multi2.activeEvents = append(multi2.activeEvents, event.activeEvent)
mReader.On("readValue", event.activeEvent).Return(event.values, nil).Once()
}
newMetric := uncoreMetric{
values: ia.CounterValue{Raw: 6008, Enabled: 0, Running: 0},
socket: multi.socket,
unitType: perfEvent.PMUName,
name: perfEvent.Name,
time: mTimer.now(),
}
newMetric2 := uncoreMetric{
values: ia.CounterValue{Raw: 125008, Enabled: 0, Running: 0},
socket: multi2.socket,
unitType: perfEvent2.PMUName,
name: perfEvent2.Name,
time: mTimer.now(),
}
expected := []uncoreMetric{newMetric, newMetric2}
entityAgg := &uncoreEventEntity{Aggregate: true, activeMultiEvents: []multiEvent{multi, multi2}}
metrics, err := mEntitiesReader.readUncoreEvents(entityAgg)
require.NoError(t, err)
require.Equal(t, expected, metrics)
mReader.AssertExpectations(t)
t.Run("reading error", func(t *testing.T) {
event := &ia.ActiveEvent{PerfEvent: perfEvent}
multi := multiEvent{perfEvent: perfEvent, activeEvents: []*ia.ActiveEvent{event}}
mReader.On("readValue", event).Return(ia.CounterValue{}, errMock).Once()
entityAgg := &uncoreEventEntity{Aggregate: true, activeMultiEvents: []multiEvent{multi}}
metrics, err = mEntitiesReader.readUncoreEvents(entityAgg)
require.Error(t, err)
require.Nil(t, metrics)
mReader.AssertExpectations(t)
})
})
t.Run("read distributed entities", func(t *testing.T) {
mReader := &mockValuesReader{}
mTimer := &moonClock{}
mEntitiesReader := &iaEntitiesValuesReader{mReader, mTimer}
perfEvent := &ia.PerfEvent{Name: "mock event", PMUName: "cbox", PMUTypes: []ia.NamedPMUType{{Name: "cbox"}}}
perfEvent2 := &ia.PerfEvent{Name: "mock event2", PMUName: "rad", PMUTypes: []ia.NamedPMUType{{Name: "rad2"}}}
multi := multiEvent{perfEvent: perfEvent, socket: 2}
events := []eventWithValues{
{&ia.ActiveEvent{PerfEvent: perfEvent}, ia.CounterValue{Raw: 2003}},
{&ia.ActiveEvent{PerfEvent: perfEvent}, ia.CounterValue{Raw: 4005}},
}
multi2 := multiEvent{perfEvent: perfEvent2, socket: 1}
events2 := []eventWithValues{
{&ia.ActiveEvent{PerfEvent: perfEvent2}, ia.CounterValue{Raw: 2003}},
{&ia.ActiveEvent{PerfEvent: perfEvent2}, ia.CounterValue{Raw: 123005}},
}
var expected []uncoreMetric
for _, event := range events {
multi.activeEvents = append(multi.activeEvents, event.activeEvent)
mReader.On("readValue", event.activeEvent).Return(event.values, nil).Once()
newMetric := uncoreMetric{
values: event.values,
socket: multi.socket,
unitType: perfEvent.PMUName,
name: perfEvent.Name,
unit: event.activeEvent.PMUName(),
time: mTimer.now(),
}
expected = append(expected, newMetric)
}
for _, event := range events2 {
multi2.activeEvents = append(multi2.activeEvents, event.activeEvent)
mReader.On("readValue", event.activeEvent).Return(event.values, nil).Once()
newMetric := uncoreMetric{
values: event.values,
socket: multi2.socket,
unitType: perfEvent2.PMUName,
name: perfEvent2.Name,
unit: event.activeEvent.PMUName(),
time: mTimer.now(),
}
expected = append(expected, newMetric)
}
entity := &uncoreEventEntity{activeMultiEvents: []multiEvent{multi, multi2}}
metrics, err := mEntitiesReader.readUncoreEvents(entity)
require.NoError(t, err)
require.Equal(t, expected, metrics)
mReader.AssertExpectations(t)
t.Run("reading error", func(t *testing.T) {
event := &ia.ActiveEvent{PerfEvent: perfEvent}
multi := multiEvent{perfEvent: perfEvent, activeEvents: []*ia.ActiveEvent{event}}
mReader.On("readValue", event).Return(ia.CounterValue{}, errMock).Once()
entityAgg := &uncoreEventEntity{activeMultiEvents: []multiEvent{multi}}
metrics, err = mEntitiesReader.readUncoreEvents(entityAgg)
require.Error(t, err)
require.Nil(t, metrics)
mReader.AssertExpectations(t)
})
})
}
func TestReadEntities(t *testing.T) {
mReader := &mockValuesReader{}
mTimer := &moonClock{}
mEntitiesReader := &iaEntitiesValuesReader{mReader, mTimer}
t.Run("read entities", func(t *testing.T) {
values := ia.CounterValue{}
socket := 0
corePerfEvent := &ia.PerfEvent{Name: "core event 1", PMUName: "cpu"}
activeCoreEvent := []*ia.ActiveEvent{{PerfEvent: corePerfEvent}}
coreMetric1 := coreMetric{values: values, name: corePerfEvent.Name, time: mTimer.now()}
corePerfEvent2 := &ia.PerfEvent{Name: "core event 2", PMUName: "cpu"}
activeCoreEvent2 := []*ia.ActiveEvent{{PerfEvent: corePerfEvent2}}
coreMetric2 := coreMetric{values: values, name: corePerfEvent2.Name, time: mTimer.now()}
uncorePerfEvent := &ia.PerfEvent{Name: "uncore event 1", PMUName: "cbox"}
activeUncoreEvent := []*ia.ActiveEvent{{PerfEvent: uncorePerfEvent}}
uncoreMetric1 := uncoreMetric{
values: values,
name: uncorePerfEvent.Name,
unitType: uncorePerfEvent.PMUName,
socket: socket,
time: mTimer.now(),
}
uncorePerfEvent2 := &ia.PerfEvent{Name: "uncore event 2", PMUName: "rig"}
activeUncoreEvent2 := []*ia.ActiveEvent{{PerfEvent: uncorePerfEvent2}}
uncoreMetric2 := uncoreMetric{
values: values,
name: uncorePerfEvent2.Name,
unitType: uncorePerfEvent2.PMUName,
socket: socket,
time: mTimer.now(),
}
coreEntities := []*coreEventEntity{{activeEvents: activeCoreEvent}, {activeEvents: activeCoreEvent2}}
uncoreEntities := []*uncoreEventEntity{
{activeMultiEvents: []multiEvent{{activeEvents: activeUncoreEvent, perfEvent: uncorePerfEvent, socket: socket}}},
{activeMultiEvents: []multiEvent{{activeEvents: activeUncoreEvent2, perfEvent: uncorePerfEvent2, socket: socket}}},
}
expectedCoreMetrics := []coreMetric{coreMetric1, coreMetric2}
expectedUncoreMetrics := []uncoreMetric{uncoreMetric1, uncoreMetric2}
mReader.On("readValue", activeCoreEvent[0]).Return(values, nil).Once()
mReader.On("readValue", activeCoreEvent2[0]).Return(values, nil).Once()
mReader.On("readValue", activeUncoreEvent[0]).Return(values, nil).Once()
mReader.On("readValue", activeUncoreEvent2[0]).Return(values, nil).Once()
coreMetrics, uncoreMetrics, err := mEntitiesReader.readEntities(coreEntities, uncoreEntities)
require.NoError(t, err)
require.Equal(t, expectedCoreMetrics, coreMetrics)
require.NotNil(t, expectedUncoreMetrics, uncoreMetrics)
mReader.AssertExpectations(t)
})
t.Run("core entity reading failed", func(t *testing.T) {
coreEntities := []*coreEventEntity{nil}
coreMetrics, uncoreMetrics, err := mEntitiesReader.readEntities(coreEntities, nil)
require.Error(t, err)
require.Contains(t, err.Error(), "entity is nil")
require.Nil(t, coreMetrics)
require.Nil(t, uncoreMetrics)
})
t.Run("uncore entity reading failed", func(t *testing.T) {
uncoreEntities := []*uncoreEventEntity{nil}
coreMetrics, uncoreMetrics, err := mEntitiesReader.readEntities(nil, uncoreEntities)
require.Error(t, err)
require.Contains(t, err.Error(), "entity is nil")
require.Nil(t, coreMetrics)
require.Nil(t, uncoreMetrics)
})
}