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