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 
16 #ifndef TENSORFLOW_CORE_PROFILER_UTILS_TIMESPAN_H_
17 #define TENSORFLOW_CORE_PROFILER_UTILS_TIMESPAN_H_
18 
19 #include <algorithm>
20 #include <string>
21 
22 #include "absl/strings/str_cat.h"
23 #include "tensorflow/core/platform/logging.h"
24 #include "tensorflow/core/platform/types.h"
25 #include "tensorflow/core/profiler/utils/time_utils.h"
26 
27 namespace tensorflow {
28 namespace profiler {
29 
30 // A Timespan is the time extent of an event: a pair of (begin, duration).
31 // Events may have duration 0 ("instant events") but duration can't be negative.
32 class Timespan {
33  public:
FromEndPoints(uint64 begin_ps,uint64 end_ps)34   static Timespan FromEndPoints(uint64 begin_ps, uint64 end_ps) {
35     DCHECK_LE(begin_ps, end_ps);
36     return Timespan(begin_ps, end_ps - begin_ps);
37   }
38 
39   explicit Timespan(uint64 begin_ps = 0, uint64 duration_ps = 0)
begin_ps_(begin_ps)40       : begin_ps_(begin_ps), duration_ps_(duration_ps) {}
41 
begin_ps()42   uint64 begin_ps() const { return begin_ps_; }
middle_ps()43   uint64 middle_ps() const { return begin_ps_ + duration_ps_ / 2; }
end_ps()44   uint64 end_ps() const { return begin_ps_ + duration_ps_; }
duration_ps()45   uint64 duration_ps() const { return duration_ps_; }
46 
47   // Returns true if the Timespan represents an instant in time (duration 0).
Instant()48   bool Instant() const { return duration_ps() == 0; }
49 
50   // Returns true if this is an empty timespan.
Empty()51   bool Empty() const { return begin_ps() == 0 && duration_ps() == 0; }
52 
53   // Note for Overlaps() and Includes(Timespan& other) below:
54   //   We have a design choice whether the end-point comparison should be
55   //   inclusive or exclusive. We decide to go for inclusive. The implication
56   //   is that an instant timespan could belong to two consecutive intervals
57   //   (e.g., Timespan(12, 0) will be included in both Timespan(11, 1) and
58   //   Timespan(12, 1)). We think this is okay because the common scenario
59   //   would be that we search for the interval that includes a point
60   //   in time from left to right, and return the first interval found.
61 
62   // Returns true if the Timespan overlaps with other.
Overlaps(const Timespan & other)63   bool Overlaps(const Timespan& other) const {
64     return begin_ps() <= other.end_ps() && other.begin_ps() <= end_ps();
65   }
66 
67   // Returns true if this Timespan includes the other.
Includes(const Timespan & other)68   bool Includes(const Timespan& other) const {
69     return begin_ps() <= other.begin_ps() && other.end_ps() <= end_ps();
70   }
71 
72   // Returns true if time_ps is within this Timespan.
Includes(uint64 time_ps)73   bool Includes(uint64 time_ps) const { return Includes(Timespan(time_ps)); }
74 
75   // Returns the duration in ps that this Timespan overlaps with the other.
OverlappedDurationPs(const Timespan & other)76   uint64 OverlappedDurationPs(const Timespan& other) const {
77     if (!Overlaps(other)) return 0;
78     return std::min(end_ps(), other.end_ps()) -
79            std::max(begin_ps(), other.begin_ps());
80   }
81 
82   // Expands the timespan to include other.
ExpandToInclude(const Timespan & other)83   void ExpandToInclude(const Timespan& other) {
84     *this = FromEndPoints(std::min(begin_ps(), other.begin_ps()),
85                           std::max(end_ps(), other.end_ps()));
86   }
87 
88   // Compares timespans by their begin time (ascending), duration (descending)
89   // so nested spans are sorted from outer to innermost.
90   bool operator<(const Timespan& other) const {
91     if (begin_ps_ < other.begin_ps_) return true;
92     if (begin_ps_ > other.begin_ps_) return false;
93     return duration_ps_ > other.duration_ps_;
94   }
95 
96   // Returns true if this timespan is equal to the given timespan.
97   bool operator==(const Timespan& other) const {
98     return begin_ps_ == other.begin_ps_ && duration_ps_ == other.duration_ps_;
99   }
100 
101   // Returns a string that shows the begin and end times.
DebugString()102   std::string DebugString() const {
103     return absl::StrCat("[", begin_ps(), ", ", end_ps(), "]");
104   }
105 
106   // Compares timespans by their duration_ps (ascending), begin time
107   // (ascending).
ByDuration(const Timespan & a,const Timespan & b)108   static bool ByDuration(const Timespan& a, const Timespan& b) {
109     if (a.duration_ps_ < b.duration_ps_) return true;
110     if (a.duration_ps_ > b.duration_ps_) return false;
111     return a.begin_ps_ < b.begin_ps_;
112   }
113 
114  private:
115   uint64 begin_ps_;
116   uint64 duration_ps_;  // 0 for an instant event.
117 };
118 
119 // Creates a Timespan from endpoints in picoseconds.
PicoSpan(uint64 start_ps,uint64 end_ps)120 inline Timespan PicoSpan(uint64 start_ps, uint64 end_ps) {
121   return Timespan::FromEndPoints(start_ps, end_ps);
122 }
123 
124 // Creates a Timespan from endpoints in milliseconds.
MilliSpan(double start_ms,double end_ms)125 inline Timespan MilliSpan(double start_ms, double end_ms) {
126   return PicoSpan(MillisToPicos(start_ms), MillisToPicos(end_ms));
127 }
128 
129 }  // namespace profiler
130 }  // namespace tensorflow
131 
132 #endif  // TENSORFLOW_CORE_PROFILER_UTILS_TIMESPAN_H_
133