| # Copyright 2015 The ChromiumOS Authors |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """A test to stress CPU, memory and disk. |
| |
| Description |
| ----------- |
| A test using `stressapptest <https://github.com/stressapptest/stressapptest>`_ |
| to stress CPU, memory, and disk. |
| |
| By default the system data partition (or the stateful partition for Chrome OS |
| devices) is used. However a long stress testing of disk may shorten eMMC or SSD |
| life, so you may want to set `disk_thread` argument to False if `seconds` is |
| pretty long. |
| |
| Setting memory ratio may be tricky. If your system does not have enough free |
| memory (for example if you have lots of tests running in parallel) then the test |
| will fail, so usually you'll want to set `free_memory_only` argument to True. |
| |
| However, if you start multiple tests at same time, other tests may allocate more |
| memory after the calculation of "free memory" is done, causing the test to fail. |
| To solve that, increase the argument `wait_secs` so the calculation of "free |
| memory" will be done when the memory usage is stabilized. |
| |
| Internal references |
| ^^^^^^^^^^^^^^^^^^^ |
| - go/memory-testing-with-stressapptest |
| |
| Test Procedure |
| -------------- |
| This is an automated test without user interaction. |
| |
| Start the test and it will run for the time specified in argument `seconds`, and |
| pass if no errors found; otherwise fail with error messages and logs, especially |
| if unexpected reboot or crash were found during execution. |
| |
| Dependency |
| ---------- |
| - Need external program `stressapptest |
| <https://github.com/stressapptest/stressapptest>`_. |
| |
| Examples |
| -------- |
| To stress CPU, memory (90% of free memory), and the disk using stateful |
| partition for 60 seconds. According to go/memory-testing-with-stressapptest, |
| running the tests with disk generates more unusual memory traffic: |
| |
| .. test_list:: |
| |
| generic_dram_examples:DRAMTests.StressAppTest |
| |
| To stress CPU and memory (90% of free memory) without disk: |
| |
| .. test_list:: |
| |
| generic_dram_examples:DRAMTests.StressAppTestOnlyCPUAndMemory |
| |
| To stress CPU, memory (90% of free memory), and the disk using stateful |
| partition for one day: |
| |
| .. test_list:: |
| |
| generic_dram_examples:DRAMTests.StressAppTestForOneDay |
| |
| To stress using only two threads, and only run on cpu core 2 and 3:: |
| |
| { |
| "pytest_name": "stressapptest", |
| "args": { |
| "num_threads": 2, |
| "taskset_args": ["-c", "2,3"] |
| } |
| } |
| |
| To specify the minimum cpu frequency to 600 MHz, and the maximum cpu frequency |
| to 3000 MHz when running stressapptest, and recover to original cpu frequency |
| after the test:: |
| |
| { |
| "pytest_name": "stressapptest", |
| "args": { |
| "scaling_min_freq": 600000, |
| "scaling_max_freq": 3000000 |
| } |
| } |
| """ |
| |
| import logging |
| import time |
| import unittest |
| |
| from cros.factory.device import device_utils |
| from cros.factory.goofy.plugins import plugin_controller |
| from cros.factory.test import state |
| from cros.factory.test import test_tags |
| from cros.factory.test.utils import stress_manager |
| from cros.factory.utils.arg_utils import Arg |
| |
| |
| class StressAppTest(unittest.TestCase): |
| """Run stressapptest to test the memory and disk is fine.""" |
| |
| related_components = ( |
| test_tags.TestCategory.BRIDGE_PCIE_EMMC, |
| test_tags.TestCategory.CPU, |
| test_tags.TestCategory.DRAM, |
| test_tags.TestCategory.STORAGE, |
| ) |
| ARGS = [ |
| Arg('seconds', int, 'Time to execute the stressapptest.', default=60), |
| Arg('memory_ratio', float, 'Radio of memory to be used by stressapptest.', |
| default=0.9), |
| Arg( |
| 'free_memory_only', bool, |
| 'Only use free memory for test. When set to True, only ' |
| 'memory_radio * free_memory are used for stressapptest.', |
| default=True), |
| Arg('wait_secs', int, |
| 'Time to wait in seconds before executing stressapptest.', default=0), |
| Arg('disk_thread', bool, |
| 'Stress disk using -f argument of stressapptest.', default=True), |
| Arg( |
| 'disk_thread_dir', str, |
| 'Directory of disk thread file will be placed ' |
| '(default to system stateful partition.)', default=None), |
| Arg('max_errors', int, 'Number of errors to exit early.', |
| default=stress_manager.DEFAULT_MAX_ERRORS), |
| Arg('num_threads', int, |
| 'Number of threads to be used. Default to number of cores.', |
| default=None), |
| Arg('taskset_args', list, |
| 'Argument to taskset to change CPU affinity for stressapptest.', |
| default=None), |
| Arg('scaling_min_freq', int, |
| 'Argument to set the value of scaling_min_freq.', default=None), |
| Arg('scaling_max_freq', int, |
| 'Argument to set the value of scaling_max_freq.', default=None), |
| Arg('scaling_governor', str, |
| 'Argument to set the value of scaling_governor.', default=None) |
| ] |
| |
| def setUp(self): |
| self.dut = device_utils.CreateDUTInterface() |
| self.goofy = state.GetInstance() |
| self._cpu_freq_manager = plugin_controller.GetPluginRPCProxy( |
| 'cpu_freq_manager') |
| |
| def runTest(self): |
| # Wait other parallel tests memory usage to settle to a stable value, so |
| # stressapptest will not claim too much memory. |
| # yapf: disable |
| if self.args.wait_secs: # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long |
| # yapf: enable |
| # yapf: disable |
| time.sleep(self.args.wait_secs) # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long |
| # yapf: enable |
| |
| cpufreq_to_value = { |
| # yapf: disable |
| 'scaling_min_freq': |
| self.args.scaling_min_freq, # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long |
| # yapf: enable |
| # yapf: disable |
| 'scaling_max_freq': |
| self.args.scaling_max_freq, # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long |
| # yapf: enable |
| # yapf: disable |
| 'scaling_governor': |
| self.args. # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long |
| scaling_governor # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long |
| # yapf: enable |
| } |
| self._cpu_freq_manager.SetFrequency(cpufreq_to_value) |
| |
| try: |
| with stress_manager.StressManager(self.dut).Run( |
| # yapf: disable |
| duration_secs=self.args.seconds, # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long |
| # yapf: enable |
| # yapf: disable |
| memory_ratio=self.args.memory_ratio, # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long |
| # yapf: enable |
| # yapf: disable |
| free_memory_only=self.args.free_memory_only, # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long |
| # yapf: enable |
| # yapf: disable |
| disk_thread=self.args.disk_thread, # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long |
| # yapf: enable |
| # yapf: disable |
| disk_thread_dir=self.args.disk_thread_dir, # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long |
| # yapf: enable |
| # yapf: disable |
| max_errors=self.args.max_errors, # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long |
| # yapf: enable |
| # yapf: disable |
| num_threads=self.args.num_threads, # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long |
| # yapf: enable |
| # yapf: disable |
| taskset_args=self.args.taskset_args, # type: ignore #TODO(b/338318729) Fixit! # pylint: disable=line-too-long |
| # yapf: enable |
| ): |
| pass |
| except stress_manager.StressManagerError as e: |
| logging.error('StressAppTest failed: %s', e) |
| raise |
| finally: |
| self.goofy.WaitForWebSocketUp() |
| self._cpu_freq_manager.RestoreFrequency() |