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

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: Wait for tab urls to change as a sign that navigation has started. 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 | tools/perf/profile_creators/fast_navigation_profile_extender_unittest.py » ('j') | 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 2015 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 """Extends a Chrome profile.
14
15 This class creates or extends an existing profile by performing a set of tab
16 navigations in large batches. This is accomplished by opening a large number
17 of tabs, simultaneously navigating all the tabs, and then waiting for all the
18 tabs to load. This provides two benefits:
19 - Takes advantage of the high number of logical cores on modern CPUs.
20 - The total time spent waiting for navigations to time out scales linearly
21 with the number of batches, but does not scale with the size of the
22 batch.
23 """
24 def __init__(self):
25 super(FastNavigationProfileExtender, self).__init__()
26
27 # A reference to the browser that will be performing all of the tab
28 # navigations.
29 self._browser = None
30
31 # A static copy of the urls that this class is going to navigate to.
32 self._navigation_urls = None
33
34 # The number of tabs to use.
35 self._NUM_TABS = 15
36
37 # The number of pages to load in parallel.
38 self._NUM_PARALLEL_PAGES = 15
39
40 assert self._NUM_PARALLEL_PAGES <= self._NUM_TABS, (' the batch size can\'t'
41 ' be larger than the number of available tabs')
42
43 # The amount of time to wait for a batch of pages to finish loading.
44 self._BATCH_PAGE_LOAD_TIMEOUT_IN_SECONDS = 10
45
46 # The default amount of time to wait for the retrieval of the URL of a tab.
47 self._TAB_URL_RETRIEVAL_TIMEOUT_IN_SECONDS = 1
48
49 def Run(self, finder_options):
50 """Extends the profile.
51
52 Args:
53 finder_options: An instance of BrowserFinderOptions that contains the
54 directory of the input profile, the directory to place the output
55 profile, and sufficient information to choose a specific browser binary.
56 """
57 try:
58 self._navigation_urls = self.GetUrlsToNavigate()
59 self._SetUpBrowser(finder_options)
60 self._PerformNavigations()
61 finally:
62 self._TearDownBrowser()
63
64 def GetUrlsToNavigate(self):
65 """Returns a list of urls to be navigated to.
66
67 Intended for subclass override.
68 """
69 raise NotImplementedError()
70
71
72 def _GetPossibleBrowser(self, finder_options):
73 """Return a possible_browser with the given options."""
74 possible_browser = browser_finder.FindBrowser(finder_options)
75 if not possible_browser:
76 raise browser_finder_exceptions.BrowserFinderException(
77 'No browser found.\n\nAvailable browsers:\n%s\n' %
78 '\n'.join(browser_finder.GetAllAvailableBrowserTypes(finder_options)))
79 finder_options.browser_options.browser_type = (
80 possible_browser.browser_type)
81
82 return possible_browser
83
84 def _RetrieveTabUrl(self, tab, timeout):
85 """Retrives the URL of the tab."""
86 try:
87 return tab.EvaluateJavaScript('document.URL', timeout)
88 except exceptions.DevtoolsTargetCrashException:
89 return None
90
91 def _WaitForUrlToChange(self, tab, initial_url, timeout):
nednguyen 2015/02/17 23:38:10 telemetry already has a util.Waitfor method that d
erikchen 2015/02/17 23:46:10 The function util.WaitFor() does not work well her
nednguyen 2015/02/17 23:50:10 You can making it configurable by making those par
erikchen 2015/02/17 23:59:38 The conditional itself requires a dynamic variable
92 """Waits for the tab to navigate away from its initial url."""
93 end_time = time.time() + timeout
94 while True:
95 seconds_to_wait = end_time - time.time()
96 seconds_to_wait = max(0, seconds_to_wait)
97
98 if seconds_to_wait == 0:
99 break
100
101 current_url = self._RetrieveTabUrl(tab, seconds_to_wait)
102 if current_url != initial_url:
103 break
104
105 # Retrieving the current url is a non-trivial operation. Add a small
106 # sleep here to prevent this method from contending with the actual
107 # navigation.
108 time.sleep(0.01)
109
110 def _BatchNavigateTabs(self, batch):
111 """Performs a batch of tab navigations with minimal delay.
112
113 Args:
114 batch: A list of tuples (tab, url).
115
116 Returns:
117 A list of tuples (tab, initial_url). |initial_url| is the url of the
118 |tab| prior to a navigation command being sent to it.
119 """
120 timeout_in_seconds = 0
121
122 queued_tabs = []
123 for tab, url in batch:
124 initial_url = self._RetrieveTabUrl(tab,
125 self._TAB_URL_RETRIEVAL_TIMEOUT_IN_SECONDS)
126
127 try:
128 tab.Navigate(url, None, timeout_in_seconds)
129 except exceptions.DevtoolsTargetCrashException:
130 # We expect a time out, and don't mind if the webpage crashes. Ignore
131 # both exceptions.
132 pass
133
134 queued_tabs.append((tab, initial_url))
135 return queued_tabs
136
137 def _WaitForQueuedTabsToLoad(self, queued_tabs):
138 """Waits for all the batch navigated tabs to finish loading.
139
140 Args:
141 queued_tabs: A list of tuples (tab, initial_url). Each tab is guaranteed
142 to have already been sent a navigation command.
143 """
144 end_time = time.time() + self._BATCH_PAGE_LOAD_TIMEOUT_IN_SECONDS
145 for tab, initial_url in queued_tabs:
146 seconds_to_wait = end_time - time.time()
147 seconds_to_wait = max(0, seconds_to_wait)
148
149 if seconds_to_wait == 0:
150 break
151
152 # Since we don't wait any time for the tab url navigation to commit, it's
153 # possible that the tab hasn't started navigating yet.
154 self._WaitForUrlToChange(tab, initial_url, seconds_to_wait)
155
156 seconds_to_wait = end_time - time.time()
157 seconds_to_wait = max(0, seconds_to_wait)
158
159 try:
160 tab.WaitForDocumentReadyStateToBeComplete(seconds_to_wait)
161 except (util.TimeoutException, exceptions.DevtoolsTargetCrashException):
162 # Ignore time outs and web page crashes.
163 pass
164
165 def _SetUpBrowser(self, finder_options):
166 """Finds the browser, starts the browser, and opens the requisite number of
167 tabs."""
168 possible_browser = self._GetPossibleBrowser(finder_options)
169 self._browser = possible_browser.Create(finder_options)
170
171 for _ in range(self._NUM_TABS):
172 self._browser.tabs.New()
173
174 def _PerformNavigations(self):
175 """Performs the navigations specified by |_navigation_urls| in large
176 batches."""
177 # The index of the first url that has not yet been navigated to.
178 navigation_url_index = 0
179 while True:
180 # Generate the next batch of navigations.
181 batch = []
182 max_index = min(navigation_url_index + self._NUM_PARALLEL_PAGES,
183 len(self._navigation_urls))
184 for i in range(navigation_url_index, max_index):
185 url = self._navigation_urls[i]
186 tab = self._browser.tabs[i % self._NUM_TABS]
187 batch.append((tab, url))
188 navigation_url_index = max_index
189
190 queued_tabs = self._BatchNavigateTabs(batch)
191 self._WaitForQueuedTabsToLoad(queued_tabs)
192
193 if navigation_url_index == len(self._navigation_urls):
194 break
195
196 def _TearDownBrowser(self):
197 """Teardown that is guaranteed to be executed before the instance is
198 destroyed."""
199 if self._browser:
200 self._browser.Close()
201 self._browser = None
OLDNEW
« no previous file with comments | « no previous file | tools/perf/profile_creators/fast_navigation_profile_extender_unittest.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698