Commit 8d414ca2 authored by jeremy@chromium.org's avatar jeremy@chromium.org

[Telemetry] Move page quiescence test to WebContents

Move quiescence test used by speed index so we can more easily reuse it in other parts of the code.

BUG=339180

Review URL: https://codereview.chromium.org/185413005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@255851 0039d316-1c4b-4281-b951-d872f2087c98
parent 3c1087e3
......@@ -3,7 +3,6 @@
# found in the LICENSE file.
import collections
import os
from metrics import Metric
from telemetry.core import bitmap
......@@ -23,10 +22,6 @@ class SpeedIndexMetric(Metric):
def __init__(self):
super(SpeedIndexMetric, self).__init__()
self._impl = None
self._script_is_loaded = False
self._is_finished = False
with open(os.path.join(os.path.dirname(__file__), 'speedindex.js')) as f:
self._js = f.read()
@classmethod
def CustomizeBrowserOptions(cls, options):
......@@ -42,8 +37,6 @@ class SpeedIndexMetric(Metric):
self._impl = (VideoSpeedIndexImpl() if tab.video_capture_supported else
PaintRectSpeedIndexImpl())
self._impl.Start(tab)
self._script_is_loaded = False
self._is_finished = False
def Stop(self, _, tab):
"""Stop timeline recording."""
......@@ -78,23 +71,7 @@ class SpeedIndexMetric(Metric):
True if 2 seconds have passed since last resource received, false
otherwise.
"""
if self._is_finished:
return True
# The script that provides the function window.timeSinceLastResponseMs()
# needs to be loaded for this function, but it must be loaded AFTER
# the Start method is called, because if the Start method is called in
# the PageMeasurement's WillNavigateToPage function, then it will
# not be available here. The script should only be re-loaded once per page
# so that variables in the script get reset only for a new page.
if not self._script_is_loaded:
tab.ExecuteJavaScript(self._js)
self._script_is_loaded = True
time_since_last_response_ms = tab.EvaluateJavaScript(
"window.timeSinceLastResponseAfterLoadMs()")
self._is_finished = time_since_last_response_ms > 2000
return self._is_finished
return tab.HasReachedQuiescence()
class SpeedIndexImpl(object):
......
// Copyright 2013 The Chromium Authors. All rights reserved.
// Copyright 2014 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.
......@@ -6,10 +6,16 @@
/**
* @fileoverview This file provides a JavaScript helper function that
* determines when the last resource was received.
* determines when network quiescence has been reached based on the time since
* the last resource was received.
*/
(function() {
// Make executing this code idempotent.
if (window.__telemetry_testHasReachedNetworkQuiescence) {
return;
}
// Set the Resource Timing interface functions that will be used below
// to use whatever version is available currently regardless of vendor
// prefix.
......@@ -38,19 +44,32 @@
// so we can clear new entries when they're added.
var lastEntry = null;
// True when no resource has been loaded from the network for
//|QUIESCENCE_TIMEOUT_MS| milliseconds. This value is sticky.
var hasReachedQuiesence = false;
// Time to wait before declaring network quiescence in milliseconds.
var QUIESCENCE_TIMEOUT_MS = 2000;
/**
* This method uses the Resource Timing interface, which is described at
* http://www.w3.org/TR/resource-timing/. It provides information about
* timings for resources such as images and script files, and it includes
* resources requested via XMLHttpRequest.
* http://www.w3.org/TR/resource-timing/. It determines whether the time
* since lodading any resources such as images and script files (including
* resources requested via XMLHttpRequest) has exceeded a threshold defined
# by |QUIESCENCE_TIMEOUT_MS|.
*
* @return {number} The time since either the load event, or the last
* the last resource was received after the load event. If the load
* event hasn't yet happened, return 0.
* @return {boolean} True if the time since either the load event, or the last
* resource was received after the load event exceeds the aforementioned
* threshold. This state is sticky, so once this function returns true for a
* given page, it will always return true.
*/
window.timeSinceLastResponseAfterLoadMs = function() {
window.__telemetry_testHasReachedNetworkQuiescence = function() {
if (hasReachedQuiesence) {
return true;
}
if (window.document.readyState !== 'complete') {
return 0;
return false;
}
var resourceTimings = window.performance.getEntriesByType('resource');
......@@ -64,13 +83,21 @@
// so we must also get load time in the same terms.
var timing = window.performance.timing;
var loadTime = timing.loadEventEnd - timing.navigationStart;
var lastResponseTimeMs = 0;
// If there have been no resource timing entries, or the last entry was
// before the load event, then return the time since the load event.
// before the load event, then use the time since the load event.
if (!lastEntry || lastEntry.responseEnd < loadTime) {
return window.performance.now() - loadTime;
lastResponseTimeMs = window.performance.now() - loadTime;
} else {
lastResponseTimeMs = window.performance.now() - lastEntry.responseEnd;
}
if (lastResponseTimeMs >= QUIESCENCE_TIMEOUT_MS) {
hasReachedQuiesence = true;
}
return window.performance.now() - lastEntry.responseEnd;
return hasReachedQuiesence;
}
})();
......@@ -2,6 +2,8 @@
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import os
from telemetry.core import util
DEFAULT_WEB_CONTENTS_TIMEOUT = 90
......@@ -13,6 +15,10 @@ class WebContents(object):
def __init__(self, inspector_backend):
self._inspector_backend = inspector_backend
with open(os.path.join(os.path.dirname(__file__),
'network_quiescence.js')) as f:
self._quiescence_js = f.read()
def Close(self):
"""Closes this page.
......@@ -46,6 +52,22 @@ class WebContents(object):
return False
util.WaitFor(IsTrue, timeout)
def HasReachedQuiescence(self):
"""Determine whether the page has reached quiescence after loading.
Returns:
True if 2 seconds have passed since last resource received, false
otherwise."""
# Inclusion of the script that provides
# window.__telemetry_testHasReachedNetworkQuiescence()
# is idempotent, it's run on every call because WebContents doesn't track
# page loads and we need to execute anew for every newly loaded page.
has_reached_quiescence = (
self.EvaluateJavaScript(self._quiescence_js +
"window.__telemetry_testHasReachedNetworkQuiescence()"))
return has_reached_quiescence
def ExecuteJavaScript(self, expr, timeout=DEFAULT_WEB_CONTENTS_TIMEOUT):
"""Executes expr in JavaScript. Does not return the result.
......
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