From 8b872ff1e96cf8af617ce76d8524bc98ed557f2f Mon Sep 17 00:00:00 2001 From: Brendan Jackman Date: Mon, 27 Feb 2017 14:45:42 +0000 Subject: [PATCH 1/2] tests/eas/preliminary: Add test for required sched_domain flags EAS silently does nothing if SD_SHARE_CAP_STATES isn't set on any sched_domains. --- tests/eas/preliminary.py | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/tests/eas/preliminary.py b/tests/eas/preliminary.py index 242eb5184..493de4804 100644 --- a/tests/eas/preliminary.py +++ b/tests/eas/preliminary.py @@ -212,4 +212,42 @@ class TestSchedutilTunables(BasicCheckTest): 'Responsiveness will be affected.'.format( self.MAX_DOWN_RATE_LIMIT_US, down_limit_fail_cpus)) -======= end +class TestSchedDomainFlags(BasicCheckTest): + """Test requirements of sched_domain flags""" + + # See include/linux/sched.h in an EAS kernel + SD_SHARE_CAP_STATES = 0x8000 + + def setUp(self): + if not self.target.file_exists('/proc/sys/kernel/sched_domain/'): + raise SkipTest('sched_domain info not exposed in procfs. ' + 'Enable CONFIG_SCHED_DEBUG in target kernel') + + def iter_cpu_sd_flags(self, cpu): + """ + Get the flags for a given CPU's sched_domains + + :param cpu: Logical CPU number whose sched_domains' flags we want + :returns: Iterator over the flags, as an int, of each of that CPU's + domains, highest-level (i.e. typically "DIE") first. + """ + base_path = '/proc/sys/kernel/sched_domain/cpu{}/'.format(cpu) + for domain in sorted(self.target.list_directory(base_path), reverse=True): + flags_path = self.target.path.join(base_path, domain, 'flags') + yield self.target.read_int(flags_path) + + def test_share_cap_states(self): + """ + Check that some domain exists with SD_SHARE_CAP_STATES set + + EAS silently does nothing if this flag is not set at any level (see + use of sd_scs percpu variable in scheduler code). + """ + cpu0_flags = [] + for flags in self.iter_cpu_sd_flags(0): + if flags & self.SD_SHARE_CAP_STATES: + return + cpu0_flags.append(flags) + flags_str = ', '.join([hex(f) for f in cpu0_flags]) + raise AssertionError('No sched_domain with SD_SHARE_CAP_STATES flag. ' + 'flags: {}'.format(flags_str)) -- GitLab From af07100fb34cfd659cf3dc3179f481c6a438aea3 Mon Sep 17 00:00:00 2001 From: Brendan Jackman Date: Tue, 28 Feb 2017 16:23:08 +0000 Subject: [PATCH 2/2] tests/eas/preliminary: Add test for SD_ASYM_CPUCAPACITY sd flag --- tests/eas/preliminary.py | 62 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/tests/eas/preliminary.py b/tests/eas/preliminary.py index 493de4804..c81fd8a78 100644 --- a/tests/eas/preliminary.py +++ b/tests/eas/preliminary.py @@ -216,6 +216,7 @@ class TestSchedDomainFlags(BasicCheckTest): """Test requirements of sched_domain flags""" # See include/linux/sched.h in an EAS kernel + SD_ASYM_CPUCAPACITY = 0x0040 SD_SHARE_CAP_STATES = 0x8000 def setUp(self): @@ -251,3 +252,64 @@ class TestSchedDomainFlags(BasicCheckTest): flags_str = ', '.join([hex(f) for f in cpu0_flags]) raise AssertionError('No sched_domain with SD_SHARE_CAP_STATES flag. ' 'flags: {}'.format(flags_str)) + + def _get_cpu_cap_path(self, cpu): + return '/sys/devices/system/cpu/cpu{}/cpu_capacity'.format(cpu) + + def read_cpu_caps(self): + """Get all the CPUs' capacities from sysfs as a list of ints""" + return [self.target.read_int(self._get_cpu_cap_path(cpu)) + for cpu in range(self.target.number_of_cpus)] + + def write_cpu_caps(self, caps): + """Write all the CPUs' capacites to sysfs from a list of ints""" + for cpu, cap in enumerate(caps): + self.target.write_value(self._get_cpu_cap_path(cpu), cap) + + def _test_asym_cpucapacity(self, caps, expect_asym): + top_sd_flags = self.iter_cpu_sd_flags(0).next() + if expect_asym: + self.assertTrue( + top_sd_flags & self.SD_ASYM_CPUCAPACITY, + 'SD_ASYM_CPUCAPACITY not set on highest sched_domain. ' + 'cpu_capacity values: {}'.format(caps)) + else: + self.assertFalse( + top_sd_flags & self.SD_ASYM_CPUCAPACITY, + 'SD_ASYM_CPUCAPACITY set unexpectedly on highest sched_domain. ' + 'cpu_capacity values: {}'.format(caps)) + + def test_asym_cpucapacity(self): + """ + Check that the SD_ASYM_CPUCAPACITY flag gets set when it should + + SD_ASYM_CPUCAPACITY should be set at least on the root domain when a + system is asymmetric. + + - Test that it is set appropriately for the current + cpu_capacity values + - Invert the apparent symmetry of the system by modifying the + cpu_capacity sysfs files, and check the flag is inverted. + - Finally, revert to the old cpu_capacity values and check the flag + returns to its old value. + """ + old_caps = self.read_cpu_caps() + old_caps_asym = any(c != old_caps[0] for c in old_caps[1:]) + + self._test_asym_cpucapacity(old_caps, old_caps_asym) + + if old_caps_asym: + # Make the (currently asymmetrical) system look symmetrical + test_caps = [1024 for _ in range(self.target.number_of_cpus)] + else: + # Make the (currently symmetrical) system look asymmetrical + test_caps = range(self.target.number_of_cpus) + + # Use a try..finally so that we leave the cpu_capacity files as we found + # them, even if the test fails (i.e. we raise an AssertionError). + try: + self.write_cpu_caps(test_caps) + self._test_asym_cpucapacity(old_caps, not old_caps_asym) + finally: + self.write_cpu_caps(old_caps) + self._test_asym_cpucapacity(old_caps, old_caps_asym) -- GitLab