151 lines
4.1 KiB
Go
151 lines
4.1 KiB
Go
|
//go:build linux && amd64
|
||
|
|
||
|
package intel_pmu
|
||
|
|
||
|
import (
|
||
|
"errors"
|
||
|
"fmt"
|
||
|
"strings"
|
||
|
|
||
|
ia "github.com/intel/iaevents"
|
||
|
|
||
|
"github.com/influxdata/telegraf"
|
||
|
)
|
||
|
|
||
|
type entitiesResolver interface {
|
||
|
resolveEntities(coreEntities []*coreEventEntity, uncoreEntities []*uncoreEventEntity) error
|
||
|
}
|
||
|
|
||
|
type iaEntitiesResolver struct {
|
||
|
reader ia.Reader
|
||
|
transformer ia.Transformer
|
||
|
log telegraf.Logger
|
||
|
}
|
||
|
|
||
|
func (e *iaEntitiesResolver) resolveEntities(coreEntities []*coreEventEntity, uncoreEntities []*uncoreEventEntity) error {
|
||
|
for _, entity := range coreEntities {
|
||
|
if entity == nil {
|
||
|
return errors.New("core entity is nil")
|
||
|
}
|
||
|
if entity.allEvents {
|
||
|
newEvents, _, err := e.resolveAllEvents()
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("failed to resolve all events: %w", err)
|
||
|
}
|
||
|
entity.parsedEvents = newEvents
|
||
|
continue
|
||
|
}
|
||
|
for _, event := range entity.parsedEvents {
|
||
|
if event == nil {
|
||
|
return errors.New("parsed core event is nil")
|
||
|
}
|
||
|
customEvent, err := e.resolveEvent(event.name, event.qualifiers)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("failed to resolve core event %q: %w", event.name, err)
|
||
|
}
|
||
|
if customEvent.Event.Uncore {
|
||
|
return fmt.Errorf("uncore event %q found in core entity", event.name)
|
||
|
}
|
||
|
event.custom = customEvent
|
||
|
}
|
||
|
}
|
||
|
for _, entity := range uncoreEntities {
|
||
|
if entity == nil {
|
||
|
return errors.New("uncore entity is nil")
|
||
|
}
|
||
|
if entity.allEvents {
|
||
|
_, newEvents, err := e.resolveAllEvents()
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("failed to resolve all events: %w", err)
|
||
|
}
|
||
|
entity.parsedEvents = newEvents
|
||
|
continue
|
||
|
}
|
||
|
for _, event := range entity.parsedEvents {
|
||
|
if event == nil {
|
||
|
return errors.New("parsed uncore event is nil")
|
||
|
}
|
||
|
customEvent, err := e.resolveEvent(event.name, event.qualifiers)
|
||
|
if err != nil {
|
||
|
return fmt.Errorf("failed to resolve uncore event %q: %w", event.name, err)
|
||
|
}
|
||
|
if !customEvent.Event.Uncore {
|
||
|
return fmt.Errorf("core event %q found in uncore entity", event.name)
|
||
|
}
|
||
|
event.custom = customEvent
|
||
|
}
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func (e *iaEntitiesResolver) resolveAllEvents() (coreEvents, uncoreEvents []*eventWithQuals, err error) {
|
||
|
if e.transformer == nil {
|
||
|
return nil, nil, errors.New("transformer is nil")
|
||
|
}
|
||
|
|
||
|
perfEvents, err := e.transformer.Transform(e.reader, ia.NewNameMatcher())
|
||
|
if err != nil {
|
||
|
var re *ia.TransformationError
|
||
|
if !errors.As(err, &re) {
|
||
|
return nil, nil, err
|
||
|
}
|
||
|
if e.log != nil && re != nil {
|
||
|
var eventErrs []string
|
||
|
for _, eventErr := range re.Errors() {
|
||
|
if eventErr == nil {
|
||
|
continue
|
||
|
}
|
||
|
eventErrs = append(eventErrs, eventErr.Error())
|
||
|
}
|
||
|
errorsStr := strings.Join(eventErrs, ",\n")
|
||
|
e.log.Warnf("Cannot resolve all of the events from provided files:\n%s.\nSome events may be omitted.", errorsStr)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for _, perfEvent := range perfEvents {
|
||
|
newEvent := &eventWithQuals{
|
||
|
name: perfEvent.Name,
|
||
|
custom: ia.CustomizableEvent{Event: perfEvent},
|
||
|
}
|
||
|
// build options for event
|
||
|
newEvent.custom.Options, err = ia.NewOptions().Build()
|
||
|
if err != nil {
|
||
|
return nil, nil, fmt.Errorf("failed to build options for event %q: %w", perfEvent.Name, err)
|
||
|
}
|
||
|
if perfEvent.Uncore {
|
||
|
uncoreEvents = append(uncoreEvents, newEvent)
|
||
|
continue
|
||
|
}
|
||
|
coreEvents = append(coreEvents, newEvent)
|
||
|
}
|
||
|
return coreEvents, uncoreEvents, nil
|
||
|
}
|
||
|
|
||
|
func (e *iaEntitiesResolver) resolveEvent(name string, qualifiers []string) (ia.CustomizableEvent, error) {
|
||
|
var custom ia.CustomizableEvent
|
||
|
if e.transformer == nil {
|
||
|
return custom, errors.New("events transformer is nil")
|
||
|
}
|
||
|
if name == "" {
|
||
|
return custom, errors.New("event name is empty")
|
||
|
}
|
||
|
matcher := ia.NewNameMatcher(name)
|
||
|
perfEvents, err := e.transformer.Transform(e.reader, matcher)
|
||
|
if err != nil {
|
||
|
return custom, fmt.Errorf("failed to transform perf events: %w", err)
|
||
|
}
|
||
|
if len(perfEvents) < 1 {
|
||
|
return custom, fmt.Errorf("failed to resolve unknown event %q", name)
|
||
|
}
|
||
|
// build options for event
|
||
|
options, err := ia.NewOptions().SetAttrModifiers(qualifiers).Build()
|
||
|
if err != nil {
|
||
|
return custom, fmt.Errorf("failed to build options for event %q: %w", name, err)
|
||
|
}
|
||
|
custom = ia.CustomizableEvent{
|
||
|
Event: perfEvents[0],
|
||
|
Options: options,
|
||
|
}
|
||
|
return custom, nil
|
||
|
}
|