xref: /aosp_15_r20/external/tensorflow/tensorflow/core/profiler/internal/tfprof_timeline.h (revision b6fb3261f9314811a0f4371741dbb8839866f948)
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