Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New parser for CpuSMTControl and tests update #3521

Merged
merged 2 commits into from
Sep 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 57 additions & 8 deletions insights/parsers/smt.py
Original file line number Diff line number Diff line change
Expand Up @@ -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``
Expand Down Expand Up @@ -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):
Expand All @@ -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::

Expand All @@ -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'
Expand All @@ -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::

Expand All @@ -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)]
Expand Down
1 change: 1 addition & 0 deletions insights/specs/default.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
91 changes: 54 additions & 37 deletions insights/tests/parsers/test_smt.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,62 +2,79 @@
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():
path_cpu_core_online = "/sys/devices/system/cpu/cpu0/online"
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