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