-
Notifications
You must be signed in to change notification settings - Fork 529
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 improvement: dynamic reordering of binop branches #4163
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
package traceql | ||
|
||
import ( | ||
"time" | ||
|
||
"github.com/grafana/tempo/pkg/tempopb" | ||
"go.opentelemetry.io/otel" | ||
) | ||
|
@@ -81,3 +83,61 @@ func (b *bucketSet) addAndTest(i int) bool { | |
b.buckets[b.sz]++ | ||
return false | ||
} | ||
|
||
const ( | ||
leftBranch = 0 | ||
rightBranch = 1 | ||
) | ||
|
||
type branchOptimizer struct { | ||
start time.Time | ||
last []time.Duration | ||
totals []time.Duration | ||
Recording bool | ||
samplesRemaining int | ||
} | ||
|
||
func newBranchPredictor(numBranches int, numSamples int) branchOptimizer { | ||
return branchOptimizer{ | ||
totals: make([]time.Duration, numBranches), | ||
last: make([]time.Duration, numBranches), | ||
samplesRemaining: numSamples, | ||
Recording: true, | ||
} | ||
} | ||
|
||
// Start recording. Should be called immediately prior to a branch execution. | ||
func (b *branchOptimizer) Start() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about StartRecording and StopRecording? |
||
b.start = time.Now() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why don't we use the same b.last[branch] = time.Now() and in the Finish method: b.last[branch] = time.Since(b.last[branch]) We can rename There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Interesting idea. The variable types are different,
joe-elliott marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
// Finish the recording and temporarily save the cost for the given branch number. | ||
func (b *branchOptimizer) Finish(branch int) { | ||
b.last[branch] = time.Since(b.start) | ||
} | ||
|
||
// Penalize the given branch using it's previously recorded cost. This is called after | ||
// executing all branches and then knowing in retrospect which ones were not needed. | ||
func (b *branchOptimizer) Penalize(branch int) { | ||
b.totals[branch] += b.last[branch] | ||
} | ||
|
||
// Sampled indicates that a full execution was done and see if we have enough samples. | ||
func (b *branchOptimizer) Sampled() (done bool) { | ||
b.samplesRemaining-- | ||
b.Recording = b.samplesRemaining > 0 | ||
return !b.Recording | ||
} | ||
mdisibio marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// OptimalBranch returns the branch with the least penalized cost over time, i.e. the optimal one to start with. | ||
func (b *branchOptimizer) OptimalBranch() int { | ||
mini := 0 | ||
min := b.totals[0] | ||
for i := 1; i < len(b.totals); i++ { | ||
mdisibio marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if b.totals[i] < min { | ||
mini = i | ||
min = b.totals[i] | ||
} | ||
} | ||
return mini | ||
} |
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.
This code is crafted to stay out of the hot-path as much as possible. There may be a way to improve it even further. However I can say that previously pulling LHS.execute into a function pointer made things slower.