Home | History | Annotate | Download | only in platform
      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