|
3 | 3 | #include "duckdb/planner/expression/bound_conjunction_expression.hpp" |
4 | 4 | #include "duckdb/execution/adaptive_filter.hpp" |
5 | 5 |
|
| 6 | +#include <iostream> |
6 | 7 | #include <random> |
| 8 | +#include <future> |
| 9 | + |
| 10 | +#define EXECUTE_PARALLEL 0 |
7 | 11 |
|
8 | 12 | namespace duckdb { |
9 | 13 |
|
@@ -56,6 +60,10 @@ void ExpressionExecutor::Execute(const BoundConjunctionExpression &expr, Express |
56 | 60 | idx_t ExpressionExecutor::Select(const BoundConjunctionExpression &expr, ExpressionState *state_p, |
57 | 61 | const SelectionVector *sel, idx_t count, SelectionVector *true_sel, |
58 | 62 | SelectionVector *false_sel) { |
| 63 | +#if EXECUTE_PARALLEL == 1 |
| 64 | + return SelectParallel(expr, state_p, sel, count, true_sel, false_sel); |
| 65 | +#endif |
| 66 | + |
59 | 67 | auto &state = state_p->Cast<ConjunctionState>(); |
60 | 68 |
|
61 | 69 | if (expr.GetExpressionType() == ExpressionType::CONJUNCTION_AND) { |
@@ -140,4 +148,104 @@ idx_t ExpressionExecutor::Select(const BoundConjunctionExpression &expr, Express |
140 | 148 | } |
141 | 149 | } |
142 | 150 |
|
| 151 | +idx_t ExpressionExecutor::AsyncSelect(const Expression &expr, ExpressionState *state, const SelectionVector *sel, |
| 152 | + idx_t count, SelectionVector *true_sel, SelectionVector *false_sel) { |
| 153 | + idx_t out = Select(expr, state, sel, count, true_sel, false_sel); |
| 154 | + // for (idx_t j = 0; j < out; j++) { |
| 155 | + // std::cout << "AsyncSelect- " << " idx- " << j << ", mapping- " << true_sel->get_index(j) << std::endl; |
| 156 | + // } |
| 157 | + return out; |
| 158 | +} |
| 159 | + |
| 160 | +idx_t ExpressionExecutor::SelectParallel(const BoundConjunctionExpression &expr, ExpressionState *state_p, |
| 161 | + const SelectionVector *sel, idx_t count, SelectionVector *true_sel, |
| 162 | + SelectionVector *false_sel) { |
| 163 | + auto &state = state_p->Cast<ConjunctionState>(); |
| 164 | + |
| 165 | + if (expr.GetExpressionType() == ExpressionType::CONJUNCTION_AND) { |
| 166 | + // get runtime statistics |
| 167 | + auto filter_state = state.adaptive_filter->BeginFilter(); |
| 168 | + const SelectionVector *current_sel = sel; |
| 169 | + idx_t false_count = 0; |
| 170 | + |
| 171 | + unique_ptr<SelectionVector> temp_true, temp_false; |
| 172 | + if (false_sel) { |
| 173 | + temp_false = make_uniq<SelectionVector>(STANDARD_VECTOR_SIZE); |
| 174 | + } |
| 175 | + if (!true_sel) { |
| 176 | + temp_true = make_uniq<SelectionVector>(STANDARD_VECTOR_SIZE); |
| 177 | + true_sel = temp_true.get(); |
| 178 | + } |
| 179 | + |
| 180 | + vector<std::future<idx_t>> futures; |
| 181 | + // vector<idx_t> futures_i; |
| 182 | + vector<unique_ptr<SelectionVector>> children_true; |
| 183 | + for (idx_t i = 0; i < expr.children.size(); i++) { |
| 184 | + children_true.push_back(make_uniq<SelectionVector>(STANDARD_VECTOR_SIZE)); |
| 185 | + } |
| 186 | + |
| 187 | + vector<SelectionVector> children_false{expr.children.size(), SelectionVector{STANDARD_VECTOR_SIZE}}; |
| 188 | + vector<idx_t> true_counts{expr.children.size(), 0}; |
| 189 | + |
| 190 | + for (idx_t i = 0; i < expr.children.size(); i++) { |
| 191 | + // futures_i.push_back(AsyncSelect(*expr.children[state.adaptive_filter->permutation[i]], |
| 192 | + // state.child_states[state.adaptive_filter->permutation[i]].get(), |
| 193 | + // current_sel, count, children_true[i].get(), &children_false[i])); |
| 194 | + |
| 195 | + // for (idx_t j = 0; j < futures_i[i]; j++) { |
| 196 | + // std::cout << "InLoopFilter- " << i << " , idx- " << j << ", mapping- " << children_true[i]->get_index(j) << std::endl; |
| 197 | + // } |
| 198 | + futures.push_back(std::async(std::launch::async, &ExpressionExecutor::AsyncSelect, |
| 199 | + this, std::cref(*expr.children[state.adaptive_filter->permutation[i]]), |
| 200 | + state.child_states[state.adaptive_filter->permutation[i]].get(), |
| 201 | + std::cref(current_sel), count, children_true[i].get(), &children_false[i])); |
| 202 | + } |
| 203 | + |
| 204 | + for (idx_t i = 0; i < expr.children.size(); i++) { |
| 205 | + // idx_t tcount = futures_i[i]; |
| 206 | + idx_t tcount = futures[i].get(); |
| 207 | + idx_t fcount = count - tcount; |
| 208 | + if (fcount > 0 && false_sel) { |
| 209 | + // move failing tuples into the false_sel |
| 210 | + // tuples passed, move them into the actual result vector |
| 211 | + for (idx_t j = 0; j < fcount; j++) { |
| 212 | + false_sel->set_index(false_count++, children_false[i].get_index(j)); |
| 213 | + } |
| 214 | + } |
| 215 | + true_counts[i] = tcount; |
| 216 | + // std::cout << "Filtered: " << tcount << std::endl; |
| 217 | + } |
| 218 | + idx_t true_count = 0; |
| 219 | + idx_t lp = 0; |
| 220 | + idx_t rp = 0; |
| 221 | + while (lp < true_counts[0] && rp < true_counts[1]) { |
| 222 | + idx_t lidx = children_true[0]->get_index(lp); |
| 223 | + idx_t ridx = children_true[1]->get_index(rp); |
| 224 | + if (lidx == ridx) { |
| 225 | + // std::cout << "Match: " << lidx << std::endl; |
| 226 | + true_sel->set_index(true_count, lidx); |
| 227 | + true_count++; |
| 228 | + lp++; |
| 229 | + rp++; |
| 230 | + } else if (lidx < ridx) { |
| 231 | + lp++; |
| 232 | + } else if (ridx < lidx) { |
| 233 | + rp++; |
| 234 | + } |
| 235 | + } |
| 236 | + // for (idx_t i = 0; i < children_true.size(); i++) { |
| 237 | + // for (idx_t j = 0; j < true_counts[i]; j++) { |
| 238 | + // std::cout << "Filter- " << i << " , idx- " << j << ", mapping- " << children_true[i]->get_index(j) << std::endl; |
| 239 | + // true_sel->set_index(true_count, children_true[i]->get_index(j)); |
| 240 | + // true_count++; |
| 241 | + // } |
| 242 | + // } |
| 243 | + // adapt runtime statistics |
| 244 | + state.adaptive_filter->EndFilter(filter_state); |
| 245 | + return true_count; |
| 246 | + } else { |
| 247 | + throw std::runtime_error("Expression executor does not support select_parallel() with !AND"); |
| 248 | + } |
| 249 | +} |
| 250 | + |
143 | 251 | } // namespace duckdb |
0 commit comments