OmniSciDB  04ee39c94c
ResultSetBaselineRadixSortTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017 MapD Technologies, 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 
24 #include "../QueryEngine/Descriptors/RowSetMemoryOwner.h"
25 #include "../QueryEngine/ResultSet.h"
26 #include "../QueryEngine/RuntimeFunctions.h"
27 #include "ResultSetTestUtils.h"
28 #include "TestHelpers.h"
29 
30 #ifdef HAVE_CUDA
31 #include "../CudaMgr/CudaMgr.h"
32 
33 extern std::unique_ptr<CudaMgr_Namespace::CudaMgr> g_cuda_mgr;
34 #endif // HAVE_CUDA
35 
36 #include <gtest/gtest.h>
37 
38 #include <algorithm>
39 #include <numeric>
40 #include <random>
41 
42 namespace {
43 
44 std::vector<TargetInfo> get_sort_int_target_infos() {
45  std::vector<TargetInfo> target_infos;
46  SQLTypeInfo int_ti(kINT, false);
47  SQLTypeInfo null_ti(kNULLT, false);
48  target_infos.push_back(TargetInfo{false, kMIN, int_ti, null_ti, false, false});
49  target_infos.push_back(TargetInfo{false, kMIN, int_ti, null_ti, false, false});
50  target_infos.push_back(TargetInfo{true, kCOUNT, int_ti, null_ti, false, false});
51  return target_infos;
52 }
53 
54 QueryMemoryDescriptor baseline_sort_desc(const std::vector<TargetInfo>& target_infos,
55  const size_t hash_entry_count,
56  const size_t key_bytewidth) {
57  QueryMemoryDescriptor query_mem_desc(
58  QueryDescriptionType::GroupByBaselineHash, 0, 0, false, {8, 8});
59  query_mem_desc.setGroupColCompactWidth(key_bytewidth);
60  static const size_t slot_bytes = 8;
61  for (size_t i = 0; i < target_infos.size(); ++i) {
62  query_mem_desc.addColSlotInfo({std::make_tuple(slot_bytes, slot_bytes)});
63  }
64  query_mem_desc.setEntryCount(hash_entry_count);
65  return query_mem_desc;
66 }
67 
68 template <class K>
70  const std::vector<TargetInfo>& target_infos,
71  const QueryMemoryDescriptor& query_mem_desc,
72  const int64_t upper_bound,
73  const int64_t empty_key) {
74  const auto key_component_count = query_mem_desc.getKeyCount();
75  const auto target_slot_count = get_slot_count(target_infos);
76  const auto slot_to_target = get_slot_to_target_mapping(target_infos);
77  const auto row_bytes = get_row_bytes(query_mem_desc);
78  for (size_t i = 0; i < query_mem_desc.getEntryCount(); ++i) {
79  const auto row_ptr = buff + i * row_bytes;
80  for (size_t key_comp_idx = 0; key_comp_idx < key_component_count; ++key_comp_idx) {
81  reinterpret_cast<K*>(row_ptr)[key_comp_idx] = empty_key;
82  }
83  for (size_t target_slot = 0; target_slot < target_slot_count; ++target_slot) {
84  auto target_it = slot_to_target.find(target_slot);
85  CHECK(target_it != slot_to_target.end());
86  const auto& target_info = target_infos[target_it->second];
87 
88  const auto cols_ptr = reinterpret_cast<int64_t*>(
89  row_ptr + get_slot_off_quad(query_mem_desc) * sizeof(int64_t));
90  cols_ptr[target_slot] = (target_info.agg_kind == kCOUNT ? 0 : 0xdeadbeef);
91  }
92  }
93  std::vector<int64_t> values(upper_bound);
94  std::iota(values.begin(), values.end(), 1);
95  const auto null_pattern = null_val_bit_pattern(target_infos.back().sql_type, false);
96  values.push_back(null_pattern);
97  std::random_device rd;
98  std::mt19937 g(rd());
99  std::shuffle(values.begin(), values.end(), g);
100  CHECK_EQ(size_t(0), row_bytes % 8);
101  const auto row_size_quad = row_bytes / 8;
102  for (const auto val : values) {
103  std::vector<K> key(key_component_count, val);
104  auto value_slots = get_group_value(reinterpret_cast<int64_t*>(buff),
105  query_mem_desc.getEntryCount(),
106  reinterpret_cast<const int64_t*>(&key[0]),
107  key.size(),
108  sizeof(K),
109  row_size_quad,
110  nullptr);
111  CHECK(value_slots);
112  fill_one_entry_baseline(value_slots, val, target_infos);
113  }
114 }
115 
117  const std::vector<TargetInfo>& target_infos,
118  const QueryMemoryDescriptor& query_mem_desc,
119  const int64_t upper_bound) {
120  const auto key_component_count = query_mem_desc.getKeyCount();
121  const auto i64_buff = reinterpret_cast<int64_t*>(buff);
122  const auto target_slot_count = get_slot_count(target_infos);
123  const auto slot_to_target = get_slot_to_target_mapping(target_infos);
124  for (size_t i = 0; i < query_mem_desc.getEntryCount(); ++i) {
125  const auto first_key_comp_offset =
126  key_offset_rowwise(i, key_component_count, target_slot_count);
127  for (size_t key_comp_idx = 0; key_comp_idx < key_component_count; ++key_comp_idx) {
128  i64_buff[first_key_comp_offset + key_comp_idx] = EMPTY_KEY_64;
129  }
130  for (size_t target_slot = 0; target_slot < target_slot_count; ++target_slot) {
131  auto target_it = slot_to_target.find(target_slot);
132  CHECK(target_it != slot_to_target.end());
133  const auto& target_info = target_infos[target_it->second];
134  i64_buff[slot_offset_rowwise(
135  i, target_slot, key_component_count, target_slot_count)] =
136  (target_info.agg_kind == kCOUNT ? 0 : 0xdeadbeef);
137  }
138  }
139  std::vector<int64_t> values(upper_bound);
140  std::iota(values.begin(), values.end(), 1);
141  const auto null_pattern = null_val_bit_pattern(target_infos.back().sql_type, false);
142  values.push_back(null_pattern);
143  std::random_device rd;
144  std::mt19937 g(rd());
145  std::shuffle(values.begin(), values.end(), g);
146  for (const auto val : values) {
147  std::vector<int64_t> key(key_component_count, val);
148  auto value_slots = get_group_value(i64_buff,
149  query_mem_desc.getEntryCount(),
150  &key[0],
151  key.size(),
152  sizeof(int64_t),
153  key_component_count + target_slot_count,
154  nullptr);
155  CHECK(value_slots);
156  fill_one_entry_baseline(value_slots, val, target_infos, false, val == null_pattern);
157  }
158 }
159 
160 template <class T>
161 void check_sorted(const ResultSet& result_set,
162  const int64_t bound,
163  const size_t top_n,
164  const size_t desc) {
165  ASSERT_EQ(top_n, result_set.rowCount());
166  T ref_val = bound;
167  while (true) {
168  const auto row = result_set.getNextRow(true, false);
169  if (row.empty()) {
170  break;
171  }
172  ASSERT_EQ(size_t(3), row.size());
173  const auto ival = v<T>(row[2]);
174  ASSERT_EQ(ref_val, ival);
175  if (desc) {
176  --ref_val;
177  } else {
178  ++ref_val;
179  }
180  }
181 }
182 
183 std::vector<TargetInfo> get_sort_fp_target_infos() {
184  std::vector<TargetInfo> target_infos;
185  SQLTypeInfo null_ti(kNULLT, false);
186  SQLTypeInfo fp_ti(kFLOAT, false);
187  target_infos.push_back(TargetInfo{false, kMIN, fp_ti, null_ti, false, false});
188  target_infos.push_back(TargetInfo{false, kMIN, fp_ti, null_ti, false, false});
189  target_infos.push_back(TargetInfo{true, kSUM, fp_ti, fp_ti, true, false});
190  return target_infos;
191 }
192 
193 template <class K>
194 int64_t empty_key_val();
195 
196 template <>
198  return EMPTY_KEY_64;
199 }
200 
201 template <>
203  return EMPTY_KEY_32;
204 }
205 
206 template <class K>
207 void SortBaselineIntegersTestImpl(const bool desc) {
208  const auto target_infos = get_sort_int_target_infos();
209  const auto query_mem_desc = baseline_sort_desc(target_infos, 400, sizeof(K));
210  const auto row_set_mem_owner = std::make_shared<RowSetMemoryOwner>();
211  const int64_t upper_bound = 200;
212  const int64_t lower_bound = 1;
213  std::unique_ptr<ResultSet> rs(new ResultSet(
214  target_infos, ExecutorDeviceType::CPU, query_mem_desc, row_set_mem_owner, nullptr));
215  auto storage = rs->allocateStorage();
216  fill_storage_buffer_baseline_sort_int<K>(storage->getUnderlyingBuffer(),
217  target_infos,
218  query_mem_desc,
219  upper_bound,
220  empty_key_val<K>());
221  std::list<Analyzer::OrderEntry> order_entries;
222  order_entries.emplace_back(3, desc, false);
223  const size_t top_n = 5;
224  rs->sort(order_entries, top_n);
225  check_sorted<int64_t>(*rs, desc ? upper_bound : lower_bound, top_n, desc);
226 }
227 
228 } // namespace
229 
230 TEST(SortBaseline, IntegersKey64) {
231  for (const bool desc : {true, false}) {
232  SortBaselineIntegersTestImpl<int64_t>(desc);
233  }
234 }
235 
236 TEST(SortBaseline, IntegersKey32) {
237  for (const bool desc : {true, false}) {
238  SortBaselineIntegersTestImpl<int32_t>(desc);
239  }
240 }
241 
242 TEST(SortBaseline, Floats) {
243  for (const bool desc : {true, false}) {
244  for (int tle_no = 1; tle_no <= 3; ++tle_no) {
245  const auto target_infos = get_sort_fp_target_infos();
246  const auto query_mem_desc = baseline_sort_desc(target_infos, 400, 8);
247  const auto row_set_mem_owner = std::make_shared<RowSetMemoryOwner>();
248  const int64_t upper_bound = 200;
249  std::unique_ptr<ResultSet> rs(new ResultSet(target_infos,
251  query_mem_desc,
252  row_set_mem_owner,
253  nullptr));
254  auto storage = rs->allocateStorage();
256  storage->getUnderlyingBuffer(), target_infos, query_mem_desc, upper_bound);
257  std::list<Analyzer::OrderEntry> order_entries;
258  order_entries.emplace_back(tle_no, desc, false);
259  const size_t top_n = 5;
260  rs->sort(order_entries, top_n);
261  check_sorted<float>(*rs, desc ? upper_bound : 1, top_n, desc);
262  }
263  }
264 }
265 
266 int main(int argc, char** argv) {
268  testing::InitGoogleTest(&argc, argv);
269 
270 #ifdef HAVE_CUDA
271  try {
272  g_cuda_mgr.reset(new CudaMgr_Namespace::CudaMgr(0));
273  } catch (...) {
274  LOG(WARNING) << "Could not instantiate CudaMgr, will run on CPU";
275  }
276 #endif // HAVE_CUDA
277 
278  int err{0};
279  try {
280  err = RUN_ALL_TESTS();
281  } catch (const std::exception& e) {
282  LOG(ERROR) << e.what();
283  }
284 
285 #ifdef HAVE_CUDA
286  g_cuda_mgr.reset(nullptr);
287 #endif // HAVE_CUDA
288 
289  return err;
290 }
size_t slot_offset_rowwise(const size_t entry_idx, const size_t slot_idx, const size_t key_count, const size_t slot_count)
#define CHECK_EQ(x, y)
Definition: Logger.h:195
#define EMPTY_KEY_64
T g(const TargetValue &r)
Definition: TestHelpers.h:118
#define LOG(tag)
Definition: Logger.h:182
void setGroupColCompactWidth(const int8_t val)
std::unordered_map< size_t, size_t > get_slot_to_target_mapping(const std::vector< TargetInfo > &target_infos)
size_t get_slot_off_quad(const QueryMemoryDescriptor &query_mem_desc)
int64_t null_val_bit_pattern(const SQLTypeInfo &ti, const bool float_argument_input)
size_t get_slot_count(const std::vector< TargetInfo > &target_infos)
Definition: sqldefs.h:71
Definition: sqldefs.h:71
NEVER_INLINE DEVICE int64_t * get_group_value(int64_t *groups_buffer, const uint32_t groups_buffer_entry_count, const int64_t *key, const uint32_t key_count, const uint32_t key_width, const uint32_t row_size_quad, const int64_t *init_vals)
TEST(SortBaseline, IntegersKey64)
void fill_storage_buffer_baseline_sort_int(int8_t *buff, const std::vector< TargetInfo > &target_infos, const QueryMemoryDescriptor &query_mem_desc, const int64_t upper_bound, const int64_t empty_key)
size_t get_row_bytes(const QueryMemoryDescriptor &query_mem_desc)
void fill_storage_buffer_baseline_sort_fp(int8_t *buff, const std::vector< TargetInfo > &target_infos, const QueryMemoryDescriptor &query_mem_desc, const int64_t upper_bound)
Definition: sqldefs.h:71
size_t key_offset_rowwise(const size_t entry_idx, const size_t key_count, const size_t slot_count)
#define CHECK(condition)
Definition: Logger.h:187
void init_logger_stderr_only(int argc, char const *const *argv)
Definition: TestHelpers.h:194
void fill_one_entry_baseline(int64_t *value_slots, const int64_t v, const std::vector< TargetInfo > &target_infos, const bool empty, const bool null_val)
#define EMPTY_KEY_32
Definition: sqltypes.h:47
void check_sorted(const ResultSet &result_set, const int64_t bound, const size_t top_n, const size_t desc)
int main(int argc, char **argv)
QueryMemoryDescriptor baseline_sort_desc(const std::vector< TargetInfo > &target_infos, const size_t hash_entry_count, const size_t key_bytewidth)