OmniSciDB  72c90bc290
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
QueryHint.h
Go to the documentation of this file.
1 /*
2  * Copyright 2022 HEAVY.AI, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef OMNISCI_QUERYHINT_H
18 #define OMNISCI_QUERYHINT_H
19 
20 #include <algorithm>
21 #include <optional>
22 
23 #include <boost/algorithm/string.hpp>
24 
26 
27 // we expect query hint enum val starts with zero,
28 // and let remaining enum value to be auto-incremented
29 enum QueryHint {
30  kCpuMode = 0,
57  kHintCount, // should be at the last elem before INVALID enum value to count #
58  // supported hints correctly
59  kInvalidHint // this should be the last elem of this enum
60 };
61 
62 static const std::unordered_map<std::string, QueryHint> SupportedQueryHints = {
63  {"cpu_mode", QueryHint::kCpuMode},
64  {"columnar_output", QueryHint::kColumnarOutput},
65  {"rowwise_output", QueryHint::kRowwiseOutput},
66  {"bbox_intersect_bucket_threshold", QueryHint::kBBoxIntersectBucketThreshold},
67  {"bbox_intersect_max_size", QueryHint::kBBoxIntersectMaxSize},
68  {"bbox_intersect_allow_gpu_build", QueryHint::kBBoxIntersectAllowGpuBuild},
69  {"bbox_intersect_no_cache", QueryHint::kBBoxIntersectNoCache},
70  {"bbox_intersect_keys_per_bin", QueryHint::kBBoxIntersectKeysPerBin},
71  {"keep_result", QueryHint::kKeepResult},
72  {"keep_table_function_result", QueryHint::kKeepTableFuncResult},
73  {"aggregate_tree_fanout", QueryHint::kAggregateTreeFanout},
74  {"cuda_block_size", QueryHint::kCudaBlockSize},
75  {"cuda_grid_size_multiplier", QueryHint::kCudaGridSize},
76  {"cuda_opt_block_and_grid_sizes", kOptCudaBlockAndGridSizes},
77  {"watchdog", QueryHint::kWatchdog},
78  {"dynamic_watchdog", QueryHint::kDynamicWatchdog},
79  {"watchdog_off", QueryHint::kWatchdogOff},
80  {"dynamic_watchdog_off", QueryHint::kDynamicWatchdogOff},
81  {"query_time_limit", QueryHint::kQueryTimeLimit},
82  {"allow_loop_join", QueryHint::kAllowLoopJoin},
83  {"disable_loop_join", QueryHint::kDisableLoopJoin},
84  {"loop_join_inner_table_max_num_rows", QueryHint::kLoopJoinInnerTableMaxNumRows},
85  {"max_join_hashtable_size", QueryHint::kMaxJoinHashTableSize},
86  {"force_baseline_hash_join", QueryHint::kforceBaselineHashJoin},
87  {"force_one_to_many_hash_join", QueryHint::kforceOneToManyHashJoin},
88  {"watchdog_max_projected_rows_per_device",
90  {"preflight_count_query_threshold", QueryHint::kPreflightCountQueryThreshold}};
91 
94  std::string hint_name;
95 
96  HintIdentifier(bool global_hint, const std::string& hint_name)
97  : global_hint(global_hint), hint_name(hint_name){};
98 };
99 
101  // this class represents parsed query hint's specification
102  // our query AST analyzer translates query hint string to understandable form which we
103  // called "ExplainedQueryHint"
104  public:
105  // default constructor used for deserialization only
108  , global_hint_{false}
109  , is_marker_{false}
110  , has_kv_type_options_{false} {}
111 
113  bool global_hint,
114  bool is_marker,
115  bool has_kv_type_options)
116  : hint_(hint)
117  , global_hint_(global_hint)
118  , is_marker_(is_marker)
119  , has_kv_type_options_(has_kv_type_options) {}
120 
122  bool global_hint,
123  bool is_marker,
124  bool has_kv_type_options,
125  std::vector<std::string>& list_options)
126  : hint_(hint)
127  , global_hint_(global_hint)
128  , is_marker_(is_marker)
129  , has_kv_type_options_(has_kv_type_options)
130  , list_options_(std::move(list_options)) {}
131 
133  bool global_hint,
134  bool is_marker,
135  bool has_kv_type_options,
136  std::unordered_map<std::string, std::string>& kv_options)
137  : hint_(hint)
138  , global_hint_(global_hint)
139  , is_marker_(is_marker)
140  , has_kv_type_options_(has_kv_type_options)
141  , kv_options_(std::move(kv_options)) {}
142 
143  void setListOptions(std::vector<std::string>& list_options) {
144  list_options_ = list_options;
145  }
146 
147  void setKVOptions(std::unordered_map<std::string, std::string>& kv_options) {
148  kv_options_ = kv_options;
149  }
150 
151  void setInheritPaths(std::vector<int>& interit_paths) {
152  inherit_paths_ = interit_paths;
153  }
154 
155  const std::vector<std::string>& getListOptions() const { return list_options_; }
156 
157  const std::vector<int>& getInteritPath() const { return inherit_paths_; }
158 
159  const std::unordered_map<std::string, std::string>& getKVOptions() const {
160  return kv_options_;
161  }
162 
163  const QueryHint getHint() const { return hint_; }
164 
165  bool isGlobalHint() const { return global_hint_; }
166 
167  bool hasOptions() const { return is_marker_; }
168 
169  bool hasKvOptions() const { return has_kv_type_options_; }
170 
171  private:
173  // Set true if this hint affects globally
174  // Otherwise it just affects the node which this hint is included (aka table hint)
176  // set true if this has no extra options (neither list_options nor kv_options)
178  // Set true if it is not a marker and has key-value type options
179  // Otherwise (it is not a marker but has list type options), we set this be false
181  std::vector<int> inherit_paths_; // currently not used
182  std::vector<std::string> list_options_;
183  std::unordered_map<std::string, std::string> kv_options_;
184 };
185 
187  // for each query hint, we first translate the raw query hint info
188  // to understandable form called "ExplainedQueryHint"
189  // and we get all necessary info from it and organize it into "RegisteredQueryHint"
190  // so by using "RegisteredQueryHint", we can know and access which query hint is
191  // registered and its detailed info such as the hint's parameter values given by user
192  // NOTE: after changing query hint fields, we "SHOULD" also update the corresponding
193  // "QueryHintSerializer" accordingly
195  : cpu_mode(false)
198  , keep_result(false)
200  , watchdog(std::nullopt)
201  , dynamic_watchdog(std::nullopt)
202  , query_time_limit(0)
205  , cuda_block_size(0)
209  , bbox_intersect_bucket_threshold(std::numeric_limits<double>::max())
214  , use_loop_join(std::nullopt)
216  , max_join_hash_table_size(std::numeric_limits<size_t>::max())
220 
222  CHECK_EQ(registered_hint.size(), global_hints.registered_hint.size());
223  // apply registered global hint to the local hint if necessary
224  // we prioritize global hint when both side of hints are enabled simultaneously
225  RegisteredQueryHint updated_query_hints(*this);
226 
227  constexpr int num_hints = static_cast<int>(QueryHint::kHintCount);
228  for (int i = 0; i < num_hints; ++i) {
229  if (global_hints.registered_hint.at(i)) {
230  updated_query_hints.registered_hint.at(i) = true;
231  switch (static_cast<QueryHint>(i)) {
232  case QueryHint::kCpuMode:
233  updated_query_hints.cpu_mode = true;
234  break;
236  updated_query_hints.columnar_output = true;
237  break;
239  updated_query_hints.rowwise_output = true;
240  break;
242  updated_query_hints.cuda_block_size = global_hints.cuda_block_size;
243  break;
245  updated_query_hints.cuda_grid_size_multiplier =
246  global_hints.cuda_grid_size_multiplier;
247  break;
249  updated_query_hints.opt_cuda_grid_and_block_size = true;
250  break;
252  updated_query_hints.bbox_intersect_bucket_threshold =
253  global_hints.bbox_intersect_bucket_threshold;
254  break;
256  updated_query_hints.bbox_intersect_max_size =
257  global_hints.bbox_intersect_max_size;
258  break;
260  updated_query_hints.bbox_intersect_allow_gpu_build = true;
261  break;
263  updated_query_hints.bbox_intersect_no_cache = true;
264  break;
266  updated_query_hints.bbox_intersect_keys_per_bin =
267  global_hints.bbox_intersect_keys_per_bin;
268  break;
270  updated_query_hints.keep_result = global_hints.keep_result;
271  break;
273  updated_query_hints.keep_table_function_result =
274  global_hints.keep_table_function_result;
275  break;
277  updated_query_hints.aggregate_tree_fanout =
278  global_hints.aggregate_tree_fanout;
279  break;
282  updated_query_hints.watchdog = global_hints.watchdog;
283  break;
286  updated_query_hints.dynamic_watchdog = global_hints.dynamic_watchdog;
287  break;
289  updated_query_hints.query_time_limit = global_hints.query_time_limit;
290  break;
293  updated_query_hints.use_loop_join = global_hints.use_loop_join;
294  break;
296  updated_query_hints.loop_join_inner_table_max_num_rows =
298  break;
300  updated_query_hints.max_join_hash_table_size =
301  global_hints.max_join_hash_table_size;
302  break;
304  updated_query_hints.force_baseline_hash_join =
305  global_hints.force_baseline_hash_join;
306  break;
308  updated_query_hints.force_one_to_many_hash_join =
309  global_hints.force_one_to_many_hash_join;
310  break;
312  updated_query_hints.watchdog_max_projected_rows_per_device =
314  break;
316  updated_query_hints.preflight_count_query_threshold =
317  global_hints.preflight_count_query_threshold;
318  break;
319  default:
320  UNREACHABLE();
321  }
322  }
323  }
324  return updated_query_hints;
325  }
326 
327  // general query execution
328  bool cpu_mode;
333  std::optional<bool> watchdog;
334  std::optional<bool> dynamic_watchdog;
338 
339  // control CUDA behavior
343 
344  // window function framing
346 
347  // bbox_intersect hash join
348  double bbox_intersect_bucket_threshold; // defined in
349  // "BoundingBoxIntersectJoinHashTable.h"
354 
355  // generic hash join
356  std::optional<bool> use_loop_join;
361 
362  std::vector<bool> registered_hint;
363 
365 
366  public:
367  static QueryHint translateQueryHint(const std::string& hint_name) {
368  const auto lowered_hint_name = boost::algorithm::to_lower_copy(hint_name);
369  auto it = SupportedQueryHints.find(lowered_hint_name);
370  return it == SupportedQueryHints.end() ? QueryHint::kInvalidHint : it->second;
371  }
372 
373  bool isAnyQueryHintDelivered() const {
374  const auto identity = [](const bool b) { return b; };
375  return std::any_of(registered_hint.begin(), registered_hint.end(), identity);
376  }
377 
378  void registerHint(const QueryHint hint) {
379  const auto hint_class = static_cast<int>(hint);
380  registered_hint.at(hint_class) = true;
381  }
382 
383  bool isHintRegistered(const QueryHint hint) const {
384  const auto hint_class = static_cast<int>(hint);
385  return registered_hint.at(hint_class);
386  }
387 };
388 
389 // a map from hint_name to its detailed info
390 using Hints = std::unordered_map<QueryHint, ExplainedQueryHint>;
391 
392 #endif // OMNISCI_QUERYHINT_H
std::unordered_map< std::string, std::string > kv_options_
Definition: QueryHint.h:183
#define CHECK_EQ(x, y)
Definition: Logger.h:301
bool isGlobalHint() const
Definition: QueryHint.h:165
double bbox_intersect_keys_per_bin
Definition: QueryHint.h:353
const std::vector< int > & getInteritPath() const
Definition: QueryHint.h:157
const std::unordered_map< std::string, std::string > & getKVOptions() const
Definition: QueryHint.h:159
#define UNREACHABLE()
Definition: Logger.h:338
size_t g_preflight_count_query_threshold
Definition: Execute.cpp:84
double g_bbox_intersect_target_entries_per_bin
Definition: Execute.cpp:111
void setListOptions(std::vector< std::string > &list_options)
Definition: QueryHint.h:143
std::optional< bool > dynamic_watchdog
Definition: QueryHint.h:334
double cuda_grid_size_multiplier
Definition: QueryHint.h:341
size_t cuda_block_size
Definition: QueryHint.h:340
ExplainedQueryHint(QueryHint hint, bool global_hint, bool is_marker, bool has_kv_type_options)
Definition: QueryHint.h:112
std::vector< bool > registered_hint
Definition: QueryHint.h:362
void setKVOptions(std::unordered_map< std::string, std::string > &kv_options)
Definition: QueryHint.h:147
unsigned g_trivial_loop_join_threshold
Definition: Execute.cpp:92
ExplainedQueryHint(QueryHint hint, bool global_hint, bool is_marker, bool has_kv_type_options, std::vector< std::string > &list_options)
Definition: QueryHint.h:121
size_t max_join_hash_table_size
Definition: QueryHint.h:358
bool opt_cuda_grid_and_block_size
Definition: QueryHint.h:342
bool hasKvOptions() const
Definition: QueryHint.h:169
bool keep_table_function_result
Definition: QueryHint.h:332
size_t query_time_limit
Definition: QueryHint.h:335
static const std::unordered_map< std::string, QueryHint > SupportedQueryHints
Definition: QueryHint.h:62
static QueryHint translateQueryHint(const std::string &hint_name)
Definition: QueryHint.h:367
std::vector< std::string > list_options_
Definition: QueryHint.h:182
double bbox_intersect_bucket_threshold
Definition: QueryHint.h:348
void registerHint(const QueryHint hint)
Definition: QueryHint.h:378
size_t g_watchdog_max_projected_rows_per_device
Definition: Execute.cpp:83
bool hasOptions() const
Definition: QueryHint.h:167
HintIdentifier(bool global_hint, const std::string &hint_name)
Definition: QueryHint.h:96
size_t watchdog_max_projected_rows_per_device
Definition: QueryHint.h:336
std::optional< bool > watchdog
Definition: QueryHint.h:333
size_t preflight_count_query_threshold
Definition: QueryHint.h:337
static RegisteredQueryHint defaults()
Definition: QueryHint.h:364
bool isHintRegistered(const QueryHint hint) const
Definition: QueryHint.h:383
std::unordered_map< QueryHint, ExplainedQueryHint > Hints
Definition: QueryHint.h:390
QueryHint
Definition: QueryHint.h:29
size_t bbox_intersect_max_size
Definition: QueryHint.h:350
bool force_baseline_hash_join
Definition: QueryHint.h:359
bool bbox_intersect_no_cache
Definition: QueryHint.h:352
std::optional< bool > use_loop_join
Definition: QueryHint.h:356
RegisteredQueryHint operator||(const RegisteredQueryHint &global_hints) const
Definition: QueryHint.h:221
bool g_enable_watchdog false
Definition: Execute.cpp:80
bool global_hint
Definition: QueryHint.h:93
size_t loop_join_inner_table_max_num_rows
Definition: QueryHint.h:357
bool bbox_intersect_allow_gpu_build
Definition: QueryHint.h:351
std::vector< int > inherit_paths_
Definition: QueryHint.h:181
bool has_kv_type_options_
Definition: QueryHint.h:180
bool any_of(std::vector< Analyzer::Expr * > const &target_exprs)
QueryHint hint_
Definition: QueryHint.h:172
size_t aggregate_tree_fanout
Definition: QueryHint.h:345
const QueryHint getHint() const
Definition: QueryHint.h:163
std::string hint_name
Definition: QueryHint.h:94
const std::vector< std::string > & getListOptions() const
Definition: QueryHint.h:155
void setInheritPaths(std::vector< int > &interit_paths)
Definition: QueryHint.h:151
ExplainedQueryHint(QueryHint hint, bool global_hint, bool is_marker, bool has_kv_type_options, std::unordered_map< std::string, std::string > &kv_options)
Definition: QueryHint.h:132
bool isAnyQueryHintDelivered() const
Definition: QueryHint.h:373
bool force_one_to_many_hash_join
Definition: QueryHint.h:360
size_t g_bbox_intersect_max_table_size_bytes
Definition: Execute.cpp:110