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