Home | History | Annotate | Download | only in internal
      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_CORE_PROFILER_INTERNAL_TFPROF_TIMELINE_H_
     17 #define TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_TIMELINE_H_
     18 
     19 #include "include/json/json.h"
     20 #include "tensorflow/core/framework/graph.pb.h"
     21 #include "tensorflow/core/framework/step_stats.pb.h"
     22 #include "tensorflow/core/lib/strings/strcat.h"
     23 #include "tensorflow/core/profiler/internal/tfprof_node_show.h"
     24 #include "tensorflow/core/protobuf/config.pb.h"
     25 
     26 namespace tensorflow {
     27 namespace tfprof {
     28 
     29 typedef std::map<string, string> Event;
     30 
     31 // Class for generating timeline json output.
     32 class ChromeTraceFormatter {
     33  public:
     34   ChromeTraceFormatter() {}
     35   // The following methods creates timeline nodes. See chrome tracing format
     36   // document for details.
     37   Json::Value CreateEvent(const string& ph, const string& category,
     38                           const string& name, int64 pid, int64 tid, int64 ts);
     39 
     40   void EmitPID(const string& name, int64 pid);
     41 
     42   void EmitRegion(int64 ts, int64 duration, int64 pid, int64 tid,
     43                   const string& category, const string& name, Json::Value args);
     44 
     45   void EmitFlowStart(const string& name, int64 ts, int64 pid, int64 tid,
     46                      int64 flow_id);
     47 
     48   void EmitFlowEnd(const string& name, int64 ts, int64 pid, int64 tid,
     49                    int64 flow_id);
     50 
     51   void EmitCounter(const string& category, const string& name, int64 pid,
     52                    int64 ts, const string& device, int64 bytes,
     53                    const std::map<int64, std::vector<string>>& tensor_mem);
     54 
     55   string Format();
     56 
     57  private:
     58   // A event is a visualization unit in timeline.
     59   std::vector<Json::Value> events_;
     60   std::vector<Json::Value> metadata_;
     61 };
     62 
     63 // A process (time series of events) in the timeline.
     64 class Process {
     65  public:
     66   Process(const string& device, int64 pid) : device(device), pid(pid) {}
     67 
     68   // Each lane is a map from start_time to end_time.
     69   std::vector<std::map<int64, int64>> lanes;
     70   // device for the time series.
     71   string device;
     72   // unique id for the time series.
     73   int64 pid;
     74 };
     75 
     76 class TimeNode {
     77  public:
     78   TimeNode(Process* process, GraphNode* node, int64 start_micros,
     79            int64 exec_micros)
     80       : process(process),
     81         node(node),
     82         start_micros(start_micros),
     83         exec_micros(exec_micros),
     84         tid(-1) {}
     85   virtual ~TimeNode() {}
     86 
     87   const string& name() { return node->name(); }
     88 
     89   Process* process;
     90   GraphNode* node;
     91   int64 start_micros;
     92   int64 exec_micros;
     93   int64 tid;
     94   std::vector<TimeNode*> next_tnodes;
     95 };
     96 
     97 // Tracking the memory based on the op input/output, temporary bytes and
     98 // persistent bytes.
     99 // Currently, we calculate a "predicted" memory, but do not use it for display.
    100 // The displayed memory timeline is directly from the TensorFlow allocator,
    101 // which is the groundtruth.
    102 class MemoryTracker {
    103  public:
    104   class Device {
    105    public:
    106     // map from tensor name to a pair of <alloc time, bytes_in_use>.
    107     std::map<string, std::map<int64, int64>> tensor_allocs;
    108     // ground truth memory stats. time->bytes.
    109     std::map<int64, int64> allocations;
    110     // tracked allocations, might miss some bytes.
    111     std::map<int64, int64> tracked_allocations;
    112   };
    113 
    114   void TrackNode(int64 step, const GraphNode* node);
    115 
    116   const std::map<string, Device>& devices() const { return devices_; }
    117 
    118  private:
    119   std::map<string, Device> devices_;
    120 };
    121 
    122 class Timeline {
    123  public:
    124   Timeline(int64 step, const string& outfile)
    125       : step_(step), outfile_(outfile) {}
    126   ~Timeline() {}
    127 
    128   int64 step() const { return step_; }
    129   void SetStep(int64 step) { step_ = step; }
    130 
    131   void GenerateGraphTimeline(const std::vector<GraphNode*>& gnodes);
    132 
    133   void GenerateScopeTimeline(const ScopeNode* node);
    134 
    135   void GenerateCodeTimeline(const CodeNode* node);
    136 
    137  private:
    138   void TrackNode(const GraphNode* node) { mem_tracker_.TrackNode(step_, node); }
    139 
    140   void OutputTimeline();
    141 
    142   template <typename Node>
    143   void EmitTreeNode(const Node* node, int64 start_time, int64 duration,
    144                     int64 depth, std::set<int64>* visited_depth) {
    145     if (visited_depth->find(depth) == visited_depth->end()) {
    146       chrome_formatter_.EmitPID(strings::StrCat("Scope:", depth), depth);
    147       visited_depth->insert(depth);
    148     }
    149 
    150     Json::Value args(Json::objectValue);
    151     args["name"] = Json::Value(node->name());
    152     args["op"] = Json::Value(node->name());
    153     chrome_formatter_.EmitRegion(start_time, duration, depth, 0, "Op",
    154                                  node->name(), args);
    155 
    156     int64 total_micros = 0;
    157     int64 c_start_time = start_time;
    158     for (const Node* child : node->show_children) {
    159       int64 total_exec_micros = child->proto().total_exec_micros();
    160       if (total_exec_micros <= 0) {
    161         continue;
    162       }
    163       EmitTreeNode(child, c_start_time, total_exec_micros, depth + 1,
    164                    visited_depth);
    165       c_start_time += total_exec_micros;
    166       total_micros += total_exec_micros;
    167     }
    168     CHECK(total_micros <= duration) << node->name() << " parent:" << duration
    169                                     << " children:" << total_micros;
    170   }
    171 
    172   void AllocateTimeNodes(GraphNode* gnode);
    173 
    174   void AllocateLanes();
    175 
    176   int64 AllocatePID();
    177 
    178   int64 step_;
    179   const string outfile_;
    180   int64 next_pid_ = 0;
    181   MemoryTracker mem_tracker_;
    182   ChromeTraceFormatter chrome_formatter_;
    183   std::map<string, int64> device_pids_;
    184 
    185   std::map<string, std::unique_ptr<Process>> process_;
    186   std::map<int64, std::map<int64, std::map<int64, TimeNode*>>> alloc_nodes_;
    187   std::map<string, std::map<int64, std::unique_ptr<TimeNode>>> tnodes_;
    188 };
    189 
    190 }  // namespace tfprof
    191 }  // namespace tensorflow
    192 
    193 #endif  // TENSORFLOW_CORE_PROFILER_INTERNAL_TFPROF_TIMELINE_H_
    194