Home | History | Annotate | Download | only in core
      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