blob: cc2952e4164682a8fdc87e0a0d67fa5829864b3b [file] [log] [blame]
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_COMMON_INTER_PROCESS_TIME_TICKS_CONVERTER_H_
#define CONTENT_COMMON_INTER_PROCESS_TIME_TICKS_CONVERTER_H_
#include <stdint.h>
#include "base/time/time.h"
#include "content/common/content_export.h"
namespace content {
// SiteSpecificTimeDelta<T> is base::TimeDelta with a type tag. It it
// essentially base::TimeDelta, but SiteSpecificTimeDelta<T> is different from
// SiteSpecificTimeDelta<U> if T is different from U.
template <typename T>
class SiteSpecificTimeDelta final {
public:
SiteSpecificTimeDelta() = default;
static SiteSpecificTimeDelta<T> FromTimeDelta(base::TimeDelta delta) {
return SiteSpecificTimeDelta<T>(delta);
}
static SiteSpecificTimeDelta<T> FromMicroseconds(int64_t usec) {
return SiteSpecificTimeDelta<T>(base::TimeDelta::FromMicroseconds(usec));
}
base::TimeDelta ToTimeDelta() const { return delta_; }
bool operator==(const SiteSpecificTimeDelta<T> rhs) const {
return delta_ == rhs.delta_;
}
bool operator<(const SiteSpecificTimeDelta<T> rhs) const {
return delta_ < rhs.delta_;
}
bool operator<=(const SiteSpecificTimeDelta<T> rhs) const {
return delta_ <= rhs.delta_;
}
private:
explicit SiteSpecificTimeDelta(base::TimeDelta delta) : delta_(delta) {}
base::TimeDelta delta_;
};
// For logging use only.
template <typename T>
std::ostream& operator<<(std::ostream& os, SiteSpecificTimeDelta<T> delta) {
return os << delta.ToTimeDelta();
}
// SiteSpecificTimeTicks<T> is base::TimeTicks with a type tag. It is
// essentially base::TimeTicks, but SiteSpecificTimeTicks<T> is different from
// SiteSpecificTimeTicks<U> if T is different from U.
template <typename T>
class SiteSpecificTimeTicks final {
public:
SiteSpecificTimeTicks() = default;
static SiteSpecificTimeTicks<T> FromTimeTicks(base::TimeTicks time_ticks) {
return SiteSpecificTimeTicks<T>(time_ticks);
}
base::TimeTicks ToTimeTicks() const { return time_ticks_; }
bool is_null() const { return time_ticks_.is_null(); }
SiteSpecificTimeTicks<T> operator+(SiteSpecificTimeDelta<T> delta) const {
return SiteSpecificTimeTicks<T>(time_ticks_ + delta.ToTimeDelta());
}
SiteSpecificTimeDelta<T> operator-(SiteSpecificTimeTicks<T> rhs) const {
return SiteSpecificTimeDelta<T>::FromTimeDelta(time_ticks_ -
rhs.time_ticks_);
}
bool operator<(const SiteSpecificTimeTicks<T> rhs) const {
return time_ticks_ < rhs.time_ticks_;
}
bool operator==(const SiteSpecificTimeTicks<T> rhs) const {
return time_ticks_ == rhs.time_ticks_;
}
bool operator<=(const SiteSpecificTimeTicks<T> rhs) const {
return time_ticks_ <= rhs.time_ticks_;
}
private:
explicit SiteSpecificTimeTicks(base::TimeTicks time_ticks)
: time_ticks_(time_ticks) {}
base::TimeTicks time_ticks_;
};
// For logging use only.
template <typename T>
std::ostream& operator<<(std::ostream& os,
SiteSpecificTimeTicks<T> time_ticks) {
return os << time_ticks.ToTimeTicks();
}
class SiteSpecificTimeLocalTag;
using LocalTimeTicks = SiteSpecificTimeTicks<SiteSpecificTimeLocalTag>;
using LocalTimeDelta = SiteSpecificTimeDelta<SiteSpecificTimeLocalTag>;
class SiteSpecificTimeRemoteTag;
using RemoteTimeTicks = SiteSpecificTimeTicks<SiteSpecificTimeRemoteTag>;
using RemoteTimeDelta = SiteSpecificTimeDelta<SiteSpecificTimeRemoteTag>;
// On Windows, TimeTicks are not always consistent between processes as
// indicated by |TimeTicks::IsConsistentAcrossProcesses()|. Often, the values on
// one process have a static offset relative to another. Occasionally, these
// offsets shift while running.
//
// To combat this, any TimeTicks values sent from the remote process to the
// local process must be tweaked in order to appear monotonic.
//
// In order to properly tweak ticks, we need 4 reference points:
//
// - |local_lower_bound|: A known point, recorded on the local process, that
// occurs before any remote values that will be
// converted.
// - |remote_lower_bound|: The equivalent point on the remote process. This
// should be recorded immediately after
// |local_lower_bound|.
// - |local_upper_bound|: A known point, recorded on the local process, that
// occurs after any remote values that will be
// converted.
// - |remote_upper_bound|: The equivalent point on the remote process. This
// should be recorded immediately before
// |local_upper_bound|.
//
// Once these bounds are determined, values within the remote process's range
// can be converted to the local process's range. The values are converted as
// follows:
//
// 1. If the remote's range exceeds the local's range, it is scaled to fit.
// Any values converted will have the same scale factor applied.
//
// 2. The remote's range is shifted so that it is centered within the
// local's range. Any values converted will be shifted the same amount.
class CONTENT_EXPORT InterProcessTimeTicksConverter {
public:
InterProcessTimeTicksConverter(LocalTimeTicks local_lower_bound,
LocalTimeTicks local_upper_bound,
RemoteTimeTicks remote_lower_bound,
RemoteTimeTicks remote_upper_bound);
// Returns the value within the local's bounds that correlates to
// |remote_ms|.
LocalTimeTicks ToLocalTimeTicks(RemoteTimeTicks remote_ms) const;
// Returns the equivalent delta after applying remote-to-local scaling to
// |remote_delta|.
LocalTimeDelta ToLocalTimeDelta(RemoteTimeDelta remote_delta) const;
// Returns the (remote time) - (local time) difference estimated by the
// converter. This is the constant that is subtracted from remote TimeTicks to
// get local TimeTicks when no scaling is applied.
base::TimeDelta GetSkewForMetrics() const;
private:
// The local time which |remote_lower_bound_| is mapped to.
LocalTimeTicks local_base_time_;
LocalTimeDelta local_range_;
double range_conversion_rate_;
RemoteTimeTicks remote_lower_bound_;
RemoteTimeTicks remote_upper_bound_;
};
} // namespace content
#endif // CONTENT_COMMON_INTER_PROCESS_TIME_TICKS_CONVERTER_H_