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