1 /* Copyright 2016 The TensorFlow Authors. All Rights Reserved. 2 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 you may not use this file except in compliance with the License. 5 You may obtain a copy of the License at 6 7 http://www.apache.org/licenses/LICENSE-2.0 8 9 Unless required by applicable law or agreed to in writing, software 10 distributed under the License is distributed on an "AS IS" BASIS, 11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 See the License for the specific language governing permissions and 13 limitations under the License. 14 ==============================================================================*/ 15 16 #include "tensorflow/core/platform/cpu_feature_guard.h" 17 18 #include <mutex> 19 #include <string> 20 21 #include "tensorflow/core/platform/cpu_info.h" 22 #include "tensorflow/core/platform/logging.h" 23 24 namespace tensorflow { 25 namespace port { 26 namespace { 27 28 // If the CPU feature isn't present, log a fatal error. 29 void CheckFeatureOrDie(CPUFeature feature, const string& feature_name) { 30 if (!TestCPUFeature(feature)) { 31 #ifdef __ANDROID__ 32 // Some Android emulators seem to indicate they don't support SSE, so to 33 // avoid crashes when testing, switch this to a warning. 34 LOG(WARNING) 35 #else 36 LOG(FATAL) 37 #endif 38 << "The TensorFlow library was compiled to use " << feature_name 39 << " instructions, but these aren't available on your machine."; 40 } 41 } 42 43 // Check if CPU feature is inclued in the TensorFlow binary. 44 void CheckIfFeatureUnused(CPUFeature feature, const string& feature_name, 45 string& missing_instructions) { 46 if (TestCPUFeature(feature)) { 47 missing_instructions.append(" "); 48 missing_instructions.append(feature_name); 49 } 50 } 51 52 // Raises an error if the binary has been compiled for a CPU feature (like AVX) 53 // that isn't available on the current machine. It also warns of performance 54 // loss if there's a feature available that's not being used. 55 // Depending on the compiler and initialization order, a SIGILL exception may 56 // occur before this code is reached, but this at least offers a chance to give 57 // a more meaningful error message. 58 class CPUFeatureGuard { 59 public: 60 CPUFeatureGuard() { 61 #ifdef __SSE__ 62 CheckFeatureOrDie(CPUFeature::SSE, "SSE"); 63 #endif // __SSE__ 64 #ifdef __SSE2__ 65 CheckFeatureOrDie(CPUFeature::SSE2, "SSE2"); 66 #endif // __SSE2__ 67 #ifdef __SSE3__ 68 CheckFeatureOrDie(CPUFeature::SSE3, "SSE3"); 69 #endif // __SSE3__ 70 #ifdef __SSE4_1__ 71 CheckFeatureOrDie(CPUFeature::SSE4_1, "SSE4.1"); 72 #endif // __SSE4_1__ 73 #ifdef __SSE4_2__ 74 CheckFeatureOrDie(CPUFeature::SSE4_2, "SSE4.2"); 75 #endif // __SSE4_2__ 76 #ifdef __AVX__ 77 CheckFeatureOrDie(CPUFeature::AVX, "AVX"); 78 #endif // __AVX__ 79 #ifdef __AVX2__ 80 CheckFeatureOrDie(CPUFeature::AVX2, "AVX2"); 81 #endif // __AVX2__ 82 #ifdef __AVX512F__ 83 CheckFeatureOrDie(CPUFeature::AVX512F, "AVX512F"); 84 #endif // __AVX512F__ 85 #ifdef __FMA__ 86 CheckFeatureOrDie(CPUFeature::FMA, "FMA"); 87 #endif // __FMA__ 88 } 89 }; 90 91 CPUFeatureGuard g_cpu_feature_guard_singleton; 92 93 std::once_flag g_cpu_feature_guard_warn_once_flag; 94 95 } // namespace 96 97 void InfoAboutUnusedCPUFeatures() { 98 std::call_once(g_cpu_feature_guard_warn_once_flag, [] { 99 string missing_instructions; 100 #if defined(_MSC_VER) && !defined(__clang__) 101 102 #ifndef __AVX__ 103 CheckIfFeatureUnused(CPUFeature::AVX, "AVX", missing_instructions); 104 #endif // __AVX__ 105 #ifndef __AVX2__ 106 CheckIfFeatureUnused(CPUFeature::AVX2, "AVX2", missing_instructions); 107 #endif // __AVX2__ 108 109 #else // if defined(_MSC_VER) && !defined(__clang__) 110 111 #ifndef __SSE__ 112 CheckIfFeatureUnused(CPUFeature::SSE, "SSE", missing_instructions); 113 #endif // __SSE__ 114 #ifndef __SSE2__ 115 CheckIfFeatureUnused(CPUFeature::SSE2, "SSE2", missing_instructions); 116 #endif // __SSE2__ 117 #ifndef __SSE3__ 118 CheckIfFeatureUnused(CPUFeature::SSE3, "SSE3", missing_instructions); 119 #endif // __SSE3__ 120 #ifndef __SSE4_1__ 121 CheckIfFeatureUnused(CPUFeature::SSE4_1, "SSE4.1", missing_instructions); 122 #endif // __SSE4_1__ 123 #ifndef __SSE4_2__ 124 CheckIfFeatureUnused(CPUFeature::SSE4_2, "SSE4.2", missing_instructions); 125 #endif // __SSE4_2__ 126 #ifndef __AVX__ 127 CheckIfFeatureUnused(CPUFeature::AVX, "AVX", missing_instructions); 128 #endif // __AVX__ 129 #ifndef __AVX2__ 130 CheckIfFeatureUnused(CPUFeature::AVX2, "AVX2", missing_instructions); 131 #endif // __AVX2__ 132 #ifndef __AVX512F__ 133 CheckIfFeatureUnused(CPUFeature::AVX512F, "AVX512F", missing_instructions); 134 #endif // __AVX512F__ 135 #ifndef __FMA__ 136 CheckIfFeatureUnused(CPUFeature::FMA, "FMA", missing_instructions); 137 #endif // __FMA__ 138 #endif // else of if defined(_MSC_VER) && !defined(__clang__) 139 if (!missing_instructions.empty()) { 140 LOG(INFO) << "Your CPU supports instructions that this TensorFlow " 141 << "binary was not compiled to use:" << missing_instructions; 142 } 143 }); 144 } 145 146 } // namespace port 147 } // namespace tensorflow 148