Home | History | Annotate | Download | only in debug
      1 /* Copyright 2016 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_DEBUG_NODE_INSERTER_H_
     17 #define TENSORFLOW_DEBUG_NODE_INSERTER_H_
     18 
     19 #include <unordered_map>
     20 #include <vector>
     21 
     22 #include "tensorflow/core/common_runtime/debugger_state_interface.h"
     23 #include "tensorflow/core/common_runtime/device.h"
     24 #include "tensorflow/core/graph/graph.h"
     25 #include "tensorflow/core/lib/core/status.h"
     26 #include "tensorflow/core/platform/protobuf.h"
     27 #include "tensorflow/core/protobuf/debug.pb.h"
     28 
     29 namespace tensorflow {
     30 
     31 class DebugNodeInserter {
     32  public:
     33   // EXPERIMENTAL: Insert special debug ops (e.g., DebugIdentity) to graph for
     34   // debugging. Currently, such ops need to take exactly one input and has the
     35   // string attribute "tensor_name" to indicate what tensor it watches.
     36   // For example, before the node insertion, the graph may look like:
     37   //
     38   // A:0 -----------1----------> B
     39   //      |
     40   //      ---------2-----------> C
     41   //
     42   // wherein the output slot 0 of node A feeds as the input to nodes B through
     43   // edge 1 and to node C through edge 2.
     44   // After the node insertion, assuming both B and C have non-Ref input, the
     45   // graph becomes:
     46   // A:0 ---3---> Copy -----------4----------> B
     47   //                       |
     48   //                       ---------5--------> C
     49   //                       |
     50   //                       ---------6--------> X
     51   //
     52   // If a node (e.g., B) has Ref input, the graph becomes:
     53   //
     54   //           --------------------------------> B
     55   //           |
     56   // A:0 ---3-----> Copy -----------4----------> C
     57   //                       |
     58   //                       -----------5--------> X
     59   //
     60   // In other words, we do not feed Refs to deep-copies to downstream nodes.
     61   //
     62   // Copy is the inserted deep-copy node that copies the input tensor on-device
     63   // (e.g., CPU-to-CPU or GPU-to-GPU deep copy) that reduces the likelihood of
     64   // racy updates during the debug watches. X is the newly created debug node
     65   // that transforms the input (copy of the watched tensor) into a debug signal.
     66   //
     67   // DebugIdentity is the simplest debugging paradigm, in which the debug signal
     68   // (i.e., X:0) equals the tensor itself. More sophisticated debug ops can be
     69   // used to transform the tensor into other debug signals. An example is the
     70   // DebugNanCounter op.
     71   //
     72   // If the nodes (A, B and C) are located on GPU and the edges from A to B or C
     73   // is HOST_MEMORY, then the CopyHost op will be used instead of the Copy op.
     74   static Status InsertNodes(
     75       const protobuf::RepeatedPtrField<DebugTensorWatch>& watches, Graph* graph,
     76       Device* device);
     77 
     78   // Set the parallel_iterations attribute of TensorFlow while loops
     79   // (specifically the nodes for which IsEnter() returns true) to 1 to prevent
     80   // any node from being executed multiple times concurrently and
     81   // generating temporally-overlapping debug Tensor dumps.
     82   static void DeparallelizeWhileLoops(Graph* graph, Device* device);
     83 
     84   // Get canonical name of a copy node.
     85   static const string GetCopyNodeName(const string& node_name,
     86                                       const int output_slot);
     87 
     88   // Get canonical name of a debug node.
     89   static const string GetDebugNodeName(const string& tensor_name,
     90                                        const int debug_op_num,
     91                                        const string& debug_op_name);
     92 
     93  private:
     94   static Status CreateCopyNode(
     95       Graph* graph, const DeviceType device_type, const bool is_host_memory,
     96       const string& src_node_name, const int src_output, const DataType src_dt,
     97       const string& tensor_name, const std::vector<string>& debug_ops,
     98       const std::vector<string>& debug_urls, Node** copy_node);
     99 
    100   // Parse the debug_op_name string to extract proper op name and attributes.
    101   // debug_op_name can be the proper op name only, e.g., "DebugNumericSummary".
    102   // It can also contain customizable keys and values. Each key-value pair is
    103   // connected with an equal sign ("="). Multiple key-value pairs are separated
    104   // with semicolons (";"), which optional whitespace in between, e.g.,
    105   // "DebugNumericSummary(mute_if_healthy=true, lower_bound=-100.0)".
    106   static Status ParseDebugOpName(
    107       const string& debug_op_name, string* debug_op_name_proper,
    108       std::unordered_map<string, string>* attributes);
    109 
    110   static Status SetDebugNodeAttributes(
    111       Node* debug_node, const std::unordered_map<string, string>& attributes);
    112 
    113   static Status CreateDebugNode(Graph* graph, const Device& device,
    114                                 const string& src_copy_node_name,
    115                                 const DataType src_dt,
    116                                 const string& tensor_name,
    117                                 const std::vector<string>& debug_urls,
    118                                 const int debug_op_num,
    119                                 const string& debug_op_name, Node** debug_node);
    120   // TODO(cais): Cut down the number of args to this method.
    121 
    122   friend class DebugGraphUtilsTest;
    123 };
    124 }  // namespace tensorflow
    125 
    126 #endif  // TENSORFLOW_DEBUG_NODE_INSERTER_H_
    127