//go:build linux && amd64 package intel_pmu import ( "errors" "fmt" ia "github.com/intel/iaevents" ) type placementMaker interface { makeCorePlacements(cores []int, factory ia.PlacementFactory) ([]ia.PlacementProvider, error) makeUncorePlacements(socket int, factory ia.PlacementFactory) ([]ia.PlacementProvider, error) } type iaPlacementMaker struct{} func (iaPlacementMaker) makeCorePlacements(cores []int, factory ia.PlacementFactory) ([]ia.PlacementProvider, error) { var err error var corePlacements []ia.PlacementProvider switch len(cores) { case 0: return nil, errors.New("no cores provided") case 1: corePlacements, err = ia.NewCorePlacements(factory, cores[0]) if err != nil { return nil, err } default: corePlacements, err = ia.NewCorePlacements(factory, cores[0], cores[1:]...) if err != nil { return nil, err } } return corePlacements, nil } func (iaPlacementMaker) makeUncorePlacements(socket int, factory ia.PlacementFactory) ([]ia.PlacementProvider, error) { return ia.NewUncoreAllPlacements(factory, socket) } type eventsActivator interface { activateEvent(ia.Activator, ia.PlacementProvider, ia.Options) (*ia.ActiveEvent, error) activateGroup(ia.PlacementProvider, []ia.CustomizableEvent) (*ia.ActiveEventGroup, error) activateMulti(ia.MultiActivator, []ia.PlacementProvider, ia.Options) (*ia.ActiveMultiEvent, error) } type iaEventsActivator struct{} func (iaEventsActivator) activateEvent(a ia.Activator, p ia.PlacementProvider, o ia.Options) (*ia.ActiveEvent, error) { return a.Activate(p, ia.NewEventTargetProcess(-1, 0), o) } func (iaEventsActivator) activateGroup(p ia.PlacementProvider, e []ia.CustomizableEvent) (*ia.ActiveEventGroup, error) { return ia.ActivateGroup(p, ia.NewEventTargetProcess(-1, 0), e) } func (iaEventsActivator) activateMulti(a ia.MultiActivator, p []ia.PlacementProvider, o ia.Options) (*ia.ActiveMultiEvent, error) { return a.ActivateMulti(p, ia.NewEventTargetProcess(-1, 0), o) } type entitiesActivator interface { activateEntities(coreEntities []*coreEventEntity, uncoreEntities []*uncoreEventEntity) error } type iaEntitiesActivator struct { placementMaker placementMaker perfActivator eventsActivator } func (ea *iaEntitiesActivator) activateEntities(coreEntities []*coreEventEntity, uncoreEntities []*uncoreEventEntity) error { for _, coreEventsEntity := range coreEntities { err := ea.activateCoreEvents(coreEventsEntity) if err != nil { return fmt.Errorf("failed to activate core events %q: %w", coreEventsEntity.EventsTag, err) } } for _, uncoreEventsEntity := range uncoreEntities { err := ea.activateUncoreEvents(uncoreEventsEntity) if err != nil { return fmt.Errorf("failed to activate uncore events %q: %w", uncoreEventsEntity.EventsTag, err) } } return nil } func (ea *iaEntitiesActivator) activateCoreEvents(entity *coreEventEntity) error { if entity == nil { return errors.New("core events entity is nil") } if ea.placementMaker == nil { return errors.New("placement maker is nil") } if entity.PerfGroup { err := ea.activateCoreEventsGroup(entity) if err != nil { return fmt.Errorf("failed to activate core events group: %w", err) } } else { for _, event := range entity.parsedEvents { if event == nil { return errors.New("core parsed event is nil") } placements, err := ea.placementMaker.makeCorePlacements(entity.parsedCores, event.custom.Event) if err != nil { return fmt.Errorf("failed to create core placements for event %q: %w", event.name, err) } activeEvents, err := ea.activateEventForPlacements(event, placements) if err != nil { return fmt.Errorf("failed to activate core event %q: %w", event.name, err) } entity.activeEvents = append(entity.activeEvents, activeEvents...) } } return nil } func (ea *iaEntitiesActivator) activateUncoreEvents(entity *uncoreEventEntity) error { if entity == nil { return errors.New("uncore events entity is nil") } if ea.perfActivator == nil || ea.placementMaker == nil { return errors.New("events activator or placement maker is nil") } for _, event := range entity.parsedEvents { if event == nil { return errors.New("uncore parsed event is nil") } perfEvent := event.custom.Event if perfEvent == nil { return fmt.Errorf("perf event of %q event is nil", event.name) } options := event.custom.Options for _, socket := range entity.parsedSockets { placements, err := ea.placementMaker.makeUncorePlacements(socket, perfEvent) if err != nil { return fmt.Errorf("failed to create uncore placements for event %q: %w", event.name, err) } activeMultiEvent, err := ea.perfActivator.activateMulti(perfEvent, placements, options) if err != nil { return fmt.Errorf("failed to activate multi event %q: %w", event.name, err) } events := activeMultiEvent.Events() entity.activeMultiEvents = append(entity.activeMultiEvents, multiEvent{events, perfEvent, socket}) } } return nil } func (ea *iaEntitiesActivator) activateCoreEventsGroup(entity *coreEventEntity) error { if ea.perfActivator == nil || ea.placementMaker == nil { return errors.New("missing perf activator or placement maker") } if entity == nil || len(entity.parsedEvents) < 1 { return errors.New("missing parsed events") } events := make([]ia.CustomizableEvent, 0, len(entity.parsedEvents)) for _, event := range entity.parsedEvents { if event == nil { return errors.New("core event is nil") } events = append(events, event.custom) } leader := entity.parsedEvents[0].custom placements, err := ea.placementMaker.makeCorePlacements(entity.parsedCores, leader.Event) if err != nil { return fmt.Errorf("failed to make core placements: %w", err) } for _, plc := range placements { activeGroup, err := ea.perfActivator.activateGroup(plc, events) if err != nil { return err } entity.activeEvents = append(entity.activeEvents, activeGroup.Events()...) } return nil } func (ea *iaEntitiesActivator) activateEventForPlacements(event *eventWithQuals, placements []ia.PlacementProvider) ([]*ia.ActiveEvent, error) { if event == nil { return nil, errors.New("core event is nil") } if ea.perfActivator == nil { return nil, errors.New("missing perf activator") } activeEvents := make([]*ia.ActiveEvent, 0, len(placements)) for _, placement := range placements { perfEvent := event.custom.Event options := event.custom.Options activeEvent, err := ea.perfActivator.activateEvent(perfEvent, placement, options) if err != nil { return nil, fmt.Errorf("failed to activate event %q: %w", event.name, err) } activeEvents = append(activeEvents, activeEvent) } return activeEvents, nil }