diff --git a/paddle/utils/CpuId.cpp b/paddle/utils/CpuId.cpp new file mode 100644 index 0000000000000000000000000000000000000000..ab73be9e89b13d1aae5803c231d92b975cb6d084 --- /dev/null +++ b/paddle/utils/CpuId.cpp @@ -0,0 +1,61 @@ +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. */ + +#include "paddle/utils/CpuId.h" +#include "paddle/utils/Util.h" + +#ifdef _WIN32 + +/// for MSVC +#define CPUID(info, x) __cpuidex(info, x, 0) + +#else + +#include + +/// for GCC/Clang +#define CPUID(info, x) __cpuid_count(x, 0, info[0], info[1], info[2], info[3]) + +#endif + +namespace paddle { + +/// init simd instance +static InitFunction __init_simd_flags( + []{ SIMDFlags::instance(); }, std::numeric_limits::max()); + +SIMDFlags::SIMDFlags() { + unsigned int cpuInfo[4]; + + CPUID(cpuInfo, 0x00000001); + simd_flags_ |= cpuInfo[3] & (1 << 25) ? SIMD_SSE : SIMD_NONE; + simd_flags_ |= cpuInfo[3] & (1 << 26) ? SIMD_SSE2 : SIMD_NONE; + simd_flags_ |= cpuInfo[2] & (1 << 0) ? SIMD_SSE3 : SIMD_NONE; + simd_flags_ |= cpuInfo[2] & (1 << 9) ? SIMD_SSSE3 : SIMD_NONE; + simd_flags_ |= cpuInfo[2] & (1 << 19) ? SIMD_SSE41 : SIMD_NONE; + simd_flags_ |= cpuInfo[2] & (1 << 20) ? SIMD_SSE42 : SIMD_NONE; + simd_flags_ |= cpuInfo[2] & (1 << 12) ? SIMD_FMA3 : SIMD_NONE; + simd_flags_ |= cpuInfo[2] & (1 << 28) ? SIMD_AVX : SIMD_NONE; + + CPUID(cpuInfo, 0x00000007); + simd_flags_ |= cpuInfo[1] & (1 << 5) ? SIMD_AVX2 : SIMD_NONE; + simd_flags_ |= cpuInfo[1] & (1 << 16) ? SIMD_AVX512: SIMD_NONE; + + CPUID(cpuInfo, 0x80000001); + simd_flags_ |= cpuInfo[2] & (1 << 16) ? SIMD_FMA4 : SIMD_NONE; +} + +SIMDFlags* SIMDFlags::instance() { + static SIMDFlags instance; + return &instance; +} + +} // namespace paddle diff --git a/paddle/utils/CpuId.h b/paddle/utils/CpuId.h new file mode 100644 index 0000000000000000000000000000000000000000..bb77d37712bb4dc2113b5d4d9b07693b5dcb95b8 --- /dev/null +++ b/paddle/utils/CpuId.h @@ -0,0 +1,71 @@ +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. */ + +#pragma once + +#include +#include "DisableCopy.h" + +namespace paddle { + +class SIMDFlags final { +public: + DISABLE_COPY(SIMDFlags); + + SIMDFlags(); + + static SIMDFlags* instance(); + + inline bool isSSE() { return simd_flags_ & SIMD_SSE; } + inline bool isSSE2() { return simd_flags_ & SIMD_SSE2; } + inline bool isSSE3() { return simd_flags_ & SIMD_SSE3; } + inline bool isSSSE3() { return simd_flags_ & SIMD_SSSE3; } + inline bool isSSE41() { return simd_flags_ & SIMD_SSE41; } + inline bool isSSE42() { return simd_flags_ & SIMD_SSE42; } + inline bool isFMA3() { return simd_flags_ & SIMD_FMA3; } + inline bool isFMA4() { return simd_flags_ & SIMD_FMA4; } + inline bool isAVX() { return simd_flags_ & SIMD_AVX; } + inline bool isAVX2() { return simd_flags_ & SIMD_AVX2; } + inline bool isAVX512() { return simd_flags_ & SIMD_AVX512;} + +private: + enum simd_t { + SIMD_NONE = 0, ///< None + SIMD_SSE = 1 << 0, ///< SSE + SIMD_SSE2 = 1 << 1, ///< SSE 2 + SIMD_SSE3 = 1 << 2, ///< SSE 3 + SIMD_SSSE3 = 1 << 3, ///< SSSE 3 + SIMD_SSE41 = 1 << 4, ///< SSE 4.1 + SIMD_SSE42 = 1 << 5, ///< SSE 4.2 + SIMD_FMA3 = 1 << 6, ///< FMA 3 + SIMD_FMA4 = 1 << 7, ///< FMA 4 + SIMD_AVX = 1 << 8, ///< AVX + SIMD_AVX2 = 1 << 9, ///< AVX 2 + SIMD_AVX512 = 1 << 10, ///< AVX 512 + }; + + /// simd flags + int simd_flags_ = SIMD_NONE; +}; + +#define HAS_SSE SIMDFlags::instance()->isSSE() +#define HAS_SSE2 SIMDFlags::instance()->isSSE2() +#define HAS_SSE3 SIMDFlags::instance()->isSSE3() +#define HAS_SSSE3 SIMDFlags::instance()->isSSSE3() +#define HAS_SSE41 SIMDFlags::instance()->isSSE41() +#define HAS_SSS42 SIMDFlags::instance()->isSSE42() +#define HAS_FMA3 SIMDFlags::instance()->isFMA3() +#define HAS_FMA4 SIMDFlags::instance()->isFMA4() +#define HAS_AVX SIMDFlags::instance()->isAVX() +#define HAS_AVX2 SIMDFlags::instance()->isAVX2() +#define HAS_AVX512 SIMDFlags::instance()->isAVX512() + +} // namespace paddle diff --git a/paddle/utils/tests/CMakeLists.txt b/paddle/utils/tests/CMakeLists.txt index adf489fafe722117c53789593923c21a087bd74a..298ede5cd6451c9b03219dff72f6e81c374f8ef1 100644 --- a/paddle/utils/tests/CMakeLists.txt +++ b/paddle/utils/tests/CMakeLists.txt @@ -5,6 +5,7 @@ add_simple_unittest(test_StringUtils) add_simple_unittest(test_CustomStackTrace) add_simple_unittest(test_ThreadBarrier) add_simple_unittest(test_SpinLock) +add_simple_unittest(test_SIMDFlags) add_executable( test_CustomStackTracePrint diff --git a/paddle/utils/tests/test_SIMDFlags.cpp b/paddle/utils/tests/test_SIMDFlags.cpp new file mode 100644 index 0000000000000000000000000000000000000000..583a649b84605a973113cb31705a4822b0d83eb0 --- /dev/null +++ b/paddle/utils/tests/test_SIMDFlags.cpp @@ -0,0 +1,55 @@ +/* Copyright (c) 2016 PaddlePaddle Authors. All Rights Reserved. +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + http://www.apache.org/licenses/LICENSE-2.0 +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. */ + + +#include + +#include "paddle/utils/CpuId.h" +#include "paddle/utils/Logging.h" +#include "paddle/utils/Util.h" + +using namespace paddle; // NOLINT + +TEST(SIMDFlags, gccTest) { +#if (defined(__GNUC__) || defined(__GNUG__)) && !(defined(__clang__)) + CHECK(__builtin_cpu_supports("sse") == HAS_SSE); + CHECK(__builtin_cpu_supports("sse2") == HAS_SSE2); + CHECK(__builtin_cpu_supports("sse3") == HAS_SSE3); + CHECK(__builtin_cpu_supports("ssse3")== HAS_SSSE3); + CHECK(__builtin_cpu_supports("sse4.1")== HAS_SSE41); + CHECK(__builtin_cpu_supports("sse4.2")== HAS_SSE42); + CHECK(__builtin_cpu_supports("fma3")== HAS_FMA3); + CHECK(__builtin_cpu_supports("fma4")== HAS_FMA4); + CHECK(__builtin_cpu_supports("avx")== HAS_AVX); + CHECK(__builtin_cpu_supports("avx2")== HAS_AVX2); + CHECK(__builtin_cpu_supports("avx512f")== HAS_AVX512); +#endif +} + +TEST(SIMDFlags, normalPrint) { + auto simd = SIMDFlags::instance(); + LOG(INFO) << "Has SSE2: " << std::boolalpha << simd->isSSE2(); + LOG(INFO) << "Has SSE3: " << std::boolalpha << simd->isSSE3(); + LOG(INFO) << "Has SSSE3: " << std::boolalpha << simd->isSSSE3(); + LOG(INFO) << "Has SSE4.1: " << std::boolalpha << simd->isSSE41(); + LOG(INFO) << "Has SSE4.2: " << std::boolalpha << simd->isSSE42(); + LOG(INFO) << "Has FMA3: " << std::boolalpha << simd->isFMA3(); + LOG(INFO) << "Has FMA4: " << std::boolalpha << simd->isFMA4(); + LOG(INFO) << "Has AVX: " << std::boolalpha << simd->isAVX(); + LOG(INFO) << "Has AVX2: " << std::boolalpha << simd->isAVX2(); + LOG(INFO) << "Has AVX512: " << std::boolalpha << simd->isAVX512(); +} + +int main(int argc, char** argv) { + testing::InitGoogleTest(&argc, argv); + paddle::initMain(argc, argv); + return RUN_ALL_TESTS(); +}