1 /* Copyright 2017 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 #ifndef TENSORFLOW_COMPILER_XLA_STATUS_MACROS_H_ 17 #define TENSORFLOW_COMPILER_XLA_STATUS_MACROS_H_ 18 19 #include <memory> 20 #include <ostream> // NOLINT 21 #include <string> 22 #include <vector> 23 24 #include "tensorflow/compiler/xla/statusor.h" 25 #include "tensorflow/compiler/xla/types.h" 26 #include "tensorflow/core/lib/core/status.h" 27 #include "tensorflow/core/platform/logging.h" 28 #include "tensorflow/core/platform/macros.h" 29 30 namespace xla { 31 namespace status_macros { 32 33 // This is a useful error message when encountering XLA Compiler errors that 34 // could be handled with the non-strict AutoJit mode. 35 extern const char kPossibleAutoJitAlternative[]; 36 37 // Stream object used to collect error messages in MAKE_ERROR macros 38 // or append error messages with APPEND_ERROR. It accepts any 39 // arguments with operator<< to build an error string, and then has an 40 // implicit cast operator to Status, which converts the 41 // logged string to a Status object and returns it, after logging the 42 // error. At least one call to operator<< is required; a compile time 43 // error will be generated if none are given. Errors will only be 44 // logged by default for certain status codes, as defined in 45 // IsLoggedByDefault. This class will give ERROR errors if you don't 46 // retrieve a Status exactly once before destruction. 47 // 48 // The class converts into an intermediate wrapper object 49 // MakeErrorStreamWithOutput to check that the error stream gets at least one 50 // item of input. 51 class MakeErrorStream { 52 public: 53 // Wrapper around MakeErrorStream that only allows for output. This 54 // is created as output of the first operator<< call on 55 // MakeErrorStream. The bare MakeErrorStream does not have a 56 // Status operator. The net effect of that is that you 57 // have to call operator<< at least once or else you'll get a 58 // compile time error. 59 class MakeErrorStreamWithOutput { 60 public: MakeErrorStreamWithOutput(MakeErrorStream * error_stream)61 explicit MakeErrorStreamWithOutput(MakeErrorStream* error_stream) 62 : wrapped_error_stream_(error_stream) {} 63 64 template <typename T> 65 MakeErrorStreamWithOutput& operator<<(const T& value) { 66 *wrapped_error_stream_ << value; 67 return *this; 68 } 69 70 // Implicit cast operators to Status and StatusOr. 71 // Exactly one of these must be called exactly once before destruction. Status()72 operator Status() { return wrapped_error_stream_->GetStatus(); } 73 template <typename T> 74 operator xla::StatusOr<T>() { 75 return wrapped_error_stream_->GetStatus(); 76 } 77 78 private: 79 MakeErrorStream* wrapped_error_stream_; 80 81 TF_DISALLOW_COPY_AND_ASSIGN(MakeErrorStreamWithOutput); 82 }; 83 84 // When starting from an existing error status, this determines whether we'll 85 // append or prepend to that status's error message. 86 enum PriorMessageHandling { kAppendToPriorMessage, kPrependToPriorMessage }; 87 88 // Make an error with the given code. 89 template <typename ERROR_CODE_TYPE> MakeErrorStream(const char * file,int line,ERROR_CODE_TYPE code)90 MakeErrorStream(const char* file, int line, ERROR_CODE_TYPE code) 91 : impl_(new Impl(file, line, code, this, true)) {} 92 93 template <typename T> 94 MakeErrorStreamWithOutput& operator<<(const T& value) { 95 CheckNotDone(); 96 impl_->stream_ << value; 97 return impl_->make_error_stream_with_output_wrapper_; 98 } 99 100 // When this message is logged (see with_logging()), include the stack trace. with_log_stack_trace()101 MakeErrorStream& with_log_stack_trace() { 102 impl_->should_log_stack_trace_ = true; 103 return *this; 104 } 105 106 // Adds RET_CHECK failure text to error message. add_ret_check_failure(const char * condition)107 MakeErrorStreamWithOutput& add_ret_check_failure(const char* condition) { 108 return *this << "RET_CHECK failure (" << impl_->file_ << ":" << impl_->line_ 109 << ") " << condition << " "; 110 } 111 112 private: 113 class Impl { 114 public: 115 Impl(const char* file, int line, tensorflow::error::Code code, 116 MakeErrorStream* error_stream, bool is_logged_by_default = true); 117 Impl(const Status& status, PriorMessageHandling prior_message_handling, 118 const char* file, int line, MakeErrorStream* error_stream); 119 120 ~Impl(); 121 122 // This must be called exactly once before destruction. 123 Status GetStatus(); 124 125 void CheckNotDone() const; 126 127 private: 128 const char* file_; 129 int line_; 130 tensorflow::error::Code code_; 131 132 PriorMessageHandling prior_message_handling_ = kAppendToPriorMessage; 133 string prior_message_; 134 bool is_done_; // true after Status object has been returned 135 std::ostringstream stream_; 136 bool should_log_; 137 int log_severity_; 138 bool should_log_stack_trace_; 139 140 // Wrapper around the MakeErrorStream object that has a 141 // Status conversion. The first << operator called on 142 // MakeErrorStream will return this object, and only this object 143 // can implicitly convert to Status. The net effect of 144 // this is that you'll get a compile time error if you call 145 // MAKE_ERROR etc. without adding any output. 146 MakeErrorStreamWithOutput make_error_stream_with_output_wrapper_; 147 148 friend class MakeErrorStream; 149 TF_DISALLOW_COPY_AND_ASSIGN(Impl); 150 }; 151 152 void CheckNotDone() const; 153 154 // Returns the status. Used by MakeErrorStreamWithOutput. GetStatus()155 Status GetStatus() const { return impl_->GetStatus(); } 156 157 // Store the actual data on the heap to reduce stack frame sizes. 158 std::unique_ptr<Impl> impl_; 159 160 TF_DISALLOW_COPY_AND_ASSIGN(MakeErrorStream); 161 }; 162 163 // Provides a conversion to bool so that it can be used inside an if statement 164 // that declares a variable. 165 class StatusAdaptorForMacros { 166 public: StatusAdaptorForMacros(Status status)167 explicit StatusAdaptorForMacros(Status status) : status_(std::move(status)) {} 168 169 StatusAdaptorForMacros(const StatusAdaptorForMacros&) = delete; 170 StatusAdaptorForMacros& operator=(const StatusAdaptorForMacros&) = delete; 171 172 explicit operator bool() const { return TF_PREDICT_TRUE(status_.ok()); } 173 Consume()174 Status&& Consume() { return std::move(status_); } 175 176 private: 177 Status status_; 178 }; 179 180 } // namespace status_macros 181 } // namespace xla 182 183 #define TF_RET_CHECK(condition) \ 184 while (TF_PREDICT_FALSE(!(condition))) \ 185 return xla::status_macros::MakeErrorStream(__FILE__, __LINE__, \ 186 tensorflow::error::INTERNAL) \ 187 .with_log_stack_trace() \ 188 .add_ret_check_failure(#condition) 189 190 #endif // TENSORFLOW_COMPILER_XLA_STATUS_MACROS_H_ 191