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
|
||||
Version: 3.8
|
||||
Release: 5%{?dist}
|
||||
Release: 6%{?dist}
|
||||
Summary: Utility to evaluate system suitability for RT Linux
|
||||
|
||||
Group: Development/Tools
|
||||
@ -46,6 +46,8 @@ Patch10: rteval-Enforce-only-one-latency-measurement-module-a.patch
|
||||
Patch11: rteval-Add-noload-option.patch
|
||||
Patch12: rteval-Fix-default-measurement-config.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
|
||||
The rteval script is a utility for measuring various aspects of
|
||||
@ -79,6 +81,13 @@ to the screen.
|
||||
%{_bindir}/rteval
|
||||
|
||||
%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
|
||||
- Prevent using cyclictest and timerlat and the same time
|
||||
- Add a --noload option
|
||||
|
Loading…
Reference in New Issue
Block a user