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