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

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

Issue 939143004: Telemetry: Fix several small problems in the profile creator. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: 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
OLDNEW
1 # Copyright 2015 The Chromium Authors. All rights reserved. 1 # Copyright 2015 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be 2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file. 3 # found in the LICENSE file.
4 import time 4 import time
5 5
6 from telemetry.core import browser_finder 6 from telemetry.core import browser_finder
7 from telemetry.core import browser_finder_exceptions 7 from telemetry.core import browser_finder_exceptions
8 from telemetry.core import exceptions 8 from telemetry.core import exceptions
9 from telemetry.core import platform 9 from telemetry.core import platform
10 from telemetry.core import util 10 from telemetry.core import util
11 from telemetry.core.backends.chrome_inspector import devtools_http
11 12
12 13
13 class FastNavigationProfileExtender(object): 14 class FastNavigationProfileExtender(object):
14 """Extends a Chrome profile. 15 """Extends a Chrome profile.
15 16
16 This class creates or extends an existing profile by performing a set of tab 17 This class creates or extends an existing profile by performing a set of tab
17 navigations in large batches. This is accomplished by opening a large number 18 navigations in large batches. This is accomplished by opening a large number
18 of tabs, simultaneously navigating all the tabs, and then waiting for all the 19 of tabs, simultaneously navigating all the tabs, and then waiting for all the
19 tabs to load. This provides two benefits: 20 tabs to load. This provides two benefits:
20 - Takes advantage of the high number of logical cores on modern CPUs. 21 - Takes advantage of the high number of logical cores on modern CPUs.
(...skipping 12 matching lines...) Expand all
33 34
34 # The path of the profile that the browser will use while it's running. 35 # The path of the profile that the browser will use while it's running.
35 # This member is initialized during SetUp(). 36 # This member is initialized during SetUp().
36 self._profile_path = None 37 self._profile_path = None
37 38
38 # A reference to the browser that will be performing all of the tab 39 # A reference to the browser that will be performing all of the tab
39 # navigations. 40 # navigations.
40 # This member is initialized during SetUp(). 41 # This member is initialized during SetUp().
41 self._browser = None 42 self._browser = None
42 43
44 # The list of tabs to use for url navigations. This list may not contain
45 # all tabs in the browser.
46 self._navigation_tabs = []
47
43 # The number of tabs to use. 48 # The number of tabs to use.
44 self._NUM_TABS = maximum_batch_size 49 self._NUM_TABS = maximum_batch_size
45 50
46 # The amount of time to wait for a batch of pages to finish loading. 51 # The amount of time to wait for a batch of pages to finish loading.
47 self._BATCH_PAGE_LOAD_TIMEOUT_IN_SECONDS = 10 52 self._BATCH_PAGE_LOAD_TIMEOUT_IN_SECONDS = 10
48 53
49 # The default amount of time to wait for the retrieval of the URL of a tab. 54 # The default amount of time to wait for the retrieval of the URL of a tab.
50 self._TAB_URL_RETRIEVAL_TIMEOUT_IN_SECONDS = 1 55 self._TAB_URL_RETRIEVAL_TIMEOUT_IN_SECONDS = 1
51 56
52 def Run(self, finder_options): 57 def Run(self, finder_options):
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
88 implementation. 93 implementation.
89 """ 94 """
90 self._profile_path = finder_options.output_profile_path 95 self._profile_path = finder_options.output_profile_path
91 possible_browser = self._GetPossibleBrowser(finder_options) 96 possible_browser = self._GetPossibleBrowser(finder_options)
92 97
93 assert possible_browser.supports_tab_control 98 assert possible_browser.supports_tab_control
94 assert (platform.GetHostPlatform().GetOSName() in 99 assert (platform.GetHostPlatform().GetOSName() in
95 ["win", "mac", "linux"]) 100 ["win", "mac", "linux"])
96 self._browser = possible_browser.Create(finder_options) 101 self._browser = possible_browser.Create(finder_options)
97 102
98 while(len(self._browser.tabs) < self._NUM_TABS):
99 self._browser.tabs.New()
100
101 def TearDown(self): 103 def TearDown(self):
102 """Teardown that is guaranteed to be executed before the instance is 104 """Teardown that is guaranteed to be executed before the instance is
103 destroyed. 105 destroyed.
104 106
105 Can be overridden by subclasses. Subclasses must call the super class 107 Can be overridden by subclasses. Subclasses must call the super class
106 implementation. 108 implementation.
107 """ 109 """
108 if self._browser: 110 if self._browser:
109 self._browser.Close() 111 self._browser.Close()
110 self._browser = None 112 self._browser = None
111 113
112 def CleanUpAfterBatchNavigation(self): 114 def CleanUpAfterBatchNavigation(self):
113 """A hook for subclasses to perform cleanup after each batch of 115 """A hook for subclasses to perform cleanup after each batch of
114 navigations. 116 navigations.
115 117
116 Can be overridden by subclasses. 118 Can be overridden by subclasses.
117 """ 119 """
118 pass 120 pass
119 121
120 @property 122 @property
121 def profile_path(self): 123 def profile_path(self):
122 return self._profile_path 124 return self._profile_path
123 125
126 def _RefreshNavigationTabs(self):
127 """Updates the member self._navigation_tabs to contain self._NUM_TABS
128 elements, each of which is not crashed. The crashed tabs are intentionally
129 leaked, since Telemetry doesn't have a good way of killing crashed tabs."""
130 live_tabs = []
131 for tab in self._navigation_tabs:
132 try:
133 live_tab = self._browser.tabs.GetTabById(tab.id)
nednguyen 2015/02/19 20:05:04 If you have to do this just to get the "live tab",
erikchen 2015/02/19 21:55:12 I've added comments - this method is doing more th
134 live_tabs.append(live_tab)
135 except KeyError:
136 pass
137
138 self._navigation_tabs = live_tabs
139
140 while len(self._navigation_tabs) < self._NUM_TABS:
141 self._navigation_tabs.append(self._browser.tabs.New())
142
143 def _RemoveNavigationTab(self, tab):
144 self._navigation_tabs.remove(tab)
145
124 def _GetPossibleBrowser(self, finder_options): 146 def _GetPossibleBrowser(self, finder_options):
125 """Return a possible_browser with the given options.""" 147 """Return a possible_browser with the given options."""
126 possible_browser = browser_finder.FindBrowser(finder_options) 148 possible_browser = browser_finder.FindBrowser(finder_options)
127 if not possible_browser: 149 if not possible_browser:
128 raise browser_finder_exceptions.BrowserFinderException( 150 raise browser_finder_exceptions.BrowserFinderException(
129 'No browser found.\n\nAvailable browsers:\n%s\n' % 151 'No browser found.\n\nAvailable browsers:\n%s\n' %
130 '\n'.join(browser_finder.GetAllAvailableBrowserTypes(finder_options))) 152 '\n'.join(browser_finder.GetAllAvailableBrowserTypes(finder_options)))
131 finder_options.browser_options.browser_type = ( 153 finder_options.browser_options.browser_type = (
132 possible_browser.browser_type) 154 possible_browser.browser_type)
133 155
134 return possible_browser 156 return possible_browser
135 157
136 def _RetrieveTabUrl(self, tab, timeout): 158 def _RetrieveTabUrl(self, tab, timeout):
137 """Retrives the URL of the tab.""" 159 """Retrives the URL of the tab."""
138 try: 160 try:
139 return tab.EvaluateJavaScript('document.URL', timeout) 161 return tab.EvaluateJavaScript('document.URL', timeout)
140 except exceptions.DevtoolsTargetCrashException: 162 except (exceptions.DevtoolsTargetCrashException,
163 devtools_http.DevToolsClientConnectionError,
164 devtools_http.DevToolsClientUrlError):
141 return None 165 return None
142 166
143 def _WaitForUrlToChange(self, tab, initial_url, timeout): 167 def _WaitForUrlToChange(self, tab, initial_url, timeout):
144 """Waits for the tab to navigate away from its initial url.""" 168 """Waits for the tab to navigate away from its initial url."""
145 end_time = time.time() + timeout 169 end_time = time.time() + timeout
146 while True: 170 while True:
147 seconds_to_wait = end_time - time.time() 171 seconds_to_wait = end_time - time.time()
148 seconds_to_wait = max(0, seconds_to_wait) 172 seconds_to_wait = max(0, seconds_to_wait)
149 173
150 if seconds_to_wait == 0: 174 if seconds_to_wait == 0:
(...skipping 20 matching lines...) Expand all
171 """ 195 """
172 timeout_in_seconds = 0 196 timeout_in_seconds = 0
173 197
174 queued_tabs = [] 198 queued_tabs = []
175 for tab, url in batch: 199 for tab, url in batch:
176 initial_url = self._RetrieveTabUrl(tab, 200 initial_url = self._RetrieveTabUrl(tab,
177 self._TAB_URL_RETRIEVAL_TIMEOUT_IN_SECONDS) 201 self._TAB_URL_RETRIEVAL_TIMEOUT_IN_SECONDS)
178 202
179 try: 203 try:
180 tab.Navigate(url, None, timeout_in_seconds) 204 tab.Navigate(url, None, timeout_in_seconds)
181 except exceptions.DevtoolsTargetCrashException: 205 except (exceptions.DevtoolsTargetCrashException,
182 # We expect a time out, and don't mind if the webpage crashes. Ignore 206 devtools_http.DevToolsClientConnectionError,
183 # both exceptions. 207 devtools_http.DevToolsClientUrlError):
208 # We expect a time out. It's possible for other problems to arise, but
209 # this method is not responsible for dealing with them. Ignore all
210 # exceptions.
184 pass 211 pass
185 212
186 queued_tabs.append((tab, initial_url)) 213 queued_tabs.append((tab, initial_url))
187 return queued_tabs 214 return queued_tabs
188 215
189 def _WaitForQueuedTabsToLoad(self, queued_tabs): 216 def _WaitForQueuedTabsToLoad(self, queued_tabs):
190 """Waits for all the batch navigated tabs to finish loading. 217 """Waits for all the batch navigated tabs to finish loading.
191 218
192 Args: 219 Args:
193 queued_tabs: A list of tuples (tab, initial_url). Each tab is guaranteed 220 queued_tabs: A list of tuples (tab, initial_url). Each tab is guaranteed
194 to have already been sent a navigation command. 221 to have already been sent a navigation command.
195 """ 222 """
196 end_time = time.time() + self._BATCH_PAGE_LOAD_TIMEOUT_IN_SECONDS 223 end_time = time.time() + self._BATCH_PAGE_LOAD_TIMEOUT_IN_SECONDS
197 for tab, initial_url in queued_tabs: 224 for tab, initial_url in queued_tabs:
198 seconds_to_wait = end_time - time.time() 225 seconds_to_wait = end_time - time.time()
199 seconds_to_wait = max(0, seconds_to_wait) 226 seconds_to_wait = max(0, seconds_to_wait)
200 227
201 if seconds_to_wait == 0: 228 if seconds_to_wait == 0:
202 break 229 break
203 230
204 # Since we don't wait any time for the tab url navigation to commit, it's 231 # Since we don't wait any time for the tab url navigation to commit, it's
205 # possible that the tab hasn't started navigating yet. 232 # possible that the tab hasn't started navigating yet.
206 self._WaitForUrlToChange(tab, initial_url, seconds_to_wait) 233 self._WaitForUrlToChange(tab, initial_url, seconds_to_wait)
207 234
208 seconds_to_wait = end_time - time.time() 235 seconds_to_wait = end_time - time.time()
209 seconds_to_wait = max(0, seconds_to_wait) 236 seconds_to_wait = max(0, seconds_to_wait)
210 237
211 try: 238 try:
212 tab.WaitForDocumentReadyStateToBeComplete(seconds_to_wait) 239 tab.WaitForDocumentReadyStateToBeComplete(seconds_to_wait)
213 except (util.TimeoutException, exceptions.DevtoolsTargetCrashException): 240 except util.TimeoutException:
214 # Ignore time outs and web page crashes. 241 # Ignore time outs.
215 pass 242 pass
243 except (exceptions.DevtoolsTargetCrashException,
244 devtools_http.DevToolsClientConnectionError,
245 devtools_http.DevToolsClientUrlError):
246 # If any error occurs, remove the tab. it's probably in an
247 # unrecoverable state.
248 self._RemoveNavigationTab(tab)
216 249
217 def _GetUrlsToNavigate(self, url_iterator): 250 def _GetUrlsToNavigate(self, url_iterator):
218 """Returns an array of urls to navigate to, given a url_iterator.""" 251 """Returns an array of urls to navigate to, given a url_iterator."""
219 urls = [] 252 urls = []
220 for _ in xrange(self._NUM_TABS): 253 for _ in xrange(self._NUM_TABS):
221 try: 254 try:
222 urls.append(url_iterator.next()) 255 urls.append(url_iterator.next())
223 except StopIteration: 256 except StopIteration:
224 break 257 break
225 return urls 258 return urls
226 259
227 def _PerformNavigations(self): 260 def _PerformNavigations(self):
228 """Repeatedly fetches a batch of urls, and navigates to those urls. This 261 """Repeatedly fetches a batch of urls, and navigates to those urls. This
229 will run until an empty batch is returned, or 262 will run until an empty batch is returned, or
230 ShouldExitAfterBatchNavigation() returns True. 263 ShouldExitAfterBatchNavigation() returns True.
231 """ 264 """
232 url_iterator = self.GetUrlIterator() 265 url_iterator = self.GetUrlIterator()
233 while True: 266 while True:
267 self._RefreshNavigationTabs()
234 urls = self._GetUrlsToNavigate(url_iterator) 268 urls = self._GetUrlsToNavigate(url_iterator)
235 269
236 if len(urls) == 0: 270 if len(urls) == 0:
237 break 271 break
238 272
239 batch = [] 273 batch = []
240 for i in range(len(urls)): 274 for i in range(len(urls)):
241 url = urls[i] 275 url = urls[i]
242 tab = self._browser.tabs[i] 276 tab = self._navigation_tabs[i]
243 batch.append((tab, url)) 277 batch.append((tab, url))
244 278
245 queued_tabs = self._BatchNavigateTabs(batch) 279 queued_tabs = self._BatchNavigateTabs(batch)
246 self._WaitForQueuedTabsToLoad(queued_tabs) 280 self._WaitForQueuedTabsToLoad(queued_tabs)
247 281
248 self.CleanUpAfterBatchNavigation() 282 self.CleanUpAfterBatchNavigation()
249 283
250 if self.ShouldExitAfterBatchNavigation(): 284 if self.ShouldExitAfterBatchNavigation():
251 break 285 break
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698