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

Side by Side Diff: chrome/test/functional/media/media_constrained_network_perf.py

Issue 8802030: Introduce new PyAuto test to measure EPT, TTP metrics. (Closed) Base URL: http://git.chromium.org/chromium/src.git@master
Patch Set: Fixup www-data path. Created 9 years 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
(Empty)
1 #!/usr/bin/env python
2 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
5
6 """Records metrics on playing media under constrained network conditions.
7
8 Spins up a Constrained Network Server (CNS) and runs through a test matrix of
9 bandwidth, latency, and packet loss settings. Each run records a
10 time-to-playback (TTP) and extra-play-percentage (EPP) metric in a format
11 consumable by the Chromium perf bots.
12
13 Since even a small number of different settings yields a large test matrix, the
14 design is threaded... however PyAuto is not, so a global lock is used when calls
15 into PyAuto are necessary. The number of threads can be set by _TEST_THREADS.
16
17 The CNS code is located under: <root>/src/media/tools/constrained_network_server
18 """
19
20 import itertools
21 import os
22 import Queue
23 import subprocess
24 import sys
25 import threading
26
27 import pyauto_media
28 import pyauto
29 import pyauto_paths
30 import pyauto_utils
31
32
33 # Settings for each network constraint.
34 _BANDWIDTH_SETTINGS_KBPS = {'None': 0, 'Low': 256, 'Medium': 2000, 'High': 5000}
35 _LATENCY_SETTINGS_MS = {'None': 0, 'Low': 43, 'Medium': 105, 'High': 180}
36 _PACKET_LOSS_SETTINGS_PERCENT = {'None': 0, 'Medium': 2, 'High': 5}
37
38 # Test constraints are all possible combination of the above settings. Each
39 # tuple must be of the form (Bandwidth, Latency, Packet Loss).
40 _TEST_CONSTRAINTS = itertools.product(
41 _BANDWIDTH_SETTINGS_KBPS.values(),
42 _LATENCY_SETTINGS_MS.values(),
43 _PACKET_LOSS_SETTINGS_PERCENT.values())
44
45 _TEST_CONSTRAINT_NAMES = itertools.product(
46 _BANDWIDTH_SETTINGS_KBPS.keys(),
47 _LATENCY_SETTINGS_MS.keys(),
48 _PACKET_LOSS_SETTINGS_PERCENT.keys())
49
50 # HTML test path; relative to src/chrome/test/data. Loads a test video and
51 # records metrics in JavaScript.
52 _TEST_HTML_PATH = os.path.join(
53 'media', 'html', 'media_constrained_network.html')
54
55 # Number of threads to use during testing.
56 _TEST_THREADS = 3
57
58 # File name of video to collect metrics for.
59 # TODO(dalecurtis): Should be set on the command line.
60 _TEST_VIDEO = 'roller.webm'
61
62 # Path to CNS executable relative to source root.
63 _CNS_PATH = os.path.join(
64 'media', 'tools', 'constrained_network_server', 'cns.py')
65
66 # Port to start the CNS on.
67 _CNS_PORT = 9000
68
69 # Base CNS URL, only requires & separated parameter names appended.
70 _CNS_BASE_URL = 'http://127.0.0.1:%d/ServeConstrained?' % _CNS_PORT
71
72
73 class TestWorker(threading.Thread):
74 """Worker thread. For each queue entry: opens tab, runs test, closes tab."""
75
76 # Atomic, monotonically increasing task identifier. Used to ID tabs.
77 _task_id = itertools.count()
78
79 def __init__(self, pyauto_test, tasks, automation_lock, url):
80 """Sets up TestWorker class variables.
81
82 Args:
83 pyauto_test: Reference to a pyauto.PyUITest instance.
84 tasks: Queue containing (settings, name) tuples.
85 automation_lock: Global automation lock for pyauto calls.
86 url: File URL to HTML/JavaScript test code.
87 """
88 threading.Thread.__init__(self)
89 self._tasks = tasks
90 self._automation_lock = automation_lock
91 self._pyauto = pyauto_test
92 self._url = url
93 self.start()
94
95 def _FindTabLocked(self, url):
96 """Returns the tab index for the tab belonging to this url.
97
98 self._automation_lock must be owned by caller.
99 """
100 for tab in self._pyauto.GetBrowserInfo()['windows'][0]['tabs']:
101 if tab['url'] == url:
102 return tab['index']
103
104 def _HaveMetrics(self, unique_url):
105 """Returns true if metrics are ready. Set self.{_epp,_ttp} < 0 pre-run."""
106 with self._automation_lock:
107 tab = self._FindTabLocked(unique_url)
108
109 if self._epp < 0:
110 self._epp = self._pyauto.GetDOMValue(
111 'extra_play_percentage', tab_index=tab)
112 if self._ttp < 0:
113 self._ttp = self._pyauto.GetDOMValue('time_to_playback', tab_index=tab)
114 return self._epp >= 0 and self._ttp >= 0
115
116 def run(self):
117 """Opens tab, starts HTML test, and records metrics for each queue entry.
118
119 No exception handling is done to make sure the main thread exits properly
120 during Chrome crashes or other failures. Doing otherwise has the potential
121 to leave the CNS server running in the background.
122
123 For a clean shutdown, put the magic exit value (None, None) in the queue.
124 """
125 while True:
126 settings, name = self._tasks.get()
127
128 # Check for magic exit values.
129 if (settings, name) == (None, None):
130 break
131
132 # Build video source URL. Values <= 0 mean the setting is disabled.
133 video_url = [_CNS_BASE_URL, 'f=' + _TEST_VIDEO]
134 if settings[0] > 0:
135 video_url.append('bandwidth=%d' % settings[0])
136 if settings[1] > 0:
137 video_url.append('latency=%d' % settings[1])
138 if settings[2] > 0:
139 video_url.append('loss=%d' % settings[2])
140 video_url = '&'.join(video_url)
141
142 # Make the test URL unique so we can figure out our tab index later.
143 unique_url = '%s?%d' % (self._url, TestWorker._task_id.next())
144
145 # Start the test!
146 with self._automation_lock:
147 self._pyauto.AppendTab(pyauto.GURL(unique_url))
148 self._pyauto.CallJavascriptFunc(
149 'startTest', [video_url], tab_index=self._FindTabLocked(unique_url))
150
151 # Wait until the necessary metrics have been collected. Okay to not lock
152 # here since pyauto.WaitUntil doesn't call into Chrome.
153 self._epp = self._ttp = -1
154 self._pyauto.WaitUntil(
155 self._HaveMetrics, args=[unique_url], retry_sleep=2)
156
157 # Record results.
158 # TODO(dalecurtis): Support reference builds.
159 series_name = ''.join(name)
160 pyauto_utils.PrintPerfResult('epp', series_name, self._epp, '%')
161 pyauto_utils.PrintPerfResult('ttp', series_name, self._ttp, 'ms')
162
163 # Close the tab.
164 with self._automation_lock:
165 self._pyauto.GetBrowserWindow(0).GetTab(
166 self._FindTabLocked(unique_url)).Close(True)
167
168 # TODO(dalecurtis): Check results for regressions.
169 self._tasks.task_done()
170
171
172 class MediaConstrainedNetworkPerfTest(pyauto.PyUITest):
173 """PyAuto test container. See file doc string for more information."""
174
175 def setUp(self):
176 """Starts the Constrained Network Server (CNS)."""
177 cmd = [sys.executable, os.path.join(pyauto_paths.GetSourceDir(), _CNS_PATH),
178 '--port', str(_CNS_PORT),
179 '--interface', 'lo',
180 '--www-root', os.path.join(
181 self.DataDir(), 'pyauto_private', 'media')]
182 process = subprocess.Popen(cmd, stderr=subprocess.PIPE)
183
184 # Wait for server to start up.
185 line = True
186 while line:
187 line = process.stderr.readline()
188 if 'STARTED' in line:
189 self._server_pid = process.pid
190 pyauto.PyUITest.setUp(self)
191 return
192 self.fail('Failed to start CNS.')
193
194 def tearDown(self):
195 """Stops the Constrained Network Server (CNS)."""
196 pyauto.PyUITest.tearDown(self)
197 self.Kill(self._server_pid)
198
199 def testConstrainedNetworkPerf(self):
200 """Starts CNS, spins up worker threads to run through _TEST_CONSTRAINTS."""
201 # Convert relative test path into an absolute path.
202 test_url = self.GetFileURLForDataPath(_TEST_HTML_PATH)
203
204 # PyAuto doesn't support threads, so we synchronize all automation calls.
205 automation_lock = threading.Lock()
206
207 # Spin up worker threads.
208 tasks = Queue.Queue()
209 threads = []
210 for _ in xrange(_TEST_THREADS):
211 threads.append(TestWorker(self, tasks, automation_lock, test_url))
212
213 for settings, name in zip(_TEST_CONSTRAINTS, _TEST_CONSTRAINT_NAMES):
214 tasks.put((settings, name))
215
216 # Add shutdown magic to end of queue.
217 for thread in threads:
218 tasks.put((None, None))
219
220 # Wait for threads to exit, gracefully or otherwise.
221 for thread in threads:
222 thread.join()
223
224
225 if __name__ == '__main__':
226 # TODO(dalecurtis): Process command line parameters here.
227 pyauto_media.Main()
OLDNEW
« no previous file with comments | « chrome/test/data/media/html/media_constrained_network.html ('k') | chrome/test/functional/media/pyauto_media.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698