377 lines
13 KiB
Go
377 lines
13 KiB
Go
//go:build linux && amd64
|
|
|
|
package intel_pmu
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"testing"
|
|
|
|
ia "github.com/intel/iaevents"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/influxdata/telegraf/testutil"
|
|
)
|
|
|
|
func TestResolveEntities(t *testing.T) {
|
|
errMock := errors.New("mock error")
|
|
mLog := testutil.Logger{}
|
|
mTransformer := &MockTransformer{}
|
|
mResolver := &iaEntitiesResolver{transformer: mTransformer, log: mLog}
|
|
|
|
type test struct {
|
|
perfEvent *ia.PerfEvent
|
|
options ia.Options
|
|
event *eventWithQuals
|
|
}
|
|
|
|
t.Run("nil entities", func(t *testing.T) {
|
|
err := mResolver.resolveEntities([]*coreEventEntity{nil}, nil)
|
|
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "core entity is nil")
|
|
|
|
err = mResolver.resolveEntities(nil, []*uncoreEventEntity{nil})
|
|
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "uncore entity is nil")
|
|
})
|
|
|
|
t.Run("nil parsed events", func(t *testing.T) {
|
|
mCoreEntity := &coreEventEntity{parsedEvents: []*eventWithQuals{nil, nil}}
|
|
mUncoreEntity := &uncoreEventEntity{parsedEvents: []*eventWithQuals{nil, nil}}
|
|
|
|
err := mResolver.resolveEntities([]*coreEventEntity{mCoreEntity}, nil)
|
|
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "parsed core event is nil")
|
|
|
|
err = mResolver.resolveEntities(nil, []*uncoreEventEntity{mUncoreEntity})
|
|
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "parsed uncore event is nil")
|
|
})
|
|
|
|
t.Run("fail to resolve core events", func(t *testing.T) {
|
|
name := "mock event 1"
|
|
mCoreEntity := &coreEventEntity{parsedEvents: []*eventWithQuals{{name: name}}, allEvents: false}
|
|
matcher := ia.NewNameMatcher(name)
|
|
|
|
mTransformer.On("Transform", nil, matcher).Once().Return(nil, errMock)
|
|
err := mResolver.resolveEntities([]*coreEventEntity{mCoreEntity}, nil)
|
|
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), fmt.Sprintf("failed to resolve core event %q", name))
|
|
mTransformer.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("fail to resolve uncore events", func(t *testing.T) {
|
|
name := "mock event 1"
|
|
mUncoreEntity := &uncoreEventEntity{parsedEvents: []*eventWithQuals{{name: name}}, allEvents: false}
|
|
matcher := ia.NewNameMatcher(name)
|
|
|
|
mTransformer.On("Transform", nil, matcher).Once().Return(nil, errMock)
|
|
err := mResolver.resolveEntities(nil, []*uncoreEventEntity{mUncoreEntity})
|
|
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), fmt.Sprintf("failed to resolve uncore event %q", name))
|
|
mTransformer.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("resolve all core and uncore events", func(t *testing.T) {
|
|
mCoreEntity := &coreEventEntity{allEvents: true}
|
|
mUncoreEntity := &uncoreEventEntity{allEvents: true}
|
|
corePerfEvents := []*ia.PerfEvent{
|
|
{Name: "core event1"},
|
|
{Name: "core event2"},
|
|
{Name: "core event3"},
|
|
}
|
|
uncorePerfEvents := []*ia.PerfEvent{
|
|
{Name: "uncore event1", Uncore: true},
|
|
{Name: "uncore event2", Uncore: true},
|
|
{Name: "uncore event3", Uncore: true},
|
|
}
|
|
matcher := ia.NewNameMatcher()
|
|
|
|
t.Run("fail to resolve all core events", func(t *testing.T) {
|
|
mTransformer.On("Transform", nil, matcher).Once().Return(nil, errMock)
|
|
err := mResolver.resolveEntities([]*coreEventEntity{mCoreEntity}, nil)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "failed to resolve all events")
|
|
mTransformer.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("fail to resolve all uncore events", func(t *testing.T) {
|
|
mTransformer.On("Transform", nil, matcher).Once().Return(nil, errMock)
|
|
err := mResolver.resolveEntities(nil, []*uncoreEventEntity{mUncoreEntity})
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "failed to resolve all events")
|
|
mTransformer.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("fail to resolve all events with transformationError", func(t *testing.T) {
|
|
transformErr := &ia.TransformationError{}
|
|
|
|
mTransformer.On("Transform", nil, matcher).Once().Return(corePerfEvents, transformErr).Once()
|
|
mTransformer.On("Transform", nil, matcher).Once().Return(uncorePerfEvents, transformErr).Once()
|
|
|
|
err := mResolver.resolveEntities([]*coreEventEntity{mCoreEntity}, []*uncoreEventEntity{mUncoreEntity})
|
|
require.NoError(t, err)
|
|
require.Len(t, mCoreEntity.parsedEvents, len(corePerfEvents))
|
|
require.Len(t, mUncoreEntity.parsedEvents, len(uncorePerfEvents))
|
|
for _, coreEvent := range mCoreEntity.parsedEvents {
|
|
require.Contains(t, corePerfEvents, coreEvent.custom.Event)
|
|
}
|
|
for _, uncoreEvent := range mUncoreEntity.parsedEvents {
|
|
require.Contains(t, uncorePerfEvents, uncoreEvent.custom.Event)
|
|
}
|
|
mTransformer.AssertExpectations(t)
|
|
})
|
|
|
|
mTransformer.On("Transform", nil, matcher).Once().Return(corePerfEvents, nil).Once()
|
|
mTransformer.On("Transform", nil, matcher).Once().Return(uncorePerfEvents, nil).Once()
|
|
|
|
err := mResolver.resolveEntities([]*coreEventEntity{mCoreEntity}, []*uncoreEventEntity{mUncoreEntity})
|
|
require.NoError(t, err)
|
|
require.Len(t, mCoreEntity.parsedEvents, len(corePerfEvents))
|
|
require.Len(t, mUncoreEntity.parsedEvents, len(uncorePerfEvents))
|
|
for _, coreEvent := range mCoreEntity.parsedEvents {
|
|
require.Contains(t, corePerfEvents, coreEvent.custom.Event)
|
|
}
|
|
for _, uncoreEvent := range mUncoreEntity.parsedEvents {
|
|
require.Contains(t, uncorePerfEvents, uncoreEvent.custom.Event)
|
|
}
|
|
mTransformer.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("uncore event found in core entity", func(t *testing.T) {
|
|
mQuals := []string{"config1=0x23h"}
|
|
eventName := "uncore event 1"
|
|
|
|
testCase := test{
|
|
event: &eventWithQuals{name: eventName, qualifiers: mQuals},
|
|
perfEvent: &ia.PerfEvent{Name: eventName, Uncore: true},
|
|
}
|
|
|
|
matcher := ia.NewNameMatcher(eventName)
|
|
mTransformer.On("Transform", nil, matcher).Return([]*ia.PerfEvent{testCase.perfEvent}, nil).Once()
|
|
|
|
mCoreEntity := &coreEventEntity{parsedEvents: []*eventWithQuals{testCase.event}, allEvents: false}
|
|
err := mResolver.resolveEntities([]*coreEventEntity{mCoreEntity}, nil)
|
|
require.ErrorContains(t, err, fmt.Sprintf("uncore event %q found in core entity", eventName))
|
|
mTransformer.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("core event found in uncore entity", func(t *testing.T) {
|
|
mQuals := []string{"config1=0x23h"}
|
|
eventName := "core event 1"
|
|
|
|
testCase := test{
|
|
event: &eventWithQuals{name: eventName, qualifiers: mQuals},
|
|
perfEvent: &ia.PerfEvent{Name: eventName, Uncore: false},
|
|
}
|
|
|
|
matcher := ia.NewNameMatcher(eventName)
|
|
mTransformer.On("Transform", nil, matcher).Return([]*ia.PerfEvent{testCase.perfEvent}, nil).Once()
|
|
|
|
mUncoreEntity := &uncoreEventEntity{parsedEvents: []*eventWithQuals{testCase.event}, allEvents: false}
|
|
err := mResolver.resolveEntities(nil, []*uncoreEventEntity{mUncoreEntity})
|
|
|
|
require.ErrorContains(t, err, fmt.Sprintf("core event %q found in uncore entity", eventName))
|
|
mTransformer.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("resolve core and uncore events", func(t *testing.T) {
|
|
var mCoreEvents []*eventWithQuals
|
|
var nUncoreEvents []*eventWithQuals
|
|
|
|
mQuals := []string{"config1=0x23h"}
|
|
mOptions, err := ia.NewOptions().SetAttrModifiers(mQuals).Build()
|
|
require.NoError(t, err)
|
|
emptyOptions, err := ia.NewOptions().Build()
|
|
require.NoError(t, err)
|
|
|
|
coreTestCases := []test{
|
|
{event: &eventWithQuals{name: "core1", qualifiers: mQuals},
|
|
options: mOptions,
|
|
perfEvent: &ia.PerfEvent{Name: "core1"}},
|
|
{event: &eventWithQuals{name: "core2", qualifiers: nil},
|
|
options: emptyOptions,
|
|
perfEvent: &ia.PerfEvent{Name: "core2"}},
|
|
{event: &eventWithQuals{name: "core3", qualifiers: nil},
|
|
options: emptyOptions,
|
|
perfEvent: &ia.PerfEvent{Name: "core3"}},
|
|
}
|
|
uncoreTestCases := []test{
|
|
{event: &eventWithQuals{name: "uncore1", qualifiers: mQuals},
|
|
options: mOptions,
|
|
perfEvent: &ia.PerfEvent{Name: "uncore1", Uncore: true}},
|
|
{event: &eventWithQuals{name: "uncore2", qualifiers: nil},
|
|
options: emptyOptions,
|
|
perfEvent: &ia.PerfEvent{Name: "uncore2", Uncore: true}},
|
|
{event: &eventWithQuals{name: "uncore3", qualifiers: nil},
|
|
options: emptyOptions,
|
|
perfEvent: &ia.PerfEvent{Name: "uncore3", Uncore: true}},
|
|
}
|
|
|
|
for _, test := range coreTestCases {
|
|
matcher := ia.NewNameMatcher(test.event.name)
|
|
mTransformer.On("Transform", nil, matcher).Return([]*ia.PerfEvent{test.perfEvent}, nil).Once()
|
|
mCoreEvents = append(mCoreEvents, test.event)
|
|
}
|
|
|
|
for _, test := range uncoreTestCases {
|
|
matcher := ia.NewNameMatcher(test.event.name)
|
|
mTransformer.On("Transform", nil, matcher).Return([]*ia.PerfEvent{test.perfEvent}, nil).Once()
|
|
nUncoreEvents = append(nUncoreEvents, test.event)
|
|
}
|
|
|
|
mCoreEntity := &coreEventEntity{parsedEvents: mCoreEvents, allEvents: false}
|
|
mUncoreEntity := &uncoreEventEntity{parsedEvents: nUncoreEvents, allEvents: false}
|
|
err = mResolver.resolveEntities([]*coreEventEntity{mCoreEntity}, []*uncoreEventEntity{mUncoreEntity})
|
|
|
|
require.NoError(t, err)
|
|
for _, test := range append(coreTestCases, uncoreTestCases...) {
|
|
require.Equal(t, test.perfEvent, test.event.custom.Event)
|
|
require.Equal(t, test.options, test.event.custom.Options)
|
|
}
|
|
mTransformer.AssertExpectations(t)
|
|
})
|
|
}
|
|
|
|
func TestResolveAllEvents(t *testing.T) {
|
|
mTransformer := &MockTransformer{}
|
|
|
|
mResolver := &iaEntitiesResolver{transformer: mTransformer}
|
|
|
|
t.Run("transformer is nil", func(t *testing.T) {
|
|
mResolver := &iaEntitiesResolver{transformer: nil}
|
|
_, _, err := mResolver.resolveAllEvents()
|
|
require.Error(t, err)
|
|
})
|
|
|
|
t.Run("transformer returns error", func(t *testing.T) {
|
|
matcher := ia.NewNameMatcher()
|
|
mTransformer.On("Transform", nil, matcher).Once().Return(nil, errors.New("mock error"))
|
|
|
|
_, _, err := mResolver.resolveAllEvents()
|
|
require.Error(t, err)
|
|
mTransformer.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("no events", func(t *testing.T) {
|
|
matcher := ia.NewNameMatcher()
|
|
mTransformer.On("Transform", nil, matcher).Once().Return(nil, nil)
|
|
|
|
_, _, err := mResolver.resolveAllEvents()
|
|
require.NoError(t, err)
|
|
mTransformer.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("successfully resolved events", func(t *testing.T) {
|
|
perfEvent1 := &ia.PerfEvent{Name: "mock1"}
|
|
perfEvent2 := &ia.PerfEvent{Name: "mock2"}
|
|
uncorePerfEvent1 := &ia.PerfEvent{Name: "mock3", Uncore: true}
|
|
uncorePerfEvent2 := &ia.PerfEvent{Name: "mock4", Uncore: true}
|
|
|
|
options, err := ia.NewOptions().Build()
|
|
require.NoError(t, err)
|
|
perfEvents := []*ia.PerfEvent{perfEvent1, perfEvent2, uncorePerfEvent1, uncorePerfEvent2}
|
|
|
|
expectedCore := []*eventWithQuals{
|
|
{name: perfEvent1.Name, custom: ia.CustomizableEvent{Event: perfEvent1, Options: options}},
|
|
{name: perfEvent2.Name, custom: ia.CustomizableEvent{Event: perfEvent2, Options: options}},
|
|
}
|
|
|
|
expectedUncore := []*eventWithQuals{
|
|
{name: uncorePerfEvent1.Name, custom: ia.CustomizableEvent{Event: uncorePerfEvent1, Options: options}},
|
|
{name: uncorePerfEvent2.Name, custom: ia.CustomizableEvent{Event: uncorePerfEvent2, Options: options}},
|
|
}
|
|
|
|
matcher := ia.NewNameMatcher()
|
|
mTransformer.On("Transform", nil, matcher).Once().Return(perfEvents, nil)
|
|
|
|
coreEvents, uncoreEvents, err := mResolver.resolveAllEvents()
|
|
require.NoError(t, err)
|
|
require.Equal(t, expectedCore, coreEvents)
|
|
require.Equal(t, expectedUncore, uncoreEvents)
|
|
|
|
mTransformer.AssertExpectations(t)
|
|
})
|
|
}
|
|
|
|
func TestResolveEvent(t *testing.T) {
|
|
mTransformer := &MockTransformer{}
|
|
mEvent := "mock event"
|
|
|
|
mResolver := &iaEntitiesResolver{transformer: mTransformer}
|
|
|
|
t.Run("transformer is nil", func(t *testing.T) {
|
|
mResolver := &iaEntitiesResolver{transformer: nil}
|
|
_, err := mResolver.resolveEvent("event", nil)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "events transformer is nil")
|
|
})
|
|
|
|
t.Run("event is empty", func(t *testing.T) {
|
|
_, err := mResolver.resolveEvent("", nil)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "event name is empty")
|
|
})
|
|
|
|
t.Run("transformer returns error", func(t *testing.T) {
|
|
matcher := ia.NewNameMatcher(mEvent)
|
|
mTransformer.On("Transform", nil, matcher).Once().Return(nil, errors.New("mock error"))
|
|
|
|
_, err := mResolver.resolveEvent(mEvent, nil)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "failed to transform perf events")
|
|
mTransformer.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("no events transformed", func(t *testing.T) {
|
|
matcher := ia.NewNameMatcher(mEvent)
|
|
mTransformer.On("Transform", nil, matcher).Once().Return(nil, nil)
|
|
|
|
_, err := mResolver.resolveEvent(mEvent, nil)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "failed to resolve unknown event")
|
|
mTransformer.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("not valid qualifiers", func(t *testing.T) {
|
|
event := "mock event 1"
|
|
qualifiers := []string{"wrong modifiers"}
|
|
|
|
matcher := ia.NewNameMatcher(event)
|
|
mPerfEvent := &ia.PerfEvent{Name: event}
|
|
mPerfEvents := []*ia.PerfEvent{mPerfEvent}
|
|
mTransformer.On("Transform", nil, matcher).Once().Return(mPerfEvents, nil)
|
|
|
|
_, err := mResolver.resolveEvent(event, qualifiers)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), fmt.Sprintf("failed to build options for event %q", event))
|
|
mTransformer.AssertExpectations(t)
|
|
})
|
|
|
|
t.Run("successfully transformed", func(t *testing.T) {
|
|
event := "mock event 1"
|
|
qualifiers := []string{"config1=0x012h", "config2=0x034k"}
|
|
|
|
matcher := ia.NewNameMatcher(event)
|
|
|
|
mPerfEvent := &ia.PerfEvent{Name: event}
|
|
mPerfEvents := []*ia.PerfEvent{mPerfEvent}
|
|
|
|
expectedOptions, err := ia.NewOptions().SetAttrModifiers(qualifiers).Build()
|
|
require.NoError(t, err)
|
|
|
|
mTransformer.On("Transform", nil, matcher).Once().Return(mPerfEvents, nil)
|
|
|
|
customEvent, err := mResolver.resolveEvent(event, qualifiers)
|
|
require.NoError(t, err)
|
|
require.Equal(t, mPerfEvent, customEvent.Event)
|
|
require.Equal(t, expectedOptions, customEvent.Options)
|
|
mTransformer.AssertExpectations(t)
|
|
})
|
|
}
|