-
Notifications
You must be signed in to change notification settings - Fork 521
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
TraceQL performance improvements #4114
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good job!, numbers are awesome
@@ -144,6 +146,7 @@ func (s *span) AttributeFor(a traceql.Attribute) (traceql.Static, bool) { | |||
if attrs[0].a.Name == s { | |||
return &attrs[0].s | |||
} | |||
return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Neat
@@ -230,27 +239,37 @@ func (s *span) AttributeFor(a traceql.Attribute) (traceql.Static, bool) { | |||
|
|||
// name search in span, resource, link, and event to give precedence to span | |||
// we don't need to do a name search at the trace level b/c it is intrinsics only | |||
if attr := findName(a.Name, s.spanAttrs); attr != nil { | |||
return *attr, true | |||
if len(s.spanAttrs) > 0 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why don't we move this logic to the findName method instead? We are already counting the length. We can add a first case:
if len(attrs) == 0 {
return nil
}
We are adding a new entry in the call stack but the code is nicer
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, this way it's skipping the method call entirely, so it ends up faster. I think it's worth it, even though the code is less nice.
@@ -152,47 +155,53 @@ func (s *span) AttributeFor(a traceql.Attribute) (traceql.Static, bool) { | |||
if attrs[1].a.Name == s { | |||
return &attrs[1].s | |||
} | |||
return nil |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure if we could return directly the StaticNil from here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice improvements 🚀
For completeness ran benchmarks on metrics. Nice improvement to the compare() function, some smaller wins for other queriers, although harder to see because they are noiser:
|
* performance improvements * Exit binop early withou evaluating RHS if possible
What this PR does:
Some micro-optimizations to improve traceql engine attribute checks. Search bottleneck is usually in the storage layer, but some complex queries, particularly ones with unscoped attributes, are bottlenecked in the engine.
The memory improvement primarily comes from fixing the for loop in span.AttributeFor.
This loop allocs because the address of the loop var must escape:
But this version doesn't because we take the address of the existing slice entry, which was the intention.
The speed improvement is from also short-circuiting binary operations more like a real compiler if statement does. Two cases can exit early and don't need to evaluate both sides:
This is the main speed improvement in
traceOrMatch
andtraceOrNoMatch
Benchmark
There is a particularly tough query run internally that was the original impetus for this change:
Which issue(s) this PR fixes:
Fixes #
Checklist
CHANGELOG.md
updated - the order of entries should be[CHANGE]
,[FEATURE]
,[ENHANCEMENT]
,[BUGFIX]