From af36f9940fdd19a395f42f6564f7883f198eb828 Mon Sep 17 00:00:00 2001 From: Roman Nozdrin Date: Wed, 8 Sep 2021 17:59:20 +0000 Subject: [PATCH] This patch introduces support for scanning/filtering vectorized execution for numeric-based data types TEXT, CHAR, VARCHAR, FLOAT and DOUBLE are not yet supported by vectorized path This patch introduces an example for Google benchmarking suite to measure a perf diff b/w legacy scan/filtering code and the templated version --- CMakeLists.txt | 2 + dbcon/joblist/primitivemsg.h | 2 +- primitives/linux-port/column.cpp | 780 ++++++++++++++++--- primitives/linux-port/primitiveprocessor.cpp | 4 +- primitives/linux-port/primitiveprocessor.h | 24 +- primitives/primproc/columncommand.cpp | 6 +- primitives/primproc/dictstep.cpp | 4 +- tests/CMakeLists.txt | 10 + tests/col16block.h | 708 +++++++++++++++++ tests/col1block.h | 2 + tests/col2block.h | 2 + tests/col4block.h | 2 + tests/col8block.h | 2 + tests/primitives_column_scan_and_filter.cpp | 325 +++++++- tests/primitives_scan_bench.cpp | 430 ++++++++++ utils/common/simd_sse.h | 473 +++++++++++ writeengine/server/we_dmlcommandproc.cpp | 1 - writeengine/shared/we_dbfileop.cpp | 1 - writeengine/shared/we_type.h | 1 + writeengine/shared/we_typeext.h | 1 + writeengine/wrapper/writeengine.cpp | 80 +- writeengine/wrapper/writeengine.h | 3 +- 22 files changed, 2720 insertions(+), 143 deletions(-) create mode 100644 tests/col16block.h create mode 100644 tests/primitives_scan_bench.cpp create mode 100644 utils/common/simd_sse.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 629e7708c..92c57ee9f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -185,6 +185,7 @@ IF (NOT INSTALL_LAYOUT) MY_CHECK_AND_SET_COMPILER_FLAG("-g -O3 -std=c++11 -fno-omit-frame-pointer -fno-strict-aliasing -Wall -fno-tree-vectorize -D_GLIBCXX_ASSERTIONS -DDBUG_OFF -DHAVE_CONFIG_H" RELEASE RELWITHDEBINFO MINSIZEREL) MY_CHECK_AND_SET_COMPILER_FLAG("-ggdb3 -std=c++11 -fno-omit-frame-pointer -fno-tree-vectorize -D_GLIBCXX_ASSERTIONS -DSAFE_MUTEX -DSAFEMALLOC -DENABLED_DEBUG_SYNC -O0 -Wall -D_DEBUG -DHAVE_CONFIG_H" DEBUG) + MY_CHECK_AND_SET_COMPILER_FLAG("-msse4.2" RELEASE RELWITHDEBINFO MINSIZEREL DEBUG) # enable security hardening features, like most distributions do # in our benchmarks that costs about ~1% of performance, depending on the load @@ -212,6 +213,7 @@ ELSE () # Remove visibility flag for now as it breaks Ubuntu 18.05 and we need to # fix our libraries anyway STRING(REPLACE "-fvisibility=hidden" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}") + MY_CHECK_AND_SET_COMPILER_FLAG("-msse4.2" RELEASE RELWITHDEBINFO MINSIZEREL DEBUG) MY_CHECK_AND_SET_COMPILER_FLAG("-D_DEBUG -O0" DEBUG) MY_CHECK_AND_SET_COMPILER_FLAG("-Wno-vla" DEBUG) ENDIF() diff --git a/dbcon/joblist/primitivemsg.h b/dbcon/joblist/primitivemsg.h index 6e92489e3..5b4bbfe05 100644 --- a/dbcon/joblist/primitivemsg.h +++ b/dbcon/joblist/primitivemsg.h @@ -826,7 +826,7 @@ namespace primitives inline primitives::RIDType* getRIDArrayPosition(uint8_t* out, const NVALSType offset) { - return getValuesArrayPosition(out, offset); + return getValuesArrayPosition(out, offset); } inline uint8_t* getFirstValueArrayPosition(ColResultHeader* outMsg) diff --git a/primitives/linux-port/column.cpp b/primitives/linux-port/column.cpp index 00293145c..4edb88b71 100644 --- a/primitives/linux-port/column.cpp +++ b/primitives/linux-port/column.cpp @@ -21,6 +21,7 @@ //#define NDEBUG #include #include +#include #ifndef _MSC_VER #include #else @@ -38,6 +39,8 @@ using namespace boost; #include "primproc.h" #include "dataconvert.h" #include "mcs_decimal.h" +#include "simd_sse.h" +#include "utils/common/columnwidth.h" using namespace logging; using namespace dbbc; @@ -47,7 +50,8 @@ using namespace execplan; namespace { -using RID_T = uint16_t; // Row index type, as used in rid arrays +// WIP Move this +using MT = uint16_t; // Column filtering is dispatched 4-way based on the column type, // which defines implementation of comparison operations for the column values @@ -118,7 +122,7 @@ inline bool colCompare_(const T& val1, const T& val2, uint8_t COP) return val1 >= val2; default: - logIt(34, COP, "colCompare"); + logIt(34, COP, "colCompare_"); return false; // throw an exception here? } } @@ -848,6 +852,34 @@ inline bool matchingColValue(const T curValue, } } +/***************************************************************************** + *** MISC FUNCS ************************************************************** + *****************************************************************************/ +// These two are templates update min/max values in the loop iterating the values in filterColumnData. +template::type* = nullptr> +inline void updateMinMax(T& Min, T& Max, const T curValue, NewColRequestHeader* in) +{ + constexpr int COL_WIDTH = sizeof(T); + if (colCompare(Min, curValue, COMPARE_GT, false, in->colType)) + Min = curValue; + + if (colCompare(Max, curValue, COMPARE_LT, false, in->colType)) + Max = curValue; +} + +template::type* = nullptr> +inline void updateMinMax(T& Min, T& Max, const T curValue, NewColRequestHeader* in) +{ + if (Min > curValue) + Min = curValue; + + if (Max < curValue) + Max = curValue; +} + + /***************************************************************************** *** READ COLUMN VALUES ****************************************************** *****************************************************************************/ @@ -936,6 +968,7 @@ inline void writeColValue( uint16_t rid, const T* srcArray) { + // TODO move base ptr calculation one level up. uint8_t* outPtr = reinterpret_cast(&out[1]); auto idx = out->NVALS++; if (OutputType & OT_RID) @@ -947,42 +980,650 @@ inline void writeColValue( if (OutputType & (OT_TOKEN | OT_DATAVALUE)) { + // TODO move base ptr calculation one level up. T* outPos = getValuesArrayPosition(primitives::getFirstValueArrayPosition(out), idx); // TODO check bytecode for the 16 byte type *outPos = srcArray[rid]; } } -// These two are templates update min/max values in the loop iterating the values in filterColumnData. -template::type* = nullptr> -inline void updateMinMax(T& Min, T& Max, T& curValue, NewColRequestHeader* in) +#if defined(__x86_64__ ) +template::type* = nullptr> +inline void vectUpdateMinMax(const bool validMinMax, const bool isNonNullOrEmpty, + T& Min, T& Max, T curValue, NewColRequestHeader* in) { - constexpr int COL_WIDTH = sizeof(T); - if (colCompare(Min, curValue, COMPARE_GT, false, in->colType)) - Min = curValue; - - if (colCompare(Max, curValue, COMPARE_LT, false, in->colType)) - Max = curValue; + if (validMinMax && isNonNullOrEmpty) + updateMinMax(Min, Max, curValue, in); } -template::type* = nullptr> -inline void updateMinMax(T& Min, T& Max, T& curValue, NewColRequestHeader* in) +// MCS won't update Min/Max for a block if it doesn't read all values in a block. +// This happens if in->NVALS > 0(HAS_INPUT_RIDS is set). +template::type* = nullptr> +inline void vectUpdateMinMax(const bool validMinMax, const bool isNonNullOrEmpty, + T& Min, T& Max, T curValue, NewColRequestHeader* in) { - if (Min > curValue) - Min = curValue; - - if (Max < curValue) - Max = curValue; + // } -// TBD Check if MCS really needs to copy values from in into out msgs or -// it is possible to copy from in msg into BPP::values directly. +template::type* = nullptr> +void vectWriteColValuesLoopRIDAsignment(primitives::RIDType* ridDstArray, ColResultHeader* out, + const primitives::RIDType calculatedRID, + const primitives::RIDType* ridSrcArray, const uint32_t srcRIDIdx) +{ + *ridDstArray = calculatedRID; + out->RidFlags |= (1 << (calculatedRID >> 9)); // set the (row/512)'th bit +} + +template::type* = nullptr> +void vectWriteColValuesLoopRIDAsignment(primitives::RIDType* ridDstArray, ColResultHeader* out, + const primitives::RIDType calculatedRID, + const primitives::RIDType* ridSrcArray, const uint32_t srcRIDIdx) +{ + *ridDstArray = ridSrcArray[srcRIDIdx]; + out->RidFlags |= (1 << (ridSrcArray[srcRIDIdx] >> 9)); // set the (row/512)'th bit +} + +// The set of SFINAE templates are used to write values/RID into the output buffer based on +// a number of template parameters +// No RIDs only values +template::type* = nullptr> +inline uint16_t vectWriteColValues(VT& simdProcessor, // SIMD processor + const MT writeMask, // SIMD intrinsics bitmask for values to write + const MT nonNullOrEmptyMask, // SIMD intrinsics inverce bitmask for NULL/EMPTY values + const bool validMinMax, // The flag to update Min/Max for a block or not + const primitives::RIDType ridOffset, // The first RID value of the dataVecTPtr + T* dataVecTPtr, // Typed SIMD vector from the input block + char* dstArray, // the actual char dst array ptr to start writing values + T& Min, T&Max, // Min/Max of the extent + NewColRequestHeader* in, // Proto message + ColResultHeader* out, // Proto message + primitives::RIDType* ridDstArray, // The actual dst arrray ptr to start writing RIDs + primitives::RIDType* ridSrcArray) // The actual src array ptr to read RIDs +{ + constexpr const uint16_t WIDTH = sizeof(T); + using SIMD_TYPE = typename VT::SIMD_TYPE; + SIMD_TYPE tmpStorageVector; + T* tmpDstVecTPtr = reinterpret_cast(&tmpStorageVector); + // Saving values based on writeMask into tmp vec. + // Min/Max processing. + // The mask is 16 bit long and it describes N elements. + // N = sizeof(vector type) / WIDTH. + uint32_t j = 0; + for (uint32_t it = 0; it < VT::vecByteSize; ++j, it += WIDTH) + { + MT bitMapPosition = 1 << it; + if (writeMask & bitMapPosition) + { + *tmpDstVecTPtr = dataVecTPtr[j]; + ++tmpDstVecTPtr; + } + + vectUpdateMinMax(validMinMax, nonNullOrEmptyMask & bitMapPosition, + Min, Max, dataVecTPtr[j], in); + } + // Store the whole vector however one level up the stack + // vectorizedFiltering() increases the dstArray by a number of + // actual values written that is the result of this function. + simdProcessor.store(dstArray, tmpStorageVector); + + return tmpDstVecTPtr - reinterpret_cast(&tmpStorageVector); +} + +// RIDs no values +template::type* = nullptr> +inline uint16_t vectWriteColValues(VT& simdProcessor, // SIMD processor + const MT writeMask, // SIMD intrinsics bitmask for values to write + const MT nonNullOrEmptyMask, // SIMD intrinsics inverce bitmask for NULL/EMPTY values + const bool validMinMax, // The flag to update Min/Max for a block or not + const primitives::RIDType ridOffset, // The first RID value of the dataVecTPtr + T* dataVecTPtr, // Typed SIMD vector from the input block + char* dstArray, // the actual char dst array ptr to start writing values + T& Min, T&Max, // Min/Max of the extent + NewColRequestHeader* in, // Proto message + ColResultHeader* out, // Proto message + primitives::RIDType* ridDstArray, // The actual dst arrray ptr to start writing RIDs + primitives::RIDType* ridSrcArray) // The actual src array ptr to read RIDs +{ + return 0; +} + +// Both RIDs and values +template::type* = nullptr> +inline uint16_t vectWriteColValues(VT& simdProcessor, // SIMD processor + const MT writeMask, // SIMD intrinsics bitmask for values to write + const MT nonNullOrEmptyMask, // SIMD intrinsics inverce bitmask for NULL/EMPTY values + const bool validMinMax, // The flag to update Min/Max for a block or not + const primitives::RIDType ridOffset, // The first RID value of the dataVecTPtr + T* dataVecTPtr, // Typed SIMD vector from the input block + char* dstArray, // the actual char dst array ptr to start writing values + T& Min, T&Max, // Min/Max of the extent + NewColRequestHeader* in, // Proto message + ColResultHeader* out, // Proto message + primitives::RIDType* ridDstArray, // The actual dst arrray ptr to start writing RIDs + primitives::RIDType* ridSrcArray) // The actual src array ptr to read RIDs +{ + constexpr const uint16_t WIDTH = sizeof(T); + using SIMD_TYPE = typename VT::SIMD_TYPE; + SIMD_TYPE tmpStorageVector; + T* tmpDstVecTPtr = reinterpret_cast(&tmpStorageVector); + // Saving values based on writeMask into tmp vec. + // Min/Max processing. + // The mask is 16 bit long and it describes N elements. + // N = sizeof(vector type) / WIDTH. + uint32_t j = 0; + for (uint32_t it = 0; it < VT::vecByteSize; ++j, it += WIDTH) + { + MT bitMapPosition = 1 << it; + if (writeMask & bitMapPosition) + { + *tmpDstVecTPtr = dataVecTPtr[j]; + ++tmpDstVecTPtr; + vectWriteColValuesLoopRIDAsignment(ridDstArray, out, ridOffset + j, + ridSrcArray, j); + ++ridDstArray; + } + vectUpdateMinMax(validMinMax, nonNullOrEmptyMask & bitMapPosition, + Min, Max, dataVecTPtr[j], in); + } + // Store the whole vector however one level up the stack + // vectorizedFiltering() increases the dstArray by a number of + // actual values written that is the result of this function. + simdProcessor.store(dstArray, tmpStorageVector); + + return tmpDstVecTPtr - reinterpret_cast(&tmpStorageVector); +} + +// RIDs no values +template::type* = nullptr> +inline uint16_t vectWriteRIDValues(VT& processor, // SIMD processor + const uint16_t valuesWritten, // The number of values written to in certain SFINAE cases + const bool validMinMax, // The flag to update Min/Max for a block or not + const primitives::RIDType ridOffset, // The first RID value of the dataVecTPtr + T* dataVecTPtr, // Typed SIMD vector from the input block + primitives::RIDType* ridDstArray, // The actual dst arrray ptr to start writing RIDs + MT writeMask, // SIMD intrinsics bitmask for values to write + T& Min, T&Max, // Min/Max of the extent + NewColRequestHeader* in, // Proto message + ColResultHeader* out, // Proto message + MT nonNullOrEmptyMask, // SIMD intrinsics inverce bitmask for NULL/EMPTY values + primitives::RIDType* ridSrcArray) // The actual src array ptr to read RIDs +{ + constexpr const uint16_t WIDTH = sizeof(T); + primitives::RIDType* origRIDDstArray = ridDstArray; + // Saving values based on writeMask into tmp vec. + // Min/Max processing. + // The mask is 16 bit long and it describes N elements where N = sizeof(vector type) / WIDTH. + uint16_t j = 0; + for (uint32_t it = 0; it < VT::vecByteSize; ++j, it += WIDTH) + { + MT bitMapPosition = 1 << it; + if (writeMask & (1 << it)) + { + vectWriteColValuesLoopRIDAsignment(ridDstArray, out, ridOffset + j, + ridSrcArray, j); + ++ridDstArray; + } + vectUpdateMinMax(validMinMax, nonNullOrEmptyMask & bitMapPosition, + Min, Max, dataVecTPtr[j], in); + } + return ridDstArray - origRIDDstArray; +} + +// Both RIDs and values +// vectWriteColValues writes RIDs traversing the writeMask. +template::type* = nullptr> +inline uint16_t vectWriteRIDValues(VT& processor, // SIMD processor + const uint16_t valuesWritten, // The number of values written to in certain SFINAE cases + const bool validMinMax, // The flag to update Min/Max for a block or not + const primitives::RIDType ridOffset, // The first RID value of the dataVecTPtr + T* dataVecTPtr, // Typed SIMD vector from the input block + primitives::RIDType* ridDstArray, // The actual dst arrray ptr to start writing RIDs + MT writeMask, // SIMD intrinsics bitmask for values to write + T& Min, T&Max, // Min/Max of the extent + NewColRequestHeader* in, // Proto message + ColResultHeader* out, // Proto message + MT nonNullOrEmptyMask, // SIMD intrinsics inverce bitmask for NULL/EMPTY values + primitives::RIDType* ridSrcArray) // The actual src array ptr to read RIDs +{ + return valuesWritten; +} + +// No RIDs only values +template::type* = nullptr> +inline uint16_t vectWriteRIDValues(VT& processor, // SIMD processor + const uint16_t valuesWritten, // The number of values written to in certain SFINAE cases + const bool validMinMax, // The flag to update Min/Max for a block or not + const primitives::RIDType ridOffset, // The first RID value of the dataVecTPtr + T* dataVecTPtr, // Typed SIMD vector from the input block + primitives::RIDType* ridDstArray, // The actual dst arrray ptr to start writing RIDs + MT writeMask, // SIMD intrinsics bitmask for values to write + T& Min, T&Max, // Min/Max of the extent + NewColRequestHeader* in, // Proto message + ColResultHeader* out, // Proto message + MT nonNullOrEmptyMask, // SIMD intrinsics inverce bitmask for NULL/EMPTY values + primitives::RIDType* ridSrcArray) // The actual src array ptr to read RIDs +{ + return valuesWritten; +} +#endif + +/***************************************************************************** + *** RUN DATA THROUGH A COLUMN FILTER **************************************** + *****************************************************************************/ +// TODO turn columnFilterMode into template param to use it in matchingColValue +// This routine filters values in a columnar block processing one scalar at a time. +template +void scalarFiltering(NewColRequestHeader* in, ColResultHeader* out, + const ColumnFilterMode columnFilterMode, + const ST* filterSet, // Set of values for simple filters (any of values / none of them) + const uint32_t filterCount, // Number of filter elements, each described by one entry in the following arrays: + const uint8_t* filterCOPs, // comparison operation + const FT* filterValues, // value to compare to + const uint8_t* filterRFs, + const ColRequestHeaderDataType& typeHolder, // TypeHolder to use collation-aware ops for char/text. + const T* srcArray, // Input array + const uint32_t srcSize, // ... and its size + const uint16_t* ridArray, // Optional array of indexes into srcArray, that defines the read order + const uint16_t ridSize, // ... and its size + const uint32_t initialRID, // The input block idx to start scanning/filter at. + const uint8_t outputType, // Used to decide whether to skip EMPTY values + const bool validMinMax, // The flag to store min/max + T emptyValue, // Deduced empty value magic + T nullValue, // Deduced null value magic + T Min, + T Max, + const bool isNullValueMatches) +{ + constexpr int WIDTH = sizeof(T); + // Loop-local variables + T curValue = 0; + primitives::RIDType rid = 0; + bool isEmpty = false; + + // Loop over the column values, storing those matching the filter, and updating the min..max range + for (uint32_t i = initialRID; + nextColValue(curValue, &isEmpty, + &i, &rid, + srcArray, srcSize, ridArray, ridSize, + outputType, emptyValue); ) + { + if (isEmpty) + continue; + else if (isNullValue(curValue, nullValue)) + { + // If NULL values match the filter, write curValue to the output buffer + if (isNullValueMatches) + writeColValue(outputType, out, rid, srcArray); + } + else + { + // If curValue matches the filter, write it to the output buffer + if (matchingColValue(curValue, columnFilterMode, filterSet, filterCount, + filterCOPs, filterValues, filterRFs, in->colType, nullValue)) + { + writeColValue(outputType, out, rid, srcArray); + } + + // Update Min and Max if necessary. EMPTY/NULL values are processed in other branches. + if (validMinMax) + updateMinMax(Min, Max, curValue, in); + } + } + + // Write captured Min/Max values to *out + out->ValidMinMax = validMinMax; + if (validMinMax) + { + out->Min = Min; + out->Max = Max; + } +} + +#if defined(__x86_64__ ) +template ::type* = nullptr> +inline SIMD_WRAPPER_TYPE simdDataLoadTemplate(VT& processor, const T* srcArray, + const T* origSrcArray, const primitives::RIDType* ridArray, const uint16_t iter) +{ + return {processor.loadFrom(reinterpret_cast(srcArray))}; +} + +// Scatter-gather implementation +// TODO Move the logic into simd namespace class methods and use intrinsics +template ::type* = nullptr> +inline SIMD_WRAPPER_TYPE simdDataLoadTemplate(VT& processor, const T* srcArray, + const T* origSrcArray, const primitives::RIDType* ridArray, const uint16_t iter) +{ + constexpr const uint16_t WIDTH = sizeof(T); + constexpr const uint16_t VECTOR_SIZE = VT::vecByteSize / WIDTH; + using SIMD_TYPE = typename VT::SIMD_TYPE; + SIMD_TYPE result; + T* resultTypedPtr = reinterpret_cast(&result); + for (uint32_t i = 0; i < VECTOR_SIZE; ++i) + { + //std::cout << " simdDataLoadTemplate ridArray[ridArrayOffset] " << (int8_t) origSrcArray[ridArray[i]] << " ridArray[i] " << ridArray[i] << "\n"; + resultTypedPtr[i] = origSrcArray[ridArray[i]]; + } + + return {result}; +} + +// This routine filters input block in a vectorized manner. +// It supports all output types, all input types. +// It doesn't support KIND==TEXT so upper layers filters this KIND out beforehand. +// It doesn't support KIND==FLOAT yet also. +// To reduce branching it first compiles the filter to produce a vector of +// vector processing class methods(actual filters) pointers and a logical function pointer +// to glue the masks produced by actual filters. +// Then it takes a vector of data, run filters and logical function using pointers. +// See the corresponding dispatcher to get more details on vector processing class. +template +void vectorizedFiltering(NewColRequestHeader* in, ColResultHeader* out, + const T* srcArray, const uint32_t srcSize, primitives::RIDType* ridArray, + const uint16_t ridSize, ParsedColumnFilter* parsedColumnFilter, + const bool validMinMax, const T emptyValue, const T nullValue, + T Min, T Max, const bool isNullValueMatches) +{ + constexpr const uint16_t WIDTH = sizeof(T); + using SIMD_TYPE = typename VT::SIMD_TYPE; + using SIMD_WRAPPER_TYPE = typename VT::SIMD_WRAPPER_TYPE; + VT simdProcessor; + SIMD_TYPE dataVec; + SIMD_TYPE emptyFilterArgVec = simdProcessor.loadValue(emptyValue); + SIMD_TYPE nullFilterArgVec = simdProcessor.loadValue(nullValue); + MT writeMask, nonEmptyMask, nonNullMask, nonNullOrEmptyMask; + MT initFilterMask = 0xFFFF; + primitives::RIDType rid = 0; + primitives::RIDType* origRidArray = ridArray; + uint16_t totalValuesWritten = 0; + char* dstArray = reinterpret_cast(primitives::getFirstValueArrayPosition(out)); + primitives::RIDType* ridDstArray = reinterpret_cast(getFirstRIDArrayPosition(out)); + const T* origSrcArray = srcArray; + const FT* filterValues = nullptr; + const ParsedColumnFilter::CopsType* filterCOPs = nullptr; + ColumnFilterMode columnFilterMode = ALWAYS_TRUE; + const ST* filterSet = nullptr; + const ParsedColumnFilter::RFsType* filterRFs = nullptr; + + uint8_t outputType = in->OutputType; + + constexpr uint16_t VECTOR_SIZE = VT::vecByteSize / WIDTH; + // If there are RIDs use its number to get a number of vectorized iterations. + uint16_t iterNumber = HAS_INPUT_RIDS ? ridSize / VECTOR_SIZE : srcSize / VECTOR_SIZE; + uint32_t filterCount = 0; + // These pragmas are to silence GCC warnings + // warning: ignoring attributes on template argument +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wignored-attributes" + std::vector filterArgsVectors; + auto ptrA = std::mem_fn(&VT::cmpEq); + using COPType = decltype(ptrA); + std::vector copFunctorVec; +#pragma GCC diagnostic pop + using BOPType = std::function; + BOPType bopFunctor; + // filter comparators and logical function compilation. + if (parsedColumnFilter != nullptr) + { + filterValues = parsedColumnFilter->getFilterVals(); + filterCOPs = parsedColumnFilter->prestored_cops.get(); + columnFilterMode = parsedColumnFilter->columnFilterMode; + filterSet = parsedColumnFilter->getFilterSet(); + filterRFs = parsedColumnFilter->prestored_rfs.get(); + filterCount = parsedColumnFilter->getFilterCount(); + if (iterNumber > 0) + { + copFunctorVec.reserve(filterCount); + switch(parsedColumnFilter->getBOP()) + { + case BOP_OR: + bopFunctor = std::bit_or(); + initFilterMask = 0; + break; + case BOP_AND: + bopFunctor = std::bit_and(); + break; + case BOP_XOR: + bopFunctor = std::bit_or(); + initFilterMask = 0; + break; + case BOP_NONE: + // According with the comments in linux-port/primitiveprocessor.h + // there can't be BOP_NONE with filterCount > 0 + bopFunctor = std::bit_and(); + break; + default: + idbassert(false); + } + filterArgsVectors.reserve(filterCount); + for (uint32_t j = 0; j < filterCount; ++j) + { + // Preload filter argument values only once. + filterArgsVectors[j] = simdProcessor.loadValue(filterValues[j]); + switch(filterCOPs[j]) + { + case(COMPARE_EQ): + copFunctorVec.push_back(std::mem_fn(&VT::cmpEq)); + break; + case(COMPARE_GE): + copFunctorVec.push_back(std::mem_fn(&VT::cmpGe)); + break; + case(COMPARE_GT): + copFunctorVec.push_back(std::mem_fn(&VT::cmpGt)); + break; + case(COMPARE_LE): + copFunctorVec.push_back(std::mem_fn(&VT::cmpLe)); + break; + case(COMPARE_LT): + copFunctorVec.push_back(std::mem_fn(&VT::cmpLt)); + break; + case(COMPARE_NE): + copFunctorVec.push_back(std::mem_fn(&VT::cmpNe)); + break; + case(COMPARE_NIL): + copFunctorVec.push_back(std::mem_fn(&VT::cmpAlwaysFalse)); + break; + // There are couple other COP, e.g. COMPARE_NOT however they can't be met here + // b/c MCS 6.x uses COMPARE_NOT for strings with OP_LIKE only. See op2num() for + // details. + + default: + idbassert(false); + } + } + } + } + + // main loop + // writeMask tells which values must get into the result. Includes values that matches filters. Can have NULLs. + // nonEmptyMask tells which vector coords are not EMPTY magics. + // nonNullMask tells which vector coords are not NULL magics. + for (uint16_t i = 0; i < iterNumber; ++i) + { + primitives::RIDType ridOffset = i * VECTOR_SIZE; + assert(!HAS_INPUT_RIDS || (HAS_INPUT_RIDS && ridSize >= ridOffset)); + dataVec = simdDataLoadTemplate(simdProcessor, srcArray, origSrcArray, ridArray, i).v; + // empty check + nonEmptyMask = simdProcessor.cmpNe(dataVec, emptyFilterArgVec); + writeMask = nonEmptyMask; + // NULL check + nonNullMask = simdProcessor.cmpNe(dataVec, nullFilterArgVec); + // Exclude NULLs from the resulting set if NULL doesn't match the filters. + writeMask = isNullValueMatches ? writeMask : writeMask & nonNullMask; + nonNullOrEmptyMask = nonNullMask & nonEmptyMask; + // filters + MT prevFilterMask = initFilterMask; + // TODO name this mask literal + MT filterMask = 0xFFFF; + for (uint32_t j = 0; j < filterCount; ++j) + { + // filter using compiled filter and preloaded filter argument + filterMask = copFunctorVec[j](simdProcessor, dataVec, filterArgsVectors[j]); + filterMask = bopFunctor(prevFilterMask, filterMask); + prevFilterMask = filterMask; + } + writeMask = writeMask & filterMask; + + T* dataVecTPtr = reinterpret_cast(&dataVec); + + // vectWriteColValues iterates over the values in the source vec + // to store values/RIDs into dstArray/ridDstArray. + // It also sets Min/Max values for the block if eligible. + // !!! vectWriteColValues increases ridDstArray internally but it doesn't go + // outside the scope of the memory allocated to out msg. + // vectWriteColValues is empty if outputMode == OT_RID. + uint16_t valuesWritten = + vectWriteColValues(simdProcessor, + writeMask, + nonNullOrEmptyMask, + validMinMax, + ridOffset, + dataVecTPtr, + dstArray, + Min, Max, + in, out, ridDstArray, + ridArray); + // Some outputType modes saves RIDs also. vectWriteRIDValues is empty for + // OT_DATAVALUE, OT_BOTH(vectWriteColValues takes care about RIDs). + valuesWritten = + vectWriteRIDValues(simdProcessor, + valuesWritten, + validMinMax, + ridOffset, + dataVecTPtr, + ridDstArray, + writeMask, + Min, Max, + in, out, + nonNullOrEmptyMask, + ridArray); + + // Calculate bytes written + uint16_t bytesWritten = valuesWritten * WIDTH; + totalValuesWritten += valuesWritten; + ridDstArray += valuesWritten; + dstArray += bytesWritten; + rid += VECTOR_SIZE; + srcArray += VECTOR_SIZE; + ridArray += VECTOR_SIZE; + } + + // Set the number of output values here b/c tail processing can skip this operation. + out->NVALS = totalValuesWritten; + // Write captured Min/Max values to *out + out->ValidMinMax = validMinMax; + if (validMinMax) + { + out->Min = Min; + out->Max = Max; + } + + // process the tail. scalarFiltering changes out contents, e.g. Min/Max, NVALS, RIDs and values array + // This tail also sets out::Min/Max, out::validMinMax if validMinMax is set. + uint32_t processedSoFar = rid; + scalarFiltering(in, out, columnFilterMode, filterSet, filterCount, filterCOPs, + filterValues, filterRFs, in->colType, origSrcArray, srcSize, origRidArray, + ridSize, processedSoFar, outputType, validMinMax, emptyValue, nullValue, + Min, Max, isNullValueMatches); +} + +// This routine dispatches template function calls to reduce branching. +template +void vectorizedFilteringDispatcher(NewColRequestHeader* in, ColResultHeader* out, + const T* srcArray, const uint32_t srcSize, uint16_t* ridArray, + const uint16_t ridSize, ParsedColumnFilter* parsedColumnFilter, + const bool validMinMax, const T emptyValue, const T nullValue, + T Min, T Max, const bool isNullValueMatches) +{ + constexpr const uint8_t WIDTH = sizeof(T); + // TODO make a SFINAE template switch for the class template spec. + using SIMD_TYPE = simd::vi128_wr; + using VT = typename simd::SimdFilterProcessor; + bool hasInputRIDs = (in->NVALS > 0) ? true : false; + if (hasInputRIDs) + { + constexpr const bool hasInput = true; + switch (in->OutputType) + { + case OT_RID: + vectorizedFiltering(in, out, + srcArray, srcSize, ridArray, ridSize, + parsedColumnFilter, + validMinMax, emptyValue, nullValue, Min, Max, isNullValueMatches); + break; + case OT_BOTH: + vectorizedFiltering(in, out, + srcArray, srcSize, ridArray, ridSize, + parsedColumnFilter, + validMinMax, emptyValue, nullValue, Min, Max, isNullValueMatches); + break; + case OT_TOKEN: + vectorizedFiltering(in, out, + srcArray, srcSize, ridArray, ridSize, + parsedColumnFilter, + validMinMax, emptyValue, nullValue, Min, Max, isNullValueMatches); + break; + case OT_DATAVALUE: + vectorizedFiltering(in, out, + srcArray, srcSize, ridArray, ridSize, + parsedColumnFilter, + validMinMax, emptyValue, nullValue, Min, Max, isNullValueMatches); + break; + } + } + else + { + constexpr const bool hasNoInput = false; + switch (in->OutputType) + { + case OT_RID: + vectorizedFiltering(in, out, + srcArray, srcSize, ridArray, ridSize, + parsedColumnFilter, + validMinMax, emptyValue, nullValue, Min, Max, isNullValueMatches); + break; + case OT_BOTH: + vectorizedFiltering(in, out, + srcArray, srcSize, ridArray, ridSize, + parsedColumnFilter, + validMinMax, emptyValue, nullValue, Min, Max, isNullValueMatches); + break; + case OT_TOKEN: + vectorizedFiltering(in, out, + srcArray, srcSize, ridArray, ridSize, + parsedColumnFilter, + validMinMax, emptyValue, nullValue, Min, Max, isNullValueMatches); + break; + case OT_DATAVALUE: + vectorizedFiltering(in, out, + srcArray, srcSize, ridArray, ridSize, + parsedColumnFilter, + validMinMax, emptyValue, nullValue, Min, Max, isNullValueMatches); + break; + + } + } +} +#endif + +// TBD Make changes in Command class ancestors to threat BPP::values as buffer. +// TBD this will allow to copy values only once from BPP::blockData to the destination. // This template contains the main scanning/filtering loop. // Copy data matching parsedColumnFilter from input to output. // Input is srcArray[srcSize], optionally accessed in the order defined by ridArray[ridSize]. -// Output is BLOB out[outSize], written starting at offset *written, which is updated afterward. +// Output is buf: ColResponseHeader, RIDType[BLOCK_SIZE], T[BLOCK_SIZE]. template void filterColumnData( NewColRequestHeader* in, @@ -995,7 +1636,7 @@ void filterColumnData( { using FT = typename IntegralTypeToFilterType::type; using ST = typename IntegralTypeToFilterSetType::type; - constexpr int COL_WIDTH = sizeof(T); + constexpr int WIDTH = sizeof(T); const T* srcArray = reinterpret_cast(srcArray16); // Cache some structure fields in local vars @@ -1015,90 +1656,49 @@ void filterColumnData( auto filterRFs = filterCount==0 ? nullptr : parsedColumnFilter->prestored_rfs.get(); ST* filterSet = filterCount==0 ? nullptr : parsedColumnFilter->getFilterSet(); - // ########################### // Bit patterns in srcArray[i] representing EMPTY and NULL values - T EMPTY_VALUE = getEmptyValue(dataType); - T NULL_VALUE = getNullValue(dataType); + T emptyValue = getEmptyValue(dataType); + T nullValue = getNullValue(dataType); // Precompute filter results for NULL values - bool isNullValueMatches = matchingColValue(NULL_VALUE, columnFilterMode, - filterSet, filterCount, filterCOPs, filterValues, filterRFs, in->colType, NULL_VALUE); + bool isNullValueMatches = matchingColValue(nullValue, columnFilterMode, + filterSet, filterCount, filterCOPs, filterValues, filterRFs, in->colType, nullValue); + // ########################### // Boolean indicating whether to capture the min and max values - bool ValidMinMax = isMinMaxValid(in); - // Local vars to capture the min and max values + bool validMinMax = isMinMaxValid(in); T Min = datatypes::numeric_limits::max(); T Max = (KIND == KIND_UNSIGNED) ? 0 : datatypes::numeric_limits::min(); -/* WIP add vertical processing - // If possible, use faster "vertical" filtering approach - if (KIND != KIND_TEXT) + // Vectorized scanning/filtering for all numerics except float/double types. + // If the total number of input values can't fill a vector the vector path + // applies scalar filtering. + // Syscat queries mustn't follow vectorized processing path b/c PP must return + // all values w/o any filter(even empty values filter) applied. + +#if defined(__x86_64__ ) + // Don't use vectorized filtering for non-integer based data types wider than 16 bytes. + if (KIND < KIND_FLOAT && WIDTH < 16) { bool canUseFastFiltering = true; - for (int i = 0; i < filterCount; ++i) + for (uint32_t i = 0; i < filterCount; ++i) if (filterRFs[i] != 0) canUseFastFiltering = false; if (canUseFastFiltering) { - processArray(srcArray, srcSize, ridArray, ridSize, - in->BOP, filterSet, filterCount, filterCOPs, filterValues, - reinterpret_cast(out) + *written, - written, & out->NVALS, & out->RidFlags, - (outputType & OT_RID) != 0, - (outputType & (OT_TOKEN | OT_DATAVALUE)) != 0, - (outputType & OT_RID) != 0, //TODO: check correctness of this condition for SKIP_EMPTY_VALUES - EMPTY_VALUE, - isNullValueMatches, NULL_VALUE, - ValidMinMax, &Min, &Max); + vectorizedFilteringDispatcher(in, out, srcArray, srcSize, ridArray, ridSize, + parsedColumnFilter.get(), validMinMax, emptyValue, + nullValue, Min, Max, isNullValueMatches); return; } } -*/ - - // Loop-local variables - T curValue = 0; - uint16_t rid = 0; - bool isEmpty = false; - - // Loop over the column values, storing those matching the filter, and updating the min..max range - for (uint32_t i = 0; - nextColValue(curValue, &isEmpty, - &i, &rid, - srcArray, srcSize, ridArray, ridSize, - outputType, EMPTY_VALUE); ) - { - if (isEmpty) - continue; - else if (isNullValue(curValue, NULL_VALUE)) - { - // If NULL values match the filter, write curValue to the output buffer - if (isNullValueMatches) - writeColValue(outputType, out, rid, srcArray); - } - else - { - // If curValue matches the filter, write it to the output buffer - if (matchingColValue(curValue, columnFilterMode, filterSet, filterCount, - filterCOPs, filterValues, filterRFs, in->colType, NULL_VALUE)) - { - writeColValue(outputType, out, rid, srcArray); - } - - // Update Min and Max if necessary. EMPTY/NULL values are processed in other branches. - if (ValidMinMax) - updateMinMax(Min, Max, curValue, in); - } - } - - - // Write captured Min/Max values to *out - out->ValidMinMax = ValidMinMax; - if (ValidMinMax) - { - out->Min = Min; - out->Max = Max; - } +#endif + uint32_t initialRID = 0; + scalarFiltering(in, out, columnFilterMode, filterSet, filterCount, filterCOPs, + filterValues, filterRFs, in->colType, srcArray, srcSize, ridArray, + ridSize, initialRID, outputType, validMinMax, emptyValue, nullValue, + Min, Max, isNullValueMatches); } // end of filterColumnData } //namespace anon diff --git a/primitives/linux-port/primitiveprocessor.cpp b/primitives/linux-port/primitiveprocessor.cpp index cc71b1eaa..09fb04029 100644 --- a/primitives/linux-port/primitiveprocessor.cpp +++ b/primitives/linux-port/primitiveprocessor.cpp @@ -62,8 +62,8 @@ ParsedColumnFilter::ParsedColumnFilter() : columnFilterMode(ALWAYS_TRUE), mFilte { } -ParsedColumnFilter::ParsedColumnFilter(const uint32_t aFilterCount) - : columnFilterMode(ALWAYS_TRUE), mFilterCount(aFilterCount) +ParsedColumnFilter::ParsedColumnFilter(const uint32_t aFilterCount, const int BOP) + : columnFilterMode(ALWAYS_TRUE), mFilterCount(aFilterCount), mBOP(BOP) { prestored_rfs.reset(new uint8_t[mFilterCount]); prestored_cops.reset(new uint8_t[mFilterCount]); diff --git a/primitives/linux-port/primitiveprocessor.h b/primitives/linux-port/primitiveprocessor.h index 1802e331b..fc54d5371 100644 --- a/primitives/linux-port/primitiveprocessor.h +++ b/primitives/linux-port/primitiveprocessor.h @@ -165,17 +165,19 @@ struct IntegralTypeToFilterSetType class ParsedColumnFilter { public: - static constexpr uint32_t noSetFilterThreshold = 8; + using CopsType = uint8_t; + using RFsType = uint8_t; + static constexpr uint32_t noSetFilterThreshold = 8; ColumnFilterMode columnFilterMode; boost::shared_array prestored_argVals; boost::shared_array prestored_argVals128; - boost::shared_array prestored_cops; + boost::shared_array prestored_cops; boost::shared_array prestored_rfs; boost::shared_ptr prestored_set; boost::shared_ptr prestored_set_128; ParsedColumnFilter(); - ParsedColumnFilter(const uint32_t aFilterCount); + ParsedColumnFilter(const uint32_t aFilterCount, const int BOP); ~ParsedColumnFilter(); templateinsert(prestored_argVals[argIndex]); } + inline int getBOP() const + { + return mBOP; + } + + inline int getFilterCount() const + { + return mFilterCount; + } + private: uint32_t mFilterCount; + int mBOP; }; //@bug 1828 These need to be public so that column operations can use it for 'like' @@ -400,7 +413,6 @@ public: template::type* = nullptr> void scanAndFilterTypeDispatcher(NewColRequestHeader* in, ColResultHeader* out); - template::type* = nullptr> void _scanAndFilterTypeDispatcher(NewColRequestHeader* in, ColResultHeader* out); @@ -433,7 +445,7 @@ public: // void p_ColAggregate(const NewColAggRequestHeader *in, NewColAggResultHeader *out); void p_Dictionary(const DictInput* in, std::vector* out, - bool skipNulls, uint32_t charsetNumber, + bool skipNulls, uint32_t charsetNumber, boost::shared_ptr eqFilter, uint8_t eqOp); @@ -492,7 +504,7 @@ boost::shared_ptr _parseColumnFilter( // Allocate the compiled filter structure with space for filterCount filters. // No need to init arrays since they will be filled on the fly. - ret.reset(new ParsedColumnFilter(filterCount)); + ret.reset(new ParsedColumnFilter(filterCount, BOP)); ret->allocateSpaceForFilterArgs(); // Choose initial filter mode based on operation and number of filter elements diff --git a/primitives/primproc/columncommand.cpp b/primitives/primproc/columncommand.cpp index d7ca66e00..94e6ace75 100644 --- a/primitives/primproc/columncommand.cpp +++ b/primitives/primproc/columncommand.cpp @@ -168,12 +168,11 @@ void ColumnCommand::_loadData() _mask = mask; -// primMsg->RidFlags = 0xffff; // disables selective block loading - //cout <<__FILE__ << "::issuePrimitive() o: " << getOID() << " l:" << primMsg->LBID << " ll: " << oidLastLbid << endl; + //primMsg->RidFlags = 0xffff; // disables selective block loading + //cerr << "::ColumnCommand::_loadData OID " << getOID() << " l:" << primMsg->LBID << " ll: " << oidLastLbid << " primMsg->RidFlags " << primMsg->RidFlags << endl; for (i = 0; i < W; ++i, _mask <<= shift) { - if ((!lastBlockReached && _isScan) || (!_isScan && primMsg->RidFlags & _mask)) { lbids[blocksToLoad] = primMsg->LBID + i; @@ -397,7 +396,6 @@ void ColumnCommand::_process_OT_BOTH() { using T = typename datatypes::WidthToSIntegralType::type; bpp->ridCount = outMsg->NVALS; - bpp->ridCount = outMsg->NVALS; bpp->ridMap = outMsg->RidFlags; uint8_t* outPtr = reinterpret_cast(&outMsg[1]); auto* ridPos = primitives::getRIDArrayPosition(outPtr, 0); diff --git a/primitives/primproc/dictstep.cpp b/primitives/primproc/dictstep.cpp index 52c012df7..0aa6e92fa 100644 --- a/primitives/primproc/dictstep.cpp +++ b/primitives/primproc/dictstep.cpp @@ -154,7 +154,7 @@ void DictStep::issuePrimitive(bool isFilter) if (!(primMsg->LBID & 0x8000000000000000LL)) { - //cout << "DS issuePrimitive lbid: " << (uint64_t)primMsg->LBID << endl; + //std::cerr << "DS issuePrimitive lbid: " << (uint64_t)primMsg->LBID << endl; primitiveprocessor::loadBlock(primMsg->LBID, bpp->versionInfo, bpp->txnID, @@ -577,7 +577,7 @@ void DictStep::_projectToRG(RowGroup& rg, uint32_t col) for (i = curResultCounter; i < tmpResultCounter; i++) { rg.getRow(newRidList[i].pos, &r); - //cout << "serializing " << tmpStrings[i] << endl; + //std::cerr << "serializing " << tmpStrings[i] << endl; r.setStringField(tmpStrings[i].getConstString(), col); } } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 0fe6f29e4..abbba30e4 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -42,3 +42,13 @@ if (WITH_UNITTESTS) add_test(NAME columnstore:comparators_tests, COMMAND comparators_tests) endif() + +# Saving this as the example of the microbench +#if (WITH_MICROBENCHMARKS AND (NOT CMAKE_BUILD_TYPE STREQUAL "debug")) +# find_package(benchmark REQUIRED) +# add_executable(primitives_scan_bench primitives_scan_bench.cpp) +# target_include_directories(primitives_scan_bench PUBLIC ${ENGINE_COMMON_INCLUDES} ${ENGINE_BLOCKCACHE_INCLUDE} ${ENGINE_PRIMPROC_INCLUDE} ) +# target_link_libraries(primitives_scan_bench ${ENGINE_LDFLAGS} ${MARIADB_CLIENT_LIBS} ${ENGINE_WRITE_LIBS} ${GTEST_LIBRARIES} processor dbbc benchmark::benchmark) +# install(TARGETS primitives_scan_bench DESTINATION ${ENGINE_BINDIR} COMPONENT columnstore-engine) +#endif() + diff --git a/tests/col16block.h b/tests/col16block.h new file mode 100644 index 000000000..67f68b496 --- /dev/null +++ b/tests/col16block.h @@ -0,0 +1,708 @@ +/* Copyright (C) 2021 MariaDB Corporation + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 of + the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#ifndef HAVE_COL16BLOCK +#define HAVE_COL16BLOCK +unsigned char ___bin_col16block_cdf[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x15, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x22, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x23, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x26, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x36, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x45, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x4b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x4e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x51, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x52, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x54, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x55, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x57, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x58, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x61, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x63, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x69, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x72, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x74, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x76, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7a, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7d, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x84, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x85, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x8b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x8e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x93, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x95, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x97, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x98, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x9a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9b, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x9d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9e, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa1, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa4, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa7, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaa, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xab, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xac, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xad, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xae, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xaf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb3, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xba, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xbb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbc, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xbd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xbe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc2, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc5, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xca, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcb, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xcc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xcd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xce, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xcf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xd0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd1, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xd2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xd3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd4, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xd5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xd6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd7, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xd8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xd9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xda, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xdb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdd, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xde, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xdf, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe2, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe3, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe6, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe9, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xea, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xeb, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xec, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xed, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xee, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xef, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf1, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf2, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf5, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf7, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfa, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x03, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x06, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x09, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x0e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x0f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x12, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x14, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x15, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x19, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x1d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x1e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x20, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x21, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x23, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x24, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x26, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x27, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x29, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x2d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x2f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x32, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x33, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x35, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x36, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x38, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x39, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x3e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x41, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x42, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x44, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x45, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x47, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x48, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x4a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x4b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4c, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x4d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x4e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x50, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x51, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x53, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x54, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x56, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x57, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x59, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x5d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x5f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x61, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x62, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x63, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x65, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x66, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x68, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x69, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6a, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x6f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x71, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x72, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x74, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x75, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x76, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x77, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x78, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7c, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x7d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x7e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x81, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x83, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x84, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x86, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x87, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x89, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x8a, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8b, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x8d, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8e, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x8f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x91, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x92, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x93, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x94, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x95, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x96, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x97, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x98, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x99, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9a, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x9c, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x9d, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x9e, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x9f, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa3, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa6, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xa7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xa8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa9, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xaa, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xab, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xac, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xad, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xae, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xaf, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb2, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb5, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xb7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xb9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xba, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbb, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xbc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xbd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbe, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xbf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc1, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc4, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc7, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xc8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xc9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xca, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xcb, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xcc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xcd, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xce, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xcf, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd0, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xd1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xd2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xd4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xd5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd6, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xd7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xd8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd9, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xda, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xdb, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdc, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xdd, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xde, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xdf, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe1, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe2, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe4, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xe7, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe8, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xe9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xea, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xeb, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xec, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xed, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xee, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xef, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf2, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf4, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf5, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf6, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf7, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xf8, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xf9, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfa, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfb, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfd, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xfe, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; +unsigned int ___bin_col16block_cdf_len = 8192; +constexpr int __col16block_cdf_umin = 2; +constexpr int __col16block_cdf_umax = 511; +#endif diff --git a/tests/col1block.h b/tests/col1block.h index 8660261a1..ab836f243 100644 --- a/tests/col1block.h +++ b/tests/col1block.h @@ -703,4 +703,6 @@ unsigned char __col1block_cdf[] = { 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff }; unsigned int __col1block_cdf_len = 8192; +constexpr int __col1block_cdf_umin = -126; +constexpr int __col1block_cdf_umax = 127; #endif diff --git a/tests/col2block.h b/tests/col2block.h index d14fab321..3637654a0 100644 --- a/tests/col2block.h +++ b/tests/col2block.h @@ -703,4 +703,6 @@ unsigned char __col2block_cdf[] = { 0xfc, 0x0f, 0xfd, 0x0f, 0xfe, 0x0f, 0xff, 0x0f }; unsigned int __col2block_cdf_len = 8192; +constexpr int __col2block_cdf_umin = 0; +constexpr int __col2block_cdf_umax = 4095; #endif diff --git a/tests/col4block.h b/tests/col4block.h index 1bc5045bb..b9dde31a6 100644 --- a/tests/col4block.h +++ b/tests/col4block.h @@ -703,4 +703,6 @@ unsigned char __col4block_cdf[] = { 0xfe, 0x07, 0x00, 0x00, 0xff, 0x07, 0x00, 0x00 }; unsigned int __col4block_cdf_len = 8192; +constexpr int __col4block_cdf_umin = 0; +constexpr int __col4block_cdf_umax = 2047; #endif diff --git a/tests/col8block.h b/tests/col8block.h index 428a59e4f..7cf0de38a 100644 --- a/tests/col8block.h +++ b/tests/col8block.h @@ -703,4 +703,6 @@ unsigned char ___bin_col8block_cdf[] = { 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; unsigned int ___bin_col8block_cdf_len = 8192; +constexpr int __col8block_cdf_umin = 0; +constexpr int __col8block_cdf_umax = 1023; #endif diff --git a/tests/primitives_column_scan_and_filter.cpp b/tests/primitives_column_scan_and_filter.cpp index 625278d36..d1e5a9cf6 100644 --- a/tests/primitives_column_scan_and_filter.cpp +++ b/tests/primitives_column_scan_and_filter.cpp @@ -17,13 +17,17 @@ #include #include + +#include "utils/common/columnwidth.h" #include "datatypes/mcs_datatype.h" +#include "datatypes/mcs_int128.h" #include "stats.h" #include "primitives/linux-port/primitiveprocessor.h" #include "col1block.h" #include "col2block.h" #include "col4block.h" #include "col8block.h" +#include "col16block.h" #include "col_float_block.h" #include "col_double_block.h" #include "col_neg_float.h" @@ -33,7 +37,7 @@ using namespace primitives; using namespace datatypes; using namespace std; -// If a test crashes check if there is a corresponding literal binary array in +// If a test crashes check if there is a corresponding literal binary array in // readBlockFromLiteralArray. class ColumnScanFilterTest : public ::testing::Test @@ -41,8 +45,8 @@ class ColumnScanFilterTest : public ::testing::Test protected: PrimitiveProcessor pp; uint8_t input[BLOCK_SIZE]; - uint8_t output[4 * BLOCK_SIZE]; - uint8_t block[BLOCK_SIZE]; + alignas(utils::MAXCOLUMNWIDTH) uint8_t output[4 * BLOCK_SIZE]; + alignas(utils::MAXCOLUMNWIDTH) uint8_t block[BLOCK_SIZE]; uint16_t* rids; uint32_t i; NewColRequestHeader* in; @@ -91,7 +95,7 @@ protected: close(fd); return block; - } + } uint8_t* readBlockFromLiteralArray(const std::string& fileName, uint8_t* block) { if (fileName == std::string("col1block.cdf")) @@ -102,6 +106,8 @@ protected: return &__col4block_cdf[0]; else if (fileName == std::string("col8block.cdf")) return &___bin_col8block_cdf[0]; + else if (fileName == std::string("col16block.cdf")) + return &___bin_col16block_cdf[0]; else if (fileName == std::string("col_float_block.cdf")) return &___bin_col_float_block_cdf[0]; else if (fileName == std::string("col_double_block.cdf")) @@ -115,7 +121,6 @@ protected: } }; - TEST_F(ColumnScanFilterTest, ColumnScan1Byte) { constexpr const uint8_t W = 1; @@ -137,7 +142,42 @@ TEST_F(ColumnScanFilterTest, ColumnScan1Byte) for (i = 0; i < 300; i++) EXPECT_EQ(results[i],i % 255); + // Can't check Min/Max for char columns until MCOL-4871 +} +TEST_F(ColumnScanFilterTest, ColumnScan1ByteVectorized) +{ + constexpr const uint8_t W = 1; + using IntegralType = datatypes::WidthToSIntegralType::type; + using UT = datatypes::make_unsigned::type; + UT* results; + in->colType = ColRequestHeaderDataType(); + in->colType.DataSize = W; + in->colType.DataType = SystemCatalog::TINYINT; + in->OutputType = OT_DATAVALUE; + in->NOPS = 0; + in->NVALS = 0; + + pp.setBlockPtr((int*) readBlockFromLiteralArray("col1block.cdf", block)); + pp.columnScanAndFilter(in, out); + + results = getValuesArrayPosition(getFirstValueArrayPosition(out), 0); + EXPECT_EQ(out->NVALS, 8160); + + for (i = 0; i < 128; ++i) + EXPECT_EQ(results[i],i); + + for (i = 129; i < 255; ++i) + EXPECT_EQ(results[i],i + 1); + + EXPECT_EQ(results[8032], 0x7F); + EXPECT_EQ(results[8033], 0x80); + + for (i = 8034; i < 8160; ++i) + EXPECT_EQ(results[i],i % 255 + 1); + + EXPECT_EQ(out->Max, __col1block_cdf_umax); + EXPECT_EQ(out->Min, __col1block_cdf_umin); } TEST_F(ColumnScanFilterTest, ColumnScan2Bytes) @@ -160,6 +200,9 @@ TEST_F(ColumnScanFilterTest, ColumnScan2Bytes) for (i = 0; i < out->NVALS; i++) EXPECT_EQ(results[i], i); + + EXPECT_EQ(out->Max, __col2block_cdf_umax); + EXPECT_EQ(out->Min, __col2block_cdf_umin); } TEST_F(ColumnScanFilterTest, ColumnScan4Bytes) @@ -182,6 +225,8 @@ TEST_F(ColumnScanFilterTest, ColumnScan4Bytes) for (i = 0; i < out->NVALS; i++) EXPECT_EQ(results[i], (uint32_t) i); + EXPECT_EQ(out->Max, __col4block_cdf_umax); + EXPECT_EQ(out->Min, __col4block_cdf_umin); } TEST_F(ColumnScanFilterTest, ColumnScan8Bytes) @@ -204,6 +249,40 @@ TEST_F(ColumnScanFilterTest, ColumnScan8Bytes) for (i = 0; i < out->NVALS; i++) ASSERT_EQ(results[i], (uint32_t) i); + EXPECT_EQ(out->Max, __col8block_cdf_umax); + EXPECT_EQ(out->Min, __col8block_cdf_umin); +} + +TEST_F(ColumnScanFilterTest, ColumnScan2Bytes1EqFilter) +{ + constexpr const uint8_t W = 2; + using IntegralType = datatypes::WidthToSIntegralType::type; + using UT = datatypes::make_unsigned::type; + UT* results; + IntegralType tmp; + + in->colType.DataSize = W; + in->colType.DataType = SystemCatalog::INT; + in->OutputType = OT_DATAVALUE; + in->NOPS = 1; + in->BOP = BOP_AND; + in->NVALS = 0; + + tmp = 50; + args->COP = COMPARE_LE; + memcpy(args->val, &tmp, in->colType.DataSize); + args = reinterpret_cast(&input[sizeof(NewColRequestHeader) + + sizeof(ColArgs) + in->colType.DataSize]); + + pp.setBlockPtr((int*) readBlockFromLiteralArray("col2block.cdf", block)); + pp.columnScanAndFilter(in, out); + + results = getValuesArrayPosition(getFirstValueArrayPosition(out), 0); + ASSERT_EQ(out->NVALS, 51); + for (i = 0; i < out->NVALS; i++) + ASSERT_EQ(results[i], i); + EXPECT_EQ(out->Max, __col2block_cdf_umax); + EXPECT_EQ(out->Min, __col2block_cdf_umin); } TEST_F(ColumnScanFilterTest, ColumnScan1ByteUsingRID) @@ -226,11 +305,101 @@ TEST_F(ColumnScanFilterTest, ColumnScan1ByteUsingRID) results = getValuesArrayPosition(getFirstValueArrayPosition(out), 0); ASSERT_EQ(out->NVALS, 2); - for (i = 0; i < out->NVALS; i++) + for (i = 0; i < out->NVALS; ++i) ASSERT_EQ(results[i], rids[i]); } -TEST_F(ColumnScanFilterTest, ColumnScan4Bytes1Filter) +TEST_F(ColumnScanFilterTest, ColumnScan1ByteUsingMultipleRIDs) +{ + constexpr const uint8_t W = 1; + using IntegralType = datatypes::WidthToSIntegralType::type; + using UT = datatypes::make_unsigned::type; + UT* results; + const size_t expectedNVALS = 127; + + in->colType.DataSize = W; + in->colType.DataType = SystemCatalog::INT; + in->OutputType = OT_DATAVALUE; + in->NOPS = 0; + in->NVALS = expectedNVALS; + for (i = 0; i < expectedNVALS; ++i) + rids[i] = i; + rids[0] = 20; + rids[1] = 17; + rids[126] = 8189; + + pp.setBlockPtr((int*) readBlockFromLiteralArray("col1block.cdf", block)); + pp.columnScanAndFilter(in, out); + + results = getValuesArrayPosition(getFirstValueArrayPosition(out), 0); + ASSERT_EQ(out->NVALS, expectedNVALS); + + for (i = 0; i < expectedNVALS - 1; ++i) + ASSERT_EQ(results[i], rids[i]); + ASSERT_EQ(results[126], 253); +} + +TEST_F(ColumnScanFilterTest, ColumnScan4Bytes1EqFilter) +{ + constexpr const uint8_t W = 4; + using IntegralType = datatypes::WidthToSIntegralType::type; + using UT = datatypes::make_unsigned::type; + UT* results; + IntegralType tmp; + + in->colType.DataSize = W; + in->colType.DataType = SystemCatalog::INT; + in->OutputType = OT_DATAVALUE; + in->NOPS = 1; + in->BOP = BOP_AND; + in->NVALS = 0; + + tmp = 2040; + args->COP = COMPARE_GE; + memcpy(args->val, &tmp, in->colType.DataSize); + args = reinterpret_cast(&input[sizeof(NewColRequestHeader) + + sizeof(ColArgs) + in->colType.DataSize]); + + pp.setBlockPtr((int*) readBlockFromLiteralArray("col4block.cdf", block)); + pp.columnScanAndFilter(in, out); + + results = getValuesArrayPosition(getFirstValueArrayPosition(out), 0); + ASSERT_EQ(out->NVALS, 8); + for (i = 0; i < out->NVALS; i++) + ASSERT_EQ(results[i], i + 2040); +} + +TEST_F(ColumnScanFilterTest, ColumnScan4BytesUsingMultipleRIDs) +{ + constexpr const uint8_t W = 4; + using IntegralType = datatypes::WidthToSIntegralType::type; + using UT = datatypes::make_unsigned::type; + UT* results; + const size_t expectedNVALS = 127; + + in->colType.DataSize = W; + in->colType.DataType = SystemCatalog::INT; + in->OutputType = OT_DATAVALUE; + in->NOPS = 0; + in->NVALS = expectedNVALS; + for (i = 0; i < expectedNVALS; ++i) + rids[i] = i; + rids[0] = 20; + rids[1] = 17; + rids[126] = 1020; + + pp.setBlockPtr((int*) readBlockFromLiteralArray("col4block.cdf", block)); + pp.columnScanAndFilter(in, out); + + results = getValuesArrayPosition(getFirstValueArrayPosition(out), 0); + + ASSERT_EQ(out->NVALS, expectedNVALS); + for (i = 0; i < expectedNVALS - 1; ++i) + ASSERT_EQ(results[i], rids[i]); + ASSERT_EQ(results[126], 1020); +} + +TEST_F(ColumnScanFilterTest, ColumnScan4Bytes2Filters) { constexpr const uint8_t W = 4; using IntegralType = datatypes::WidthToSIntegralType::type; @@ -261,6 +430,72 @@ TEST_F(ColumnScanFilterTest, ColumnScan4Bytes1Filter) for (i = 0; i < out->NVALS; i++) ASSERT_EQ(results[i], 11 + (uint32_t)i); + + EXPECT_EQ(out->Max, __col4block_cdf_umax); + EXPECT_EQ(out->Min, __col4block_cdf_umin); +} + +TEST_F(ColumnScanFilterTest, ColumnScan8Bytes1EqFilter) +{ + constexpr const uint8_t W = 8; + using IntegralType = datatypes::WidthToSIntegralType::type; + using UT = datatypes::make_unsigned::type; + UT* results; + IntegralType tmp; + + in->colType.DataSize = W; + in->colType.DataType = SystemCatalog::INT; + in->OutputType = OT_DATAVALUE; + in->NOPS = 1; + in->BOP = BOP_AND; + in->NVALS = 0; + + tmp = 11; + args->COP = COMPARE_LT; + memcpy(args->val, &tmp, in->colType.DataSize); + args = reinterpret_cast(&input[sizeof(NewColRequestHeader) + + sizeof(ColArgs) + in->colType.DataSize]); + + pp.setBlockPtr((int*) readBlockFromLiteralArray("col8block.cdf", block)); + pp.columnScanAndFilter(in, out); + + results = getValuesArrayPosition(getFirstValueArrayPosition(out), 0); + ASSERT_EQ(out->NVALS, 11); + for (i = 0; i < out->NVALS; i++) + ASSERT_EQ(results[i], i); + + EXPECT_EQ(out->Max, __col8block_cdf_umax); + EXPECT_EQ(out->Min, __col8block_cdf_umin); +} + +TEST_F(ColumnScanFilterTest, ColumnScan8BytesUsingMultipleRIDs) +{ + constexpr const uint8_t W = 8; + using IntegralType = datatypes::WidthToSIntegralType::type; + using UT = datatypes::make_unsigned::type; + UT* results; + const size_t expectedNVALS = 127; + + in->colType.DataSize = W; + in->colType.DataType = SystemCatalog::INT; + in->OutputType = OT_DATAVALUE; + in->NOPS = 0; + in->NVALS = expectedNVALS; + for (i = 0; i < expectedNVALS; ++i) + rids[i] = i; + rids[0] = 20; + rids[1] = 17; + rids[126] = 1020; + + pp.setBlockPtr((int*) readBlockFromLiteralArray("col8block.cdf", block)); + pp.columnScanAndFilter(in, out); + + results = getValuesArrayPosition(getFirstValueArrayPosition(out), 0); + + ASSERT_EQ(out->NVALS, expectedNVALS); + for (i = 0; i < expectedNVALS - 1; ++i) + ASSERT_EQ(results[i], rids[i]); + ASSERT_EQ(results[126], 1020); } //void p_Col_7() @@ -296,6 +531,9 @@ TEST_F(ColumnScanFilterTest, ColumnScan8Bytes2CompFilters) for (i = 0; i < out->NVALS; i++) ASSERT_EQ(results[i], (uint32_t) (i < 10 ? i : i - 10 + 1001)); + + EXPECT_EQ(out->Max, __col8block_cdf_umax); + EXPECT_EQ(out->Min, __col8block_cdf_umin); } TEST_F(ColumnScanFilterTest, ColumnScan8Bytes2EqFilters) @@ -330,6 +568,8 @@ TEST_F(ColumnScanFilterTest, ColumnScan8Bytes2EqFilters) ASSERT_EQ(out->NVALS, 2); ASSERT_EQ(results[0], 10); ASSERT_EQ(results[1], 1000); + ASSERT_EQ(out->Max, __col8block_cdf_umax); + ASSERT_EQ(out->Min, __col8block_cdf_umin); } TEST_F(ColumnScanFilterTest, ColumnScan8Bytes2EqFiltersRID) @@ -370,7 +610,7 @@ TEST_F(ColumnScanFilterTest, ColumnScan8Bytes2EqFiltersRID) ASSERT_EQ(results[0], 10); } -TEST_F(ColumnScanFilterTest, ColumnScan8Bytes2EqFiltersRIDOutputRid) +TEST_F(ColumnScanFilterTest, ColumnScan8Bytes2FiltersRIDOutputRid) { constexpr const uint8_t W = 8; using IntegralType = datatypes::WidthToSIntegralType::type; @@ -400,7 +640,9 @@ TEST_F(ColumnScanFilterTest, ColumnScan8Bytes2EqFiltersRIDOutputRid) ASSERT_EQ(out->NVALS, 33); for (i = 0; i < out->NVALS; i++) - ASSERT_EQ(results[i], (i < 10 ? i : i - 10 + 1001)); + ASSERT_EQ(results[i], (i < 10 ? i : i - 10 + 1001)); + ASSERT_EQ(out->Max, __col8block_cdf_umax); + ASSERT_EQ(out->Min, __col8block_cdf_umin); } TEST_F(ColumnScanFilterTest, ColumnScan8Bytes2EqFiltersRIDOutputBoth) @@ -437,6 +679,8 @@ TEST_F(ColumnScanFilterTest, ColumnScan8Bytes2EqFiltersRIDOutputBoth) ASSERT_EQ(resultRid[i], (i < 10 ? i : i - 10 + 1001)); ASSERT_EQ(resultVal[i], (i < 10 ? i : i - 10 + 1001)); } + ASSERT_EQ(out->Max, __col8block_cdf_umax); + ASSERT_EQ(out->Min, __col8block_cdf_umin); } //void p_Col_12() @@ -649,7 +893,7 @@ TEST_F(ColumnScanFilterTest, ColumnScan4BytesNegDouble2CompFilters) pp.setBlockPtr((int*) readBlockFromLiteralArray("col_neg_double.cdf", block)); pp.columnScanAndFilter(in, out); - //ASSERT_EQ(out->NVALS, 19); + ASSERT_EQ(out->NVALS, 19); for (i = 0; i < out->NVALS; i++) { @@ -657,8 +901,67 @@ TEST_F(ColumnScanFilterTest, ColumnScan4BytesNegDouble2CompFilters) } } +TEST_F(ColumnScanFilterTest, ColumnScan16Bytes) +{ + constexpr const uint8_t W = 16; + using IntegralType = datatypes::WidthToSIntegralType::type; + IntegralType* results; + + in->colType.DataSize = W; + in->colType.DataType = SystemCatalog::DECIMAL; + in->OutputType = OT_DATAVALUE; + in->NOPS = 0; + in->BOP = BOP_OR; + in->NVALS = 0; + + pp.setBlockPtr((int*) readBlockFromLiteralArray("col16block.cdf", block)); + pp.columnScanAndFilter(in, out); + + results = getValuesArrayPosition(getFirstValueArrayPosition(out), 0); + + ASSERT_EQ(out->NVALS, 511); + // I was not able to use datatypes::TSInt128 static member so I used this + int128_t NullValue = int128_t(0x8000000000000000LL) << 64; + ASSERT_EQ(results[0], NullValue); + for (i = 1; i < out->NVALS; ++i) + ASSERT_EQ(results[i], i+1); + EXPECT_EQ(out->Max, __col16block_cdf_umax); + EXPECT_EQ(out->Min, __col16block_cdf_umin); +} + TEST_F(ColumnScanFilterTest, ColumnScan16Bytes2CompFilters) { -//TBD + constexpr const uint8_t W = 16; + using IntegralType = datatypes::WidthToSIntegralType::type; + IntegralType* results; + IntegralType tmp; + + in->colType.DataSize = W; + in->colType.DataType = SystemCatalog::DECIMAL; + in->OutputType = OT_DATAVALUE; + in->NOPS = 2; + in->BOP = BOP_OR; + in->NVALS = 0; + + tmp = 10; + args->COP = COMPARE_EQ; + memcpy(args->val, &tmp, in->colType.DataSize); + args = reinterpret_cast(&input[sizeof(NewColRequestHeader) + + sizeof(ColArgs) + in->colType.DataSize]); + args->COP = COMPARE_EQ; + tmp = 510; + memcpy(args->val, &tmp, in->colType.DataSize); + + pp.setBlockPtr((int*) readBlockFromLiteralArray("col16block.cdf", block)); + pp.columnScanAndFilter(in, out); + + results = getValuesArrayPosition(getFirstValueArrayPosition(out), 0); + + ASSERT_EQ(out->NVALS, 2); + ASSERT_EQ(results[0], 10); + ASSERT_EQ(results[1], 510); + + EXPECT_EQ(out->Max, __col16block_cdf_umax); + EXPECT_EQ(out->Min, __col16block_cdf_umin); } // vim:ts=2 sw=2: diff --git a/tests/primitives_scan_bench.cpp b/tests/primitives_scan_bench.cpp new file mode 100644 index 000000000..84e6f4716 --- /dev/null +++ b/tests/primitives_scan_bench.cpp @@ -0,0 +1,430 @@ +/* Copyright (C) 2021 MariaDB Corporation + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 of + the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#include +#include +#include + +#include "datatypes/mcs_datatype.h" +#include "stats.h" +#include "primitives/linux-port/primitiveprocessor.h" +#include "col1block.h" +#include "col2block.h" +#include "col4block.h" +#include "col8block.h" +#include "col_float_block.h" +#include "col_double_block.h" +#include "col_neg_float.h" +#include "col_neg_double.h" + +using namespace primitives; +using namespace datatypes; +using namespace std; + +// TODO Use FastOperation() to speed up run loop + +uint8_t* readBlockFromLiteralArray(const std::string& fileName, uint8_t* block) +{ + if (fileName == std::string("col1block.cdf")) + return &__col1block_cdf[0]; + else if (fileName == std::string("col2block.cdf")) + return &__col2block_cdf[0]; + else if (fileName == std::string("col4block.cdf")) + return &__col4block_cdf[0]; + else if (fileName == std::string("col8block.cdf")) + return &___bin_col8block_cdf[0]; + else if (fileName == std::string("col_float_block.cdf")) + return &___bin_col_float_block_cdf[0]; + else if (fileName == std::string("col_double_block.cdf")) + return &___bin_col_double_block_cdf[0]; + else if (fileName == std::string("col_neg_float.cdf")) + return &___bin_col_neg_float_cdf[0]; + else if (fileName == std::string("col_neg_double.cdf")) + return &___bin_col_neg_double_cdf[0]; + + return nullptr; +} + +class FilterBenchFixture : public benchmark::Fixture +{ + public: + PrimitiveProcessor pp; + uint8_t input[BLOCK_SIZE]; + uint8_t output[4 * BLOCK_SIZE]; + uint8_t block[BLOCK_SIZE]; + uint16_t* rids; + uint32_t i; + uint32_t written; + NewColRequestHeader* in; + ColResultHeader* out; + ColArgs* args; + + void SetUp(benchmark::State& state) + { + memset(input, 0, BLOCK_SIZE); + memset(output, 0, 4 * BLOCK_SIZE); + in = reinterpret_cast(input); + out = reinterpret_cast(output); + rids = reinterpret_cast(&in[1]); + args = reinterpret_cast(&in[1]); + } + + // to avoid gcc compile time warning + void SetUp(const benchmark::State& state) + { + SetUp(const_cast(state)); + } + + void inTestRunSetUp(const std::string& dataName, const size_t dataSize, const uint8_t dataType, const uint32_t outputType, ColArgs* args) + { + in->colType = ColRequestHeaderDataType(); + in->colType.DataSize = dataSize; + in->colType.DataType = dataType; + in->OutputType = outputType; + in->NOPS = 0; + in->NVALS = 0; + pp.setBlockPtr((int*) readBlockFromLiteralArray(dataName, block)); + } + void runFilterBenchLegacy() + { + pp.p_Col(in, out, 4 * BLOCK_SIZE, &written); + } + + template + void runFilterBenchTemplated() + { + using IntegralType = typename datatypes::WidthToSIntegralType::type; + pp.columnScanAndFilter(in, out); + } + + template + void setUp1EqFilter() + { + using IntegralType = typename datatypes::WidthToSIntegralType::type; + in->NOPS = 1; + in->NVALS = 0; + IntegralType tmp = 20; + args->COP = COMPARE_EQ; + memcpy(args->val, &tmp, W); + } + +}; + +BENCHMARK_DEFINE_F(FilterBenchFixture, BM_ColumnScan1ByteLegacyCode)(benchmark::State& state) +{ + for (auto _ : state) + { + constexpr const uint8_t W = 1; + state.PauseTiming(); + inTestRunSetUp("col1block.cdf", W, SystemCatalog::CHAR, OT_DATAVALUE, args); + state.ResumeTiming(); + runFilterBenchLegacy(); + } +} + +BENCHMARK_REGISTER_F(FilterBenchFixture, BM_ColumnScan1ByteLegacyCode); + +BENCHMARK_DEFINE_F(FilterBenchFixture, BM_ColumnScan1Byte1FilterLegacyCode)(benchmark::State& state) +{ + for (auto _ : state) + { + state.PauseTiming(); + constexpr const uint8_t W = 1; + setUp1EqFilter(); + inTestRunSetUp("col1block.cdf", W, SystemCatalog::CHAR, OT_DATAVALUE, args); + state.ResumeTiming(); + + runFilterBenchLegacy(); + } +} + +BENCHMARK_REGISTER_F(FilterBenchFixture, BM_ColumnScan1Byte1FilterLegacyCode); + +BENCHMARK_DEFINE_F(FilterBenchFixture, BM_ColumnScan1ByteTemplatedCode)(benchmark::State& state) +{ + for (auto _ : state) + { + constexpr const uint8_t W = 1; + state.PauseTiming(); + inTestRunSetUp("col1block.cdf", W, SystemCatalog::CHAR, OT_DATAVALUE, args); + state.ResumeTiming(); + runFilterBenchTemplated(); + } +} + +BENCHMARK_REGISTER_F(FilterBenchFixture, BM_ColumnScan1ByteTemplatedCode); + +BENCHMARK_DEFINE_F(FilterBenchFixture, BM_ColumnScan1Byte1FilterTemplatedCode)(benchmark::State& state) +{ + for (auto _ : state) + { + state.PauseTiming(); + constexpr const uint8_t W = 1; + setUp1EqFilter(); + inTestRunSetUp("col1block.cdf", W, SystemCatalog::CHAR, OT_DATAVALUE, args); + state.ResumeTiming(); + runFilterBenchTemplated(); + } +} + +BENCHMARK_REGISTER_F(FilterBenchFixture, BM_ColumnScan1Byte1FilterTemplatedCode); + +BENCHMARK_DEFINE_F(FilterBenchFixture, BM_ColumnScan1ByteVectorizedCode)(benchmark::State& state) +{ + for (auto _ : state) + { + constexpr const uint8_t W = 1; + state.PauseTiming(); + inTestRunSetUp("col1block.cdf", W, SystemCatalog::TINYINT, OT_DATAVALUE, args); + state.ResumeTiming(); + runFilterBenchTemplated(); + } +} + +BENCHMARK_REGISTER_F(FilterBenchFixture, BM_ColumnScan1ByteVectorizedCode); + +BENCHMARK_DEFINE_F(FilterBenchFixture, BM_ColumnScan1Byte1FilterVectorizedCode)(benchmark::State& state) +{ + for (auto _ : state) + { + state.PauseTiming(); + constexpr const uint8_t W = 1; + setUp1EqFilter(); + inTestRunSetUp("col1block.cdf", W, SystemCatalog::TINYINT, OT_DATAVALUE, args); + state.ResumeTiming(); + runFilterBenchTemplated(); + } +} + +BENCHMARK_REGISTER_F(FilterBenchFixture, BM_ColumnScan1Byte1FilterVectorizedCode); + +BENCHMARK_DEFINE_F(FilterBenchFixture, BM_ColumnScan2ByteLegacyCode)(benchmark::State& state) +{ + for (auto _ : state) + { + constexpr const uint8_t W = 2; + state.PauseTiming(); + inTestRunSetUp("col2block.cdf", W, SystemCatalog::INT, OT_DATAVALUE, args); + state.ResumeTiming(); + runFilterBenchLegacy(); + } +} +BENCHMARK_REGISTER_F(FilterBenchFixture, BM_ColumnScan2ByteLegacyCode); + +BENCHMARK_DEFINE_F(FilterBenchFixture, BM_ColumnScan2Byte1FilterLegacyCode)(benchmark::State& state) +{ + for (auto _ : state) + { + state.PauseTiming(); + constexpr const uint8_t W = 2; + setUp1EqFilter(); + inTestRunSetUp("col2block.cdf", W, SystemCatalog::INT, OT_DATAVALUE, args); + state.ResumeTiming(); + runFilterBenchLegacy(); + } +} +BENCHMARK_REGISTER_F(FilterBenchFixture, BM_ColumnScan2Byte1FilterLegacyCode); + +BENCHMARK_DEFINE_F(FilterBenchFixture, BM_ColumnScan2ByteTemplatedCode)(benchmark::State& state) +{ + for (auto _ : state) + { + constexpr const uint8_t W = 2; + state.PauseTiming(); + inTestRunSetUp("col2block.cdf", W, SystemCatalog::INT, OT_DATAVALUE, args); + state.ResumeTiming(); + runFilterBenchTemplated(); + } +} + +BENCHMARK_REGISTER_F(FilterBenchFixture, BM_ColumnScan2ByteTemplatedCode); + +BENCHMARK_DEFINE_F(FilterBenchFixture, BM_ColumnScan2Byte1FilterTemplatedCode)(benchmark::State& state) +{ + for (auto _ : state) + { + state.PauseTiming(); + constexpr const uint8_t W = 2; + setUp1EqFilter(); + inTestRunSetUp("col2block.cdf", W, SystemCatalog::INT, OT_DATAVALUE, args); + state.ResumeTiming(); + runFilterBenchTemplated(); + } +} + +BENCHMARK_REGISTER_F(FilterBenchFixture, BM_ColumnScan2Byte1FilterTemplatedCode); + +BENCHMARK_DEFINE_F(FilterBenchFixture, BM_ColumnScan2Byte1FilterVectorizedCode)(benchmark::State& state) +{ + for (auto _ : state) + { + state.PauseTiming(); + constexpr const uint8_t W = 2; + setUp1EqFilter(); + inTestRunSetUp("col2block.cdf", W, SystemCatalog::TINYINT, OT_DATAVALUE, args); + state.ResumeTiming(); + runFilterBenchTemplated(); + } +} + +BENCHMARK_REGISTER_F(FilterBenchFixture, BM_ColumnScan2Byte1FilterVectorizedCode); + +BENCHMARK_DEFINE_F(FilterBenchFixture, BM_ColumnScan4ByteLegacyCode)(benchmark::State& state) +{ + for (auto _ : state) + { + constexpr const uint8_t W = 4; + state.PauseTiming(); + inTestRunSetUp("col4block.cdf", W, SystemCatalog::INT, OT_DATAVALUE, args); + state.ResumeTiming(); + runFilterBenchLegacy(); + } +} + +BENCHMARK_REGISTER_F(FilterBenchFixture, BM_ColumnScan4ByteLegacyCode); + +BENCHMARK_DEFINE_F(FilterBenchFixture, BM_ColumnScan4Byte1FilterLegacyCode)(benchmark::State& state) +{ + for (auto _ : state) + { + constexpr const uint8_t W = 4; + state.PauseTiming(); + setUp1EqFilter(); + inTestRunSetUp("col4block.cdf", W, SystemCatalog::INT, OT_DATAVALUE, args); + state.ResumeTiming(); + runFilterBenchLegacy(); + } +} + +BENCHMARK_REGISTER_F(FilterBenchFixture, BM_ColumnScan4Byte1FilterLegacyCode); + +BENCHMARK_DEFINE_F(FilterBenchFixture, BM_ColumnScan4ByteTemplatedCode)(benchmark::State& state) +{ + for (auto _ : state) + { + state.PauseTiming(); + constexpr const uint8_t W = 4; + inTestRunSetUp("col4block.cdf", W, SystemCatalog::INT, OT_DATAVALUE, args); + state.ResumeTiming(); + runFilterBenchTemplated(); + } +} + +BENCHMARK_REGISTER_F(FilterBenchFixture, BM_ColumnScan4ByteTemplatedCode); + +BENCHMARK_DEFINE_F(FilterBenchFixture, BM_ColumnScan4ByteVectorizedCode)(benchmark::State& state) +{ + for (auto _ : state) + { + state.PauseTiming(); + constexpr const uint8_t W = 4; + setUp1EqFilter(); + inTestRunSetUp("col4block.cdf", W, SystemCatalog::TINYINT, OT_DATAVALUE, args); + state.ResumeTiming(); + runFilterBenchTemplated(); + } +} + +BENCHMARK_REGISTER_F(FilterBenchFixture, BM_ColumnScan4ByteVectorizedCode); + +BENCHMARK_DEFINE_F(FilterBenchFixture, BM_ColumnScan8ByteLegacyCode)(benchmark::State& state) +{ + for (auto _ : state) + { + constexpr const uint8_t W = 8; + state.PauseTiming(); + inTestRunSetUp("col8block.cdf", W, SystemCatalog::INT, OT_DATAVALUE, args); + state.ResumeTiming(); + runFilterBenchLegacy(); + } +} +BENCHMARK_REGISTER_F(FilterBenchFixture, BM_ColumnScan8ByteLegacyCode); + +BENCHMARK_DEFINE_F(FilterBenchFixture, BM_ColumnScan8Byte1FilterLegacyCode)(benchmark::State& state) +{ + for (auto _ : state) + { + state.PauseTiming(); + constexpr const uint8_t W = 8; + setUp1EqFilter(); + inTestRunSetUp("col8block.cdf", W, SystemCatalog::INT, OT_DATAVALUE, args); + state.ResumeTiming(); + runFilterBenchLegacy(); + } +} +BENCHMARK_REGISTER_F(FilterBenchFixture, BM_ColumnScan8Byte1FilterLegacyCode); + +BENCHMARK_DEFINE_F(FilterBenchFixture, BM_ColumnScan8ByteTemplatedCode)(benchmark::State& state) +{ + for (auto _ : state) + { + constexpr const uint8_t W = 8; + state.PauseTiming(); + inTestRunSetUp("col8block.cdf", W, SystemCatalog::INT, OT_DATAVALUE, args); + state.ResumeTiming(); + runFilterBenchTemplated(); + } +} + +BENCHMARK_REGISTER_F(FilterBenchFixture, BM_ColumnScan8ByteTemplatedCode); + +BENCHMARK_DEFINE_F(FilterBenchFixture, BM_ColumnScan8Byte1FilterTemplatedCode)(benchmark::State& state) +{ + for (auto _ : state) + { + constexpr const uint8_t W = 8; + state.PauseTiming(); + setUp1EqFilter(); + inTestRunSetUp("col8block.cdf", W, SystemCatalog::INT, OT_DATAVALUE, args); + state.ResumeTiming(); + runFilterBenchTemplated(); + } +} + +BENCHMARK_REGISTER_F(FilterBenchFixture, BM_ColumnScan8Byte1FilterTemplatedCode); + +BENCHMARK_DEFINE_F(FilterBenchFixture, BM_ColumnScan8ByteVectorizedCode)(benchmark::State& state) +{ + for (auto _ : state) + { + constexpr const uint8_t W = 8; + state.PauseTiming(); + inTestRunSetUp("col8block.cdf", W, SystemCatalog::TINYINT, OT_DATAVALUE, args); + state.ResumeTiming(); + runFilterBenchTemplated(); + } +} + +BENCHMARK_REGISTER_F(FilterBenchFixture, BM_ColumnScan8ByteVectorizedCode); + +BENCHMARK_DEFINE_F(FilterBenchFixture, BM_ColumnScan8Byte1FilterVectorizedCode)(benchmark::State& state) +{ + for (auto _ : state) + { + constexpr const uint8_t W = 8; + state.PauseTiming(); + setUp1EqFilter(); + inTestRunSetUp("col8block.cdf", W, SystemCatalog::TINYINT, OT_DATAVALUE, args); + state.ResumeTiming(); + runFilterBenchTemplated(); + } +} + +BENCHMARK_REGISTER_F(FilterBenchFixture, BM_ColumnScan8Byte1FilterVectorizedCode); + +BENCHMARK_MAIN(); +// vim:ts=2 sw=2: diff --git a/utils/common/simd_sse.h b/utils/common/simd_sse.h new file mode 100644 index 000000000..494deaa2e --- /dev/null +++ b/utils/common/simd_sse.h @@ -0,0 +1,473 @@ +/* Copyright (C) 2021 Mariadb Corporation. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; version 2 of + the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + MA 02110-1301, USA. */ + +#ifndef UTILS_SIMD_SSE_H +#define UTILS_SIMD_SSE_H + +#if defined(__x86_64__ ) + +#include +#include + +#ifdef __OPTIMIZE__ + #include + #include + #define MCS_FORCE_INLINE __attribute__((__always_inline__)) +#else + #define __OPTIMIZE__ + #include + #include + #undef __OPTIMIZE__ + #define MCS_FORCE_INLINE inline +#endif + +#include + +namespace simd +{ + using vi128_t = __m128i; + using msk128_t = uint16_t; + using int128_t = __int128; + using MT = uint16_t; + // This ugly wrapper used to allow to use __m128i as a template class parameter argument + struct vi128_wr + { + __m128i v; + }; + + template + class SimdFilterProcessor + { }; + + template<> + class SimdFilterProcessor + { + // This is a dummy class that is not currently used. + public: + constexpr static const uint16_t vecByteSize = 16U; + constexpr static const uint16_t vecBitSize = 128U; + using T = int128_t; + using SIMD_WRAPPER_TYPE = simd::vi128_wr; + using SIMD_TYPE = simd::vi128_t; + // Load value + MCS_FORCE_INLINE vi128_t loadValue(const T fill) + { + return _mm_loadu_si128(reinterpret_cast(&fill)); + } + + // Load from + MCS_FORCE_INLINE vi128_t loadFrom(const char* from) + { + return _mm_loadu_si128(reinterpret_cast(from)); + } + + MCS_FORCE_INLINE MT cmpDummy(vi128_t& x, vi128_t& y) + { + return 0xFFFF; + } + // Compare + MCS_FORCE_INLINE MT cmpEq(vi128_t& x, vi128_t& y) + { + return cmpDummy(x, y); + } + + MCS_FORCE_INLINE MT cmpGe(vi128_t& x, vi128_t& y) + { + return cmpDummy(x, y); + } + + MCS_FORCE_INLINE MT cmpGt(vi128_t& x, vi128_t& y) + { + return cmpDummy(x, y); + } + + MCS_FORCE_INLINE MT cmpLt(vi128_t& x, vi128_t& y) + { + return cmpDummy(x, y); + } + + MCS_FORCE_INLINE MT cmpLe(vi128_t& x, vi128_t& y) + { + return cmpDummy(x, y); + } + + MCS_FORCE_INLINE MT cmpNe(vi128_t& x, vi128_t& y) + { + return cmpDummy(x, y); + } + + MCS_FORCE_INLINE MT cmpAlwaysFalse(vi128_t& x, vi128_t& y) + { + return 0; + } + + // misc + MCS_FORCE_INLINE uint16_t convertVectorToBitMask(vi128_t& vmask) + { + return _mm_movemask_epi8(vmask); + } + + MCS_FORCE_INLINE vi128_t setToZero() + { + return _mm_setzero_si128(); + } + + // store + MCS_FORCE_INLINE void storeWMask(vi128_t& x, vi128_t& vmask, char* dst) + { + _mm_maskmoveu_si128(x, vmask, dst); + } + + MCS_FORCE_INLINE void store(char* dst, vi128_t& x) + { + _mm_storeu_si128(reinterpret_cast(dst), x); + } + }; + + template<> + class SimdFilterProcessor + { + public: + constexpr static const uint16_t vecByteSize = 16U; + constexpr static const uint16_t vecBitSize = 128U; + using T = datatypes::WidthToSIntegralType<8>::type; + using SIMD_WRAPPER_TYPE = simd::vi128_wr; + using SIMD_TYPE = simd::vi128_t; + // Load value + MCS_FORCE_INLINE vi128_t loadValue(const T fill) + { + return _mm_set_epi64x(fill, fill); + } + + // Load from + MCS_FORCE_INLINE vi128_t loadFrom(const char* from) + { + return _mm_loadu_si128(reinterpret_cast(from)); + } + + // Compare + MCS_FORCE_INLINE MT cmpGe(vi128_t& x, vi128_t& y) + { + return _mm_movemask_epi8(_mm_or_si128(_mm_cmpgt_epi64(x, y),_mm_cmpeq_epi64(x, y))); + } + + MCS_FORCE_INLINE MT cmpGt(vi128_t& x, vi128_t& y) + { + return _mm_movemask_epi8(_mm_cmpgt_epi64(x, y)); + } + + MCS_FORCE_INLINE MT cmpEq(vi128_t& x, vi128_t& y) + { + return _mm_movemask_epi8(_mm_cmpeq_epi64(x, y)); + } + + MCS_FORCE_INLINE MT cmpLe(vi128_t& x, vi128_t& y) + { + return cmpGt(x, y) ^ 0xFFFF; + } + + MCS_FORCE_INLINE MT cmpLt(vi128_t& x, vi128_t& y) + { + return cmpNe(x, y) ^ cmpGt(x, y); + } + + MCS_FORCE_INLINE MT cmpNe(vi128_t& x, vi128_t& y) + { + return _mm_movemask_epi8(_mm_cmpeq_epi64(x, y)) ^ 0xFFFF; + } + + MCS_FORCE_INLINE MT cmpAlwaysFalse(vi128_t& x, vi128_t& y) + { + return 0; + } + + // misc + MCS_FORCE_INLINE MT convertVectorToBitMask(vi128_t& vmask) + { + return _mm_movemask_epi8(vmask); + } + + MCS_FORCE_INLINE vi128_t setToZero() + { + return _mm_setzero_si128(); + } + + // store + MCS_FORCE_INLINE void storeWMask(vi128_t& x, vi128_t& vmask, char* dst) + { + _mm_maskmoveu_si128(x, vmask, dst); + } + + MCS_FORCE_INLINE void store(char* dst, vi128_t& x) + { + _mm_storeu_si128(reinterpret_cast(dst), x); + } + }; + + template<> + class SimdFilterProcessor + { + public: + constexpr static const uint16_t vecByteSize = 16U; + constexpr static const uint16_t vecBitSize = 128U; + using T = datatypes::WidthToSIntegralType<4>::type; + using SIMD_WRAPPER_TYPE = simd::vi128_wr; + using SIMD_TYPE = simd::vi128_t; + // Load value + MCS_FORCE_INLINE vi128_t loadValue(const T fill) + { + return _mm_set1_epi32(fill); + } + + // Load from + MCS_FORCE_INLINE vi128_t loadFrom(const char* from) + { + return _mm_loadu_si128(reinterpret_cast(from)); + } + + // Compare + MCS_FORCE_INLINE MT cmpEq(vi128_t& x, vi128_t& y) + { + return _mm_movemask_epi8(_mm_cmpeq_epi32(x, y)); + } + + MCS_FORCE_INLINE MT cmpGe(vi128_t& x, vi128_t& y) + { + return cmpLt(x, y) ^ 0xFFFF; + } + + MCS_FORCE_INLINE MT cmpGt(vi128_t& x, vi128_t& y) + { + return _mm_movemask_epi8(_mm_cmpgt_epi32(x, y)); + } + + MCS_FORCE_INLINE MT cmpLe(vi128_t& x, vi128_t& y) + { + return cmpGt(x, y) ^ 0xFFFF; + } + + MCS_FORCE_INLINE MT cmpLt(vi128_t& x, vi128_t& y) + { + return _mm_movemask_epi8(_mm_cmplt_epi32(x, y)); + } + + MCS_FORCE_INLINE MT cmpNe(vi128_t& x, vi128_t& y) + { + return _mm_movemask_epi8(_mm_cmpeq_epi32(x, y)) ^ 0xFFFF; + } + + MCS_FORCE_INLINE MT cmpAlwaysFalse(vi128_t& x, vi128_t& y) + { + return 0; + } + + // misc + MCS_FORCE_INLINE MT convertVectorToBitMask(vi128_t& vmask) + { + return _mm_movemask_epi8(vmask); + } + + MCS_FORCE_INLINE vi128_t setToZero() + { + return _mm_setzero_si128(); + } + + // store + MCS_FORCE_INLINE void storeWMask(vi128_t& x, vi128_t& vmask, char* dst) + { + _mm_maskmoveu_si128(x, vmask, dst); + } + + MCS_FORCE_INLINE void store(char* dst, vi128_t& x) + { + _mm_storeu_si128(reinterpret_cast(dst), x); + } + }; + + template<> + class SimdFilterProcessor + { + public: + constexpr static const uint16_t vecByteSize = 16U; + constexpr static const uint16_t vecBitSize = 128U; + using T = datatypes::WidthToSIntegralType<2>::type; + using SIMD_WRAPPER_TYPE = simd::vi128_wr; + using SIMD_TYPE = simd::vi128_t; + // Load value + MCS_FORCE_INLINE vi128_t loadValue(const T fill) + { + return _mm_set1_epi16(fill); + } + + // Load from + MCS_FORCE_INLINE vi128_t loadFrom(const char* from) + { + return _mm_loadu_si128(reinterpret_cast(from)); + } + + // Compare + MCS_FORCE_INLINE MT cmpEq(vi128_t& x, vi128_t& y) + { + return _mm_movemask_epi8(_mm_cmpeq_epi16(x, y)); + } + + MCS_FORCE_INLINE MT cmpGe(vi128_t& x, vi128_t& y) + { + return cmpLt(x, y) ^ 0xFFFF; + } + + MCS_FORCE_INLINE MT cmpGt(vi128_t& x, vi128_t& y) + { + return _mm_movemask_epi8(_mm_cmpgt_epi16(x, y)); + } + + MCS_FORCE_INLINE MT cmpLe(vi128_t& x, vi128_t& y) + { + return cmpGt(x, y) ^ 0xFFFF; + } + + MCS_FORCE_INLINE MT cmpLt(vi128_t& x, vi128_t& y) + { + return _mm_movemask_epi8(_mm_cmplt_epi16(x, y)); + } + + MCS_FORCE_INLINE MT cmpNe(vi128_t& x, vi128_t& y) + { + return _mm_movemask_epi8(_mm_cmpeq_epi16(x, y)) ^ 0xFFFF; + } + + MCS_FORCE_INLINE MT cmpAlwaysFalse(vi128_t& x, vi128_t& y) + { + return 0; + } + + // misc + MCS_FORCE_INLINE MT convertVectorToBitMask(vi128_t& vmask) + { + return _mm_movemask_epi8(vmask); + } + + MCS_FORCE_INLINE vi128_t setToZero() + { + return _mm_setzero_si128(); + } + + // store + MCS_FORCE_INLINE void storeWMask(vi128_t& x, vi128_t& vmask, char* dst) + { + _mm_maskmoveu_si128(x, vmask, dst); + } + + MCS_FORCE_INLINE void store(char* dst, vi128_t& x) + { + _mm_storeu_si128(reinterpret_cast(dst), x); + } + }; + + template<> + class SimdFilterProcessor + { + public: + constexpr static const uint16_t vecByteSize = 16U; + constexpr static const uint16_t vecBitSize = 128U; + using T = datatypes::WidthToSIntegralType<1>::type; + using SIMD_WRAPPER_TYPE = simd::vi128_wr; + using SIMD_TYPE = simd::vi128_t; + // Load value + MCS_FORCE_INLINE vi128_t loadValue(const T fill) + { + return _mm_set1_epi8(fill); + } + + // Load from + MCS_FORCE_INLINE vi128_t loadFrom(const char* from) + { + return _mm_loadu_si128(reinterpret_cast(from)); + } + + // Compare + MCS_FORCE_INLINE MT cmpEq(vi128_t& x, vi128_t& y) + { + return _mm_movemask_epi8(_mm_cmpeq_epi8(x, y)); + } + + MCS_FORCE_INLINE MT cmpGe(vi128_t& x, vi128_t& y) + { + return cmpLt(x, y) ^ 0xFFFF; + } + + MCS_FORCE_INLINE MT cmpGt(vi128_t& x, vi128_t& y) + { + return _mm_movemask_epi8(_mm_cmpgt_epi8(x, y)); + } + + MCS_FORCE_INLINE MT cmpLe(vi128_t& x, vi128_t& y) + { + return cmpGt(x, y) ^ 0xFFFF; + } + + MCS_FORCE_INLINE MT cmpLt(vi128_t& x, vi128_t& y) + { + return _mm_movemask_epi8(_mm_cmplt_epi8(x, y)); + } + + MCS_FORCE_INLINE MT cmpNe(vi128_t& x, vi128_t& y) + { + return _mm_movemask_epi8(_mm_cmpeq_epi8(x, y)) ^ 0xFFFF; + } + + MCS_FORCE_INLINE MT cmpAlwaysFalse(vi128_t& x, vi128_t& y) + { + return 0; + } + + // permute +/* TODO Available in AVX-512 + MCS_FORCE_INLINE vi128_t perm8Bits(vi128_t& x, vi128_t& idx) + { + return _mm_permutexvar_epi8(x, idx); + } +*/ + // misc + MCS_FORCE_INLINE MT convertVectorToBitMask(vi128_t& vmask) + { + return _mm_movemask_epi8(vmask); + } + + MCS_FORCE_INLINE vi128_t setToZero() + { + return _mm_setzero_si128(); + } + + // store + MCS_FORCE_INLINE void storeWMask(vi128_t& x, vi128_t& vmask, char* dst) + { + _mm_maskmoveu_si128(x, vmask, dst); + } + + MCS_FORCE_INLINE void store(char* dst, vi128_t& x) + { + _mm_storeu_si128(reinterpret_cast(dst), x); + } + }; + +} // end of simd + +#endif // if defined(__x86_64__ ) + +#endif +// vim:ts=2 sw=2: diff --git a/writeengine/server/we_dmlcommandproc.cpp b/writeengine/server/we_dmlcommandproc.cpp index ede2747d3..fcbe80759 100644 --- a/writeengine/server/we_dmlcommandproc.cpp +++ b/writeengine/server/we_dmlcommandproc.cpp @@ -1287,7 +1287,6 @@ uint8_t WE_DMLCommandProc::processBatchInsert(messageqcpp::ByteStream& bs, std:: // call the write engine to write the rows int error = NO_ERROR; - //fWriteEngine.setDebugLevel(WriteEngine::DEBUG_3); if (colValuesList.size() > 0) { if (colValuesList[0].size() > 0) diff --git a/writeengine/shared/we_dbfileop.cpp b/writeengine/shared/we_dbfileop.cpp index aa909f8ae..bfc7107f0 100644 --- a/writeengine/shared/we_dbfileop.cpp +++ b/writeengine/shared/we_dbfileop.cpp @@ -283,7 +283,6 @@ int DbFileOp::writeDBFile( CommBlock& cb, const unsigned char* writeBuf, { CacheKey key; int ret; - if ( Cache::getUseCache() ) { if ( Cache::cacheKeyExist( cb.file.oid, lbid ) ) diff --git a/writeengine/shared/we_type.h b/writeengine/shared/we_type.h index 40d9a828e..e1f5eaf7a 100644 --- a/writeengine/shared/we_type.h +++ b/writeengine/shared/we_type.h @@ -1,4 +1,5 @@ /* Copyright (C) 2014 InfiniDB, Inc. + Copyright (C) 2016-2021 MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/writeengine/shared/we_typeext.h b/writeengine/shared/we_typeext.h index 91c95f0c1..59e69e266 100644 --- a/writeengine/shared/we_typeext.h +++ b/writeengine/shared/we_typeext.h @@ -1,4 +1,5 @@ /* Copyright (C) 2014 InfiniDB, Inc. + Copyright (C) 2016-2021 MariaDB Corporation This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License diff --git a/writeengine/wrapper/writeengine.cpp b/writeengine/wrapper/writeengine.cpp index b15233b72..f5c9c431e 100644 --- a/writeengine/wrapper/writeengine.cpp +++ b/writeengine/wrapper/writeengine.cpp @@ -26,6 +26,7 @@ #include #include #include +#include using namespace std; #include "joblisttypes.h" @@ -70,6 +71,7 @@ namespace WriteEngine { StopWatch timer; +using OidToIdxMap = std::unordered_map; /**@brief WriteEngineWrapper Constructor */ @@ -1323,7 +1325,7 @@ int WriteEngineWrapper::insertColumnRecs(const TxnID& txnid, // debug information for testing if (isDebug(DEBUG_2)) { - printInputValue(colStructList, colValueList, ridList); + printInputValue(colStructList, colValueList, ridList, dctnryStructList, dictStrList); } // end @@ -2869,7 +2871,7 @@ int WriteEngineWrapper::insertColumnRec_SYS(const TxnID& txnid, // debug information for testing if (isDebug(DEBUG_2)) { - printInputValue(colStructList, colValueList, ridList); + printInputValue(colStructList, colValueList, ridList, dctnryStructList, dictStrList); } // end @@ -3531,7 +3533,7 @@ int WriteEngineWrapper::insertColumnRec_Single(const TxnID& txnid, // debug information for testing if (isDebug(DEBUG_2)) { - printInputValue(colStructList, colValueList, ridList); + printInputValue(colStructList, colValueList, ridList, dctnryStructList, dictStrList); } //Convert data type and column width to write engine specific @@ -4188,35 +4190,41 @@ int WriteEngineWrapper::insertColumnRec_Single(const TxnID& txnid, ***********************************************************/ void WriteEngineWrapper::printInputValue(const ColStructList& colStructList, const ColValueList& colValueList, - const RIDList& ridList) const + const RIDList& ridList, + const DctnryStructList& dctnryStructList, + const DictStrList& dictStrList) const { ColTupleList curTupleList; ColStruct curColStruct; ColTuple curTuple; string curStr; ColStructList::size_type i; - ColTupleList::size_type j; + size_t j; + OidToIdxMap oidToIdxMap; - printf("\n=========================\n"); -// printf("\nTable OID : %d \n", tableOid); + std::cerr << std::endl << "=========================" << std::endl; - printf("\nTotal RIDs: %zu\n", ridList.size()); + std::cerr << "Total RIDs: " << ridList.size() << std::endl; for (i = 0; i < ridList.size(); i++) - cout << "RID[" << i << "] : " << ridList[i] << "\n"; - - printf("\nTotal Columns: %zu\n", colStructList.size()); + std::cerr << "RID[" << i << "] : " << ridList[i] << std::endl; + std::cerr << "Total Columns: " << colStructList.size() << std::endl; for (i = 0; i < colStructList.size(); i++) { curColStruct = colStructList[i]; curTupleList = colValueList[i]; + if (curColStruct.tokenFlag) + { + oidToIdxMap.insert({curColStruct.dataOid, i}); + continue; + } - printf("\nColumn[%zu]", i); - printf("\nData file OID : %d \t", curColStruct.dataOid); - printf("\tWidth : %d \t Type: %d", curColStruct.colWidth, curColStruct.colDataType); - printf("\nTotal values : %zu \n", curTupleList.size()); + std::cerr << "Column[" << i << "]"; + std::cerr << "Data file OID : " << curColStruct.dataOid << "\t"; + std::cerr << "Width : " << curColStruct.colWidth << "\t" << " Type: " << curColStruct.colDataType << std::endl; + std::cerr << "Total values : " << curTupleList.size() << std::endl; for (j = 0; j < curTupleList.size(); j++) { @@ -4226,19 +4234,22 @@ void WriteEngineWrapper::printInputValue(const ColStructList& colStructList, { if (curTuple.data.type() == typeid(int)) curStr = boost::lexical_cast(boost::any_cast(curTuple.data)); + else if (curTuple.data.type() == typeid(unsigned int)) + curStr = boost::lexical_cast(boost::any_cast(curTuple.data)); else if (curTuple.data.type() == typeid(float)) curStr = boost::lexical_cast(boost::any_cast(curTuple.data)); else if (curTuple.data.type() == typeid(long long)) curStr = boost::lexical_cast(boost::any_cast(curTuple.data)); + else if (curTuple.data.type() == typeid(unsigned long long)) + curStr = boost::lexical_cast(boost::any_cast(curTuple.data)); else if (curTuple.data.type() == typeid(int128_t)) - { - datatypes::TSInt128 val(boost::any_cast(curTuple.data)); - curStr = val.toString(); - } + curStr = datatypes::TSInt128(boost::any_cast(curTuple.data)).toString(); else if (curTuple.data.type() == typeid(double)) curStr = boost::lexical_cast(boost::any_cast(curTuple.data)); else if (curTuple.data.type() == typeid(short)) curStr = boost::lexical_cast(boost::any_cast(curTuple.data)); + else if (curTuple.data.type() == typeid(unsigned short)) + curStr = boost::lexical_cast(boost::any_cast(curTuple.data)); else if (curTuple.data.type() == typeid(char)) curStr = boost::lexical_cast(boost::any_cast(curTuple.data)); else @@ -4249,12 +4260,36 @@ void WriteEngineWrapper::printInputValue(const ColStructList& colStructList, } if (isDebug(DEBUG_3)) - printf("Value[%zu] : %s\n", j, curStr.c_str()); + std::cerr << "Value[" << j << "]: " << curStr.c_str() << std::endl; + } + } + for (i = 0; i < dctnryStructList.size(); ++i) + { + if (dctnryStructList[i].dctnryOid == 0) + continue; + std::cerr << "Dict[" << i << "]"; + std::cerr << " file OID : " << dctnryStructList[i].dctnryOid << " Token file OID: " << dctnryStructList[i].columnOid << "\t"; + std::cerr << "Width : " << dctnryStructList[i].colWidth << "\t" << " Type: " << dctnryStructList[i].fCompressionType << std::endl; + std::cerr << "Total values : " << dictStrList.size() << std::endl; + if (isDebug(DEBUG_3)) + { + for (j = 0; j < dictStrList[i].size(); ++j) + { + // We presume there will be a value. + auto tokenOidIdx = oidToIdxMap[dctnryStructList[i].columnOid]; + std::cerr << "string [" << dictStrList[i][j] << "]" << std::endl; + bool isToken = colStructList[tokenOidIdx].colType == WriteEngine::WR_TOKEN && + colStructList[tokenOidIdx].tokenFlag; + if (isToken && !colValueList[tokenOidIdx][j].data.empty()) + { + Token t = boost::any_cast(colValueList[tokenOidIdx][j].data); + std::cerr << "Token: block pos:[" << t.op << "] fbo: [" << t.fbo << "] bc: [" << t.bc << "]" << std::endl; + } + } } - } - printf("\n=========================\n"); + std::cerr << "=========================" << std::endl; } /*********************************************************** @@ -6046,7 +6081,6 @@ int WriteEngineWrapper::tokenize(const TxnID& txnid, DctnryTuple& dctnryTuple, i { int cop = op(ct); m_dctnry[cop]->setTransId(txnid); - //cout << "Tokenizing dctnryTuple.sigValue " << dctnryTuple.sigValue << endl; return m_dctnry[cop]->updateDctnry(dctnryTuple.sigValue, dctnryTuple.sigSize, dctnryTuple.token); } diff --git a/writeengine/wrapper/writeengine.h b/writeengine/wrapper/writeengine.h index 5423a7361..a3f9634fc 100644 --- a/writeengine/wrapper/writeengine.h +++ b/writeengine/wrapper/writeengine.h @@ -716,7 +716,7 @@ private: /** * @brief Print input value from DDL/DML processors */ - void printInputValue(const ColStructList& colStructList, const ColValueList& colValueList, const RIDList& ridList) const; + void printInputValue(const ColStructList& colStructList, const ColValueList& colValueList, const RIDList& ridList, const DctnryStructList& dctnryStructList, const DictStrList& dictStrList) const; /** * @brief Process version buffer @@ -826,7 +826,6 @@ private: ColumnOp* m_colOp[TOTAL_COMPRESS_OP]; // column operations Dctnry* m_dctnry[TOTAL_COMPRESS_OP]; // dictionary operations OpType m_opType; // operation type - DebugLevel m_debugLevel; // debug level }; } //end of namespace