1
0
Fork 0
telegraf/plugins/inputs/intel_pmu/activators_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

431 lines
17 KiB
Go

//go:build linux && amd64
package intel_pmu
import (
"errors"
"fmt"
"testing"
ia "github.com/intel/iaevents"
"github.com/stretchr/testify/require"
)
type mockPlacementFactory struct {
err bool
}
func (m *mockPlacementFactory) NewPlacements(_ string, cpu int, cpus ...int) ([]ia.PlacementProvider, error) {
if m.err {
return nil, errors.New("mock error")
}
placements := []ia.PlacementProvider{
&ia.Placement{CPU: cpu, PMUType: 4},
}
for _, cpu := range cpus {
placements = append(placements, &ia.Placement{CPU: cpu, PMUType: 4})
}
return placements, nil
}
func TestActivateEntities(t *testing.T) {
mEntitiesActivator := &iaEntitiesActivator{}
// more core test cases in TestActivateCoreEvents
t.Run("failed to activate core events", func(t *testing.T) {
tag := "TAG"
mEntities := []*coreEventEntity{{EventsTag: tag}}
err := mEntitiesActivator.activateEntities(mEntities, nil)
require.Error(t, err)
require.Contains(t, err.Error(), fmt.Sprintf("failed to activate core events %q", tag))
})
// more uncore test cases in TestActivateUncoreEvents
t.Run("failed to activate uncore events", func(t *testing.T) {
tag := "TAG"
mEntities := []*uncoreEventEntity{{EventsTag: tag}}
err := mEntitiesActivator.activateEntities(nil, mEntities)
require.Error(t, err)
require.Contains(t, err.Error(), fmt.Sprintf("failed to activate uncore events %q", tag))
})
t.Run("nothing to do", func(t *testing.T) {
err := mEntitiesActivator.activateEntities(nil, nil)
require.NoError(t, err)
})
}
func TestActivateUncoreEvents(t *testing.T) {
mActivator := &mockEventsActivator{}
mMaker := &mockPlacementMaker{}
errMock := errors.New("error mock")
t.Run("entity is nil", func(t *testing.T) {
mEntitiesActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: mActivator}
err := mEntitiesActivator.activateUncoreEvents(nil)
require.Error(t, err)
require.Contains(t, err.Error(), "uncore events entity is nil")
})
t.Run("event is nil", func(t *testing.T) {
mEntitiesActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: mActivator}
mEntity := &uncoreEventEntity{parsedEvents: []*eventWithQuals{nil, nil}}
err := mEntitiesActivator.activateUncoreEvents(mEntity)
require.Error(t, err)
require.Contains(t, err.Error(), "uncore parsed event is nil")
})
t.Run("perf event is nil", func(t *testing.T) {
mEntitiesActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: mActivator}
name := "event name"
mEntity := &uncoreEventEntity{parsedEvents: []*eventWithQuals{{name: name, custom: ia.CustomizableEvent{Event: nil}}}}
err := mEntitiesActivator.activateUncoreEvents(mEntity)
require.Error(t, err)
require.Contains(t, err.Error(), fmt.Sprintf("perf event of %q event is nil", name))
})
t.Run("placement maker and perf activator is nil", func(t *testing.T) {
mEntitiesActivator := &iaEntitiesActivator{placementMaker: nil, perfActivator: nil}
err := mEntitiesActivator.activateUncoreEvents(&uncoreEventEntity{})
require.Error(t, err)
require.Contains(t, err.Error(), "events activator or placement maker is nil")
})
t.Run("failed to create placements", func(t *testing.T) {
mEntitiesActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: mActivator}
eventName := "mock event 1"
parsedEvents := []*eventWithQuals{{name: eventName, custom: ia.CustomizableEvent{Event: &ia.PerfEvent{Name: eventName}}}}
mEntity := &uncoreEventEntity{parsedEvents: parsedEvents, parsedSockets: []int{0, 1, 2}}
mMaker.On("makeUncorePlacements", parsedEvents[0].custom.Event, mEntity.parsedSockets[0]).Return(nil, errMock).Once()
err := mEntitiesActivator.activateUncoreEvents(mEntity)
require.Error(t, err)
require.Contains(t, err.Error(), fmt.Sprintf("ailed to create uncore placements for event %q", eventName))
mMaker.AssertExpectations(t)
})
t.Run("failed to activate event", func(t *testing.T) {
mEntitiesActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: mActivator}
eventName := "mock event 1"
parsedEvents := []*eventWithQuals{{name: eventName, custom: ia.CustomizableEvent{Event: &ia.PerfEvent{Name: eventName}}}}
placements := []ia.PlacementProvider{&ia.Placement{CPU: 0}, &ia.Placement{CPU: 1}}
mEntity := &uncoreEventEntity{parsedEvents: parsedEvents, parsedSockets: []int{0, 1, 2}}
mMaker.On("makeUncorePlacements", parsedEvents[0].custom.Event, mEntity.parsedSockets[0]).Return(placements, nil).Once()
mActivator.On("activateMulti", parsedEvents[0].custom.Event, placements, parsedEvents[0].custom.Options).Return(nil, errMock).Once()
err := mEntitiesActivator.activateUncoreEvents(mEntity)
require.Error(t, err)
require.Contains(t, err.Error(), fmt.Sprintf("failed to activate multi event %q", eventName))
mMaker.AssertExpectations(t)
mActivator.AssertExpectations(t)
})
t.Run("successfully activate core events", func(t *testing.T) {
mEntitiesActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: mActivator}
parsedEvents := []*eventWithQuals{
{custom: ia.CustomizableEvent{Event: &ia.PerfEvent{Name: "mock event 1", Uncore: true}}},
{custom: ia.CustomizableEvent{Event: &ia.PerfEvent{Name: "mock event 2", Uncore: true}}},
{custom: ia.CustomizableEvent{Event: &ia.PerfEvent{Name: "mock event 3", Uncore: true}}},
{custom: ia.CustomizableEvent{Event: &ia.PerfEvent{Name: "mock event 4", Uncore: true}}},
}
mEntity := &uncoreEventEntity{parsedEvents: parsedEvents, parsedSockets: []int{0, 1, 2}}
placements := []ia.PlacementProvider{&ia.Placement{}, &ia.Placement{}, &ia.Placement{}}
var expectedEvents []multiEvent
for _, event := range parsedEvents {
for _, socket := range mEntity.parsedSockets {
mMaker.On("makeUncorePlacements", event.custom.Event, socket).Return(placements, nil).Once()
newActiveMultiEvent := &ia.ActiveMultiEvent{}
expectedEvents = append(expectedEvents, multiEvent{newActiveMultiEvent.Events(), event.custom.Event, socket})
mActivator.On("activateMulti", event.custom.Event, placements, event.custom.Options).Return(newActiveMultiEvent, nil).Once()
}
}
err := mEntitiesActivator.activateUncoreEvents(mEntity)
require.NoError(t, err)
require.Equal(t, expectedEvents, mEntity.activeMultiEvents)
mMaker.AssertExpectations(t)
mActivator.AssertExpectations(t)
})
}
func TestActivateCoreEvents(t *testing.T) {
mMaker := &mockPlacementMaker{}
mActivator := &mockEventsActivator{}
errMock := errors.New("error mock")
t.Run("entity is nil", func(t *testing.T) {
mEntitiesActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: mActivator}
err := mEntitiesActivator.activateCoreEvents(nil)
require.Error(t, err)
require.Contains(t, err.Error(), "core events entity is nil")
})
t.Run("placement maker is nil", func(t *testing.T) {
mEntitiesActivator := &iaEntitiesActivator{placementMaker: nil, perfActivator: mActivator}
err := mEntitiesActivator.activateCoreEvents(&coreEventEntity{})
require.Error(t, err)
require.Contains(t, err.Error(), "placement maker is nil")
})
t.Run("event is nil", func(t *testing.T) {
mEntitiesActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: mActivator}
mEntity := &coreEventEntity{parsedEvents: []*eventWithQuals{nil, nil}}
err := mEntitiesActivator.activateCoreEvents(mEntity)
require.Error(t, err)
require.Contains(t, err.Error(), "core parsed event is nil")
})
t.Run("failed to create placements", func(t *testing.T) {
mEntitiesActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: mActivator}
parsedEvents := []*eventWithQuals{{name: "mock event 1", custom: ia.CustomizableEvent{Event: &ia.PerfEvent{Name: "mock event 1"}}}}
mEntity := &coreEventEntity{PerfGroup: false, parsedEvents: parsedEvents, parsedCores: []int{0, 1, 2}}
mMaker.On("makeCorePlacements", mEntity.parsedCores, parsedEvents[0].custom.Event).Return(nil, errMock).Once()
err := mEntitiesActivator.activateCoreEvents(mEntity)
require.Error(t, err)
require.Contains(t, err.Error(), fmt.Sprintf("failed to create core placements for event %q", parsedEvents[0].name))
mMaker.AssertExpectations(t)
})
t.Run("failed to activate event", func(t *testing.T) {
mEntitiesActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: mActivator}
parsedEvents := []*eventWithQuals{{name: "mock event 1", custom: ia.CustomizableEvent{Event: &ia.PerfEvent{Name: "mock event 1"}}}}
placements := []ia.PlacementProvider{&ia.Placement{CPU: 0}, &ia.Placement{CPU: 1}}
mEntity := &coreEventEntity{PerfGroup: false, parsedEvents: parsedEvents, parsedCores: []int{0, 1, 2}}
event := parsedEvents[0]
plc := placements[0]
mMaker.On("makeCorePlacements", mEntity.parsedCores, event.custom.Event).Return(placements, nil).Once()
mActivator.On("activateEvent", event.custom.Event, plc, event.custom.Options).Return(nil, errMock).Once()
err := mEntitiesActivator.activateCoreEvents(mEntity)
require.Error(t, err)
require.Contains(t, err.Error(), fmt.Sprintf("failed to activate core event %q", parsedEvents[0].name))
mMaker.AssertExpectations(t)
mActivator.AssertExpectations(t)
})
t.Run("failed to activate core events group", func(t *testing.T) {
mEntitiesActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: nil}
mEntity := &coreEventEntity{PerfGroup: true, parsedEvents: nil}
err := mEntitiesActivator.activateCoreEvents(mEntity)
require.Error(t, err)
require.Contains(t, err.Error(), "failed to activate core events group")
})
t.Run("successfully activate core events", func(t *testing.T) {
mEntitiesActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: mActivator}
parsedEvents := []*eventWithQuals{
{custom: ia.CustomizableEvent{Event: &ia.PerfEvent{Name: "mock event 1"}}},
{custom: ia.CustomizableEvent{Event: &ia.PerfEvent{Name: "mock event 2"}}},
{custom: ia.CustomizableEvent{Event: &ia.PerfEvent{Name: "mock event 3"}}},
{custom: ia.CustomizableEvent{Event: &ia.PerfEvent{Name: "mock event 4"}}},
}
placements := []ia.PlacementProvider{&ia.Placement{CPU: 0}, &ia.Placement{CPU: 1}, &ia.Placement{CPU: 2}}
mEntity := &coreEventEntity{PerfGroup: false, parsedEvents: parsedEvents, parsedCores: []int{0, 1, 2}}
var activeEvents []*ia.ActiveEvent
for _, event := range parsedEvents {
mMaker.On("makeCorePlacements", mEntity.parsedCores, event.custom.Event).Return(placements, nil).Once()
for _, plc := range placements {
newActiveEvent := &ia.ActiveEvent{PerfEvent: event.custom.Event}
activeEvents = append(activeEvents, newActiveEvent)
mActivator.On("activateEvent", event.custom.Event, plc, event.custom.Options).Return(newActiveEvent, nil).Once()
}
}
err := mEntitiesActivator.activateCoreEvents(mEntity)
require.NoError(t, err)
require.Equal(t, activeEvents, mEntity.activeEvents)
mMaker.AssertExpectations(t)
mActivator.AssertExpectations(t)
})
}
func TestActivateCoreEventsGroup(t *testing.T) {
mMaker := &mockPlacementMaker{}
mActivator := &mockEventsActivator{}
eActivator := &iaEntitiesActivator{placementMaker: mMaker, perfActivator: mActivator}
errMock := errors.New("mock error")
leader := &ia.PerfEvent{Name: "mock event 1"}
perfEvent2 := &ia.PerfEvent{Name: "mock event 2"}
parsedEvents := []*eventWithQuals{{custom: ia.CustomizableEvent{Event: leader}}, {custom: ia.CustomizableEvent{Event: perfEvent2}}}
placements := []ia.PlacementProvider{&ia.Placement{}, &ia.Placement{}}
// cannot populate this struct due to unexported events field
activeGroup := &ia.ActiveEventGroup{}
mEntity := &coreEventEntity{
EventsTag: "mock group",
PerfGroup: true,
parsedEvents: parsedEvents,
parsedCores: nil,
}
events := make([]ia.CustomizableEvent, 0, len(parsedEvents))
for _, event := range parsedEvents {
events = append(events, event.custom)
}
t.Run("missing perf activator and placement maker", func(t *testing.T) {
mActivator := &iaEntitiesActivator{}
err := mActivator.activateCoreEventsGroup(nil)
require.Error(t, err)
require.Contains(t, err.Error(), "missing perf activator or placement maker")
})
t.Run("missing parsed events", func(t *testing.T) {
mActivator := &iaEntitiesActivator{placementMaker: &mockPlacementMaker{}, perfActivator: &mockEventsActivator{}}
err := mActivator.activateCoreEventsGroup(nil)
require.Error(t, err)
require.Contains(t, err.Error(), "missing parsed events")
})
t.Run("nil in parsed event", func(t *testing.T) {
mEntity := &coreEventEntity{EventsTag: "Nice tag", PerfGroup: true, parsedEvents: []*eventWithQuals{nil, nil}}
err := eActivator.activateCoreEventsGroup(mEntity)
require.Error(t, err)
require.Contains(t, err.Error(), "core event is nil")
})
t.Run("failed to make core placements", func(t *testing.T) {
mMaker.On("makeCorePlacements", mEntity.parsedCores, leader).Return(nil, errMock).Once()
err := eActivator.activateCoreEventsGroup(mEntity)
require.Error(t, err)
require.Contains(t, err.Error(), "failed to make core placements")
mMaker.AssertExpectations(t)
})
t.Run("failed to activate group", func(t *testing.T) {
mMaker.On("makeCorePlacements", mEntity.parsedCores, leader).Return(placements, nil).Once()
mActivator.On("activateGroup", placements[0], events).Return(nil, errMock).Once()
err := eActivator.activateCoreEventsGroup(mEntity)
require.Error(t, err)
require.Contains(t, err.Error(), errMock.Error())
mMaker.AssertExpectations(t)
mActivator.AssertExpectations(t)
})
var allActive []*ia.ActiveEvent
t.Run("successfully activated group", func(t *testing.T) {
mMaker.On("makeCorePlacements", mEntity.parsedCores, leader).Return(placements, nil).Once()
for _, plc := range placements {
mActivator.On("activateGroup", plc, events).Return(activeGroup, nil).Once()
allActive = append(allActive, activeGroup.Events()...)
}
err := eActivator.activateCoreEventsGroup(mEntity)
require.NoError(t, err)
require.Equal(t, allActive, mEntity.activeEvents)
mMaker.AssertExpectations(t)
mActivator.AssertExpectations(t)
})
}
func TestMakeCorePlacements(t *testing.T) {
tests := []struct {
name string
cores []int
perfEvent ia.PlacementFactory
result []ia.PlacementProvider
errMsg string
}{
{"no cores", nil, &ia.PerfEvent{}, nil, "no cores provided"},
{"one core placement", []int{1}, &mockPlacementFactory{}, []ia.PlacementProvider{&ia.Placement{CPU: 1, PMUType: 4}}, ""},
{"multiple core placement", []int{1, 2, 4}, &mockPlacementFactory{}, []ia.PlacementProvider{
&ia.Placement{CPU: 1, PMUType: 4},
&ia.Placement{CPU: 2, PMUType: 4},
&ia.Placement{CPU: 4, PMUType: 4}},
""},
{"placement factory error", []int{1}, &mockPlacementFactory{true}, nil, "mock error"},
{"placement factory error 2", []int{1, 2, 3}, &mockPlacementFactory{true}, nil, "mock error"},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
maker := &iaPlacementMaker{}
providers, err := maker.makeCorePlacements(test.cores, test.perfEvent)
if len(test.errMsg) > 0 {
require.Error(t, err)
require.Nil(t, providers)
require.Contains(t, err.Error(), test.errMsg)
return
}
require.NoError(t, err)
require.Equal(t, test.result, providers)
})
}
}
func TestActivateEventForPlacement(t *testing.T) {
placement1 := &ia.Placement{CPU: 0}
placement2 := &ia.Placement{CPU: 1}
placement3 := &ia.Placement{CPU: 2}
mPlacements := []ia.PlacementProvider{placement1, placement2, placement3}
mPerfEvent := &ia.PerfEvent{Name: "mock1"}
mOptions := &ia.PerfEventOptions{}
mEvent := &eventWithQuals{name: mPerfEvent.Name, custom: ia.CustomizableEvent{Event: mPerfEvent, Options: mOptions}}
mPerfActivator := &mockEventsActivator{}
mActivator := &iaEntitiesActivator{perfActivator: mPerfActivator}
t.Run("event is nil", func(t *testing.T) {
activeEvents, err := mActivator.activateEventForPlacements(nil, mPlacements)
require.Error(t, err)
require.Contains(t, err.Error(), "core event is nil")
require.Empty(t, activeEvents)
})
t.Run("perf activator is nil", func(t *testing.T) {
mActivator := &iaEntitiesActivator{}
activeEvents, err := mActivator.activateEventForPlacements(mEvent, mPlacements)
require.Error(t, err)
require.Contains(t, err.Error(), "missing perf activator")
require.Empty(t, activeEvents)
})
t.Run("placements are nil", func(t *testing.T) {
activeEvents, err := mActivator.activateEventForPlacements(mEvent, nil)
require.NoError(t, err)
require.Empty(t, activeEvents)
})
t.Run("activation error", func(t *testing.T) {
mPerfActivator.On("activateEvent", mPerfEvent, placement1, mOptions).Once().Return(nil, errors.New("err"))
activeEvents, err := mActivator.activateEventForPlacements(mEvent, mPlacements)
require.Error(t, err)
require.Contains(t, err.Error(), fmt.Sprintf("failed to activate event %q", mEvent.name))
require.Nil(t, activeEvents)
mPerfActivator.AssertExpectations(t)
})
t.Run("successfully activated", func(t *testing.T) {
mActiveEvent := &ia.ActiveEvent{}
mActiveEvent2 := &ia.ActiveEvent{}
mActiveEvent3 := &ia.ActiveEvent{}
mPerfActivator.On("activateEvent", mPerfEvent, placement1, mOptions).Once().Return(mActiveEvent, nil).
On("activateEvent", mPerfEvent, placement2, mOptions).Once().Return(mActiveEvent2, nil).
On("activateEvent", mPerfEvent, placement3, mOptions).Once().Return(mActiveEvent3, nil)
activeEvents, err := mActivator.activateEventForPlacements(mEvent, mPlacements)
require.NoError(t, err)
require.Len(t, activeEvents, len(mPlacements))
require.Contains(t, activeEvents, mActiveEvent)
require.Contains(t, activeEvents, mActiveEvent2)
mPerfActivator.AssertExpectations(t)
})
}