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/byte_order.h"
22 #include "tensorflow/core/platform/cpu_info.h"
23 #include "tensorflow/core/platform/logging.h"
24
25 namespace tensorflow {
26 namespace port {
27 namespace {
28
29 // If the CPU feature isn't present, log a fatal error.
CheckFeatureOrDie(CPUFeature feature,const string & feature_name)30 void CheckFeatureOrDie(CPUFeature feature, const string& feature_name) {
31 if (!TestCPUFeature(feature)) {
32 #ifdef __ANDROID__
33 // Some Android emulators seem to indicate they don't support SSE, so to
34 // avoid crashes when testing, switch this to a warning.
35 LOG(WARNING)
36 #else
37 LOG(FATAL)
38 #endif
39 << "The TensorFlow library was compiled to use " << feature_name
40 << " instructions, but these aren't available on your machine.";
41 }
42 }
43
44 // Check if CPU feature is included in the TensorFlow binary.
CheckIfFeatureUnused(CPUFeature feature,const string & feature_name,string & missing_instructions)45 void CheckIfFeatureUnused(CPUFeature feature, const string& feature_name,
46 string& missing_instructions) {
47 if (TestCPUFeature(feature)) {
48 missing_instructions.append(" ");
49 missing_instructions.append(feature_name);
50 }
51 }
52
53 // Raises an error if the binary has been compiled for a CPU feature (like AVX)
54 // that isn't available on the current machine. It also warns of performance
55 // loss if there's a feature available that's not being used.
56 // Depending on the compiler and initialization order, a SIGILL exception may
57 // occur before this code is reached, but this at least offers a chance to give
58 // a more meaningful error message.
59 class CPUFeatureGuard {
60 public:
CPUFeatureGuard()61 CPUFeatureGuard() {
62 #ifdef __SSE__
63 CheckFeatureOrDie(CPUFeature::SSE, "SSE");
64 #endif // __SSE__
65 #ifdef __SSE2__
66 CheckFeatureOrDie(CPUFeature::SSE2, "SSE2");
67 #endif // __SSE2__
68 #ifdef __SSE3__
69 CheckFeatureOrDie(CPUFeature::SSE3, "SSE3");
70 #endif // __SSE3__
71 #ifdef __SSE4_1__
72 CheckFeatureOrDie(CPUFeature::SSE4_1, "SSE4.1");
73 #endif // __SSE4_1__
74 #ifdef __SSE4_2__
75 CheckFeatureOrDie(CPUFeature::SSE4_2, "SSE4.2");
76 #endif // __SSE4_2__
77 #ifdef __AVX__
78 CheckFeatureOrDie(CPUFeature::AVX, "AVX");
79 #endif // __AVX__
80 #ifdef __AVX2__
81 CheckFeatureOrDie(CPUFeature::AVX2, "AVX2");
82 #endif // __AVX2__
83 #ifdef __AVX512F__
84 CheckFeatureOrDie(CPUFeature::AVX512F, "AVX512F");
85 #endif // __AVX512F__
86 #ifdef __FMA__
87 CheckFeatureOrDie(CPUFeature::FMA, "FMA");
88 #endif // __FMA__
89 }
90 };
91
92 CPUFeatureGuard g_cpu_feature_guard_singleton;
93
94 std::once_flag g_cpu_feature_guard_warn_once_flag;
95
96 } // namespace
97
InfoAboutUnusedCPUFeatures()98 void InfoAboutUnusedCPUFeatures() {
99 std::call_once(g_cpu_feature_guard_warn_once_flag, [] {
100 string missing_instructions;
101 #if defined(_MSC_VER) && !defined(__clang__)
102
103 #ifndef __AVX__
104 CheckIfFeatureUnused(CPUFeature::AVX, "AVX", missing_instructions);
105 #endif // __AVX__
106 #ifndef __AVX2__
107 CheckIfFeatureUnused(CPUFeature::AVX2, "AVX2", missing_instructions);
108 #endif // __AVX2__
109
110 #else // if defined(_MSC_VER) && !defined(__clang__)
111
112 #ifndef __SSE__
113 CheckIfFeatureUnused(CPUFeature::SSE, "SSE", missing_instructions);
114 #endif // __SSE__
115 #ifndef __SSE2__
116 CheckIfFeatureUnused(CPUFeature::SSE2, "SSE2", missing_instructions);
117 #endif // __SSE2__
118 #ifndef __SSE3__
119 CheckIfFeatureUnused(CPUFeature::SSE3, "SSE3", missing_instructions);
120 #endif // __SSE3__
121 #ifndef __SSE4_1__
122 CheckIfFeatureUnused(CPUFeature::SSE4_1, "SSE4.1", missing_instructions);
123 #endif // __SSE4_1__
124 #ifndef __SSE4_2__
125 CheckIfFeatureUnused(CPUFeature::SSE4_2, "SSE4.2", missing_instructions);
126 #endif // __SSE4_2__
127 #ifndef __AVX__
128 CheckIfFeatureUnused(CPUFeature::AVX, "AVX", missing_instructions);
129 #endif // __AVX__
130 #ifndef __AVX2__
131 CheckIfFeatureUnused(CPUFeature::AVX2, "AVX2", missing_instructions);
132 #endif // __AVX2__
133 #ifndef __AVX512F__
134 CheckIfFeatureUnused(CPUFeature::AVX512F, "AVX512F", missing_instructions);
135 #endif // __AVX512F__
136 #ifndef __FMA__
137 CheckIfFeatureUnused(CPUFeature::FMA, "FMA", missing_instructions);
138 #endif // __FMA__
139 #endif // else of if defined(_MSC_VER) && !defined(__clang__)
140 if (!missing_instructions.empty()) {
141 #ifndef INTEL_MKL
142 LOG(INFO) << "Your CPU supports instructions that this TensorFlow "
143 << "binary was not compiled to use:" << missing_instructions;
144 #else
145 LOG(INFO) << "This TensorFlow binary is optimized with Intel(R) MKL-DNN "
146 << "to use the following CPU instructions in performance "
147 << "critical operations: " << missing_instructions << std::endl
148 << "To enable them in non-MKL-DNN operations, rebuild "
149 << "TensorFlow with the appropriate compiler flags.";
150 #endif
151 }
152 });
153 }
154
155 } // namespace port
156 } // namespace tensorflow
157