Skip to content

Commit

Permalink
Improve encapsulation of expression evaluation classes
Browse files Browse the repository at this point in the history
  • Loading branch information
mbasmanova committed Aug 9, 2021
1 parent 72b008c commit 5aa09fa
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 40 deletions.
21 changes: 16 additions & 5 deletions velox/expression/EvalCtx.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ class EvalCtx {
return row_;
}

velox::memory::MemoryPool* pool() const {
memory::MemoryPool* pool() const {
return execCtx_->pool();
}

Expand Down Expand Up @@ -165,6 +165,21 @@ class EvalCtx {
return exprSet_;
}

VectorEncoding::Simple wrapEncoding() const {
return wrapEncoding_;
}

void setConstantWrap(vector_size_t wrapIndex) {
wrapEncoding_ = VectorEncoding::Simple::CONSTANT;
constantWrapIndex_ = wrapIndex;
}

void setDictionaryWrap(BufferPtr wrap, BufferPtr wrapNulls) {
wrapEncoding_ = VectorEncoding::Simple::DICTIONARY;
wrap_ = std::move(wrap);
wrapNulls_ = std::move(wrapNulls);
}

// Copy "rows" of localResult into results if "result" is partially populated
// and must be preserved. Copy localResult pointer into result otherwise.
void moveOrCopyResult(
Expand Down Expand Up @@ -193,8 +208,6 @@ class EvalCtx {
VectorEncoding::Simple wrapEncoding_ = VectorEncoding::Simple::FLAT;
vector_size_t constantWrapIndex_;

// True if may remember results for positions in selection.
bool mayCache_{false};
bool mayHaveNulls_{false};
bool throwOnError_{true};

Expand All @@ -206,8 +219,6 @@ class EvalCtx {
const SelectivityVector* finalSelection_;

FlatVectorPtr<StringView> errors_;

friend class Expr;
};

class LocalSelectivityVector {
Expand Down
63 changes: 32 additions & 31 deletions velox/expression/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@

#include "velox/expression/Expr.h"
#include "velox/core/Expressions.h"
#include "velox/expression/CastExpr.h"
#include "velox/expression/ControlExpr.h"
#include "velox/expression/ExprCompiler.h"
#include "velox/expression/VarSetter.h"
#include "velox/expression/VectorFunction.h"
#include "velox/expression/VectorFunctionRegistry.h"

namespace facebook::velox::exec {

Expand Down Expand Up @@ -172,6 +174,8 @@ void Expr::eval(
return;
}

// Check if this expression has been evaluated already. If so, fetch and
// return the previously computed result.
if (checkGetSharedSubexprValues(rows, context, result)) {
return;
}
Expand All @@ -194,7 +198,7 @@ bool Expr::checkGetSharedSubexprValues(
// For now, disable the optimization if any encodings have been peeled off.

if (!isMultiplyReferenced_ || !sharedSubexprValues_ ||
context->wrapEncoding_ != VectorEncoding::Simple::FLAT) {
context->wrapEncoding() != VectorEncoding::Simple::FLAT) {
return false;
}

Expand Down Expand Up @@ -230,7 +234,7 @@ void Expr::checkUpdateSharedSubexprValues(
EvalCtx* context,
const VectorPtr& result) {
if (!isMultiplyReferenced_ || sharedSubexprValues_ ||
context->wrapEncoding_ != VectorEncoding::Simple::FLAT) {
context->wrapEncoding() != VectorEncoding::Simple::FLAT) {
return;
}

Expand Down Expand Up @@ -304,30 +308,29 @@ void Expr::setDictionaryWrapping(
const SelectivityVector& rows,
BaseVector& firstWrapper,
EvalCtx* context) {
context->wrapEncoding_ = VectorEncoding::Simple::DICTIONARY;
if (decoded.indicesNotCopied() && decoded.nullsNotCopied()) {
context->wrap_ = firstWrapper.wrapInfo();
context->wrapNulls_ = firstWrapper.nulls();
context->setDictionaryWrap(firstWrapper.wrapInfo(), firstWrapper.nulls());
} else {
context->wrap_ = newBuffer<vector_size_t>(
auto wrap = newBuffer<vector_size_t>(
decoded.indices(), rows.end(), context->execCtx()->pool());
if (decoded.hasExtraNulls()) {
// Nulls are added by wrapping. Add a null wrap.
context->wrapNulls_ = newBuffer<bool>(
decoded.nulls(), rows.end(), context->execCtx()->pool());
}
// If nulls are added by wrapping add a null wrap.
auto wrapNulls = decoded.hasExtraNulls()
? newBuffer<bool>(
decoded.nulls(), rows.end(), context->execCtx()->pool())
: BufferPtr(nullptr);
context->setDictionaryWrap(std::move(wrap), std::move(wrapNulls));
}
}

std::pair<SelectivityVector*, SelectivityVector*> Expr::peelEncodings(
Expr::PeelEncodingsResult Expr::peelEncodings(
EvalCtx* context,
ContextSaver* saver,
const SelectivityVector& rows,
LocalDecodedVector& localDecoded,
LocalSelectivityVector& newRowsHolder,
LocalSelectivityVector& finalRowsHolder) {
if (context->wrapEncoding_ == VectorEncoding::Simple::CONSTANT) {
return std::make_pair(nullptr, nullptr);
if (context->wrapEncoding() == VectorEncoding::Simple::CONSTANT) {
return {nullptr, nullptr, false};
}
std::vector<VectorPtr> peeledVectors;
std::vector<VectorPtr> maybePeeled;
Expand Down Expand Up @@ -413,7 +416,7 @@ std::pair<SelectivityVector*, SelectivityVector*> Expr::peelEncodings(
} while (peeled && nonConstant);

if (numLevels == 0 && nonConstant) {
return std::make_pair(nullptr, nullptr);
return {nullptr, nullptr, false};
}

// We peel off the wrappers and make a new selection.
Expand All @@ -423,27 +426,26 @@ std::pair<SelectivityVector*, SelectivityVector*> Expr::peelEncodings(
// All the fields are constant across the rows of interest.
newRows = singleRow(newRowsHolder, rows.begin());
context->saveAndReset(saver, rows);
context->wrapEncoding_ = VectorEncoding::Simple::CONSTANT;
context->constantWrapIndex_ = rows.begin();
context->setConstantWrap(rows.begin());
} else {
auto decoded = localDecoded.get();
auto firstWrapper = context->getField(firstPeeled).get();
const auto& rowsToDecode =
context->isFinalSelection_ ? rows : *context->finalSelection_;
context->isFinalSelection() ? rows : *context->finalSelection();
decoded->makeIndices(*firstWrapper, rowsToDecode, numLevels);
auto indices = decoded->indices();

newRows = translateToInnerRows(rows, *decoded, newRowsHolder);

if (!context->isFinalSelection_) {
if (!context->isFinalSelection()) {
newFinalSelection = translateToInnerRows(
*context->finalSelection_, *decoded, finalRowsHolder);
*context->finalSelection(), *decoded, finalRowsHolder);
}

context->saveAndReset(saver, rows);

if (!context->isFinalSelection_) {
context->finalSelection_ = newFinalSelection;
if (!context->isFinalSelection()) {
*context->mutableFinalSelection() = newFinalSelection;
}

setDictionaryWrapping(*decoded, rows, *firstWrapper, context);
Expand All @@ -463,8 +465,8 @@ std::pair<SelectivityVector*, SelectivityVector*> Expr::peelEncodings(
}
}
// If the expression depends on one dictionary, results are cacheable.
context->mayCache_ = numPeeled == 1 && constantFields.empty();
return std::make_pair(std::move(newRows), std::move(newFinalSelection));
bool mayCache = numPeeled == 1 && constantFields.empty();
return {newRows, newFinalSelection, mayCache};
}

void Expr::evalEncodings(
Expand All @@ -485,17 +487,17 @@ void Expr::evalEncodings(
LocalSelectivityVector finalRowsHolder(context);
ContextSaver saveContext;
LocalDecodedVector decodedHolder(context);
auto [newRows, newFinalSelection] = peelEncodings(
auto peelEncodingsResult = peelEncodings(
context,
&saveContext,
rows,
decodedHolder,
newRowsHolder,
finalRowsHolder);
auto newRows = peelEncodingsResult.newRows;
if (newRows) {
VectorPtr peeledResult;
if (context->mayCache_) {
context->mayCache_ = false;
if (peelEncodingsResult.mayCache) {
evalWithMemo(*newRows, context, &peeledResult);
} else {
evalWithNulls(*newRows, context, &peeledResult);
Expand Down Expand Up @@ -635,7 +637,7 @@ void Expr::evalWithMemo(
if (uncached->hasSelections()) {
evalAll(*uncached, context, result);
deselectErrors(context, *uncached);
context->exprSet_->memoizingExprs_.insert(this);
context->exprSet()->addToMemo(this);
auto newCacheSize = uncached->end();
if (cachedDictionaryIndices_->size() < newCacheSize) {
int32_t oldSize = cachedDictionaryIndices_->size();
Expand Down Expand Up @@ -820,7 +822,7 @@ bool Expr::applyFunctionWithPeeling(
const SelectivityVector& applyRows,
EvalCtx* context,
VectorPtr* result) {
if (context->wrapEncoding_ == VectorEncoding::Simple::CONSTANT) {
if (context->wrapEncoding() == VectorEncoding::Simple::CONSTANT) {
return false;
}
int numLevels = 0;
Expand Down Expand Up @@ -916,8 +918,7 @@ bool Expr::applyFunctionWithPeeling(
newRows = singleRow(newRowsHolder, rows.begin());

context->saveAndReset(&saver, rows);
context->wrapEncoding_ = VectorEncoding::Simple::CONSTANT;
context->constantWrapIndex_ = rows.begin();
context->setConstantWrap(rows.begin());
} else {
auto decoded = localDecoded.get();
decoded->makeIndices(*firstWrapper, applyRows, numLevels);
Expand Down
18 changes: 14 additions & 4 deletions velox/expression/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,13 @@ class Expr {
EvalCtx* context,
VectorPtr* result) const;

std::pair<SelectivityVector*, SelectivityVector*> peelEncodings(
struct PeelEncodingsResult {
SelectivityVector* newRows;
SelectivityVector* newFinalSelection;
bool mayCache;
};

PeelEncodingsResult peelEncodings(
EvalCtx* context,
ContextSaver* saver,
const SelectivityVector& rows,
Expand Down Expand Up @@ -355,10 +361,17 @@ class ExprSet {
return exprs_[index];
}

// Flags a shared subexpression which needs to be reset (e.g. previously
// computed results must be deleted) when evaluating new batch of data.
void addToReset(const std::shared_ptr<Expr>& expr) {
toReset_.emplace_back(expr);
}

// Flags an expression that remembers the results for a dictionary.
void addToMemo(Expr* expr) {
memoizingExprs_.insert(expr);
}

private:
void clearSharedSubexprs();

Expand All @@ -371,9 +384,6 @@ class ExprSet {
// Exprs which retain memoized state, e.g. from running over dictionaries.
std::unordered_set<Expr*> memoizingExprs_;
core::ExecCtx* const execCtx_;

friend class Expr;
friend class ExprTest;
};

/// Enabled for string vectors. Computes the ascii status of the vector by
Expand Down

0 comments on commit 5aa09fa

Please sign in to comment.