From c1151585e595af768dbb556d3e7fd475d484cfed Mon Sep 17 00:00:00 2001 From: cheqi Date: Thu, 18 Oct 2018 20:21:57 +0800 Subject: [PATCH] add unit test --- .gitignore | 3 + AnnService/Aggregator.vcxproj | 5 +- AnnService/Client.vcxproj | 4 +- AnnService/CoreLibrary.vcxproj | 6 +- AnnService/IndexBuilder.vcxproj | 5 +- AnnService/Server.vcxproj | 4 +- AnnService/SocketLib.vcxproj | 4 +- AnnService/inc/Core/BKT/Dataset.h | 6 +- AnnService/inc/Core/BKT/DistanceUtils.h | 284 +++++++++++------------- AnnService/inc/Core/Common.h | 2 +- AnnService/src/Core/VectorIndex.cpp | 2 +- PythonWrapper/PythonClient.vcxproj | 5 +- PythonWrapper/PythonCore.vcxproj | 7 +- SPTAG.sdf | Bin 0 -> 65536 bytes SPTAG.sln | 10 + Test/Test.vcxproj | 146 ++++++++++++ Test/Test.vcxproj.filters | 33 +++ Test/Test.vcxproj.user | 4 + Test/inc/BKTTest.h | 30 +++ Test/inc/DistanceTest.h | 59 +++++ Test/inc/Test.h | 4 + Test/src/BKTTest.cpp | 25 +++ Test/src/DistanceTest.cpp | 61 +++++ Test/src/main.cpp | 38 ++++ 24 files changed, 571 insertions(+), 176 deletions(-) create mode 100644 SPTAG.sdf create mode 100644 Test/Test.vcxproj create mode 100644 Test/Test.vcxproj.filters create mode 100644 Test/Test.vcxproj.user create mode 100644 Test/inc/BKTTest.h create mode 100644 Test/inc/DistanceTest.h create mode 100644 Test/inc/Test.h create mode 100644 Test/src/BKTTest.cpp create mode 100644 Test/src/DistanceTest.cpp create mode 100644 Test/src/main.cpp diff --git a/.gitignore b/.gitignore index 25b69ed9..9d205a89 100644 --- a/.gitignore +++ b/.gitignore @@ -67,3 +67,6 @@ dkms.conf /PythonWrapper/inc/CoreInterface_wrap.cxx /PythonWrapper/inc/SPTAG.py /PythonWrapper/inc/SPTAGClient.py +/ipch/TEST-4fb66b42 +/obj/x64_Debug +/x64/Debug diff --git a/AnnService/Aggregator.vcxproj b/AnnService/Aggregator.vcxproj index 322c6283..f21fe3a0 100644 --- a/AnnService/Aggregator.vcxproj +++ b/AnnService/Aggregator.vcxproj @@ -29,13 +29,13 @@ Application true - v141 + v140 MultiByte Application false - v141 + v140 true MultiByte @@ -82,6 +82,7 @@ Disabled true true + _MBCS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) CoreLibrary.lib;SocketLib.lib;%(AdditionalDependencies) diff --git a/AnnService/Client.vcxproj b/AnnService/Client.vcxproj index ae84d410..a8c603e2 100644 --- a/AnnService/Client.vcxproj +++ b/AnnService/Client.vcxproj @@ -29,13 +29,13 @@ Application true - v141 + v140 MultiByte Application false - v141 + v140 true MultiByte diff --git a/AnnService/CoreLibrary.vcxproj b/AnnService/CoreLibrary.vcxproj index 7dc47afe..73811fa3 100644 --- a/AnnService/CoreLibrary.vcxproj +++ b/AnnService/CoreLibrary.vcxproj @@ -30,13 +30,13 @@ Application true - v141 + v140 MultiByte Application false - v141 + v140 true MultiByte @@ -95,6 +95,7 @@ true true /Zc:twoPhase- %(AdditionalOptions) + _MBCS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) @@ -122,6 +123,7 @@ true true /Zc:twoPhase- %(AdditionalOptions) + _MBCS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) true diff --git a/AnnService/IndexBuilder.vcxproj b/AnnService/IndexBuilder.vcxproj index fe3009c3..175ece74 100644 --- a/AnnService/IndexBuilder.vcxproj +++ b/AnnService/IndexBuilder.vcxproj @@ -29,13 +29,13 @@ Application true - v141 + v140 MultiByte Application false - v141 + v140 true MultiByte @@ -108,6 +108,7 @@ Disabled true true + _MBCS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) diff --git a/AnnService/Server.vcxproj b/AnnService/Server.vcxproj index 7fa2d627..f57ebb2b 100644 --- a/AnnService/Server.vcxproj +++ b/AnnService/Server.vcxproj @@ -29,13 +29,13 @@ Application true - v141 + v140 MultiByte Application false - v141 + v140 true MultiByte diff --git a/AnnService/SocketLib.vcxproj b/AnnService/SocketLib.vcxproj index e7c3eb9e..98dc3ba8 100644 --- a/AnnService/SocketLib.vcxproj +++ b/AnnService/SocketLib.vcxproj @@ -28,13 +28,13 @@ StaticLibrary true - v141 + v140 MultiByte StaticLibrary false - v141 + v140 true MultiByte diff --git a/AnnService/inc/Core/BKT/Dataset.h b/AnnService/inc/Core/BKT/Dataset.h index 8cda00ac..6e4ada70 100644 --- a/AnnService/inc/Core/BKT/Dataset.h +++ b/AnnService/inc/Core/BKT/Dataset.h @@ -133,8 +133,10 @@ namespace SPTAG { if (cache != nullptr) delete cache; if (ownData) aligned_free(data); - dataIncremental->clear(); - delete dataIncremental; + if (dataIncremental) { + dataIncremental->clear(); + delete dataIncremental; + } } void Initialize(int rows_, int cols_, T* data_ = nullptr, const char * filename_ = nullptr, int cachesize_ = 0) { diff --git a/AnnService/inc/Core/BKT/DistanceUtils.h b/AnnService/inc/Core/BKT/DistanceUtils.h index ea86cbfe..766009ee 100644 --- a/AnnService/inc/Core/BKT/DistanceUtils.h +++ b/AnnService/inc/Core/BKT/DistanceUtils.h @@ -20,7 +20,6 @@ namespace SPTAG { namespace BKT { - class DistanceUtils { public: @@ -35,14 +34,55 @@ namespace SPTAG __m128i xhi = _mm_unpackhi_epi8(X, sign_x); __m128i ylo = _mm_unpacklo_epi8(Y, sign_y); __m128i yhi = _mm_unpackhi_epi8(Y, sign_y); - + return _mm_cvtepi32_ps(_mm_add_epi32(_mm_madd_epi16(xlo, ylo), _mm_madd_epi16(xhi, yhi))); } + + static inline __m128 _mm_sqdf_epi8(__m128i X, __m128i Y) + { + __m128i zero = _mm_setzero_si128(); + + __m128i sign_x = _mm_cmplt_epi8(X, zero); + __m128i sign_y = _mm_cmplt_epi8(Y, zero); + + __m128i xlo = _mm_unpacklo_epi8(X, sign_x); + __m128i xhi = _mm_unpackhi_epi8(X, sign_x); + __m128i ylo = _mm_unpacklo_epi8(Y, sign_y); + __m128i yhi = _mm_unpackhi_epi8(Y, sign_y); + + __m128i dlo = _mm_sub_epi16(xlo, ylo); + __m128i dhi = _mm_sub_epi16(xhi, yhi); + + return _mm_cvtepi32_ps(_mm_add_epi32(_mm_madd_epi16(dlo, dlo), _mm_madd_epi16(dhi, dhi))); + } + static inline __m128 _mm_mul_epi16(__m128i X, __m128i Y) { return _mm_cvtepi32_ps(_mm_madd_epi16(X, Y)); } + static inline __m128 _mm_sqdf_epi16(__m128i X, __m128i Y) + { + __m128i zero = _mm_setzero_si128(); + + __m128i sign_x = _mm_cmplt_epi16(X, zero); + __m128i sign_y = _mm_cmplt_epi16(Y, zero); + + __m128i xlo = _mm_unpacklo_epi16(X, sign_x); + __m128i xhi = _mm_unpackhi_epi16(X, sign_x); + __m128i ylo = _mm_unpacklo_epi16(Y, sign_y); + __m128i yhi = _mm_unpackhi_epi16(Y, sign_y); + + __m128 dlo = _mm_cvtepi32_ps(_mm_sub_epi32(xlo, ylo)); + __m128 dhi = _mm_cvtepi32_ps(_mm_sub_epi32(xhi, yhi)); + + return _mm_add_ps(_mm_mul_ps(dlo, dlo), _mm_mul_ps(dhi, dhi)); + } + static inline __m128 _mm_sqdf_ps(__m128 X, __m128 Y) + { + __m128 d = _mm_sub_ps(X, Y); + return _mm_mul_ps(d, d); + } #if defined(AVX) static inline __m256 _mm256_mul_epi8(__m256i X, __m256i Y) { @@ -58,10 +98,49 @@ namespace SPTAG return _mm256_cvtepi32_ps(_mm256_add_epi32(_mm256_madd_epi16(xlo, ylo), _mm256_madd_epi16(xhi, yhi))); } + static inline __m256 _mm256_sqdf_epi8(__m256i X, __m256i Y) + { + __m256i zero = _mm256_setzero_si256(); + + __m256i sign_x = _mm256_cmpgt_epi8(zero, X); + __m256i sign_y = _mm256_cmpgt_epi8(zero, Y); + + __m256i xlo = _mm256_unpacklo_epi8(X, sign_x); + __m256i xhi = _mm256_unpackhi_epi8(X, sign_x); + __m256i ylo = _mm256_unpacklo_epi8(Y, sign_y); + __m256i yhi = _mm256_unpackhi_epi8(Y, sign_y); + + __m256i dlo = _mm256_sub_epi16(xlo, ylo); + __m256i dhi = _mm256_sub_epi16(xhi, yhi); + + return _mm256_cvtepi32_ps(_mm256_add_epi32(_mm256_madd_epi16(dlo, dlo), _mm256_madd_epi16(dhi, dhi))); + } static inline __m256 _mm256_mul_epi16(__m256i X, __m256i Y) { return _mm256_cvtepi32_ps(_mm256_madd_epi16(X, Y)); } + static inline __m256 _mm256_sqdf_epi16(__m256i X, __m256i Y) + { + __m256i zero = _mm256_setzero_si256(); + + __m256i sign_x = _mm256_cmpgt_epi16(zero, X); + __m256i sign_y = _mm256_cmpgt_epi16(zero, Y); + + __m256i xlo = _mm256_unpacklo_epi16(X, sign_x); + __m256i xhi = _mm256_unpackhi_epi16(X, sign_x); + __m256i ylo = _mm256_unpacklo_epi16(Y, sign_y); + __m256i yhi = _mm256_unpackhi_epi16(Y, sign_y); + + __m256 dlo = _mm256_cvtepi32_ps(_mm256_sub_epi32(xlo, ylo)); + __m256 dhi = _mm256_cvtepi32_ps(_mm256_sub_epi32(xhi, yhi)); + + return _mm256_add_ps(_mm256_mul_ps(dlo, dlo), _mm256_mul_ps(dhi, dhi)); + } + static inline __m256 _mm256_sqdf_ps(__m256 X, __m256 Y) + { + __m256 d = _mm256_sub_ps(X, Y); + return _mm256_mul_ps(d, d); + } #endif /* template @@ -75,6 +154,14 @@ namespace SPTAG return diff; } */ +#define REPEAT(type, ctype, delta, load, exec, acc, result) \ + { \ + type c1 = load((ctype *)(pX)); \ + type c2 = load((ctype *)(pY)); \ + pX += delta; pY += delta; \ + result = acc(result, exec(c1, c2)); \ + } \ + static float ComputeL2Distance(const std::int8_t *pX, const std::int8_t *pY, int length) { const std::int8_t* pEnd32 = pX + ((length >> 5) << 5); @@ -84,42 +171,21 @@ namespace SPTAG #if defined(SSE) __m128 diff128 = _mm_setzero_ps(); while (pX < pEnd32) { - __m128i c1 = _mm_loadu_si128((__m128i *)(pX)); - __m128i c2 = _mm_loadu_si128((__m128i *)(pY)); - pX += 16; pY += 16; - c1 = _mm_subs_epi8(c1, c2); - diff128 = _mm_add_ps(diff128, _mm_mul_epi8(c1, c1)); - - c1 = _mm_loadu_si128((__m128i *)(pX)); - c2 = _mm_loadu_si128((__m128i *)(pY)); - pX += 16; pY += 16; - c1 = _mm_subs_epi8(c1, c2); - diff128 = _mm_add_ps(diff128, _mm_mul_epi8(c1, c1)); + REPEAT(__m128i, __m128i, 16, _mm_loadu_si128, _mm_sqdf_epi8, _mm_add_ps, diff128) + REPEAT(__m128i, __m128i, 16, _mm_loadu_si128, _mm_sqdf_epi8, _mm_add_ps, diff128) } while (pX < pEnd16) { - __m128i c1 = _mm_loadu_si128((__m128i *)(pX)); - __m128i c2 = _mm_loadu_si128((__m128i *)(pY)); - pX += 16; pY += 16; - c1 = _mm_subs_epi8(c1, c2); - diff128 = _mm_add_ps(diff128, _mm_mul_epi8(c1, c1)); + REPEAT(__m128i, __m128i, 16, _mm_loadu_si128, _mm_sqdf_epi8, _mm_add_ps, diff128) } float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; #elif defined(AVX) __m256 diff256 = _mm256_setzero_ps(); while (pX < pEnd32) { - __m256i c1 = _mm256_loadu_si256((__m256i *)(pX)); - __m256i c2 = _mm256_loadu_si256((__m256i *)(pY)); - pX += 32; pY += 32; - c1 = _mm256_subs_epi8(c1, c2); - diff256 = _mm256_add_ps(diff256, _mm256_mul_epi8(c1, c1)); + REPEAT(__m256i, __m256i, 32, _mm256_loadu_si256, _mm256_sqdf_epi8, _mm256_add_ps, diff256) } __m128 diff128 = _mm_add_ps(_mm256_castps256_ps128(diff256), _mm256_extractf128_ps(diff256, 1)); while (pX < pEnd16) { - __m128i c1 = _mm_loadu_si128((__m128i *)(pX)); - __m128i c2 = _mm_loadu_si128((__m128i *)(pY)); - pX += 16; pY += 16; - c1 = _mm_subs_epi8(c1, c2); - diff128 = _mm_add_ps(diff128, _mm_mul_epi8(c1, c1)); + REPEAT(__m128i, __m128i, 16, _mm_loadu_si128, _mm_sqdf_epi8, _mm_add_ps, diff128) } float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; #else @@ -146,42 +212,21 @@ namespace SPTAG #if defined(SSE) __m128 diff128 = _mm_setzero_ps(); while (pX < pEnd16) { - __m128i c1 = _mm_loadu_si128((__m128i *)(pX)); - __m128i c2 = _mm_loadu_si128((__m128i *)(pY)); - pX += 8; pY += 8; - c1 = _mm_subs_epi16(c1, c2); - diff128 = _mm_add_ps(diff128, _mm_mul_epi16(c1, c1)); - - c1 = _mm_loadu_si128((__m128i *)(pX)); - c2 = _mm_loadu_si128((__m128i *)(pY)); - pX += 8; pY += 8; - c1 = _mm_subs_epi16(c1, c2); - diff128 = _mm_add_ps(diff128, _mm_mul_epi16(c1, c1)); + REPEAT(__m128i, __m128i, 8, _mm_loadu_si128, _mm_sqdf_epi16, _mm_add_ps, diff128) + REPEAT(__m128i, __m128i, 8, _mm_loadu_si128, _mm_sqdf_epi16, _mm_add_ps, diff128) } while (pX < pEnd8) { - __m128i c1 = _mm_loadu_si128((__m128i *)(pX)); - __m128i c2 = _mm_loadu_si128((__m128i *)(pY)); - pX += 8; pY += 8; - c1 = _mm_subs_epi16(c1, c2); - diff128 = _mm_add_ps(diff128, _mm_mul_epi16(c1, c1)); + REPEAT(__m128i, __m128i, 8, _mm_loadu_si128, _mm_sqdf_epi16, _mm_add_ps, diff128) } float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; #elif defined(AVX) __m256 diff256 = _mm256_setzero_ps(); while (pX < pEnd16) { - __m256i c1 = _mm256_loadu_si256((__m256i *)(pX)); - __m256i c2 = _mm256_loadu_si256((__m256i *)(pY)); - pX += 16; pY += 16; - c1 = _mm256_subs_epi16(c1, c2); - diff256 = _mm256_add_ps(diff256, _mm256_mul_epi16(c1, c1)); + REPEAT(__m256i, __m256i, 16, _mm256_loadu_si256, _mm256_sqdf_epi16, _mm256_add_ps, diff256) } __m128 diff128 = _mm_add_ps(_mm256_castps256_ps128(diff256), _mm256_extractf128_ps(diff256, 1)); while (pX < pEnd8) { - __m128i c1 = _mm_loadu_si128((__m128i *)(pX)); - __m128i c2 = _mm_loadu_si128((__m128i *)(pY)); - pX += 8; pY += 8; - c1 = _mm_subs_epi16(c1, c2); - diff128 = _mm_add_ps(diff128, _mm_mul_epi16(c1, c1)); + REPEAT(__m128i, __m128i, 8, _mm_loadu_si128, _mm_sqdf_epi16, _mm_add_ps, diff128) } float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; #else @@ -202,52 +247,34 @@ namespace SPTAG static float ComputeL2Distance(const float *pX, const float *pY, int length) { - const float* pEnd8 = pX + ((length >> 3) << 3); + const float* pEnd16 = pX + ((length >> 4) << 4); const float* pEnd4 = pX + ((length >> 2) << 2); const float* pEnd1 = pX + length; #if defined(SSE) __m128 diff128 = _mm_setzero_ps(); - while (pX < pEnd8) + while (pX < pEnd16) { - __m128 c1 = _mm_loadu_ps(pX); - __m128 c2 = _mm_loadu_ps(pY); - pX += 4; pY += 4; - c1 = _mm_sub_ps(c1, c2); - diff128 = _mm_add_ps(diff128, _mm_mul_ps(c1, c1)); - - c1 = _mm_loadu_ps(pX); - c2 = _mm_loadu_ps(pY); - pX += 4; pY += 4; - c1 = _mm_sub_ps(c1, c2); - diff128 = _mm_add_ps(diff128, _mm_mul_ps(c1, c1)); + REPEAT(__m128, const float, 4, _mm_loadu_ps, _mm_sqdf_ps, _mm_add_ps, diff128) + REPEAT(__m128, const float, 4, _mm_loadu_ps, _mm_sqdf_ps, _mm_add_ps, diff128) + REPEAT(__m128, const float, 4, _mm_loadu_ps, _mm_sqdf_ps, _mm_add_ps, diff128) + REPEAT(__m128, const float, 4, _mm_loadu_ps, _mm_sqdf_ps, _mm_add_ps, diff128) } while (pX < pEnd4) { - __m128 c1 = _mm_loadu_ps(pX); - __m128 c2 = _mm_loadu_ps(pY); - pX += 4; pY += 4; - c1 = _mm_sub_ps(c1, c2); - diff128 = _mm_add_ps(diff128, _mm_mul_ps(c1, c1)); + REPEAT(__m128, const float, 4, _mm_loadu_ps, _mm_sqdf_ps, _mm_add_ps, diff128) } float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; #elif defined(AVX) __m256 diff256 = _mm256_setzero_ps(); - while (pX < pEnd8) + while (pX < pEnd16) { - __m256 c1 = _mm256_loadu_ps(pX); - __m256 c2 = _mm256_loadu_ps(pY); - pX += 8; pY += 8; - c1 = _mm256_sub_ps(c1, c2); - diff256 = _mm256_add_ps(diff256, _mm256_mul_ps(c1, c1)); + REPEAT(__m256, const float, 8, _mm256_loadu_ps, _mm256_sqdf_ps, _mm256_add_ps, diff256) + REPEAT(__m256, const float, 8, _mm256_loadu_ps, _mm256_sqdf_ps, _mm256_add_ps, diff256) } __m128 diff128 = _mm_add_ps(_mm256_castps256_ps128(diff256), _mm256_extractf128_ps(diff256, 1)); while (pX < pEnd4) { - __m128 c1 = _mm_loadu_ps(pX); - __m128 c2 = _mm_loadu_ps(pY); - pX += 4; pY += 4; - c1 = _mm_sub_ps(c1, c2); - diff128 = _mm_add_ps(diff128, _mm_mul_ps(c1, c1)); + REPEAT(__m128, const float, 4, _mm_loadu_ps, _mm_sqdf_ps, _mm_add_ps, diff128) } float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; #else @@ -282,35 +309,21 @@ namespace SPTAG __m128 diff128 = _mm_setzero_ps(); while (pX < pEnd32) { - __m128i c1 = _mm_loadu_si128((__m128i *)(pX)); - __m128i c2 = _mm_loadu_si128((__m128i *)(pY)); - pX += 16; pY += 16; - diff128 = _mm_add_ps(diff128, _mm_mul_epi8(c1, c2)); - - c1 = _mm_loadu_si128((__m128i *)(pX)); - c2 = _mm_loadu_si128((__m128i *)(pY)); - pX += 16; pY += 16; - diff128 = _mm_add_ps(diff128, _mm_mul_epi8(c1, c2)); + REPEAT(__m128i, __m128i, 16, _mm_loadu_si128, _mm_mul_epi8, _mm_add_ps, diff128) + REPEAT(__m128i, __m128i, 16, _mm_loadu_si128, _mm_mul_epi8, _mm_add_ps, diff128) } while (pX < pEnd16) { - __m128 c1 = _mm_mul_epi8(_mm_loadu_si128((__m128i *)(pX)), _mm_loadu_si128((__m128i *)(pY))); - pX += 16; pY += 16; - diff128 = _mm_add_ps(diff128, c1); + REPEAT(__m128i, __m128i, 16, _mm_loadu_si128, _mm_mul_epi8, _mm_add_ps, diff128) } float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; #elif defined(AVX) __m256 diff256 = _mm256_setzero_ps(); while (pX < pEnd32) { - __m256i c1 = _mm256_loadu_si256((__m256i *)(pX)); - __m256i c2 = _mm256_loadu_si256((__m256i *)(pY)); - pX += 32; pY += 32; - diff256 = _mm256_add_ps(diff256, _mm256_mul_epi8(c1, c2)); + REPEAT(__m256i, __m256i, 32, _mm256_loadu_si256, _mm256_mul_epi8, _mm256_add_ps, diff256) } __m128 diff128 = _mm_add_ps(_mm256_castps256_ps128(diff256), _mm256_extractf128_ps(diff256, 1)); while (pX < pEnd16) { - __m128 c1 = _mm_mul_epi8(_mm_loadu_si128((__m128i *)(pX)), _mm_loadu_si128((__m128i *)(pY))); - pX += 16; pY += 16; - diff128 = _mm_add_ps(diff128, c1); + REPEAT(__m128i, __m128i, 16, _mm_loadu_si128, _mm_mul_epi8, _mm_add_ps, diff128) } float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; #else @@ -335,36 +348,22 @@ namespace SPTAG #if defined(SSE) __m128 diff128 = _mm_setzero_ps(); while (pX < pEnd16) { - __m128i c1 = _mm_loadu_si128((__m128i *)(pX)); - __m128i c2 = _mm_loadu_si128((__m128i *)(pY)); - pX += 8; pY += 8; - diff128 = _mm_add_ps(diff128, _mm_mul_epi16(c1, c2)); - - c1 = _mm_loadu_si128((__m128i *)(pX)); - c2 = _mm_loadu_si128((__m128i *)(pY)); - pX += 8; pY += 8; - diff128 = _mm_add_ps(diff128, _mm_mul_epi16(c1, c2)); + REPEAT(__m128i, __m128i, 8, _mm_loadu_si128, _mm_mul_epi16, _mm_add_ps, diff128) + REPEAT(__m128i, __m128i, 8, _mm_loadu_si128, _mm_mul_epi16, _mm_add_ps, diff128) } while (pX < pEnd8) { - __m128 c1 = _mm_mul_epi16(_mm_loadu_si128((__m128i *)(pX)), _mm_loadu_si128((__m128i *)(pY))); - pX += 8; pY += 8; - diff128 = _mm_add_ps(diff128, c1); + REPEAT(__m128i, __m128i, 8, _mm_loadu_si128, _mm_mul_epi16, _mm_add_ps, diff128) } float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; #elif defined(AVX) __m256 diff256 = _mm256_setzero_ps(); while (pX < pEnd16) { - __m256i c1 = _mm256_loadu_si256((__m256i *)(pX)); - __m256i c2 = _mm256_loadu_si256((__m256i *)(pY)); - pX += 16; pY += 16; - diff256 = _mm256_add_ps(diff256, _mm256_mul_epi16(c1, c2)); + REPEAT(__m256i, __m256i, 16, _mm256_loadu_si256, _mm256_mul_epi16, _mm256_add_ps, diff256) } __m128 diff128 = _mm_add_ps(_mm256_castps256_ps128(diff256), _mm256_extractf128_ps(diff256, 1)); while (pX < pEnd8) { - __m128 c1 = _mm_mul_epi16(_mm_loadu_si128((__m128i *)(pX)), _mm_loadu_si128((__m128i *)(pY))); - pX += 8; pY += 8; - diff128 = _mm_add_ps(diff128, c1); + REPEAT(__m128i, __m128i, 8, _mm_loadu_si128, _mm_mul_epi16, _mm_add_ps, diff128) } float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; #else @@ -390,32 +389,14 @@ namespace SPTAG __m128 diff128 = _mm_setzero_ps(); while (pX < pEnd16) { - __m128 c1 = _mm_loadu_ps(pX); - __m128 c2 = _mm_loadu_ps(pY); - pX += 4; pY += 4; - diff128 = _mm_add_ps(diff128, _mm_mul_ps(c1, c2)); - - c1 = _mm_loadu_ps(pX); - c2 = _mm_loadu_ps(pY); - pX += 4; pY += 4; - diff128 = _mm_add_ps(diff128, _mm_mul_ps(c1, c2)); - - c1 = _mm_loadu_ps(pX); - c2 = _mm_loadu_ps(pY); - pX += 4; pY += 4; - diff128 = _mm_add_ps(diff128, _mm_mul_ps(c1, c2)); - - c1 = _mm_loadu_ps(pX); - c2 = _mm_loadu_ps(pY); - pX += 4; pY += 4; - diff128 = _mm_add_ps(diff128, _mm_mul_ps(c1, c2)); + REPEAT(__m128, const float, 4, _mm_loadu_ps, _mm_mul_ps, _mm_add_ps, diff128) + REPEAT(__m128, const float, 4, _mm_loadu_ps, _mm_mul_ps, _mm_add_ps, diff128) + REPEAT(__m128, const float, 4, _mm_loadu_ps, _mm_mul_ps, _mm_add_ps, diff128) + REPEAT(__m128, const float, 4, _mm_loadu_ps, _mm_mul_ps, _mm_add_ps, diff128) } while (pX < pEnd4) { - __m128 c1 = _mm_loadu_ps(pX); - __m128 c2 = _mm_loadu_ps(pY); - pX += 4; pY += 4; - diff128 = _mm_add_ps(diff128, _mm_mul_ps(c1, c2)); + REPEAT(__m128, const float, 4, _mm_loadu_ps, _mm_mul_ps, _mm_add_ps, diff128) } float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; @@ -423,22 +404,13 @@ namespace SPTAG __m256 diff256 = _mm256_setzero_ps(); while (pX < pEnd16) { - __m256 c1 = _mm256_loadu_ps(pX); - __m256 c2 = _mm256_loadu_ps(pY); - pX += 8; pY += 8; - diff256 = _mm256_add_ps(diff256, _mm256_mul_ps(c1, c2)); - - c1 = _mm256_loadu_ps(pX); - c2 = _mm256_loadu_ps(pY); - pX += 8; pY += 8; - diff256 = _mm256_add_ps(diff256, _mm256_mul_ps(c1, c2)); + REPEAT(__m256, const float, 8, _mm256_loadu_ps, _mm256_mul_ps, _mm256_add_ps, diff256) + REPEAT(__m256, const float, 8, _mm256_loadu_ps, _mm256_mul_ps, _mm256_add_ps, diff256) } __m128 diff128 = _mm_add_ps(_mm256_castps256_ps128(diff256), _mm256_extractf128_ps(diff256, 1)); while (pX < pEnd4) { - __m128 c1 = _mm_mul_ps(_mm_loadu_ps(pX), _mm_loadu_ps(pY)); - pX += 4; pY += 4; - diff128 = _mm_add_ps(diff128, c1); + REPEAT(__m128, const float, 4, _mm_loadu_ps, _mm_mul_ps, _mm_add_ps, diff128) } float diff = DIFF128[0] + DIFF128[1] + DIFF128[2] + DIFF128[3]; #else diff --git a/AnnService/inc/Core/Common.h b/AnnService/inc/Core/Common.h index 4aa1ed44..2aafd264 100644 --- a/AnnService/inc/Core/Common.h +++ b/AnnService/inc/Core/Common.h @@ -29,7 +29,7 @@ inline T max(T a, T b) { return a > b ? a : b; } #else -#include +#define WIN32_LEAN_AND_MEAN #include #include #define FolderSep '\\' diff --git a/AnnService/src/Core/VectorIndex.cpp b/AnnService/src/Core/VectorIndex.cpp index 52bbef47..aeacb594 100644 --- a/AnnService/src/Core/VectorIndex.cpp +++ b/AnnService/src/Core/VectorIndex.cpp @@ -62,7 +62,7 @@ VectorIndex::CreateInstance(IndexAlgoType p_algo, VectorValueType p_valuetype) { #define DefineVectorValueType(Name, Type) \ case VectorValueType::Name: \ - return std::shared_ptr>(new BKT::Index); \ + return std::shared_ptr(new BKT::Index); \ #include "inc/Core/DefinitionList.h" #undef DefineVectorValueType diff --git a/PythonWrapper/PythonClient.vcxproj b/PythonWrapper/PythonClient.vcxproj index d8827778..5de20b04 100644 --- a/PythonWrapper/PythonClient.vcxproj +++ b/PythonWrapper/PythonClient.vcxproj @@ -29,13 +29,13 @@ DynamicLibrary true - v141 + v140 MultiByte DynamicLibrary false - v141 + v140 true MultiByte @@ -110,6 +110,7 @@ Disabled true true + _WINDLL;_SCL_SECURE_NO_WARNINGS;SWIG_PYTHON_INTERPRETER_NO_DEBUG;%(PreprocessorDefinitions) diff --git a/PythonWrapper/PythonCore.vcxproj b/PythonWrapper/PythonCore.vcxproj index 250973cf..09fd482d 100644 --- a/PythonWrapper/PythonCore.vcxproj +++ b/PythonWrapper/PythonCore.vcxproj @@ -29,13 +29,13 @@ Application true - v141 + v140 MultiByte Application false - v141 + v140 true MultiByte @@ -81,6 +81,9 @@ CoreLibrary.lib;$(PyLinkLib);%(AdditionalDependencies) + + _WINDLL;SWIG_PYTHON_INTERPRETER_NO_DEBUG;%(PreprocessorDefinitions) + diff --git a/SPTAG.sdf b/SPTAG.sdf new file mode 100644 index 0000000000000000000000000000000000000000..254a44ece6de77823917e2b4a7aed9f3a9fedc6e GIT binary patch literal 65536 zcmeI(F-pWh6adh_$q?L13lAXT0R-C>ti6Dic3WF|1`lB45yW%Zcm{XAGDFxxu~=c{ zeMtVF$&gH5s$t0c&BJ}nV|f{i+Rh`R|#`(@0Y009C72oNAZfB*pk1PBoLR^WMBACz*}$Bgrzzk9EO z009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBly zK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF z5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk z1PBlyK!5-N0t5&UAV7cs0RjXF5FkK+009C72oNAZfB*pk1PBlyK!5-N0t5&UAV7cs L0RjXF>{eg{NpuS@ literal 0 HcmV?d00001 diff --git a/SPTAG.sln b/SPTAG.sln index bcacb1d4..20c1ccf2 100644 --- a/SPTAG.sln +++ b/SPTAG.sln @@ -44,6 +44,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "IndexBuilder", "AnnService\ {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9} = {C2BC5FDE-C853-4F3D-B7E4-2C9B5524DDF9} EndProjectSection EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Test", "Test\Test.vcxproj", "{29A25655-CCF2-47F8-8BC8-DFE1B5CF993C}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -116,6 +118,14 @@ Global {F492F794-E78B-4B1F-A556-5E045B9163D5}.Release|x64.Build.0 = Release|x64 {F492F794-E78B-4B1F-A556-5E045B9163D5}.Release|x86.ActiveCfg = Release|Win32 {F492F794-E78B-4B1F-A556-5E045B9163D5}.Release|x86.Build.0 = Release|Win32 + {29A25655-CCF2-47F8-8BC8-DFE1B5CF993C}.Debug|x64.ActiveCfg = Debug|x64 + {29A25655-CCF2-47F8-8BC8-DFE1B5CF993C}.Debug|x64.Build.0 = Debug|x64 + {29A25655-CCF2-47F8-8BC8-DFE1B5CF993C}.Debug|x86.ActiveCfg = Debug|Win32 + {29A25655-CCF2-47F8-8BC8-DFE1B5CF993C}.Debug|x86.Build.0 = Debug|Win32 + {29A25655-CCF2-47F8-8BC8-DFE1B5CF993C}.Release|x64.ActiveCfg = Release|x64 + {29A25655-CCF2-47F8-8BC8-DFE1B5CF993C}.Release|x64.Build.0 = Release|x64 + {29A25655-CCF2-47F8-8BC8-DFE1B5CF993C}.Release|x86.ActiveCfg = Release|Win32 + {29A25655-CCF2-47F8-8BC8-DFE1B5CF993C}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Test/Test.vcxproj b/Test/Test.vcxproj new file mode 100644 index 00000000..306393a9 --- /dev/null +++ b/Test/Test.vcxproj @@ -0,0 +1,146 @@ + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + 15.0 + {29A25655-CCF2-47F8-8BC8-DFE1B5CF993C} + Test + 8.1 + + + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + Application + true + v140 + MultiByte + + + Application + false + v140 + true + MultiByte + + + + + + + + + + + + + + + + + + + + + $(SolutionDir)obj\$(Platform)_$(Configuration)\$(ProjectName)\ + $(BoostIncDir);$(ProjectDir);$(SolutionDir)AnnService\;$(IncludePath) + $(OutAppDir) + $(OutLibDir);$(BoostLibDir);$(LibraryPath) + + + + CoreLibrary.lib;%(AdditionalDependencies) + + + + + Level3 + MaxSpeed + true + true + true + true + + + true + true + + + Console + + + + + Level3 + Disabled + true + true + + + + + Level3 + Disabled + true + true + _MBCS;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + + + Console + + + + + Level3 + MaxSpeed + true + true + true + true + + + true + true + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Test/Test.vcxproj.filters b/Test/Test.vcxproj.filters new file mode 100644 index 00000000..71509659 --- /dev/null +++ b/Test/Test.vcxproj.filters @@ -0,0 +1,33 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + \ No newline at end of file diff --git a/Test/Test.vcxproj.user b/Test/Test.vcxproj.user new file mode 100644 index 00000000..abe8dd89 --- /dev/null +++ b/Test/Test.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Test/inc/BKTTest.h b/Test/inc/BKTTest.h new file mode 100644 index 00000000..bcee62f9 --- /dev/null +++ b/Test/inc/BKTTest.h @@ -0,0 +1,30 @@ +#ifndef _SPTAG_TEST_BKTTEST_H_ +#define _SPTAG_TEST_BKTTEST_H_ + +#include +#include "inc/Helper/SimpleIniReader.h" +#include "inc/Core/VectorIndex.h" + +BOOST_AUTO_TEST_SUITE(BKTTest) + +BOOST_AUTO_TEST_CASE(test1) +{ + SPTAG::Helper::IniReader reader; + reader.SetParameter("Index", "DistCalcMethod", "Cosine"); + reader.SetParameter("Index", "BKTNumber", "2"); + reader.SetParameter("Index", "NeighborhoodSize", "16"); + + auto index = SPTAG::VectorIndex::CreateInstance(SPTAG::IndexAlgoType::BKT, SPTAG::VectorValueType::Float); + + for (const auto& iter : reader.GetParameters("Index")) + { + index->SetParameter(iter.first.c_str(), iter.second.c_str()); + } + + BOOST_CHECK(index->GetIndexName() == "BKT"); + BOOST_CHECK(index->GetParameter("BKTNumber") == "2"); + BOOST_CHECK(index->GetParameter("NeighborhoodSize") == "16"); +} + +BOOST_AUTO_TEST_SUITE_END() +#endif // _SPTAG_TEST_BKTTEST_H_ \ No newline at end of file diff --git a/Test/inc/DistanceTest.h b/Test/inc/DistanceTest.h new file mode 100644 index 00000000..38397fd3 --- /dev/null +++ b/Test/inc/DistanceTest.h @@ -0,0 +1,59 @@ +#ifndef _SPTAG_TEST_DISTANCETEST_H_ +#define _SPTAG_TEST_DISTANCETEST_H_ + +#include +#include "inc/Core/BKT/DistanceUtils.h" + +BOOST_AUTO_TEST_SUITE(DistanceTest) + +template +static float ComputeCosineDistance(const T *pX, const T *pY, int length) { + float diff = 0; + const T* pEnd1 = pX + length; + while (pX < pEnd1) diff += (*pX++) * (*pY++); + return diff; +} + +template +static float ComputeL2Distance(const T *pX, const T *pY, int length) +{ + float diff = 0; + const T* pEnd1 = pX + length; + while (pX < pEnd1) { + float c1 = ((float)(*pX++) - (float)(*pY++)); diff += c1 * c1; + } + return diff; +} + +template +T random(int high = RAND_MAX, int low = 0) // Generates a random value. +{ + return (T)(low + float(high - low)*(std::rand() / static_cast(RAND_MAX))); +} + +template +void test(int high) { + int dimension = random(256, 2); + T *X = new T[dimension], *Y = new T[dimension]; + BOOST_ASSERT(X != nullptr && Y != nullptr); + for (int i = 0; i < dimension; i++) { + X[i] = random(high, -high); + Y[i] = random(high, -high); + } + + BOOST_CHECK_CLOSE_FRACTION(ComputeL2Distance(X, Y, dimension), SPTAG::BKT::DistanceUtils::ComputeL2Distance(X, Y, dimension), 1e-6); + BOOST_CHECK_CLOSE_FRACTION(high*high - ComputeCosineDistance(X, Y, dimension), SPTAG::BKT::DistanceUtils::ComputeCosineDistance(X, Y, dimension), 1e-6); + + delete[] X; + delete[] Y; +} + +BOOST_AUTO_TEST_CASE(TestDistanceComputation) +{ + test(1); + test(127); + test(32767); +} + +BOOST_AUTO_TEST_SUITE_END() +#endif // _SPTAG_TEST_DISTANCETEST_H_ \ No newline at end of file diff --git a/Test/inc/Test.h b/Test/inc/Test.h new file mode 100644 index 00000000..be44ae45 --- /dev/null +++ b/Test/inc/Test.h @@ -0,0 +1,4 @@ +#pragma once + +#include +#include diff --git a/Test/src/BKTTest.cpp b/Test/src/BKTTest.cpp new file mode 100644 index 00000000..0ec934ea --- /dev/null +++ b/Test/src/BKTTest.cpp @@ -0,0 +1,25 @@ +#include "inc/Test.h" +#include "inc/Helper/SimpleIniReader.h" +#include "inc/Core/VectorIndex.h" + +BOOST_AUTO_TEST_SUITE (BKTTest) + +BOOST_AUTO_TEST_CASE(ParameterTest) +{ + SPTAG::Helper::IniReader reader; + reader.SetParameter("Index", "DistCalcMethod", "Cosine"); + reader.SetParameter("Index", "BKTNumber", "2"); + reader.SetParameter("Index", "NeighborhoodSize", "16"); + + auto index = SPTAG::VectorIndex::CreateInstance(SPTAG::IndexAlgoType::BKT, SPTAG::VectorValueType::Float); + + for (const auto& iter : reader.GetParameters("Index")) + { + index->SetParameter(iter.first.c_str(), iter.second.c_str()); + } + + BOOST_CHECK(index->GetParameter("BKTNumber") == "2"); + BOOST_CHECK(index->GetParameter("NeighborhoodSize") == "16"); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/Test/src/DistanceTest.cpp b/Test/src/DistanceTest.cpp new file mode 100644 index 00000000..6a717cc1 --- /dev/null +++ b/Test/src/DistanceTest.cpp @@ -0,0 +1,61 @@ +#include +#include "inc/Test.h" +#include "inc/Core/BKT/DistanceUtils.h" + +template +static float ComputeCosineDistance(const T *pX, const T *pY, int length) { + float diff = 0; + const T* pEnd1 = pX + length; + while (pX < pEnd1) diff += (*pX++) * (*pY++); + return diff; +} + +template +static float ComputeL2Distance(const T *pX, const T *pY, int length) +{ + float diff = 0; + const T* pEnd1 = pX + length; + while (pX < pEnd1) { + float c1 = ((float)(*pX++) - (float)(*pY++)); diff += c1 * c1; + } + return diff; +} + +template +T random(int high = RAND_MAX, int low = 0) // Generates a random value. +{ + return (T)(low + float(high - low)*(std::rand()/static_cast(RAND_MAX + 1.0))); +} + +template +void test(int high) { + int dimension = random(256, 2); + T *X = new T[dimension], *Y = new T[dimension]; + BOOST_ASSERT(X != nullptr && Y != nullptr); + for (int i = 0; i < dimension; i++) { + X[i] = random(high, -high); + Y[i] = random(high, -high); + } + for (int i = 0; i < dimension; i++) + std::cout << (int)X[i] << " "; + std::cout << std::endl; + for (int i = 0; i < dimension; i++) + std::cout << (int)Y[i] << " "; + std::cout << std::endl; + BOOST_CHECK_CLOSE_FRACTION(ComputeL2Distance(X, Y, dimension), SPTAG::BKT::DistanceUtils::ComputeL2Distance(X, Y, dimension), 1e-6); + BOOST_CHECK_CLOSE_FRACTION(high*high - ComputeCosineDistance(X, Y, dimension), SPTAG::BKT::DistanceUtils::ComputeCosineDistance(X, Y, dimension), 1e-6); + + delete[] X; + delete[] Y; +} + +BOOST_AUTO_TEST_SUITE(DistanceTest) + +BOOST_AUTO_TEST_CASE(TestDistanceComputation) +{ + test(1); + test(127); + test(32767); +} + +BOOST_AUTO_TEST_SUITE_END() \ No newline at end of file diff --git a/Test/src/main.cpp b/Test/src/main.cpp new file mode 100644 index 00000000..91444f66 --- /dev/null +++ b/Test/src/main.cpp @@ -0,0 +1,38 @@ +#define BOOST_TEST_MAIN +#define BOOST_TEST_MODULE Main +#include "inc/Test.h" + +#include +#include + +using namespace boost::unit_test; + +class SPTAGVisitor : public test_tree_visitor +{ +public: + void visit(test_case const& test) + { + std::string prefix(2, '\t'); + std::cout << prefix << "Case: " << test.p_name << std::endl; + } + + bool test_suite_start(test_suite const& suite) + { + std::string prefix(1, '\t'); + std::cout << prefix << "Suite: " << suite.p_name << std::endl; + return true; + } +}; + +struct GlobalFixture +{ + GlobalFixture() + { + SPTAGVisitor visitor; + traverse_test_tree(framework::master_test_suite(), visitor, false); + } + +}; + +BOOST_TEST_GLOBAL_FIXTURE(GlobalFixture); +