blob: 7e777be7ed1ea64a5e9bfd2a330c891811b5e324 [file] [log] [blame]
# Copyright 2018 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import logging
import time
from autotest_lib.client.bin import test
from autotest_lib.client.bin import utils
from autotest_lib.client.common_lib import error
from autotest_lib.client.common_lib.cros import chrome
from autotest_lib.client.common_lib.cros import arc_util
from autotest_lib.client.cros.power import sys_power
# Stop adding tab when swap_free / swap_total is less than this value.
_LOW_SWAP_THRESHOLD = 0.5
# Terminate the test if active_tabs / created_tabs is less than this value.
_TOO_FEW_ACTIVE_TABS_THRESHOLD = 0.33
class power_LowMemorySuspend(test.test):
"""Low memory suspending stress test."""
version = 1
def low_swap_free(self):
"""Returns true if free swap is low."""
meminfo = utils.get_meminfo()
if meminfo.SwapFree < meminfo.SwapTotal * _LOW_SWAP_THRESHOLD:
logging.info("Swap is low, swap free: %d, swap total: %d",
meminfo.SwapFree, meminfo.SwapTotal)
return True
return False
def create_tabs(self, cr):
"""Creates tabs until swap free is low.
@return: list of created tabs
"""
# Any non-trivial web page is suitable to consume memory.
URL = 'https://inbox.google.com/'
tabs = []
# There is some race condition to navigate the first tab, navigating
# the first tab may fail unless sleep 2 seconds before navigation.
# Skip the first tab.
while not self.low_swap_free():
logging.info('creating tab %d', len(tabs))
tab = cr.browser.tabs.New()
tabs.append(tab)
tab.Navigate(URL);
try:
tab.WaitForDocumentReadyStateToBeComplete(timeout=20)
except Exception as e:
logging.warning('Exception when waiting page ready: %s', e)
return tabs
def check_tab_discard(self, cr, tabs):
"""Raises error if too many tabs are discarded."""
try:
active_tabs = len(cr.browser.tabs)
except Exception as e:
logging.info('error getting active tab count: %s', e)
return
created_tabs = len(tabs)
if (active_tabs < created_tabs * _TOO_FEW_ACTIVE_TABS_THRESHOLD):
msg = ('Too many discards, active tabs: %d, created tabs: %d' %
(active_tabs, created_tabs))
raise error.TestFail(msg)
def cycling_suspend(self, cr, tabs, switches_per_suspend,
total_suspend_duration, suspend_seconds,
additional_sleep):
"""Page cycling and suspending.
@return: total suspending count.
"""
start_time = time.time()
suspend_count = 0
tab_index = 0
spurious_wakeup_count = 0
MAX_SPURIOUS_WAKEUP = 5
while time.time() - start_time < total_suspend_duration:
# Page cycling
for _ in range(switches_per_suspend):
try:
tabs[tab_index].Activate()
tabs[tab_index].WaitForFrameToBeDisplayed()
except Exception as e:
logging.info('cannot activate tab: %s', e)
tab_index = (tab_index + 1) % len(tabs)
self.check_tab_discard(cr, tabs)
# Suspending for the specified seconds.
try:
sys_power.do_suspend(suspend_seconds)
except sys_power.SpuriousWakeupError:
spurious_wakeup_count += 1
if spurious_wakeup_count > MAX_SPURIOUS_WAKEUP:
raise error.TestFail('Too many SpuriousWakeupError.')
suspend_count += 1
# Waiting for system stable, otherwise the subsequent tab
# operations may fail.
time.sleep(additional_sleep)
self.check_tab_discard(cr, tabs)
return suspend_count
def run_once(self, switches_per_suspend=15, total_suspend_duration=2400,
suspend_seconds=10, additional_sleep=10):
"""Runs the test once."""
username, password = arc_util.get_test_account_info()
with chrome.Chrome(gaia_login=True, username=username,
password=password) as cr:
tabs = self.create_tabs(cr)
suspend_count = self.cycling_suspend(
cr, tabs, switches_per_suspend, total_suspend_duration,
suspend_seconds, additional_sleep)
tabs_after_suspending = len(cr.browser.tabs)
meminfo = utils.get_meminfo()
ending_swap_free = meminfo.SwapFree
swap_total = meminfo.SwapTotal
perf_results = {}
perf_results['number_of_tabs'] = len(tabs)
perf_results['number_of_suspending'] = suspend_count
perf_results['tabs_after_suspending'] = tabs_after_suspending
perf_results['ending_swap_free'] = ending_swap_free
perf_results['swap_total'] = swap_total
self.write_perf_keyval(perf_results)
self.output_perf_value(description='number_of_tabs',
value=len(tabs))
self.output_perf_value(description='number_of_suspending',
value=suspend_count)
self.output_perf_value(description='tabs_after_suspending',
value=tabs_after_suspending)
self.output_perf_value(description='ending_swap_free',
value=ending_swap_free, units='KB')
self.output_perf_value(description='swap_total',
value=swap_total, units='KB')