Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions cmd/metrics/event_defs.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func LoadEventGroups(eventDefinitionOverridePath string, metadata Metadata) (gro
if len(group) > 0 {
groups = append(groups, group)
} else {
slog.Warn("No collectable events in group", slog.String("ending", line))
slog.Debug("No collectable events in group", slog.String("ending", line))
}
group = GroupDefinition{} // clear the list
}
Expand All @@ -90,7 +90,7 @@ func LoadEventGroups(eventDefinitionOverridePath string, metadata Metadata) (gro
groups, err = expandUncoreGroups(groups, metadata)

if uncollectable.Cardinality() != 0 {
slog.Warn("Events not collectable on target", slog.String("events", uncollectable.String()))
slog.Debug("Events not collectable on target", slog.String("events", uncollectable.String()))
}
return
}
Expand Down
67 changes: 37 additions & 30 deletions cmd/metrics/event_frame.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,22 +110,27 @@ func GetEventFrames(rawEvents [][]byte, eventGroupDefinitions []GroupDefinition,
}

// parseEvents parses the raw event data into a list of Event
func parseEvents(rawEvents [][]byte, eventGroupDefinitions []GroupDefinition) (events []Event, err error) {
events = make([]Event, 0, len(rawEvents))
func parseEvents(rawEvents [][]byte, eventGroupDefinitions []GroupDefinition) ([]Event, error) {
events := make([]Event, 0, len(rawEvents))
groupIdx := 0
eventIdx := -1
previousEvent := ""
var eventsNotCounted []string
var eventsNotSupported []string
for _, rawEvent := range rawEvents {
var event Event
if event, err = parseEventJSON(rawEvent); err != nil { // nosemgrep
if strings.Contains(err.Error(), "unrecognized event format") {
slog.Error(err.Error(), slog.String("event", string(rawEvent)))
return
} else {
slog.Debug(err.Error(), slog.String("event", string(rawEvent)))
event.Value = math.NaN()
err = nil
}
event, err := parseEventJSON(rawEvent) // nosemgrep
if err != nil {
slog.Error(err.Error(), slog.String("event", string(rawEvent)))
return nil, err
}
if event.CounterValue == "<not counted>" {
slog.Debug("event not counted", slog.String("event", string(rawEvent)))
eventsNotCounted = append(eventsNotCounted, event.Event)
event.Value = math.NaN()
} else if event.CounterValue == "<not supported>" {
slog.Debug("event not supported", slog.String("event", string(rawEvent)))
eventsNotSupported = append(eventsNotSupported, event.Event)
event.Value = math.NaN()
}
if event.Event != previousEvent {
eventIdx++
Expand All @@ -134,19 +139,25 @@ func parseEvents(rawEvents [][]byte, eventGroupDefinitions []GroupDefinition) (e
if eventIdx == len(eventGroupDefinitions[groupIdx]) { // last event in group
groupIdx++
if groupIdx == len(eventGroupDefinitions) {
// if in cgroup scope, we receive one set of events for each cgroup
if flagScope == scopeCgroup {
groupIdx = 0
} else {
err = fmt.Errorf("event group definitions not aligning with raw events")
return
return nil, fmt.Errorf("event group definitions not aligning with raw events")
}
}
eventIdx = 0
}
event.Group = groupIdx
events = append(events, event)
}
return
if len(eventsNotCounted) > 0 {
slog.Warn("events not counted", slog.String("events", strings.Join(eventsNotCounted, ",")))
}
if len(eventsNotSupported) > 0 {
slog.Warn("events not supported", slog.String("events", strings.Join(eventsNotSupported, ",")))
}
return events, nil
}

// coalesceEvents separates the events into a number of event lists by granularity and scope
Expand Down Expand Up @@ -354,22 +365,18 @@ func collapseUncoreGroups(inGroups []EventGroup, firstIdx int, count int) (outGr

// parseEventJSON parses JSON formatted event into struct
// example: {"interval" : 5.005113019, "cpu": "0", "counter-value" : "22901873.000000", "unit" : "", "cgroup" : "...1cb2de.scope", "event" : "L1D.REPLACEMENT", "event-runtime" : 80081151765, "pcnt-running" : 6.00, "metric-value" : 0.000000, "metric-unit" : "(null)"}
func parseEventJSON(rawEvent []byte) (event Event, err error) {
if err = json.Unmarshal(rawEvent, &event); err != nil {
func parseEventJSON(rawEvent []byte) (Event, error) {
var event Event
if err := json.Unmarshal(rawEvent, &event); err != nil {
err = fmt.Errorf("unrecognized event format: \"%s\"", rawEvent)
return
return event, err
}
if event.CounterValue == "<not supported>" {
err = fmt.Errorf("event not supported: \"%s\"", rawEvent)
return
}
if event.CounterValue == "<not counted>" {
err = fmt.Errorf("event not counted: \"%s\"", rawEvent)
return
}
if event.Value, err = strconv.ParseFloat(event.CounterValue, 64); err != nil {
err = fmt.Errorf("failed to parse event value as float: \"%s\"", rawEvent)
return
if !strings.Contains(event.CounterValue, "not counted") && !strings.Contains(event.CounterValue, "not supported") {
var err error
if event.Value, err = strconv.ParseFloat(event.CounterValue, 64); err != nil {
slog.Error("failed to parse event value", slog.String("event", event.Event), slog.String("value", event.CounterValue))
event.Value = math.NaN()
}
}
return
return event, nil
}
22 changes: 16 additions & 6 deletions cmd/metrics/metrics.go
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ func getFlagGroups() []common.FlagGroup {
},
{
Name: flagRefreshName,
Help: "number of seconds to run before refreshing the \"hot\" or \"filtered\" process or cgroup list",
Help: "number of seconds to run before refreshing the \"hot\" or \"filtered\" process or cgroup list. If 0, the list will not be refreshed.",
},
}
groups = append(groups, common.FlagGroup{
Expand Down Expand Up @@ -436,15 +436,14 @@ func validateFlags(cmd *cobra.Command, args []string) error {
return common.FlagValidationError(cmd, "cannot specify refresh when duration is set")
}
// if refresh is less than 1, error
if flagRefresh < 1 {
return common.FlagValidationError(cmd, "refresh must be greater than 0")
if flagRefresh < 0 {
return common.FlagValidationError(cmd, "refresh must be greater than or equal to 0")
}
// if refresh is less than perf print interval, error
if flagRefresh < flagPerfPrintInterval {
return common.FlagValidationError(cmd, fmt.Sprintf("refresh must be greater than or equal to the event collection interval (%d)", flagPerfPrintInterval))
}
}

// output options
// confirm valid granularity
if cmd.Flags().Lookup(flagGranularityName).Changed && !slices.Contains(granularityOptions, flagGranularity) {
Expand All @@ -462,8 +461,19 @@ func validateFlags(cmd *cobra.Command, args []string) error {
}
// advanced options
// confirm valid perf print interval
if cmd.Flags().Lookup(flagPerfPrintIntervalName).Changed && flagPerfPrintInterval < 1 {
return common.FlagValidationError(cmd, "event collection interval must be at least 1 second")
if cmd.Flags().Lookup(flagPerfPrintIntervalName).Changed {
if flagPerfPrintInterval < 1 {
return common.FlagValidationError(cmd, "event collection interval must be at least 1 second")
}
// if perf print interval is greater than duration, error
if flagDuration > 0 && flagPerfPrintInterval > flagDuration {
return common.FlagValidationError(cmd, fmt.Sprintf("event collection interval must be less than or equal to the duration (%d)", flagDuration))
}
// if refresh is relevant, perf print interval must be less than refresh
relevant := flagRefresh > 0 && flagScope != scopeSystem && len(flagPidList) == 0 && len(flagCidList) == 0
if relevant && flagPerfPrintInterval > flagRefresh {
return common.FlagValidationError(cmd, fmt.Sprintf("event collection interval must be less than or equal to the refresh interval (%d)", flagRefresh))
}
}
// confirm valid perf mux interval
if cmd.Flags().Lookup(flagPerfMuxIntervalName).Changed && flagPerfMuxInterval < 10 {
Expand Down