diff options
author | Zhizhou Yang <zhizhouy@google.com> | 2019-11-05 18:12:42 -0800 |
---|---|---|
committer | Zhizhou Yang <zhizhouy@google.com> | 2019-11-12 01:22:47 +0000 |
commit | 5e83ee9c31d48d49669dc4e4b4fffbd7f759be9b (patch) | |
tree | 51a7f6239119250768a7babf46311ae883ed5743 /crosperf | |
parent | 31e0e81c1bcdbf082c91eff9ad16828aadd08df3 (diff) | |
download | toolchain-utils-5e83ee9c31d48d49669dc4e4b4fffbd7f759be9b.tar.gz |
crosperf: migrate all device setup code to a separate utils file
This patch extracts all the device setup code which interacts with DUT
to a single utils file, and be put into a wrapper class. This will help
migrating all related code to telemetry_Crosperf for skylab runs.
BUG=chromium:1020655
TEST=Passed all unittests; tested with simple experiment on kevin.
Change-Id: I2edcd7bb2d8cd0255d3ae6d380a5983c24427d98
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/toolchain-utils/+/1895500
Tested-by: Zhizhou Yang <zhizhouy@google.com>
Reviewed-by: Zhizhou Yang <zhizhouy@google.com>
Reviewed-by: Denis Nikitin <denik@chromium.org>
Commit-Queue: Zhizhou Yang <zhizhouy@google.com>
Diffstat (limited to 'crosperf')
-rw-r--r-- | crosperf/schedv2.py | 157 | ||||
-rw-r--r-- | crosperf/suite_runner.py | 421 | ||||
-rwxr-xr-x | crosperf/suite_runner_unittest.py | 694 |
3 files changed, 137 insertions, 1135 deletions
diff --git a/crosperf/schedv2.py b/crosperf/schedv2.py index dea3cdd3..d15f18c0 100644 --- a/crosperf/schedv2.py +++ b/crosperf/schedv2.py @@ -9,7 +9,6 @@ from __future__ import division from __future__ import print_function import sys -import time import traceback from collections import defaultdict @@ -21,6 +20,7 @@ import test_flag from machine_image_manager import MachineImageManager from cros_utils import command_executer from cros_utils import logger +from cros_utils.device_setup_utils import DutWrapper class DutWorker(Thread): @@ -49,153 +49,6 @@ class DutWorker(Thread): # suite_runner.Terminate and updates timeline. self._active_br.Terminate() - def _kerncmd_update_needed(self, intel_pstate): - """Check whether kernel cmdline update is needed. - - Args: - intel_pstate: kernel command line argument (active, passive, no_hwp) - - Returns: - True if update is needed. - """ - - ce = command_executer.GetCommandExecuter() - good = 0 - - # Check that dut platform supports hwp - cmd = "grep -q '^flags.*hwp' /proc/cpuinfo" - ret_code = ce.CrosRunCommand( - cmd, - chromeos_root=self._sched.get_labels(0).chromeos_root, - machine=self._dut.name) - if ret_code != good: - # Intel hwp is not supported, update is not needed. - return False - - kern_cmdline_cmd = 'grep -q "intel_pstate=%s" /proc/cmdline' % intel_pstate - ret_code = ce.CrosRunCommand( - kern_cmdline_cmd, - chromeos_root=self._sched.get_labels(0).chromeos_root, - machine=self._dut.name) - self._logger.LogOutput('grep /proc/cmdline returned %d' % ret_code) - if (intel_pstate and ret_code == good or - not intel_pstate and ret_code != good): - # No need to updated cmdline if: - # 1. We are setting intel_pstate and we found it is already set. - # 2. Not using intel_pstate and it is not in cmdline. - return False - - # Otherwise we need to update intel_pstate. - return True - - def _update_kerncmd_intel_pstate(self, intel_pstate): - """Update kernel command line. - - Args: - intel_pstate: kernel command line argument (active, passive, no_hwp) - """ - - ce = command_executer.GetCommandExecuter() - good = 0 - - # First phase is to remove rootfs verification to allow cmdline change. - remove_verif_cmd = ' '.join([ - '/usr/share/vboot/bin/make_dev_ssd.sh', - '--remove_rootfs_verification', - '--partition %d', - ]) - # Command for partition 2. - verif_part2_failed = ce.CrosRunCommand( - remove_verif_cmd % 2, - chromeos_root=self._sched.get_labels(0).chromeos_root, - machine=self._dut.name) - # Command for partition 4 - # Some machines in the lab use partition 4 to boot from, - # so cmdline should be update for both partitions. - verif_part4_failed = ce.CrosRunCommand( - remove_verif_cmd % 4, - chromeos_root=self._sched.get_labels(0).chromeos_root, - machine=self._dut.name) - if verif_part2_failed or verif_part4_failed: - self._logger.LogFatal( - 'ERROR. Failed to update kernel cmdline on partition %d.\n' - 'Remove verification failed with status %d' % - (2 if verif_part2_failed else 4, verif_part2_failed or - verif_part4_failed)) - - ce.CrosRunCommand( - 'reboot && exit', - chromeos_root=self._sched.get_labels(0).chromeos_root, - machine=self._dut.name) - # Give enough time for dut to complete reboot - # TODO(denik): Replace with the function checking machine availability. - time.sleep(30) - - # Second phase to update intel_pstate in kernel cmdline. - kern_cmdline = '\n'.join([ - 'tmpfile=$(mktemp)', - 'partnumb=%d', - 'pstate=%s', - # Store kernel cmdline in a temp file. - '/usr/share/vboot/bin/make_dev_ssd.sh --partition ${partnumb}' - ' --save_config ${tmpfile}', - # Remove intel_pstate argument if present. - "sed -i -r 's/ intel_pstate=[A-Za-z_]+//g' ${tmpfile}.${partnumb}", - # Insert intel_pstate with a new value if it is set. - '[[ -n ${pstate} ]] &&' - ' sed -i -e \"s/ *$/ intel_pstate=${pstate}/\" ${tmpfile}.${partnumb}', - # Save the change in kernel cmdline. - # After completion we have to reboot. - '/usr/share/vboot/bin/make_dev_ssd.sh --partition ${partnumb}' - ' --set_config ${tmpfile}' - ]) - kern_part2_cmdline_cmd = kern_cmdline % (2, intel_pstate) - self._logger.LogOutput( - 'Command to change kernel command line: %s' % kern_part2_cmdline_cmd) - upd_part2_failed = ce.CrosRunCommand( - kern_part2_cmdline_cmd, - chromeos_root=self._sched.get_labels(0).chromeos_root, - machine=self._dut.name) - # Again here we are updating cmdline for partition 4 - # in addition to partition 2. Without this some machines - # in the lab might fail. - kern_part4_cmdline_cmd = kern_cmdline % (4, intel_pstate) - self._logger.LogOutput( - 'Command to change kernel command line: %s' % kern_part4_cmdline_cmd) - upd_part4_failed = ce.CrosRunCommand( - kern_part4_cmdline_cmd, - chromeos_root=self._sched.get_labels(0).chromeos_root, - machine=self._dut.name) - if upd_part2_failed or upd_part4_failed: - self._logger.LogFatal( - 'ERROR. Failed to update kernel cmdline on partition %d.\n' - 'intel_pstate update failed with status %d' % - (2 if upd_part2_failed else 4, upd_part2_failed or upd_part4_failed)) - - ce.CrosRunCommand( - 'reboot && exit', - chromeos_root=self._sched.get_labels(0).chromeos_root, - machine=self._dut.name) - # Wait 30s after reboot. - time.sleep(30) - - # Verification phase. - # Check that cmdline was updated. - # Throw an exception if not. - kern_cmdline_cmd = 'grep -q "intel_pstate=%s" /proc/cmdline' % intel_pstate - ret_code = ce.CrosRunCommand( - kern_cmdline_cmd, - chromeos_root=self._sched.get_labels(0).chromeos_root, - machine=self._dut.name) - if (intel_pstate and ret_code != good or - not intel_pstate and ret_code == good): - # Kernel cmdline doesn't match input intel_pstate. - self._logger.LogFatal( - 'ERROR. Failed to update kernel cmdline. ' - 'Final verification failed with status %d' % ret_code) - - self._logger.LogOutput('Kernel cmdline updated successfully.') - def run(self): """Do the "run-test->(optionally reimage)->run-test" chore. @@ -238,8 +91,12 @@ class DutWorker(Thread): else: self._logger.LogOutput('Update kernel cmdline if necessary ' 'and reboot') - if self._kerncmd_update_needed(intel_pstate): - self._update_kerncmd_intel_pstate(intel_pstate) + run_on_dut = DutWrapper( + self._sched.get_labels(0).chromeos_root, + self._dut.name, + logger=self._logger) + if run_on_dut.KerncmdUpdateNeeded(intel_pstate): + run_on_dut.UpdateKerncmdIntelPstate(intel_pstate) # Execute the br. self._execute_benchmark_run(br) diff --git a/crosperf/suite_runner.py b/crosperf/suite_runner.py index fbacf17a..2311a728 100644 --- a/crosperf/suite_runner.py +++ b/crosperf/suite_runner.py @@ -9,11 +9,11 @@ from __future__ import division from __future__ import print_function import os -import re import shlex import time from cros_utils import command_executer +from cros_utils.device_setup_utils import DutWrapper TEST_THAT_PATH = '/usr/bin/test_that' # TODO: Need to check whether Skylab is installed and set up correctly. @@ -69,102 +69,29 @@ class SuiteRunner(object): self.enable_aslr = enable_aslr self.dut_config = dut_config - def DutWrapper(self, machine_name, chromeos_root): - """Wrap DUT parameters inside. - - Eventially CommandExecuter will reqiure only one - argument - command. - """ - - def RunCommandOnDut(command, ignore_status=False): - ret, msg, err_msg = self._ce.CrosRunCommandWOutput( - command, machine=machine_name, chromeos_root=chromeos_root) - - if ret: - err_msg = ('Command execution on DUT %s failed.\n' - 'Failing command: %s\n' - 'returned %d\n' - 'Error message: %s' % (machine_name, command, ret, err_msg)) - if ignore_status: - self.logger.LogError(err_msg + - '\n(Failure is considered non-fatal. Continue.)') - else: - self.logger.LogFatal(err_msg) - - return ret, msg, err_msg - - return RunCommandOnDut - def Run(self, cros_machine, label, benchmark, test_args, profiler_args): machine_name = cros_machine.name if not label.skylab: # Initialize command executer on DUT. - run_on_dut = self.DutWrapper(machine_name, label.chromeos_root) + run_on_dut = DutWrapper( + label.chromeos_root, + machine_name, + logger=self.logger, + log_level=self.log_level, + ce=self._ce, + dut_config=self.dut_config) for i in range(0, benchmark.retries + 1): if label.skylab: - # TODO: need to migrate DisableASLR and PinGovernorExecutionFrequencies - # since in skylab mode, we may not know the DUT until one is assigned + # TODO: need to migrate Device setups to autotest for skylab. + # Since in skylab mode, we may not know the DUT until one is assigned # to the test. For telemetry_Crosperf run, we can move them into the # server test script, for client runs, need to figure out wrapper to do # it before running. ret_tup = self.Skylab_Run(label, benchmark, test_args, profiler_args) else: - # Stop UI before configuring the DUT. - # This will accelerate setup (waiting for cooldown has x10 drop) - # and help to reset a Chrome state left after the previous test. - self.StopUI(run_on_dut) - - # Unless the user turns on ASLR in the flag, we first disable ASLR - # before running the benchmarks - if not self.enable_aslr: - self.DisableASLR(run_on_dut) - - # CPU usage setup comes first where we enable/disable cores. - self.SetupCpuUsage(run_on_dut) - cpu_online_status = self.GetCpuOnline(run_on_dut) - # List of online cores of type int (core number). - online_cores = [ - core for core, status in cpu_online_status.items() if status - ] - if self.dut_config['cooldown_time']: - # Setup power conservative mode for effective cool down. - # Set ignore status since powersave may no be available - # on all platforms and we are going to handle it. - ret = self.SetCpuGovernor('powersave', run_on_dut, ignore_status=True) - if ret: - # "powersave" is not available, use "ondemand". - # Still not a fatal error if it fails. - ret = self.SetCpuGovernor( - 'ondemand', run_on_dut, ignore_status=True) - # TODO(denik): Run comparison test for 'powersave' and 'ondemand' - # on scarlet and kevin64. - # We might have to consider reducing freq manually to the min - # if it helps to reduce waiting time. - wait_time = self.WaitCooldown(run_on_dut) - cros_machine.AddCooldownWaitTime(wait_time) - - # Setup CPU governor for the benchmark run. - # It overwrites the previous governor settings. - governor = self.dut_config['governor'] - # FIXME(denik): Pass online cores to governor setup. - self.SetCpuGovernor(governor, run_on_dut, ignore_status=False) - - # Disable Turbo and Setup CPU freq should ALWAYS proceed governor setup - # since governor may change: - # - frequency; - # - turbo/boost. - self.DisableTurbo(run_on_dut) - self.SetupCpuFreq(run_on_dut, online_cores) - # FIXME(denik): Currently we are not recovering the previous cpufreq - # settings since we do reboot/setup every time anyway. - # But it may change in the future and then we have to recover the - # settings. - - # DUT setup is done. Start a fresh new shiny UI. - self.StartUI(run_on_dut) - + self.SetupDevice(run_on_dut, cros_machine) if benchmark.suite == 'telemetry_Crosperf': - self.DecreaseWaitTime(run_on_dut) + run_on_dut.DecreaseWaitTime() ret_tup = self.Telemetry_Crosperf_Run(machine_name, label, benchmark, test_args, profiler_args) else: @@ -184,277 +111,59 @@ class SuiteRunner(object): break return ret_tup - def DisableASLR(self, run_on_dut): - disable_aslr = ('set -e && ' - 'if [[ -e /proc/sys/kernel/randomize_va_space ]]; then ' - ' echo 0 > /proc/sys/kernel/randomize_va_space; ' - 'fi') - if self.log_level == 'average': - self.logger.LogOutput('Disable ASLR.') - run_on_dut(disable_aslr) - - def SetCpuGovernor(self, governor, run_on_dut, ignore_status=False): - set_gov_cmd = ( - 'for f in `ls -d /sys/devices/system/cpu/cpu*/cpufreq 2>/dev/null`; do ' - # Skip writing scaling_governor if cpu is offline. - ' [[ -e ${f/cpufreq/online} ]] && grep -q 0 ${f/cpufreq/online} ' - ' && continue; ' - ' cd $f; ' - ' if [[ -e scaling_governor ]]; then ' - ' echo %s > scaling_governor; fi; ' - 'done; ') - if self.log_level == 'average': - self.logger.LogOutput('Setup CPU Governor: %s.' % governor) - ret, _, _ = run_on_dut(set_gov_cmd % governor, ignore_status=ignore_status) - return ret - - def DisableTurbo(self, run_on_dut): - dis_turbo_cmd = ( - 'if [[ -e /sys/devices/system/cpu/intel_pstate/no_turbo ]]; then ' - ' if grep -q 0 /sys/devices/system/cpu/intel_pstate/no_turbo; then ' - ' echo -n 1 > /sys/devices/system/cpu/intel_pstate/no_turbo; ' - ' fi; ' - 'fi; ') - if self.log_level == 'average': - self.logger.LogOutput('Disable Turbo.') - run_on_dut(dis_turbo_cmd) - - def WaitCooldown(self, run_on_dut): - waittime = 0 - timeout_in_sec = int(self.dut_config['cooldown_time']) * 60 - # Temperature from sensors come in uCelsius units. - temp_in_ucels = int(self.dut_config['cooldown_temp']) * 1000 - sleep_interval = 30 - - # Wait until any of two events occurs: - # 1. CPU cools down to a specified temperature. - # 2. Timeout cooldown_time expires. - # For the case when targeted temperature is not reached within specified - # timeout the benchmark is going to start with higher initial CPU temp. - # In the worst case it may affect test results but at the same time we - # guarantee the upper bound of waiting time. - # TODO(denik): Report (or highlight) "high" CPU temperature in test results. - # "high" should be calculated based on empirical data per platform. - # Based on such reports we can adjust CPU configuration or - # cooldown limits accordingly. - while waittime < timeout_in_sec: - _, temp_output, _ = run_on_dut( - 'cat /sys/class/thermal/thermal_zone*/temp', ignore_status=True) - if any(int(temp) > temp_in_ucels for temp in temp_output.split()): - time.sleep(sleep_interval) - waittime += sleep_interval - else: - # Exit the loop when: - # 1. Reported temp numbers from all thermal sensors do not exceed - # 'cooldown_temp' or - # 2. No data from the sensors. - break - - self.logger.LogOutput('Cooldown wait time: %.1f min' % (waittime / 60)) - return waittime - - def SetupCpuUsage(self, run_on_dut): - """Setup CPU usage. - - Based on self.dut_config['cpu_usage'] configure CPU cores - utilization. - """ - - if (self.dut_config['cpu_usage'] == 'big_only' or - self.dut_config['cpu_usage'] == 'little_only'): - _, arch, _ = run_on_dut('uname -m') - - if arch.lower().startswith('arm') or arch.lower().startswith('aarch64'): - self.SetupArmCores(run_on_dut) - - def SetupArmCores(self, run_on_dut): - """Setup ARM big/little cores.""" - - # CPU implemeters/part numbers of big/LITTLE CPU. - # Format: dict(CPU implementer: set(CPU part numbers)) - LITTLE_CORES = { - '0x41': { - '0xd01', # Cortex A32 - '0xd03', # Cortex A53 - '0xd04', # Cortex A35 - '0xd05', # Cortex A55 - }, - } - BIG_CORES = { - '0x41': { - '0xd07', # Cortex A57 - '0xd08', # Cortex A72 - '0xd09', # Cortex A73 - '0xd0a', # Cortex A75 - '0xd0b', # Cortex A76 - }, - } - - # Values of CPU Implementer and CPU part number are exposed by cpuinfo. - # Format: - # ================= - # processor : 0 - # model name : ARMv8 Processor rev 4 (v8l) - # BogoMIPS : 48.00 - # Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 - # CPU implementer : 0x41 - # CPU architecture: 8 - # CPU variant : 0x0 - # CPU part : 0xd03 - # CPU revision : 4 - - _, cpuinfo, _ = run_on_dut('cat /proc/cpuinfo') - - # List of all CPU cores: 0, 1, .. - proc_matches = re.findall(r'^processor\s*: (\d+)$', cpuinfo, re.MULTILINE) - # List of all corresponding CPU implementers - impl_matches = re.findall(r'^CPU implementer\s*: (0x[\da-f]+)$', cpuinfo, - re.MULTILINE) - # List of all corresponding CPU part numbers - part_matches = re.findall(r'^CPU part\s*: (0x[\da-f]+)$', cpuinfo, - re.MULTILINE) - assert len(proc_matches) == len(impl_matches) - assert len(part_matches) == len(impl_matches) - - all_cores = set(proc_matches) - dut_big_cores = { - core - for core, impl, part in zip(proc_matches, impl_matches, part_matches) - if impl in BIG_CORES and part in BIG_CORES[impl] - } - dut_lit_cores = { - core - for core, impl, part in zip(proc_matches, impl_matches, part_matches) - if impl in LITTLE_CORES and part in LITTLE_CORES[impl] - } - - if self.dut_config['cpu_usage'] == 'big_only': - cores_to_enable = dut_big_cores - cores_to_disable = all_cores - dut_big_cores - elif self.dut_config['cpu_usage'] == 'little_only': - cores_to_enable = dut_lit_cores - cores_to_disable = all_cores - dut_lit_cores - else: - self.logger.LogError( - 'cpu_usage=%s is not supported on ARM.\n' - 'Ignore ARM CPU setup and continue.' % self.dut_config['cpu_usage']) - return - - if cores_to_enable: - cmd_enable_cores = ('echo 1 | tee /sys/devices/system/cpu/cpu{%s}/online' - % ','.join(sorted(cores_to_enable))) - - cmd_disable_cores = '' - if cores_to_disable: - cmd_disable_cores = ( - 'echo 0 | tee /sys/devices/system/cpu/cpu{%s}/online' % ','.join( - sorted(cores_to_disable))) - - run_on_dut('; '.join([cmd_enable_cores, cmd_disable_cores])) - else: - # If there are no cores enabled by dut_config then configuration - # is invalid for current platform and should be ignored. - self.logger.LogError( - '"cpu_usage" is invalid for targeted platform.\n' - 'dut_config[cpu_usage]=%s\n' - 'dut big cores: %s\n' - 'dut little cores: %s\n' - 'Ignore ARM CPU setup and continue.' % (self.dut_config['cpu_usage'], - dut_big_cores, dut_lit_cores)) - - def GetCpuOnline(self, run_on_dut): - """Get online status of CPU cores. - - Return dict of {int(cpu_num): <0|1>}. - """ - get_cpu_online_cmd = ('paste -d" "' - ' <(ls /sys/devices/system/cpu/cpu*/online)' - ' <(cat /sys/devices/system/cpu/cpu*/online)') - _, online_output_str, _ = run_on_dut(get_cpu_online_cmd) - - # Here is the output we expect to see: - # ----------------- - # /sys/devices/system/cpu/cpu0/online 0 - # /sys/devices/system/cpu/cpu1/online 1 - - cpu_online = {} - cpu_online_match = re.compile(r'^[/\S]+/cpu(\d+)/[/\S]+\s+(\d+)$') - for line in online_output_str.splitlines(): - match = cpu_online_match.match(line) - if match: - cpu = int(match.group(1)) - status = int(match.group(2)) - cpu_online[cpu] = status - # At least one CPU has to be online. - assert cpu_online - - return cpu_online - - def SetupCpuFreq(self, run_on_dut, online_cores): - """Setup CPU frequency. - - Based on self.dut_config['cpu_freq_pct'] setup frequency of online CPU cores - to a supported value which is less or equal to (freq_pct * max_freq / 100) - limited by min_freq. - - NOTE: scaling_available_frequencies support is required. - Otherwise the function has no effect. - """ - freq_percent = self.dut_config['cpu_freq_pct'] - list_all_avail_freq_cmd = ('ls /sys/devices/system/cpu/cpu{%s}/cpufreq/' - 'scaling_available_frequencies') - # Ignore error to support general usage of frequency setup. - # Not all platforms support scaling_available_frequencies. - ret, all_avail_freq_str, _ = run_on_dut( - list_all_avail_freq_cmd % ','.join(str(core) for core in online_cores), - ignore_status=True) - if ret or not all_avail_freq_str: - # No scalable frequencies available for the core. - return ret - for avail_freq_path in all_avail_freq_str.split(): - # Get available freq from every scaling_available_frequency path. - # Error is considered fatal in run_on_dut(). - _, avail_freq_str, _ = run_on_dut('cat ' + avail_freq_path) - assert avail_freq_str - - all_avail_freq = sorted( - int(freq_str) for freq_str in avail_freq_str.split()) - min_freq = all_avail_freq[0] - max_freq = all_avail_freq[-1] - # Calculate the frequency we are targeting. - target_freq = round(max_freq * freq_percent / 100) - # More likely it's not in the list of supported frequencies - # and our goal is to find the one which is less or equal. - # Default is min and we will try to maximize it. - avail_ngt_target = min_freq - # Find the largest not greater than the target. - for next_largest in reversed(all_avail_freq): - if next_largest <= target_freq: - avail_ngt_target = next_largest - break - - max_freq_path = avail_freq_path.replace('scaling_available_frequencies', - 'scaling_max_freq') - min_freq_path = avail_freq_path.replace('scaling_available_frequencies', - 'scaling_min_freq') - # With default ignore_status=False we expect 0 status or Fatal error. - run_on_dut('echo %s | tee %s %s' % (avail_ngt_target, max_freq_path, - min_freq_path)) - - def DecreaseWaitTime(self, run_on_dut): - """Change the ten seconds wait time for pagecycler to two seconds.""" - FILE = '/usr/local/telemetry/src/tools/perf/page_sets/page_cycler_story.py' - ret = run_on_dut('ls ' + FILE) - - if not ret: - sed_command = 'sed -i "s/_TTI_WAIT_TIME = 10/_TTI_WAIT_TIME = 2/g" ' - run_on_dut(sed_command + FILE) - - def StopUI(self, run_on_dut): - run_on_dut('stop ui') - - def StartUI(self, run_on_dut): - run_on_dut('start ui') + def SetupDevice(self, run_on_dut, cros_machine): + # Stop UI before configuring the DUT. + # This will accelerate setup (waiting for cooldown has x10 drop) + # and help to reset a Chrome state left after the previous test. + run_on_dut.StopUI() + + # Unless the user turns on ASLR in the flag, we first disable ASLR + # before running the benchmarks + if not self.enable_aslr: + run_on_dut.DisableASLR() + + # CPU usage setup comes first where we enable/disable cores. + run_on_dut.SetupCpuUsage() + cpu_online_status = run_on_dut.GetCpuOnline() + # List of online cores of type int (core number). + online_cores = [ + core for core, status in cpu_online_status.items() if status + ] + if self.dut_config['cooldown_time']: + # Setup power conservative mode for effective cool down. + # Set ignore status since powersave may no be available + # on all platforms and we are going to handle it. + ret = run_on_dut.SetCpuGovernor('powersave', ignore_status=True) + if ret: + # "powersave" is not available, use "ondemand". + # Still not a fatal error if it fails. + ret = run_on_dut.SetCpuGovernor('ondemand', ignore_status=True) + # TODO(denik): Run comparison test for 'powersave' and 'ondemand' + # on scarlet and kevin64. + # We might have to consider reducing freq manually to the min + # if it helps to reduce waiting time. + wait_time = run_on_dut.WaitCooldown() + cros_machine.AddCooldownWaitTime(wait_time) + + # Setup CPU governor for the benchmark run. + # It overwrites the previous governor settings. + governor = self.dut_config['governor'] + # FIXME(denik): Pass online cores to governor setup. + run_on_dut.SetCpuGovernor(governor, ignore_status=False) + + # Disable Turbo and Setup CPU freq should ALWAYS proceed governor setup + # since governor may change: + # - frequency; + # - turbo/boost. + run_on_dut.DisableTurbo() + run_on_dut.SetupCpuFreq(online_cores) + # FIXME(denik): Currently we are not recovering the previous cpufreq + # settings since we do reboot/setup every time anyway. + # But it may change in the future and then we have to recover the + # settings. + + # DUT setup is done. Start a fresh new shiny UI. + run_on_dut.StartUI() def Test_That_Run(self, machine, label, benchmark, test_args, profiler_args): """Run the test_that test..""" diff --git a/crosperf/suite_runner_unittest.py b/crosperf/suite_runner_unittest.py index bf8bc317..edde46a7 100755 --- a/crosperf/suite_runner_unittest.py +++ b/crosperf/suite_runner_unittest.py @@ -22,82 +22,9 @@ from benchmark import Benchmark from cros_utils import command_executer from cros_utils import logger +from cros_utils.device_setup_utils import DutWrapper from machine_manager import MockCrosMachine -BIG_LITTLE_CPUINFO = """processor : 0 -model name : ARMv8 Processor rev 4 (v8l) -BogoMIPS : 48.00 -Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 -CPU implementer : 0x41 -CPU architecture: 8 -CPU variant : 0x0 -CPU part : 0xd03 -CPU revision : 4 - -processor : 1 -model name : ARMv8 Processor rev 4 (v8l) -BogoMIPS : 48.00 -Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 -CPU implementer : 0x41 -CPU architecture: 8 -CPU variant : 0x0 -CPU part : 0xd03 -CPU revision : 4 - -processor : 2 -model name : ARMv8 Processor rev 2 (v8l) -BogoMIPS : 48.00 -Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 -CPU implementer : 0x41 -CPU architecture: 8 -CPU variant : 0x0 -CPU part : 0xd08 -CPU revision : 2 -""" -LITTLE_ONLY_CPUINFO = """processor : 0 -model name : ARMv8 Processor rev 4 (v8l) -BogoMIPS : 48.00 -Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 -CPU implementer : 0x41 -CPU architecture: 8 -CPU variant : 0x0 -CPU part : 0xd03 -CPU revision : 4 - -processor : 1 -model name : ARMv8 Processor rev 4 (v8l) -BogoMIPS : 48.00 -Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 -CPU implementer : 0x41 -CPU architecture: 8 -CPU variant : 0x0 -CPU part : 0xd03 -CPU revision : 4 -""" - -NOT_BIG_LITTLE_CPUINFO = """processor : 0 -model name : ARMv7 Processor rev 1 (v7l) -Features : swp half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpv4 -CPU implementer : 0x41 -CPU architecture: 7 -CPU variant : 0x0 -CPU part : 0xc0d -CPU revision : 1 - -processor : 1 -model name : ARMv7 Processor rev 1 (v7l) -Features : swp half thumb fastmult vfp edsp thumbee neon vfpv3 tls vfpv4 -CPU implementer : 0x41 -CPU architecture: 7 -CPU variant : 0x0 -CPU part : 0xc0d -CPU revision : 1 - -Hardware : Rockchip (Device Tree) -Revision : 0000 -Serial : 0000000000000000 -""" - class SuiteRunnerTest(unittest.TestCase): """Class of SuiteRunner test.""" @@ -147,7 +74,6 @@ class SuiteRunnerTest(unittest.TestCase): self.telemetry_crosperf_args = [] self.call_skylab_run = False self.call_telemetry_crosperf_run = False - self.call_disable_aslr = False def setUp(self): self.runner = suite_runner.SuiteRunner( @@ -167,17 +93,11 @@ class SuiteRunnerTest(unittest.TestCase): self.call_test_that_run = False self.call_skylab_run = False self.call_telemetry_crosperf_run = False - self.call_disable_aslr = False self.skylab_run_args = [] self.test_that_args = [] self.telemetry_run_args = [] self.telemetry_crosperf_args = [] - def FakeDisableASLR(runner): - # pylint fix for unused variable. - del runner - self.call_disable_aslr = True - def FakeSkylabRun(test_label, benchmark, test_args, profiler_args): self.skylab_run_args = [test_label, benchmark, test_args, profiler_args] self.call_skylab_run = True @@ -204,17 +124,12 @@ class SuiteRunnerTest(unittest.TestCase): del command, ignore_status return 0, '', '' - self.runner.DisableASLR = FakeDisableASLR self.runner.Skylab_Run = FakeSkylabRun self.runner.Telemetry_Crosperf_Run = FakeTelemetryCrosperfRun self.runner.Test_That_Run = FakeTestThatRun - self.runner.SetupCpuUsage = mock.Mock() - self.runner.SetupCpuFreq = mock.Mock() - self.runner.DutWrapper = mock.Mock(return_value=FakeRunner) - self.runner.DisableTurbo = mock.Mock() - self.runner.SetCpuGovernor = mock.Mock() - self.runner.WaitCooldown = mock.Mock(return_value=0) - self.runner.GetCpuOnline = mock.Mock(return_value={0: 1, 1: 1, 2: 0}) + self.runner.SetupDevice = mock.Mock() + DutWrapper.RunCommandOnDut = mock.Mock(return_value=FakeRunner) + self.runner.dut_config['cooldown_time'] = 0 self.runner.dut_config['governor'] = 'fake_governor' self.runner.dut_config['cpu_freq_pct'] = 65 @@ -228,590 +143,111 @@ class SuiteRunnerTest(unittest.TestCase): self.mock_label.skylab = True self.runner.Run(cros_machine, self.mock_label, self.telemetry_bench, test_args, profiler_args) - self.assertFalse(self.call_disable_aslr) self.assertTrue(self.call_skylab_run) self.assertFalse(self.call_test_that_run) self.assertFalse(self.call_telemetry_crosperf_run) self.assertEqual(self.skylab_run_args, [self.mock_label, self.telemetry_bench, '', '']) - self.runner.SetupCpuUsage.assert_not_called() - self.runner.SetupCpuFreq.assert_not_called() - self.runner.GetCpuOnline.assert_not_called() - self.runner.DutWrapper.assert_not_called() - self.runner.SetCpuGovernor.assert_not_called() - self.runner.DisableTurbo.assert_not_called() - self.runner.WaitCooldown.assert_not_called() + self.runner.SetupDevice.assert_not_called() self.mock_label.skylab = False reset() self.runner.Run(cros_machine, self.mock_label, self.test_that_bench, test_args, profiler_args) - self.assertTrue(self.call_disable_aslr) self.assertTrue(self.call_test_that_run) self.assertFalse(self.call_telemetry_crosperf_run) self.assertEqual( self.test_that_args, ['fake_machine', self.mock_label, self.test_that_bench, '', '']) - self.runner.SetupCpuUsage.assert_called_once_with(FakeRunner) - self.runner.SetupCpuFreq.assert_called_once_with(FakeRunner, [0, 1]) - self.runner.GetCpuOnline.assert_called_once_with(FakeRunner) - self.runner.DutWrapper.assert_called_once_with( - machine, self.mock_label.chromeos_root) - self.runner.SetCpuGovernor.assert_called_once_with( - 'fake_governor', FakeRunner, ignore_status=False) - self.runner.DisableTurbo.assert_called_once_with(FakeRunner) - self.runner.WaitCooldown.assert_not_called() reset() self.runner.Run(cros_machine, self.mock_label, self.telemetry_crosperf_bench, test_args, profiler_args) - self.assertTrue(self.call_disable_aslr) self.assertFalse(self.call_test_that_run) self.assertTrue(self.call_telemetry_crosperf_run) self.assertEqual(self.telemetry_crosperf_args, [ 'fake_machine', self.mock_label, self.telemetry_crosperf_bench, '', '' ]) - self.runner.DutWrapper.assert_called_with(machine, - self.mock_label.chromeos_root) - def test_run_with_cooldown(self): + def test_setup_device(self): def FakeRunner(command, ignore_status=False): # pylint fix for unused variable. del command, ignore_status return 0, '', '' - self.runner.DisableASLR = mock.Mock() - self.runner.DutWrapper = mock.Mock(return_value=FakeRunner) - self.runner.DisableTurbo = mock.Mock() - self.runner.SetCpuGovernor = mock.Mock() - self.runner.SetupCpuUsage = mock.Mock() - self.runner.SetupCpuFreq = mock.Mock() - self.runner.WaitCooldown = mock.Mock(return_value=0) - self.runner.GetCpuOnline = mock.Mock(return_value={0: 0, 1: 1}) - self.runner.Telemetry_Crosperf_Run = mock.Mock(return_value=(0, '', '')) - self.runner.dut_config['cooldown_time'] = 10 + DutWrapper.RunCommandOnDut = mock.Mock(return_value=FakeRunner) + DutWrapper.DisableASLR = mock.Mock() + DutWrapper.SetupCpuUsage = mock.Mock() + DutWrapper.SetupCpuFreq = mock.Mock() + DutWrapper.DisableTurbo = mock.Mock() + DutWrapper.SetCpuGovernor = mock.Mock() + DutWrapper.WaitCooldown = mock.Mock(return_value=0) + DutWrapper.GetCpuOnline = mock.Mock(return_value={0: 1, 1: 1, 2: 0}) + self.runner.dut_config['cooldown_time'] = 0 self.runner.dut_config['governor'] = 'fake_governor' - self.runner.dut_config['cpu_freq_pct'] = 75 + self.runner.dut_config['cpu_freq_pct'] = 65 machine = 'fake_machine' cros_machine = MockCrosMachine(machine, self.mock_label.chromeos_root, self.mock_logger) - self.runner.Run(cros_machine, self.mock_label, - self.telemetry_crosperf_bench, '', '') - - self.runner.WaitCooldown.assert_called_once_with(FakeRunner) - self.runner.DisableASLR.assert_called_once() - self.runner.Telemetry_Crosperf_Run.assert_called_once() - self.runner.DisableTurbo.assert_called_once_with(FakeRunner) - self.runner.SetupCpuUsage.assert_called_once_with(FakeRunner) - self.runner.SetupCpuFreq.assert_called_once_with(FakeRunner, [1]) - self.runner.SetCpuGovernor.assert_called() - self.runner.GetCpuOnline.assert_called_once_with(FakeRunner) - self.assertGreater(self.runner.SetCpuGovernor.call_count, 1) - self.assertEqual( - self.runner.SetCpuGovernor.call_args, - mock.call('fake_governor', FakeRunner, ignore_status=False)) - - @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommandWOutput') - def test_dut_wrapper(self, mock_cros_runcmd): - self.mock_cmd_exec.CrosRunCommandWOutput = mock_cros_runcmd - mock_cros_runcmd.return_value = (0, '', '') - run_on_dut = self.runner.DutWrapper('lumpy.cros2', '/tmp/chromeos') - mock_cros_runcmd.assert_not_called() - run_on_dut('run command;') - mock_cros_runcmd.assert_called_once_with( - 'run command;', chromeos_root='/tmp/chromeos', machine='lumpy.cros2') - - @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommandWOutput') - def test_dut_wrapper_fatal_error(self, mock_cros_runcmd): - self.mock_cmd_exec.CrosRunCommandWOutput = mock_cros_runcmd - # Command returns error 1. - mock_cros_runcmd.return_value = (1, '', 'Error!') - run_on_dut = self.runner.DutWrapper('lumpy.cros2', '/tmp/chromeos') - mock_cros_runcmd.assert_not_called() - run_on_dut('run command;') - mock_cros_runcmd.assert_called_once_with( - 'run command;', chromeos_root='/tmp/chromeos', machine='lumpy.cros2') - # Error status causes log fatal. - self.assertEqual( - self.mock_logger.method_calls[-1], - mock.call.LogFatal('Command execution on DUT lumpy.cros2 failed.\n' - 'Failing command: run command;\nreturned 1\n' - 'Error message: Error!')) - - @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommandWOutput') - def test_dut_wrapper_ignore_error(self, mock_cros_runcmd): - self.mock_cmd_exec.CrosRunCommandWOutput = mock_cros_runcmd - # Command returns error 1. - mock_cros_runcmd.return_value = (1, '', 'Error!') - run_on_dut = self.runner.DutWrapper('lumpy.cros2', '/tmp/chromeos') - run_on_dut('run command;', ignore_status=True) - mock_cros_runcmd.assert_called_once_with( - 'run command;', chromeos_root='/tmp/chromeos', machine='lumpy.cros2') - # Error status is not fatal. LogError records the error message. - self.assertEqual( - self.mock_logger.method_calls[-1], - mock.call.LogError('Command execution on DUT lumpy.cros2 failed.\n' - 'Failing command: run command;\nreturned 1\n' - 'Error message: Error!\n' - '(Failure is considered non-fatal. Continue.)')) - - def test_disable_aslr(self): - run_on_dut = mock.Mock() - self.runner.DisableASLR(run_on_dut) - # pyformat: disable - set_cpu_cmd = ('set -e && ' - 'if [[ -e /proc/sys/kernel/randomize_va_space ]]; then ' - ' echo 0 > /proc/sys/kernel/randomize_va_space; ' - 'fi') - run_on_dut.assert_called_once_with(set_cpu_cmd) - - def test_set_cpu_governor(self): - dut_runner = mock.Mock(return_value=(0, '', '')) - self.runner.SetCpuGovernor('new_governor', dut_runner, ignore_status=False) - set_cpu_cmd = ( - 'for f in `ls -d /sys/devices/system/cpu/cpu*/cpufreq 2>/dev/null`; do ' - # Skip writing scaling_governor if cpu is not online. - ' [[ -e ${f/cpufreq/online} ]] && grep -q 0 ${f/cpufreq/online} ' - ' && continue; ' - ' cd $f; ' - ' if [[ -e scaling_governor ]]; then ' - ' echo %s > scaling_governor; fi; ' - 'done; ') - dut_runner.assert_called_once_with( - set_cpu_cmd % 'new_governor', ignore_status=False) - - def test_set_cpu_governor_propagate_error(self): - dut_runner = mock.Mock(return_value=(1, '', 'Error.')) - self.runner.SetCpuGovernor('non-exist_governor', dut_runner) - set_cpu_cmd = ( - 'for f in `ls -d /sys/devices/system/cpu/cpu*/cpufreq 2>/dev/null`; do ' - # Skip writing scaling_governor if cpu is not online. - ' [[ -e ${f/cpufreq/online} ]] && grep -q 0 ${f/cpufreq/online} ' - ' && continue; ' - ' cd $f; ' - ' if [[ -e scaling_governor ]]; then ' - ' echo %s > scaling_governor; fi; ' - 'done; ') - # By default error status is fatal. - dut_runner.assert_called_once_with( - set_cpu_cmd % 'non-exist_governor', ignore_status=False) - - def test_set_cpu_governor_ignore_status(self): - dut_runner = mock.Mock(return_value=(1, '', 'Error.')) - ret_code = self.runner.SetCpuGovernor( - 'non-exist_governor', dut_runner, ignore_status=True) - set_cpu_cmd = ( - 'for f in `ls -d /sys/devices/system/cpu/cpu*/cpufreq 2>/dev/null`; do ' - # Skip writing scaling_governor if cpu is not online. - ' [[ -e ${f/cpufreq/online} ]] && grep -q 0 ${f/cpufreq/online} ' - ' && continue; ' - ' cd $f; ' - ' if [[ -e scaling_governor ]]; then ' - ' echo %s > scaling_governor; fi; ' - 'done; ') - dut_runner.assert_called_once_with( - set_cpu_cmd % 'non-exist_governor', ignore_status=True) - self.assertEqual(ret_code, 1) - - def test_disable_turbo(self): - dut_runner = mock.Mock(return_value=(0, '', '')) - self.runner.DisableTurbo(dut_runner) - set_cpu_cmd = ( - # Disable Turbo in Intel pstate driver - 'if [[ -e /sys/devices/system/cpu/intel_pstate/no_turbo ]]; then ' - ' if grep -q 0 /sys/devices/system/cpu/intel_pstate/no_turbo; then ' - ' echo -n 1 > /sys/devices/system/cpu/intel_pstate/no_turbo; ' - ' fi; ' - 'fi; ') - dut_runner.assert_called_once_with(set_cpu_cmd) - - def test_get_cpu_online_two(self): - """Test one digit CPU #.""" - dut_runner = mock.Mock( - return_value=(0, '/sys/devices/system/cpu/cpu0/online 0\n' - '/sys/devices/system/cpu/cpu1/online 1\n', '')) - cpu_online = self.runner.GetCpuOnline(dut_runner) - self.assertEqual(cpu_online, {0: 0, 1: 1}) - - def test_get_cpu_online_twelve(self): - """Test two digit CPU #.""" - dut_runner = mock.Mock( - return_value=(0, '/sys/devices/system/cpu/cpu0/online 1\n' - '/sys/devices/system/cpu/cpu1/online 0\n' - '/sys/devices/system/cpu/cpu10/online 1\n' - '/sys/devices/system/cpu/cpu11/online 1\n' - '/sys/devices/system/cpu/cpu2/online 1\n' - '/sys/devices/system/cpu/cpu3/online 0\n' - '/sys/devices/system/cpu/cpu4/online 1\n' - '/sys/devices/system/cpu/cpu5/online 0\n' - '/sys/devices/system/cpu/cpu6/online 1\n' - '/sys/devices/system/cpu/cpu7/online 0\n' - '/sys/devices/system/cpu/cpu8/online 1\n' - '/sys/devices/system/cpu/cpu9/online 0\n', '')) - cpu_online = self.runner.GetCpuOnline(dut_runner) - self.assertEqual(cpu_online, { - 0: 1, - 1: 0, - 2: 1, - 3: 0, - 4: 1, - 5: 0, - 6: 1, - 7: 0, - 8: 1, - 9: 0, - 10: 1, - 11: 1 - }) - - def test_get_cpu_online_no_output(self): - """Test error case, no output.""" - dut_runner = mock.Mock(return_value=(0, '', '')) - with self.assertRaises(AssertionError): - self.runner.GetCpuOnline(dut_runner) - - def test_get_cpu_online_command_error(self): - """Test error case, command error.""" - dut_runner = mock.Mock(side_effect=AssertionError) - with self.assertRaises(AssertionError): - self.runner.GetCpuOnline(dut_runner) - - @mock.patch.object(suite_runner.SuiteRunner, 'SetupArmCores') - def test_setup_cpu_usage_little_on_arm(self, mock_setup_arm): - self.runner.SetupArmCores = mock_setup_arm - dut_runner = mock.Mock(return_value=(0, 'armv7l', '')) - self.runner.dut_config['cpu_usage'] = 'little_only' - self.runner.SetupCpuUsage(dut_runner) - self.runner.SetupArmCores.assert_called_once_with(dut_runner) - - @mock.patch.object(suite_runner.SuiteRunner, 'SetupArmCores') - def test_setup_cpu_usage_big_on_aarch64(self, mock_setup_arm): - self.runner.SetupArmCores = mock_setup_arm - dut_runner = mock.Mock(return_value=(0, 'aarch64', '')) - self.runner.dut_config['cpu_usage'] = 'big_only' - self.runner.SetupCpuUsage(dut_runner) - self.runner.SetupArmCores.assert_called_once_with(dut_runner) - - @mock.patch.object(suite_runner.SuiteRunner, 'SetupArmCores') - def test_setup_cpu_usage_big_on_intel(self, mock_setup_arm): - self.runner.SetupArmCores = mock_setup_arm - dut_runner = mock.Mock(return_value=(0, 'x86_64', '')) - self.runner.dut_config['cpu_usage'] = 'big_only' - self.runner.SetupCpuUsage(dut_runner) - # Check that SetupArmCores not called with invalid setup. - self.runner.SetupArmCores.assert_not_called() - - @mock.patch.object(suite_runner.SuiteRunner, 'SetupArmCores') - def test_setup_cpu_usage_all_on_intel(self, mock_setup_arm): - self.runner.SetupArmCores = mock_setup_arm - dut_runner = mock.Mock(return_value=(0, 'x86_64', '')) - self.runner.dut_config['cpu_usage'] = 'all' - self.runner.SetupCpuUsage(dut_runner) - # Check that SetupArmCores not called in general case. - self.runner.SetupArmCores.assert_not_called() - - def test_setup_arm_cores_big_on_big_little(self): - dut_runner = mock.Mock(side_effect=[ - (0, BIG_LITTLE_CPUINFO, ''), - (0, '', ''), - ]) - self.runner.dut_config['cpu_usage'] = 'big_only' - self.runner.SetupArmCores(dut_runner) - dut_runner.assert_called_with( - 'echo 1 | tee /sys/devices/system/cpu/cpu{2}/online; ' - 'echo 0 | tee /sys/devices/system/cpu/cpu{0,1}/online') - - def test_setup_arm_cores_little_on_big_little(self): - dut_runner = mock.Mock(side_effect=[ - (0, BIG_LITTLE_CPUINFO, ''), - (0, '', ''), - ]) - self.runner.dut_config['cpu_usage'] = 'little_only' - self.runner.SetupArmCores(dut_runner) - dut_runner.assert_called_with( - 'echo 1 | tee /sys/devices/system/cpu/cpu{0,1}/online; ' - 'echo 0 | tee /sys/devices/system/cpu/cpu{2}/online') - - def test_setup_arm_cores_invalid_config(self): - dut_runner = mock.Mock(side_effect=[ - (0, LITTLE_ONLY_CPUINFO, ''), - (0, '', ''), - ]) - self.runner.dut_config['cpu_usage'] = 'big_only' - self.runner.SetupArmCores(dut_runner) - # Check that setup command is not sent when trying - # to use 'big_only' on a platform with all little cores. - dut_runner.assert_called_once_with('cat /proc/cpuinfo') - - def test_setup_arm_cores_not_big_little(self): - dut_runner = mock.Mock(side_effect=[ - (0, NOT_BIG_LITTLE_CPUINFO, ''), - (0, '', ''), - ]) - self.runner.dut_config['cpu_usage'] = 'big_only' - self.runner.SetupArmCores(dut_runner) - # Check that setup command is not sent when trying - # to use 'big_only' on a platform w/o support of big/little. - dut_runner.assert_called_once_with('cat /proc/cpuinfo') - - def test_setup_arm_cores_unsupported_cpu_usage(self): - dut_runner = mock.Mock(side_effect=[ - (0, BIG_LITTLE_CPUINFO, ''), - (0, '', ''), - ]) - self.runner.dut_config['cpu_usage'] = 'exclusive_cores' - self.runner.SetupArmCores(dut_runner) - # Check that setup command is not sent when trying to use - # 'exclusive_cores' on ARM CPU setup. - dut_runner.assert_called_once_with('cat /proc/cpuinfo') - - def test_setup_cpu_freq_single_full(self): - online = [0] - dut_runner = mock.Mock(side_effect=[ - (0, - '/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies\n', - ''), - (0, '1 2 3 4 5 6 7 8 9 10', ''), - (0, '', ''), - ]) - self.runner.dut_config['cpu_freq_pct'] = 100 - self.runner.SetupCpuFreq(dut_runner, online) - self.assertGreaterEqual(dut_runner.call_count, 3) - self.assertEqual( - dut_runner.call_args, - mock.call('echo 10 | tee ' - '/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq ' - '/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq')) - - def test_setup_cpu_freq_middle(self): - online = [0] - dut_runner = mock.Mock(side_effect=[ - (0, - '/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies\n', - ''), - (0, '1 2 3 4 5 6 7 8 9 10', ''), - (0, '', ''), - ]) - self.runner.dut_config['cpu_freq_pct'] = 60 - self.runner.SetupCpuFreq(dut_runner, online) - self.assertGreaterEqual(dut_runner.call_count, 2) - self.assertEqual( - dut_runner.call_args, - mock.call('echo 6 | tee ' - '/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq ' - '/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq')) - - def test_setup_cpu_freq_lowest(self): - online = [0] - dut_runner = mock.Mock(side_effect=[ - (0, - '/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies\n', - ''), - (0, '1 2 3 4 5 6 7 8 9 10', ''), - (0, '', ''), - ]) - self.runner.dut_config['cpu_freq_pct'] = 0 - self.runner.SetupCpuFreq(dut_runner, online) - self.assertGreaterEqual(dut_runner.call_count, 2) - self.assertEqual( - dut_runner.call_args, - mock.call('echo 1 | tee ' - '/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq ' - '/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq')) - - def test_setup_cpu_freq_multiple_middle(self): - online = [0, 1] - dut_runner = mock.Mock(side_effect=[ - (0, - '/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies\n' - '/sys/devices/system/cpu/cpu1/cpufreq/scaling_available_frequencies\n', - ''), - (0, '1 2 3 4 5 6 7 8 9 10', ''), - (0, '', ''), - (0, '1 4 6 8 10 12 14 16 18 20', ''), - (0, '', ''), - ]) - self.runner.dut_config['cpu_freq_pct'] = 70 - self.runner.SetupCpuFreq(dut_runner, online) - self.assertEqual(dut_runner.call_count, 5) - self.assertEqual( - dut_runner.call_args_list[2], - mock.call('echo 7 | tee ' - '/sys/devices/system/cpu/cpu0/cpufreq/scaling_max_freq ' - '/sys/devices/system/cpu/cpu0/cpufreq/scaling_min_freq')) - self.assertEqual( - dut_runner.call_args_list[4], - mock.call('echo 14 | tee ' - '/sys/devices/system/cpu/cpu1/cpufreq/scaling_max_freq ' - '/sys/devices/system/cpu/cpu1/cpufreq/scaling_min_freq')) - - def test_setup_cpu_freq_no_scaling_available(self): - online = [0, 1] - dut_runner = mock.Mock(return_value=(2, '', 'No such file or directory')) - self.runner.dut_config['cpu_freq_pct'] = 50 - self.runner.SetupCpuFreq(dut_runner, online) - dut_runner.assert_called_once() - self.assertNotRegexpMatches(dut_runner.call_args_list[0][0][0], - '^echo.*scaling_max_freq$') - - def test_setup_cpu_freq_multiple_no_access(self): - online = [0, 1] - dut_runner = mock.Mock(side_effect=[ - (0, - '/sys/devices/system/cpu/cpu0/cpufreq/scaling_available_frequencies\n' - '/sys/devices/system/cpu/cpu1/cpufreq/scaling_available_frequencies\n', - ''), - (0, '1 4 6 8 10 12 14 16 18 20', ''), - AssertionError(), - ]) - self.runner.dut_config['cpu_freq_pct'] = 30 - # Error status causes log fatal. - with self.assertRaises(AssertionError): - self.runner.SetupCpuFreq(dut_runner, online) + mock_run_on_dut = DutWrapper( + self.mock_label.chromeos_root, + machine, + logger=self.mock_logger, + dut_config=self.runner.dut_config) - @mock.patch.object(time, 'sleep') - def test_wait_cooldown_nowait(self, mock_sleep): - mock_sleep.return_value = 0 - dut_runner = mock.Mock(return_value=(0, '39000', '')) - self.runner.dut_config['cooldown_time'] = 10 - self.runner.dut_config['cooldown_temp'] = 40 - wait_time = self.runner.WaitCooldown(dut_runner) - # Send command to DUT only once to check temperature - # and make sure it does not exceed the threshold. - dut_runner.assert_called_once() - mock_sleep.assert_not_called() - self.assertEqual(wait_time, 0) + self.runner.SetupDevice(mock_run_on_dut, cros_machine) - @mock.patch.object(time, 'sleep') - def test_wait_cooldown_needwait_once(self, mock_sleep): - """Wait one iteration for cooldown. - - Set large enough timeout and changing temperature - output. Make sure it exits when expected value - received. - Expect that WaitCooldown check temp twice. - """ - mock_sleep.return_value = 0 - dut_runner = mock.Mock(side_effect=[(0, '41000', ''), (0, '39999', '')]) - self.runner.dut_config['cooldown_time'] = 100 - self.runner.dut_config['cooldown_temp'] = 40 - wait_time = self.runner.WaitCooldown(dut_runner) - dut_runner.assert_called() - self.assertEqual(dut_runner.call_count, 2) - mock_sleep.assert_called() - self.assertGreater(wait_time, 0) - - @mock.patch.object(time, 'sleep') - def test_wait_cooldown_needwait(self, mock_sleep): - """Test exit by timeout. + DutWrapper.SetupCpuUsage.assert_called_once_with() + DutWrapper.SetupCpuFreq.assert_called_once_with([0, 1]) + DutWrapper.GetCpuOnline.assert_called_once_with() + DutWrapper.SetCpuGovernor.assert_called_once_with( + 'fake_governor', ignore_status=False) + DutWrapper.DisableTurbo.assert_called_once_with() + DutWrapper.WaitCooldown.assert_not_called() - Send command to DUT checking the temperature and - check repeatedly until timeout goes off. - Output from temperature sensor never changes. - """ - mock_sleep.return_value = 0 - dut_runner = mock.Mock(return_value=(0, '41000', '')) - self.runner.dut_config['cooldown_time'] = 60 - self.runner.dut_config['cooldown_temp'] = 40 - wait_time = self.runner.WaitCooldown(dut_runner) - dut_runner.assert_called() - self.assertGreater(dut_runner.call_count, 2) - mock_sleep.assert_called() - self.assertGreater(wait_time, 0) + def test_setup_device_with_cooldown(self): - @mock.patch.object(time, 'sleep') - def test_wait_cooldown_needwait_multtemp(self, mock_sleep): - """Wait until all temps go down. - - Set large enough timeout and changing temperature - output. Make sure it exits when expected value - for all temperatures received. - Expect 3 checks. - """ - mock_sleep.return_value = 0 - dut_runner = mock.Mock(side_effect=[ - (0, '41000\n20000\n30000\n45000', ''), - (0, '39000\n20000\n30000\n41000', ''), - (0, '39000\n20000\n30000\n31000', ''), - ]) - self.runner.dut_config['cooldown_time'] = 100 - self.runner.dut_config['cooldown_temp'] = 40 - wait_time = self.runner.WaitCooldown(dut_runner) - dut_runner.assert_called() - self.assertEqual(dut_runner.call_count, 3) - mock_sleep.assert_called() - self.assertGreater(wait_time, 0) - - @mock.patch.object(time, 'sleep') - def test_wait_cooldown_thermal_error(self, mock_sleep): - """Handle error status. - - Any error should be considered non-fatal. - """ - mock_sleep.return_value = 0 - dut_runner = mock.Mock(side_effect=[ - (1, '39000\n20000\n30000\n41000', 'Thermal error'), - (1, '39000\n20000\n30000\n31000', 'Thermal error'), - ]) - self.runner.dut_config['cooldown_time'] = 10 - self.runner.dut_config['cooldown_temp'] = 40 - wait_time = self.runner.WaitCooldown(dut_runner) - # Check that errors are ignored. - dut_runner.assert_called_with( - 'cat /sys/class/thermal/thermal_zone*/temp', ignore_status=True) - self.assertEqual(dut_runner.call_count, 2) - # Check that we are waiting even when an error is returned - # as soon as data is coming. - mock_sleep.assert_called() - self.assertGreater(wait_time, 0) + def FakeRunner(command, ignore_status=False): + # pylint fix for unused variable. + del command, ignore_status + return 0, '', '' - @mock.patch.object(time, 'sleep') - def test_wait_cooldown_thermal_no_output(self, mock_sleep): - """Handle no output. + DutWrapper.RunCommandOnDut = mock.Mock(return_value=FakeRunner) + DutWrapper.DisableASLR = mock.Mock() + DutWrapper.DisableTurbo = mock.Mock() + DutWrapper.SetCpuGovernor = mock.Mock() + DutWrapper.SetupCpuUsage = mock.Mock() + DutWrapper.SetupCpuFreq = mock.Mock() + DutWrapper.WaitCooldown = mock.Mock(return_value=0) + DutWrapper.GetCpuOnline = mock.Mock(return_value={0: 0, 1: 1}) - Check handling of empty stdout. - """ - mock_sleep.return_value = 0 - dut_runner = mock.Mock(side_effect=[(1, '', 'Thermal error')]) self.runner.dut_config['cooldown_time'] = 10 - self.runner.dut_config['cooldown_temp'] = 40 - wait_time = self.runner.WaitCooldown(dut_runner) - # Check that errors are ignored. - dut_runner.assert_called_once_with( - 'cat /sys/class/thermal/thermal_zone*/temp', ignore_status=True) - # No wait. - mock_sleep.assert_not_called() - self.assertEqual(wait_time, 0) - - @mock.patch.object(time, 'sleep') - def test_wait_cooldown_thermal_ws_output(self, mock_sleep): - """Handle whitespace output. + self.runner.dut_config['governor'] = 'fake_governor' + self.runner.dut_config['cpu_freq_pct'] = 75 - Check handling of whitespace only. - """ - mock_sleep.return_value = 0 - dut_runner = mock.Mock(side_effect=[(1, '\n', 'Thermal error')]) - self.runner.dut_config['cooldown_time'] = 10 - self.runner.dut_config['cooldown_temp'] = 40 - wait_time = self.runner.WaitCooldown(dut_runner) - # Check that errors are ignored. - dut_runner.assert_called_once_with( - 'cat /sys/class/thermal/thermal_zone*/temp', ignore_status=True) - # No wait. - mock_sleep.assert_not_called() - self.assertEqual(wait_time, 0) - - def test_stop_ui(self): - dut_runner = mock.Mock(return_value=(0, '', '')) - self.runner.StopUI(dut_runner) - dut_runner.assert_called_once_with('stop ui') - - def test_start_ui(self): - dut_runner = mock.Mock(return_value=(0, '', '')) - self.runner.StartUI(dut_runner) - dut_runner.assert_called_once_with('start ui') + machine = 'fake_machine' + cros_machine = MockCrosMachine(machine, self.mock_label.chromeos_root, + self.mock_logger) + mock_run_on_dut = DutWrapper( + self.mock_label.chromeos_root, + machine, + logger=self.mock_logger, + dut_config=self.runner.dut_config) + + self.runner.SetupDevice(mock_run_on_dut, cros_machine) + + DutWrapper.WaitCooldown.assert_called_once_with() + DutWrapper.DisableASLR.assert_called_once() + DutWrapper.DisableTurbo.assert_called_once_with() + DutWrapper.SetupCpuUsage.assert_called_once_with() + DutWrapper.SetupCpuFreq.assert_called_once_with([1]) + DutWrapper.SetCpuGovernor.assert_called() + DutWrapper.GetCpuOnline.assert_called_once_with() + self.assertGreater(DutWrapper.SetCpuGovernor.call_count, 1) + self.assertEqual(DutWrapper.SetCpuGovernor.call_args, + mock.call('fake_governor', ignore_status=False)) @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommand') @mock.patch.object(command_executer.CommandExecuter, |