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

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: Remove changes to profile_generator.py. 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 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 # The amount of time to wait for a navigation to be committed.
50 self._NAVIGATION_COMMIT_WAIT_IN_SECONDS = 0.1
51
52 def Run(self, finder_options):
53 """Extends the profile.
54
55 Args:
56 finder_options: An instance of BrowserFinderOptions that contains the
57 directory of the input profile, the directory to place the output
58 profile, and sufficient information to choose a specific browser binary.
59 """
60 try:
61 self._navigation_urls = self.GetUrlsToNavigate()
62 self._SetUpBrowser(finder_options)
63 self._PerformNavigations()
64 finally:
65 self._TearDownBrowser()
66
67 def GetUrlsToNavigate(self):
68 """Returns a list of urls to be navigated to.
69
70 Intended for subclass override.
71 """
72 raise NotImplementedError()
73
74
75 def _GetPossibleBrowser(self, finder_options):
76 """Return a possible_browser with the given options."""
77 possible_browser = browser_finder.FindBrowser(finder_options)
78 if not possible_browser:
79 raise browser_finder_exceptions.BrowserFinderException(
80 'No browser found.\n\nAvailable browsers:\n%s\n' %
81 '\n'.join(browser_finder.GetAllAvailableBrowserTypes(finder_options)))
82 finder_options.browser_options.browser_type = (
83 possible_browser.browser_type)
84
85 return possible_browser
86
87 def _RetrieveTabUrl(self, tab):
88 """Retrives the URL of the tab."""
89 try:
90 return tab.EvaluateJavaScript('document.URL',
91 self._TAB_URL_RETRIEVAL_TIMEOUT_IN_SECONDS)
92 except exceptions.DevtoolsTargetCrashException:
93 return None
94
95 def _BatchNavigateTabs(self, batch):
96 """Performs a batch of tab navigations with minimal delay.
97
98 Args:
99 batch: A list of tuples (tab, url).
100
101 Returns:
102 A list of tuples (tab, initial_url). |initial_url| is the url of the
103 |tab| prior to a navigation command being sent to it.
104 """
105 timeout_in_seconds = 0
106
107 queued_tabs = []
108 for tab, url in batch:
109 initial_url = self._RetrieveTabUrl(tab)
110
111 try:
112 tab.Navigate(url, None, timeout_in_seconds)
113 except exceptions.DevtoolsTargetCrashException:
114 # We expect a time out, and don't mind if the webpage crashes. Ignore
115 # both exceptions.
116 pass
117
118 queued_tabs.append((tab, initial_url))
119 return queued_tabs
120
121 def _WaitForQueuedTabsToLoad(self, queued_tabs):
122 """Waits for all the batch navigated tabs to finish loading.
123
124 Args:
125 queued_tabs: A list of tuples (tab, initial_url). Each tab is guaranteed
126 to have already been sent a navigation command.
127 """
128 end_time = time.time() + self._BATCH_PAGE_LOAD_TIMEOUT_IN_SECONDS
129 for tab, initial_url in queued_tabs:
130 seconds_to_wait = end_time - time.time()
131 seconds_to_wait = max(0, seconds_to_wait)
132
133 if seconds_to_wait == 0:
134 break
135
136 # Since we don't wait any time for the tab url navigation to commit, it's
137 # possible that the tab hasn't started navigating yet.
138 current_url = self._RetrieveTabUrl(tab)
139
140 if current_url == initial_url:
141 # If the navigation hasn't been committed yet, wait a small amount of
142 # time. Don't bother rechecking the condition, since it's also possible
143 # that the web page isn't processing javascript.
144 time.sleep(self._NAVIGATION_COMMIT_WAIT_IN_SECONDS)
nednguyen 2015/02/12 20:54:21 Please wait for the WaitForNavigate CL landed & up
erikchen 2015/02/17 19:00:20 Done. The CL now uses WaitForNavigate(), and no lo
145
146 try:
147 tab.WaitForDocumentReadyStateToBeComplete(seconds_to_wait)
148 except (util.TimeoutException, exceptions.DevtoolsTargetCrashException):
149 # Ignore time outs and web page crashes.
150 pass
151
152 def _SetUpBrowser(self, finder_options):
153 """Finds the browser, starts the browser, and opens the requisite number of
154 tabs."""
155 possible_browser = self._GetPossibleBrowser(finder_options)
156 self._browser = possible_browser.Create(finder_options)
157
158 for _ in range(self._NUM_TABS):
159 self._browser.tabs.New()
160
161 def _PerformNavigations(self):
162 """Performs the navigations specified by |_navigation_urls| in large
163 batches."""
164 # The index of the first url that has not yet been navigated to.
165 navigation_url_index = 0
166 while True:
167 # Generate the next batch of navigations.
168 batch = []
169 max_index = min(navigation_url_index + self._NUM_PARALLEL_PAGES,
170 len(self._navigation_urls))
171 for i in range(navigation_url_index, max_index):
172 url = self._navigation_urls[i]
173 tab = self._browser.tabs[i % self._NUM_TABS]
174 batch.append((tab, url))
175 navigation_url_index = max_index
176
177 queued_tabs = self._BatchNavigateTabs(batch)
178 self._WaitForQueuedTabsToLoad(queued_tabs)
179
180 if navigation_url_index == len(self._navigation_urls):
181 break
182
183 def _TearDownBrowser(self):
184 """Teardown that is guaranteed to be executed before the instance is
185 destroyed."""
186 if self._browser:
187 self._browser.Close()
188 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