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 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 33 void Status::Update(const Status& new_status) { 34 if (ok()) { 35 *this = new_status; 36 } 37 } 38 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 47 const string& Status::empty_string() { 48 static string* empty = new string; 49 return *empty; 50 } 51 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 113 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 124 void Status::IgnoreError() const { 125 // no-op 126 } 127 128 std::ostream& operator<<(std::ostream& os, const Status& x) { 129 os << x.ToString(); 130 return os; 131 } 132 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 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 154 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