Chromium Code Reviews| Index: tools/perf/page_sets/mobile_first_story.py |
| diff --git a/tools/perf/page_sets/mobile_first_story.py b/tools/perf/page_sets/mobile_first_story.py |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..4734cf404ba7cac559e6e2f3a41560683222ff8f |
| --- /dev/null |
| +++ b/tools/perf/page_sets/mobile_first_story.py |
| @@ -0,0 +1,221 @@ |
| +# Copyright 2015 The Chromium Authors. All rights reserved. |
| +# Use of this source code is governed by a BSD-style license that can be |
| +# found in the LICENSE file. |
|
aiolos (Not reviewing)
2015/12/10 20:37:05
Nit: rename this file to mobile_first.py instead o
perezju
2015/12/11 09:41:38
Acknowledged.
|
| + |
| +import logging |
| + |
| +from telemetry.core import android_platform |
| +from telemetry.core import platform as platform_module |
| +from telemetry.internal.browser import browser_finder |
| +from telemetry.internal.platform import android_device |
|
aiolos (Not reviewing)
2015/12/10 20:37:05
You shouldn't use anything in telemetry/internal.
perezju
2015/12/11 09:41:38
I see. That makes sense, and I understand the rati
|
| +from telemetry.page import action_runner |
| +from telemetry import story as story_module |
| +from telemetry.web_perf import timeline_based_measurement |
| + |
| +from devil.android.sdk import intent as intent_module |
| +from devil.android.sdk import keyevent |
| +from devil.utils import geometry |
| +from devil.utils import timeout_retry |
| + |
| + |
| +class SharedMobileFirstState(story_module.SharedState): |
| + def __init__(self, test, finder_options, story_set): |
| + super(SharedMobileFirstState, self).__init__( |
| + test, finder_options, story_set) |
| + self._test = test |
| + self._story_set = story_set |
| + self._android_platform = self._GetAndroidPlatform(finder_options) |
| + self._gmail_app = self._CreateGmailApp() |
| + self._browser = self._CreateBrowser(finder_options) |
| + self._current_story = None |
| + self._current_results = None |
| + self._new_tab_ids = set() |
| + |
| + def _GetAndroidPlatform(self, finder_options): |
| + device = android_device.GetDevice(finder_options) |
| + assert device, 'Benchmark requires an android device.' |
| + platform = platform_module.GetPlatformForDevice(device, finder_options) |
| + assert isinstance(platform, android_platform.AndroidPlatform) |
| + return platform |
| + |
| + def _CreateGmailApp(self): |
| + return self.platform.LaunchAndroidApplication( |
| + intent_module.Intent( |
| + package='com.google.android.gm', |
| + activity='com.google.android.gm.ui.MailActivityGmail')) |
| + |
| + def _CreateBrowser(self, finder_options): |
| + return browser_finder.FindBrowser(finder_options).Create(finder_options) |
| + |
| + @property |
| + def is_timeline_based(self): |
| + return isinstance( |
| + self._test, timeline_based_measurement.TimelineBasedMeasurement) |
| + |
| + @property |
| + def platform(self): |
| + return self._android_platform |
| + |
| + @property |
| + def gmail_app(self): |
| + return self._gmail_app |
| + |
| + @property |
| + def browser(self): |
| + return self._browser |
| + |
| + @property |
| + def results(self): |
| + return self._current_results |
| + |
| + def WillRunStory(self, story): |
| + self._current_story = story |
| + if self.is_timeline_based: |
| + self._test.WillRunStory(self.platform) |
| + |
| + def CanRunStory(self, story): |
| + return True # All stories must be run. |
| + |
| + def RunStory(self, results): |
| + self._current_results = results |
| + self._current_story.Run(self) |
| + |
| + def GetBrowserTab(self, new_tab=False): |
| + if new_tab: |
| + tab = self.browser.tabs.New() |
| + else: |
| + tab = self.browser.foreground_tab |
| + self._new_tab_ids.add(tab.id) |
| + return tab |
| + |
| + def CloseOldTabs(self): |
| + logging.info('Closing old tabs:') |
| + for tab in self.browser.tabs: |
| + if tab.id in self._new_tab_ids: |
| + logging.info('- keeping [%s] %s', tab.id, tab.url) |
| + else: |
| + logging.info('- closing [%s] %s', tab.id, tab.url) |
| + tab.Close() |
| + self._new_tab_ids = set() |
| + |
| + def DidRunStory(self, results): |
| + if self.is_timeline_based: |
| + self._test.DidRunStory(self.platform) |
| + self._current_story = None |
| + self._current_results = None |
| + |
| + def TearDownState(self): |
| + self._browser.Close() |
| + self._gmail_app.Close() |
| + |
| + |
| +class _MobileFirstStory(story_module.Story): # pylint: disable=abstract-method |
| + DUMP_WAIT_TIME = 3 |
| + INTERACTION_LABEL = 'foreground' |
| + |
| + def __init__(self, name, memory_infra=False): |
| + super(_MobileFirstStory, self).__init__(SharedMobileFirstState, name=name) |
| + self._memory_infra = memory_infra |
| + |
| + def _TakeMemoryMeasurement(self, shared_state, tab): |
| + runner = action_runner.ActionRunner(tab) |
| + runner.tab.WaitForDocumentReadyStateToBeComplete() |
| + runner.Wait(1) # See crbug.com/540022#c17. |
| + with runner.CreateInteraction(self.INTERACTION_LABEL): |
| + runner.Wait(self.DUMP_WAIT_TIME) |
| + if shared_state.is_timeline_based and self._memory_infra: |
| + runner.ForceGarbageCollection() |
| + runner.tab.browser.platform.FlushEntireSystemCache() |
| + runner.Wait(self.DUMP_WAIT_TIME) |
| + if not runner.tab.browser.DumpMemory(): |
| + logging.error('Unable to get a memory dump for %s.', self.name) |
| + # TODO(perezju): Use platform to also measure memory for Android apps |
| + # with no access to memory-infra. |
| + |
| +class ChromeAppStory(_MobileFirstStory): |
| + def __init__(self, name, url, last_page=False): |
| + super(ChromeAppStory, self).__init__(name=name, memory_infra=True) |
| + self._url = url |
| + self._last_page = last_page |
| + |
| + def Run(self, shared_state): |
| + navigate_on_new_tab = self._url is not None |
| + tab = shared_state.GetBrowserTab(new_tab=navigate_on_new_tab) |
| + if navigate_on_new_tab: |
| + tab.Navigate(self._url) |
| + self._TakeMemoryMeasurement(shared_state, tab) |
| + if self._last_page: |
| + shared_state.CloseOldTabs() |
| + |
| + |
| +class GmailAppStory(_MobileFirstStory): |
| + def __init__(self, name): |
| + super(GmailAppStory, self).__init__(name=name) |
| + |
| + def Run(self, shared_state): |
| + # Go to the app switcher and tap on Gmail. |
| + shared_state.platform.android_action_runner.InputKeyEvent( |
| + keyevent.KEYCODE_APP_SWITCH) |
| + shared_state.platform.system_ui.WaitForUiNode( |
| + resource_id='activity_description', text='Gmail').Tap() |
| + |
| + # If there is a "Back" button, tap on it to go to converation list view. |
| + navigate_up = shared_state.gmail_app.ui.GetUiNode( |
| + content_desc='Navigate up') |
| + if navigate_up: |
| + logging.info('Tapping on "Navigate up" button.') |
| + navigate_up.Tap() |
| + |
| + # Tap on the last email on the conversation list view. |
| + logging.info('Tapping on last email in list view.') |
| + shared_state.gmail_app.ui.WaitForUiNode( |
| + resource_id='conversation_list_view')[-1].Tap() |
| + |
| + # Wait for the email body to show, and take a memory measurement. |
| + logging.info('Waiting for conversation_webview') |
| + webview_view = shared_state.gmail_app.ui.WaitForUiNode( |
| + resource_id='conversation_webview') |
| + webview_content = self._GetSingleWebview(shared_state.gmail_app) |
| + self._TakeMemoryMeasurement(shared_state, webview_content) |
| + |
| + # Tap on the first link found on the email body, causes Chrome to launch. |
| + link_bounds = geometry.Rectangle.FromDict( |
| + webview_content.EvaluateJavaScript( |
| + 'document.links[0].getBoundingClientRect()')) |
| + webview_view.Tap(link_bounds.center, dp_units=True) |
| + |
| + def _GetSingleWebview(self, app): |
| + def get_webviews(): |
| + return app.GetWebViews() |
| + |
| + webviews = timeout_retry.WaitFor(get_webviews, wait_period=1, max_tries=5) |
| + assert webviews, 'No webviews found.' |
| + |
| + webview_content = webviews.pop() |
| + logging.info('Will work with webview: %s', webview_content.id) |
| + if len(webviews): |
| + logging.warning('Ignoring (%d) other webviews found: %s.', |
| + len(webviews), ', '.join(w.id for w in webviews)) |
| + |
| + return webview_content |
| + |
| + |
| +class GooglerMobileFirstStorySet(story_module.StorySet): |
| + """Mobile First Googler story set.""" |
| + |
| + def __init__(self): |
| + super(GooglerMobileFirstStorySet, self).__init__( |
| + archive_data_file='data/googler_mobile_first.json', |
| + cloud_storage_bucket=story_module.PARTNER_BUCKET) |
| + self.AddStory(GmailAppStory('gmail_read_email')) |
| + self.AddStory(ChromeAppStory( |
| + name='chromium_code_review', |
| + url=None)) # Grabs url from email body. |
| + self.AddStory(ChromeAppStory( |
| + name='chromium_issue', |
| + url='http://crbug.com/567696')) |
| + self.AddStory(ChromeAppStory( |
| + name='chromium_code_search', |
| + url='https://code.google.com/p/chromium/codesearch' |
| + '#chromium/src/tools/perf/benchmarks/memory_infra.py', |
| + last_page=True)) |