Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(15)

Side by Side Diff: tools/perf/profile_creators/fast_navigation_profile_extender.py

Issue 907503002: telemetry: Create a helper class to quickly extend profiles. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Minor fixes. Created 5 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 # Copyright 2014 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 import time
5
6 from telemetry.core import browser_finder
7 from telemetry.core import browser_finder_exceptions
8 from telemetry.core import exceptions
9 from telemetry.core import util
10
11
12 class FastNavigationProfileExtender(object):
13 """
14 This class creates or extends an existing profile by performing a set of tab
15 navigations in large batches. This is accomplished by opening a large number
16 of tabs, simultaneously navigating all the tabs, and then waiting for all the
17 tabs to load. This provides two benefits:
18 - Takes advantage of the high number of logical cores on modern CPUs.
19 - The total time spent waiting for navigations to time out scales linearly
20 with the number of batches, but does not scale with the size of the
21 batch.
22 """
23 def Run(self, finder_options):
24 """
25 Superclass override.
26
27 |finder_options| contains the directory of the input profile, the directory
28 to place the output profile, and sufficient information to choose a specific
29 browser binary.
30 """
31 profile_extender = _FastNavigationUserStory(finder_options,
32 self.NavigationUrls())
33 try:
34 profile_extender.WillRunUserStory()
35 profile_extender.RunUserStory()
nednguyen 2015/02/09 20:57:18 You will only need these two hooks if you think th
erikchen 2015/02/09 21:17:35 Renamed the hooks to BrowserSetup() and PerformNav
36 except:
37 raise
38 finally:
39 profile_extender.TearDownState()
nednguyen 2015/02/09 20:57:18 Also this one.
erikchen 2015/02/09 21:17:35 Renamed to BrowserTeardown()
40
41 def NavigationUrls(self):
42 """
43 Intended for subclass override. Returns a list of urls to be navigated to.
44 """
45 raise NotImplementedError()
46
47
48 class _FastNavigationUserStory(object):
49 """
50 This class contains the bulk of the logic related to
51 FastNavigationProfileExtender. Once UserStory has been refactored, this class
52 should become a subclass of UserStory. For more details, see
53 http://code.google.com/p/chromium/issues/detail?id=417812
54
55 This class intentionally mimics the format of SharedUserStoryState to make
56 the future refactor easier.
57 """
58 def __init__(self, finder_options, navigation_urls):
59 super(_FastNavigationUserStory, self).__init__()
60 self.browser = None
61 self._finder_options = finder_options
62 self._navigation_urls = navigation_urls
63
64 # The number of tabs to use.
65 self._NUM_TABS = 15
66
67 # The number of pages to load in parallel.
68 self._NUM_PARALLEL_PAGES = 15
69
70 # The amount of time to wait for pages to finish loading.
71 self._PAGE_LOAD_TIMEOUT_IN_SECONDS = 10
72
73 # The amount of time to wait for the retrieval of the URL of a tab.
74 self._TAB_URL_RETRIEVAL_TIMEOUT_IN_SECONDS = 1
75
76 # The amount of time to wait for a navigation to be committed.
77 self._NAVIGATION_COMMIT_WAIT_IN_SECONDS = 0.1
78
79 # A list of tuples (tab, initial_url). A navigation command has been sent
80 # to |tab|. |tab| had a URL of |initial_url| before the command was sent.
81 self._queued_tabs = []
82
83 # The index of the first url that has not yet been navigated to.
84 self._navigation_url_index = 0
85
86 def _GetPossibleBrowser(self, finder_options):
87 """Return a possible_browser with the given options."""
88 possible_browser = browser_finder.FindBrowser(finder_options)
89 if not possible_browser:
90 raise browser_finder_exceptions.BrowserFinderException(
91 'No browser found.\n\nAvailable browsers:\n%s\n' %
92 '\n'.join(browser_finder.GetAllAvailableBrowserTypes(finder_options)))
93 finder_options.browser_options.browser_type = (
94 possible_browser.browser_type)
95
96 return possible_browser
97
98 def _RetrieveTabUrl(self, tab):
99 """Retrives the URL of the tab."""
100 try:
101 return tab.EvaluateJavaScript('document.URL',
102 self._TAB_URL_RETRIEVAL_TIMEOUT_IN_SECONDS)
103 except exceptions.DevtoolsTargetCrashException:
104 return None
105
106 def _BatchNavigateTabs(self):
107 """Performs a batch of tab navigations with minimal delay."""
108 max_index = min(self._navigation_url_index + self._NUM_PARALLEL_PAGES,
109 len(self._navigation_urls))
110 timeout_in_seconds = 0
111
112 for i in range(self._navigation_url_index, max_index):
113 url = self._navigation_urls[i]
114 tab = self.browser.tabs[i % self._NUM_TABS]
115 initial_url = self._RetrieveTabUrl(tab)
116
117 try:
118 tab.Navigate(url, None, timeout_in_seconds)
119 except exceptions.DevtoolsTargetCrashException:
120 # We expect a time out, and don't mind if the webpage crashes. Ignore
121 # both exceptions.
122 pass
123
124 self._queued_tabs.append((tab, initial_url))
125 self._navigation_url_index = max_index
126
127 def _WaitForQueuedTabsToLoad(self):
128 """Waits for all the batch navigated tabs to finish loading."""
129 end_time = time.time() + self._PAGE_LOAD_TIMEOUT_IN_SECONDS
130 for tab, initial_url in self._queued_tabs:
131 seconds_to_wait = end_time - time.time()
132 seconds_to_wait = max(0, seconds_to_wait)
133
134 if seconds_to_wait == 0:
135 break
136
137 # Since we don't wait any time for the tab url navigation to commit, it's
138 # possible that the tab hasn't started navigating yet.
139 current_url = self._RetrieveTabUrl(tab)
140
141 if current_url == initial_url:
142 # If the navigation hasn't been committed yet, wait a small amount of
143 # time. Don't bother rechecking the condition, since it's also possible
144 # that the web page isn't processing javascript.
145 time.sleep(self._NAVIGATION_COMMIT_WAIT_IN_SECONDS)
146
147 try:
148 tab.WaitForDocumentReadyStateToBeComplete(seconds_to_wait)
149 except (util.TimeoutException, exceptions.DevtoolsTargetCrashException):
150 # Ignore time outs and web page crashes.
151 pass
152 self._queued_tabs = []
153
154 def WillRunUserStory(self):
155 """
156 Finds the browser, starts the browser, and opens the requisite number of
157 tabs.
158 """
159 possible_browser = self._GetPossibleBrowser(self._finder_options)
160 self.browser = possible_browser.Create(self._finder_options)
161
162 for _ in range(self._NUM_TABS):
163 self.browser.tabs.New()
164
165 def RunUserStory(self):
166 """
167 Performs the navigations specified by |_navigation_urls| in large batches.
168 """
169 while True:
170 self._BatchNavigateTabs()
171 self._WaitForQueuedTabsToLoad()
172
173 if self._navigation_url_index == len(self._navigation_urls):
174 break
175
176 def TearDownState(self):
177 """
178 Teardown that is guaranteed to be executed before the instance is destroyed.
179 """
180 if self.browser:
181 self.browser.Close()
182 self.browser = None
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698