• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Lint as: python2, python3
2# Copyright 2018 The Chromium OS 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
6import logging
7import time
8
9from autotest_lib.client.bin import test
10from autotest_lib.client.bin import utils
11from autotest_lib.client.common_lib import error
12from autotest_lib.client.common_lib.cros import chrome
13from autotest_lib.client.common_lib.cros import power_load_util
14from autotest_lib.client.cros.power import sys_power
15
16
17# Stop adding tab when swap_free / swap_total is less than this value.
18_LOW_SWAP_THRESHOLD = 0.5
19# Terminate the test if active_tabs / created_tabs is less than this value.
20_TOO_FEW_ACTIVE_TABS_THRESHOLD = 0.33
21
22
23class power_LowMemorySuspend(test.test):
24    """Low memory suspending stress test."""
25    version = 1
26
27    def low_swap_free(self):
28        """Returns true if free swap is low."""
29        meminfo = utils.get_meminfo()
30        if meminfo.SwapFree < meminfo.SwapTotal * _LOW_SWAP_THRESHOLD:
31            logging.info("Swap is low, swap free: %d, swap total: %d",
32                         meminfo.SwapFree, meminfo.SwapTotal)
33            return True
34        return False
35
36    def create_tabs(self, cr):
37        """Creates tabs until swap free is low.
38
39        @return: list of created tabs
40        """
41        # Any non-trivial web page is suitable to consume memory.
42        URL = 'https://inbox.google.com/'
43        tabs = []
44
45        # There is some race condition to navigate the first tab, navigating
46        # the first tab may fail unless sleep 2 seconds before navigation.
47        # Skip the first tab.
48
49        while not self.low_swap_free():
50            logging.info('creating tab %d', len(tabs))
51            tab = cr.browser.tabs.New()
52            tabs.append(tab)
53            tab.Navigate(URL);
54            try:
55                tab.WaitForDocumentReadyStateToBeComplete(timeout=20)
56            except Exception as e:
57                logging.warning('Exception when waiting page ready: %s', e)
58
59        return tabs
60
61    def check_tab_discard(self, cr, tabs):
62        """Raises error if too many tabs are discarded."""
63        try:
64            active_tabs = len(cr.browser.tabs)
65        except Exception as e:
66            logging.info('error getting active tab count: %s', e)
67            return
68        created_tabs = len(tabs)
69        if (active_tabs < created_tabs * _TOO_FEW_ACTIVE_TABS_THRESHOLD):
70            msg = ('Too many discards, active tabs: %d, created tabs: %d' %
71                   (active_tabs, created_tabs))
72            raise error.TestFail(msg)
73
74    def cycling_suspend(self, cr, tabs, switches_per_suspend,
75                        total_suspend_duration, suspend_seconds,
76                        additional_sleep):
77        """Page cycling and suspending.
78
79        @return: total suspending count.
80        """
81        start_time = time.time()
82        suspend_count = 0
83        tab_index = 0
84        spurious_wakeup_count = 0
85        MAX_SPURIOUS_WAKEUP = 5
86
87        while time.time() - start_time < total_suspend_duration:
88            # Page cycling
89            for _ in range(switches_per_suspend):
90                try:
91                    tabs[tab_index].Activate()
92                    tabs[tab_index].WaitForFrameToBeDisplayed()
93                except Exception as e:
94                    logging.info('cannot activate tab: %s', e)
95                tab_index = (tab_index + 1) % len(tabs)
96
97            self.check_tab_discard(cr, tabs)
98
99            # Suspending for the specified seconds.
100            try:
101                sys_power.do_suspend(suspend_seconds)
102            except sys_power.SpuriousWakeupError:
103                spurious_wakeup_count += 1
104                if spurious_wakeup_count > MAX_SPURIOUS_WAKEUP:
105                    raise error.TestFail('Too many SpuriousWakeupError.')
106            suspend_count += 1
107
108            # Waiting for system stable, otherwise the subsequent tab
109            # operations may fail.
110            time.sleep(additional_sleep)
111
112            self.check_tab_discard(cr, tabs)
113
114        return suspend_count
115
116    def run_once(self, switches_per_suspend=15, total_suspend_duration=2400,
117                 suspend_seconds=10, additional_sleep=10):
118        """Runs the test once."""
119        username = power_load_util.get_username()
120        password = power_load_util.get_password()
121        with chrome.Chrome(gaia_login=True, username=username,
122                           password=password) as cr:
123            tabs = self.create_tabs(cr)
124            suspend_count = self.cycling_suspend(
125                cr, tabs, switches_per_suspend, total_suspend_duration,
126                suspend_seconds, additional_sleep)
127
128            tabs_after_suspending = len(cr.browser.tabs)
129            meminfo = utils.get_meminfo()
130            ending_swap_free = meminfo.SwapFree
131            swap_total = meminfo.SwapTotal
132
133        perf_results = {}
134        perf_results['number_of_tabs'] = len(tabs)
135        perf_results['number_of_suspending'] = suspend_count
136        perf_results['tabs_after_suspending'] = tabs_after_suspending
137        perf_results['ending_swap_free'] = ending_swap_free
138        perf_results['swap_total'] = swap_total
139        self.write_perf_keyval(perf_results)
140
141        self.output_perf_value(description='number_of_tabs',
142                               value=len(tabs))
143        self.output_perf_value(description='number_of_suspending',
144                               value=suspend_count)
145        self.output_perf_value(description='tabs_after_suspending',
146                               value=tabs_after_suspending)
147        self.output_perf_value(description='ending_swap_free',
148                               value=ending_swap_free, units='KB')
149        self.output_perf_value(description='swap_total',
150                               value=swap_total, units='KB')
151
152