• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright 2015 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_CORE_PLATFORM_STATUS_H_
17 #define TENSORFLOW_CORE_PLATFORM_STATUS_H_
18 
19 #include <functional>
20 #include <iosfwd>
21 #include <memory>
22 #include <string>
23 #include <unordered_map>
24 
25 #include "tensorflow/core/platform/logging.h"
26 #include "tensorflow/core/platform/macros.h"
27 #include "tensorflow/core/platform/stack_frame.h"
28 #include "tensorflow/core/platform/stringpiece.h"
29 #include "tensorflow/core/platform/types.h"
30 #include "tensorflow/core/protobuf/error_codes.pb.h"
31 
32 namespace tensorflow {
33 
34 #if defined(__clang__)
35 // Only clang supports warn_unused_result as a type annotation.
36 class TF_MUST_USE_RESULT Status;
37 #endif
38 
39 /// @ingroup core
40 /// Denotes success or failure of a call in Tensorflow.
41 class Status {
42  public:
43   /// Create a success status.
Status()44   Status() {}
45 
46   /// \brief Create a status with the specified error code and msg as a
47   /// human-readable string containing more detailed information.
Status(tensorflow::error::Code code,tensorflow::StringPiece msg)48   Status(tensorflow::error::Code code, tensorflow::StringPiece msg)
49       : Status(code, msg, {}) {}
50 
51   /// \brief Create a status with the specified error code, msg, and stack trace
52   /// as a human-readable string containing more detailed information.
53 #ifndef SWIG
54   Status(tensorflow::error::Code code, tensorflow::StringPiece msg,
55          std::vector<StackFrame>&& stack_trace);
56 #endif
57 
58   /// Copy the specified status.
59   Status(const Status& s);
60   Status& operator=(const Status& s);
61 #ifndef SWIG
62   Status(Status&& s) noexcept;
63   Status& operator=(Status&& s) noexcept;
64 #endif  // SWIG
65 
OK()66   static Status OK() { return Status(); }
67 
68   /// Returns true iff the status indicates success.
ok()69   bool ok() const { return (state_ == nullptr); }
70 
code()71   tensorflow::error::Code code() const {
72     return ok() ? tensorflow::error::OK : state_->code;
73   }
74 
error_message()75   const std::string& error_message() const {
76     return ok() ? empty_string() : state_->msg;
77   }
78 
stack_trace()79   const std::vector<StackFrame>& stack_trace() const {
80     return ok() ? empty_stack_trace() : state_->stack_trace;
81   }
82 
83   bool operator==(const Status& x) const;
84   bool operator!=(const Status& x) const;
85 
86   /// \brief If `ok()`, stores `new_status` into `*this`.  If `!ok()`,
87   /// preserves the current status, but may augment with additional
88   /// information about `new_status`.
89   ///
90   /// Convenient way of keeping track of the first error encountered.
91   /// Instead of:
92   ///   `if (overall_status.ok()) overall_status = new_status`
93   /// Use:
94   ///   `overall_status.Update(new_status);`
95   void Update(const Status& new_status);
96 
97   /// \brief Return a string representation of this status suitable for
98   /// printing. Returns the string `"OK"` for success.
99   ///
100   /// By default, it returns combination of the error code name, the message and
101   /// any associated payload messages. This string is designed simply to be
102   /// human readable and its exact format should not be load bearing. Do not
103   /// depend on the exact format of the result of `ToString()` which is subject
104   /// to change.
105   std::string ToString() const;
106 
107   // Ignores any errors. This method does nothing except potentially suppress
108   // complaints from any tools that are checking that errors are not dropped on
109   // the floor.
110   void IgnoreError() const;
111 
112   // The Payload-related APIs are cloned from absl::Status.
113   //
114   // Returns the payload of a status given its unique `type_url` key, if
115   // present. Returns an empty StringPiece if the status is ok, or if the key is
116   // not present.
117   tensorflow::StringPiece GetPayload(tensorflow::StringPiece type_url) const;
118 
119   // Sets the payload for a non-ok status using a `type_url` key, overwriting
120   // any existing payload for that `type_url`.
121   //
122   // This function does nothing if the Status is ok.
123   void SetPayload(tensorflow::StringPiece type_url,
124                   tensorflow::StringPiece payload);
125 
126   // Erases the payload corresponding to the `type_url` key.  Returns `true` if
127   // the payload was present.
128   bool ErasePayload(tensorflow::StringPiece type_url);
129 
130   // Returns all the payload information.
131   // Returns an empty result if status is ok.
132   const std::unordered_map<std::string, std::string> GetAllPayloads() const;
133 
134   // Copies all the payloads using the input and discards existing payloads.
135   // Does nothing if status is ok or 'payloads' is empty.
136   void ReplaceAllPayloads(
137       const std::unordered_map<std::string, std::string>& payloads);
138 
139  private:
140   static const std::string& empty_string();
141   static const std::vector<StackFrame>& empty_stack_trace();
142   struct State {
143     tensorflow::error::Code code;
144     std::string msg;
145     std::vector<StackFrame> stack_trace;
146     std::unordered_map<std::string, std::string> payloads;
147   };
148 
149   // OK status has a `NULL` state_.  Otherwise, `state_` points to
150   // a `State` structure containing the error code and message(s)
151   std::unique_ptr<State> state_;
152 
153   void SlowCopyFrom(const State* src);
154 };
155 
156 // Helper class to manage multiple child status values.
157 class StatusGroup {
158  public:
159   // Utility function to mark a Status as derived. By marking derived status,
160   // Derived status messages are ignored when reporting errors to end users.
161   static Status MakeDerived(const Status& s);
162   static bool IsDerived(const Status& s);
163 
164   // Enable warning and error log collection for appending to the aggregated
165   // status. This function may be called more than once.
166   static void ConfigureLogHistory();
167 
168   // Return a merged status with combined child status messages with a summary.
169   Status as_summary_status() const;
170   // Return a merged status with combined child status messages with
171   // concatenation.
172   Status as_concatenated_status() const;
173 
ok()174   bool ok() const { return ok_; }
175 
176   // Augment this group with the child status `status`.
177   void Update(const Status& status);
178 
179   // Attach recent warning and error log messages
180   void AttachLogMessages();
HasLogMessages()181   bool HasLogMessages() const { return !recent_logs_.empty(); }
182 
183  private:
184   bool ok_ = true;
185   size_t num_ok_ = 0;
186   std::vector<Status> children_;
187   std::vector<std::string> recent_logs_;  // recent warning and error logs
188 };
189 
Status(const Status & s)190 inline Status::Status(const Status& s)
191     : state_((s.state_ == nullptr) ? nullptr : new State(*s.state_)) {}
192 
193 inline Status& Status::operator=(const Status& s) {
194   // The following condition catches both aliasing (when this == &s),
195   // and the common case where both s and *this are ok.
196   if (state_ != s.state_) {
197     SlowCopyFrom(s.state_.get());
198   }
199   return *this;
200 }
201 
202 #ifndef SWIG
Status(Status && s)203 inline Status::Status(Status&& s) noexcept : state_(std::move(s.state_)) {}
204 
205 inline Status& Status::operator=(Status&& s) noexcept {
206   if (state_ != s.state_) {
207     state_ = std::move(s.state_);
208   }
209   return *this;
210 }
211 #endif  // SWIG
212 
213 inline bool Status::operator==(const Status& x) const {
214   return (this->state_ == x.state_) || (ToString() == x.ToString());
215 }
216 
217 inline bool Status::operator!=(const Status& x) const { return !(*this == x); }
218 
219 /// @ingroup core
220 std::ostream& operator<<(std::ostream& os, const Status& x);
221 
222 typedef std::function<void(const Status&)> StatusCallback;
223 
224 extern tensorflow::string* TfCheckOpHelperOutOfLine(
225     const ::tensorflow::Status& v, const char* msg);
226 
TfCheckOpHelper(::tensorflow::Status v,const char * msg)227 inline tensorflow::string* TfCheckOpHelper(::tensorflow::Status v,
228                                            const char* msg) {
229   if (v.ok()) return nullptr;
230   return TfCheckOpHelperOutOfLine(v, msg);
231 }
232 
233 #define TF_DO_CHECK_OK(val, level)                                \
234   while (auto _result = ::tensorflow::TfCheckOpHelper(val, #val)) \
235   LOG(level) << *(_result)
236 
237 #define TF_CHECK_OK(val) TF_DO_CHECK_OK(val, FATAL)
238 #define TF_QCHECK_OK(val) TF_DO_CHECK_OK(val, QFATAL)
239 
240 // DEBUG only version of TF_CHECK_OK.  Compiler still parses 'val' even in opt
241 // mode.
242 #ifndef NDEBUG
243 #define TF_DCHECK_OK(val) TF_CHECK_OK(val)
244 #else
245 #define TF_DCHECK_OK(val) \
246   while (false && (::tensorflow::Status::OK() == (val))) LOG(FATAL)
247 #endif
248 
249 }  // namespace tensorflow
250 
251 #endif  // TENSORFLOW_CORE_PLATFORM_STATUS_H_
252