1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef CONTENT_COMMON_INTER_PROCESS_TIME_TICKS_CONVERTER_H_ 6 #define CONTENT_COMMON_INTER_PROCESS_TIME_TICKS_CONVERTER_H_ 7 8 #include "base/time/time.h" 9 #include "content/common/content_export.h" 10 11 namespace content { 12 13 class LocalTimeDelta; 14 class LocalTimeTicks; 15 class RemoteTimeDelta; 16 class RemoteTimeTicks; 17 18 // On Windows, TimeTicks are not consistent between processes. Often, the values 19 // on one process have a static offset relative to another. Occasionally, these 20 // offsets shift while running. 21 // 22 // To combat this, any TimeTicks values sent from the remote process to the 23 // local process must be tweaked in order to appear monotonic. 24 // 25 // In order to properly tweak ticks, we need 4 reference points: 26 // 27 // - |local_lower_bound|: A known point, recorded on the local process, that 28 // occurs before any remote values that will be 29 // converted. 30 // - |remote_lower_bound|: The equivalent point on the remote process. This 31 // should be recorded immediately after 32 // |local_lower_bound|. 33 // - |local_upper_bound|: A known point, recorded on the local process, that 34 // occurs after any remote values that will be 35 // converted. 36 // - |remote_upper_bound|: The equivalent point on the remote process. This 37 // should be recorded immediately before 38 // |local_upper_bound|. 39 // 40 // Once these bounds are determined, values within the remote process's range 41 // can be converted to the local process's range. The values are converted as 42 // follows: 43 // 44 // 1. If the remote's range exceeds the local's range, it is scaled to fit. 45 // Any values converted will have the same scale factor applied. 46 // 47 // 2. The remote's range is shifted so that it is centered within the 48 // local's range. Any values converted will be shifted the same amount. 49 class CONTENT_EXPORT InterProcessTimeTicksConverter { 50 public: 51 InterProcessTimeTicksConverter(const LocalTimeTicks& local_lower_bound, 52 const LocalTimeTicks& local_upper_bound, 53 const RemoteTimeTicks& remote_lower_bound, 54 const RemoteTimeTicks& remote_upper_bound); 55 56 // Returns the value within the local's bounds that correlates to 57 // |remote_ms|. 58 LocalTimeTicks ToLocalTimeTicks(const RemoteTimeTicks& remote_ms) const; 59 60 // Returns the equivalent delta after applying remote-to-local scaling to 61 // |remote_delta|. 62 LocalTimeDelta ToLocalTimeDelta(const RemoteTimeDelta& remote_delta) const; 63 64 // Returns true iff the TimeTicks are converted by adding a constant, without 65 // scaling. This is the case whenever the remote timespan is smaller than the 66 // local timespan, which should be the majority of cases due to IPC overhead. 67 bool IsSkewAdditiveForMetrics() const; 68 69 // Returns the (remote time) - (local time) difference estimated by the 70 // converter. This is the constant that is subtracted from remote TimeTicks to 71 // get local TimeTicks when no scaling is applied. 72 base::TimeDelta GetSkewForMetrics() const; 73 74 private: 75 int64 Convert(int64 value) const; 76 77 // The local time which |remote_lower_bound_| is mapped to. 78 int64 local_base_time_; 79 80 int64 numerator_; 81 int64 denominator_; 82 83 int64 remote_lower_bound_; 84 int64 remote_upper_bound_; 85 }; 86 87 class CONTENT_EXPORT LocalTimeDelta { 88 public: ToInt32()89 int ToInt32() const { return value_; } 90 91 private: 92 friend class InterProcessTimeTicksConverter; 93 friend class LocalTimeTicks; 94 LocalTimeDelta(int value)95 LocalTimeDelta(int value) : value_(value) {} 96 97 int value_; 98 }; 99 100 class CONTENT_EXPORT LocalTimeTicks { 101 public: FromTimeTicks(const base::TimeTicks & value)102 static LocalTimeTicks FromTimeTicks(const base::TimeTicks& value) { 103 return LocalTimeTicks(value.ToInternalValue()); 104 } 105 ToTimeTicks()106 base::TimeTicks ToTimeTicks() { 107 return base::TimeTicks::FromInternalValue(value_); 108 } 109 110 LocalTimeTicks operator+(const LocalTimeDelta& delta) { 111 return LocalTimeTicks(value_ + delta.value_); 112 } 113 114 private: 115 friend class InterProcessTimeTicksConverter; 116 LocalTimeTicks(int64 value)117 LocalTimeTicks(int64 value) : value_(value) {} 118 119 int64 value_; 120 }; 121 122 class CONTENT_EXPORT RemoteTimeDelta { 123 public: FromRawDelta(int delta)124 static RemoteTimeDelta FromRawDelta(int delta) { 125 return RemoteTimeDelta(delta); 126 } 127 128 private: 129 friend class InterProcessTimeTicksConverter; 130 friend class RemoteTimeTicks; 131 RemoteTimeDelta(int value)132 RemoteTimeDelta(int value) : value_(value) {} 133 134 int value_; 135 }; 136 137 class CONTENT_EXPORT RemoteTimeTicks { 138 public: FromTimeTicks(const base::TimeTicks & ticks)139 static RemoteTimeTicks FromTimeTicks(const base::TimeTicks& ticks) { 140 return RemoteTimeTicks(ticks.ToInternalValue()); 141 } 142 143 RemoteTimeDelta operator-(const RemoteTimeTicks& rhs) const { 144 return RemoteTimeDelta(value_ - rhs.value_); 145 } 146 147 private: 148 friend class InterProcessTimeTicksConverter; 149 RemoteTimeTicks(int64 value)150 RemoteTimeTicks(int64 value) : value_(value) {} 151 152 int64 value_; 153 }; 154 155 } // namespace content 156 157 #endif // CONTENT_COMMON_INTER_PROCESS_TIME_TICKS_CONVERTER_H_ 158