Commit 4f3e2866 authored by majidvp's avatar majidvp Committed by Commit bot

Limit InterProcessTimeTickConverter to platforms that require it

On most platforms the monotonic clock is system wide which means it is
consistent across processes making conversion unnecessary. In fact not
only it is unnecessary but harmfull because the
InterProcessTimeTickConverter (IPTTC) conversion [1] is an estimation
which introduces some error.

The patch limits the usage of IPTTC to platforms that require it which
is any Windows where we cannot use |QueryPerformanceCounter|.

After this change we will only collect UMA metrics[2] for IPTTC on
platforms where it is used.

[1] https://docs.google.com/document/d/1RcaOZ1G8ttAez9YuilvbDJCkCaYuLKqNkVpQvIBqsvM/edit
[2] Affects InterProcessTimeTicks.*

BUG=616574
CQ_INCLUDE_TRYBOTS=tryserver.chromium.linux:linux_site_isolation

Review-Url: https://codereview.chromium.org/2090783002
Cr-Commit-Position: refs/heads/master@{#407270}
parent 00314989
......@@ -713,6 +713,13 @@ class BASE_EXPORT TimeTicks : public time_internal::TimeBase<TimeTicks> {
// clock will be used instead.
static bool IsHighResolution();
// Returns true if TimeTicks is consistent across processes, meaning that
// timestamps taken on different processes can be safely compared with one
// another. (Note that, even on platforms where this returns true, time values
// from different threads that are within one tick of each other must be
// considered to have an ambiguous ordering.)
static bool IsConsistentAcrossProcesses();
#if defined(OS_WIN)
// Translates an absolute QPC timestamp into a TimeTicks value. The returned
// value has the same origin as Now(). Do NOT attempt to use this if
......
......@@ -258,6 +258,11 @@ bool TimeTicks::IsHighResolution() {
return true;
}
// static
bool TimeTicks::IsConsistentAcrossProcesses() {
return true;
}
// static
TimeTicks::Clock TimeTicks::GetClock() {
#if defined(OS_IOS)
......
......@@ -339,6 +339,11 @@ bool TimeTicks::IsHighResolution() {
return true;
}
// static
bool TimeTicks::IsConsistentAcrossProcesses() {
return true;
}
// static
ThreadTicks ThreadTicks::Now() {
#if (defined(_POSIX_THREAD_CPUTIME) && (_POSIX_THREAD_CPUTIME >= 0)) || \
......
......@@ -503,6 +503,26 @@ bool TimeTicks::IsHighResolution() {
return g_now_function == &QPCNow;
}
// static
bool TimeTicks::IsConsistentAcrossProcesses() {
// According to Windows documentation [1] QPC is consistent post-Windows
// Vista. So if we are using QPC then we are consistent which is the same as
// being high resolution.
//
// [1] https://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx
//
// "In general, the performance counter results are consistent across all
// processors in multi-core and multi-processor systems, even when measured on
// different threads or processes. Here are some exceptions to this rule:
// - Pre-Windows Vista operating systems that run on certain processors might
// violate this consistency because of one of these reasons:
// 1. The hardware processors have a non-invariant TSC and the BIOS
// doesn't indicate this condition correctly.
// 2. The TSC synchronization algorithm that was used wasn't suitable for
// systems with large numbers of processors."
return IsHighResolution();
}
// static
TimeTicks::Clock TimeTicks::GetClock() {
return IsHighResolution() ?
......
......@@ -1363,37 +1363,41 @@ void RenderFrameHostImpl::OnBeforeUnloadACK(
base::TimeTicks before_unload_end_time = renderer_before_unload_end_time;
if (!renderer_before_unload_start_time.is_null() &&
!renderer_before_unload_end_time.is_null()) {
// When passing TimeTicks across process boundaries, we need to compensate
// for any skew between the processes. Here we are converting the
// renderer's notion of before_unload_end_time to TimeTicks in the browser
// process. See comments in inter_process_time_ticks_converter.h for more.
base::TimeTicks receive_before_unload_ack_time = base::TimeTicks::Now();
InterProcessTimeTicksConverter converter(
LocalTimeTicks::FromTimeTicks(send_before_unload_start_time_),
LocalTimeTicks::FromTimeTicks(receive_before_unload_ack_time),
RemoteTimeTicks::FromTimeTicks(renderer_before_unload_start_time),
RemoteTimeTicks::FromTimeTicks(renderer_before_unload_end_time));
LocalTimeTicks browser_before_unload_end_time =
converter.ToLocalTimeTicks(
RemoteTimeTicks::FromTimeTicks(renderer_before_unload_end_time));
before_unload_end_time = browser_before_unload_end_time.ToTimeTicks();
// Collect UMA on the inter-process skew.
bool is_skew_additive = false;
if (converter.IsSkewAdditiveForMetrics()) {
is_skew_additive = true;
base::TimeDelta skew = converter.GetSkewForMetrics();
if (skew >= base::TimeDelta()) {
UMA_HISTOGRAM_TIMES(
"InterProcessTimeTicks.BrowserBehind_RendererToBrowser", skew);
} else {
UMA_HISTOGRAM_TIMES(
"InterProcessTimeTicks.BrowserAhead_RendererToBrowser", -skew);
if (!base::TimeTicks::IsConsistentAcrossProcesses()) {
// TimeTicks is not consistent across processes and we are passing
// TimeTicks across process boundaries so we need to compensate for any
// skew between the processes. Here we are converting the renderer's
// notion of before_unload_end_time to TimeTicks in the browser process.
// See comments in inter_process_time_ticks_converter.h for more.
InterProcessTimeTicksConverter converter(
LocalTimeTicks::FromTimeTicks(send_before_unload_start_time_),
LocalTimeTicks::FromTimeTicks(receive_before_unload_ack_time),
RemoteTimeTicks::FromTimeTicks(renderer_before_unload_start_time),
RemoteTimeTicks::FromTimeTicks(renderer_before_unload_end_time));
LocalTimeTicks browser_before_unload_end_time =
converter.ToLocalTimeTicks(
RemoteTimeTicks::FromTimeTicks(renderer_before_unload_end_time));
before_unload_end_time = browser_before_unload_end_time.ToTimeTicks();
// Collect UMA on the inter-process skew.
bool is_skew_additive = false;
if (converter.IsSkewAdditiveForMetrics()) {
is_skew_additive = true;
base::TimeDelta skew = converter.GetSkewForMetrics();
if (skew >= base::TimeDelta()) {
UMA_HISTOGRAM_TIMES(
"InterProcessTimeTicks.BrowserBehind_RendererToBrowser", skew);
} else {
UMA_HISTOGRAM_TIMES(
"InterProcessTimeTicks.BrowserAhead_RendererToBrowser", -skew);
}
}
UMA_HISTOGRAM_BOOLEAN(
"InterProcessTimeTicks.IsSkewAdditive_RendererToBrowser",
is_skew_additive);
}
UMA_HISTOGRAM_BOOLEAN(
"InterProcessTimeTicks.IsSkewAdditive_RendererToBrowser",
is_skew_additive);
base::TimeDelta on_before_unload_overhead_time =
(receive_before_unload_ack_time - send_before_unload_start_time_) -
......
......@@ -608,7 +608,8 @@ void ResourceDispatcher::ToResourceResponseInfo(
const ResourceResponseHead& browser_info,
ResourceResponseInfo* renderer_info) const {
*renderer_info = browser_info;
if (request_info.request_start.is_null() ||
if (base::TimeTicks::IsConsistentAcrossProcesses() ||
request_info.request_start.is_null() ||
request_info.response_start.is_null() ||
browser_info.request_start.is_null() ||
browser_info.response_start.is_null() ||
......
......@@ -17,8 +17,9 @@ class LocalTimeTicks;
class RemoteTimeDelta;
class RemoteTimeTicks;
// On Windows, TimeTicks are not consistent between processes. Often, the values
// on one process have a static offset relative to another. Occasionally, these
// 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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment