• 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   std::string ToString() const;
100 
101   // Ignores any errors. This method does nothing except potentially suppress
102   // complaints from any tools that are checking that errors are not dropped on
103   // the floor.
104   void IgnoreError() const;
105 
106   // The Payload-related APIs are cloned from absl::Status.
107   //
108   // Returns the payload of a status given its unique `type_url` key, if
109   // present. Returns an empty StringPiece if the status is ok, or if the key is
110   // not present.
111   tensorflow::StringPiece GetPayload(tensorflow::StringPiece type_url) const;
112 
113   // Sets the payload for a non-ok status using a `type_url` key, overwriting
114   // any existing payload for that `type_url`.
115   //
116   // NOTE: This function does nothing if the Status is ok.
117   void SetPayload(tensorflow::StringPiece type_url,
118                   tensorflow::StringPiece payload);
119 
120   // Erases the payload corresponding to the `type_url` key.  Returns `true` if
121   // the payload was present.
122   bool ErasePayload(tensorflow::StringPiece type_url);
123 
124  private:
125   static const std::string& empty_string();
126   static const std::vector<StackFrame>& empty_stack_trace();
127   struct State {
128     tensorflow::error::Code code;
129     std::string msg;
130     std::vector<StackFrame> stack_trace;
131     std::unordered_map<std::string, std::string> payloads;
132   };
133 
134   // OK status has a `NULL` state_.  Otherwise, `state_` points to
135   // a `State` structure containing the error code and message(s)
136   std::unique_ptr<State> state_;
137 
138   void SlowCopyFrom(const State* src);
139 };
140 
141 // Helper class to manage multiple child status values.
142 class StatusGroup {
143  public:
144   // Utility function to mark a Status as derived. By marking derived status,
145   // Derived status messages are ignored when reporting errors to end users.
146   static Status MakeDerived(const Status& s);
147   static bool IsDerived(const Status& s);
148 
149   // Enable warning and error log collection for appending to the aggregated
150   // status. This function may be called more than once.
151   static void ConfigureLogHistory();
152 
153   // Return a merged status with combined child status messages with a summary.
154   Status as_summary_status() const;
155   // Return a merged status with combined child status messages with
156   // concatenation.
157   Status as_concatenated_status() const;
158 
ok()159   bool ok() const { return ok_; }
160 
161   // Augment this group with the child status `status`.
162   void Update(const Status& status);
163 
164   // Attach recent warning and error log messages
165   void AttachLogMessages();
HasLogMessages()166   bool HasLogMessages() const { return !recent_logs_.empty(); }
167 
168  private:
169   bool ok_ = true;
170   size_t num_ok_ = 0;
171   std::vector<Status> children_;
172   std::vector<std::string> recent_logs_;  // recent warning and error logs
173 };
174 
Status(const Status & s)175 inline Status::Status(const Status& s)
176     : state_((s.state_ == nullptr) ? nullptr : new State(*s.state_)) {}
177 
178 inline Status& Status::operator=(const Status& s) {
179   // The following condition catches both aliasing (when this == &s),
180   // and the common case where both s and *this are ok.
181   if (state_ != s.state_) {
182     SlowCopyFrom(s.state_.get());
183   }
184   return *this;
185 }
186 
187 #ifndef SWIG
Status(Status && s)188 inline Status::Status(Status&& s) noexcept : state_(std::move(s.state_)) {}
189 
190 inline Status& Status::operator=(Status&& s) noexcept {
191   if (state_ != s.state_) {
192     state_ = std::move(s.state_);
193   }
194   return *this;
195 }
196 #endif  // SWIG
197 
198 inline bool Status::operator==(const Status& x) const {
199   return (this->state_ == x.state_) || (ToString() == x.ToString());
200 }
201 
202 inline bool Status::operator!=(const Status& x) const { return !(*this == x); }
203 
204 /// @ingroup core
205 std::ostream& operator<<(std::ostream& os, const Status& x);
206 
207 typedef std::function<void(const Status&)> StatusCallback;
208 
209 extern tensorflow::string* TfCheckOpHelperOutOfLine(
210     const ::tensorflow::Status& v, const char* msg);
211 
TfCheckOpHelper(::tensorflow::Status v,const char * msg)212 inline tensorflow::string* TfCheckOpHelper(::tensorflow::Status v,
213                                            const char* msg) {
214   if (v.ok()) return nullptr;
215   return TfCheckOpHelperOutOfLine(v, msg);
216 }
217 
218 #define TF_DO_CHECK_OK(val, level)                                \
219   while (auto _result = ::tensorflow::TfCheckOpHelper(val, #val)) \
220   LOG(level) << *(_result)
221 
222 #define TF_CHECK_OK(val) TF_DO_CHECK_OK(val, FATAL)
223 #define TF_QCHECK_OK(val) TF_DO_CHECK_OK(val, QFATAL)
224 
225 // DEBUG only version of TF_CHECK_OK.  Compiler still parses 'val' even in opt
226 // mode.
227 #ifndef NDEBUG
228 #define TF_DCHECK_OK(val) TF_CHECK_OK(val)
229 #else
230 #define TF_DCHECK_OK(val) \
231   while (false && (::tensorflow::Status::OK() == (val))) LOG(FATAL)
232 #endif
233 
234 }  // namespace tensorflow
235 
236 #endif  // TENSORFLOW_CORE_PLATFORM_STATUS_H_
237