From 73a472c5bb959612e77bcab67b2aadaf1f466a7f Mon Sep 17 00:00:00 2001 From: Jitka Obselkova <41325380+jobselko@users.noreply.github.com> Date: Thu, 15 Sep 2022 08:03:18 +0200 Subject: [PATCH] New parser for CpuSMTControl and tests update (#3521) * Add CpuSMTControl parser Signed-off-by: Jitka Obselkova * Rework current tests Signed-off-by: Jitka Obselkova Signed-off-by: Jitka Obselkova --- insights/parsers/smt.py | 65 ++++++++++++++++++--- insights/specs/default.py | 1 + insights/tests/parsers/test_smt.py | 91 ++++++++++++++++++------------ 3 files changed, 112 insertions(+), 45 deletions(-) diff --git a/insights/parsers/smt.py b/insights/parsers/smt.py index a6e2f18b29..dc1f3e0b15 100644 --- a/insights/parsers/smt.py +++ b/insights/parsers/smt.py @@ -6,6 +6,8 @@ CpuSMTActive - file ``/sys/devices/system/cpu/smt/active`` ---------------------------------------------------------- +CpuSMTControl - file ``/sys/devices/system/cpu/smt/control`` +------------------------------------------------------------ CpuCoreOnline - files matching ``/sys/devices/system/cpu/cpu[0-9]*/online`` --------------------------------------------------------------------------- CpuSiblings - files matching ``/sys/devices/system/cpu/cpu[0-9]*/topology/thread_siblings_list`` @@ -33,7 +35,7 @@ class CpuSMTActive(Parser): SkipException: When content is empty or cannot be parsed. Examples: - >>> cpu_smt.on + >>> cpu_smt_active.on True """ def parse_content(self, content): @@ -42,11 +44,57 @@ def parse_content(self, content): self.on = bool(int(content[0])) +@parser(Specs.cpu_smt_control) +class CpuSMTControl(Parser): + """ + Class for parsing ``/sys/devices/system/cpu/smt/control`` file. + Reports whether SMT is user-controllable. + + Four settings are possible:: + + on: SMT enabled + off: SMT disabled + forceoff: SMT disabled, cannot change at runtime + notsupported: CPU does not support SMT + + Typical output of this command is:: + + off + + Raises: + SkipException: When content is empty or cannot be parsed. + + Examples: + >>> cpu_smt_control.on + False + >>> cpu_smt_control.modifiable + True + >>> cpu_smt_control.supported + True + """ + SMT_CONTROL = { + "on": [True, True, True], + "off": [False, True, True], + "forceoff": [False, False, True], + "notsupported": [False, False, False] + } + + def parse_content(self, content): + if not content: + raise SkipException("No content.") + + values = self.SMT_CONTROL[content[0]] + + self.on = values[0] + self.modifiable = values[1] + self.supported = values[2] + + @parser(Specs.cpu_cores) class CpuCoreOnline(Parser): """ - Class for parsing ``/sys/devices/system/cpu/cpu[0-9]*/online`` matching files. - Reports whether a CPU core is online. Cpu0 is always online, so it does not have the "online" file. + Class for parsing ``/sys/devices/system/cpu/cpu[0-9]*/online`` matching files. Reports whether + a CPU core is online. Cpu0 is always online, so it does not have the "online" file. Typical output of this command is:: @@ -58,9 +106,9 @@ class CpuCoreOnline(Parser): SkipException: When content is empty or cannot be parsed Examples: - >>> cpu_core.core_id + >>> cpu_core_online.core_id 0 - >>> cpu_core.on + >>> cpu_core_online.on True """ cpu_core_path = r'/sys/devices/system/cpu/cpu(\d+)/online' @@ -78,8 +126,8 @@ def __repr__(self): @parser(Specs.cpu_siblings) class CpuSiblings(Parser): """ - Class for parsing ``/sys/devices/system/cpu/cpu[0-9]*/topology/thread_siblings_list`` matching files. - Reports CPU core siblings. + Class for parsing ``/sys/devices/system/cpu/cpu[0-9]*/topology/thread_siblings_list`` + matching files. Reports CPU core siblings. Typical output of this command is:: @@ -103,7 +151,8 @@ def parse_content(self, content): if not content: raise SkipException("No content.") - # The separator in the sibling list may be either in the format 0-1 or 0,2 depending on the CPU model + # The separator in the sibling list may be either in the format 0-1 or 0,2 depending on + # the CPU model if "-" in content[0]: cpu_range = [int(x) for x in content[0].split("-")] self.siblings = [x for x in range(cpu_range[0], cpu_range[1] + 1)] diff --git a/insights/specs/default.py b/insights/specs/default.py index 1efd2cb306..ca596e7a5e 100644 --- a/insights/specs/default.py +++ b/insights/specs/default.py @@ -136,6 +136,7 @@ class DefaultSpecs(Specs): cpu_cores = glob_file("sys/devices/system/cpu/cpu[0-9]*/online") cpu_siblings = glob_file("sys/devices/system/cpu/cpu[0-9]*/topology/thread_siblings_list") cpu_smt_active = simple_file("sys/devices/system/cpu/smt/active") + cpu_smt_control = simple_file("sys/devices/system/cpu/smt/control") cpu_vulns = glob_file("sys/devices/system/cpu/vulnerabilities/*") cpuinfo = simple_file("/proc/cpuinfo") cpupower_frequency_info = simple_command("/usr/bin/cpupower -c all frequency-info") diff --git a/insights/tests/parsers/test_smt.py b/insights/tests/parsers/test_smt.py index 4e4acfbc3f..878fd60cbd 100644 --- a/insights/tests/parsers/test_smt.py +++ b/insights/tests/parsers/test_smt.py @@ -2,52 +2,68 @@ import pytest from insights.parsers import smt, SkipException -from insights.parsers.smt import CpuSMTActive, CpuCoreOnline, CpuSiblings +from insights.parsers.smt import CpuSMTActive, CpuSMTControl, CpuCoreOnline, CpuSiblings from insights.tests import context_wrap -def test_cpu_smt_active(): - with pytest.raises(SkipException): - CpuSMTActive(context_wrap("")) +@pytest.mark.parametrize("setting, on", [ + ("0", False), + ("1", True) +]) +def test_cpu_smt_active(setting, on): + p = CpuSMTActive(context_wrap(setting)) + assert p.on == on - p = CpuSMTActive(context_wrap("1")) - assert p.on - p = CpuSMTActive(context_wrap("0")) - assert not p.on +@pytest.mark.parametrize("setting, on, modifiable, supported", [ + ("on", True, True, True), + ("off", False, True, True), + ("forceoff", False, False, True), + ("notsupported", False, False, False) +]) +def test_cpu_smt_control(setting, on, modifiable, supported): + p = CpuSMTControl(context_wrap(setting)) + assert p.on == on + assert p.modifiable == modifiable + assert p.supported == supported -def test_cpu_core_online(): - with pytest.raises(SkipException): - CpuCoreOnline(context_wrap("")) +@pytest.mark.parametrize("setting, on, status", [ + (0, False, "Offline"), + (1, True, "Online") +]) +def test_cpu_core_online(setting, on, status): path = "/sys/devices/system/cpu/cpu{0}/online" - p = CpuCoreOnline(context_wrap("0", path=path.format(0))) - assert p.core_id == 0 - assert not p.on - assert repr(p) == "[Core 0: Offline]" - p = CpuCoreOnline(context_wrap("1", path=path.format(1))) - assert p.core_id == 1 - assert p.on - assert repr(p) == "[Core 1: Online]" + p = CpuCoreOnline(context_wrap(str(setting), path=path.format(setting))) + assert p.core_id == setting + assert p.on == on + assert repr(p) == "[Core {0}: {1}]".format(setting, status) -def test_cpu_siblings(): - with pytest.raises(SkipException): - CpuSiblings(context_wrap("")) +@pytest.mark.parametrize("setting, core_id, siblings", [ + ("0,2", 0, [0, 2]), + ("1-3", 3, [1, 2, 3]), + ("1", 1, [1]) +]) +def test_cpu_siblings(setting, core_id, siblings): path = "/sys/devices/system/cpu/cpu{0}/topology/thread_siblings_list" - p = CpuSiblings(context_wrap("0,2", path=path.format(0))) - assert p.core_id == 0 - assert p.siblings == [0, 2] - assert repr(p) == "[Core 0 Siblings: [0, 2]]" - p = CpuSiblings(context_wrap("1-3", path=path.format(3))) - assert p.core_id == 3 - assert p.siblings == [1, 2, 3] - assert repr(p) == "[Core 3 Siblings: [1, 2, 3]]" - p = CpuSiblings(context_wrap("1", path=path.format(1))) - assert p.core_id == 1 - assert p.siblings == [1] - assert repr(p) == "[Core 1 Siblings: [1]]" + + p = CpuSiblings(context_wrap(setting, path=path.format(core_id))) + assert p.core_id == core_id + assert p.siblings == siblings + assert repr(p) == "[Core {0} Siblings: {1}]".format(core_id, siblings) + + +@pytest.mark.parametrize("parser", [ + CpuSMTActive, + CpuSMTControl, + CpuCoreOnline, + CpuSiblings +]) +def test_exceptions(parser): + with pytest.raises(SkipException): + parser(context_wrap("")) def test_doc_examples(): @@ -55,9 +71,10 @@ def test_doc_examples(): path_cpu_siblings = "/sys/devices/system/cpu/cpu0/topology/thread_siblings_list" env = { - "cpu_smt": CpuSMTActive(context_wrap("1")), - "cpu_core": CpuCoreOnline(context_wrap("1", path=path_cpu_core_online)), - "cpu_siblings": CpuSiblings(context_wrap("0,2", path=path_cpu_siblings)) + "cpu_smt_active": CpuSMTActive(context_wrap("1")), + "cpu_smt_control": CpuSMTControl(context_wrap("off")), + "cpu_core_online": CpuCoreOnline(context_wrap("1", path=path_cpu_core_online)), + "cpu_siblings": CpuSiblings(context_wrap("0,2", path=path_cpu_siblings)), } failed, total = doctest.testmod(smt, globs=env) assert failed == 0