diff options
author | Denis Nikitin <denik@google.com> | 2019-09-04 07:51:52 -0700 |
---|---|---|
committer | Denis Nikitin <denik@chromium.org> | 2019-09-10 05:34:59 +0000 |
commit | 1acae417eaeda7640327721f7226bf1e0ea960ed (patch) | |
tree | 8b50e7a911afe483a715f86778513d5afb43cbe8 /crosperf | |
parent | 9d114045ddf617b67fd7af5aaccd0b5dcd4282ea (diff) | |
download | toolchain-utils-1acae417eaeda7640327721f7226bf1e0ea960ed.tar.gz |
crosperf: Setup CPU configuration based on 'cpu_usage'.
Based on dut_config['cpu_usage'] setup DUT to use
big or little cores only on ARM platform.
Ignore 'cpu_usage' if setup is invalid for targeted platform.
For example 'big_only" on Intel or ARM w/o big/little support.
BUG=chromium:966514
TEST=Unitest and local HW tests passed.
Cq-Depend: chromium:1778515
Change-Id: Ida457a1ceaf20c4dcbb8d40334a2423836999574
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/toolchain-utils/+/1783849
Reviewed-by: Caroline Tice <cmtice@chromium.org>
Legacy-Commit-Queue: Commit Bot <commit-bot@chromium.org>
Tested-by: Denis Nikitin <denik@chromium.org>
Diffstat (limited to 'crosperf')
-rw-r--r-- | crosperf/suite_runner.py | 122 | ||||
-rwxr-xr-x | crosperf/suite_runner_unittest.py | 189 |
2 files changed, 310 insertions, 1 deletions
diff --git a/crosperf/suite_runner.py b/crosperf/suite_runner.py index 2831b9bd..d5d6c2c7 100644 --- a/crosperf/suite_runner.py +++ b/crosperf/suite_runner.py @@ -8,6 +8,7 @@ from __future__ import print_function import os +import re import shlex import time @@ -80,6 +81,7 @@ class SuiteRunner(object): if not self.enable_aslr: self.DisableASLR(machine, label.chromeos_root) self.PinGovernorExecutionFrequencies(machine, label.chromeos_root) + self.SetupCpuUsage(machine, label.chromeos_root) if benchmark.suite == 'telemetry_Crosperf': self.DecreaseWaitTime(machine, label.chromeos_root) ret_tup = self.Telemetry_Crosperf_Run(machine, label, benchmark, @@ -173,6 +175,126 @@ class SuiteRunner(object): self.logger.LogFatalIf( ret, 'Could not pin frequencies on machine: %s' % machine_name) + def SetupCpuUsage(self, machine_name, chromeos_root): + """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'): + ret, arch, _ = self._ce.CrosRunCommandWOutput( + 'uname -m', machine=machine_name, chromeos_root=chromeos_root) + self.logger.LogFatalIf( + ret, 'Setup CPU failed. Could not retrieve architecture model.') + + if arch.lower().startswith('arm') or arch.lower().startswith('aarch64'): + self.SetupArmCores(machine_name, chromeos_root) + + def SetupArmCores(self, machine_name, chromeos_root): + """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 + + ret, cpuinfo, _ = self._ce.CrosRunCommandWOutput( + 'cat /proc/cpuinfo', machine=machine_name, chromeos_root=chromeos_root) + self.logger.LogFatalIf(ret, + 'Setup ARM CPU failed. Could not retrieve 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))) + + ret = self._ce.CrosRunCommand( + '; '.join([cmd_enable_cores, cmd_disable_cores]), + machine=machine_name, + chromeos_root=chromeos_root) + self.logger.LogFatalIf( + ret, 'Setup ARM CPU failed. Could not retrieve cpuinfo.') + 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 DecreaseWaitTime(self, machine_name, chromeos_root): """Change the ten seconds wait time for pagecycler to two seconds.""" FILE = '/usr/local/telemetry/src/tools/perf/page_sets/page_cycler_story.py' diff --git a/crosperf/suite_runner_unittest.py b/crosperf/suite_runner_unittest.py index 4af6f4e9..c5a4c181 100755 --- a/crosperf/suite_runner_unittest.py +++ b/crosperf/suite_runner_unittest.py @@ -12,8 +12,8 @@ from __future__ import print_function import os.path import time -import mock import unittest +import mock import suite_runner import label @@ -23,6 +23,80 @@ from benchmark import Benchmark from cros_utils import command_executer from cros_utils import logger +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.""" @@ -68,6 +142,7 @@ class SuiteRunnerTest(unittest.TestCase): self.call_test_that_run = False self.disable_aslr_args = [] self.pin_governor_args = [] + self.setup_cpu_usage_args = [] self.skylab_run_args = [] self.test_that_args = [] self.telemetry_run_args = [] @@ -76,6 +151,7 @@ class SuiteRunnerTest(unittest.TestCase): self.call_telemetry_crosperf_run = False self.call_disable_aslr = False self.call_pin_governor = False + self.call_setup_cpu_usage = False def setUp(self): self.runner = suite_runner.SuiteRunner( @@ -93,10 +169,12 @@ class SuiteRunnerTest(unittest.TestCase): def reset(): self.call_pin_governor = False + self.call_setup_cpu_usage = False self.call_test_that_run = False self.call_skylab_run = False self.call_telemetry_crosperf_run = False self.pin_governor_args = [] + self.setup_cpu_usage_args = [] self.skylab_run_args = [] self.test_that_args = [] self.telemetry_run_args = [] @@ -110,6 +188,10 @@ class SuiteRunnerTest(unittest.TestCase): self.call_pin_governor = True self.pin_governor_args = [machine, chroot] + def FakeSetupCpuUsage(machine, chroot): + self.call_setup_cpu_usage = True + self.setup_cpu_usage_args = [machine, chroot] + 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 @@ -133,6 +215,7 @@ class SuiteRunnerTest(unittest.TestCase): self.runner.DisableASLR = FakeDisableASLR self.runner.PinGovernorExecutionFrequencies = FakePinGovernor + self.runner.SetupCpuUsage = FakeSetupCpuUsage self.runner.Skylab_Run = FakeSkylabRun self.runner.Telemetry_Crosperf_Run = FakeTelemetryCrosperfRun self.runner.Test_That_Run = FakeTestThatRun @@ -146,6 +229,7 @@ class SuiteRunnerTest(unittest.TestCase): profiler_args) self.assertFalse(self.call_disable_aslr) self.assertFalse(self.call_pin_governor) + self.assertFalse(self.call_setup_cpu_usage) self.assertTrue(self.call_skylab_run) self.assertFalse(self.call_test_that_run) self.assertFalse(self.call_telemetry_crosperf_run) @@ -158,6 +242,9 @@ class SuiteRunnerTest(unittest.TestCase): profiler_args) self.assertTrue(self.call_disable_aslr) self.assertTrue(self.call_pin_governor) + self.assertTrue(self.call_setup_cpu_usage) + self.assertEqual(self.setup_cpu_usage_args, + [machine, self.mock_label.chromeos_root]) self.assertTrue(self.call_test_that_run) self.assertFalse(self.call_telemetry_crosperf_run) self.assertEqual( @@ -169,6 +256,7 @@ class SuiteRunnerTest(unittest.TestCase): test_args, profiler_args) self.assertTrue(self.call_disable_aslr) self.assertTrue(self.call_pin_governor) + self.assertTrue(self.call_setup_cpu_usage) self.assertFalse(self.call_test_that_run) self.assertTrue(self.call_telemetry_crosperf_run) self.assertEqual(self.telemetry_crosperf_args, [ @@ -217,6 +305,105 @@ class SuiteRunnerTest(unittest.TestCase): # pyformat: enable self.assertEqual(cmd, (set_cpu_cmd,)) + @mock.patch.object(suite_runner.SuiteRunner, 'SetupArmCores') + @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommandWOutput') + def test_setup_cpu_usage_little_on_arm(self, mock_cros_runcmd_wout, + mock_setup_arm): + self.mock_cmd_exec.CrosRunCommandWOutput = mock_cros_runcmd_wout + self.runner.SetupArmCores = mock_setup_arm + mock_cros_runcmd_wout.return_value = (0, 'armv7l', '') + self.runner.dut_config['cpu_usage'] = 'little_only' + self.runner.SetupCpuUsage('remote.cros', '/tmp/chromeos') + self.assertEqual(mock_setup_arm.call_count, 1) + + @mock.patch.object(suite_runner.SuiteRunner, 'SetupArmCores') + @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommandWOutput') + def test_setup_cpu_usage_big_on_aarch64(self, mock_cros_runcmd_wout, + mock_setup_arm): + self.mock_cmd_exec.CrosRunCommandWOutput = mock_cros_runcmd_wout + self.runner.SetupArmCores = mock_setup_arm + mock_cros_runcmd_wout.return_value = (0, 'aarch64', '') + self.runner.dut_config['cpu_usage'] = 'big_only' + self.runner.SetupCpuUsage('remote.cros', '/tmp/chromeos') + self.assertEqual(mock_setup_arm.call_count, 1) + + @mock.patch.object(suite_runner.SuiteRunner, 'SetupArmCores') + @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommandWOutput') + def test_setup_cpu_usage_all_on_intel(self, mock_cros_runcmd_wout, + mock_setup_arm): + self.mock_cmd_exec.CrosRunCommandWOutput = mock_cros_runcmd_wout + self.runner.SetupArmCores = mock_setup_arm + mock_cros_runcmd_wout.return_value = (0, 'x86_64', '') + self.runner.dut_config['cpu_usage'] = 'all' + self.runner.SetupCpuUsage('remote.cros', '/tmp/chromeos') + # Check that SetupArmCores not called. + self.assertEqual(mock_setup_arm.call_count, 0) + + @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommandWOutput') + @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommand') + def test_setup_arm_cores_big_on_big_little(self, mock_cros_runcmd, + mock_cros_runcmd_wout): + self.mock_cmd_exec.CrosRunCommand = mock_cros_runcmd + self.mock_cmd_exec.CrosRunCommandWOutput = mock_cros_runcmd_wout + mock_cros_runcmd_wout.return_value = (0, BIG_LITTLE_CPUINFO, '') + self.runner.dut_config['cpu_usage'] = 'big_only' + self.runner.SetupArmCores('remote.cros', '/tmp/chromeos') + self.assertEqual(mock_cros_runcmd.call_args_list[0][0], + ('echo 1 | tee /sys/devices/system/cpu/cpu{2}/online; ' + 'echo 0 | tee /sys/devices/system/cpu/cpu{0,1}/online',)) + + @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommandWOutput') + @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommand') + def test_setup_arm_cores_little_on_big_little(self, mock_cros_runcmd, + mock_cros_runcmd_wout): + self.mock_cmd_exec.CrosRunCommand = mock_cros_runcmd + self.mock_cmd_exec.CrosRunCommandWOutput = mock_cros_runcmd_wout + mock_cros_runcmd_wout.return_value = (0, BIG_LITTLE_CPUINFO, '') + self.runner.dut_config['cpu_usage'] = 'little_only' + self.runner.SetupArmCores('remote.cros', '/tmp/chromeos') + self.assertEqual(mock_cros_runcmd.call_args_list[0][0], + ('echo 1 | tee /sys/devices/system/cpu/cpu{0,1}/online; ' + 'echo 0 | tee /sys/devices/system/cpu/cpu{2}/online',)) + + @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommandWOutput') + @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommand') + def test_setup_arm_cores_invalid_config(self, mock_cros_runcmd, + mock_cros_runcmd_wout): + self.mock_cmd_exec.CrosRunCommand = mock_cros_runcmd + self.mock_cmd_exec.CrosRunCommandWOutput = mock_cros_runcmd_wout + mock_cros_runcmd_wout.return_value = (0, LITTLE_ONLY_CPUINFO, '') + self.runner.dut_config['cpu_usage'] = 'big_only' + self.runner.SetupArmCores('remote.cros', '/tmp/chromeos') + # Check that CrosRun is not called when trying + # to use 'big_only' on a platform with all little cores. + self.assertEqual(mock_cros_runcmd.call_count, 0) + + @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommandWOutput') + @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommand') + def test_setup_arm_cores_not_big_little(self, mock_cros_runcmd, + mock_cros_runcmd_wout): + self.mock_cmd_exec.CrosRunCommand = mock_cros_runcmd + self.mock_cmd_exec.CrosRunCommandWOutput = mock_cros_runcmd_wout + mock_cros_runcmd_wout.return_value = (0, NOT_BIG_LITTLE_CPUINFO, '') + self.runner.dut_config['cpu_usage'] = 'big_only' + self.runner.SetupArmCores('remote.cros', '/tmp/chromeos') + # Check that CrosRun is not called when trying + # to use 'big_only' on a platform w/o support of big/little. + self.assertEqual(mock_cros_runcmd.call_count, 0) + + @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommandWOutput') + @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommand') + def test_setup_arm_cores_unsupported_cpu_usage(self, mock_cros_runcmd, + mock_cros_runcmd_wout): + self.mock_cmd_exec.CrosRunCommand = mock_cros_runcmd + self.mock_cmd_exec.CrosRunCommandWOutput = mock_cros_runcmd_wout + mock_cros_runcmd_wout.return_value = (0, BIG_LITTLE_CPUINFO, '') + self.runner.dut_config['cpu_usage'] = 'exclusive_cores' + self.runner.SetupArmCores('remote.cros', '/tmp/chromeos') + # Check that CrosRun is not called when trying to use + # 'exclusive_cores' on ARM CPU setup. + self.assertEqual(mock_cros_runcmd.call_count, 0) + @mock.patch.object(command_executer.CommandExecuter, 'CrosRunCommand') def test_reboot_machine(self, mock_cros_runcmd): |