Index: tools/perf/profile_creators/fast_navigation_profile_extender.py |
diff --git a/tools/perf/profile_creators/fast_navigation_profile_extender.py b/tools/perf/profile_creators/fast_navigation_profile_extender.py |
index d5b3da74caea6f517258f50e6b0c5dd16037b862..164b30aaf955b6f146992eff79f1848ebcfb0fa9 100644 |
--- a/tools/perf/profile_creators/fast_navigation_profile_extender.py |
+++ b/tools/perf/profile_creators/fast_navigation_profile_extender.py |
@@ -5,6 +5,7 @@ import time |
from profile_creators import profile_extender |
from telemetry.core import exceptions |
+from telemetry.core import util |
class FastNavigationProfileExtender(profile_extender.ProfileExtender): |
@@ -36,11 +37,13 @@ class FastNavigationProfileExtender(profile_extender.ProfileExtender): |
# The number of tabs to use. |
self._NUM_TABS = maximum_batch_size |
- # The amount of time to wait for a batch of pages to finish loading. |
- self._BATCH_PAGE_LOAD_TIMEOUT_IN_SECONDS = 10 |
+ # The amount of additional time to wait for a batch of pages to finish |
+ # loading for each page in the batch. |
+ self._BATCH_TIMEOUT_PER_PAGE_IN_SECONDS = 20 |
- # The default amount of time to wait for the retrieval of the URL of a tab. |
- self._TAB_URL_RETRIEVAL_TIMEOUT_IN_SECONDS = 1 |
+ # The amount of time to wait for a page to quiesce. Some pages will never |
+ # quiesce. |
+ self._TIME_TO_WAIT_FOR_PAGE_TO_QUIESCE_IN_SECONDS = 10 |
def Run(self): |
"""Superclass override.""" |
@@ -49,6 +52,7 @@ class FastNavigationProfileExtender(profile_extender.ProfileExtender): |
self._PerformNavigations() |
finally: |
self.TearDownBrowser() |
+ self.VerifyProfileWasExtended() |
erikchen
2015/05/05 22:16:45
I'm intentionally omitting my implementation of Ve
nednguyen
2015/05/07 22:39:20
These notes to the code reviewers should also be p
erikchen
2015/05/08 19:47:58
Done.
|
def GetUrlIterator(self): |
"""Gets URLs for the browser to navigate to. |
@@ -77,18 +81,7 @@ class FastNavigationProfileExtender(profile_extender.ProfileExtender): |
def _AddNewTab(self): |
"""Adds a new tab to the browser.""" |
- |
- # Adding a new tab requires making a request over devtools. This can fail |
- # for a variety of reasons. Retry 3 times. |
- retry_count = 3 |
- for i in range(retry_count): |
- try: |
- self._navigation_tabs.append(self._browser.tabs.New()) |
- except exceptions.Error: |
- if i == retry_count - 1: |
- raise |
- else: |
- break |
+ self._navigation_tabs.append(self._browser.tabs.New()) |
def _RefreshNavigationTabs(self): |
"""Updates the member self._navigation_tabs to contain self._NUM_TABS |
@@ -114,14 +107,14 @@ class FastNavigationProfileExtender(profile_extender.ProfileExtender): |
def _RetrieveTabUrl(self, tab, timeout): |
"""Retrives the URL of the tab.""" |
- try: |
- return tab.EvaluateJavaScript('document.URL', timeout) |
- except exceptions.Error: |
- return None |
+ return tab.EvaluateJavaScript('document.URL', timeout) |
dtu
2015/05/07 21:50:36
Does tab.url not work in this case? (tab.url uses
erikchen
2015/05/08 19:47:58
That's a good suggestion - I've added a comment he
|
+ |
+ def _WaitForUrlToChange(self, tab, initial_url, end_time): |
+ """Waits for the tab to navigate away from its initial url. |
- def _WaitForUrlToChange(self, tab, initial_url, timeout): |
- """Waits for the tab to navigate away from its initial url.""" |
- end_time = time.time() + timeout |
+ If time.time() is larger than end_time, the function does nothing. |
+ Otherwise, the function tries to return no later than end_time. |
+ """ |
while True: |
seconds_to_wait = end_time - time.time() |
seconds_to_wait = max(0, seconds_to_wait) |
@@ -130,7 +123,7 @@ class FastNavigationProfileExtender(profile_extender.ProfileExtender): |
break |
current_url = self._RetrieveTabUrl(tab, seconds_to_wait) |
- if current_url != initial_url: |
+ if current_url != initial_url and current_url != "": |
break |
# Retrieving the current url is a non-trivial operation. Add a small |
@@ -138,6 +131,18 @@ class FastNavigationProfileExtender(profile_extender.ProfileExtender): |
# navigation. |
time.sleep(0.01) |
+ def _WaitForTabToBeReady(self, tab, end_time): |
+ """Waits for the tab to be ready. |
+ |
+ If time.time() is larger than end_time, the function does nothing. |
+ Otherwise, the function tries to return no later than end_time. |
+ """ |
+ seconds_to_wait = end_time - time.time() |
+ seconds_to_wait = max(0, seconds_to_wait) |
+ if seconds_to_wait == 0: |
dtu
2015/05/07 21:50:36
Instead of doing max(), why not just check seconds
erikchen
2015/05/08 19:47:58
Done.
|
+ return |
+ tab.WaitForDocumentReadyStateToBeComplete(seconds_to_wait) |
+ |
def _BatchNavigateTabs(self, batch): |
"""Performs a batch of tab navigations with minimal delay. |
@@ -148,21 +153,22 @@ class FastNavigationProfileExtender(profile_extender.ProfileExtender): |
A list of tuples (tab, initial_url). |initial_url| is the url of the |
|tab| prior to a navigation command being sent to it. |
""" |
- timeout_in_seconds = 0 |
+ # Attempting to pass in a timeout of 0 seconds results in a synchronous |
+ # socket error from the websocket library. Pass in a very small timeout |
+ # instead so that the websocket library raises a Timeout exception. This |
+ # prevents the logic from accidentally catching different socket |
+ # exceptions. |
+ timeout_in_seconds = 0.01 |
queued_tabs = [] |
for tab, url in batch: |
- initial_url = self._RetrieveTabUrl(tab, |
- self._TAB_URL_RETRIEVAL_TIMEOUT_IN_SECONDS) |
- |
+ initial_url = self._RetrieveTabUrl(tab, 20) |
try: |
tab.Navigate(url, None, timeout_in_seconds) |
- except exceptions.Error: |
- # We expect a time out. It's possible for other problems to arise, but |
- # this method is not responsible for dealing with them. Ignore all |
- # exceptions. |
+ except exceptions.TimeoutException: |
+ # We expect to receive a timeout exception, since we're not waiting for |
+ # the navigation to complete. |
pass |
- |
queued_tabs.append((tab, initial_url)) |
return queued_tabs |
@@ -173,30 +179,26 @@ class FastNavigationProfileExtender(profile_extender.ProfileExtender): |
queued_tabs: A list of tuples (tab, initial_url). Each tab is guaranteed |
to have already been sent a navigation command. |
""" |
- end_time = time.time() + self._BATCH_PAGE_LOAD_TIMEOUT_IN_SECONDS |
+ total_batch_timeout = (len(queued_tabs) * |
+ self._BATCH_TIMEOUT_PER_PAGE_IN_SECONDS) |
+ end_time = time.time() + total_batch_timeout |
for tab, initial_url in queued_tabs: |
- seconds_to_wait = end_time - time.time() |
- seconds_to_wait = max(0, seconds_to_wait) |
- |
- if seconds_to_wait == 0: |
- break |
- |
- # Since we don't wait any time for the tab url navigation to commit, it's |
+ # Since we didn't wait any time for the tab url navigation to commit, it's |
# possible that the tab hasn't started navigating yet. |
- self._WaitForUrlToChange(tab, initial_url, seconds_to_wait) |
+ self._WaitForUrlToChange(tab, initial_url, end_time) |
+ self._WaitForTabToBeReady(tab, end_time) |
+ # Wait up to 10 seconds for the page to quiesce. If the page hasn't |
+ # quiesced in 10 seconds, it will probably never quiesce. |
seconds_to_wait = end_time - time.time() |
seconds_to_wait = max(0, seconds_to_wait) |
- |
+ seconds_to_wait = min(self._TIME_TO_WAIT_FOR_PAGE_TO_QUIESCE_IN_SECONDS, |
+ seconds_to_wait) |
try: |
- tab.WaitForDocumentReadyStateToBeComplete(seconds_to_wait) |
+ util.WaitFor(lambda tab=tab: tab.HasReachedQuiescence(), |
dtu
2015/05/07 21:50:36
Just lambda: tab.HasReachedQuiescence()
erikchen
2015/05/08 19:47:58
Actually, there's no need for the lambda either.
|
+ seconds_to_wait) |
except exceptions.TimeoutException: |
- # Ignore time outs. |
pass |
- except exceptions.Error: |
- # If any error occurs, remove the tab. it's probably in an |
- # unrecoverable state. |
- self._RemoveNavigationTab(tab) |
def _GetUrlsToNavigate(self, url_iterator): |
"""Returns an array of urls to navigate to, given a url_iterator.""" |