1 /* Copyright 2019 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 #ifndef TENSORFLOW_CORE_PROFILER_UTILS_XPLANE_BUILDER_H_
16 #define TENSORFLOW_CORE_PROFILER_UTILS_XPLANE_BUILDER_H_
17
18 #include <stddef.h>
19
20 #include <string>
21 #include <utility>
22
23 #include "absl/container/flat_hash_map.h"
24 #include "absl/strings/numbers.h"
25 #include "absl/strings/string_view.h"
26 #include "tensorflow/core/platform/macros.h"
27 #include "tensorflow/core/platform/protobuf.h"
28 #include "tensorflow/core/platform/types.h"
29 #include "tensorflow/core/profiler/protobuf/xplane.pb.h"
30 #include "tensorflow/core/profiler/utils/time_utils.h"
31 #include "tensorflow/core/profiler/utils/timespan.h"
32
33 namespace tensorflow {
34 namespace profiler {
35
36 class XPlaneBuilder;
37
38 template <typename T>
39 class XStatsBuilder {
40 public:
XStatsBuilder(T * stats_owner,XPlaneBuilder * stats_metadata_owner)41 explicit XStatsBuilder(T* stats_owner, XPlaneBuilder* stats_metadata_owner)
42 : stats_owner_(stats_owner),
43 stats_metadata_owner_(stats_metadata_owner) {}
44
AddStatValue(const XStatMetadata & metadata,uint32 value)45 void AddStatValue(const XStatMetadata& metadata, uint32 value) {
46 AddStat(metadata)->set_uint64_value(value);
47 }
AddStatValue(const XStatMetadata & metadata,unsigned long value)48 void AddStatValue(const XStatMetadata& metadata,
49 unsigned long value) { // NOLINT
50 AddStat(metadata)->set_uint64_value(value);
51 }
AddStatValue(const XStatMetadata & metadata,unsigned long long value)52 void AddStatValue(const XStatMetadata& metadata,
53 unsigned long long value) { // NOLINT
54 AddStat(metadata)->set_uint64_value(value);
55 }
AddStatValue(const XStatMetadata & metadata,int32 value)56 void AddStatValue(const XStatMetadata& metadata, int32 value) {
57 AddStat(metadata)->set_int64_value(value);
58 }
AddStatValue(const XStatMetadata & metadata,long value)59 void AddStatValue(const XStatMetadata& metadata, long value) { // NOLINT
60 AddStat(metadata)->set_int64_value(value);
61 }
AddStatValue(const XStatMetadata & metadata,long long value)62 void AddStatValue(const XStatMetadata& metadata, long long value) { // NOLINT
63 AddStat(metadata)->set_int64_value(value);
64 }
AddStatValue(const XStatMetadata & metadata,double value)65 void AddStatValue(const XStatMetadata& metadata, double value) {
66 AddStat(metadata)->set_double_value(value);
67 }
AddStatValue(const XStatMetadata & metadata,absl::string_view value)68 void AddStatValue(const XStatMetadata& metadata, absl::string_view value) {
69 AddStat(metadata)->set_str_value(std::string(value));
70 }
AddStatValue(const XStatMetadata & metadata,std::string && value)71 void AddStatValue(const XStatMetadata& metadata, std::string&& value) {
72 AddStat(metadata)->set_str_value(std::move(value));
73 }
AddStatValue(const XStatMetadata & metadata,const XStatMetadata & value)74 void AddStatValue(const XStatMetadata& metadata, const XStatMetadata& value) {
75 AddStat(metadata)->set_ref_value(value.id());
76 }
AddStatValue(const XStatMetadata & metadata,const protobuf::MessageLite & proto)77 void AddStatValue(const XStatMetadata& metadata,
78 const protobuf::MessageLite& proto) {
79 auto* bytes = AddStat(metadata)->mutable_bytes_value();
80 proto.SerializeToString(bytes);
81 }
82
83 // Adds a stat by copying a stat from another XPlane. Does not check if a stat
84 // with the same metadata already exists in the event. To avoid duplicated
85 // stats, use the variant below.
AddStat(const XStatMetadata & metadata,const XStat & src_stat,const XPlane & src_plane)86 void AddStat(const XStatMetadata& metadata, const XStat& src_stat,
87 const XPlane& src_plane) {
88 CopyStatValue(src_stat, src_plane, AddStat(metadata));
89 }
90 // Same as above but overrides an existing stat with the same metadata.
SetOrAddStat(const XStatMetadata & metadata,const XStat & src_stat,const XPlane & src_plane)91 void SetOrAddStat(const XStatMetadata& metadata, const XStat& src_stat,
92 const XPlane& src_plane) {
93 CopyStatValue(src_stat, src_plane, FindOrAddStat(metadata));
94 }
95
ParseAndAddStatValue(const XStatMetadata & metadata,absl::string_view value)96 void ParseAndAddStatValue(const XStatMetadata& metadata,
97 absl::string_view value) {
98 int64 int_value;
99 uint64 uint_value;
100 double double_value;
101 if (absl::SimpleAtoi(value, &int_value)) {
102 AddStatValue(metadata, int_value);
103 } else if (absl::SimpleAtoi(value, &uint_value)) {
104 AddStatValue(metadata, uint_value);
105 } else if (absl::SimpleAtod(value, &double_value)) {
106 AddStatValue(metadata, double_value);
107 } else {
108 AddStatValue(metadata, GetOrCreateStatMetadata(value));
109 }
110 }
111
ReserveStats(size_t num_stats)112 void ReserveStats(size_t num_stats) {
113 stats_owner_->mutable_stats()->Reserve(num_stats);
114 }
115
116 private:
AddStat(const XStatMetadata & metadata)117 XStat* AddStat(const XStatMetadata& metadata) {
118 XStat* stat = stats_owner_->add_stats();
119 stat->set_metadata_id(metadata.id());
120 return stat;
121 }
122
FindOrAddStat(const XStatMetadata & metadata)123 XStat* FindOrAddStat(const XStatMetadata& metadata) {
124 for (auto& stat : *stats_owner_->mutable_stats()) {
125 if (stat.metadata_id() == metadata.id()) {
126 return &stat;
127 }
128 }
129 return AddStat(metadata);
130 }
131
CopyStatValue(const XStat & src_stat,const XPlane & src_plane,XStat * dst_stat)132 void CopyStatValue(const XStat& src_stat, const XPlane& src_plane,
133 XStat* dst_stat) {
134 switch (src_stat.value_case()) {
135 case XStat::VALUE_NOT_SET:
136 break;
137 case XStat::kInt64Value:
138 dst_stat->set_int64_value(src_stat.int64_value());
139 break;
140 case XStat::kUint64Value:
141 dst_stat->set_uint64_value(src_stat.uint64_value());
142 break;
143 case XStat::kDoubleValue:
144 dst_stat->set_double_value(src_stat.double_value());
145 break;
146 case XStat::kStrValue:
147 dst_stat->set_str_value(src_stat.str_value());
148 break;
149 case XStat::kRefValue: {
150 const auto& stat_metadata_by_id = src_plane.stat_metadata();
151 const auto it = stat_metadata_by_id.find(src_stat.ref_value());
152 if (TF_PREDICT_TRUE(it != stat_metadata_by_id.end())) {
153 absl::string_view value = it->second.name();
154 dst_stat->set_ref_value(GetOrCreateStatMetadata(value).id());
155 }
156 break;
157 }
158 case XStat::kBytesValue:
159 dst_stat->set_bytes_value(src_stat.bytes_value());
160 break;
161 }
162 }
163
164 const XStatMetadata& GetOrCreateStatMetadata(absl::string_view value);
165
166 T* stats_owner_;
167 XPlaneBuilder* stats_metadata_owner_;
168 };
169
170 class XEventBuilder : public XStatsBuilder<XEvent> {
171 public:
XEventBuilder(const XLine * line,XPlaneBuilder * plane,XEvent * event)172 XEventBuilder(const XLine* line, XPlaneBuilder* plane, XEvent* event)
173 : XStatsBuilder<XEvent>(event, plane), line_(line), event_(event) {}
174
OffsetPs()175 int64 OffsetPs() const { return event_->offset_ps(); }
MetadataId()176 int64 MetadataId() const { return event_->metadata_id(); }
177
SetOffsetPs(int64 offset_ps)178 void SetOffsetPs(int64 offset_ps) { event_->set_offset_ps(offset_ps); }
179
SetOffsetNs(int64 offset_ns)180 void SetOffsetNs(int64 offset_ns) { SetOffsetPs(NanosToPicos(offset_ns)); }
181
SetTimestampNs(int64 timestamp_ns)182 void SetTimestampNs(int64 timestamp_ns) {
183 SetOffsetPs(NanosToPicos(timestamp_ns - line_->timestamp_ns()));
184 }
185
SetNumOccurrences(int64 num_occurrences)186 void SetNumOccurrences(int64 num_occurrences) {
187 event_->set_num_occurrences(num_occurrences);
188 }
189
SetDurationPs(int64 duration_ps)190 void SetDurationPs(int64 duration_ps) {
191 event_->set_duration_ps(duration_ps);
192 }
SetDurationNs(int64 duration_ns)193 void SetDurationNs(int64 duration_ns) {
194 SetDurationPs(NanosToPicos(duration_ns));
195 }
196
SetEndTimestampPs(int64 end_timestamp_ps)197 void SetEndTimestampPs(int64 end_timestamp_ps) {
198 SetDurationPs(end_timestamp_ps - PicosToNanos(line_->timestamp_ns()) -
199 event_->offset_ps());
200 }
SetEndTimestampNs(int64 end_timestamp_ns)201 void SetEndTimestampNs(int64 end_timestamp_ns) {
202 SetDurationPs(NanosToPicos(end_timestamp_ns - line_->timestamp_ns()) -
203 event_->offset_ps());
204 }
205
GetTimespan()206 Timespan GetTimespan() const {
207 return Timespan(NanosToPicos(line_->timestamp_ns()) + event_->offset_ps(),
208 event_->duration_ps());
209 }
210
211 private:
212 const XLine* line_;
213 XEvent* event_;
214 };
215
216 class XLineBuilder {
217 public:
XLineBuilder(XLine * line,XPlaneBuilder * plane)218 explicit XLineBuilder(XLine* line, XPlaneBuilder* plane)
219 : line_(line), plane_(plane) {}
220
221 // Returns the owner plane.
Plane()222 XPlaneBuilder* Plane() const { return plane_; }
223
Id()224 int64 Id() const { return line_->id(); }
SetId(int64 id)225 void SetId(int64 id) { line_->set_id(id); }
226
NumEvents()227 int64 NumEvents() const { return line_->events_size(); }
228
Name()229 absl::string_view Name() const { return line_->name(); }
SetName(absl::string_view name)230 void SetName(absl::string_view name) { line_->set_name(std::string(name)); }
231
SetNameIfEmpty(absl::string_view name)232 void SetNameIfEmpty(absl::string_view name) {
233 if (line_->name().empty()) SetName(name);
234 }
235
TimestampNs()236 int64 TimestampNs() const { return line_->timestamp_ns(); }
237 // This will set the line start timestamp.
238 // WARNING: The offset_ps of existing events will not be altered.
SetTimestampNs(int64 timestamp_ns)239 void SetTimestampNs(int64 timestamp_ns) {
240 line_->set_timestamp_ns(timestamp_ns);
241 }
242 // This will set the line start timestamp to specific time, and adjust
243 // the offset_ps of all existing events.
244 void SetTimestampNsAndAdjustEventOffsets(int64 timestamp_ns);
245
SetDurationPs(int64 duration_ps)246 void SetDurationPs(int64 duration_ps) { line_->set_duration_ps(duration_ps); }
247
ReserveEvents(size_t num_events)248 void ReserveEvents(size_t num_events) {
249 line_->mutable_events()->Reserve(num_events);
250 }
251
SetDisplayNameIfEmpty(absl::string_view display_name)252 void SetDisplayNameIfEmpty(absl::string_view display_name) {
253 if (line_->display_name().empty()) {
254 line_->set_display_name(std::string(display_name));
255 }
256 }
257
258 XEventBuilder AddEvent(const XEventMetadata& metadata);
259 XEventBuilder AddEvent(const XEvent& event);
260
261 private:
262 XLine* line_;
263 XPlaneBuilder* plane_;
264 };
265
266 // Provides methods to build an XPlane.
267 // NOTE: avoid to use two builders to wrap the same XPlane.
268 class XPlaneBuilder : public XStatsBuilder<XPlane> {
269 public:
270 explicit XPlaneBuilder(XPlane* plane);
271
Id()272 int64 Id() const { return plane_->id(); }
SetId(int64 id)273 void SetId(int64 id) { plane_->set_id(id); }
274
Name()275 absl::string_view Name() const { return plane_->name(); }
SetName(absl::string_view name)276 void SetName(absl::string_view name) { plane_->set_name(std::string(name)); }
277
ReserveLines(size_t num_lines)278 void ReserveLines(size_t num_lines) {
279 plane_->mutable_lines()->Reserve(num_lines);
280 }
281
282 template <typename ForEachLineFunc>
ForEachLine(ForEachLineFunc && for_each_line)283 void ForEachLine(ForEachLineFunc&& for_each_line) {
284 for (XLine& line : *plane_->mutable_lines()) {
285 for_each_line(XLineBuilder(&line, this));
286 }
287 }
288
289 // Returns a builder for the line with the given id. Creates a new line if the
290 // id was unused, otherwise the builder will add events to an existing line.
291 XLineBuilder GetOrCreateLine(int64 line_id);
292
293 // Returns a new event metadata with an automatically generated metadata_id.
294 // WARNING: If calling this function, don't call GetOrCreateEventMetadata.
295 XEventMetadata* CreateEventMetadata();
296
297 // Returns event metadata with the given id. Creates a new metadata if the id
298 // was unused.
299 // WARNING: If calling this function, don't call the string overloads below
300 // on the same instance.
301 XEventMetadata* GetOrCreateEventMetadata(int64 metadata_id);
302
303 // Returns event metadata with the given name. The id is internally assigned.
304 // Creates a new metadata if the name was unused.
305 // Using these overloads guarantees names are unique.
306 // WARNING: If calling any of these overloads, do not call the integer one
307 // above on the same instance.
308 XEventMetadata* GetOrCreateEventMetadata(absl::string_view name);
309 XEventMetadata* GetOrCreateEventMetadata(std::string&& name);
GetOrCreateEventMetadata(const char * name)310 XEventMetadata* GetOrCreateEventMetadata(const char* name) {
311 return GetOrCreateEventMetadata(absl::string_view(name));
312 }
313
314 // Returns a new stat metadata with an automatically generated metadata_id.
315 // WARNING: If calling this function, don't call GetOrCreateEventMetadata.
316 XStatMetadata* CreateStatMetadata();
317
318 // Returns stat metadata with the given id. Creates a new metadata if the id
319 // was unused.
320 // WARNING: If calling this function, don't call the string overloads below
321 // on the same instance.
322 XStatMetadata* GetOrCreateStatMetadata(int64 metadata_id);
323
324 // Returns stat metadata with the given name. The id is internally assigned.
325 // Creates a new metadata if the name was unused.
326 // Using these overloads guarantees names are unique.
327 // WARNING: If calling any of these overloads, do not call the integer one
328 // above on the same instance.
329 XStatMetadata* GetOrCreateStatMetadata(absl::string_view name);
330 XStatMetadata* GetOrCreateStatMetadata(std::string&& name);
GetOrCreateStatMetadata(const char * name)331 XStatMetadata* GetOrCreateStatMetadata(const char* name) {
332 return GetOrCreateStatMetadata(absl::string_view(name));
333 }
334
335 private:
336 XPlane* plane_;
337
338 // Artifacts to accelerate the builders.
339 int64 last_event_metadata_id_ = 0LL;
340 int64 last_stat_metadata_id_ = 0LL;
341 absl::flat_hash_map<std::string, XEventMetadata*> event_metadata_by_name_;
342 absl::flat_hash_map<std::string, XStatMetadata*> stat_metadata_by_name_;
343 absl::flat_hash_map<int64, XLine*> lines_by_id_;
344 };
345
346 template <typename T>
GetOrCreateStatMetadata(absl::string_view value)347 const XStatMetadata& XStatsBuilder<T>::GetOrCreateStatMetadata(
348 absl::string_view value) {
349 return *stats_metadata_owner_->GetOrCreateStatMetadata(value);
350 }
351
352 } // namespace profiler
353 } // namespace tensorflow
354
355 #endif // TENSORFLOW_CORE_PROFILER_UTILS_XPLANE_BUILDER_H_
356