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