-
Notifications
You must be signed in to change notification settings - Fork 590
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
perf(expr): new interface for expression directly returning scalar #9049
Conversation
Signed-off-by: Bugen Zhao <i@bugenzhao.com>
Signed-off-by: Bugen Zhao <i@bugenzhao.com>
Signed-off-by: Bugen Zhao <i@bugenzhao.com>
Signed-off-by: Bugen Zhao <i@bugenzhao.com>
Signed-off-by: Bugen Zhao <i@bugenzhao.com>
Signed-off-by: Bugen Zhao <i@bugenzhao.com>
@@ -205,6 +205,15 @@ fn bench_expr(c: &mut Criterion) { | |||
.to_async(FuturesExecutor) | |||
.iter(|| constant.eval(&input)) | |||
}); | |||
c.bench_function("extract(constant)", |bencher| { |
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 is there any general way to construct this test case. :(
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.
I guess not... Let's keep it manual construction :(
Codecov Report
@@ Coverage Diff @@
## main #9049 +/- ##
==========================================
- Coverage 70.78% 70.77% -0.01%
==========================================
Files 1195 1196 +1
Lines 197687 197696 +9
==========================================
+ Hits 139926 139927 +1
- Misses 57761 57769 +8
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 9 files with indirect coverage changes 📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
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.
Looks both good and hacky to me at the same time 🥵
🤔 This seems kind of "lazy evaluation" (or "late materialization"?): executor still use |
async fn eval(&self, input: &DataChunk) -> Result<ArrayRef>; | ||
/// The default implementation calls `eval` and puts the result into the `Array` variant. | ||
async fn eval_new(&self, input: &DataChunk) -> Result<ValueImpl> { | ||
self.eval(input).map_ok(ValueImpl::Array).await |
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.
So it stackoverflows if both not implemented? 😄
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.
Yes. 🥵 Not sure if there's a way to avoid this.
src/expr/src/expr/template.rs
Outdated
// Otherwise, fallback to array computation. | ||
// TODO: match all possible combinations to further get rid of the overhead of `Either` iterators. |
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.
Wait, so EXTRACT(HOUR FROM col)
still fallbacks to array computation? Then where's the improvement from? 🥵
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.
For execution, yes. The difference is that we're not allocating a new array for HOUR
now. Instead, iter
here directly calls repeat().take()
.
Signed-off-by: Bugen Zhao <i@bugenzhao.com>
Not that hacky. 🥵 Actually I borrow the ideas partially from https://github.com/datafuselabs/databend/blob/a3ac38f838eb37e8ea5600d526e7d1b2f3c0bb50/src/query/expression/src/evaluator.rs#L138. |
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.
Generally LGTM!
@@ -205,6 +205,15 @@ fn bench_expr(c: &mut Criterion) { | |||
.to_async(FuturesExecutor) | |||
.iter(|| constant.eval(&input)) | |||
}); | |||
c.bench_function("extract(constant)", |bencher| { |
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.
I guess not... Let's keep it manual construction :(
Signed-off-by: Bugen Zhao <i@bugenzhao.com>
Signed-off-by: Bugen Zhao i@bugenzhao.comI hereby agree to the terms of the RisingWave Labs, Inc. Contributor License Agreement.
What's changed and what's your intention?
Do not repeat the literal value 1024 times when evaluating an expression that usually takes a literal as one input like
EXTRACT(HOUR FROM col)
. (#9052)The simplified implementation for demo purposes is here. Briefly, we introduce a new interface of
Expr::eval_new
(temporary name) which returns eitherArray
, or directlyDatum
if the return value is supposed to be a constant array. When using the return value as argument, theDatum
variant can be directly iterated withrepeat.take
instead of allocating a real array.The
eval_new
is bidirectionally compatible witheval
by always falling back to theArray
variant, so most of the hand-written expressions are not touched in this PR. Instead, we rewrite the implementation witheval_new
for all templated expressions, and apply the optimization toexpr_literal
.Either
as the iterator.template_fast
is not touched as we're not sure whether this breaks SIMD.Checklist For Contributors
./risedev check
(or alias,./risedev c
)Checklist For Reviewers
Documentation
Click here for Documentation
Types of user-facing changes
Please keep the types that apply to your changes, and remove the others.
Release note