github.com/rohankumardubey/aresdb@v0.0.2-0.20190517170215-e54e3ca06b9c/query/unittest_utils.hpp (about) 1 // Copyright (c) 2017-2018 Uber Technologies, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef QUERY_UNITTEST_UTILS_HPP_ 16 #define QUERY_UNITTEST_UTILS_HPP_ 17 18 #include <thrust/device_vector.h> 19 #include <thrust/equal.h> 20 #include <thrust/execution_policy.h> 21 #include <thrust/host_vector.h> 22 #include <thrust/transform.h> 23 #include <algorithm> 24 #include <cmath> 25 #include <functional> 26 #include <tuple> 27 #include "query/memory.hpp" 28 #include "query/utils.hpp" 29 30 typedef typename thrust::host_vector<unsigned char>::iterator charIter; 31 typedef typename thrust::host_vector<uint32_t>::iterator UInt32Iter; 32 typedef typename thrust::host_vector<int>::iterator IntIter; 33 typedef typename thrust::host_vector<bool>::iterator BoolIter; 34 typedef typename thrust::host_vector<uint8_t>::iterator Uint8Iter; 35 typedef typename thrust::host_vector<uint16_t>::iterator Uint16Iter; 36 37 struct float_compare_func { 38 __host__ __device__ 39 bool operator()(float x, float y) const { 40 return abs(x - y) < 0.0001; 41 } 42 }; 43 44 // Functor to compare the value element of a tuple against an expected value. 45 template<int N> 46 struct tuple_compare_func { 47 template<typename Value> 48 __host__ __device__ 49 bool operator()(thrust::tuple<Value, bool> t, Value v) const { 50 return thrust::get<N>(t) == v; 51 } 52 53 __host__ __device__ 54 bool operator()(thrust::tuple<float_t, bool> t, float_t v) const { 55 return float_compare_func()(thrust::get<N>(t), v); 56 } 57 }; 58 59 // compare_value extracts element from tuples returned by Iterator1 and compare 60 // with Iterator2. 61 template<typename Iterator1, typename Iterator2, int N> 62 inline bool compare_tuple(Iterator1 begin, 63 Iterator1 end, 64 Iterator2 expectedBegin) { 65 #ifdef RUN_ON_DEVICE 66 int size = end - begin; 67 typedef typename thrust::iterator_traits<Iterator1>::value_type V; 68 ares::device_vector<V> actualD(size); 69 thrust::copy(thrust::device, begin, end, actualD.begin()); 70 thrust::host_vector<V> actualH(size); 71 cudaMemcpy(actualH.data(), thrust::raw_pointer_cast(actualD.data()), 72 sizeof(V) * size, cudaMemcpyDeviceToHost); 73 CheckCUDAError("cudaMemcpy"); 74 return std::equal(actualH.begin(), actualH.end(), expectedBegin, 75 tuple_compare_func<N>()); 76 #else 77 return std::equal(begin, end, expectedBegin, tuple_compare_func<N>()); 78 #endif 79 } 80 81 template<typename Iterator1, typename Iterator2> 82 inline bool compare_value(Iterator1 begin, Iterator1 end, Iterator2 expected) { 83 return compare_tuple<Iterator1, Iterator2, 0>(begin, end, expected); 84 } 85 86 template<typename Iterator1, typename Iterator2> 87 inline bool compare_null(Iterator1 begin, Iterator1 end, Iterator2 expected) { 88 return compare_tuple<Iterator1, Iterator2, 1>(begin, end, expected); 89 } 90 91 // Pointer returned by this function must be released by caller. 92 template<typename V> 93 inline V *allocate(V *input, int size) { 94 size_t totalSize = sizeof(V) * size; 95 V *ptr; 96 #ifdef RUN_ON_DEVICE 97 ares::deviceMalloc(reinterpret_cast<void **>(&ptr), totalSize); 98 cudaMemcpy(ptr, input, totalSize, cudaMemcpyHostToDevice); 99 CheckCUDAError("cudaMemcpy"); 100 #else 101 ptr = reinterpret_cast<V *>(malloc(totalSize)); 102 memcpy(reinterpret_cast<void *>(ptr), 103 reinterpret_cast<void *>(input), 104 totalSize); 105 #endif 106 return ptr; 107 } 108 109 inline int align_offset(int offset, int alignment) { 110 return (offset + alignment - 1) / alignment * alignment; 111 } 112 113 // Pointer returned by this function must be released by caller. Pointers 114 // will be aligned by 8 bytes. Note if it's scratch space, values comes 115 // before nulls. So 5th parameter should be values bytes and 6th parameter 116 // is nullsBytes. 117 template<typename Value> 118 inline uint8_t * 119 allocate_column(uint32_t *counts, 120 uint8_t *nulls, 121 Value *values, 122 int countsBytes, 123 int nullsBytes, int valuesBytes) { 124 uint8_t *ptr; 125 int alignedCountsBytes = align_offset(countsBytes, 8); 126 int alignedNullsBytes = align_offset(nullsBytes, 8); 127 int alignedValuesBytes = align_offset(valuesBytes, 8); 128 int totalBytes = alignedCountsBytes + alignedNullsBytes + alignedValuesBytes; 129 #ifdef RUN_ON_DEVICE 130 ares::deviceMalloc(reinterpret_cast<void **>(&ptr), totalBytes); 131 if (counts != nullptr) { 132 cudaMemcpy(ptr, counts, countsBytes, cudaMemcpyHostToDevice); 133 CheckCUDAError("cudaMemcpy counts"); 134 } 135 136 if (nulls != nullptr) { 137 cudaMemcpy(ptr + alignedCountsBytes, nulls, nullsBytes, 138 cudaMemcpyHostToDevice); 139 CheckCUDAError("cudaMemcpy nulls"); 140 } 141 cudaMemcpy(ptr + alignedCountsBytes + alignedNullsBytes, 142 reinterpret_cast<void *>(values), 143 valuesBytes, 144 cudaMemcpyHostToDevice); 145 CheckCUDAError("cudaMemcpy values"); 146 #else 147 ptr = reinterpret_cast<uint8_t *>(malloc(totalBytes)); 148 if (counts != nullptr) { 149 memcpy(ptr, counts, countsBytes); 150 } 151 152 if (nulls != nullptr) { 153 memcpy(ptr + alignedCountsBytes, nulls, nullsBytes); 154 } 155 memcpy(ptr + alignedCountsBytes + alignedNullsBytes, 156 reinterpret_cast<void *>(values), 157 valuesBytes); 158 #endif 159 return ptr; 160 } 161 162 template<typename V, typename CmpFunc> 163 inline bool equal(V *resBegin, V *resEnd, V *expectedBegin, CmpFunc f) { 164 #ifdef RUN_ON_DEVICE 165 int size = resEnd - resBegin; 166 thrust::host_vector<V> expectedH(expectedBegin, expectedBegin + size); 167 thrust::device_vector<V> expectedV = expectedH; 168 return thrust::equal(thrust::device, resBegin, resEnd, expectedV.begin(), f); 169 #else 170 return thrust::equal(resBegin, resEnd, expectedBegin, f); 171 #endif 172 } 173 174 template<typename V> 175 inline bool equal(V *resBegin, V *resEnd, V *expectedBegin) { 176 return equal(resBegin, resEnd, expectedBegin, thrust::equal_to<V>()); 177 } 178 179 inline bool equal(float *resBegin, float *resEnd, float *expectedBegin) { 180 return equal(resBegin, resEnd, expectedBegin, float_compare_func()); 181 } 182 183 // equal_print prints the result if it's running on host and returns whether 184 // the result is as expected. 185 template<typename V, typename CmpFunc> 186 inline bool equal_print(V *resBegin, V *resEnd, V *expectedBegin, CmpFunc f) { 187 int size = resEnd - resBegin; 188 #ifdef RUN_ON_DEVICE 189 thrust::host_vector<V> expectedH(expectedBegin, expectedBegin + size); 190 thrust::device_vector<V> expectedV = expectedH; 191 return thrust::equal(thrust::device, resBegin, resEnd, expectedV.begin(), f); 192 #else 193 std::cout << "result:" << std::endl; 194 std::ostream_iterator<int > out_it(std::cout, ", "); 195 std::copy(resBegin, resEnd, out_it); 196 std::cout << std::endl; 197 std::cout << "expected:" << std::endl; 198 std::copy(expectedBegin, expectedBegin + size, out_it); 199 std::cout << std::endl; 200 return thrust::equal(resBegin, resEnd, expectedBegin, f); 201 #endif 202 } 203 204 template<typename V> 205 inline bool equal_print(V *resBegin, V *resEnd, V *expectedBegin) { 206 return equal_print(resBegin, resEnd, expectedBegin, thrust::equal_to<V>()); 207 } 208 209 inline bool equal_print(float *resBegin, float *resEnd, float *expectedBegin) { 210 return equal_print(resBegin, resEnd, expectedBegin, float_compare_func()); 211 } 212 213 inline uint32_t get_ts(int year, int month, int day) { 214 std::tm tm; 215 tm.tm_hour = 0; 216 tm.tm_min = 0; 217 tm.tm_sec = 0; 218 tm.tm_mday = day; 219 tm.tm_mon = month - 1; 220 tm.tm_year = year - 1900; 221 return static_cast<uint32_t >(timegm(&tm)); 222 } 223 224 inline GeoShapeBatch get_geo_shape_batch(const float *shapeLatsH, 225 const float *shapeLongsH, 226 const uint8_t *shapeIndexsH, 227 uint8_t numShapes, 228 int32_t totalNumPoints) { 229 uint8_t *shapeLatLongsH = reinterpret_cast<uint8_t *>( 230 malloc(totalNumPoints * 4 * 2 + totalNumPoints)); 231 for (int i = 0; i < totalNumPoints; i++) { 232 reinterpret_cast<float *>(shapeLatLongsH)[i] = shapeLatsH[i]; 233 } 234 for (int i = 0; i < totalNumPoints; i++) { 235 reinterpret_cast<float *>(shapeLatLongsH)[totalNumPoints + i] = 236 shapeLongsH[i]; 237 } 238 for (int i = 0; i < totalNumPoints; i++) { 239 shapeLatLongsH[totalNumPoints * 8 + i] = shapeIndexsH[i]; 240 } 241 uint8_t *shapeLatLongs = 242 allocate(shapeLatLongsH, totalNumPoints * 4 * 2 + totalNumPoints); 243 uint8_t totalWords = (numShapes + 31) / 32; 244 GeoShapeBatch geoShapeBatch = {shapeLatLongs, totalNumPoints, totalWords}; 245 free(shapeLatLongsH); 246 return geoShapeBatch; 247 } 248 249 inline GeoShape get_geo_shape(const float *shapeLatH, 250 const float *shapeLongH, uint16_t numPoints) { 251 float *shapeLat = allocate(const_cast<float *>(shapeLatH), numPoints); 252 float *shapeLong = allocate(const_cast<float *>(shapeLongH), numPoints); 253 GeoShape geoShape = {shapeLat, shapeLong, numPoints}; 254 return geoShape; 255 } 256 257 template<typename V> 258 inline void release(V* devPtr) { 259 ares::deviceFree(devPtr); 260 } 261 262 inline void release(GeoShapeBatch shapes) { 263 ares::deviceFree(shapes.LatLongs); 264 } 265 266 inline void release(GeoShape shape) { 267 ares::deviceFree(shape.Lats); 268 ares::deviceFree(shape.Longs); 269 } 270 271 #endif // QUERY_UNITTEST_UTILS_HPP_