This is an automated email from the ASF dual-hosted git repository.
lihaopeng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new 6a566ccb74 [Enhancement][Vectorized] add constexpr_loop_match (#10283)
6a566ccb74 is described below
commit 6a566ccb74c42e387dd58a78a318385dbab36b3d
Author: Pxl <[email protected]>
AuthorDate: Wed Jun 29 14:58:50 2022 +0800
[Enhancement][Vectorized] add constexpr_loop_match (#10283)
---
be/src/vec/exec/join/vhash_join_node.cpp | 61 +++++++++++-----------
be/src/vec/exec/join/vhash_join_node.h | 2 +-
be/src/vec/functions/function_json.cpp | 34 +++++++++---
be/src/vec/utils/template_helpers.hpp | 89 +++++++++++++++++++++++++++-----
4 files changed, 136 insertions(+), 50 deletions(-)
diff --git a/be/src/vec/exec/join/vhash_join_node.cpp
b/be/src/vec/exec/join/vhash_join_node.cpp
index fa1400a626..e625c6c883 100644
--- a/be/src/vec/exec/join/vhash_join_node.cpp
+++ b/be/src/vec/exec/join/vhash_join_node.cpp
@@ -24,6 +24,7 @@
#include "vec/core/materialize_block.h"
#include "vec/exprs/vexpr.h"
#include "vec/exprs/vexpr_context.h"
+#include "vec/utils/template_helpers.hpp"
#include "vec/utils/util.hpp"
namespace doris::vectorized {
@@ -37,7 +38,7 @@ std::variant<std::false_type, std::true_type> static inline
make_bool_variant(bo
}
using ProfileCounter = RuntimeProfile::Counter;
-template <class HashTableContext, bool ignore_null, bool build_unique>
+template <class HashTableContext>
struct ProcessHashTableBuild {
ProcessHashTableBuild(int rows, Block& acquired_block, ColumnRawPtrs&
build_raw_ptrs,
HashJoinNode* join_node, int batch_size, uint8_t
offset)
@@ -49,8 +50,8 @@ struct ProcessHashTableBuild {
_batch_size(batch_size),
_offset(offset) {}
- Status operator()(HashTableContext& hash_table_ctx, ConstNullMapPtr
null_map,
- bool has_runtime_filter) {
+ template <bool ignore_null, bool build_unique, bool has_runtime_filter>
+ void run(HashTableContext& hash_table_ctx, ConstNullMapPtr null_map) {
using KeyGetter = typename HashTableContext::State;
using Mapped = typename HashTableContext::Mapped;
int64_t old_bucket_bytes =
hash_table_ctx.hash_table.get_buffer_size_in_bytes();
@@ -73,7 +74,7 @@ struct ProcessHashTableBuild {
hash_table_ctx.hash_table.reset_resize_timer();
vector<int>& inserted_rows =
_join_node->_inserted_rows[&_acquired_block];
- if (has_runtime_filter) {
+ if constexpr (has_runtime_filter) {
inserted_rows.reserve(_batch_size);
}
@@ -92,14 +93,14 @@ struct ProcessHashTableBuild {
if (emplace_result.is_inserted()) {
new (&emplace_result.get_mapped()) Mapped({k, _offset});
- if (has_runtime_filter) {
+ if constexpr (has_runtime_filter) {
inserted_rows.push_back(k);
}
} else {
if constexpr (!build_unique) {
/// The first element of the list is stored in the value
of the hash table, the rest in the pool.
emplace_result.get_mapped().insert({k, _offset},
_join_node->_arena);
- if (has_runtime_filter) {
+ if constexpr (has_runtime_filter) {
inserted_rows.push_back(k);
}
} else {
@@ -110,10 +111,17 @@ struct ProcessHashTableBuild {
COUNTER_UPDATE(_join_node->_build_table_expanse_timer,
hash_table_ctx.hash_table.get_resize_timer_value());
-
- return Status::OK();
}
+ template <bool ignore_null, bool build_unique, bool has_runtime_filter>
+ struct Reducer {
+ template <typename... TArgs>
+ static void run(ProcessHashTableBuild<HashTableContext>& build,
TArgs&&... args) {
+ build.template run<ignore_null, build_unique, has_runtime_filter>(
+ std::forward<TArgs>(args)...);
+ }
+ };
+
private:
const int _rows;
int _skip_rows;
@@ -275,7 +283,7 @@ struct ProcessHashTableProbe {
{
SCOPED_TIMER(_search_hashtable_timer);
- for (; _probe_index < _probe_rows;) {
+ while (_probe_index < _probe_rows) {
if constexpr (ignore_null) {
if ((*null_map)[_probe_index]) {
_items_counts[_probe_index++] = (uint32_t)0;
@@ -394,7 +402,7 @@ struct ProcessHashTableProbe {
int current_offset = 0;
- for (; _probe_index < _probe_rows;) {
+ while (_probe_index < _probe_rows) {
// ignore null rows
if constexpr (ignore_null) {
if ((*null_map)[_probe_index]) {
@@ -509,11 +517,6 @@ struct ProcessHashTableProbe {
}
output_block->get_by_position(result_column_id).column =
std::move(new_filter_column);
- } else if constexpr (JoinOpType::value ==
TJoinOp::RIGHT_OUTER_JOIN) {
- for (int i = 0; i < column->size(); ++i) {
- DCHECK(visited_map[i]);
- *visited_map[i] |= column->get_bool(i);
- }
} else if constexpr (JoinOpType::value == TJoinOp::LEFT_SEMI_JOIN)
{
auto new_filter_column = ColumnVector<UInt8>::create();
auto& filter_map = new_filter_column->get_data();
@@ -556,7 +559,8 @@ struct ProcessHashTableProbe {
output_block->get_by_position(result_column_id).column =
std::move(new_filter_column);
} else if constexpr (JoinOpType::value == TJoinOp::RIGHT_SEMI_JOIN
||
- JoinOpType::value ==
TJoinOp::RIGHT_ANTI_JOIN) {
+ JoinOpType::value == TJoinOp::RIGHT_ANTI_JOIN
||
+ JoinOpType::value ==
TJoinOp::RIGHT_OUTER_JOIN) {
for (int i = 0; i < column->size(); ++i) {
DCHECK(visited_map[i]);
*visited_map[i] |= column->get_bool(i);
@@ -822,7 +826,9 @@ Status HashJoinNode::close(RuntimeState* state) {
VExpr::close(_build_expr_ctxs, state);
VExpr::close(_probe_expr_ctxs, state);
- if (_vother_join_conjunct_ptr) (*_vother_join_conjunct_ptr)->close(state);
+ if (_vother_join_conjunct_ptr) {
+ (*_vother_join_conjunct_ptr)->close(state);
+ }
_hash_table_mem_tracker->release(_mem_used);
@@ -1169,19 +1175,14 @@ Status HashJoinNode::_process_build_block(RuntimeState*
state, Block& block, uin
[&](auto&& arg) {
using HashTableCtxType = std::decay_t<decltype(arg)>;
if constexpr (!std::is_same_v<HashTableCtxType,
std::monostate>) {
-#define CALL_BUILD_FUNCTION(HAS_NULL, BUILD_UNIQUE)
\
- ProcessHashTableBuild<HashTableCtxType, HAS_NULL, BUILD_UNIQUE>
hash_table_build_process( \
- rows, block, raw_ptrs, this, state->batch_size(), offset);
\
- st = hash_table_build_process(arg, &null_map_val, has_runtime_filter);
- if (std::pair {has_null, _build_unique} == std::pair
{true, true}) {
- CALL_BUILD_FUNCTION(true, true);
- } else if (std::pair {has_null, _build_unique} ==
std::pair {true, false}) {
- CALL_BUILD_FUNCTION(true, false);
- } else if (std::pair {has_null, _build_unique} ==
std::pair {false, true}) {
- CALL_BUILD_FUNCTION(false, true);
- } else {
- CALL_BUILD_FUNCTION(false, false);
- }
+ ProcessHashTableBuild<HashTableCtxType>
hash_table_build_process(
+ rows, block, raw_ptrs, this, state->batch_size(),
offset);
+
+ constexpr_3_bool_match<ProcessHashTableBuild<
+ HashTableCtxType>::template
Reducer>::run(has_null, _build_unique,
+
has_runtime_filter,
+
hash_table_build_process, arg,
+
&null_map_val);
} else {
LOG(FATAL) << "FATAL: uninited hash table";
}
diff --git a/be/src/vec/exec/join/vhash_join_node.h
b/be/src/vec/exec/join/vhash_join_node.h
index 7db2db48d3..175134b522 100644
--- a/be/src/vec/exec/join/vhash_join_node.h
+++ b/be/src/vec/exec/join/vhash_join_node.h
@@ -252,7 +252,7 @@ private:
void _hash_table_init();
- template <class HashTableContext, bool ignore_null, bool build_unique>
+ template <class HashTableContext>
friend struct ProcessHashTableBuild;
template <class HashTableContext, class JoinOpType, bool ignore_null>
diff --git a/be/src/vec/functions/function_json.cpp
b/be/src/vec/functions/function_json.cpp
index 2019ac5910..6abdc6a4b2 100644
--- a/be/src/vec/functions/function_json.cpp
+++ b/be/src/vec/functions/function_json.cpp
@@ -407,18 +407,37 @@ struct JsonParser<'3'> {
}
};
+template <>
+struct JsonParser<'4'> {
+ // time
+ static void update_value(StringParser::ParseResult& result,
rapidjson::Value& value,
+ StringRef data,
rapidjson::Document::AllocatorType& allocator) {
+ // remove double quotes, "xxx" -> xxx
+ value.SetString(data.data + 1, data.size - 2, allocator);
+ }
+};
+
+template <int flag, typename Impl>
+struct ExecuteReducer {
+ template <typename... TArgs>
+ static void run(TArgs&&... args) {
+ Impl::template
execute_type<JsonParser<flag>>(std::forward<TArgs>(args)...);
+ }
+};
+
struct FunctionJsonArrayImpl {
static constexpr auto name = "json_array";
- CONSTEXPR_LOOP_MATCH_DECLARE(execute_type);
+ template <int flag>
+ using Reducer = ExecuteReducer<flag, FunctionJsonArrayImpl>;
static void execute_parse(const std::string& type_flags,
const std::vector<const ColumnString*>&
data_columns,
std::vector<rapidjson::Value>& objects,
rapidjson::Document::AllocatorType& allocator) {
for (int i = 0; i < data_columns.size() - 1; i++) {
- constexpr_loop_match<'0', '6', JsonParser>(type_flags[i], objects,
allocator,
- data_columns[i]);
+ constexpr_int_match<'0', '5', Reducer>::run(type_flags[i],
objects, allocator,
+ data_columns[i]);
}
}
@@ -439,7 +458,8 @@ struct FunctionJsonArrayImpl {
struct FunctionJsonObjectImpl {
static constexpr auto name = "json_object";
- CONSTEXPR_LOOP_MATCH_DECLARE(execute_type);
+ template <int flag>
+ using Reducer = ExecuteReducer<flag, FunctionJsonObjectImpl>;
static void execute_parse(std::string type_flags,
const std::vector<const ColumnString*>&
data_columns,
@@ -450,8 +470,8 @@ struct FunctionJsonObjectImpl {
}
for (int i = 0; i + 1 < data_columns.size() - 1; i += 2) {
- constexpr_loop_match<'0', '6', JsonParser>(type_flags[i + 1],
objects, allocator,
- data_columns[i],
data_columns[i + 1]);
+ constexpr_int_match<'0', '5', Reducer>::run(type_flags[i + 1],
objects, allocator,
+ data_columns[i],
data_columns[i + 1]);
}
}
@@ -464,7 +484,7 @@ struct FunctionJsonObjectImpl {
rapidjson::Value value;
for (int i = 0; i < objects.size(); i++) {
- JsonParser<'4'>::update_value(result, key,
key_column->get_data_at(i),
+ JsonParser<'5'>::update_value(result, key,
key_column->get_data_at(i),
allocator); // key always is string
TypeImpl::update_value(result, value,
value_column->get_data_at(i), allocator);
objects[i].AddMember(key, value, allocator);
diff --git a/be/src/vec/utils/template_helpers.hpp
b/be/src/vec/utils/template_helpers.hpp
index afe745d1aa..5db9147c89 100644
--- a/be/src/vec/utils/template_helpers.hpp
+++ b/be/src/vec/utils/template_helpers.hpp
@@ -17,6 +17,8 @@
#pragma once
+#include <limits>
+
#include "http/http_status.h"
#include "vec/aggregate_functions/aggregate_function.h"
#include "vec/columns/column_complex.h"
@@ -70,18 +72,81 @@ IAggregateFunction* create_class_with_type(const IDataType&
argument_type, TArgs
return nullptr;
}
-// We can use template lambda function in C++20, but now just use static
function
-#define CONSTEXPR_LOOP_MATCH_DECLARE(EXECUTE)
\
- template <int start, int end, template <int> typename Object, typename...
TArgs> \
- static void constexpr_loop_match(int target, TArgs&&... args) {
\
- if constexpr (start < end) {
\
- if (start == target) {
\
- EXECUTE<Object<start>>(std::forward<TArgs>(args)...);
\
- } else {
\
- constexpr_loop_match<start + 1, end, Object>(target,
\
-
std::forward<TArgs>(args)...); \
- }
\
- }
\
+template <typename LoopType, LoopType start, LoopType end, template <LoopType>
typename Reducer>
+struct constexpr_loop_match {
+ template <typename... TArgs>
+ static void run(LoopType target, TArgs&&... args) {
+ if constexpr (start <= end) {
+ if (start == target) {
+ Reducer<start>::run(std::forward<TArgs>(args)...);
+ } else {
+ if constexpr (start < std::numeric_limits<LoopType>::max()) {
+ constexpr_loop_match<LoopType, start + 1, end,
Reducer>::run(
+ target, std::forward<TArgs>(args)...);
+ }
+ }
+ }
+ }
+};
+
+template <int start, int end, template <int> typename Reducer>
+using constexpr_int_match = constexpr_loop_match<int, start, end, Reducer>;
+
+template <template <bool> typename Reducer>
+using constexpr_bool_match = constexpr_loop_match<bool, false, true, Reducer>;
+
+// we can't use variadic-parameters, because it will reject alias-templates.
+//
https://stackoverflow.com/questions/30707011/pack-expansion-for-alias-template
+template <typename LoopType, LoopType start, LoopType end,
+ template <LoopType, LoopType> typename Reducer,
+ template <template <LoopType> typename> typename InnerMatch>
+struct constexpr_2_loop_match {
+ template <LoopType matched>
+ using InnerReducer = Reducer<start, matched>;
+
+ template <typename... TArgs>
+ static void run(LoopType target, TArgs&&... args) {
+ if constexpr (start <= end) {
+ if (start == target) {
+ InnerMatch<InnerReducer>::run(std::forward<TArgs>(args)...);
+ } else {
+ if constexpr (start < std::numeric_limits<LoopType>::max()) {
+ constexpr_2_loop_match<LoopType, start + 1, end, Reducer,
InnerMatch>::run(
+ target, std::forward<TArgs>(args)...);
+ }
+ }
+ }
}
+};
+
+template <template <bool, bool> typename Reducer>
+using constexpr_2_bool_match =
+ constexpr_2_loop_match<bool, false, true, Reducer,
constexpr_bool_match>;
+
+template <typename LoopType, LoopType start, LoopType end,
+ template <LoopType, LoopType, LoopType> typename Reducer,
+ template <template <LoopType, LoopType> typename> typename
InnerMatch>
+struct constexpr_3_loop_match {
+ template <LoopType matched, LoopType matched_next>
+ using InnerReducer = Reducer<start, matched, matched_next>;
+
+ template <typename... TArgs>
+ static void run(LoopType target, TArgs&&... args) {
+ if constexpr (start <= end) {
+ if (start == target) {
+ InnerMatch<InnerReducer>::run(std::forward<TArgs>(args)...);
+ } else {
+ if constexpr (start < std::numeric_limits<LoopType>::max()) {
+ constexpr_3_loop_match<LoopType, start + 1, end, Reducer,
InnerMatch>::run(
+ target, std::forward<TArgs>(args)...);
+ }
+ }
+ }
+ }
+};
+
+template <template <bool, bool, bool> typename Reducer>
+using constexpr_3_bool_match =
+ constexpr_3_loop_match<bool, false, true, Reducer,
constexpr_2_bool_match>;
} // namespace doris::vectorized
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]