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 #include "tensorflow/core/lib/core/status.h"
17 #include <stdio.h>
18 #include <map>
19 #include "tensorflow/core/lib/core/error_codes.pb.h"
20 #include "tensorflow/core/lib/strings/str_util.h"
21 #include "tensorflow/core/lib/strings/strcat.h"
22 #include "tensorflow/core/lib/strings/stringprintf.h"
23 
24 namespace tensorflow {
25 
Status(tensorflow::error::Code code,StringPiece msg)26 Status::Status(tensorflow::error::Code code, StringPiece msg) {
27   assert(code != tensorflow::error::OK);
28   state_ = std::unique_ptr<State>(new State);
29   state_->code = code;
30   state_->msg = string(msg);
31 }
32 
Update(const Status & new_status)33 void Status::Update(const Status& new_status) {
34   if (ok()) {
35     *this = new_status;
36   }
37 }
38 
SlowCopyFrom(const State * src)39 void Status::SlowCopyFrom(const State* src) {
40   if (src == nullptr) {
41     state_ = nullptr;
42   } else {
43     state_ = std::unique_ptr<State>(new State(*src));
44   }
45 }
46 
empty_string()47 const string& Status::empty_string() {
48   static string* empty = new string;
49   return *empty;
50 }
51 
error_name(error::Code code)52 string error_name(error::Code code) {
53   switch (code) {
54     case tensorflow::error::OK:
55       return "OK";
56       break;
57     case tensorflow::error::CANCELLED:
58       return "Cancelled";
59       break;
60     case tensorflow::error::UNKNOWN:
61       return "Unknown";
62       break;
63     case tensorflow::error::INVALID_ARGUMENT:
64       return "Invalid argument";
65       break;
66     case tensorflow::error::DEADLINE_EXCEEDED:
67       return "Deadline exceeded";
68       break;
69     case tensorflow::error::NOT_FOUND:
70       return "Not found";
71       break;
72     case tensorflow::error::ALREADY_EXISTS:
73       return "Already exists";
74       break;
75     case tensorflow::error::PERMISSION_DENIED:
76       return "Permission denied";
77       break;
78     case tensorflow::error::UNAUTHENTICATED:
79       return "Unauthenticated";
80       break;
81     case tensorflow::error::RESOURCE_EXHAUSTED:
82       return "Resource exhausted";
83       break;
84     case tensorflow::error::FAILED_PRECONDITION:
85       return "Failed precondition";
86       break;
87     case tensorflow::error::ABORTED:
88       return "Aborted";
89       break;
90     case tensorflow::error::OUT_OF_RANGE:
91       return "Out of range";
92       break;
93     case tensorflow::error::UNIMPLEMENTED:
94       return "Unimplemented";
95       break;
96     case tensorflow::error::INTERNAL:
97       return "Internal";
98       break;
99     case tensorflow::error::UNAVAILABLE:
100       return "Unavailable";
101       break;
102     case tensorflow::error::DATA_LOSS:
103       return "Data loss";
104       break;
105     default:
106       char tmp[30];
107       snprintf(tmp, sizeof(tmp), "Unknown code(%d)", static_cast<int>(code));
108       return tmp;
109       break;
110   }
111 }
112 
ToString() const113 string Status::ToString() const {
114   if (state_ == nullptr) {
115     return "OK";
116   } else {
117     string result(error_name(code()));
118     result += ": ";
119     result += state_->msg;
120     return result;
121   }
122 }
123 
IgnoreError() const124 void Status::IgnoreError() const {
125   // no-op
126 }
127 
operator <<(std::ostream & os,const Status & x)128 std::ostream& operator<<(std::ostream& os, const Status& x) {
129   os << x.ToString();
130   return os;
131 }
132 
TfCheckOpHelperOutOfLine(const::tensorflow::Status & v,const char * msg)133 string* TfCheckOpHelperOutOfLine(const ::tensorflow::Status& v,
134                                  const char* msg) {
135   string r("Non-OK-status: ");
136   r += msg;
137   r += " status: ";
138   r += v.ToString();
139   // Leaks string but this is only to be used in a fatal error message
140   return new string(r);
141 }
142 
Update(const Status & s)143 void StatusGroup::Update(const Status& s) {
144   if (s.ok()) {
145     ++num_ok_;
146   } else {
147     ok_ = false;
148     children_.push_back(s);
149   }
150 }
151 
152 const int kMaxChildMessageSize = 2048;
153 
as_status() const154 Status StatusGroup::as_status() const {
155   if (ok_) {
156     return Status::OK();
157   }
158 
159   // Reduce verbosity when handling duplicate messages. If there is only a
160   // single message, or all messages have similar content, then return the
161   // longest status message.
162   std::vector<Status> sorted_children(children_);
163   std::sort(sorted_children.begin(), sorted_children.end(),
164             [](const Status& a, const Status& b) {
165               return a.error_message().length() > b.error_message().length();
166             });
167   bool single_status = true;
168   for (const auto& s : sorted_children) {
169     if (s.code() != sorted_children[0].code() ||
170         sorted_children[0].error_message().find(s.error_message()) ==
171             string::npos) {
172       single_status = false;
173       break;
174     }
175   }
176 
177   if (single_status) {
178     return sorted_children[0];
179   }
180 
181   std::vector<string> fmt;
182 
183   // Compute a final output string with status codes sorted by frequency in
184   // increasing order.  This prefers more "interesting" messages over child
185   // messages that may come from cancellation.
186   std::map<error::Code, std::vector<Status>> code_to_status;
187   for (const Status& s : children_) {
188     code_to_status[s.code()].push_back(s);
189   }
190 
191   std::vector<std::pair<error::Code, int>> count_vec;
192   count_vec.reserve(code_to_status.size());
193   for (auto& p : code_to_status) {
194     count_vec.push_back(std::make_pair(p.first, p.second.size()));
195   }
196 
197   std::sort(
198       count_vec.begin(), count_vec.end(),
199       [](const std::pair<error::Code, int>& a,
200          const std::pair<error::Code, int>& b) { return a.second < b.second; });
201 
202   fmt.push_back(
203       strings::Printf("Combined status information from %zu operations:\n",
204                       num_ok_ + children_.size()));
205 
206   for (const auto& p : count_vec) {
207     // Deduplicate error messages
208     std::map<string, int> child_errors;
209     for (const Status& s : code_to_status[p.first]) {
210       ++child_errors[s.error_message()];
211     }
212 
213     string child_fmt;
214     for (auto& m : child_errors) {
215       child_fmt.append(strings::Printf(
216           "  %s [%dx]",
217           str_util::StringReplace(m.first, "\n", "\n  ", true).c_str(),
218           m.second));
219       child_fmt.append("\n");
220     }
221     // Strip last newline.
222     child_fmt = child_fmt.substr(0, child_fmt.size() - 1);
223 
224     if (child_fmt.size() > kMaxChildMessageSize) {
225       child_fmt =
226           strings::StrCat(child_fmt.substr(0, kMaxChildMessageSize), "...");
227     }
228     fmt.push_back(strings::Printf("Status code: %s [%dx]\n%s",
229                                   error_name(p.first).c_str(), p.second,
230                                   child_fmt.c_str()));
231   }
232 
233   fmt.push_back(strings::Printf("(%zd successful operations.)", num_ok_));
234 
235   // TODO(power): use the least-frequently occurring status for the return code
236   return Status(children_[0].code(), str_util::Join(fmt, "\n"));
237 }
238 
239 }  // namespace tensorflow
240