query/algorithm_unittest.cu (1,721 lines of code) (raw):

// Copyright (c) 2017-2018 Uber Technologies, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include <thrust/transform.h> #include <cstdint> #include <cfloat> #include <algorithm> #include <cmath> #include <exception> #include <iterator> #include <iostream> #include <type_traits> #include <unordered_map> #include "gtest/gtest.h" #include "algorithm.hpp" #include "iterator.hpp" #include "query/time_series_aggregate.h" #include "transform.hpp" #include "unittest_utils.hpp" namespace ares { template<typename TypeA, typename TypeB, typename ExpectedType> void checkCommonTypeAsExpected() { bool isSame = std::is_same<typename common_type<TypeA, TypeB>::type, ExpectedType>::value; EXPECT_TRUE(isSame); } // cppcheck-suppress * TEST(CommonTypeTraitsTest, CheckCommonType) { checkCommonTypeAsExpected<float_t, float_t, float_t>(); checkCommonTypeAsExpected<int16_t, float_t, float_t>(); checkCommonTypeAsExpected<float_t, float_t, float_t>(); checkCommonTypeAsExpected<float_t, uint32_t, float_t>(); checkCommonTypeAsExpected<int16_t, uint32_t, int32_t>(); checkCommonTypeAsExpected<int32_t, uint32_t, int32_t>(); checkCommonTypeAsExpected<int32_t, bool, int32_t>(); checkCommonTypeAsExpected<uint32_t, bool, uint32_t>(); checkCommonTypeAsExpected<uint16_t, bool, uint32_t>(); } // cppcheck-suppress * TEST(CGoCallResHandleTest, CheckCGoCallResHandle) { CGoCallResHandle resHandle = {0, nullptr}; try { throw std::invalid_argument("test"); } catch (std::exception &e) { resHandle.pStrErr = strdup(e.what()); } EXPECT_STREQ(resHandle.pStrErr, "test"); EXPECT_TRUE(resHandle.pStrErr != nullptr); free(const_cast<char *>(resHandle.pStrErr)); CGoCallResHandle resHandle2 = {0, nullptr}; try { printf("test CGoCallResHandle\n"); } catch (std::exception &e) { resHandle2.pStrErr = strdup(e.what()); } EXPECT_TRUE(resHandle2.pStrErr == nullptr); } // cppcheck-suppress * TEST(UnaryTransformTest, CheckInt) { const int size = 3; uint32_t indexVectorH[size * 2] = {0, 1, 2}; int inputValuesH[size] = {-1, 1, 0}; // T T F uint8_t inputNullsH[1 + ((size - 1) / 8)] = {0x03}; int outputValuesH[size] = {0, 0, 0}; bool outputNullsH[size] = {false, false, false}; uint32_t *indexVector = allocate(&indexVectorH[0], size * 2); uint8_t *basePtr = allocate_column(nullptr, &inputNullsH[0], &inputValuesH[0], 0, 1, 12); uint8_t *outputBasePtr = allocate_column(nullptr, reinterpret_cast<uint8_t *>(&outputValuesH[0]), &outputNullsH[0], 0, 12, 3); DefaultValue defaultValue = {false, {.Int32Val = 0}}; VectorPartySlice inputVP = {basePtr, 0, 8, 0, Int32, defaultValue}; ScratchSpaceVector outputScratchSpace = {outputBasePtr, 16, Int32}; InputVector input = {{.VP = inputVP}, VectorPartyInput}; OutputVector output = {{.ScratchSpace = outputScratchSpace}, ScratchSpaceOutput}; UnaryTransform(input, output, indexVector, size, nullptr, 0, Negate, 0, 0); int expectedValues[size] = {1, -1, 0}; bool expectedNulls[size] = {true, true, false}; int *outputValuesD = reinterpret_cast<int *>(outputBasePtr); bool *outputNulls = reinterpret_cast<bool *>(outputBasePtr) + 16; EXPECT_TRUE( equal(outputValuesD, outputValuesD + size, &expectedValues[0])); EXPECT_TRUE( equal(outputNulls, outputNulls + size, &expectedNulls[0])); release(basePtr); release(outputBasePtr); release(indexVector); } // cppcheck-suppress * TEST(UnaryTransformTest, CheckConstant) { const int size = 3; uint32_t indexVectorH[size * 2] = {0, 1, 2}; ConstantVector constant = { {.IntVal = 1}, true, ConstInt, }; int outputValuesH[size] = {0, 0, 0}; bool outputNullsH[size] = {false, false, false}; uint32_t *indexVector = allocate(&indexVectorH[0], size * 2); uint8_t *outputBasePtr = allocate_column(nullptr, reinterpret_cast<uint8_t *>(&outputValuesH[0]), &outputNullsH[0], 0, 12, 3); ScratchSpaceVector outputScratchSpace = {outputBasePtr, 16, Int32}; InputVector input = {{.Constant = constant}, ConstantInput}; OutputVector output = {{.ScratchSpace = outputScratchSpace}, ScratchSpaceOutput}; UnaryTransform(input, output, &indexVector[0], size, nullptr, 0, Negate, 0, 0); int expectedValues[3] = {-1, -1, -1}; bool expectedNulls[3] = {true, true, true}; int *outputValuesD = reinterpret_cast<int *>(outputBasePtr); bool *outputNulls = reinterpret_cast<bool *>(outputBasePtr) + 16; EXPECT_TRUE( equal(outputValuesD, outputValuesD + size, &expectedValues[0])); EXPECT_TRUE( equal(outputNulls, outputNulls + size, &expectedNulls[0])); release(outputBasePtr); release(indexVector); } // cppcheck-suppress * TEST(UnaryTransformTest, CheckMeasureOutputIteratorForAvg) { const int size = 3; uint32_t indexVectorH[size * 2] = {0, 1, 2}; uint32_t baseCountsH[size + 1] = {0, 3, 9, 12}; int inputValuesH[size] = {-1, 1, 0}; // T T F uint8_t inputNullsH[1 + ((size - 1) / 8)] = {0x03}; int64_t outputValuesH[size] = {0, 0, 0}; uint32_t *indexVector = allocate(&indexVectorH[0], size * 2); uint32_t *baseCounts = allocate(&baseCountsH[0], size + 1); uint8_t *basePtr = allocate_column(nullptr, &inputNullsH[0], &inputValuesH[0], 0, 1, 12); int64_t *outputValuesD = allocate(&outputValuesH[0], size); DefaultValue defaultValue = {false, {.Int32Val = 0}}; VectorPartySlice inputVP = {basePtr, 0, 8, 0, Int32, defaultValue}; MeasureOutputVector outputMeasure = { reinterpret_cast<uint32_t *>(outputValuesD), Int64, AGGR_SUM_SIGNED}; InputVector input = {{.VP = inputVP}, VectorPartyInput}; OutputVector output = {{.Measure = outputMeasure}, MeasureOutput}; UnaryTransform(input, output, indexVector, size, baseCounts, 0, Negate, 0, 0); int64_t expectedValues[3] = {3, -6, 0}; EXPECT_TRUE(equal(outputValuesD, outputValuesD + size, &expectedValues[0])); // Test NOOP functor UnaryTransform(input, output, indexVector, size, baseCounts, 0, Noop, 0, 0); int64_t expectedValues2[3] = {-3, 6, 0}; EXPECT_TRUE(equal(outputValuesD, outputValuesD + size, &expectedValues2[0])); // Test avg aggregation. MeasureOutputVector outputMeasure2 = { reinterpret_cast<uint32_t *>(outputValuesD), Float64, AGGR_AVG_FLOAT}; OutputVector output2 = {{.Measure = outputMeasure2}, MeasureOutput}; UnaryTransform(input, output2, indexVector, size, baseCounts, 0, Noop, 0, 0); float_t expectedValues3[6] = {-1.0, 0, 1.0, 0, 0, 0}; *reinterpret_cast<uint32_t*>(&expectedValues3[1]) = 3; *reinterpret_cast<uint32_t*>(&expectedValues3[3]) = 6; EXPECT_TRUE(equal_print(outputValuesD, outputValuesD + size, reinterpret_cast<int64_t*>(&expectedValues3[0]))); release(basePtr); release(outputValuesD); release(indexVector); release(baseCounts); } // cppcheck-suppress * TEST(UnaryTransformTest, CheckDimensionOutputIterator) { const int size = 3; uint32_t indexVectorH[size * 2] = {0, 1, 2}; int16_t inputValuesH[size] = {-1, 1, 0}; // T T F uint8_t inputNullsH[1 + ((size - 1) / 8)] = {0x03}; uint8_t outputValuesH[3 * 3]; thrust::fill(std::begin(outputValuesH), std::end(outputValuesH), 0); uint8_t *basePtr = allocate_column(nullptr, &inputNullsH[0], &inputValuesH[0], 0, 1, 6); uint32_t *indexVector = allocate(&indexVectorH[0], size * 2); uint8_t *outputValuesD = allocate(&outputValuesH[0], 9); DefaultValue defaultValue = {false, {.Int32Val = 0}}; VectorPartySlice inputVP = {basePtr, 0, 8, 0, Int16, defaultValue}; DimensionOutputVector outputDimension = { outputValuesD, outputValuesD + 6, Int16}; InputVector input = {{.VP = inputVP}, VectorPartyInput}; OutputVector output = {{.Dimension = outputDimension}, DimensionOutput}; UnaryTransform(input, output, indexVector, size, nullptr, 0, Negate, 0, 0); uint8_t expectedValues[9] = {1, 0, 0xFF, 0xFF, 0, 0, 1, 1, 0}; EXPECT_TRUE(equal(outputValuesD, outputValuesD + 9, &expectedValues[0])); // Test NOOP functor UnaryTransform(input, output, indexVector, size, nullptr, 0, Noop, 0, 0); uint8_t expectedValues2[9] = {0xFF, 0xFF, 1, 0, 0, 0, 1, 1, 0}; EXPECT_TRUE(equal(outputValuesD, outputValuesD + 9, &expectedValues2[0])); release(basePtr); release(outputValuesD); release(indexVector); } // cppcheck-suppress * TEST(UnaryFilterTest, CheckFilter) { const int size = 3; uint32_t indexVectorH[size] = {0, 1, 2}; RecordID recordIDVectorH[3]; for (int i = 0; i < size; i++) { RecordID recordID = {(int32_t) 0, (uint32_t) i}; recordIDVectorH[i] = recordID; } uint8_t boolVectorH[size] = {0, 0, 0}; int inputValuesH[size] = {1, 0, 1}; uint8_t inputNullsH[size] = {1, 0, 1}; uint8_t *basePtr = allocate_column(nullptr, reinterpret_cast<uint8_t *>(&inputValuesH[0]), &inputNullsH[0], 0, 12, 3); uint32_t *indexVector = allocate(&indexVectorH[0], size); uint8_t *boolVector = allocate(&boolVectorH[0], size); RecordID *recordIDVector = allocate(&recordIDVectorH[0], size); ScratchSpaceVector inputVP = {basePtr, 16, Int32}; InputVector input = {{.ScratchSpace = inputVP}, ScratchSpaceInput}; RecordID *recordIDVectors[1] = {recordIDVector}; CGoCallResHandle resHandle = UnaryFilter(input, indexVector, boolVector, size, recordIDVectors, 1, nullptr, 0, IsNotNull, 0, 0); EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 2); EXPECT_EQ(resHandle.pStrErr, nullptr); int length = reinterpret_cast<int64_t>(resHandle.res); uint32_t expectedValues[2] = {0, 2}; RecordID recordID0 = {(int32_t) 0, (int32_t) 0}; RecordID recordID1 = {(int32_t) 0, (int32_t) 2}; RecordID expectedRecordIDs[2] = {recordID0, recordID1}; EXPECT_TRUE(equal(indexVector, indexVector + length, &expectedValues[0])); EXPECT_TRUE(equal( reinterpret_cast<uint8_t *>(recordIDVector), reinterpret_cast<uint8_t *>(recordIDVector) + sizeof(RecordID) * length, reinterpret_cast<uint8_t *>(&expectedRecordIDs[0]))); release(basePtr); release(boolVector); release(indexVector); release(recordIDVector); } // cppcheck-suppress * TEST(UnaryFilterTest, AllEmpty) { const int size = 3; uint32_t indexVectorH[size] = {0, 1, 2}; uint8_t boolVectorH[size] = {0, 0, 0}; int inputValuesH[size] = {0, 0, 0}; uint8_t inputNullsH[size] = {1, 1, 1}; uint8_t *basePtr = allocate_column(nullptr, reinterpret_cast<uint8_t *>(&inputValuesH[0]), &inputNullsH[0], 0, 12, 3); uint32_t *indexVector = allocate(&indexVectorH[0], size); uint8_t *boolVector = allocate(&boolVectorH[0], size); ScratchSpaceVector inputVP = {basePtr, 16, Int32}; InputVector input = {{.ScratchSpace = inputVP}, ScratchSpaceInput}; CGoCallResHandle resHandle = UnaryFilter(input, indexVector, boolVector, size, nullptr, 0, nullptr, 0, Negate, 0, 0); EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 0); EXPECT_EQ(resHandle.pStrErr, nullptr); release(basePtr); release(indexVector); } // cppcheck-suppress * TEST(BinaryTransformTest, CheckInt) { const int size = 3; uint32_t indexVectorH[size * 2] = {0, 1, 2}; int lhsValuesH[size] = {-1, 1, 0}; // T T F uint8_t lhsNullsH[1 + ((size - 1) / 8)] = {0x03}; uint8_t *lhsBasePtr = allocate_column(nullptr, &lhsNullsH[0], &lhsValuesH[0], 0, 1, 12); int rhsValuesH[size] = {0, 1, -1}; // F T T uint8_t rhsNullsH[1 + ((size - 1) / 8)] = {0x06}; uint8_t *rhsBasePtr = allocate_column(nullptr, &rhsNullsH[0], &rhsValuesH[0], 0, 1, 12); int outputValuesH[size] = {0, 0, 0}; bool outputNullsH[size] = {false, false, false}; uint8_t *outputBasePtr = allocate_column(nullptr, reinterpret_cast<uint8_t *>(&outputValuesH[0]), &outputNullsH[0], 0, 12, 3); uint32_t *indexVector = allocate(&indexVectorH[0], size * 2); DefaultValue defaultValue = {false, {.Int32Val = 0}}; VectorPartySlice lhsColumn = {lhsBasePtr, 0, 8, 0, Int32, defaultValue}; VectorPartySlice rhsColumn = {rhsBasePtr, 0, 8, 0, Int32, defaultValue}; ScratchSpaceVector outputScratchSpace = {outputBasePtr, 16, Int32}; InputVector lhs = {{.VP = lhsColumn}, VectorPartyInput}; InputVector rhs = {{.VP = rhsColumn}, VectorPartyInput}; OutputVector output = {{.ScratchSpace = outputScratchSpace}, ScratchSpaceOutput}; BinaryTransform(lhs, rhs, output, indexVector, size, nullptr, 0, Plus, 0, 0); int expectedValues[3] = {0, 2, 0}; bool expectedNulls[3] = {false, true, false}; int *outputValuesD = reinterpret_cast<int *>(outputBasePtr); bool *outputNulls = reinterpret_cast<bool *>(outputBasePtr) + 16; EXPECT_TRUE( equal(outputValuesD, outputValuesD + size, &expectedValues[0])); EXPECT_TRUE( equal(outputNulls, outputNulls + size, &expectedNulls[0])); release(lhsBasePtr); release(rhsBasePtr); release(outputBasePtr); release(indexVector); } // cppcheck-suppress * TEST(BinaryTransformTest, CheckGeoPoint) { const int size = 3; uint32_t indexVectorH[size * 2] = {0, 1, 2}; GeoPointT lhsValuesH[size] = {{1, 1}, {1, 0}, {0, 0}}; // T T F uint8_t lhsNullsH[1 + ((size - 1) / 8)] = {0x03}; uint8_t *lhsBasePtr = allocate_column(nullptr, &lhsNullsH[0], &lhsValuesH[0], 0, 1, 24); ConstantVector rhsConstant = {{.GeoPointVal = {1, 1}}, true, ConstGeoPoint}; uint32_t outputValuesH[size] = {false, false, false}; bool outputNullsH[size] = {false, false, false}; uint8_t *outputBasePtr = allocate_column(nullptr, reinterpret_cast<uint8_t *>(&outputValuesH[0]), &outputNullsH[0], 0, 12, 3); uint32_t *indexVector = allocate(&indexVectorH[0], size * 2); DefaultValue defaultValue = {false, {.Int32Val = 0}}; VectorPartySlice lhsColumn = {lhsBasePtr, 0, 8, 0, GeoPoint, defaultValue}; ScratchSpaceVector outputScratchSpace = {outputBasePtr, 16, Uint32}; InputVector lhs = {{.VP = lhsColumn}, VectorPartyInput}; InputVector rhs = {{.Constant = rhsConstant}, ConstantInput}; OutputVector output = {{.ScratchSpace = outputScratchSpace}, ScratchSpaceOutput}; BinaryTransform(lhs, rhs, output, indexVector, size, nullptr, 0, Equal, 0, 0); uint32_t expectedValues[3] = {true, false, false}; bool expectedNulls[3] = {true, true, false}; uint32_t *outputValuesD = reinterpret_cast<uint32_t *>(outputBasePtr); bool *outputNulls = reinterpret_cast<bool *>(outputBasePtr) + 16; EXPECT_TRUE( equal(outputValuesD, outputValuesD + size, &expectedValues[0])); EXPECT_TRUE( equal(outputNulls, outputNulls + size, &expectedNulls[0])); int rhsValuesH[size] = {0, 1, -1}; // F T T uint8_t rhsNullsH[1 + ((size - 1) / 8)] = {0x06}; uint8_t *rhsBasePtr = allocate_column(nullptr, &rhsNullsH[0], &rhsValuesH[0], 0, 1, 12); VectorPartySlice rhsColumn = {rhsBasePtr, 0, 8, 0, Int32, defaultValue}; InputVector rhsVector = {{.VP = rhsColumn}, VectorPartyInput}; CGoCallResHandle resHandle = {0, nullptr}; resHandle = BinaryTransform(lhs, rhsVector, output, indexVector, size, nullptr, 0, Equal, 0, 0); EXPECT_TRUE(resHandle.pStrErr != nullptr); free(const_cast<char *>(resHandle.pStrErr)); release(lhsBasePtr); release(rhsBasePtr); release(outputBasePtr); release(indexVector); } // cppcheck-suppress * TEST(BinaryTransformTest, CheckFloatAndUnpackedBoolIter) { const int size = 3; uint32_t indexVectorH[size * 2] = {0, 1, 2}; int lhsValuesH[size] = {-1, 1, 0}; uint8_t lhsNullsH[size] = {1, 1, 1}; uint8_t *lhsBasePtr = allocate_column(nullptr, reinterpret_cast<uint8_t *>(&lhsValuesH[0]), &lhsNullsH[0], 0, 12, 3); float rhsValuesH[size] = {1.1, -1.1, 0.1}; uint8_t rhsNullsH[size] = {1, 1, 1}; uint8_t *rhsBasePtr = allocate_column(nullptr, reinterpret_cast<uint8_t *>(&rhsValuesH[0]), &rhsNullsH[0], 0, 12, 3); float outputValuesH[size] = {200, 0, 0}; bool outputNullsH[size] = {false, false, false}; uint8_t *outputBasePtr = allocate_column(nullptr, reinterpret_cast<uint8_t *>(&outputValuesH[0]), &outputNullsH[0], 0, 12, 3); uint32_t *indexVector = allocate(&indexVectorH[0], size * 2); ScratchSpaceVector lhsColumn = {lhsBasePtr, 16, Int32}; ScratchSpaceVector rhsColumn = {rhsBasePtr, 16, Float32}; ScratchSpaceVector outputScratchSpace = { outputBasePtr, 16, Float32}; InputVector lhs = {{.ScratchSpace = lhsColumn}, ScratchSpaceInput}; InputVector rhs = {{.ScratchSpace = rhsColumn}, ScratchSpaceInput}; OutputVector output = {{.ScratchSpace = outputScratchSpace}, ScratchSpaceOutput}; BinaryTransform(lhs, rhs, output, indexVector, size, nullptr, 0, Minus, 0, 0); float expectedValues[3] = {-2.1, 2.1, -0.1}; bool expectedNulls[3] = {true, true, true}; float_t *outputValuesD = reinterpret_cast<float_t *>(outputBasePtr); bool *outputNulls = reinterpret_cast<bool *>(outputBasePtr) + 16; EXPECT_TRUE( equal(outputValuesD, outputValuesD + size, &expectedValues[0])); EXPECT_TRUE( equal(outputNulls, outputNulls + size, &expectedNulls[0])); // transform using multiply functor. BinaryTransform(lhs, rhs, output, indexVector, size, nullptr, 0, Multiply, 0, 0); float expectedValues2[3] = {-1.1, -1.1, -0}; bool expectedNulls2[3] = {true, true, true}; EXPECT_TRUE( equal(outputValuesD, outputValuesD + size, &expectedValues2[0])); EXPECT_TRUE( equal(outputNulls, outputNulls + size, &expectedNulls2[0])); release(lhsBasePtr); release(rhsBasePtr); release(outputBasePtr); release(indexVector); } // cppcheck-suppress * TEST(BinaryTransformTest, CheckConstantIterator) { const int size = 3; uint32_t indexVectorH[size * 2] = {0, 1, 2}; int columnValuesH[size] = {-1, 1, 0}; uint8_t columnNullsH[size] = {1, 1, 1}; uint8_t *columnBasePtr = allocate_column(nullptr, reinterpret_cast<uint8_t *>(&columnValuesH[0]), &columnNullsH[0], 0, 12, 3); float outputValuesH[size] = {0, 0, 0}; uint8_t outputNullsH[size] = {false, false, false}; uint8_t *outputBasePtr = allocate_column(nullptr, reinterpret_cast<uint8_t *>(&outputValuesH[0]), &outputNullsH[0], 0, 12, 3); uint32_t *indexVector = allocate(&indexVectorH[0], size * 2); ScratchSpaceVector lhsColumn = {columnBasePtr, 16, Int32}; ConstantVector rhsConstant = {{.FloatVal = 0.1}, true, ConstFloat}; ScratchSpaceVector outputScratchSpace = {outputBasePtr, 16, Float32}; InputVector lhs = {{.ScratchSpace = lhsColumn}, ScratchSpaceInput}; InputVector rhs = {{.Constant = rhsConstant}, ConstantInput}; OutputVector output = {{.ScratchSpace = outputScratchSpace}, ScratchSpaceOutput}; BinaryTransform(lhs, rhs, output, indexVector, size, nullptr, 0, Plus, 0, 0); float expectedValues[3] = {-0.9, 1.1, 0.1}; bool expectedNulls[3] = {true, true, true}; float_t *outputValuesD = reinterpret_cast<float_t *>(outputBasePtr); bool *outputNulls = reinterpret_cast<bool *>(outputBasePtr) + 16; EXPECT_TRUE( equal(outputValuesD, outputValuesD + size, &expectedValues[0])); EXPECT_TRUE( equal(outputNulls, outputNulls + size, &expectedNulls[0])); release(columnBasePtr); release(outputBasePtr); release(indexVector); } // cppcheck-suppress * TEST(BinaryFilterTest, CheckFilter) { const int size = 3; int lhsValuesH[size] = {0, 1, 2}; uint8_t lhsNullsH[size] = {1, 1, 1}; uint8_t *lhsBasePtr = allocate_column(nullptr, reinterpret_cast<uint8_t *>(&lhsValuesH[0]), &lhsNullsH[0], 0, 12, 3); float rhsValuesH[size] = {0.1, 0.9, 1.9}; uint8_t rhsNullsH[size] = {1, 1, 1}; uint8_t *rhsBasePtr = allocate_column(nullptr, reinterpret_cast<uint8_t *>(&rhsValuesH[0]), &rhsNullsH[0], 0, 12, 3); uint32_t indexVectorH[size * 2] = {0, 1, 2}; uint8_t boolVectorH[size] = {0, 0, 0}; uint32_t *indexVector = allocate(&indexVectorH[0], size); uint8_t *boolVector = allocate(&boolVectorH[0], size); ScratchSpaceVector lhsColumn = {lhsBasePtr, 16, Int32}; ScratchSpaceVector rhsColumn = {rhsBasePtr, 16, Float32}; InputVector lhs = {{.ScratchSpace = lhsColumn}, ScratchSpaceInput}; InputVector rhs = {{.ScratchSpace = rhsColumn}, ScratchSpaceInput}; CGoCallResHandle resHandle = BinaryFilter(lhs, rhs, indexVector, boolVector, size, nullptr, 0, nullptr, 0, GreaterThan, 0, 0); EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 2); EXPECT_EQ(resHandle.pStrErr, nullptr); int length = reinterpret_cast<int64_t>(resHandle.res); uint32_t expectedValues[2] = {1, 2}; EXPECT_TRUE( equal(indexVector, indexVector + length, &expectedValues[0])); release(lhsBasePtr); release(rhsBasePtr); release(indexVector); release(boolVector); } // cppcheck-suppress * TEST(BinaryTransformTest, CheckMeasureOutputIterator) { const int size = 3; uint32_t indexVectorH[size * 2] = {0, 1, 2}; uint32_t baseCountsH[size + 1] = {0, 3, 9, 10}; int lhsValuesH[size] = {-1, 1, 0}; uint8_t lhsNullsH[size] = {1, 1, 0}; uint8_t *lhsBasePtr = allocate_column(nullptr, reinterpret_cast<uint8_t *>(&lhsValuesH[0]), &lhsNullsH[0], 0, 12, 3); float rhsValuesH[size] = {1.1, -1.1, 0.1}; uint8_t rhsNullsH[size] = {1, 1, 1}; uint8_t *rhsBasePtr = allocate_column(nullptr, reinterpret_cast<uint8_t *>(&rhsValuesH[0]), &rhsNullsH[0], 0, 12, 3); float outputValuesH[size] = {0, 0, 0}; float *outputValuesD = allocate(&outputValuesH[0], size); uint32_t *indexVector = allocate(&indexVectorH[0], size); uint32_t *baseCounts = allocate(&baseCountsH[0], size); ScratchSpaceVector lhsColumn = {lhsBasePtr, 16, Int32}; ScratchSpaceVector rhsColumn = {rhsBasePtr, 16, Float32}; MeasureOutputVector outputMeasure = { reinterpret_cast<uint32_t *>(outputValuesD), Float32, AGGR_SUM_FLOAT}; InputVector lhs = {{.ScratchSpace = lhsColumn}, ScratchSpaceInput}; InputVector rhs = {{.ScratchSpace = rhsColumn}, ScratchSpaceInput}; OutputVector output = {{.Measure = outputMeasure}, MeasureOutput}; BinaryTransform(lhs, rhs, output, indexVector, size, baseCounts, 0, Minus, 0, 0); float expectedValues[3] = {-6.3, 12.6, 0.0}; EXPECT_TRUE( equal(outputValuesD, outputValuesD + 3, &expectedValues[0])); release(lhsBasePtr); release(rhsBasePtr); release(outputValuesD); release(indexVector); release(baseCounts); } // cppcheck-suppress * TEST(InitIndexVectorTest, InitIndexVector) { const int size = 3; uint32_t indexVectorH[size * 2] = {0, 0, 0}; uint32_t *indexVector = allocate(&indexVectorH[0], 3); InitIndexVector(indexVector, 0, 3, 0, 0); uint32_t expectedValues[3] = {0, 1, 2}; EXPECT_TRUE( equal(indexVector, indexVector + size, &expectedValues[0])); release(indexVector); } // cppcheck-suppress * TEST(HashLookupTest, CheckLookup) { // hash index created in golang cuckoo_hash_index uint8_t bucketsH[312] = { 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 12, 0, 0, 0, 140, 236, 116, 56, 157, 195, 184, 133, 16, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 17, 0, 0, 0, 11, 0, 0, 0, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 10, 0, 0, 0, 0, 0, 0, 0, 14, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 121, 236, 209, 218, 160, 185, 109, 187, 0, 0, 0, 0, 8, 0, 0, 0, 15, 0, 0, 0, 9, 0, 0, 0, 1, 0, 0, 0, 10, 0, 0, 0, 14, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 13, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t *buckets = allocate(bucketsH, 312); CuckooHashIndex hashIndex = { buckets, {(uint32_t) 2596996162, (uint32_t) 4039455774, (uint32_t) 2854263694, (uint32_t) 1879968118}, 4, 4, 2}; const int size = 18; uint32_t indexVectorH[size] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}; uint32_t inputValuesH[size] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}; uint8_t inputNullsH[3] = {0xFF, 0xFF, 0xFF}; uint8_t *basePtr = allocate_column(nullptr, &inputNullsH[0], &inputValuesH[0], 0, 3, size * 4); RecordID outputValuesH[18]; uint32_t *indexVector = allocate(&indexVectorH[0], size); RecordID *outputValuesD = allocate(&outputValuesH[0], size); DefaultValue defaultValue = {false, {.Int32Val = 0}}; VectorPartySlice inputVP = {basePtr, 0, 8, 0, Int32, defaultValue}; InputVector input = {{.VP = inputVP}, VectorPartyInput}; HashLookup(input, outputValuesD, indexVector, size, nullptr, 0, hashIndex, 0, 0); RecordID expectedOutputValues[18]; for (int i = 0; i < size; i++) { RecordID recordID = {(int32_t) 0, (uint32_t) i}; expectedOutputValues[i] = recordID; } EXPECT_TRUE( equal(reinterpret_cast<uint8_t *>(outputValuesD), reinterpret_cast<uint8_t *>( outputValuesD) + sizeof(RecordID) * size, reinterpret_cast<uint8_t *>(&expectedOutputValues[0]))); release(buckets); release(indexVector); release(basePtr); release(outputValuesD); } // cppcheck-suppress * TEST(HashLookupTest, CheckUUID) { // hash index created in golang cuckoo_hash_index uint8_t bucketsH[600] = { 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 154, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint8_t *buckets = allocate(bucketsH, 600); CuckooHashIndex hashIndex = { buckets, {(uint32_t) 1904795661, (uint32_t) 1908039658, (uint32_t) 3167437076, (uint32_t) 4232957548}, 16, 4, 2}; const int size = 3; uint32_t indexVectorH[size] = {0, 1, 2}; UUIDT inputValuesH[size] = {{0, 0}, {1, 0}, {2, 0}}; uint8_t inputNullsH[1] = {0xFF}; uint8_t *basePtr = allocate_column(nullptr, &inputNullsH[0], &inputValuesH[0], 0, 1, size * 16); RecordID outputValuesH[3]; uint32_t *indexVector = allocate(&indexVectorH[0], size); RecordID *outputValuesD = allocate(&outputValuesH[0], size); DefaultValue defaultValue = {false, {}}; VectorPartySlice inputVP = {basePtr, 0, 8, 0, UUID, defaultValue}; InputVector input = {{.VP = inputVP}, VectorPartyInput}; HashLookup(input, outputValuesD, indexVector, size, nullptr, 0, hashIndex, 0, 0); RecordID expectedOutputValues[3]; for (int i = 0; i < size; i++) { RecordID recordID = {(int32_t) 0, (uint32_t) i}; expectedOutputValues[i] = recordID; } EXPECT_TRUE( equal(reinterpret_cast<uint8_t *>(outputValuesD), reinterpret_cast<uint8_t *>( outputValuesD) + sizeof(RecordID) * size, reinterpret_cast<uint8_t *>(&expectedOutputValues[0]))); release(buckets); release(indexVector); release(basePtr); release(outputValuesD); } // cppcheck-suppress * TEST(ForeignTableColumnTransformTest, CheckTransform) { const int numBatches = 5; const int kNumRecords = 5; const int numRecordsInLastBatch = 5; int16_t* const timezoneLookup = nullptr; int16_t timezoneLookupSize = 0; int32_t baseBatchID = -2147483648; RecordID recordIDsH[kNumRecords]; VectorPartySlice batches[kNumRecords]; for (int i = 0; i < kNumRecords; i++) { RecordID recordID = {(int32_t) i + baseBatchID, (uint32_t) i}; recordIDsH[i] = recordID; } RecordID *recordIDs = allocate(&recordIDsH[0], kNumRecords); int valuesH[5][5] = {{1, 0, 0, 0, 0}, {0, 2, 0, 0, 0}, {0, 0, 3, 0, 0}, {0, 0, 0, 4, 0}, {0, 0, 0, 0, 5}}; uint8_t nullsH[1] = {0xFF}; uint8_t *basePtrs[5]; for (int i = 0; i < numBatches; i++) { uint8_t *basePtr = allocate_column(nullptr, nullsH, &valuesH[i][0], 0, 1, 20); VectorPartySlice foreignVP = {basePtr, 0, 8, 0, Int32}; batches[i] = foreignVP; basePtrs[i] = basePtr; } DefaultValue defaultValue = {false, {.Int32Val = 0}}; ForeignColumnVector foreignColumnVP = {recordIDs, batches, baseBatchID, (int32_t) numBatches, (int32_t) numRecordsInLastBatch, timezoneLookup, timezoneLookupSize, Int32, defaultValue}; InputVector input = {{.ForeignVP = foreignColumnVP}, ForeignColumnInput}; int outputValuesH[kNumRecords]; bool outputNullsH[kNumRecords]; uint8_t *outputBasePtr = allocate_column(nullptr, reinterpret_cast<uint8_t *>(&outputValuesH[0]), &outputNullsH[0], 0, 20, 5); ScratchSpaceVector outputScratchSpace = {outputBasePtr, 24, Int32}; OutputVector output = {{.ScratchSpace = outputScratchSpace}, ScratchSpaceOutput}; int expectedValues[kNumRecords] = {-1, -2, -3, -4, -5}; bool expectedNulls[kNumRecords] = {true, true, true, true, true}; int *outputValuesD = reinterpret_cast<int *>(outputBasePtr); bool *outputNulls = reinterpret_cast<bool *>(outputBasePtr) + 24; UnaryTransform(input, output, nullptr, kNumRecords, nullptr, 0, Negate, 0, 0); ForeignTableIterator<int> *vpIters = prepareForeignTableIterators( numBatches, batches, 4, false, 0, 0); RecordIDJoinIterator<int> inputIter( recordIDs, numBatches, baseBatchID, vpIters, numRecordsInLastBatch, timezoneLookup, timezoneLookupSize); outputValuesD = reinterpret_cast<int *>(outputBasePtr); outputNulls = reinterpret_cast<bool *>(outputBasePtr) + 24; EXPECT_TRUE( equal(outputValuesD, outputValuesD + kNumRecords, &expectedValues[0])); EXPECT_TRUE(equal(outputNulls, outputNulls + kNumRecords, &expectedNulls[0])); release(recordIDs); for (int i = 0; i < numBatches; i++) { release(basePtrs[i]); } release(outputBasePtr); } // cppcheck-suppress * TEST(SortDimColumnVectorTest, CheckSort) { // test with 1 4-byte dim, 1 2-byte dim and 1 1-byte dim // with capacity = 3 // numBytes=(4+2+1+3)*3=30 uint8_t keysH[30] = {0}; reinterpret_cast<uint32_t *>(keysH)[0] = 1; reinterpret_cast<uint32_t *>(keysH)[1] = 2; reinterpret_cast<uint32_t *>(keysH)[2] = 1; reinterpret_cast<uint16_t *>(keysH + 12)[0] = 1; reinterpret_cast<uint16_t *>(keysH + 12)[1] = 2; reinterpret_cast<uint16_t *>(keysH + 12)[2] = 1; (keysH + 18)[0] = 1; (keysH + 18)[1] = 2; (keysH + 18)[2] = 1; uint32_t indexH[3] = {0, 1, 2}; uint64_t hashValuesH[3] = {0}; uint8_t *keys = allocate(&keysH[0], 30); uint32_t *index = allocate(&indexH[0], 3); uint64_t *hashValues = allocate(&hashValuesH[0], 3); const int vectorCapacity = 3; const int length = 3; DimensionVector keyColVector = { keys, hashValues, index, vectorCapacity, {(uint8_t)0, (uint8_t)0, (uint8_t)1, (uint8_t)1, (uint8_t)1}}; Sort(keyColVector, length, 0, 0); uint32_t expectedIndex1[3] = {1, 0, 2}; uint32_t expectedIndex2[3] = {0, 2, 1}; EXPECT_TRUE(equal(index, index + 3, expectedIndex1) || equal(index, index + 3, expectedIndex2)); } // cppcheck-suppress * TEST(ReduceDimColumnVectorTest, CheckReduce) { // test with 3 dimensions (4-byte, 2-byte, 1-byte) // each dimension vector has 6 elements with values assigned as [1,2,3,2,3,1] uint8_t inputDimValuesH[60] = {1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 0, 3, 0, 2, 0, 3, 0, 1, 0, 1, 2, 3, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; uint64_t inputHashValuesH[6] = {1, 1, 2, 2, 3, 3}; uint32_t inputIndexVectorH[6] = {1, 3, 2, 4, 0, 5}; uint32_t inputValuesH[6] = {5, 1, 3, 2, 4, 6}; uint8_t outputDimValuesH[60] = {0}; uint64_t outputHashValuesH[6] = {0}; uint32_t outputIndexVectorH[6] = {0}; uint32_t outputValuesH[6] = {0}; uint8_t *inputDimValuesD = allocate(inputDimValuesH, 60); uint64_t *inputHashValues = allocate(inputHashValuesH, 6); uint32_t *inputIndexVector = allocate(inputIndexVectorH, 6); uint32_t *inputValuesD = allocate(inputValuesH, 6); uint8_t *outputDimValuesD = allocate(outputDimValuesH, 60); uint64_t *outputHashValues = allocate(outputHashValuesH, 6); uint32_t *outputIndexVector = allocate(outputIndexVectorH, 6); uint32_t *outputValuesD = allocate(outputValuesH, 6); uint32_t expectedValues[3] = {3, 7, 11}; uint32_t expectedIndex[3] = {1, 2, 0}; // output dimension values should be [2,3,1] for each dim vector uint8_t expectedDimValues[60] = { 2, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 3, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 3, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, }; int length = 6; int vectorCapacity = 6; DimensionVector inputKeys = { inputDimValuesD, inputHashValues, inputIndexVector, vectorCapacity, {(uint8_t)0, (uint8_t)0, (uint8_t)1, (uint8_t)1, (uint8_t)1}}; DimensionVector outputKeys = { outputDimValuesD, outputHashValues, outputIndexVector, vectorCapacity, {(uint8_t)0, (uint8_t)0, (uint8_t)1, (uint8_t)1, (uint8_t)1}}; CGoCallResHandle resHandle = Reduce(inputKeys, reinterpret_cast<uint8_t *>(inputValuesD), outputKeys, reinterpret_cast<uint8_t *>(outputValuesD), 4, length, AGGR_SUM_UNSIGNED, 0, 0); EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 3); EXPECT_EQ(resHandle.pStrErr, nullptr); EXPECT_TRUE(equal(outputValuesD, outputValuesD + 3, expectedValues)); EXPECT_TRUE(equal(outputIndexVector, outputIndexVector + 3, expectedIndex)); EXPECT_TRUE(equal(outputDimValuesD, outputDimValuesD + 60, expectedDimValues)); } TEST(SortAndReduceTest, CheckReduceByAvg) { // 6 elements 1 2 3 2 3 1 uint8_t inputDimValuesH[30] = {1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1}; uint64_t inputHashValuesH[6] = {1, 1, 2, 2, 3, 3}; uint32_t inputIndexVectorH[6] = {1, 3, 2, 4, 0, 5}; float_t inputValuesH[12] = {5.0, 0, 1.0, 0, 3.0, 0, 2.0, 0, 4.0, 0, 6.0, 0}; // set count to be 1. for (int i = 0; i < 6; i++) { *reinterpret_cast<uint32_t*>(&inputValuesH[i*2+1]) = uint32_t(1); } uint8_t outputDimValuesH[30] = {0}; uint64_t outputHashValuesH[6] = {0}; uint32_t outputIndexVectorH[6] = {0}; uint64_t outputValuesH[6] = {0}; uint8_t *inputDimValuesD = allocate(inputDimValuesH, 30); uint64_t *inputHashValues = allocate(inputHashValuesH, 6); uint32_t *inputIndexVector = allocate(inputIndexVectorH, 6); uint32_t *inputValuesD = allocate(reinterpret_cast<uint32_t*>(&inputValuesH[0]), 12); uint8_t *outputDimValuesD = allocate(outputDimValuesH, 30); uint64_t *outputHashValues = allocate(outputHashValuesH, 6); uint32_t *outputIndexVector = allocate(outputIndexVectorH, 6); uint64_t *outputValuesD = allocate(outputValuesH, 6); float_t expectedValuesF[6] = {1.5, 0, 3.5, 0, 5.5, 0}; uint64_t* expectedValues = reinterpret_cast<uint64_t*>(&expectedValuesF[0]); for (int i = 0; i < 3; i++) { *(reinterpret_cast<uint32_t *>(&expectedValues[i]) + 1) = 2; } uint32_t expectedIndex[3] = {1, 2, 0}; // output dimension values should be [2,3,1] for each dim vector uint8_t expectedDimValues[30] = { 2, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, }; int length = 6; int vectorCapacity = 6; DimensionVector inputKeys = { inputDimValuesD, inputHashValues, inputIndexVector, vectorCapacity, {(uint8_t)0, (uint8_t)0, (uint8_t)1, (uint8_t)0, (uint8_t)0}}; DimensionVector outputKeys = { outputDimValuesD, outputHashValues, outputIndexVector, vectorCapacity, {(uint8_t)0, (uint8_t)0, (uint8_t)1, (uint8_t)0, (uint8_t)0}}; CGoCallResHandle resHandle = Reduce(inputKeys, reinterpret_cast<uint8_t *>(inputValuesD), outputKeys, reinterpret_cast<uint8_t *>(outputValuesD), 8, length, AGGR_AVG_FLOAT, 0, 0); EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 3); EXPECT_EQ(resHandle.pStrErr, nullptr); EXPECT_TRUE(equal(outputValuesD, outputValuesD + 3, expectedValues)); EXPECT_TRUE(equal(outputIndexVector, outputIndexVector + 3, expectedIndex)); EXPECT_TRUE(equal(outputDimValuesD, outputDimValuesD + 30, expectedDimValues)); } // cppcheck-suppress * TEST(SortAndReduceTest, CheckHash) { int size = 8; uint8_t dimValuesH[16] = {2, 1, 0, 3, 0, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1}; uint32_t measureValuesH[8] = {1, 1, 1, 1, 1, 1, 1, 1}; uint64_t hashValuesH[8] = {0}; uint32_t indexValuesH[8] = {0}; uint8_t dimValuesOutH[16] = {0}; uint32_t measureValuesOutH[8] = {0}; uint64_t hashValuesOutH[8] = {0}; uint32_t indexValuesOutH[8] = {0}; uint8_t *dimValues = allocate(dimValuesH, 16); uint32_t *measureValues = allocate(measureValuesH, 8); uint64_t *hashValues = allocate(hashValuesH, 8); uint32_t *indexValues = allocate(indexValuesH, 8); uint8_t *dimValuesOut = allocate(dimValuesOutH, 16); uint32_t *measureValuesOut = allocate(measureValuesOutH, 8); uint64_t *hashValuesOut = allocate(hashValuesOutH, 8); uint32_t *indexValuesOut = allocate(indexValuesOutH, 8); InitIndexVector(indexValues, 0, size, 0, 0); const int length = 8; const int vectorCapacity = 8; DimensionVector inputKeyColVector = { dimValues, hashValues, indexValues, vectorCapacity, {(uint8_t)0, (uint8_t)0, (uint8_t)0, (uint8_t)0, (uint8_t)1}}; DimensionVector outputKeyColVector = { dimValuesOut, hashValuesOut, indexValuesOut, vectorCapacity, {(uint8_t)0, (uint8_t)0, (uint8_t)0, (uint8_t)0, (uint8_t)1}}; Sort(inputKeyColVector, length, 0, 0); CGoCallResHandle resHandle = Reduce(inputKeyColVector, reinterpret_cast<uint8_t *>(measureValues), outputKeyColVector, reinterpret_cast<uint8_t *>(measureValuesOut), 4, length, AGGR_SUM_UNSIGNED, nullptr, 0); uint8_t expectedDims[16] = {2, 0, 3, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0}; uint32_t expectedMeasures[8] = {2, 2, 2, 2, 0, 0, 0, 0}; uint32_t expectedIndexes[8] = {0, 2, 3, 1, 0, 0, 0, 0}; EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 4); EXPECT_EQ(resHandle.pStrErr, nullptr); EXPECT_TRUE(equal(dimValuesOut, dimValuesOut + 16, &expectedDims[0])); EXPECT_TRUE( equal(measureValuesOut, measureValuesOut + 8, &expectedMeasures[0])); EXPECT_TRUE(equal(indexValuesOut, indexValuesOut + 8, &expectedIndexes[0])); release(dimValues); release(measureValues); release(hashValues); release(indexValues); release(dimValuesOut); release(measureValuesOut); release(hashValuesOut); release(indexValuesOut); } // cppcheck-suppress * TEST(HyperLogLogTest, CheckSparseMode) { int prevResultSize = 0; int curBatchSize = 8; const int vectorCapacity = 8; uint8_t prevDimH[16] = {1, 1, 2, 2, 3, 3, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1}; uint32_t prevValuesH[8] = {0}; uint64_t prevHashH[8] = {0}; uint32_t prevIndexH[8] = {0}; uint8_t curDimH[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; uint32_t curValuesH[8] = {0x010001, 0x020002, 0x010002, 0x020002, 0x010003, 0x020003, 0x010004, 0x020004}; uint32_t curIndexH[8] = {0, 1, 2, 3, 4, 5, 6, 7}; uint64_t curHashH[8] = {0}; uint8_t *prevDim = allocate(prevDimH, 16); uint32_t *prevValues = allocate(prevValuesH, 8); uint64_t *prevHash = allocate(prevHashH, 8); uint32_t *prevIndex = allocate(prevIndexH, 8); uint8_t *curDim = allocate(curDimH, 16); uint32_t *curValues = allocate(curValuesH, 8); uint64_t *curHash = allocate(curHashH, 8); uint32_t *curIndex = allocate(curIndexH, 8); DimensionVector prevDimOut = { prevDim, prevHash, prevIndex, vectorCapacity, {(uint8_t)0, (uint8_t)0, (uint8_t)0, (uint8_t)0, (uint8_t)1}}; DimensionVector curDimOut = { curDim, curHash, curIndex, vectorCapacity, {(uint8_t)0, (uint8_t)0, (uint8_t)0, (uint8_t)0, (uint8_t)1}}; uint8_t *hllVector; size_t hllVectorSize; uint16_t *hllDimRegIDCount; CGoCallResHandle resHandle = HyperLogLog(prevDimOut, curDimOut, prevValues, curValues, prevResultSize, curBatchSize, true, &hllVector, &hllVectorSize, &hllDimRegIDCount, 0, 0); EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 4); EXPECT_EQ(resHandle.pStrErr, nullptr); int resSize = reinterpret_cast<int64_t>(resHandle.res); EXPECT_EQ(resSize, 4); EXPECT_EQ(hllVectorSize, 20); uint8_t expectedDims[16] = {2, 4, 3, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0}; uint8_t expectedHLL[20] = {2, 0, 3, 0, 4, 0, 3, 0, 3, 0, 3, 0, 1, 0, 2, 0, 2, 0, 3, 0}; uint16_t expectedDimRegIDCount[4] = {1, 1, 1, 2}; EXPECT_TRUE(equal(curDim, curDim + 16, &expectedDims[0])); EXPECT_TRUE(equal(hllVector, hllVector + hllVectorSize, &expectedHLL[0])); EXPECT_TRUE(equal(hllDimRegIDCount, hllDimRegIDCount + resSize, &expectedDimRegIDCount[0])); release(prevDim); release(curDim); release(prevValues); release(prevHash); release(prevIndex); release(curValues); release(curHash); release(curIndex); release(hllVector); release(hllDimRegIDCount); } // cppcheck-suppress * TEST(HyperLogLogTest, CheckDenseMode) { int prevResultSize = 0; int curBatchSize = 5000; const int vectorCapacity = 5000; uint8_t prevDimH[10000] = {0}; // {1,1,2,2,0,0, ... } prevDimH[0] = 1; prevDimH[1] = 1; prevDimH[2] = 2; prevDimH[3] = 2; for (int i = 5000; i < 10000; i++) { prevDimH[i] = 1; } uint32_t prevValuesH[5000] = {0}; uint64_t prevHashH[5000] = {0}; uint32_t prevIndexH[5000] = {0}; uint8_t curDimH[10000] = {0}; uint32_t curValuesH[5000] = {0}; curValuesH[0] = 0x010001; curValuesH[1] = 0x020002; curValuesH[2] = 0x010002; curValuesH[3] = 0x020002; for (int i = 4; i < 5000; i++) { // 4996 registers curValuesH[i] = (0x010000 | (i - 4)); } uint32_t curIndexH[5000] = {0}; for (int i = 0; i < 5000; i++) { curIndexH[i] = i; } uint64_t curHashH[5000] = {0}; uint8_t *prevDim = allocate(prevDimH, 10000); uint32_t *prevValues = allocate(prevValuesH, 5000); uint64_t *prevHash = allocate(prevHashH, 5000); uint32_t *prevIndex = allocate(prevIndexH, 5000); uint8_t *curDim = allocate(curDimH, 10000); uint32_t *curValues = allocate(curValuesH, 5000); uint64_t *curHash = allocate(curHashH, 5000); uint32_t *curIndex = allocate(curIndexH, 5000); DimensionVector prevDimOut = { prevDim, prevHash, prevIndex, vectorCapacity, {(uint8_t)0, (uint8_t)0, (uint8_t)0, (uint8_t)0, (uint8_t)1}}; DimensionVector curDimOut = { curDim, curHash, curIndex, vectorCapacity, {(uint8_t)0, (uint8_t)0, (uint8_t)0, (uint8_t)0, (uint8_t)1}}; uint8_t *hllVector; size_t hllVectorSize; uint16_t *hllDimRegIDCount; CGoCallResHandle resHandle = HyperLogLog(prevDimOut, curDimOut, prevValues, curValues, prevResultSize, curBatchSize, true, &hllVector, &hllVectorSize, &hllDimRegIDCount, 0, 0); EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 3); EXPECT_EQ(resHandle.pStrErr, nullptr); int resSize = reinterpret_cast<int64_t>(resHandle.res); EXPECT_EQ(resSize, 3); EXPECT_EQ(hllVectorSize, 16396); uint8_t expectedDims[10000] = {0}; expectedDims[0] = 2; expectedDims[1] = 0; expectedDims[2] = 1; expectedDims[5000] = 1; expectedDims[5001] = 1; expectedDims[5002] = 1; uint8_t expectedHLL[16396] = {0}; expectedHLL[0] = 2; expectedHLL[1] = 0; expectedHLL[2] = 3; expectedHLL[3] = 0; for (int i = 4; i < 5000; i++) { expectedHLL[i] = 2; } expectedHLL[16388] = 1; expectedHLL[16389] = 0; expectedHLL[16390] = 2; expectedHLL[16391] = 0; expectedHLL[16392] = 2; expectedHLL[16393] = 0; expectedHLL[16394] = 3; expectedHLL[16395] = 0; uint16_t expectedDimRegIDCount[3] = {1, 4996, 2}; EXPECT_TRUE(equal(curDim, curDim + 10000, &expectedDims[0])); EXPECT_TRUE(equal(hllVector, hllVector + hllVectorSize, &expectedHLL[0])); EXPECT_TRUE(equal(hllDimRegIDCount, hllDimRegIDCount + resSize, &expectedDimRegIDCount[0])); release(prevDim); release(curDim); release(prevValues); release(prevHash); release(prevIndex); release(curValues); release(curHash); release(curIndex); release(hllVector); release(hllDimRegIDCount); } // cppcheck-suppress * TEST(DateFunctorsTest, CheckGetStarts) { // First ensure the constant memory is properly initialized. BootstrapDevice(); const int size = 3; uint32_t indexVectorH[size * 2] = {0, 1, 2}; uint32_t *indexVector = allocate(&indexVectorH[0], size * 2); uint32_t inputValuesH[size] = {0, get_ts(2018, 6, 11), get_ts(1970, 1, 1)}; bool inputNullsH[size] = {false, true, true}; uint8_t *basePtr = allocate_column(nullptr, reinterpret_cast<uint8_t *>(&inputValuesH[0]), &inputNullsH[0], 0, 12, 3); uint32_t outputValuesH[size] = {0, 0, 0}; bool outputNullsH[size] = {false, false, false}; uint8_t *outputBasePtr = allocate_column(nullptr, reinterpret_cast<uint8_t *>(&outputValuesH[0]), &outputNullsH[0], 0, 12, 3); ScratchSpaceVector inputScratchSpace = {basePtr, 16, Int32}; ScratchSpaceVector outputScratchSpace = {outputBasePtr, 16, Int32}; InputVector input = {{.ScratchSpace = inputScratchSpace}, ScratchSpaceInput}; OutputVector output = {{.ScratchSpace = outputScratchSpace}, ScratchSpaceOutput}; UnaryTransform(input, output, indexVector, size, nullptr, 0, GetMonthStart, 0, 0); uint32_t *outputValuesD = reinterpret_cast<uint32_t *>(outputBasePtr); bool *outputNulls = reinterpret_cast<bool *>(outputBasePtr) + 16; uint32_t expectedValues[3] = {0, get_ts(2018, 6, 1), get_ts(1970, 1, 1)}; bool expectedNulls[3] = {false, true, true}; EXPECT_TRUE( equal(outputValuesD, outputValuesD + size, &expectedValues[0])); EXPECT_TRUE( equal(outputNulls, outputNulls + size, &expectedNulls[0])); // Check get quarter start. UnaryTransform(input, output, indexVector, size, nullptr, 0, GetQuarterStart, 0, 0); uint32_t expectedValues2[3] = {0, get_ts(2018, 4, 1), get_ts(1970, 1, 1)}; bool expectedNulls2[3] = {false, true, true}; EXPECT_TRUE( equal(outputValuesD, outputValuesD + size, &expectedValues2[0])); EXPECT_TRUE( equal(outputNulls, outputNulls + size, &expectedNulls2[0])); // Check get year start. UnaryTransform(input, output, indexVector, size, nullptr, 0, GetYearStart, 0, 0); uint32_t expectedValues3[3] = {0, get_ts(2018, 1, 1), get_ts(1970, 1, 1)}; bool expectedNulls3[3] = {false, true, true}; EXPECT_TRUE( equal(outputValuesD, outputValuesD + size, &expectedValues3[0])); EXPECT_TRUE( equal(outputNulls, outputNulls + size, &expectedNulls3[0])); release(basePtr); release(outputBasePtr); release(indexVector); } // cppcheck-suppress * TEST(GeoBatchIntersectTest, CheckInShape) { // 3 shapes // 1. Square with (1,1), (1,-1), (-1,-1), (-1, 1) // 2. Triangle with (3,3),(2,2),(4,2) // 3. Square with a hole (0,6),(3,6),(3,3),(0,3), hole (1,5),(2,5),(2,4),(1,4) float shapeLatsH[20] = {1, 1, -1, -1, 1, 3, 2, 4, 3, 0, 3, 3, 0, 0, FLT_MAX, 1, 2, 2, 1, 1}; float shapeLongsH[20] = {1, -1, -1, 1, 1, 3, 2, 2, 3, 6, 6, 3, 3, 6, FLT_MAX, 5, 5, 4, 4, 5}; uint8_t shapeIndexsH[20] = {0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; GeoShapeBatch geoShapes = get_geo_shape_batch(shapeLatsH, shapeLongsH, shapeIndexsH, 3, 20); uint32_t indexVectorH[5] = {0, 1, 2, 3, 4}; uint32_t *indexVector = allocate(indexVectorH, 5); // 5 points (0,0),(3,2.5),(1.5, 3.5),(1.5,4.5),null // in 1 in 2 in 3 out out GeoPointT pointsH[5] = {{0, 0}, {3, 2.5}, {1.5, 3.5}, {1.5, 4.5}, {0, 0}}; uint8_t nullsH[1] = {0x0F}; uint32_t outputPredicateH[5] = {0}; uint32_t *outputPredicate = allocate(outputPredicateH, 5); // in. bool inOrOut = true; uint8_t *basePtr = allocate_column(nullptr, &nullsH[0], &pointsH[0], 0, 1, 40); DefaultValue defaultValue = {false}; VectorPartySlice inputVP = {basePtr, 0, 8, 0, GeoPoint, defaultValue, 5}; InputVector points = {{.VP = inputVP}, VectorPartyInput}; CGoCallResHandle resHandle = GeoBatchIntersects(geoShapes, points, indexVector, 5, 0, nullptr, 0, outputPredicate, inOrOut, 0, 0); EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 3); EXPECT_EQ(resHandle.pStrErr, nullptr); uint32_t expectedOutputPredicate[5] = {1, 2, 4, 0, 0}; EXPECT_TRUE( equal(outputPredicate, outputPredicate + 5, expectedOutputPredicate)); release(outputPredicate); release(indexVector); release(basePtr); release(geoShapes); } // cppcheck-suppress * TEST(GeoBatchIntersectTest, CheckRecordIDJoinIterator) { // 3 shapes // 1. Square with (1,1), (1,-1), (-1,-1), (-1, 1) // 2. Triangle with (3,3),(2,2),(4,2) // 3. Square with a hole (0,6),(3,6),(3,3),(0,3), hole (1,5),(2,5),(2,4),(1,4) float shapeLatsH[20] = {1, 1, -1, -1, 1, 3, 2, 4, 3, 0, 3, 3, 0, 0, FLT_MAX, 1, 2, 2, 1, 1}; float shapeLongsH[20] = {1, -1, -1, 1, 1, 3, 2, 2, 3, 6, 6, 3, 3, 6, FLT_MAX, 5, 5, 4, 4, 5}; uint8_t shapeIndexsH[20] = {0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; GeoShapeBatch geoShapes = get_geo_shape_batch(shapeLatsH, shapeLongsH, shapeIndexsH, 3, 20); uint32_t indexVectorH[5] = {0, 1, 2, 3, 4}; uint32_t *indexVector = allocate(indexVectorH, 5); // 5 points (0,0),(3,2.5),(1.5, 3.5),(1.5,4.5),null // in 1 in 2 in 3 out out const int numBatches = 5; const int kNumRecords = 5; const int numRecordsInLastBatch = 5; int32_t baseBatchID = -2147483648; RecordID recordIDsH[kNumRecords]; VectorPartySlice batches[kNumRecords]; for (int i = 0; i < kNumRecords; i++) { RecordID recordID = {(int32_t) i + baseBatchID, (uint32_t) i}; recordIDsH[i] = recordID; } RecordID *recordIDs = allocate(&recordIDsH[0], kNumRecords); GeoPointT valuesH[5][5]; GeoPointT pointsH[5] = {{0, 0}, {3, 2.5}, {1.5, 3.5}, {1.5, 4.5}, {0, 0}}; for (int i = 0; i < kNumRecords; i++) { valuesH[i][i] = pointsH[i]; } uint8_t nullsH[1] = {0x0F}; uint8_t *basePtrs[5]; for (int i = 0; i < numBatches; i++) { uint8_t *basePtr = allocate_column(nullptr, nullsH, &valuesH[i][0], 0, 1, 40); VectorPartySlice foreignVP = {basePtr, 0, 8, 0, GeoPoint}; batches[i] = foreignVP; basePtrs[i] = basePtr; } DefaultValue defaultValue = {false, {}}; ForeignColumnVector foreignColumnVP = {recordIDs, batches, baseBatchID, (int32_t) numBatches, (int32_t) numRecordsInLastBatch, nullptr, 0, GeoPoint, defaultValue}; InputVector points = {{.ForeignVP = foreignColumnVP}, ForeignColumnInput}; uint32_t outputPredicateH[5] = {0}; uint32_t *outputPredicate = allocate(outputPredicateH, 5); CGoCallResHandle resHandle = GeoBatchIntersects(geoShapes, points, indexVector, 5, 0, nullptr, 0, outputPredicate, true, 0, 0); EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 3); EXPECT_EQ(resHandle.pStrErr, nullptr); uint32_t expectedOutputPredicate[5] = {1, 2, 4, 0, 0}; EXPECT_TRUE( equal(outputPredicate, outputPredicate + 5, expectedOutputPredicate)); release(outputPredicate); release(indexVector); release(recordIDs); release(geoShapes); for (int i = 0; i < numBatches; i++) { release(basePtrs[i]); } } // cppcheck-suppress * TEST(GeoBatchIntersectTest, CheckNotInShape) { // 3 shapes // 1. Square with (1,1), (1,-1), (-1,-1), (-1, 1) // 2. Triangle with (3,3),(2,2),(4,2) // 3. Square with a hole (0,6),(3,6),(3,3),(0,3), hole (1,5),(2,5),(2,4),(1,4) float shapeLatsH[20] = {1, 1, -1, -1, 1, 3, 2, 4, 3, 0, 3, 3, 0, 0, FLT_MAX, 1, 2, 2, 1, 1}; float shapeLongsH[20] = {1, -1, -1, 1, 1, 3, 2, 2, 3, 6, 6, 3, 3, 6, FLT_MAX, 5, 5, 4, 4, 5}; uint8_t shapeIndexsH[20] = {0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2}; GeoShapeBatch geoShapes = get_geo_shape_batch(shapeLatsH, shapeLongsH, shapeIndexsH, 3, 20); uint32_t indexVectorH[5] = {0, 1, 2, 3, 4}; uint32_t *indexVector = allocate(indexVectorH, 5); // 5 points (0,0),(3,2.5),(1.5, 3.5),(1.5,4.5),null // in 1 in 2 in 3 out out GeoPointT pointsH[5] = {{0, 0}, {3, 2.5}, {1.5, 3.5}, {1.5, 4.5}, {0, 0}}; uint8_t nullsH[1] = {0x0F}; uint32_t outputPredicateH[5] = {0}; uint32_t *outputPredicate = allocate(outputPredicateH, 5); // in. bool inOrOut = false; uint8_t *basePtr = allocate_column(nullptr, &nullsH[0], &pointsH[0], 0, 1, 40); DefaultValue defaultValue = {false}; VectorPartySlice inputVP = {basePtr, 0, 8, 0, GeoPoint, defaultValue, 5}; InputVector points = {{.VP = inputVP}, VectorPartyInput}; CGoCallResHandle resHandle = GeoBatchIntersects(geoShapes, points, indexVector, 5, 0, nullptr, 0, outputPredicate, inOrOut, 0, 0); EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 1); EXPECT_EQ(resHandle.pStrErr, nullptr); uint32_t expectedOutputPredicate[5] = {1, 2, 4, 0, 1}; EXPECT_TRUE( equal(outputPredicate, outputPredicate + 5, expectedOutputPredicate)); release(outputPredicate); release(indexVector); release(basePtr); release(geoShapes); } // cppcheck-suppress * TEST(GeoBatchIntersectionJoinTest, DimensionWriting) { float shapeLatsH[15] = { 1, 1, -1, -1, 1, 2, 2, -2, -2, 2, 1.5 + 0.1, 1.5 + 0.1, 1.5 - 0.1, 1.5 - 0.1, 1.5 + 0.1}; float shapeLongsH[15] = { 1, -1, -1, 1, 1, 2, -2, -2, 2, 2, 3.5 + 0.1, 3.5 - 0.1, 3.5 + 0.1, 3.5 - 0.1, 3.5 + 0.1}; uint8_t shapeIndexsH[15] = {0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2}; GeoShapeBatch geoShapes = get_geo_shape_batch(shapeLatsH, shapeLongsH, shapeIndexsH, 3, 15); uint32_t indexVectorH[5] = {0, 1, 2, 3, 4}; uint32_t *indexVector = allocate(indexVectorH, 5); // 5 points (1.5,1.5) (0,0) (1.5,4.5) (1.5, 3.5) null // in2 in1,2 out in3 out GeoPointT pointsH[5] = {{1.5, 1.5}, {0, 0}, {1.5, 4.5}, {1.5, 3.5}, {0, 0}}; uint8_t nullsH[1] = {0x0F}; uint32_t outputPredicateH[5] = {0}; uint32_t *outputPredicate = allocate(outputPredicateH, 5); uint8_t *basePtr = allocate_column(nullptr, &nullsH[0], &pointsH[0], 0, 1, 40); DefaultValue defaultValue = {false}; VectorPartySlice inputVP = {basePtr, 0, 8, 0, GeoPoint, defaultValue, 5}; uint8_t outputValuesH[10]; thrust::fill(std::begin(outputValuesH), std::end(outputValuesH), 0); uint8_t *outputValuesD = allocate(&outputValuesH[0], 10); DimensionOutputVector outputDimension = {outputValuesD, outputValuesD + 5, Uint8}; InputVector points = {{.VP = inputVP}, VectorPartyInput}; CGoCallResHandle resHandle = GeoBatchIntersects(geoShapes, points, indexVector, 5, 0, nullptr, 0, outputPredicate, true, 0, 0); EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 3); EXPECT_EQ(resHandle.pStrErr, nullptr); resHandle = WriteGeoShapeDim(1, outputDimension, 5, outputPredicate, 0, 0); uint32_t expectedOutputPredicate[5] = {2, 3, 0, 4, 0}; GeoPredicateIterator geoIter(expectedOutputPredicate, 1); EXPECT_TRUE( equal(outputPredicate, outputPredicate + 5, expectedOutputPredicate)); uint8_t expectedDimValues[5] = {1, 0, 2, 0, 0}; uint8_t expectedDimNulls[5] = {1, 1, 1, 0, 0}; EXPECT_TRUE(equal(outputDimension.DimValues, outputDimension.DimValues + 5, expectedDimValues)); EXPECT_TRUE(equal(outputDimension.DimNulls, outputDimension.DimNulls + 5, expectedDimNulls)); release(outputPredicate); release(indexVector); release(basePtr); release(geoShapes); } TEST(ExpandTest, testOverFill) { // test with 3 dimensions (4-byte, 2-byte, 1-byte) // each dimension vector has 6 elements with values assigned as // [1,2,3,2,3,1] uint8_t inputDimValuesH[60] = { 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 0, 3, 0, 2, 0, 3, 0, 1, 0, 1, 2, 3, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; uint32_t inputIndexVectorH[6] = {1, 2, 4, 7, 9, 12}; uint32_t baseCountVectorH[16] = { 0, 0, 1, 3, 4, 7, 8, 10, 13, 14, 16, 19, 22, 23, 26, 30 }; // => counts{1, 2, 3, 3, 2, 1} // so normal result will be {1, 2, 2, 3, 3, 3, 2, 2, 2, 3, 3, 1} // and only cut first 10 elem uint8_t outputDimValuesH[100] = {0}; uint8_t expectedDimValues[100] = { 1, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 1, 0, 2, 0, 2, 0, 3, 0, 3, 0, 3, 0, 2, 0, 2, 0, 2, 0, 3, 0, 1, 2, 2, 3, 3, 3, 2, 2, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, }; uint8_t *inputDimValuesD = allocate(inputDimValuesH, 60); uint32_t *inputIndexVector = allocate(inputIndexVectorH, 6); uint32_t *baseCountVector = allocate(baseCountVectorH, 16); uint8_t *outputDimValuesD = allocate(outputDimValuesH, 100); int length = 6; int vectorCapacity = 6; DimensionVector inputKeys = { inputDimValuesD, NULL, NULL, vectorCapacity, {(uint8_t)0, (uint8_t)0, (uint8_t)1, (uint8_t)1, (uint8_t)1}}; int outCapacity = 10; DimensionVector outputKeys = { outputDimValuesD, NULL, NULL, outCapacity, {(uint8_t)0, (uint8_t)0, (uint8_t)1, (uint8_t)1, (uint8_t)1}}; CGoCallResHandle resHandle = Expand(inputKeys, outputKeys, baseCountVector, inputIndexVector, length, 0, 0, 0); EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 10); EXPECT_EQ(resHandle.pStrErr, nullptr); EXPECT_TRUE(equal(outputDimValuesD, outputDimValuesD + 100, expectedDimValues)); } TEST(ExpandTest, testAppend) { // test with 3 dimensions (4-byte, 2-byte, 1-byte) // each dimension vector has 6 elements with values assigned as // [1,2,3,2,3,1] uint8_t inputDimValuesH[60] = { 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 0, 3, 0, 2, 0, 3, 0, 1, 0, 1, 2, 3, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; uint32_t inputIndexVectorH[6] = {1, 2, 4, 7, 9, 12}; uint32_t baseCountVectorH[16] = { 0, 0, 1, 3, 4, 7, 8, 10, 13, 14, 16, 19, 22, 23, 26, 30 }; // => counts{1, 2, 3, 3, 2, 1} // so normal result will be {1, 2, 2, 3, 3, 3, 2, 2, 2, 3, 3, 1} // and only append the first 5 elem to the last 5 elem of output uint8_t outputDimValuesH[100] = {0}; uint8_t expectedDimValues[100] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 2, 0, 3, 0, 3, 0, 0, 0, 0, 0, 0, 1, 2, 2, 3, 3, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, }; uint8_t *inputDimValuesD = allocate(inputDimValuesH, 60); uint32_t *inputIndexVector = allocate(inputIndexVectorH, 6); uint32_t *baseCountVector = allocate(baseCountVectorH, 16); uint8_t *outputDimValuesD = allocate(outputDimValuesH, 100); int length = 6; int vectorCapacity = 6; int outCapacity = 10; DimensionVector inputKeys = { inputDimValuesD, NULL, NULL, vectorCapacity, {(uint8_t)0, (uint8_t)0, (uint8_t)1, (uint8_t)1, (uint8_t)1}}; DimensionVector outputKeys = { outputDimValuesD, NULL, NULL, outCapacity, {(uint8_t)0, (uint8_t)0, (uint8_t)1, (uint8_t)1, (uint8_t)1}}; CGoCallResHandle resHandle = Expand(inputKeys, outputKeys, baseCountVector, inputIndexVector, length, 5, 0, 0); EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 10); EXPECT_EQ(resHandle.pStrErr, nullptr); EXPECT_TRUE(equal(outputDimValuesD, outputDimValuesD + 100, expectedDimValues)); } TEST(ExpandTest, testFillPartial) { // test with 3 dimensions (4-byte, 2-byte, 1-byte) // each dimension vector has 6 elements with values assigned as // [1,2,3,2,3,1] uint8_t inputDimValuesH[60] = { 1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 0, 3, 0, 2, 0, 3, 0, 1, 0, 1, 2, 3, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; uint32_t inputIndexVectorH[6] = {1, 2, 4}; uint32_t baseCountVectorH[16] = { 0, 0, 1, 3, 4, 7, 8, 10, 13, 14, 16, 19, 22, 23, 26, 30 }; // => counts{1, 2, 3} // so normal result will be {1, 2, 2, 3, 3, 3} // and only cut first 10 elem uint8_t outputDimValuesH[100] = {0}; uint8_t expectedDimValues[100] = { 1, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 0, 2, 0, 3, 0, 3, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 3, 3, 3, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0 }; uint8_t *inputDimValuesD = allocate(inputDimValuesH, 60); uint32_t *inputIndexVector = allocate(inputIndexVectorH, 6); uint32_t *baseCountVector = allocate(baseCountVectorH, 16); uint8_t *outputDimValuesD = allocate(outputDimValuesH, 100); int length = 3; int vectorCapacity = 6; DimensionVector inputKeys = { inputDimValuesD, NULL, NULL, vectorCapacity, {(uint8_t)0, (uint8_t)0, (uint8_t)1, (uint8_t)1, (uint8_t)1}}; int outCapacity = 10; DimensionVector outputKeys = { outputDimValuesD, NULL, NULL, outCapacity, {(uint8_t)0, (uint8_t)0, (uint8_t)1, (uint8_t)1, (uint8_t)1}}; CGoCallResHandle resHandle = Expand(inputKeys, outputKeys, baseCountVector, inputIndexVector, length, 0, 0, 0); EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 6); EXPECT_EQ(resHandle.pStrErr, nullptr); EXPECT_TRUE(equal(outputDimValuesD, outputDimValuesD + 100, expectedDimValues)); } // For now this test should only run in device mode and when c++14 is supported. // TODO(lucafuji): add host version of concurrent hash map to support host mode // mock and test. #ifdef SUPPORT_HASH_REDUCTION // cppcheck-suppress * TEST(HashReductionTest, CheckReduce) { // test with 3 dimensions (4-byte, 2-byte, 1-byte) // each dimension vector has 6 elements with values assigned as [1,2,3,2,3,1] uint8_t inputDimValuesH[60] = {1, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 1, 0, 0, 0, 1, 0, 2, 0, 3, 0, 2, 0, 3, 0, 1, 0, 1, 2, 3, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}; uint32_t inputValuesH[6] = {5, 1, 3, 2, 4, 6}; uint8_t outputDimValuesH[60] = {0}; uint32_t outputValuesH[6] = {0}; uint8_t *inputDimValuesD = allocate(inputDimValuesH, 60); uint32_t *inputValuesD = allocate(inputValuesH, 6); uint8_t *outputDimValuesD = allocate(outputDimValuesH, 60); uint32_t *outputValuesD = allocate(outputValuesH, 6); // since the result is hashed therefore no order is ganranteed, // we can build a result map and compare with the expected map. uint32_t expectedValues[3] = {3, 11, 7}; // output dimension values should be [2,1,3] for each dim vector uint8_t expectedDimValues[60] = { 2, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 1, 0, 3, 0, 0, 0, 0, 0, 0, 0, 2, 1, 3, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, }; // the key is (dim[0] << 32) | (dim[1] << 16) | (dim[2] << 8) | // valid[0] << 2 | valid[1] << 1 | valid[2]. auto build_map = [](uint8_t *dimValues, uint32_t *values, int length, int capacity) { std::unordered_map<int64_t, uint32_t> map; for (int i = 0; i < length; i++) { int64_t key = 0; uint32_t* curDim32 = reinterpret_cast<uint32_t*>(dimValues) + i; key |= static_cast<int64_t>(*curDim32) << 32; curDim32 += capacity-i; uint16_t* curDim16 = reinterpret_cast<uint16_t*>(curDim32) + i; key |= static_cast<int64_t>(*curDim16) << 16; curDim16 += capacity-i; uint8_t* curDim8 = reinterpret_cast<uint8_t*>(curDim16) + i; key |= static_cast<int64_t>(*curDim8) << 8; curDim8 += capacity-i; key |= static_cast<int64_t>(curDim8[i]) << 2; curDim8 += capacity; key |= static_cast<int64_t>(curDim8[i]) << 1; curDim8 += capacity; key |= static_cast<int64_t>(curDim8[i]); map[key] = values[i]; } return map; }; auto expectedMap = build_map(expectedDimValues, expectedValues, 3, 6); int capacity = 6; int vectorCapacity = 6; DimensionVector inputKeys = { inputDimValuesD, nullptr, nullptr, vectorCapacity, {(uint8_t)0, (uint8_t)0, (uint8_t)1, (uint8_t)1, (uint8_t)1}}; DimensionVector outputKeys = { outputDimValuesD, nullptr, nullptr, vectorCapacity, {(uint8_t)0, (uint8_t)0, (uint8_t)1, (uint8_t)1, (uint8_t)1}}; CGoCallResHandle resHandle = HashReduce(inputKeys, reinterpret_cast<uint8_t *>(inputValuesD), outputKeys, reinterpret_cast<uint8_t *>(outputValuesD), 4, capacity, AGGR_SUM_UNSIGNED, 0, 0); EXPECT_EQ(reinterpret_cast<int64_t>(resHandle.res), 3); EXPECT_EQ(resHandle.pStrErr, nullptr); copy_device_to_host(outputDimValuesH, outputDimValuesD, 60); copy_device_to_host(outputValuesH, outputValuesD, 6); auto outputMap = build_map(outputDimValuesH, outputValuesH, 3, 6); EXPECT_EQ(outputMap.size(), expectedMap.size()); for (auto iter = outputMap.begin(); iter != outputMap.end(); iter++) { int64_t key = iter->first; uint32_t value = iter->second; EXPECT_EQ(value, expectedMap[key]); } } #endif } // namespace ares