PageRenderTime 58ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/tools/perf/page_sets/media_cases.py

http://github.com/chromium/chromium
Python | 390 lines | 258 code | 48 blank | 84 comment | 15 complexity | 795d807c3425110bae8c2ab28768a5d8 MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.0, BSD-2-Clause, LGPL-2.1, MPL-2.0, 0BSD, EPL-1.0, MPL-2.0-no-copyleft-exception, GPL-2.0, BitTorrent-1.0, CPL-1.0, LGPL-3.0, Unlicense, BSD-3-Clause, CC0-1.0, JSON, MIT, GPL-3.0, CC-BY-SA-3.0, AGPL-1.0
  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. # This file defines performance test scenarios related to playing video and
  5. # audio files using HTML5 APIs (as opposed to older tech like Flash and
  6. # Silverlight). These scenarios simply exercise the Chromium code in particular
  7. # ways. The metrics that are produced are calculated in a separate step.
  8. import abc
  9. from telemetry.page import page as page_module
  10. from telemetry.page import traffic_setting as traffic_setting_module
  11. from telemetry import story
  12. # A complete list of page tags to check. This prevents misspellings and provides
  13. # documentation of scenarios for code readers. These tags can be used to filter
  14. # the list of pages to run using flags like --story-tag-filter=X.
  15. _PAGE_TAGS_LIST = [
  16. # Audio codecs.
  17. 'pcm',
  18. 'mp3',
  19. 'aac',
  20. 'vorbis',
  21. 'opus',
  22. # Video codecs.
  23. 'av1',
  24. 'h264',
  25. 'vp8',
  26. 'vp9',
  27. # Test types.
  28. 'audio_video',
  29. 'audio_only',
  30. 'video_only',
  31. # Other filter tags.
  32. 'is_50fps',
  33. 'is_4k',
  34. # Play action.
  35. 'seek',
  36. 'beginning_to_end',
  37. 'background',
  38. # Add javascript load.
  39. 'busyjs',
  40. # Constrained network settings.
  41. 'cns',
  42. # VideoStack API.
  43. 'src',
  44. 'mse'
  45. ]
  46. # A list of traffic setting names to append to page names when used.
  47. # Traffic settings is a way to constrain the network to match real-world
  48. # scenarios.
  49. _TRAFFIC_SETTING_NAMES = {
  50. traffic_setting_module.GPRS: 'GPRS',
  51. traffic_setting_module.REGULAR_2G: 'Regular-2G',
  52. traffic_setting_module.GOOD_2G: 'Good-2G',
  53. traffic_setting_module.REGULAR_3G: 'Regular-3G',
  54. traffic_setting_module.GOOD_3G: 'Good-3G',
  55. traffic_setting_module.REGULAR_4G: 'Regular-4G',
  56. traffic_setting_module.DSL: 'DSL',
  57. traffic_setting_module.WIFI: 'WiFi',
  58. }
  59. _URL_BASE = 'file://media_cases/'
  60. #
  61. # The following section contains base classes for pages.
  62. #
  63. class _MediaPage(page_module.Page):
  64. def __init__(self, url, page_set, tags, extra_browser_args=None,
  65. traffic_setting=traffic_setting_module.NONE):
  66. name = url.split('/')[-1]
  67. if traffic_setting != traffic_setting_module.NONE:
  68. name += '_' + _TRAFFIC_SETTING_NAMES[traffic_setting]
  69. tags.append('cns')
  70. if tags:
  71. for t in tags:
  72. assert t in _PAGE_TAGS_LIST
  73. assert not ('src' in tags and 'mse' in tags)
  74. super(_MediaPage, self).__init__(
  75. url=url, page_set=page_set, tags=tags, name=name,
  76. extra_browser_args=extra_browser_args,
  77. traffic_setting=traffic_setting)
  78. def GetExtraTracingMetrics(self):
  79. metrics = super(_MediaPage, self).GetExtraTracingMetrics()
  80. if self.ShouldMeasureMemory():
  81. metrics.append('memoryMetric')
  82. return metrics
  83. def ShouldMeasureMemory(self):
  84. """Returns whether the page should do a memory dump.
  85. Also controls whether the pages enables the memory metric.
  86. Subclasses should override to disable memory measurement.
  87. Memory dumps are cpu-intensive, so it is reasonable keep it off in
  88. some cases to avoid skewing cpu usage measurements.
  89. """
  90. return True
  91. class _BeginningToEndPlayPage(_MediaPage):
  92. """A normal play page simply plays the given media until the end."""
  93. def __init__(self, url, page_set, tags, extra_browser_args=None,
  94. traffic_setting=traffic_setting_module.NONE):
  95. tags.append('beginning_to_end')
  96. tags.append('src')
  97. super(_BeginningToEndPlayPage, self).__init__(
  98. url, page_set, tags, extra_browser_args,
  99. traffic_setting=traffic_setting)
  100. def RunPageInteractions(self, action_runner):
  101. # Play the media until it has finished or it times out.
  102. action_runner.PlayMedia(playing_event_timeout_in_seconds=60,
  103. ended_event_timeout_in_seconds=60)
  104. # Generate memory dump for memoryMetric.
  105. if self.ShouldMeasureMemory():
  106. action_runner.MeasureMemory()
  107. class _SeekPage(_MediaPage):
  108. """A seek page seeks twice in the video and measures the seek time."""
  109. def __init__(self, url, page_set, tags, extra_browser_args=None,
  110. action_timeout_in_seconds=60,
  111. traffic_setting=traffic_setting_module.NONE):
  112. tags.append('seek')
  113. tags.append('src')
  114. self._action_timeout = action_timeout_in_seconds
  115. super(_SeekPage, self).__init__(
  116. url, page_set, tags, extra_browser_args,
  117. traffic_setting=traffic_setting)
  118. def RunPageInteractions(self, action_runner):
  119. timeout = self._action_timeout
  120. # Start the media playback.
  121. action_runner.PlayMedia(
  122. playing_event_timeout_in_seconds=timeout)
  123. # Wait for 1 second so that we know the play-head is at ~1s.
  124. action_runner.Wait(1)
  125. # Seek to before the play-head location.
  126. action_runner.SeekMedia(seconds=0.5, timeout_in_seconds=timeout,
  127. label='seek_warm')
  128. # Seek to after the play-head location.
  129. action_runner.SeekMedia(seconds=9, timeout_in_seconds=timeout,
  130. label='seek_cold')
  131. # Generate memory dump for memoryMetric.
  132. if self.ShouldMeasureMemory():
  133. action_runner.MeasureMemory()
  134. class _BackgroundPlaybackPage(_MediaPage):
  135. """A Background playback page plays the given media in a background tab.
  136. The motivation for this test case is crbug.com/678663.
  137. """
  138. def __init__(self, url, page_set, tags, extra_browser_args=None,
  139. background_time=10,
  140. traffic_setting=traffic_setting_module.NONE):
  141. self._background_time = background_time
  142. tags.append('background')
  143. tags.append('src')
  144. # --disable-background-media-suspend is required since for Android,
  145. # background playback gets suspended. This flag makes Android work the same
  146. # way as desktop and not turn off video playback in the background.
  147. extra_browser_args = extra_browser_args or []
  148. extra_browser_args.append('--disable-background-media-suspend')
  149. super(_BackgroundPlaybackPage, self).__init__(
  150. url, page_set, tags, extra_browser_args)
  151. def RunPageInteractions(self, action_runner):
  152. # Steps:
  153. # 1. Play a video
  154. # 2. Open new tab overtop to obscure the video
  155. # 3. Close the tab to go back to the tab that is playing the video.
  156. action_runner.PlayMedia(
  157. playing_event_timeout_in_seconds=60)
  158. action_runner.Wait(.5)
  159. new_tab = action_runner.tab.browser.tabs.New()
  160. new_tab.Activate()
  161. action_runner.Wait(self._background_time)
  162. new_tab.Close()
  163. action_runner.Wait(.5)
  164. # Generate memory dump for memoryMetric.
  165. if self.ShouldMeasureMemory():
  166. action_runner.MeasureMemory()
  167. class _MSEPage(_MediaPage):
  168. def __init__(self, url, page_set, tags, extra_browser_args=None,
  169. number_of_runs=10):
  170. assert number_of_runs >= 1
  171. self._number_of_runs = number_of_runs
  172. tags.append('mse')
  173. super(_MSEPage, self).__init__(
  174. url, page_set, tags, extra_browser_args)
  175. def RunPageInteractions(self, action_runner):
  176. # The page automatically runs the test at load time.
  177. self._CheckTestResult(action_runner)
  178. # Now run it a few more times to get more reliable data.
  179. # Note that each run takes ~.5s, so running a bunch of times to get reliable
  180. # data is reasonable.
  181. for _ in range(self._number_of_runs - 1):
  182. url = action_runner.tab.url
  183. action_runner.tab.ClearCache(force=True)
  184. action_runner.tab.Navigate(url)
  185. self._CheckTestResult(action_runner)
  186. def _CheckTestResult(self, action_runner):
  187. action_runner.WaitForJavaScriptCondition('window.__testDone == true')
  188. test_failed = action_runner.EvaluateJavaScript('window.__testFailed')
  189. if test_failed:
  190. raise RuntimeError(action_runner.EvaluateJavaScript('window.__testError'))
  191. def ShouldMeasureMemory(self):
  192. return False
  193. def _GetDesktopOnlyMediaPages(page_set):
  194. return [
  195. _BeginningToEndPlayPage(
  196. url=_URL_BASE + 'video.html?src=tulip0.av1.mp4',
  197. page_set=page_set,
  198. tags=['av1', 'video_only']),
  199. _SeekPage(
  200. url=_URL_BASE + 'video.html?src=tulip0.av1.mp4&seek',
  201. page_set=page_set,
  202. tags=['av1', 'video_only', 'seek']),
  203. _MSEPage(
  204. url=_URL_BASE + 'mse.html?media=tulip0.av1.mp4',
  205. page_set=page_set,
  206. tags=['av1', 'video_only']),
  207. ]
  208. def _GetCrossPlatformMediaPages(page_set):
  209. return [
  210. # 1080p 50fps crowd test cases. High non-60fps frame rate is good for
  211. # finding rendering and efficiency regressions.
  212. _BeginningToEndPlayPage(
  213. url=_URL_BASE + 'video.html?src=crowd1080.webm',
  214. page_set=page_set,
  215. tags=['is_50fps', 'vp8', 'vorbis', 'audio_video']),
  216. _BeginningToEndPlayPage(
  217. url=_URL_BASE + 'video.html?src=crowd1080.mp4',
  218. page_set=page_set,
  219. tags=['is_50fps', 'h264', 'aac', 'audio_video']),
  220. _BeginningToEndPlayPage(
  221. url=_URL_BASE + 'video.html?src=crowd1080_vp9.webm',
  222. page_set=page_set,
  223. tags=['is_50fps', 'vp9', 'video_only']),
  224. # Audio only test cases. MP3 and OGG are important to test since they are
  225. # unstructured containers and thus are prone to efficiency regressions.
  226. _BeginningToEndPlayPage(
  227. url=_URL_BASE + 'video.html?src=tulip2.ogg&type=audio',
  228. page_set=page_set,
  229. tags=['vorbis', 'audio_only']),
  230. _BeginningToEndPlayPage(
  231. url=_URL_BASE + 'video.html?src=tulip2.mp3&type=audio',
  232. page_set=page_set,
  233. tags=['mp3', 'audio_only']),
  234. _BeginningToEndPlayPage(
  235. url=_URL_BASE + 'video.html?src=tulip2.m4a&type=audio',
  236. page_set=page_set,
  237. tags=['aac', 'audio_only']),
  238. # Baseline + busyjs test.
  239. _BeginningToEndPlayPage(
  240. url=_URL_BASE + 'video.html?src=tulip2.mp4',
  241. page_set=page_set,
  242. tags=['h264', 'aac', 'audio_video']),
  243. _BeginningToEndPlayPage(
  244. url=_URL_BASE + 'video.html?src=tulip2.mp4&busyjs',
  245. page_set=page_set,
  246. tags=['h264', 'aac', 'audio_video', 'busyjs']),
  247. # Baseline + WiFi test.
  248. _BeginningToEndPlayPage(
  249. url=_URL_BASE + 'video.html?src=tulip2.vp9.webm',
  250. page_set=page_set,
  251. tags=['vp9', 'opus', 'audio_video']),
  252. _BeginningToEndPlayPage(
  253. url=_URL_BASE + 'video.html?src=tulip2.vp9.webm',
  254. page_set=page_set,
  255. tags=['vp9', 'opus', 'audio_video'],
  256. traffic_setting=traffic_setting_module.WIFI),
  257. # Seek tests in MP3 and OGG are important since they don't have seek
  258. # indices and thus show off efficiency regressions easily.
  259. _SeekPage(
  260. url=_URL_BASE + 'video.html?src=tulip2.ogg&type=audio&seek',
  261. page_set=page_set,
  262. tags=['vorbis', 'audio_only']),
  263. _SeekPage(
  264. url=_URL_BASE + 'video.html?src=tulip2.mp3&type=audio&seek',
  265. page_set=page_set,
  266. tags=['mp3', 'audio_only']),
  267. # High resolution seek test cases which will exaggerate any decoding
  268. # efficiency or buffering regressions.
  269. _SeekPage(
  270. url=_URL_BASE + 'video.html?src=garden2_10s.webm&seek',
  271. page_set=page_set,
  272. tags=['is_4k', 'vp8', 'vorbis', 'audio_video']),
  273. _SeekPage(
  274. url=_URL_BASE + 'video.html?src=garden2_10s.mp4&seek',
  275. page_set=page_set,
  276. tags=['is_4k', 'h264', 'aac', 'audio_video']),
  277. _SeekPage(
  278. url=(_URL_BASE + 'video.html?src='
  279. 'smpte_3840x2160_60fps_vp9.webm&seek'),
  280. page_set=page_set,
  281. tags=['is_4k', 'vp9', 'video_only'],
  282. action_timeout_in_seconds=120),
  283. # Basic test that ensures background playback works properly.
  284. _BackgroundPlaybackPage(
  285. url=_URL_BASE + 'video.html?src=tulip2.vp9.webm&background',
  286. page_set=page_set,
  287. tags=['vp9', 'opus', 'audio_video']),
  288. # Basic MSE test pages for common configurations. Note: By default the
  289. # test will only append the first 128k of the specified files, so when
  290. # adding tests ensure that is enough to trigger a timeupdate event. If not
  291. # you'll need to specify an additional appendSize parameter.
  292. _MSEPage(
  293. url=_URL_BASE + 'mse.html?media=aac_audio.mp4,h264_video.mp4',
  294. page_set=page_set,
  295. tags=['h264', 'aac', 'audio_video']),
  296. _MSEPage(
  297. url=_URL_BASE + 'mse.html?media=tulip2.vp9.webm',
  298. page_set=page_set,
  299. tags=['vp9', 'opus', 'audio_video']),
  300. _MSEPage(
  301. url=_URL_BASE + 'mse.html?media=aac_audio.mp4',
  302. page_set=page_set,
  303. tags=['aac', 'audio_only']),
  304. _MSEPage(
  305. url=_URL_BASE + 'mse.html?media=h264_video.mp4',
  306. page_set=page_set,
  307. tags=['h264', 'video_only']),
  308. ]
  309. class _MediaCasesStorySet(story.StorySet):
  310. """Abstract Media Cases Story Set to be overriden."""
  311. def __init__(self, measure_memory=False):
  312. super(_MediaCasesStorySet, self).__init__(
  313. cloud_storage_bucket=story.PARTNER_BUCKET)
  314. self.measure_memory = measure_memory
  315. for page in self._BuildPages():
  316. self.AddStory(page)
  317. @abc.abstractmethod
  318. def _BuildPages(self):
  319. """Subclasses should implement this to return an iterator of pages."""
  320. class MediaCasesDesktopStorySet(_MediaCasesStorySet):
  321. """
  322. Description: Video Stack Perf pages that report time_to_play, seek time and
  323. many other media-specific and generic metrics.
  324. """
  325. def _BuildPages(self):
  326. return iter(
  327. _GetCrossPlatformMediaPages(self) + _GetDesktopOnlyMediaPages(self))
  328. class MediaCasesMobileStorySet(_MediaCasesStorySet):
  329. """
  330. Description: Video Stack Perf pages that report time_to_play, seek time and
  331. many other media-specific and generic metrics.
  332. The mobile story set removes stories that are too difficult for mobile
  333. devices.
  334. """
  335. def _BuildPages(self):
  336. for page in _GetCrossPlatformMediaPages(self):
  337. if 'is_4k' in page.tags or 'is_50fps' in page.tags:
  338. continue
  339. yield page