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_