Add functionality to allow user to execute cpupower tool to
set idle state depth while running rteval. Disable latency trick by using --default-system option with cyclictest when setting idle state depth. Resolves: RHEL-37645 Signed-off-by: Anubhav Shelat <ashelat@redhat.com>
This commit is contained in:
parent
ef808082f2
commit
e2c4c6e2d5
221
rteval-Added-functionality-to-allow-user-to-set-the-.patch
Normal file
221
rteval-Added-functionality-to-allow-user-to-set-the-.patch
Normal file
@ -0,0 +1,221 @@
|
|||||||
|
From b3c96935c82b7410422ca2973398ac9d0272c844 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Anubhav Shelat <ashelat@redhat.com>
|
||||||
|
Date: Fri, 2 Aug 2024 11:46:35 -0400
|
||||||
|
Subject: [PATCH 1/2] rteval: Added functionality to allow user to set the
|
||||||
|
cstate of specified cpus when running rteval
|
||||||
|
|
||||||
|
We would like to be able to set the idle states of CPUs while running
|
||||||
|
rteval.
|
||||||
|
|
||||||
|
This patch adds the file cpupower.py and option '--idle-set' within
|
||||||
|
rteval to use cpupower. The set idle state is applied to the cpulist
|
||||||
|
given by '--measurement-cpulist'.
|
||||||
|
|
||||||
|
cpupower.py provides the infrastructure to interface and execute the cpupower
|
||||||
|
command, and the options in rteval-cmd let the user specify the idle state
|
||||||
|
to be set and the CPUs to set it on.
|
||||||
|
|
||||||
|
Signed-off-by: Anubhav Shelat <ashelat@redhat.com>
|
||||||
|
Signed-off-by: John Kacur <jkacur@redhat.com>
|
||||||
|
---
|
||||||
|
rteval-cmd | 9 ++
|
||||||
|
rteval/cpupower.py | 125 +++++++++++++++++++++++++
|
||||||
|
rteval/modules/__init__.py | 2 +-
|
||||||
|
rteval/modules/measurement/__init__.py | 2 +
|
||||||
|
4 files changed, 137 insertions(+), 1 deletion(-)
|
||||||
|
create mode 100644 rteval/cpupower.py
|
||||||
|
|
||||||
|
diff --git a/rteval-cmd b/rteval-cmd
|
||||||
|
index 19c82a0b64b3..f440a8a22622 100755
|
||||||
|
--- a/rteval-cmd
|
||||||
|
+++ b/rteval-cmd
|
||||||
|
@@ -29,6 +29,7 @@ from rteval.Log import Log
|
||||||
|
from rteval import RtEval, rtevalConfig
|
||||||
|
from rteval.modules.loads import LoadModules
|
||||||
|
from rteval.modules.measurement import MeasurementModules
|
||||||
|
+from rteval import cpupower
|
||||||
|
from rteval.version import RTEVAL_VERSION
|
||||||
|
from rteval.systopology import SysTopology, parse_cpulist_from_config
|
||||||
|
from rteval.modules.loads.kcompile import ModuleParameters
|
||||||
|
@@ -402,6 +403,10 @@ if __name__ == '__main__':
|
||||||
|
if not os.path.isdir(rtevcfg.workdir):
|
||||||
|
raise RuntimeError(f"work directory {rtevcfg.workdir} does not exist")
|
||||||
|
|
||||||
|
+ # if idle-set has been specified, enable the idle state via cpupower
|
||||||
|
+ if msrcfg.idlestate:
|
||||||
|
+ cpupower_controller = cpupower.Cpupower(msrcfg.cpulist, msrcfg.idlestate, logger=logger)
|
||||||
|
+ cpupower_controller.enable_idle_state()
|
||||||
|
|
||||||
|
rteval = RtEval(config, loadmods, measuremods, logger)
|
||||||
|
rteval.Prepare(rtevcfg.onlyload)
|
||||||
|
@@ -421,6 +426,10 @@ if __name__ == '__main__':
|
||||||
|
ec = rteval.Measure()
|
||||||
|
logger.log(Log.DEBUG, f"exiting with exit code: {ec}")
|
||||||
|
|
||||||
|
+ # restore previous idle state settings
|
||||||
|
+ if msrcfg.idlestate:
|
||||||
|
+ cpupower_controller.restore_idle_states()
|
||||||
|
+
|
||||||
|
sys.exit(ec)
|
||||||
|
except KeyboardInterrupt:
|
||||||
|
sys.exit(0)
|
||||||
|
diff --git a/rteval/cpupower.py b/rteval/cpupower.py
|
||||||
|
new file mode 100644
|
||||||
|
index 000000000000..37c4d33f1df4
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/rteval/cpupower.py
|
||||||
|
@@ -0,0 +1,125 @@
|
||||||
|
+# SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
+
|
||||||
|
+# Copyright 2024 Anubhav Shelat <ashelat@redhat.com>
|
||||||
|
+""" Object to execute cpupower tool """
|
||||||
|
+
|
||||||
|
+import subprocess
|
||||||
|
+import os
|
||||||
|
+import shutil
|
||||||
|
+import sys
|
||||||
|
+from rteval.Log import Log
|
||||||
|
+from rteval.systopology import SysTopology as SysTop
|
||||||
|
+from rteval import cpulist_utils
|
||||||
|
+
|
||||||
|
+PATH = '/sys/devices/system/cpu/'
|
||||||
|
+
|
||||||
|
+class Cpupower:
|
||||||
|
+ """ class to store data for executing cpupower and restoring idle state configuration """
|
||||||
|
+ def __init__(self, cpulist, idlestate, logger=None):
|
||||||
|
+ if not self.cpupower_present():
|
||||||
|
+ print('cpupower not found')
|
||||||
|
+ sys.exit(1)
|
||||||
|
+
|
||||||
|
+ self.__idle_state = int(idlestate)
|
||||||
|
+ self.__states = os.listdir(PATH + 'cpu0/cpuidle/')
|
||||||
|
+ # self.__idle_states is a dict with cpus as keys,
|
||||||
|
+ # and another dict as the value. The value dict
|
||||||
|
+ # has idle states as keys and a boolean as the
|
||||||
|
+ # value indicating if the state is disabled.
|
||||||
|
+ self.__idle_states = {}
|
||||||
|
+ self.__name = "cpupower"
|
||||||
|
+ self.__online_cpus = SysTop().online_cpus()
|
||||||
|
+ self.__cpulist = cpulist
|
||||||
|
+ self.__logger = logger
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ def _log(self, logtype, msg):
|
||||||
|
+ """ Common log function for rteval modules """
|
||||||
|
+ if self.__logger:
|
||||||
|
+ self.__logger.log(logtype, f"[{self.__name}] {msg}")
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ def enable_idle_state(self):
|
||||||
|
+ """ Use cpupower to set the idle state """
|
||||||
|
+ self.get_idle_states()
|
||||||
|
+
|
||||||
|
+ # ensure that idle state is in range of available idle states
|
||||||
|
+ if self.__idle_state > len(self.__states) - 1 or self.__idle_state < 0:
|
||||||
|
+ print(f'Idle state {self.__idle_state} is out of range')
|
||||||
|
+ sys.exit(1)
|
||||||
|
+
|
||||||
|
+ # enable all idle states to a certain depth, and disable any deeper idle states
|
||||||
|
+ with open(os.devnull, 'wb') as buffer:
|
||||||
|
+ for state in self.__states:
|
||||||
|
+ s = state.strip("state")
|
||||||
|
+ if int(s) > self.__idle_state:
|
||||||
|
+ self.run_cpupower(['cpupower', '-c', self.__cpulist,'idle-set', '-d', s], buffer)
|
||||||
|
+ else:
|
||||||
|
+ self.run_cpupower(['cpupower', '-c', self.__cpulist,'idle-set', '-e', s], buffer)
|
||||||
|
+
|
||||||
|
+ self._log(Log.DEBUG, f'Idle state depth {self.__idle_state} enabled on CPUs {self.__cpulist}')
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ def run_cpupower(self, args, output_buffer=None):
|
||||||
|
+ """ execute cpupower """
|
||||||
|
+ try:
|
||||||
|
+ subprocess.run(args, check=True, stdout=output_buffer)
|
||||||
|
+ except subprocess.CalledProcessError:
|
||||||
|
+ print('cpupower failed')
|
||||||
|
+ sys.exit(1)
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ def get_idle_states(self):
|
||||||
|
+ """ Store the current idle state setting """
|
||||||
|
+ for cpu in self.__online_cpus:
|
||||||
|
+ self.__idle_states[cpu] = {}
|
||||||
|
+ for state in self.__states:
|
||||||
|
+ fp = os.path.join(PATH, 'cpu' + str(cpu) + '/cpuidle/' + state + '/disable')
|
||||||
|
+ self.__idle_states[cpu][state] = self.read_idle_state(fp)
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ def restore_idle_states(self):
|
||||||
|
+ """ restore the idle state setting """
|
||||||
|
+ for cpu, states in self.__idle_states.items():
|
||||||
|
+ for state, disabled in states.items():
|
||||||
|
+ fp = os.path.join(PATH, 'cpu' + str(cpu) + '/cpuidle/' + state + '/disable')
|
||||||
|
+ self.write_idle_state(fp, disabled)
|
||||||
|
+ self._log(Log.DEBUG, 'Idle state settings restored')
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ def read_idle_state(self, file):
|
||||||
|
+ """ read the disable value for an idle state """
|
||||||
|
+ with open(file, 'r', encoding='utf-8') as f:
|
||||||
|
+ return f.read(1)
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ def write_idle_state(self, file, state):
|
||||||
|
+ """ write the disable value for and idle state """
|
||||||
|
+ with open(file, 'w', encoding='utf-8') as f:
|
||||||
|
+ f.write(state)
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ def get_idle_info(self):
|
||||||
|
+ """ execute cpupower idle-info """
|
||||||
|
+ self.run_cpupower(['cpupower', 'idle-info'])
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+ def cpupower_present(self):
|
||||||
|
+ """ check if cpupower is downloaded """
|
||||||
|
+ return shutil.which("cpupower") is not None
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+if __name__ == '__main__':
|
||||||
|
+ l = Log()
|
||||||
|
+ l.SetLogVerbosity(Log.DEBUG)
|
||||||
|
+
|
||||||
|
+ online_cpus = cpulist_utils.collapse_cpulist(SysTop().online_cpus())
|
||||||
|
+ idlestate = '1'
|
||||||
|
+ info = True
|
||||||
|
+
|
||||||
|
+ cpupower = Cpupower(online_cpus, idlestate, logger=l)
|
||||||
|
+ if idlestate:
|
||||||
|
+ cpupower.enable_idle_state()
|
||||||
|
+ cpupower.restore_idle_states()
|
||||||
|
+ print()
|
||||||
|
+ cpupower.get_idle_info()
|
||||||
|
diff --git a/rteval/modules/__init__.py b/rteval/modules/__init__.py
|
||||||
|
index d7792108d5b8..acd6330788e2 100644
|
||||||
|
--- a/rteval/modules/__init__.py
|
||||||
|
+++ b/rteval/modules/__init__.py
|
||||||
|
@@ -282,7 +282,7 @@ reference from the first import"""
|
||||||
|
grparser.add_argument(f'--{self.__modtype}-cpulist',
|
||||||
|
dest=f'{self.__modtype}___cpulist', action='store', default="",
|
||||||
|
help=f'CPU list where {self.__modtype} modules will run',
|
||||||
|
- metavar='LIST')
|
||||||
|
+ metavar='CPULIST')
|
||||||
|
|
||||||
|
for (modname, mod) in list(self.__modsloaded.items()):
|
||||||
|
opts = mod.ModuleParameters()
|
||||||
|
diff --git a/rteval/modules/measurement/__init__.py b/rteval/modules/measurement/__init__.py
|
||||||
|
index ecadd0885991..9314d1cb6bbc 100644
|
||||||
|
--- a/rteval/modules/measurement/__init__.py
|
||||||
|
+++ b/rteval/modules/measurement/__init__.py
|
||||||
|
@@ -38,6 +38,8 @@ class MeasurementModules(RtEvalModules):
|
||||||
|
default=self._cfg.GetSection("measurement").setdefault("run-on-isolcpus", "false").lower()
|
||||||
|
== "true",
|
||||||
|
help="Include isolated CPUs in default cpulist")
|
||||||
|
+ grparser.add_argument('--idle-set', dest='measurement___idlestate', metavar='IDLESTATE',
|
||||||
|
+ default=None, help='Idle state depth to set on cpus running measurement modules')
|
||||||
|
|
||||||
|
|
||||||
|
def Setup(self, modparams):
|
||||||
|
--
|
||||||
|
2.45.2
|
||||||
|
|
71
rteval-run-cyclictest-using-default-system-when-sett.patch
Normal file
71
rteval-run-cyclictest-using-default-system-when-sett.patch
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
From 034fb231ff06aa4615b7531a04e4c3e0ce4aa662 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Anubhav Shelat <ashelat@redhat.com>
|
||||||
|
Date: Fri, 2 Aug 2024 11:46:36 -0400
|
||||||
|
Subject: [PATCH 2/2] rteval: run cyclictest using '--default-system' when
|
||||||
|
setting idle states
|
||||||
|
|
||||||
|
When running cyclictest in rteval, cyclictest automatically disables
|
||||||
|
idle states. This means whenever the user sets the idle state of a cpu
|
||||||
|
list using '--idle-set' it is overridden by cyclictest.
|
||||||
|
|
||||||
|
To fix this, the variable 'usingCpupower' is appended to the parameter
|
||||||
|
dictionary that's passed to the Cyclictest measurement object which executes
|
||||||
|
cyclictest in rteval.
|
||||||
|
|
||||||
|
If '--idle-set' is specified when running rteval,
|
||||||
|
'usingCpupower' is set to true and the '--default-system' option is
|
||||||
|
appended to the cyclictest command, which will prevent cyclictest from
|
||||||
|
disabling cstates.
|
||||||
|
|
||||||
|
Signed-off-by: Anubhav Shelat <ashelat@redhat.com>
|
||||||
|
Signed-off-by: John Kacur <jkacur@redhat.com>
|
||||||
|
---
|
||||||
|
rteval-cmd | 4 ++++
|
||||||
|
rteval/__init__.py | 1 +
|
||||||
|
rteval/modules/measurement/cyclictest.py | 3 +++
|
||||||
|
3 files changed, 8 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/rteval-cmd b/rteval-cmd
|
||||||
|
index f440a8a22622..4e13d312a24a 100755
|
||||||
|
--- a/rteval-cmd
|
||||||
|
+++ b/rteval-cmd
|
||||||
|
@@ -266,6 +266,10 @@ if __name__ == '__main__':
|
||||||
|
| (rtevcfg.debugging and Log.DEBUG)
|
||||||
|
logger.SetLogVerbosity(loglev)
|
||||||
|
|
||||||
|
+ # check if cpupower is being used
|
||||||
|
+ if sys.argv.count('--idle-set') > 0:
|
||||||
|
+ rtevcfg.update({'usingCpupower': True})
|
||||||
|
+
|
||||||
|
# Load modules
|
||||||
|
loadmods = LoadModules(config, logger=logger)
|
||||||
|
measuremods = MeasurementModules(config, logger=logger)
|
||||||
|
diff --git a/rteval/__init__.py b/rteval/__init__.py
|
||||||
|
index 4d3e0c23e5ab..8ded374d287e 100644
|
||||||
|
--- a/rteval/__init__.py
|
||||||
|
+++ b/rteval/__init__.py
|
||||||
|
@@ -119,6 +119,7 @@ class RtEval(rtevalReport):
|
||||||
|
'memsize':self._sysinfo.mem_get_size(),
|
||||||
|
'numanodes':self._sysinfo.mem_get_numa_nodes(),
|
||||||
|
'duration': float(self.__rtevcfg.duration),
|
||||||
|
+ 'usingCpupower': self.__rtevcfg.usingCpupower
|
||||||
|
}
|
||||||
|
|
||||||
|
if self._loadmods:
|
||||||
|
diff --git a/rteval/modules/measurement/cyclictest.py b/rteval/modules/measurement/cyclictest.py
|
||||||
|
index d919058e927f..2e8f6f1870ed 100644
|
||||||
|
--- a/rteval/modules/measurement/cyclictest.py
|
||||||
|
+++ b/rteval/modules/measurement/cyclictest.py
|
||||||
|
@@ -251,6 +251,9 @@ class Cyclictest(rtevalModulePrototype):
|
||||||
|
self.__cmd.append(f'-t{self.__numcores}')
|
||||||
|
self.__cmd.append(f'-a{self.__cpulist}')
|
||||||
|
|
||||||
|
+ if (self.__cfg.usingCpupower):
|
||||||
|
+ self.__cmd.append('--default-system')
|
||||||
|
+
|
||||||
|
if 'threads' in self.__cfg and self.__cfg.threads:
|
||||||
|
self.__cmd.append(f"-t{int(self.__cfg.threads)}")
|
||||||
|
|
||||||
|
--
|
||||||
|
2.45.2
|
||||||
|
|
11
rteval.spec
11
rteval.spec
@ -1,6 +1,6 @@
|
|||||||
Name: rteval
|
Name: rteval
|
||||||
Version: 3.8
|
Version: 3.8
|
||||||
Release: 5%{?dist}
|
Release: 6%{?dist}
|
||||||
Summary: Utility to evaluate system suitability for RT Linux
|
Summary: Utility to evaluate system suitability for RT Linux
|
||||||
|
|
||||||
Group: Development/Tools
|
Group: Development/Tools
|
||||||
@ -46,6 +46,8 @@ Patch10: rteval-Enforce-only-one-latency-measurement-module-a.patch
|
|||||||
Patch11: rteval-Add-noload-option.patch
|
Patch11: rteval-Add-noload-option.patch
|
||||||
Patch12: rteval-Fix-default-measurement-config.patch
|
Patch12: rteval-Fix-default-measurement-config.patch
|
||||||
Patch13: rteval-measurement-Change-latency-flag-to-latency_te.patch
|
Patch13: rteval-measurement-Change-latency-flag-to-latency_te.patch
|
||||||
|
Patch14: rteval-Added-functionality-to-allow-user-to-set-the-.patch
|
||||||
|
Patch15: rteval-run-cyclictest-using-default-system-when-sett.patch
|
||||||
|
|
||||||
%description
|
%description
|
||||||
The rteval script is a utility for measuring various aspects of
|
The rteval script is a utility for measuring various aspects of
|
||||||
@ -79,6 +81,13 @@ to the screen.
|
|||||||
%{_bindir}/rteval
|
%{_bindir}/rteval
|
||||||
|
|
||||||
%changelog
|
%changelog
|
||||||
|
* Tue Aug 6 2024 Anubhav Shelat <ashelat@redhat.com> - 3.8-6
|
||||||
|
- Add functionality to allow user to execute cpupower tool to
|
||||||
|
set idle state depth while running rteval.
|
||||||
|
- Disable latency trick by using --default-system option with
|
||||||
|
cyclictest when setting idle state depth.
|
||||||
|
Resolves: RHEL-37645
|
||||||
|
|
||||||
* Mon Jul 29 2024 Crystal Wood <crwood@redhat.com> - 3.8-5
|
* Mon Jul 29 2024 Crystal Wood <crwood@redhat.com> - 3.8-5
|
||||||
- Prevent using cyclictest and timerlat and the same time
|
- Prevent using cyclictest and timerlat and the same time
|
||||||
- Add a --noload option
|
- Add a --noload option
|
||||||
|
Loading…
Reference in New Issue
Block a user