Rebase rteval to upstream rteval-3.8

Resolves: RHEL-30165
Signed-off-by: John Kacur <jkacur@redhat.com>
This commit is contained in:
John Kacur 2024-05-07 14:19:11 -04:00
parent 3db03791e8
commit 26ed496843
24 changed files with 8 additions and 3561 deletions

1
.gitignore vendored
View File

@ -6,3 +6,4 @@
/rteval-3.7.tar.xz /rteval-3.7.tar.xz
/0001-rteval-Change-the-default-kernel-for-kcompile-to-lin.patch /0001-rteval-Change-the-default-kernel-for-kcompile-to-lin.patch
/0002-rteval-Remove-upstream-spec-file.patch /0002-rteval-Remove-upstream-spec-file.patch
/rteval-3.8.tar.xz

View File

@ -1,70 +0,0 @@
From 636701e66cb98b979948b7a47320809c734e2a9e Mon Sep 17 00:00:00 2001
From: Tomas Glozar <tglozar@redhat.com>
Date: Thu, 4 Apr 2024 10:14:38 +0200
Subject: [PATCH] rteval: Add relative cpulists for loads
Relative cpulists were added for measurements in 64ce7848 ("rteval: Add
relative cpulists for measurements"). It was observed since that this
feature would also be useful for load cpulists, for example when the
measurements are performed externally and rteval is only used to run
loads.
Add support for relative cpulists also for loads. This works the same
way as for measurements using parse_cpulist_from_config, only difference
is there is no --loads-run-on-isolcpus option. That is, --loads-cpulist
now also takes lists with addition (+) and removal (-) of CPUs against
the default list, e.g. +0,1,-7,8.
Signed-off-by: Tomas Glozar <tglozar@redhat.com>
Signed-off-by: John Kacur <jkacur@redhat.com>
---
rteval-cmd | 17 ++++++++++-------
1 file changed, 10 insertions(+), 7 deletions(-)
diff --git a/rteval-cmd b/rteval-cmd
index ed13af3..c72bc61 100755
--- a/rteval-cmd
+++ b/rteval-cmd
@@ -331,29 +331,32 @@ if __name__ == '__main__':
ldcfg = config.GetSection('loads')
msrcfg = config.GetSection('measurement')
+ # Remember if cpulists were explicitly set by the user before running
+ # parse_cpulist_from_config, which generates default value for them
msrcfg_cpulist_present = msrcfg.cpulist != ""
- # Parse measurement cpulist using parse_cpulist_from_config to account for run-on-isolcpus
- # and relative cpusets
+ ldcfg_cpulist_present = ldcfg.cpulist != ""
+ # Parse cpulists using parse_cpulist_from_config to account for
+ # run-on-isolcpus and relative cpusets
cpulist = parse_cpulist_from_config(msrcfg.cpulist, msrcfg.run_on_isolcpus)
if msrcfg_cpulist_present and not cpulist_utils.is_relative(msrcfg.cpulist) and msrcfg.run_on_isolcpus:
logger.log(Log.WARN, "ignoring --measurement-run-on-isolcpus, since cpulist is specified")
msrcfg.cpulist = collapse_cpulist(cpulist)
- if ldcfg.cpulist:
- ldcfg.cpulist = remove_offline(ldcfg.cpulist)
+ cpulist = parse_cpulist_from_config(ldcfg.cpulist)
+ ldcfg.cpulist = collapse_cpulist(cpulist)
# if we only specified one set of cpus (loads or measurement)
# default the other to the inverse of the specified list
- if not ldcfg.cpulist and msrcfg_cpulist_present:
+ if not ldcfg_cpulist_present and msrcfg_cpulist_present:
tmplist = expand_cpulist(msrcfg.cpulist)
tmplist = SysTopology().invert_cpulist(tmplist)
tmplist = cpulist_utils.online_cpulist(tmplist)
ldcfg.cpulist = collapse_cpulist(tmplist)
- if not msrcfg_cpulist_present and ldcfg.cpulist:
+ if not msrcfg_cpulist_present and ldcfg_cpulist_present:
tmplist = expand_cpulist(ldcfg.cpulist)
tmplist = SysTopology().invert_cpulist(tmplist)
tmplist = cpulist_utils.online_cpulist(tmplist)
msrcfg.cpulist = collapse_cpulist(tmplist)
- if ldcfg.cpulist:
+ if ldcfg_cpulist_present:
logger.log(Log.DEBUG, f"loads cpulist: {ldcfg.cpulist}")
# if --onlyload is specified msrcfg.cpulist is unused
if msrcfg_cpulist_present and not rtevcfg.onlyload:
--
2.44.0

View File

@ -1,278 +0,0 @@
From 64ce7848dfabd2056d35c8a60f3354db45e36286 Mon Sep 17 00:00:00 2001
From: Tomas Glozar <tglozar@redhat.com>
Date: Thu, 18 Jan 2024 10:18:10 +0100
Subject: [PATCH 2/4] rteval: Add relative cpulists for measurements
Instead of specifying an absolute list of CPUs to run measurements on
in --measurement-cpulist, implement an option to specify a relative list
with respect to the current cpuset of rteval.
The relative cpulist can include CPUs both for addition and for removal,
e.g. +0,1,-7,8.
Also move the logic for processing cpulists specified by the user as
a string into cpulists usable by rteval to a single function.
Signed-off-by: Tomas Glozar <tglozar@redhat.com>
Signed-off-by: John Kacur <jkacur@redhat.com>
---
rteval-cmd | 26 +++++++-----
rteval/cpulist_utils.py | 33 ++++++++++++++++
rteval/modules/measurement/__init__.py | 9 +----
rteval/modules/measurement/cyclictest.py | 50 +++---------------------
rteval/systopology.py | 33 ++++++++++++++++
5 files changed, 90 insertions(+), 61 deletions(-)
diff --git a/rteval-cmd b/rteval-cmd
index d224728..a5e8746 100755
--- a/rteval-cmd
+++ b/rteval-cmd
@@ -30,7 +30,7 @@ from rteval import RtEval, rtevalConfig
from rteval.modules.loads import LoadModules
from rteval.modules.measurement import MeasurementModules
from rteval.version import RTEVAL_VERSION
-from rteval.systopology import SysTopology
+from rteval.systopology import SysTopology, parse_cpulist_from_config
from rteval.modules.loads.kcompile import ModuleParameters
import rteval.cpulist_utils as cpulist_utils
@@ -339,26 +339,32 @@ if __name__ == '__main__':
ldcfg = config.GetSection('loads')
msrcfg = config.GetSection('measurement')
- if ldcfg.cpulist and msrcfg.cpulist:
+ msrcfg_cpulist_present = msrcfg.cpulist != ""
+ # Parse measurement cpulist using parse_cpulist_from_config to account for run-on-isolcpus
+ # and relative cpusets
+ cpulist = parse_cpulist_from_config(msrcfg.cpulist, msrcfg.run_on_isolcpus)
+ if msrcfg_cpulist_present and not cpulist_utils.is_relative(msrcfg.cpulist) and msrcfg.run_on_isolcpus:
+ logger.log(Log.WARN, "ignoring --measurement-run-on-isolcpus, since cpulist is specified")
+ msrcfg.cpulist = collapse_cpulist(cpulist)
+ if ldcfg.cpulist:
ldcfg.cpulist = remove_offline(ldcfg.cpulist)
- msrcfg.cpulist = remove_offline(msrcfg.cpulist)
# if we only specified one set of cpus (loads or measurement)
# default the other to the inverse of the specified list
- if not ldcfg.cpulist and msrcfg.cpulist:
+ if not ldcfg.cpulist and msrcfg_cpulist_present:
tmplist = expand_cpulist(msrcfg.cpulist)
tmplist = SysTopology().invert_cpulist(tmplist)
- ldcfg.cpulist = compress_cpulist(tmplist)
- msrcfg.cpulist = remove_offline(msrcfg.cpulist)
- if not msrcfg.cpulist and ldcfg.cpulist:
+ tmplist = cpulist_utils.online_cpulist(tmplist)
+ ldcfg.cpulist = collapse_cpulist(tmplist)
+ if not msrcfg_cpulist_present and ldcfg.cpulist:
tmplist = expand_cpulist(ldcfg.cpulist)
tmplist = SysTopology().invert_cpulist(tmplist)
- msrcfg.cpulist = compress_cpulist(tmplist)
- ldcfg.cpulist = remove_offline(ldcfg.cpulist)
+ tmplist = cpulist_utils.online_cpulist(tmplist)
+ msrcfg.cpulist = collapse_cpulist(tmplist)
if ldcfg.cpulist:
logger.log(Log.DEBUG, f"loads cpulist: {ldcfg.cpulist}")
# if --onlyload is specified msrcfg.cpulist is unused
- if msrcfg.cpulist and not rtevcfg.onlyload:
+ if msrcfg_cpulist_present and not rtevcfg.onlyload:
logger.log(Log.DEBUG, f"measurement cpulist: {msrcfg.cpulist}")
logger.log(Log.DEBUG, f"workdir: {rtevcfg.workdir}")
diff --git a/rteval/cpulist_utils.py b/rteval/cpulist_utils.py
index 402d579..7abc45a 100644
--- a/rteval/cpulist_utils.py
+++ b/rteval/cpulist_utils.py
@@ -126,3 +126,36 @@ def nonisolated_cpulist(cpulist):
isolated_cpulist = sysread(cpupath, "isolated")
isolated_cpulist = expand_cpulist(isolated_cpulist)
return list(set(cpulist).difference(set(isolated_cpulist)))
+
+
+def is_relative(cpulist):
+ return cpulist.startswith("+") or cpulist.startswith("-")
+
+
+def expand_relative_cpulist(cpulist):
+ """
+ Expand a relative cpulist into a tuple of lists.
+ :param cpulist: Relative cpulist of form +1,2,3,-4,5,6
+ :return: Tuple of two lists, one for added CPUs, one for removed CPUs
+ """
+ added_cpus = []
+ removed_cpus = []
+
+ if not cpulist:
+ return added_cpus, removed_cpus
+
+ cpus = None
+
+ for part in cpulist.split(','):
+ if part.startswith('+') or part.startswith('-'):
+ cpus = added_cpus if part[0] == '+' else removed_cpus
+ part = part[1:]
+ if '-' in part:
+ a, b = part.split('-')
+ a, b = int(a), int(b)
+ cpus.extend(list(range(a, b + 1)))
+ else:
+ a = int(part)
+ cpus.append(a)
+
+ return list(set(added_cpus)), list(set(removed_cpus))
diff --git a/rteval/modules/measurement/__init__.py b/rteval/modules/measurement/__init__.py
index 66dc9c5..11bd7b0 100644
--- a/rteval/modules/measurement/__init__.py
+++ b/rteval/modules/measurement/__init__.py
@@ -5,7 +5,7 @@
import libxml2
from rteval.modules import RtEvalModules, ModuleContainer
-from rteval.systopology import SysTopology as SysTop
+from rteval.systopology import parse_cpulist_from_config
import rteval.cpulist_utils as cpulist_utils
class MeasurementProfile(RtEvalModules):
@@ -183,12 +183,7 @@ measurement profiles, based on their characteristics"""
rep_n = libxml2.newNode("Measurements")
cpulist = self.__cfg.GetSection("measurement").cpulist
run_on_isolcpus = self.__cfg.GetSection("measurement").run_on_isolcpus
- if cpulist:
- # Convert str to list and remove offline cpus
- cpulist = cpulist_utils.expand_cpulist(cpulist)
- cpulist = cpulist_utils.online_cpulist(cpulist)
- else:
- cpulist = SysTop().online_cpus() if run_on_isolcpus else SysTop().default_cpus()
+ cpulist = parse_cpulist_from_config(cpulist, run_on_isolcpus)
rep_n.newProp("measurecpus", cpulist_utils.collapse_cpulist(cpulist))
for mp in self.__measureprofiles:
diff --git a/rteval/modules/measurement/cyclictest.py b/rteval/modules/measurement/cyclictest.py
index fdca257..7224225 100644
--- a/rteval/modules/measurement/cyclictest.py
+++ b/rteval/modules/measurement/cyclictest.py
@@ -16,8 +16,7 @@ import math
import libxml2
from rteval.Log import Log
from rteval.modules import rtevalModulePrototype
-from rteval.systopology import cpuinfo
-from rteval.systopology import SysTopology
+from rteval.systopology import cpuinfo, parse_cpulist_from_config
import rteval.cpulist_utils as cpulist_utils
expand_cpulist = cpulist_utils.expand_cpulist
@@ -193,39 +192,9 @@ class Cyclictest(rtevalModulePrototype):
self.__priority = int(self.__cfg.setdefault('priority', 95))
self.__buckets = int(self.__cfg.setdefault('buckets', 2000))
self.__numcores = 0
- self.__cpus = []
self.__cyclicdata = {}
- self.__sparse = False
- self.__run_on_isolcpus = bool(self.__cfg.setdefault('run-on-isolcpus', False))
-
- if self.__cfg.cpulist:
- self.__cpulist = self.__cfg.cpulist
- self.__cpus = expand_cpulist(self.__cpulist)
- # Only include online cpus
- self.__cpus = cpulist_utils.online_cpulist(self.__cpus)
- # Reset cpulist from the newly calculated self.__cpus
- self.__cpulist = cpulist_utils.collapse_cpulist(self.__cpus)
- self.__cpus = [str(c) for c in self.__cpus]
- self.__sparse = True
- if self.__run_on_isolcpus:
- self._log(Log.WARN, "ignoring --measurement-run-on-isolcpus, since cpulist is specified")
- else:
- self.__cpus = SysTopology().online_cpus_str()
- # Get the cpuset from the environment
- cpuset = os.sched_getaffinity(0)
- # Convert the elements to strings
- cpuset = [str(c) for c in cpuset]
- # Get isolated CPU list
- isolcpus = [str(c) for c in SysTopology().isolated_cpus()]
- # Only include cpus that are in the cpuset and isolated CPUs if run_on_isolcpus is enabled
- self.__cpus = [c for c in self.__cpus if c in cpuset or self.__run_on_isolcpus and c in isolcpus]
- if self.__run_on_isolcpus:
- self.__sparse = True
- self.__cpulist = cpulist_utils.collapse_cpulist([int(c) for c in self.__cpus])
-
- # Sort the list of cpus to align with the order reported by cyclictest
- self.__cpus.sort(key=int)
-
+ self.__cpulist = self.__cfg.cpulist
+ self.__cpus = [str(c) for c in expand_cpulist(self.__cpulist)]
self.__numcores = len(self.__cpus)
info = cpuinfo()
@@ -242,10 +211,7 @@ class Cyclictest(rtevalModulePrototype):
logfnc=self._log)
self.__cyclicdata['system'].description = (f"({self.__numcores} cores) ") + info['0']['model name']
- if self.__sparse:
- self._log(Log.DEBUG, f"system using {self.__numcores} cpu cores")
- else:
- self._log(Log.DEBUG, f"system has {self.__numcores} cpu cores")
+ self._log(Log.DEBUG, f"system using {self.__numcores} cpu cores")
self.__started = False
self.__cyclicoutput = None
self.__breaktraceval = None
@@ -280,12 +246,8 @@ class Cyclictest(rtevalModulePrototype):
f'-h {self.__buckets}',
f"-p{int(self.__priority)}",
]
- if self.__sparse:
- self.__cmd.append(f'-t{self.__numcores}')
- self.__cmd.append(f'-a{self.__cpulist}')
- else:
- self.__cmd.append('-t')
- self.__cmd.append('-a')
+ self.__cmd.append(f'-t{self.__numcores}')
+ self.__cmd.append(f'-a{self.__cpulist}')
if 'threads' in self.__cfg and self.__cfg.threads:
self.__cmd.append(f"-t{int(self.__cfg.threads)}")
diff --git a/rteval/systopology.py b/rteval/systopology.py
index 9e45762..6bcfc77 100644
--- a/rteval/systopology.py
+++ b/rteval/systopology.py
@@ -241,6 +241,39 @@ class SysTopology:
""" return a list of online cpus in cpulist """
return [c for c in self.online_cpus() if c in cpulist]
+
+def parse_cpulist_from_config(cpulist, run_on_isolcpus=False):
+ """
+ Generates a cpulist based on --*-cpulist argument given by user
+ :param cpulist: Value of --*-cpulist argument
+ :param run_on_isolcpus: Value of --*-run-on-isolcpus argument
+ :return: Sorted list of CPUs as integers
+ """
+ if cpulist and not cpulist_utils.is_relative(cpulist):
+ result = cpulist_utils.expand_cpulist(cpulist)
+ # Only include online cpus
+ result = cpulist_utils.online_cpulist(result)
+ else:
+ result = SysTopology().online_cpus()
+ # Get the cpuset from the environment
+ cpuset = os.sched_getaffinity(0)
+ # Get isolated CPU list
+ isolcpus = SysTopology().isolated_cpus()
+ if cpulist and cpulist_utils.is_relative(cpulist):
+ # Include cpus that are not removed in relative cpuset and are either in cpuset from affinity,
+ # isolcpus (with run_on_isolcpus enabled, or added by relative cpuset
+ added_cpus, removed_cpus = cpulist_utils.expand_relative_cpulist(cpulist)
+ result = [c for c in result
+ if (c in cpuset or
+ c in added_cpus or
+ run_on_isolcpus and c in isolcpus) and
+ c not in removed_cpus]
+ else:
+ # Only include cpus that are in the cpuset and isolated CPUs if run_on_isolcpus is enabled
+ result = [c for c in result if c in cpuset or run_on_isolcpus and c in isolcpus]
+ return result
+
+
if __name__ == "__main__":
def unit_test():
--
2.43.0

View File

@ -1,189 +0,0 @@
From 393c95ee69ec98816a26aa0583f6b1cac4acb5e7 Mon Sep 17 00:00:00 2001
From: John Kacur <jkacur@redhat.com>
Date: Fri, 12 Apr 2024 14:40:37 -0400
Subject: [PATCH 02/13] rteval: Add rtla timerlat as a measurement module
This is the first step to adding timerlat as a measurement module
With this change you can run timerlat as a standalone rteval file like
this (as root)
python rteval/modules/measurement/timerlat.py
You can also modify your rteval.conf to list timerlat in the
[measurement] section, for example like this
[measurement]
cyclictest: module
timerlat: module
and then both measurement moduels will be run from rteval, for example
rteval -D -d5m --measurement-cpulist=1-5
Will run rteval with Debug info, for 5m and cyclictest and timerlat will
run on cpus 1-5 and load modules will run on the other available cpus.
Currently MakeReport just prints to standard out the same information
that timerlat outputs, in otherwords, there is no processing into xml
yet. Also, there is no way to invoke tracing at the time, but that will
be added soon!
Signed-off-by: John Kacur <jkacur@redhat.com>
---
rteval-cmd | 1 +
rteval/modules/measurement/timerlat.py | 131 +++++++++++++++++++++++++
2 files changed, 132 insertions(+)
create mode 100644 rteval/modules/measurement/timerlat.py
diff --git a/rteval-cmd b/rteval-cmd
index c72bc614ad78..5cb6d7a44523 100755
--- a/rteval-cmd
+++ b/rteval-cmd
@@ -247,6 +247,7 @@ if __name__ == '__main__':
if not config.HasSection('measurement'):
config.AppendConfig('measurement', {
'cyclictest' : 'module',
+ 'timerlat' : 'module',
'sysstat' : 'module'})
# Prepare log levels before loading modules, not to have unwanted log messages
diff --git a/rteval/modules/measurement/timerlat.py b/rteval/modules/measurement/timerlat.py
new file mode 100644
index 000000000000..d4e78de8d2a2
--- /dev/null
+++ b/rteval/modules/measurement/timerlat.py
@@ -0,0 +1,131 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright 2024 John Kacur <jkacur@redhat.com>
+#
+""" timerlat.py - objectd to manage rtla timerlat """
+import os
+import subprocess
+import signal
+import time
+import tempfile
+import libxml2
+from rteval.Log import Log
+from rteval.modules import rtevalModulePrototype
+from rteval.systopology import cpuinfo, SysTopology
+from rteval.cpulist_utils import expand_cpulist, collapse_cpulist
+
+class Timerlat(rtevalModulePrototype):
+ """ measurement modules for rteval """
+ def __init__(self, config, logger=None):
+ rtevalModulePrototype.__init__(self, 'measurement', 'timerlat', logger)
+
+ self.__cfg = config
+
+ self.__numanodes = int(self.__cfg.setdefault('numanodes', 0))
+ self.__priority = int(self.__cfg.setdefault('priority', 95))
+
+ self.__cpulist = self.__cfg.setdefault('cpulist', "")
+ self.__cpus = [str(c) for c in expand_cpulist(self.__cpulist)]
+ self.__numcores = len(self.__cpus)
+
+ self.__timerlat_out = None
+ self.__timerlat_err = None
+ self.__started = False
+ self._log(Log.DEBUG, f"system using {self.__numcores} cpu cores")
+
+
+ def _WorkloadSetup(self):
+ self.__timerlat_process = None
+
+ def _WorkloadBuild(self):
+ self._setReady()
+
+ def _WorkloadPrepare(self):
+ self.__cmd = ['rtla', 'timerlat', 'hist', '-P', f'f:{int(self.__priority)}', '-u']
+ self.__cmd.append(f'-c{self.__cpulist}')
+ self._log(Log.DEBUG, f'self.__cmd = {self.__cmd}')
+ self.__timerlat_out = tempfile.SpooledTemporaryFile(mode='w+b')
+ self.__timerlat_err = tempfile.SpooledTemporaryFile(mode='w+b')
+
+ def _WorkloadTask(self):
+ if self.__started:
+ return
+
+ self._log(Log.DEBUG, f'starting with cmd: {" ".join(self.__cmd)}')
+
+ self.__timerlat_out.seek(0)
+ self.__timerlat_err.seek(0)
+ try:
+ self.__timerlat_process = subprocess.Popen(self.__cmd,
+ stdout=self.__timerlat_out,
+ stderr=self.__timerlat_err,
+ stdin=None)
+ self.__started = True
+ except OSError:
+ self.__started = False
+
+ def WorkloadAlive(self):
+ if self.__started:
+ return self.__timerlat_process.poll() is None
+ return False
+
+ def _WorkloadCleanup(self):
+ if not self.__started:
+ return
+ while self.__timerlat_process.poll() is None:
+ self._log(Log.DEBUG, "Sending SIGINT")
+ os.kill(self.__timerlat_process.pid, signal.SIGINT)
+ time.sleep(2)
+
+ self._setFinished()
+ self.__started = False
+
+ def MakeReport(self):
+ self.__timerlat_out.seek(0)
+ for line in self.__timerlat_out:
+ line = bytes.decode(line)
+ print(line)
+ self.__timerlat_out.close()
+
+
+def ModuleInfo():
+ """ Required measurement module information """
+ return {"parallel": True,
+ "loads": True}
+
+def ModuleParameters():
+ """ default parameters """
+ return {"priority": {"descr": "Run rtla timerlat with this priority",
+ "default": 95,
+ "metavar": "PRIO" }
+ }
+
+def create(params, logger):
+ """ Instantiate a Timerlat measurement module object"""
+ return Timerlat(params, logger)
+
+if __name__ == '__main__':
+ from rteval.rtevalConfig import rtevalConfig
+
+ l = Log()
+ l.SetLogVerbosity(Log.INFO|Log.DEBUG|Log.ERR|Log.WARN)
+
+ cfg = rtevalConfig({}, logger=l)
+ prms = {}
+ modprms = ModuleParameters()
+ for c, p in list(modprms.items()):
+ prms[c] = p['default']
+ cfg.AppendConfig('timerlat', prms)
+
+ cfg_tl = cfg.GetSection('timerlat')
+ cfg_tl.cpulist = collapse_cpulist(SysTopology().online_cpus())
+
+ RUNTIME = 10
+
+ tl = Timerlat(cfg_tl, l)
+ tl._WorkloadSetup()
+ tl._WorkloadPrepare()
+ tl._WorkloadTask()
+ time.sleep(RUNTIME)
+ tl._WorkloadCleanup()
+ tl.MakeReport()
--
2.44.0

View File

@ -1,178 +0,0 @@
From 20fbcc1547d77a77a3e333bac28b7f28632d8707 Mon Sep 17 00:00:00 2001
From: John Kacur <jkacur@redhat.com>
Date: Fri, 26 Apr 2024 14:45:48 -0400
Subject: [PATCH 08/13] rteval: Add summary reporting for timerlat
This adds an rteval section to the xsl file and generates a timerlat
report at the end of a run. To use it edit your rteval.conf file
to comment out cyclictest and uncomment timerlat
Another interesting thing you can do is uncomment both of them and
get a report from both in one run.
You can also use this with the summary report, for example
rteval -Z rteval-20240426-3/summary.xml
will work with timerlat now. (or both cyclictest and timerlat at the
same time.)
Signed-off-by: John Kacur <jkacur@redhat.com>
---
rteval.conf | 1 +
rteval/rteval_text.xsl | 103 +++++++++++++++++++++++++++++++++++++++--
2 files changed, 100 insertions(+), 4 deletions(-)
diff --git a/rteval.conf b/rteval.conf
index 4c32fcf4d842..601410b51c28 100644
--- a/rteval.conf
+++ b/rteval.conf
@@ -7,6 +7,7 @@ report_interval: 600
[measurement]
cyclictest: module
+# timerlat: module
[loads]
kcompile: module
diff --git a/rteval/rteval_text.xsl b/rteval/rteval_text.xsl
index f526526d4d49..1e9c0f0d26c5 100644
--- a/rteval/rteval_text.xsl
+++ b/rteval/rteval_text.xsl
@@ -201,11 +201,11 @@
<!-- -->
<!-- select="cyclictest|new_foo_section|another_section" -->
<!-- -->
- <xsl:apply-templates select="cyclictest|hwlatdetect[@format='1.0']|sysstat"/>
+ <xsl:apply-templates select="cyclictest|timerlat|hwlatdetect[@format='1.0']|sysstat"/>
<xsl:text>&#10;</xsl:text>
</xsl:template>
- <!-- Format the cyclic test section of the report -->
+ <!-- Format the cyclictest section of the report -->
<xsl:template match="/rteval/Measurements/Profile/cyclictest">
<xsl:text> Latency test&#10;</xsl:text>
@@ -237,7 +237,7 @@
</xsl:template>
- <!-- Format the CPU core section in the cyclict test part -->
+ <!-- Format the CPU core section in the cyclictest part -->
<xsl:template match="/rteval/Measurements/Profile/cyclictest/core">
<xsl:text> CPU core </xsl:text>
<xsl:value-of select="@id"/>
@@ -300,6 +300,101 @@
<xsl:text>&#10;</xsl:text>
</xsl:template>
+ <!-- Format the timerlat section of the report -->
+ <xsl:template match="/rteval/Measurements/Profile/timerlat">
+ <xsl:text> Latency test&#10;</xsl:text>
+
+ <xsl:text> Started: </xsl:text>
+ <xsl:value-of select="timestamps/runloop_start"/>
+ <xsl:text>&#10;</xsl:text>
+
+ <xsl:text> Stopped: </xsl:text>
+ <xsl:value-of select="timestamps/runloop_stop"/>
+ <xsl:text>&#10;</xsl:text>
+
+ <xsl:text> Command: </xsl:text>
+ <xsl:value-of select="@command_line"/>
+ <xsl:text>&#10;&#10;</xsl:text>
+
+ <xsl:apply-templates select="abort_report"/>
+
+ <xsl:text> System: </xsl:text>
+ <xsl:value-of select="system/@description"/>
+ <xsl:text>&#10;</xsl:text>
+
+ <xsl:text> Statistics: &#10;</xsl:text>
+ <xsl:apply-templates select="system/statistics"/>
+
+ <!-- Add CPU core info and stats-->
+ <xsl:apply-templates select="core">
+ <xsl:sort select="@id" data-type="number"/>
+ </xsl:apply-templates>
+ </xsl:template>
+
+
+ <!-- Format the CPU core section in the timerlat part -->
+ <xsl:template match="/rteval/Measurements/Profile/timerlat/core">
+ <xsl:text> CPU core </xsl:text>
+ <xsl:value-of select="@id"/>
+ <xsl:text> Priority: </xsl:text>
+ <xsl:value-of select="@priority"/>
+ <xsl:text>&#10;</xsl:text>
+ <xsl:text> Statistics: </xsl:text>
+ <xsl:text>&#10;</xsl:text>
+ <xsl:apply-templates select="statistics"/>
+ </xsl:template>
+
+
+ <!-- Generic formatting of statistics information -->
+ <xsl:template match="/rteval/Measurements/Profile/timerlat/*/statistics">
+ <xsl:text> Samples: </xsl:text>
+ <xsl:value-of select="samples"/>
+ <xsl:text>&#10;</xsl:text>
+
+ <xsl:if test="samples > 0">
+ <xsl:text> Mean: </xsl:text>
+ <xsl:value-of select="mean"/>
+ <xsl:value-of select="mean/@unit"/>
+ <xsl:text>&#10;</xsl:text>
+
+ <xsl:text> Median: </xsl:text>
+ <xsl:value-of select="median"/>
+ <xsl:value-of select="median/@unit"/>
+ <xsl:text>&#10;</xsl:text>
+
+ <xsl:text> Mode: </xsl:text>
+ <xsl:value-of select="mode"/>
+ <xsl:value-of select="mode/@unit"/>
+ <xsl:text>&#10;</xsl:text>
+
+ <xsl:text> Range: </xsl:text>
+ <xsl:value-of select="range"/>
+ <xsl:value-of select="range/@unit"/>
+ <xsl:text>&#10;</xsl:text>
+
+ <xsl:text> Min: </xsl:text>
+ <xsl:value-of select="minimum"/>
+ <xsl:value-of select="minimum/@unit"/>
+ <xsl:text>&#10;</xsl:text>
+
+ <xsl:text> Max: </xsl:text>
+ <xsl:value-of select="maximum"/>
+ <xsl:value-of select="maximum/@unit"/>
+ <xsl:text>&#10;</xsl:text>
+
+ <xsl:text> Mean Absolute Dev: </xsl:text>
+ <xsl:value-of select="mean_absolute_deviation"/>
+ <xsl:value-of select="mean_absolute_deviation/@unit"/>
+ <xsl:text>&#10;</xsl:text>
+
+ <xsl:text> Std.dev: </xsl:text>
+ <xsl:value-of select="standard_deviation"/>
+ <xsl:value-of select="standard_deviation/@unit"/>
+ <xsl:text>&#10;</xsl:text>
+ </xsl:if>
+ <xsl:text>&#10;</xsl:text>
+ </xsl:template>
+
<!-- Format the hwlatdetect test section of the report -->
<xsl:template match="/rteval/Measurements/Profile/hwlatdetect[@format='1.0' and not(@aborted)]">
@@ -340,7 +435,7 @@
<xsl:text>us&#10;</xsl:text>
</xsl:template>
- <!-- Format the cyclic test section of the report -->
+ <!-- Format the cyclictest section of the report -->
<xsl:template match="/rteval/Measurements/Profile/sysstat">
<xsl:text> sysstat measurements&#10;</xsl:text>
--
2.44.0

View File

@ -1,65 +0,0 @@
From c0ee73f00f6868e0ead5ace958a88a6a23db6ad3 Mon Sep 17 00:00:00 2001
From: John Kacur <jkacur@redhat.com>
Date: Thu, 9 Nov 2023 15:43:53 -0500
Subject: [PATCH] rteval: Change the default kernel for kcompile to linux-6.6.1
Change the default kernel for kcompile to linux-6.6.1
Signed-off-by: John Kacur <jkacur@redhat.com>
---
Makefile | 2 +-
rteval/modules/loads/kcompile.py | 4 ++--
rteval/rteval.conf | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/Makefile b/Makefile
index b73e8c13f3e5..14f74e087eff 100644
--- a/Makefile
+++ b/Makefile
@@ -18,7 +18,7 @@ PREFIX := /usr
DATADIR := $(DESTDIR)/$(PREFIX)/share
LOADDIR := loadsource
-KLOAD := $(LOADDIR)/linux-6.1.8.tar.xz
+KLOAD := $(LOADDIR)/linux-6.6.1.tar.xz
BLOAD := $(LOADDIR)/dbench-4.0.tar.gz
LOADS := $(KLOAD) $(BLOAD)
diff --git a/rteval/modules/loads/kcompile.py b/rteval/modules/loads/kcompile.py
index 8be79ce630d5..0d025771e90e 100644
--- a/rteval/modules/loads/kcompile.py
+++ b/rteval/modules/loads/kcompile.py
@@ -20,7 +20,7 @@ expand_cpulist = CpuList.expand_cpulist
compress_cpulist = CpuList.compress_cpulist
nonisolated_cpulist = CpuList.nonisolated_cpulist
-DEFAULT_KERNEL_PREFIX = "linux-6.1"
+DEFAULT_KERNEL_PREFIX = "linux-6.6"
class KBuildJob:
'''Class to manage a build job bound to a particular node'''
@@ -334,7 +334,7 @@ class Kcompile(CommandLineLoad):
def ModuleParameters():
return {"source": {"descr": "Source tar ball",
- "default": "linux-6.1.8.tar.xz",
+ "default": "linux-6.6.1.tar.xz",
"metavar": "TARBALL"},
"jobspercore": {"descr": "Number of working threads per core",
"default": 2,
diff --git a/rteval/rteval.conf b/rteval/rteval.conf
index 79e28032dc6b..a4aad33e264f 100644
--- a/rteval/rteval.conf
+++ b/rteval/rteval.conf
@@ -18,7 +18,7 @@ dbench: external
stressng: module
[kcompile]
-source: linux-6.1.8.xz
+source: linux-6.6.1.xz
jobspercore: 2
[hackbench]
--
2.41.0

View File

@ -1,616 +0,0 @@
From a788ea3ec976e51309f0bfae1a41cce704a77f2d Mon Sep 17 00:00:00 2001
From: Tomas Glozar <tglozar@redhat.com>
Date: Thu, 18 Jan 2024 10:18:09 +0100
Subject: [PATCH 1/4] rteval: Convert CpuList class to a module
Move out code from CpuList class in rteval.systopology into a separate
module named rteval.cpulist_utils and avoid wrapping CPU lists in
a CpuList object.
Almost all uses of CpuList in the code either use the static methods of
the class or its constructor to filter online CPUs by running
CpuList(...).cpulist. The only exception to this are NumaNode and
SimNumaNode classes in systopology; these store a CpuList object,
however their .getcpulist() method extracts the list out. Thus,
the class is completely unnecessary.
Note: A better name for the module would be cpulist, consistent with the
original name of the class, but this name is already used for variables
throughout the code, hence cpulist_utils is used instead.
Signed-off-by: Tomas Glozar <tglozar@redhat.com>
Signed-off-by: John Kacur <jkacur@redhat.com>
---
rteval-cmd | 10 +-
rteval/cpulist_utils.py | 128 ++++++++++++++++++
rteval/modules/loads/__init__.py | 8 +-
rteval/modules/loads/hackbench.py | 9 +-
rteval/modules/loads/kcompile.py | 11 +-
rteval/modules/loads/stressng.py | 8 +-
rteval/modules/measurement/__init__.py | 8 +-
rteval/modules/measurement/cyclictest.py | 11 +-
rteval/systopology.py | 165 ++---------------------
9 files changed, 177 insertions(+), 181 deletions(-)
create mode 100644 rteval/cpulist_utils.py
diff --git a/rteval-cmd b/rteval-cmd
index 7c41429..d224728 100755
--- a/rteval-cmd
+++ b/rteval-cmd
@@ -30,11 +30,13 @@ from rteval import RtEval, rtevalConfig
from rteval.modules.loads import LoadModules
from rteval.modules.measurement import MeasurementModules
from rteval.version import RTEVAL_VERSION
-from rteval.systopology import CpuList, SysTopology
+from rteval.systopology import SysTopology
from rteval.modules.loads.kcompile import ModuleParameters
+import rteval.cpulist_utils as cpulist_utils
-compress_cpulist = CpuList.compress_cpulist
-expand_cpulist = CpuList.expand_cpulist
+compress_cpulist = cpulist_utils.compress_cpulist
+expand_cpulist = cpulist_utils.expand_cpulist
+collapse_cpulist = cpulist_utils.collapse_cpulist
def summarize(repfile, xslt):
""" Summarize an already existing XML report """
@@ -211,7 +213,7 @@ def remove_offline(cpulist):
""" return cpulist in collapsed compressed form with only online cpus """
tmplist = expand_cpulist(cpulist)
tmplist = SysTopology().online_cpulist(tmplist)
- return CpuList.collapse_cpulist(tmplist)
+ return collapse_cpulist(tmplist)
if __name__ == '__main__':
diff --git a/rteval/cpulist_utils.py b/rteval/cpulist_utils.py
new file mode 100644
index 0000000..402d579
--- /dev/null
+++ b/rteval/cpulist_utils.py
@@ -0,0 +1,128 @@
+# -*- coding: utf-8 -*-
+# SPDX-License-Identifier: GPL-2.0-or-later
+#
+# Copyright 2016 - Clark Williams <williams@redhat.com>
+# Copyright 2021 - John Kacur <jkacur@redhat.com>
+# Copyright 2023 - Tomas Glozar <tglozar@redhat.com>
+#
+"""Module providing utility functions for working with CPU lists"""
+
+import os
+
+
+cpupath = "/sys/devices/system/cpu"
+
+
+def sysread(path, obj):
+ """ Helper function for reading system files """
+ with open(os.path.join(path, obj), "r") as fp:
+ return fp.readline().strip()
+
+
+def _online_file_exists():
+ """ Check whether machine / kernel is configured with online file """
+ # Note: some machines do not have cpu0/online so we check cpu1/online.
+ # In the case of machines with a single CPU, there is no cpu1, but
+ # that is not a problem, since a single CPU cannot be offline
+ return os.path.exists(os.path.join(cpupath, "cpu1/online"))
+
+
+def _isolated_file_exists():
+ """ Check whether machine / kernel is configured with isolated file """
+ return os.path.exists(os.path.join(cpupath, "isolated"))
+
+
+def collapse_cpulist(cpulist):
+ """
+ Collapse a list of cpu numbers into a string range
+ of cpus (e.g. 0-5, 7, 9)
+ """
+ cur_range = [None, None]
+ result = []
+ for cpu in cpulist + [None]:
+ if cur_range[0] is None:
+ cur_range[0] = cur_range[1] = cpu
+ continue
+ if cpu is not None and cpu == cur_range[1] + 1:
+ # Extend currently processed range
+ cur_range[1] += 1
+ else:
+ # Range processing finished, add range to string
+ result.append(f"{cur_range[0]}-{cur_range[1]}"
+ if cur_range[0] != cur_range[1]
+ else str(cur_range[0]))
+ # Reset
+ cur_range[0] = cur_range[1] = cpu
+ return ",".join(result)
+
+
+def compress_cpulist(cpulist):
+ """ return a string representation of cpulist """
+ if not cpulist:
+ return ""
+ if isinstance(cpulist[0], int):
+ return ",".join(str(e) for e in cpulist)
+ return ",".join(cpulist)
+
+
+def expand_cpulist(cpulist):
+ """ expand a range string into an array of cpu numbers
+ don't error check against online cpus
+ """
+ result = []
+
+ if not cpulist:
+ return result
+
+ for part in cpulist.split(','):
+ if '-' in part:
+ a, b = part.split('-')
+ a, b = int(a), int(b)
+ result.extend(list(range(a, b + 1)))
+ else:
+ a = int(part)
+ result.append(a)
+ return [int(i) for i in list(set(result))]
+
+
+def is_online(n):
+ """ check whether cpu n is online """
+ path = os.path.join(cpupath, f'cpu{n}')
+
+ # Some hardware doesn't allow cpu0 to be turned off
+ if not os.path.exists(path + '/online') and n == 0:
+ return True
+
+ return sysread(path, "online") == "1"
+
+
+def online_cpulist(cpulist):
+ """ Given a cpulist, return a cpulist of online cpus """
+ # This only works if the sys online files exist
+ if not _online_file_exists():
+ return cpulist
+ newlist = []
+ for cpu in cpulist:
+ if not _online_file_exists() and cpu == '0':
+ newlist.append(cpu)
+ elif is_online(int(cpu)):
+ newlist.append(cpu)
+ return newlist
+
+
+def isolated_cpulist(cpulist):
+ """Given a cpulist, return a cpulist of isolated CPUs"""
+ if not _isolated_file_exists():
+ return cpulist
+ isolated_cpulist = sysread(cpupath, "isolated")
+ isolated_cpulist = expand_cpulist(isolated_cpulist)
+ return list(set(isolated_cpulist) & set(cpulist))
+
+
+def nonisolated_cpulist(cpulist):
+ """Given a cpulist, return a cpulist of non-isolated CPUs"""
+ if not _isolated_file_exists():
+ return cpulist
+ isolated_cpulist = sysread(cpupath, "isolated")
+ isolated_cpulist = expand_cpulist(isolated_cpulist)
+ return list(set(cpulist).difference(set(isolated_cpulist)))
diff --git a/rteval/modules/loads/__init__.py b/rteval/modules/loads/__init__.py
index 13fba1e..0845742 100644
--- a/rteval/modules/loads/__init__.py
+++ b/rteval/modules/loads/__init__.py
@@ -11,7 +11,8 @@ import libxml2
from rteval.Log import Log
from rteval.rtevalConfig import rtevalCfgSection
from rteval.modules import RtEvalModules, rtevalModulePrototype
-from rteval.systopology import CpuList, SysTopology as SysTop
+from rteval.systopology import SysTopology as SysTop
+import rteval.cpulist_utils as cpulist_utils
class LoadThread(rtevalModulePrototype):
def __init__(self, name, config, logger=None):
@@ -117,10 +118,11 @@ class LoadModules(RtEvalModules):
cpulist = self._cfg.GetSection(self._module_config).cpulist
if cpulist:
# Convert str to list and remove offline cpus
- cpulist = CpuList(cpulist).cpulist
+ cpulist = cpulist_utils.expand_cpulist(cpulist)
+ cpulist = cpulist_utils.online_cpulist(cpulist)
else:
cpulist = SysTop().default_cpus()
- rep_n.newProp("loadcpus", CpuList.collapse_cpulist(cpulist))
+ rep_n.newProp("loadcpus", cpulist_utils.collapse_cpulist(cpulist))
return rep_n
diff --git a/rteval/modules/loads/hackbench.py b/rteval/modules/loads/hackbench.py
index cfc7063..a70fdb3 100644
--- a/rteval/modules/loads/hackbench.py
+++ b/rteval/modules/loads/hackbench.py
@@ -16,10 +16,11 @@ import errno
from signal import SIGKILL
from rteval.modules.loads import CommandLineLoad
from rteval.Log import Log
-from rteval.systopology import CpuList, SysTopology
+from rteval.systopology import SysTopology
+import rteval.cpulist_utils as cpulist_utils
-expand_cpulist = CpuList.expand_cpulist
-isolated_cpulist = CpuList.isolated_cpulist
+expand_cpulist = cpulist_utils.expand_cpulist
+isolated_cpulist = cpulist_utils.isolated_cpulist
class Hackbench(CommandLineLoad):
def __init__(self, config, logger):
@@ -61,7 +62,7 @@ class Hackbench(CommandLineLoad):
self.cpus[n] = [c for c in self.cpus[n] if c in expand_cpulist(self.cpulist)]
# if a cpulist was not specified, exclude isolated cpus
else:
- self.cpus[n] = CpuList.nonisolated_cpulist(self.cpus[n])
+ self.cpus[n] = cpulist_utils.nonisolated_cpulist(self.cpus[n])
# track largest number of cpus used on a node
node_biggest = len(self.cpus[n])
diff --git a/rteval/modules/loads/kcompile.py b/rteval/modules/loads/kcompile.py
index 0d02577..b606f7a 100644
--- a/rteval/modules/loads/kcompile.py
+++ b/rteval/modules/loads/kcompile.py
@@ -14,11 +14,12 @@ import subprocess
from rteval.modules import rtevalRuntimeError
from rteval.modules.loads import CommandLineLoad
from rteval.Log import Log
-from rteval.systopology import CpuList, SysTopology
+from rteval.systopology import SysTopology
+import rteval.cpulist_utils as cpulist_utils
-expand_cpulist = CpuList.expand_cpulist
-compress_cpulist = CpuList.compress_cpulist
-nonisolated_cpulist = CpuList.nonisolated_cpulist
+expand_cpulist = cpulist_utils.expand_cpulist
+compress_cpulist = cpulist_utils.compress_cpulist
+nonisolated_cpulist = cpulist_utils.nonisolated_cpulist
DEFAULT_KERNEL_PREFIX = "linux-6.6"
@@ -38,7 +39,7 @@ class KBuildJob:
os.mkdir(self.objdir)
# Exclude isolated CPUs if cpulist not set
- cpus_available = len(nonisolated_cpulist(self.node.cpus.cpulist))
+ cpus_available = len(nonisolated_cpulist(self.node.cpus))
if os.path.exists('/usr/bin/numactl') and not cpulist:
# Use numactl
diff --git a/rteval/modules/loads/stressng.py b/rteval/modules/loads/stressng.py
index 7c9e63f..cbcf6b7 100644
--- a/rteval/modules/loads/stressng.py
+++ b/rteval/modules/loads/stressng.py
@@ -7,10 +7,10 @@ import subprocess
import signal
from rteval.modules.loads import CommandLineLoad
from rteval.Log import Log
-from rteval.systopology import CpuList, SysTopology
+from rteval.systopology import SysTopology
+import rteval.cpulist_utils as cpulist_utils
-expand_cpulist = CpuList.expand_cpulist
-nonisolated_cpulist = CpuList.nonisolated_cpulist
+expand_cpulist = cpulist_utils.expand_cpulist
class Stressng(CommandLineLoad):
" This class creates a load module that runs stress-ng "
@@ -73,7 +73,7 @@ class Stressng(CommandLineLoad):
cpus[n] = [c for c in cpus[n] if c in expand_cpulist(self.cpulist)]
# if a cpulist was not specified, exclude isolated cpus
else:
- cpus[n] = CpuList.nonisolated_cpulist(cpus[n])
+ cpus[n] = cpulist_utils.nonisolated_cpulist(cpus[n])
# remove nodes with no cpus available for running
diff --git a/rteval/modules/measurement/__init__.py b/rteval/modules/measurement/__init__.py
index 41b8022..66dc9c5 100644
--- a/rteval/modules/measurement/__init__.py
+++ b/rteval/modules/measurement/__init__.py
@@ -5,7 +5,8 @@
import libxml2
from rteval.modules import RtEvalModules, ModuleContainer
-from rteval.systopology import CpuList, SysTopology as SysTop
+from rteval.systopology import SysTopology as SysTop
+import rteval.cpulist_utils as cpulist_utils
class MeasurementProfile(RtEvalModules):
"""Keeps and controls all the measurement modules with the same measurement profile"""
@@ -184,10 +185,11 @@ measurement profiles, based on their characteristics"""
run_on_isolcpus = self.__cfg.GetSection("measurement").run_on_isolcpus
if cpulist:
# Convert str to list and remove offline cpus
- cpulist = CpuList(cpulist).cpulist
+ cpulist = cpulist_utils.expand_cpulist(cpulist)
+ cpulist = cpulist_utils.online_cpulist(cpulist)
else:
cpulist = SysTop().online_cpus() if run_on_isolcpus else SysTop().default_cpus()
- rep_n.newProp("measurecpus", CpuList.collapse_cpulist(cpulist))
+ rep_n.newProp("measurecpus", cpulist_utils.collapse_cpulist(cpulist))
for mp in self.__measureprofiles:
mprep_n = mp.MakeReport()
diff --git a/rteval/modules/measurement/cyclictest.py b/rteval/modules/measurement/cyclictest.py
index 1b14e7e..fdca257 100644
--- a/rteval/modules/measurement/cyclictest.py
+++ b/rteval/modules/measurement/cyclictest.py
@@ -17,9 +17,10 @@ import libxml2
from rteval.Log import Log
from rteval.modules import rtevalModulePrototype
from rteval.systopology import cpuinfo
-from rteval.systopology import CpuList, SysTopology
+from rteval.systopology import SysTopology
+import rteval.cpulist_utils as cpulist_utils
-expand_cpulist = CpuList.expand_cpulist
+expand_cpulist = cpulist_utils.expand_cpulist
class RunData:
'''class to keep instance data from a cyclictest run'''
@@ -201,9 +202,9 @@ class Cyclictest(rtevalModulePrototype):
self.__cpulist = self.__cfg.cpulist
self.__cpus = expand_cpulist(self.__cpulist)
# Only include online cpus
- self.__cpus = CpuList(self.__cpus).cpulist
+ self.__cpus = cpulist_utils.online_cpulist(self.__cpus)
# Reset cpulist from the newly calculated self.__cpus
- self.__cpulist = CpuList.collapse_cpulist(self.__cpus)
+ self.__cpulist = cpulist_utils.collapse_cpulist(self.__cpus)
self.__cpus = [str(c) for c in self.__cpus]
self.__sparse = True
if self.__run_on_isolcpus:
@@ -220,7 +221,7 @@ class Cyclictest(rtevalModulePrototype):
self.__cpus = [c for c in self.__cpus if c in cpuset or self.__run_on_isolcpus and c in isolcpus]
if self.__run_on_isolcpus:
self.__sparse = True
- self.__cpulist = CpuList.collapse_cpulist([int(c) for c in self.__cpus])
+ self.__cpulist = cpulist_utils.collapse_cpulist([int(c) for c in self.__cpus])
# Sort the list of cpus to align with the order reported by cyclictest
self.__cpus.sort(key=int)
diff --git a/rteval/systopology.py b/rteval/systopology.py
index bed5192..9e45762 100644
--- a/rteval/systopology.py
+++ b/rteval/systopology.py
@@ -9,12 +9,8 @@
import os
import os.path
import glob
-
-
-def sysread(path, obj):
- """ Helper function for reading system files """
- with open(os.path.join(path, obj), "r") as fp:
- return fp.readline().strip()
+import rteval.cpulist_utils as cpulist_utils
+from rteval.cpulist_utils import sysread
def cpuinfo():
''' return a dictionary of cpu keys with various cpu information '''
@@ -56,145 +52,6 @@ def cpuinfo():
return info
-#
-# class to provide access to a list of cpus
-#
-
-class CpuList:
- "Object that represents a group of system cpus"
-
- cpupath = '/sys/devices/system/cpu'
-
- def __init__(self, cpulist):
- if isinstance(cpulist, list):
- self.cpulist = cpulist
- elif isinstance(cpulist, str):
- self.cpulist = self.expand_cpulist(cpulist)
- self.cpulist = self.online_cpulist(self.cpulist)
- self.cpulist.sort()
-
- def __str__(self):
- return self.collapse_cpulist(self.cpulist)
-
- def __contains__(self, cpu):
- return cpu in self.cpulist
-
- def __len__(self):
- return len(self.cpulist)
-
- def getcpulist(self):
- """ return the list of cpus tracked """
- return self.cpulist
-
- @staticmethod
- def online_file_exists():
- """ Check whether machine / kernel is configured with online file """
- # Note: some machines do not have cpu0/online so we check cpu1/online.
- # In the case of machines with a single CPU, there is no cpu1, but
- # that is not a problem, since a single CPU cannot be offline
- return os.path.exists(os.path.join(CpuList.cpupath, "cpu1/online"))
-
- @staticmethod
- def isolated_file_exists():
- """ Check whether machine / kernel is configured with isolated file """
- return os.path.exists(os.path.join(CpuList.cpupath, "isolated"))
-
- @staticmethod
- def collapse_cpulist(cpulist):
- """
- Collapse a list of cpu numbers into a string range
- of cpus (e.g. 0-5, 7, 9)
- """
- cur_range = [None, None]
- result = []
- for cpu in cpulist + [None]:
- if cur_range[0] is None:
- cur_range[0] = cur_range[1] = cpu
- continue
- if cpu is not None and cpu == cur_range[1] + 1:
- # Extend currently processed range
- cur_range[1] += 1
- else:
- # Range processing finished, add range to string
- result.append(f"{cur_range[0]}-{cur_range[1]}"
- if cur_range[0] != cur_range[1]
- else str(cur_range[0]))
- # Reset
- cur_range[0] = cur_range[1] = cpu
- return ",".join(result)
-
- @staticmethod
- def compress_cpulist(cpulist):
- """ return a string representation of cpulist """
- if not cpulist:
- return ""
- if isinstance(cpulist[0], int):
- return ",".join(str(e) for e in cpulist)
- return ",".join(cpulist)
-
- @staticmethod
- def expand_cpulist(cpulist):
- """ expand a range string into an array of cpu numbers
- don't error check against online cpus
- """
- result = []
-
- if not cpulist:
- return result
-
- for part in cpulist.split(','):
- if '-' in part:
- a, b = part.split('-')
- a, b = int(a), int(b)
- result.extend(list(range(a, b + 1)))
- else:
- a = int(part)
- result.append(a)
- return [int(i) for i in list(set(result))]
-
- @staticmethod
- def is_online(n):
- """ check whether cpu n is online """
- path = os.path.join(CpuList.cpupath, f'cpu{n}')
-
- # Some hardware doesn't allow cpu0 to be turned off
- if not os.path.exists(path + '/online') and n == 0:
- return True
-
- return sysread(path, "online") == "1"
-
- @staticmethod
- def online_cpulist(cpulist):
- """ Given a cpulist, return a cpulist of online cpus """
- # This only works if the sys online files exist
- if not CpuList.online_file_exists():
- return cpulist
- newlist = []
- for cpu in cpulist:
- if not CpuList.online_file_exists() and cpu == '0':
- newlist.append(cpu)
- elif CpuList.is_online(int(cpu)):
- newlist.append(cpu)
- return newlist
-
- @staticmethod
- def isolated_cpulist(cpulist):
- """Given a cpulist, return a cpulist of isolated CPUs"""
- if not CpuList.isolated_file_exists():
- return cpulist
- isolated_cpulist = sysread(CpuList.cpupath, "isolated")
- isolated_cpulist = CpuList.expand_cpulist(isolated_cpulist)
- return list(set(isolated_cpulist) & set(cpulist))
-
- @staticmethod
- def nonisolated_cpulist(cpulist):
- """Given a cpulist, return a cpulist of non-isolated CPUs"""
- if not CpuList.isolated_file_exists():
- return cpulist
- isolated_cpulist = sysread(CpuList.cpupath, "isolated")
- isolated_cpulist = CpuList.expand_cpulist(isolated_cpulist)
- return list(set(cpulist).difference(set(isolated_cpulist)))
-
#
# class to abstract access to NUMA nodes in /sys filesystem
#
@@ -208,7 +65,8 @@ class NumaNode:
"""
self.path = path
self.nodeid = int(os.path.basename(path)[4:].strip())
- self.cpus = CpuList(sysread(self.path, "cpulist"))
+ self.cpus = cpulist_utils.expand_cpulist(sysread(self.path, "cpulist"))
+ self.cpus = cpulist_utils.online_cpulist(self.cpus)
self.getmeminfo()
def __contains__(self, cpu):
@@ -240,11 +98,11 @@ class NumaNode:
def getcpustr(self):
""" return list of cpus for this node as a string """
- return str(self.cpus)
+ return cpulist_utils.collapse_cpulist(self.cpus)
def getcpulist(self):
""" return list of cpus for this node """
- return self.cpus.getcpulist()
+ return self.cpus
class SimNumaNode(NumaNode):
"""class representing a simulated NUMA node.
@@ -257,7 +115,8 @@ class SimNumaNode(NumaNode):
def __init__(self):
self.nodeid = 0
- self.cpus = CpuList(sysread(SimNumaNode.cpupath, "possible"))
+ self.cpus = cpulist_utils.expand_cpulist(sysread(SimNumaNode.cpupath, "possible"))
+ self.cpus = cpulist_utils.online_cpulist(self.cpus)
self.getmeminfo()
def getmeminfo(self):
@@ -339,7 +198,7 @@ class SysTopology:
""" return a list of integers of all online cpus """
cpulist = []
for n in self.nodes:
- cpulist += self.getcpus(n)
+ cpulist += cpulist_utils.online_cpulist(self.getcpus(n))
cpulist.sort()
return cpulist
@@ -347,7 +206,7 @@ class SysTopology:
""" return a list of integers of all isolated cpus """
cpulist = []
for n in self.nodes:
- cpulist += CpuList.isolated_cpulist(self.getcpus(n))
+ cpulist += cpulist_utils.isolated_cpulist(self.getcpus(n))
cpulist.sort()
return cpulist
@@ -355,7 +214,7 @@ class SysTopology:
""" return a list of integers of all default schedulable cpus, i.e. online non-isolated cpus """
cpulist = []
for n in self.nodes:
- cpulist += CpuList.nonisolated_cpulist(self.getcpus(n))
+ cpulist += cpulist_utils.nonisolated_cpulist(self.getcpus(n))
cpulist.sort()
return cpulist
@@ -403,7 +262,7 @@ if __name__ == "__main__":
onlcpus = s.online_cpus()
print(f'onlcpus = {onlcpus}')
- onlcpus = CpuList.collapse_cpulist(onlcpus)
+ onlcpus = cpulist_utils.collapse_cpulist(onlcpus)
print(f'onlcpus = {onlcpus}')
onlcpus_str = s.online_cpus_str()
--
2.43.0

View File

@ -1,88 +0,0 @@
From ea72c99ead85d1fcf156b9a3825a547ba7f4d0f8 Mon Sep 17 00:00:00 2001
From: John Kacur <jkacur@redhat.com>
Date: Fri, 12 Apr 2024 14:34:11 -0400
Subject: [PATCH 01/13] rteval: Cyclictest.py: Make standalone file work again
Make standalone Cyclictest.py work again for testing purposes
- remove unused parse_cpulist_from_config
- Instead of "import as", use "from" and the requested functionality
- Obtain the default buckets from the ModuleParameters to use if a
number is not otherwise provided
- set the cpulist to "" if not otherwise provided
- add a few docstrings to functions
- obtain a default cpulist from online_cpus for the standalone test
Signed-off-by: John Kacur <jkacur@redhat.com>
---
rteval/modules/measurement/cyclictest.py | 19 ++++++++-----------
1 file changed, 8 insertions(+), 11 deletions(-)
diff --git a/rteval/modules/measurement/cyclictest.py b/rteval/modules/measurement/cyclictest.py
index 722422589d62..671426e13c4d 100644
--- a/rteval/modules/measurement/cyclictest.py
+++ b/rteval/modules/measurement/cyclictest.py
@@ -16,10 +16,8 @@ import math
import libxml2
from rteval.Log import Log
from rteval.modules import rtevalModulePrototype
-from rteval.systopology import cpuinfo, parse_cpulist_from_config
-import rteval.cpulist_utils as cpulist_utils
-
-expand_cpulist = cpulist_utils.expand_cpulist
+from rteval.systopology import cpuinfo, SysTopology
+from rteval.cpulist_utils import expand_cpulist, collapse_cpulist
class RunData:
'''class to keep instance data from a cyclictest run'''
@@ -190,10 +188,11 @@ class Cyclictest(rtevalModulePrototype):
# Create a RunData object per CPU core
self.__numanodes = int(self.__cfg.setdefault('numanodes', 0))
self.__priority = int(self.__cfg.setdefault('priority', 95))
- self.__buckets = int(self.__cfg.setdefault('buckets', 2000))
+ default_buckets = ModuleParameters()["buckets"]["default"]
+ self.__buckets = int(self.__cfg.setdefault('buckets', default_buckets))
self.__numcores = 0
self.__cyclicdata = {}
- self.__cpulist = self.__cfg.cpulist
+ self.__cpulist = self.__cfg.setdefault('cpulist', "")
self.__cpus = [str(c) for c in expand_cpulist(self.__cpulist)]
self.__numcores = len(self.__cpus)
@@ -393,14 +392,13 @@ class Cyclictest(rtevalModulePrototype):
return rep_n
-
def ModuleInfo():
return {"parallel": True,
"loads": True}
-
def ModuleParameters():
+ """ default parameters """
return {"interval": {"descr": "Base interval of the threads in microseconds",
"default": 100,
"metavar": "INTV_US"},
@@ -421,6 +419,7 @@ def ModuleParameters():
def create(params, logger):
+ """ Instantiate a Cyclictest measurement module object """
return Cyclictest(params, logger)
@@ -438,9 +437,7 @@ if __name__ == '__main__':
cfg.AppendConfig('cyclictest', prms)
cfg_ct = cfg.GetSection('cyclictest')
- cfg_ct.reportdir = "."
- cfg_ct.buckets = 200
- # cfg_ct.breaktrace = 30
+ cfg_ct.cpulist = collapse_cpulist(SysTopology().online_cpus())
runtime = 10
--
2.44.0

View File

@ -1,87 +0,0 @@
From d142f0d23d8df1cede3573c3d6cfbf16535b3475 Mon Sep 17 00:00:00 2001
From: John Kacur <jkacur@redhat.com>
Date: Wed, 20 Dec 2023 17:55:21 -0500
Subject: [PATCH 2/2] rteval: Disable use of python-dmidecode
python-dmidecode is not being maintained upstream.
For now just disable it's use in rteval since it is useful but not
essential information for running rteval
In the future look at generating this info directly using dmidecode.
Signed-off-by: John Kacur <jkacur@redhat.com>
---
README | 6 ------
doc/installing.txt | 9 ---------
rteval/sysinfo/dmi.py | 4 ++--
3 files changed, 2 insertions(+), 17 deletions(-)
diff --git a/README b/README
index a5cf98344a46..b352d7f66ad2 100644
--- a/README
+++ b/README
@@ -19,15 +19,9 @@ Rteval requires the following packages to run:
Python >= 3.0
http://www.python.org/download/
-python-ethtool
- git://git.kernel.org/pub/scm/linux/kernel/git/acme/python-ethtool.git
-
python-lxml
http://lxml.de/
-python-dmidecode
- http://www.ohloh.net/p/python-dmidecode
-
libxml2-python
http://xmlsoft.org/
diff --git a/doc/installing.txt b/doc/installing.txt
index ff2d43cb9481..227249bbc9ed 100644
--- a/doc/installing.txt
+++ b/doc/installing.txt
@@ -1,18 +1,10 @@
The rteval utility requires some external software libraries to run
properly. These are:
-python-ethtool
- A python library to query network interfaces
- git://git.kernel.org/pub/scm/linux/kernel/git/acme/python-ethtool.git
-
python-lxml
A python library to parse XML files and XSLT stylesheets
http://lxml.de/
-python-dmidecode
- A python library used to access DMI table information
- http://www.autonomy.net.au/display/pydmi/Home
-
libxml2-python
A python library to parse XML files
http://xmlsoft.org/
@@ -22,7 +14,6 @@ rt-tests
git://git.kernel.org/pub/scm/utils/rt-tests/rt-tests.git
-$ sudo yum install python-{dmidecode,ethtool)
$ git clone \
git://git.kernel.org/pub/scm/utils/rt-tests/rt-tests.git
$ cd rt-tests && sudo make prefix=/usr install
diff --git a/rteval/sysinfo/dmi.py b/rteval/sysinfo/dmi.py
index e8285d263fe6..c01a0eef1435 100644
--- a/rteval/sysinfo/dmi.py
+++ b/rteval/sysinfo/dmi.py
@@ -15,8 +15,8 @@ from rteval import xmlout
from rteval import rtevalConfig
try:
- import dmidecode
- dmidecode_avail = True
+ # import dmidecode
+ dmidecode_avail = False
except ModuleNotFoundError:
dmidecode_avail = False
--
2.42.0

View File

@ -1,69 +0,0 @@
From 843ff713340ab701aa8859ca8b3d8a776608175c Mon Sep 17 00:00:00 2001
From: John Kacur <jkacur@redhat.com>
Date: Mon, 29 Apr 2024 10:47:41 -0400
Subject: [PATCH 09/13] rteval: Generate raw histogram data for an existing
timerlat report
Generate raw histogram data for an existing timerlat report.
Signed-off-by: John Kacur <jkacur@redhat.com>
---
rteval/rteval_histogram_raw.xsl | 29 ++++++++++++++++++++++++++++-
1 file changed, 28 insertions(+), 1 deletion(-)
diff --git a/rteval/rteval_histogram_raw.xsl b/rteval/rteval_histogram_raw.xsl
index 038419bf03b7..00b2be34f305 100644
--- a/rteval/rteval_histogram_raw.xsl
+++ b/rteval/rteval_histogram_raw.xsl
@@ -12,15 +12,26 @@
<!-- Extract overall system histogram data -->
<xsl:apply-templates select="Measurements/Profile/cyclictest/system/histogram/bucket">
- <xsl:with-param name="label" select="'system'"/>
+ <xsl:with-param name="label" select="'system'"/>
<xsl:sort select="Measurements/Profile/cyclictest/core/histogram/bucket/@index" data-type="number"/>
</xsl:apply-templates>
+ <xsl:apply-templates select="Measurements/Profile/timerlat/system/histogram/bucket">
+ <xsl:with-param name="label" select="'system'"/>
+ <xsl:sort select="Measurements/Profile/timerlat/core/histogram/bucket/@index" data-type="number"/>
+ </xsl:apply-templates>
+
<!-- Extract per cpu core histogram data -->
<xsl:apply-templates select="Measurements/Profile/cyclictest/core/histogram/bucket">
<xsl:sort select="Measurements/Profile/cyclictest/core/@id" data-type="number"/>
<xsl:sort select="Measurements/Profile/cyclictest/core/histogram/bucket/@index" data-type="number"/>
</xsl:apply-templates>
+
+ <xsl:apply-templates select="Measurements/Profile/timerlat/core/histogram/bucket">
+ <xsl:sort select="Measurements/Profile/timerlat/core/@id" data-type="number"/>
+ <xsl:sort select="Measurements/Profile/timerlat/core/histogram/bucket/@index" data-type="number"/>
+ </xsl:apply-templates>
+
</xsl:template>
<!-- -->
<!-- End of main report framework -->
@@ -43,4 +54,20 @@
<xsl:text>&#10;</xsl:text>
</xsl:template>
+ <xsl:template match="/rteval/Measurements/Profile/timerlat/*/histogram/bucket">
+ <xsl:param name="label"/>
+ <xsl:choose>
+ <!-- If we don't have a id tag in what should be a 'core' tag, use the given label -->
+ <xsl:when test="../../@id"><xsl:value-of select="../../@id"/></xsl:when>
+ <xsl:otherwise><xsl:value-of select="$label"/></xsl:otherwise>
+ </xsl:choose>
+ <xsl:text>&#09;</xsl:text>
+
+ <xsl:value-of select="@index"/>
+ <xsl:text>&#09;</xsl:text>
+
+ <xsl:value-of select="@value"/>
+ <xsl:text>&#10;</xsl:text>
+ </xsl:template>
+
</xsl:stylesheet>
--
2.44.0

View File

@ -1,299 +0,0 @@
From 43c45ba7dae488c16beb359834b3a71ebf6068d6 Mon Sep 17 00:00:00 2001
From: Tomas Glozar <tglozar@redhat.com>
Date: Mon, 4 Mar 2024 11:26:03 +0100
Subject: [PATCH] rteval: Implement initial dmidecode support
Previously rteval used python-dmidecode to gather DMI data from a
system. Since python-dmidecode is without a maintainer, its support was
removed in d142f0d2 ("rteval: Disable use of python-dmidecode").
Add get_dmidecode_xml() function into rteval/sysinfo/dmi.py that does
simple parsing of dmidecode command-line tool output without any
structure changes and include it into the rteval report.
Notes:
- ProcessWarnings() in rteval.sysinfo.dmi was reworked into a class
method of DMIinfo and to use the class's __log field as logger. It
now also does not ignore warnings that appear when running rteval as
non-root, since that is no longer supported. Additionally,
a duplicate call in rteval-cmd was removed.
- rteval/rteval_dmi.xsl XSLT template was left untouched and is
currectly not used. In a future commit, it is expected to be rewritten
to transform the XML format outputted by get_dmidecode_xml() into the
same format that was used with python-dmidecode.
Signed-off-by: Tomas Glozar <tglozar@redhat.com>
Signed-off-by: John Kacur <jkacur@redhat.com>
---
rteval-cmd | 2 -
rteval/sysinfo/__init__.py | 2 +-
rteval/sysinfo/dmi.py | 178 ++++++++++++++++++++++++-------------
3 files changed, 118 insertions(+), 64 deletions(-)
diff --git a/rteval-cmd b/rteval-cmd
index a5e8746..018a414 100755
--- a/rteval-cmd
+++ b/rteval-cmd
@@ -268,8 +268,6 @@ if __name__ == '__main__':
| (rtevcfg.debugging and Log.DEBUG)
logger.SetLogVerbosity(loglev)
- dmi.ProcessWarnings(logger=logger)
-
# Load modules
loadmods = LoadModules(config, logger=logger)
measuremods = MeasurementModules(config, logger=logger)
diff --git a/rteval/sysinfo/__init__.py b/rteval/sysinfo/__init__.py
index d3f9efb..09af52e 100644
--- a/rteval/sysinfo/__init__.py
+++ b/rteval/sysinfo/__init__.py
@@ -30,7 +30,7 @@ class SystemInfo(KernelInfo, SystemServices, dmi.DMIinfo, CPUtopology,
NetworkInfo.__init__(self, logger=logger)
# Parse initial DMI decoding errors
- dmi.ProcessWarnings(logger=logger)
+ self.ProcessWarnings()
# Parse CPU info
CPUtopology._parse(self)
diff --git a/rteval/sysinfo/dmi.py b/rteval/sysinfo/dmi.py
index c01a0ee..f1aab9f 100644
--- a/rteval/sysinfo/dmi.py
+++ b/rteval/sysinfo/dmi.py
@@ -3,6 +3,7 @@
# Copyright 2009 - 2013 Clark Williams <williams@redhat.com>
# Copyright 2009 - 2013 David Sommerseth <davids@redhat.com>
# Copyright 2022 John Kacur <jkacur@redhat.com>
+# Copyright 2024 Tomas Glozar <tglozar@redhat.com>
#
""" dmi.py class to wrap DMI Table Information """
@@ -10,65 +11,125 @@ import sys
import os
import libxml2
import lxml.etree
+import shutil
+import re
+from subprocess import Popen, PIPE, SubprocessError
from rteval.Log import Log
from rteval import xmlout
from rteval import rtevalConfig
-try:
- # import dmidecode
- dmidecode_avail = False
-except ModuleNotFoundError:
- dmidecode_avail = False
-
-def set_dmidecode_avail(val):
- """ Used to set global variable dmidecode_avail from a function """
- global dmidecode_avail
- dmidecode_avail = val
-
-def ProcessWarnings(logger=None):
- """ Process Warnings from dmidecode """
-
- if not dmidecode_avail:
- return
-
- if not hasattr(dmidecode, 'get_warnings'):
- return
-
- warnings = dmidecode.get_warnings()
- if warnings is None:
- return
-
- ignore1 = '/dev/mem: Permission denied'
- ignore2 = 'No SMBIOS nor DMI entry point found, sorry.'
- ignore3 = 'Failed to open memory buffer (/dev/mem): Permission denied'
- ignore = (ignore1, ignore2, ignore3)
- for warnline in warnings.split('\n'):
- # Ignore these warnings, as they are "valid" if not running as root
- if warnline in ignore:
- continue
- # All other warnings will be printed
- if len(warnline) > 0:
- logger.log(Log.DEBUG, f"** DMI WARNING ** {warnline}")
- set_dmidecode_avail(False)
+def get_dmidecode_xml(dmidecode_executable):
+ """
+ Transform human-readable dmidecode output into machine-processable XML format
+ :param dmidecode_executable: Path to dmidecode tool executable
+ :return: Tuple of values with resulting XML and dmidecode warnings
+ """
+ proc = Popen(dmidecode_executable, text=True, stdout=PIPE, stderr=PIPE)
+ outs, errs = proc.communicate()
+ parts = outs.split("\n\n")
+ if len(parts) < 2:
+ raise RuntimeError("Parsing dmidecode output failed")
+ header = parts[0]
+ handles = parts[1:]
+ root = lxml.etree.Element("dmidecode")
+ # Parse dmidecode output header
+ # Note: Only supports SMBIOS data currently
+ regex = re.compile(r"# dmidecode (\d+\.\d+)\n"
+ r"Getting SMBIOS data from sysfs\.\n"
+ r"SMBIOS ((?:\d+\.)+\d+) present\.\n"
+ r"(?:(\d+) structures occupying (\d+) bytes\.\n)?"
+ r"Table at (0x[0-9A-Fa-f]+)\.", re.MULTILINE)
+ match = re.match(regex, header)
+ if match is None:
+ raise RuntimeError("Parsing dmidecode output failed")
+ root.attrib["dmidecodeversion"] = match.group(1)
+ root.attrib["smbiosversion"] = match.group(2)
+ if match.group(3) is not None:
+ root.attrib["structures"] = match.group(3)
+ if match.group(4) is not None:
+ root.attrib["size"] = match.group(4)
+ root.attrib["address"] = match.group(5)
+
+ # Generate element per handle in dmidecode output
+ for handle_text in handles:
+ if not handle_text:
+ # Empty line
+ continue
- dmidecode.clear_warnings()
+ handle = lxml.etree.Element("Handle")
+ lines = handle_text.splitlines()
+ # Parse handle header
+ if len(lines) < 2:
+ raise RuntimeError("Parsing dmidecode handle failed")
+ header, name, content = lines[0], lines[1], lines[2:]
+ match = re.match(r"Handle (0x[0-9A-Fa-f]{4}), "
+ r"DMI type (\d+), (\d+) bytes", header)
+ if match is None:
+ raise RuntimeError("Parsing dmidecode handle failed")
+ handle.attrib["address"] = match.group(1)
+ handle.attrib["type"] = match.group(2)
+ handle.attrib["bytes"] = match.group(3)
+ handle.attrib["name"] = name
+
+ # Parse all fields in handle and create an element for each
+ list_field = None
+ for index, line in enumerate(content):
+ line = content[index]
+ if line.rfind("\t") > 0:
+ # We are inside a list field, add value to it
+ value = lxml.etree.Element("Value")
+ value.text = line.strip()
+ list_field.append(value)
+ continue
+ line = line.lstrip().split(":", 1)
+ if len(line) != 2:
+ raise RuntimeError("Parsing dmidecode field failed")
+ if not line[1] or (index + 1 < len(content) and
+ content[index + 1].rfind("\t") > 0):
+ # No characters after : or next line is inside list field
+ # means a list field
+ # Note: there are list fields which specify a number of
+ # items, for example "Installable Languages", so merely
+ # checking for no characters after : is not enough
+ list_field = lxml.etree.Element("List")
+ list_field.attrib["Name"] = line[0].strip()
+ handle.append(list_field)
+ else:
+ # Regular field
+ field = lxml.etree.Element("Field")
+ field.attrib["Name"] = line[0].strip()
+ field.text = line[1].strip()
+ handle.append(field)
+
+ root.append(handle)
+
+ return root, errs
class DMIinfo:
- '''class used to obtain DMI info via python-dmidecode'''
+ '''class used to obtain DMI info via dmidecode'''
def __init__(self, logger=None):
self.__version = '0.6'
self._log = logger
- if not dmidecode_avail:
- logger.log(Log.DEBUG, "DMI info unavailable, ignoring DMI tables")
+ dmidecode_executable = shutil.which("dmidecode")
+ if dmidecode_executable is None:
+ logger.log(Log.DEBUG, "DMI info unavailable,"
+ " ignoring DMI tables")
self.__fake = True
return
self.__fake = False
- self.__dmixml = dmidecode.dmidecodeXML()
+ try:
+ self.__dmixml, self.__warnings = get_dmidecode_xml(
+ dmidecode_executable)
+ except (RuntimeError, OSError, SubprocessError) as error:
+ logger.log(Log.DEBUG, "DMI info unavailable: {};"
+ " ignoring DMI tables".format(str(error)))
+ self.__fake = True
+ return
self.__xsltparser = self.__load_xslt('rteval_dmi.xsl')
@@ -88,30 +149,25 @@ class DMIinfo:
raise RuntimeError(f'Could not locate XSLT template for DMI data ({fname})')
+ def ProcessWarnings(self):
+ """Prints out warnings from dmidecode into log if there were any"""
+ if self.__fake or self._log is None:
+ return
+ for warnline in self.__warnings.split('\n'):
+ if len(warnline) > 0:
+ self._log.log(Log.DEBUG, f"** DMI WARNING ** {warnline}")
+
def MakeReport(self):
""" Add DMI information to final report """
- rep_n = libxml2.newNode("DMIinfo")
- rep_n.newProp("version", self.__version)
if self.__fake:
+ rep_n = libxml2.newNode("DMIinfo")
+ rep_n.newProp("version", self.__version)
rep_n.addContent("No DMI tables available")
rep_n.newProp("not_available", "1")
- else:
- self.__dmixml.SetResultType(dmidecode.DMIXML_DOC)
- try:
- dmiqry = xmlout.convert_libxml2_to_lxml_doc(self.__dmixml.QuerySection('all'))
- except Exception as ex1:
- self._log.log(Log.DEBUG, f'** EXCEPTION {str(ex1)}, will query BIOS only')
- try:
- # If we can't query 'all', at least query 'bios'
- dmiqry = xmlout.convert_libxml2_to_lxml_doc(self.__dmixml.QuerySection('bios'))
- except Exception as ex2:
- rep_n.addContent("No DMI tables available")
- rep_n.newProp("not_available", "1")
- self._log.log(Log.DEBUG, f'** EXCEPTION {str(ex2)}, dmi info will not be reported')
- return rep_n
- resdoc = self.__xsltparser(dmiqry)
- dmi_n = xmlout.convert_lxml_to_libxml2_nodes(resdoc.getroot())
- rep_n.addChild(dmi_n)
+ return rep_n
+ rep_n = xmlout.convert_lxml_to_libxml2_nodes(self.__dmixml)
+ rep_n.setName("DMIinfo")
+ rep_n.newProp("version", self.__version)
return rep_n
def unit_test(rootdir):
@@ -130,12 +186,12 @@ def unit_test(rootdir):
log = Log()
log.SetLogVerbosity(Log.DEBUG|Log.INFO)
- ProcessWarnings(logger=log)
if os.getuid() != 0:
print("** ERROR ** Must be root to run this unit_test()")
return 1
d = DMIinfo(logger=log)
+ d.ProcessWarnings()
dx = d.MakeReport()
x = libxml2.newDoc("1.0")
x.setRootElement(dx)
--
2.44.0

View File

@ -1,60 +0,0 @@
From 701ab9f5d50fb0e1308ad8ea163d49525d3d90af Mon Sep 17 00:00:00 2001
From: Tomas Glozar <tglozar@redhat.com>
Date: Mon, 29 Apr 2024 10:47:20 +0200
Subject: [PATCH 10/13] rteval: Make output work with new dmiinfo format
Commit 43c45ba7 ("rteval: Implement initial dmidecode support")
re-introduced DMI information into rteval XML summary, but in a
different format, which is not correctly picked up in rteval_text.xsl
for formatting BIOS and vendor information into rteval text output.
This lead to the information not being displayed correctly:
Model: -
BIOS version: (ver: , rev :, release date: )
Modify the relevant section of rteval_text.xsl to make it understand the
new format. Also, adjust the incorrect spacing around "rev".
New output (in QEMU VM):
Model: QEMU - Standard PC (Q35 + ICH9, 2009)
BIOS version: SeaBIOS (ver: 1.16.3-1.fc39, rev: 0.0, release date: 04/01/2014)
Signed-off-by: Tomas Glozar <tglozar@redhat.com>
Signed-off-by: John Kacur <jkacur@redhat.com>
---
rteval/rteval_text.xsl | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/rteval/rteval_text.xsl b/rteval/rteval_text.xsl
index 1e9c0f0d26c5..2f03bda0bb55 100644
--- a/rteval/rteval_text.xsl
+++ b/rteval/rteval_text.xsl
@@ -39,18 +39,18 @@
<xsl:text>&#10;</xsl:text>
<xsl:text> Model: </xsl:text>
- <xsl:value-of select="SystemInfo/DMIinfo/HardwareInfo/GeneralInfo/Manufacturer|HardwareInfo/GeneralInfo/ProductName"/>
- <xsl:text> - </xsl:text><xsl:value-of select="SystemInfo/DMIinfo/HardwareInfo/GeneralInfo/ProductName|HardwareInfo/GeneralInfo/ProductName"/>
+ <xsl:value-of select="SystemInfo/DMIinfo/Handle[@name='System Information']/Field[@Name='Manufacturer']"/>
+ <xsl:text> - </xsl:text><xsl:value-of select="SystemInfo/DMIinfo/Handle[@name='System Information']/Field[@Name='Product Name']"/>
<xsl:text>&#10;</xsl:text>
<xsl:text> BIOS version: </xsl:text>
- <xsl:value-of select="SystemInfo/DMIinfo/HardwareInfo/BIOS|HardwareInfo/BIOS"/>
+ <xsl:value-of select="SystemInfo/DMIinfo/Handle[@name='BIOS Information']/Field[@Name='Vendor']"/>
<xsl:text> (ver: </xsl:text>
- <xsl:value-of select="SystemInfo/DMIinfo/HardwareInfo/BIOS/@Version|HardwareInfo/BIOS/@Version"/>
- <xsl:text>, rev :</xsl:text>
- <xsl:value-of select="SystemInfo/DMIinfo/HardwareInfo/BIOS/@BIOSrevision|HardwareInfo/BIOS/@BIOSrevision"/>
+ <xsl:value-of select="SystemInfo/DMIinfo/Handle[@name='BIOS Information']/Field[@Name='Version']"/>
+ <xsl:text>, rev: </xsl:text>
+ <xsl:value-of select="SystemInfo/DMIinfo/Handle[@name='BIOS Information']/Field[@Name='BIOS Revision']"/>
<xsl:text>, release date: </xsl:text>
- <xsl:value-of select="SystemInfo/DMIinfo/HardwareInfo/BIOS/@ReleaseDate|HardwareInfo/BIOS/@ReleaseDate"/>
+ <xsl:value-of select="SystemInfo/DMIinfo/Handle[@name='BIOS Information']/Field[@Name='Release Date']"/>
<xsl:text>)</xsl:text>
<xsl:text>&#10;&#10;</xsl:text>
--
2.44.0

View File

@ -1,64 +0,0 @@
From 2d2e85c459d240926c99b1961bbef090aa80a1fc Mon Sep 17 00:00:00 2001
From: John Kacur <jkacur@redhat.com>
Date: Wed, 20 Dec 2023 17:22:22 -0500
Subject: [PATCH 1/2] rteval: Makefile: More rpm cleanups
Afer having removed the upstream specfile, there were still a few
references to rpms in the Makefile. These are not necessary because any
work with rpms can be done with modern rpm tools and are typically done
by distributions
Also test whether directory 'run' exists since it may have been removed
by make realclean, and create it if it does not
Signed-off-by: John Kacur <jkacur@redhat.com>
---
Makefile | 11 +++--------
1 file changed, 3 insertions(+), 8 deletions(-)
diff --git a/Makefile b/Makefile
index ee4cca555b95..b8bed643f760 100644
--- a/Makefile
+++ b/Makefile
@@ -31,6 +31,7 @@ load:
$(PYTHON) rteval-cmd --onlyload -D -L -v --workdir=./run --loaddir=$(HERE)/loadsource -f $(HERE)/rteval/rteval.conf -i $(HERE)/rteval
sysreport:
+ [ -d $(HERE)/run ] || mkdir run
$(PYTHON) rteval-cmd -D -v --workdir=$(HERE)/run --loaddir=$(HERE)/loadsource --duration=$(D) -i $(HERE)/rteval --sysreport
clean:
@@ -39,7 +40,7 @@ clean:
realclean: clean
[ -f $(XMLRPCDIR)/Makefile ] && make -C $(XMLRPCDIR) maintainer-clean || echo -n
- rm -rf run rpm
+ rm -rf run
install: install_loads install_rteval
@@ -73,13 +74,6 @@ rteval-xmlrpc-$(XMLRPCVER).tar.gz :
make distcheck
cp $(XMLRPCDIR)/rteval-xmlrpc-$(XMLRPCVER).tar.gz $(HERE)/
-rpm_prep:
- rm -rf rpm
- mkdir -p rpm/{BUILD,RPMS,SRPMS,SOURCES,SPECS}
-
-rpms rpm: rpm_prep rtevalrpm loadrpm
-
-
help:
@echo ""
@echo "rteval Makefile targets:"
@@ -88,6 +82,7 @@ help:
@echo " tarfile: create the source tarball"
@echo " install: install rteval locally"
@echo " clean: cleanup generated files"
+ @echo " realclean: Same as clean plus directory run"
@echo " sysreport: do a short testrun and generate sysreport data"
@echo " tags: generate a ctags file"
@echo " cleantags: remove the ctags file"
--
2.42.0

View File

@ -1,85 +0,0 @@
From 768daa63ec8e2299da53afe081e7304b37fc91cf Mon Sep 17 00:00:00 2001
From: Tomas Glozar <tglozar@redhat.com>
Date: Wed, 29 Nov 2023 10:34:55 +0100
Subject: [PATCH 2/9] rteval: Minor improvements to CpuList class
- Remove unnecessary if-else from online_file_exists
- Use cpupath in online_file_exists
- In is_online, remove check for n in cpuset and make it static
- Mark also the remaining methods static since they do not rely on
any fields of the class
Signed-off-by: Tomas Glozar <tglozar@redhat.com>
- Removed incorrect line from commit message
Signed-off-by: John Kacur <jkacur@redhat.com>
---
rteval/systopology.py | 29 +++++++++++++++--------------
1 file changed, 15 insertions(+), 14 deletions(-)
diff --git a/rteval/systopology.py b/rteval/systopology.py
index ea8e242..60ac8e8 100644
--- a/rteval/systopology.py
+++ b/rteval/systopology.py
@@ -82,12 +82,17 @@ class CpuList:
def __len__(self):
return len(self.cpulist)
+ def getcpulist(self):
+ """ return the list of cpus tracked """
+ return self.cpulist
+
@staticmethod
def online_file_exists():
""" Check whether machine / kernel is configured with online file """
- if os.path.exists('/sys/devices/system/cpu/cpu1/online'):
- return True
- return False
+ # Note: some machines do not have cpu0/online so we check cpu1/online.
+ # In the case of machines with a single CPU, there is no cpu1, but
+ # that is not a problem, since a single CPU cannot be offline
+ return os.path.exists(os.path.join(CpuList.cpupath, "cpu1/online"))
@staticmethod
def isolated_file_exists():
@@ -147,14 +152,9 @@ class CpuList:
result.append(a)
return [int(i) for i in list(set(result))]
- def getcpulist(self):
- """ return the list of cpus tracked """
- return self.cpulist
-
- def is_online(self, n):
+ @staticmethod
+ def is_online(n):
""" check whether cpu n is online """
- if n not in self.cpulist:
- raise RuntimeError(f"invalid cpu number {n}")
path = os.path.join(CpuList.cpupath, f'cpu{n}')
# Some hardware doesn't allow cpu0 to be turned off
@@ -163,16 +163,17 @@ class CpuList:
return sysread(path, "online") == "1"
- def online_cpulist(self, cpulist):
+ @staticmethod
+ def online_cpulist(cpulist):
""" Given a cpulist, return a cpulist of online cpus """
# This only works if the sys online files exist
- if not self.online_file_exists():
+ if not CpuList.online_file_exists():
return cpulist
newlist = []
for cpu in cpulist:
- if not self.online_file_exists() and cpu == '0':
+ if not CpuList.online_file_exists() and cpu == '0':
newlist.append(cpu)
- elif self.is_online(int(cpu)):
+ elif CpuList.is_online(int(cpu)):
newlist.append(cpu)
return newlist
--
2.43.0

View File

@ -1,225 +0,0 @@
From 4b4f50900e38a931ed9585c6cf200b74c0120a20 Mon Sep 17 00:00:00 2001
From: Tomas Glozar <tglozar@redhat.com>
Date: Wed, 29 Nov 2023 10:34:54 +0100
Subject: [PATCH 1/9] rteval: Refactor collapse_cpulist in systopology
Instead of having duplicate code in two functions, one top-level and
one member function of CpuList, have only one static function in
CpuList.
Additionally re-write the implementation to use a more straight forward
one-pass algorithm.
Signed-off-by: Tomas Glozar <tglozar@redhat.com>
Signed-off-by: John Kacur <jkacur@redhat.com>
---
rteval-cmd | 4 +-
rteval/modules/loads/__init__.py | 4 +-
rteval/modules/measurement/__init__.py | 4 +-
rteval/modules/measurement/cyclictest.py | 6 +--
rteval/systopology.py | 68 ++++++++----------------
5 files changed, 30 insertions(+), 56 deletions(-)
diff --git a/rteval-cmd b/rteval-cmd
index 6f613a3..7c41429 100755
--- a/rteval-cmd
+++ b/rteval-cmd
@@ -30,7 +30,7 @@ from rteval import RtEval, rtevalConfig
from rteval.modules.loads import LoadModules
from rteval.modules.measurement import MeasurementModules
from rteval.version import RTEVAL_VERSION
-from rteval.systopology import CpuList, SysTopology, collapse_cpulist
+from rteval.systopology import CpuList, SysTopology
from rteval.modules.loads.kcompile import ModuleParameters
compress_cpulist = CpuList.compress_cpulist
@@ -211,7 +211,7 @@ def remove_offline(cpulist):
""" return cpulist in collapsed compressed form with only online cpus """
tmplist = expand_cpulist(cpulist)
tmplist = SysTopology().online_cpulist(tmplist)
- return collapse_cpulist(tmplist)
+ return CpuList.collapse_cpulist(tmplist)
if __name__ == '__main__':
diff --git a/rteval/modules/loads/__init__.py b/rteval/modules/loads/__init__.py
index aca0c9f..13fba1e 100644
--- a/rteval/modules/loads/__init__.py
+++ b/rteval/modules/loads/__init__.py
@@ -11,7 +11,7 @@ import libxml2
from rteval.Log import Log
from rteval.rtevalConfig import rtevalCfgSection
from rteval.modules import RtEvalModules, rtevalModulePrototype
-from rteval.systopology import collapse_cpulist, CpuList, SysTopology as SysTop
+from rteval.systopology import CpuList, SysTopology as SysTop
class LoadThread(rtevalModulePrototype):
def __init__(self, name, config, logger=None):
@@ -120,7 +120,7 @@ class LoadModules(RtEvalModules):
cpulist = CpuList(cpulist).cpulist
else:
cpulist = SysTop().default_cpus()
- rep_n.newProp("loadcpus", collapse_cpulist(cpulist))
+ rep_n.newProp("loadcpus", CpuList.collapse_cpulist(cpulist))
return rep_n
diff --git a/rteval/modules/measurement/__init__.py b/rteval/modules/measurement/__init__.py
index 2a0556b..41b8022 100644
--- a/rteval/modules/measurement/__init__.py
+++ b/rteval/modules/measurement/__init__.py
@@ -5,7 +5,7 @@
import libxml2
from rteval.modules import RtEvalModules, ModuleContainer
-from rteval.systopology import collapse_cpulist, CpuList, SysTopology as SysTop
+from rteval.systopology import CpuList, SysTopology as SysTop
class MeasurementProfile(RtEvalModules):
"""Keeps and controls all the measurement modules with the same measurement profile"""
@@ -187,7 +187,7 @@ measurement profiles, based on their characteristics"""
cpulist = CpuList(cpulist).cpulist
else:
cpulist = SysTop().online_cpus() if run_on_isolcpus else SysTop().default_cpus()
- rep_n.newProp("measurecpus", collapse_cpulist(cpulist))
+ rep_n.newProp("measurecpus", CpuList.collapse_cpulist(cpulist))
for mp in self.__measureprofiles:
mprep_n = mp.MakeReport()
diff --git a/rteval/modules/measurement/cyclictest.py b/rteval/modules/measurement/cyclictest.py
index 0af1d31..1b14e7e 100644
--- a/rteval/modules/measurement/cyclictest.py
+++ b/rteval/modules/measurement/cyclictest.py
@@ -17,7 +17,7 @@ import libxml2
from rteval.Log import Log
from rteval.modules import rtevalModulePrototype
from rteval.systopology import cpuinfo
-from rteval.systopology import CpuList, SysTopology, collapse_cpulist
+from rteval.systopology import CpuList, SysTopology
expand_cpulist = CpuList.expand_cpulist
@@ -203,7 +203,7 @@ class Cyclictest(rtevalModulePrototype):
# Only include online cpus
self.__cpus = CpuList(self.__cpus).cpulist
# Reset cpulist from the newly calculated self.__cpus
- self.__cpulist = collapse_cpulist(self.__cpus)
+ self.__cpulist = CpuList.collapse_cpulist(self.__cpus)
self.__cpus = [str(c) for c in self.__cpus]
self.__sparse = True
if self.__run_on_isolcpus:
@@ -220,7 +220,7 @@ class Cyclictest(rtevalModulePrototype):
self.__cpus = [c for c in self.__cpus if c in cpuset or self.__run_on_isolcpus and c in isolcpus]
if self.__run_on_isolcpus:
self.__sparse = True
- self.__cpulist = collapse_cpulist(self.__cpus)
+ self.__cpulist = CpuList.collapse_cpulist([int(c) for c in self.__cpus])
# Sort the list of cpus to align with the order reported by cyclictest
self.__cpus.sort(key=int)
diff --git a/rteval/systopology.py b/rteval/systopology.py
index 62ad355..ea8e242 100644
--- a/rteval/systopology.py
+++ b/rteval/systopology.py
@@ -10,25 +10,6 @@ import os
import os.path
import glob
-# Utility version of collapse_cpulist that doesn't require a CpuList object
-def collapse_cpulist(cpulist):
- """ Collapse a list of cpu numbers into a string range
- of cpus (e.g. 0-5, 7, 9) """
- if len(cpulist) == 0:
- return ""
- idx = CpuList.longest_sequence(cpulist)
- if idx == 0:
- seq = str(cpulist[0])
- else:
- if idx == 1:
- seq = f"{cpulist[0]},{cpulist[idx]}"
- else:
- seq = f"{cpulist[0]}-{cpulist[idx]}"
-
- rest = collapse_cpulist(cpulist[idx+1:])
- if rest == "":
- return seq
- return ",".join((seq, rest))
def sysread(path, obj):
""" Helper function for reading system files """
@@ -93,7 +74,7 @@ class CpuList:
self.cpulist.sort()
def __str__(self):
- return self.__collapse_cpulist(self.cpulist)
+ return self.collapse_cpulist(self.cpulist)
def __contains__(self, cpu):
return cpu in self.cpulist
@@ -114,35 +95,28 @@ class CpuList:
return os.path.exists(os.path.join(CpuList.cpupath, "isolated"))
@staticmethod
- def longest_sequence(cpulist):
- """ return index of last element of a sequence that steps by one """
- lim = len(cpulist)
- for idx, _ in enumerate(cpulist):
- if idx+1 == lim:
- break
- if int(cpulist[idx+1]) != (int(cpulist[idx])+1):
- return idx
- return lim - 1
-
- def __collapse_cpulist(self, cpulist):
- """ Collapse a list of cpu numbers into a string range
+ def collapse_cpulist(cpulist):
+ """
+ Collapse a list of cpu numbers into a string range
of cpus (e.g. 0-5, 7, 9)
"""
- if len(cpulist) == 0:
- return ""
- idx = self.longest_sequence(cpulist)
- if idx == 0:
- seq = str(cpulist[0])
- else:
- if idx == 1:
- seq = f"{cpulist[0]},{cpulist[idx]}"
+ cur_range = [None, None]
+ result = []
+ for cpu in cpulist + [None]:
+ if cur_range[0] is None:
+ cur_range[0] = cur_range[1] = cpu
+ continue
+ if cpu is not None and cpu == cur_range[1] + 1:
+ # Extend currently processed range
+ cur_range[1] += 1
else:
- seq = f"{cpulist[0]}-{cpulist[idx]}"
-
- rest = self.__collapse_cpulist(cpulist[idx+1:])
- if rest == "":
- return seq
- return ",".join((seq, rest))
+ # Range processing finished, add range to string
+ result.append(f"{cur_range[0]}-{cur_range[1]}"
+ if cur_range[0] != cur_range[1]
+ else str(cur_range[0]))
+ # Reset
+ cur_range[0] = cur_range[1] = cpu
+ return ",".join(result)
@staticmethod
def compress_cpulist(cpulist):
@@ -428,7 +402,7 @@ if __name__ == "__main__":
onlcpus = s.online_cpus()
print(f'onlcpus = {onlcpus}')
- onlcpus = collapse_cpulist(onlcpus)
+ onlcpus = CpuList.collapse_cpulist(onlcpus)
print(f'onlcpus = {onlcpus}')
onlcpus_str = s.online_cpus_str()
--
2.43.0

View File

@ -1,566 +0,0 @@
From de8e25ff3a30dbdbba6fb1b68ea0921dff55cd91 Mon Sep 17 00:00:00 2001
From: John Kacur <jkacur@redhat.com>
Date: Mon, 13 Nov 2023 14:32:19 -0500
Subject: [PATCH] rteval: Remove upstream spec file
Specfiles should be maintained by distributions and not in the upstream
code. In practice they are not maintained upstream except for version
numbers, so just remove the specfile.
This also moves a lot of functionality around rpms in the Makefile, but
this functionality exists in tools such as rpmbuild and friends anyway.
Signed-off-by: John Kacur <jkacur@redhat.com>
---
Makefile | 37 ----
rteval.spec | 484 ----------------------------------------------------
2 files changed, 521 deletions(-)
delete mode 100644 rteval.spec
diff --git a/Makefile b/Makefile
index 14f74e087eff..ee4cca555b95 100644
--- a/Makefile
+++ b/Makefile
@@ -79,49 +79,12 @@ rpm_prep:
rpms rpm: rpm_prep rtevalrpm loadrpm
-rtevalrpm: rteval-$(VERSION).tar.bz2
- cp $^ rpm/SOURCES
- cp rteval.spec rpm/SPECS
- rpmbuild -ba --define "_topdir $(HERE)/rpm" rpm/SPECS/rteval.spec
-
-rtevalsrpm: rteval-$(VERSION).tar.bz2
- cp $^ rpm/SOURCES
- cp rteval.spec rpm/SPECS
- rpmbuild -bs --define "_topdir $(HERE)/rpm" rpm/SPECS/rteval.spec
-
-
-xmlrpcrpm: rteval-xmlrpc-$(XMLRPCVER).tar.gz
- cp rteval-xmlrpc-$(XMLRPCVER).tar.gz rpm/SOURCES/
- cp server/rteval-parser.spec rpm/SPECS/
- rpmbuild -ba --define "_topdir $(HERE)/rpm" rpm/SPECS/rteval-parser.spec
-
-xmlsrpm: rteval-xmlrpc-$(XMLRPCVER).tar.gz
- cp rteval-xmlrpc-$(XMLRPCVER).tar.gz rpm/SOURCES/
- cp server/rteval-parser.spec rpm/SPECS/
- rpmbuild -bs --define "_topdir $(HERE)/rpm" rpm/SPECS/rteval-parser.spec
-
-loadrpm:
- rm -rf rpm-loads
- mkdir -p rpm-loads/{BUILD,RPMS,SRPMS,SOURCES,SPECS}
- cp rteval-loads.spec rpm-loads/SPECS
- cp $(LOADS) rpm-loads/SOURCES
- rpmbuild -ba --define "_topdir $(HERE)/rpm-loads" rpm-loads/SPECS/rteval-loads.spec
-
-rpmlint: rpms
- @echo "==============="
- @echo "running rpmlint"
- rpmlint -v $(shell find ./rpm -type f -name "*.rpm") \
- $(shell find ./rpm-loads -type f -name "*.rpm") \
- $(shell find ./rpm/SPECS -type f -name "rteval*.spec") \
- $(shell find ./rpm-loads/SPECS -type f -name "rteval*.spec" )
help:
@echo ""
@echo "rteval Makefile targets:"
@echo ""
@echo " runit: do a short testrun locally [default]"
- @echo " rpm: run rpmbuild for all rpms"
- @echo " rpmlint: run rpmlint against all rpms/srpms/specfiles"
@echo " tarfile: create the source tarball"
@echo " install: install rteval locally"
@echo " clean: cleanup generated files"
diff --git a/rteval.spec b/rteval.spec
deleted file mode 100644
index b5842f0d8206..000000000000
--- a/rteval.spec
+++ /dev/null
@@ -1,484 +0,0 @@
-%{!?python_sitelib: %define python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")}
-%{!?python_ver: %define python_ver %(%{__python} -c "import sys ; print sys.version[:3]")}
-
-Name: rteval
-Version: 3.7
-Release: 1%{?dist}
-Summary: Utility to evaluate system suitability for RT Linux
-
-Group: Development/Tools
-License: GPLv2
-URL: http://git.kernel.org/?p=linux/kernel/git/clrkwllms/rteval.git
-Source0: rteval-%{version}.tar.bz2
-BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
-
-BuildRequires: python3-devel
-Requires: platform-python
-Requires: python3-ethtool python3-lxml
-Requires: python3-dmidecode >= 3.10
-Requires: rt-tests >= 0.97
-Requires: rteval-loads >= 1.4
-Requires: rteval-common => %{version}-%{release}
-Requires: sysstat
-Requires: bzip2
-Requires: kernel-headers
-Requires: sos
-BuildArch: noarch
-Obsoletes: rteval <= 1.7
-Requires: numactl
-
-%description
-The rteval script is a utility for measuring various aspects of
-realtime behavior on a system under load. The script unpacks the
-kernel source, and then goes into a loop, running hackbench and
-compiling a kernel tree. During that loop the cyclictest program
-is run to measure event response time. After the run time completes,
-a statistical analysis of the event response times is done and printed
-to the screen.
-
-
-%package common
-Summary: Common rteval files
-BuildArch: noarch
-
-%description common
-Common files used by rteval, rteval-xmlrpc and rteval-parser
-
-%prep
-%setup -q
-
-# version sanity check (make sure specfile and rteval.py match)
-cp rteval/version.py rtevalversion.py
-srcver=$(%{__python} -c "from rtevalversion import RTEVAL_VERSION; print RTEVAL_VERSION")
-rm -rf rtevalversion.py
-if [ $srcver != %{version} ]; then
- printf "\n***\n*** rteval spec file version do not match the rteval/rteval.py version\n***\n\n"
- exit -1
-fi
-
-%build
-%{__python} setup.py build
-
-%install
-%{__python} setup.py install --root=$RPM_BUILD_ROOT
-
-%clean
-rm -rf $RPM_BUILD_ROOT
-
-%files common
-%doc COPYING
-%dir %{_datadir}/%{name}
-%{python_sitelib}/rteval/rtevalclient.py*
-%{python_sitelib}/rteval/rtevalConfig.py*
-%{python_sitelib}/rteval/rtevalXMLRPC.py*
-%{python_sitelib}/rteval/version.py*
-%{python_sitelib}/rteval/Log.py*
-%{python_sitelib}/rteval/misc.py*
-%{python_sitelib}/rteval/systopology.py*
-
-%files
-%defattr(-,root,root,-)
-%if "%{python_ver}" >= "2.5"
-%{python_sitelib}/*.egg-info
-%endif
-
-%doc COPYING README doc/rteval.txt
-%{_mandir}/man8/rteval.8.gz
-%config(noreplace) %{_sysconfdir}/rteval.conf
-%{_datadir}/%{name}/rteval_*.xsl
-%{python_sitelib}/rteval/__init__.py*
-%{python_sitelib}/rteval/rtevalMailer.py*
-%{python_sitelib}/rteval/rtevalReport.py*
-%{python_sitelib}/rteval/xmlout.py*
-%{python_sitelib}/rteval/modules
-%{python_sitelib}/rteval/sysinfo
-/usr/bin/rteval
-
-%changelog
-* Thu Mar 16 2017 Clark Williams <williams@redhat.com> - 2.14-1
-- removed leftover import of systopology from sysinfo
-
-* Wed Mar 15 2017 Clark Williams <williams@redhat.com> - 2.13-2
-- Updated specfile to correct version and bz [1382155]
-
-* Tue Sep 20 2016 Clark Williams <williams@rehdat.com> - 2.12-1
-- handle empty environment variables SUDO_USER and USER [1312057]
-
-* Tue Aug 30 2016 Clark Williams <williams@rehdat.com> - 2.11-1
-- make sure we return non-zero for early exit from tests
-
-* Wed Aug 3 2016 Clark Williams <williams@rehdat.com> - 2.10-1
-- bumped version for RHEL 7.3 release
-
-* Mon May 9 2016 Clark Williams <williams@redhat.com> - 2.9.1
-- default cpulist for modules if only one specified [1333831]
-
-* Tue Apr 26 2016 Clark Williams <williams@redhat.com> - 2.8.1
-- add the --version option to print the rteval version
-- made the --cyclictest-breaktrace option work properly [1209986]
-
-* Fri Apr 1 2016 Clark Williams <williams@redhat.com> - 2.7.1
-- treat SIGINT and SIGTERM as valid end-of-run events [1278757]
-- added cpulist options to man page
-
-* Thu Feb 11 2016 Clark Williams <williams@redhat.com> - 2.6.1
-- update to make --loads-cpulist and --measurement-cpulist work [1306437]
-
-* Thu Dec 10 2015 Clark Williams <williams@refhat.com> - 2.5-1
-- stop using old numactl --cpubind argument
-
-* Wed Dec 9 2015 Clark Williams <williams@refhat.com> - 2.4.2
-- added Require of package numactl
-
-* Tue Nov 17 2015 Clark Williams <williams@refhat.com> - 2.4.1
-- rework hackbench load to not generate cross-node traffic [1282826]
-
-* Wed Aug 12 2015 Clark Williams <williams@redhat.com> - 2.3-1
-- comment out HWLatDetect module from default config [1245699]
-
-* Wed Jun 10 2015 Clark Williams <williams@redhat.com> - 2.2-1
-- add --loads-cpulist and --measurement-cpulist to allow cpu placement [1230401]
-
-* Thu Apr 23 2015 Luis Claudio R. Goncalves <lgoncalv@redhat.com> - 2.1-8
-- load default configs when no config file is specified (Jiri kastner) [1212452]
-
-* Wed Jan 14 2015 Clark Williams <williams@redhat.com> - 2.1-7
-- added requires of bzip2 to specfile [1151567]
-
-* Thu Jan 8 2015 Clark Williams <williams@redhat.com> - 2.1-6
-- cleaned up product documentation [1173315]
-
-* Mon Nov 10 2014 Luis Claudio R. Goncalves <lgoncalv@redhat.com> - 2.1-5
-- rebuild for RHEL-7.1 (1151567)
-
-* Thu Mar 27 2014 Clark Williams <williams@redhat.com> - 2.1-4
-- cherry-picked old commit to deal with installdir problem
-
-* Wed Mar 26 2014 Clark Williams <williams@redhat.com> - 2.1-3
-- added sysstat requires to specfile
-
-* Tue Mar 12 2013 David Sommerseth <davids@redhat.com> - 2.1-2
-- Migrated from libxslt-python to python-lxml
-
-* Fri Jan 18 2013 David Sommerseth <davids@redhat.com> - 2.1-1
-- Made some log lines clearer
-- cyclictest: Added --cyclictest-breaktrace feature
-- cyclictest: Removed --cyclictest-distance option
-- cyclictest: Use a tempfile buffer for cyclictest's stdout data
-- cyclictest: Report if breaktrace was triggered
-- cyclictest: Make the unit test work again
-- cyclictest: Only log and show statistic data when samples are collected
-- Copyright updates
-
-* Thu Jan 17 2013 David Sommerseth <davids@redhat.com> - 2.0.1-1
-- Fix up type casting in the core module code
-- hwlatdetect: Add some more useful debug info
-- Reworked the run logic for modules - allow them to flag they won't run
-- Fixed a few log messages in load modules
-- Add a 30 seconds sleep before unleashing the measurement threads
-
-* Thu Jan 10 2013 David Sommerseth <davids@redhat.com> - 2.0-3
-- Separate out RTEVAL_VERSION into rteval.version, to avoid
- massive BuildRequirements
-
-* Fri Dec 21 2012 David Sommerseth <davids@redhat.com> - 2.0-2
-- Split out common files into rteval-common
-
-* Fri Dec 21 2012 David Sommerseth <davids@redhat.com> - 2.0-1
-- Updated to rteval v2.0 and reworked spec file to use setup.py directly
-
-* Tue Oct 23 2012 Clark Williams <williams@redhat.com> - 1.36-1
-- deal with system not having dmidecode python module
-- make sure to cast priority parameter to int
-- from Raphaël Beamonte <raphael.beamonte@gmail.com>:
- - Rewrite of the get_kthreads method to make it cross-distribution
- - Adds getcmdpath method to use which to locate the used commands
- - Rewrite of the get_services method to make it cross-distribution
-
-* Mon Apr 2 2012 Clark Williams <williams@redhat.com> - 1.35-1
-- fix thinko where SIGINT and SIGTERM handlers were commented out
-
-* Thu Jan 12 2012 Clark Williams <williams@redhat.com> - 1.34-1
-- fix missing config merge in rteval.py to pass parameters
- down to cyclictest
-- modify hackbench to use helper function to start process
-
-* Sat May 14 2011 Clark Williams <williams@redhat.com> - 1.33-1
-- modify hackbench cutoff to be 0.75GB/core
-
-* Mon Aug 23 2010 Clark Williams <williams@redhat.com> - 1.32-1
-- update docs
-- refactor some RTEval methods to utility functions
-- modify hackbench.py not to run under low memory conditions
-- clean up XML generation to deal with new hackbench code
-- clean up XSL code to deal with new XML 'run' attribute
-- from David Sommerseth <davids@redhat.com>:
- - improve CPU socket counting logic
- - delay log directory creation until actually needed
-- from Gowrishankar <gowrishankar.m@in.ibm.com>:
- - check if the core id really exists (multithreading fix)
-
-* Mon Jul 26 2010 Clark Williams <williams@redhat.com> - 1.31-1
-- from David Sommerseth <davids@redhat.com>:
- - Updated hackbench implementation to avoid overusing resources
- - Don't show NUMA node information if it's missing in the summary.xml
- - Show CPU cores properly
-
-* Wed Jul 21 2010 Clark Williams <williams@redhat.com> - 1.30-1
-- added code to hackbench to try to detect and ease memory pressure
-
-* Fri Jul 16 2010 Clark Williams <williams@redhat.com> - 1.29-1
-- fixed incorrect type value in kcompile.py
-
-* Fri Jul 16 2010 Clark Williams <williams@redhat.com> - 1.28-1
-- added logic to loads to adjust number of jobs based on ratio
- of memory per core
-
-* Wed Jul 14 2010 Clark Williams <williams@redhat.com> - 1.27-1
-- modified hackbench to go back to using threads rather than
- processes for units of work
-- added memory size, number of numa nodes and run duration to the
- parameter dictionary passed to all loads and cyclictest
-
-* Tue Jul 13 2010 Clark Williams <williams@redhat.com> - 1.26-1
-- modified hackbench parameters to reduce memory consumption
-
-* Mon Jul 12 2010 Clark Williams <williams@redhat.com> - 1.25-1
-- fixed cyclictest bug that caused everything to be uniprocessor
-- updated source copyrights to 2010
-
-* Fri Jul 9 2010 Clark Williams <williams@redhat.com> - 1.24-1
-- modified hackbench arguments and added new parameters for
- hackbench in rteval.conf
-
-* Thu Jul 8 2010 Clark Williams <williams@redhat.com> - 1.23-1
-- version bump to deal with out-of-sync cvs issue
-
-* Thu Jul 8 2010 Clark Williams <williams@redhat.com> - 1.22-1
-- merged David Sommerseth <davids@redhat.com> changes to use
- hackbench from rt-tests packages rather than carry local copy
-- converted all loads and cyclictest to pass __init__ parameters
- in a dictionary rather than as discrete parameters
-- added logging for load output
-
-* Tue Apr 13 2010 Clark Williams <williams@redhat.com> - 1.21-1
-- from Luis Claudio Goncalves <lgoncalv@redhat.com>:
- - remove unecessary wait() call in cyclictest.py
- - close /dev/null after using it
- - call subprocess.wait() when needed
- - remove delayloop code in hackbench.py
-- from David Sommerseth <davids@redhat.com>:
- - add SIGINT handler
- - handle non-root user case
- - process DMI warnings before command line arguments
- - added --annotate feature to rteval
- - updates to xmlrpc code
-
-* Tue Apr 6 2010 Clark Williams <williams@redhat.com> - 1.20-1
-- code fixes from Luis Claudio Goncalves <lgoncalv@redhat.com>
-- from David Sommerseth <davids@redhat.com>:
- - xmlrpc server updates
- - cputopology.py for recording topology in xml
- - added NUMA node recording for run data
- - rpmlint fixes
-- added start of rteval whitepaper in docs dir
-
-* Tue Mar 16 2010 Clark Williams <williams@redhat.com> - 1.19-1
-- add ability for --summarize to read tarfiles
-- from David Sommerseth <davids@redhat.com>
- - gather info about loaded kernel modules for XML file
- - added child tracking to hackbench to prevent zombies
-
-* Tue Feb 16 2010 Clark Williams <williams@redhat.com> - 1.18-1
-- fix usage of python 2.6 features on RHEL5 (python 2.4)
-
-* Tue Feb 16 2010 Clark Williams <williams@redhat.com> - 1.17-1
-- added logic to filter non-printables from service status output
- so that we have legal XML output
-- added logic to hackbench.py to cleanup properly at the end
- of the test
-
-* Thu Feb 11 2010 Clark Williams <williams@redhat.com> - 1.16-1
-- fix errors in show_remaining_time() introduced because
- time values are floats rather than ints
-
-* Thu Feb 11 2010 Clark Williams <williams@redhat.com> - 1.15-1
-- added logic to use --numa and --smp options of new cyclictest
-- added countdown report for time remaining in a run
-
-* Tue Feb 9 2010 Clark Williams <williams@redhat.com> - 1.14-1
-- David Sommerseth <davids@redhat.com>:
- merged XMLReport() changes for hwcert suite
-
-* Tue Dec 22 2009 Clark Williams <williams@redhat.com> - 1.13-1
-- added cyclictest default initializers
-- added sanity checks to statistics reduction code
-- updated release checklist to include origin push
-- updated Makefile clean and help targets
-- davids updates (mainly for v7 integration):
- - Add explicit sys.path directory to the python sitelib+
- '/rteval'
- - Send program arguments via RtEval() constructor
- - Added more DMI data into the summary.xml report
- - Fixed issue with not including all devices in the
- OnBoardDeviceInfo tag
-
-* Thu Dec 3 2009 David Sommerseth <davids@redhat.com> - 1.12-2
-- fixed Makefile and specfile to include and install the
- rteval/rteval_histogram_raw.py source file for gaining
- raw access to histogram data
-- Removed xmlrpc package during merge against master_ipv4 branch
-
-* Wed Nov 25 2009 Clark Williams <williams@redhat.com> - 1.12-1
-- fix incorrect reporting of measurement thread priorities
-
-* Mon Nov 16 2009 Clark Williams <williams@redhat.com> - 1.11-5
-- ensure that no double-slashes ("//") appear in the symlink
- path for /usr/bin/rteval (problem with rpmdiff)
-
-* Tue Nov 10 2009 Clark Williams <williams@redhat.com> - 1.11-4
-- changed symlink back to install and tracked by %%files
-
-* Mon Nov 9 2009 Clark Williams <williams@redhat.com> - 1.11-3
-- changed symlink generation from %%post to %%posttrans
-
-* Mon Nov 9 2009 Clark Williams <williams@redhat.com> - 1.11-2
-- fixed incorrect dependency for libxslt
-
-* Fri Nov 6 2009 Clark Williams <williams@redhat.com> - 1.11-1
-- added base OS info to XML file and XSL report
-- created new package rteval-loads for the load source code
-
-* Wed Nov 4 2009 Clark Williams <williams@redhat.com> - 1.10-1
-- added config file section for cyclictest and two settable
- parameters, buckets and interval
-
-* Thu Oct 29 2009 Clark Williams <williams@redhat.com> - 1.9-1
-- merged davids updates:
- -H option (raw histogram data)
- cleaned up xsl files
- fixed cpu sorting
-
-* Mon Oct 26 2009 David Sommerseth <davids@redhat.com> - 1.8-3
-- Fixed rpmlint complaints
-
-* Mon Oct 26 2009 David Sommerseth <davids@redhat.com> - 1.8-2
-- Added xmlrpc package, containing the XML-RPC mod_python modules
-
-* Tue Oct 20 2009 Clark Williams <williams@redhat.com> - 1.8-1
-- split kcompile and hackbench into sub-packages
-- reworked Makefile (and specfile) install/uninstall logic
-- fixed sysreport incorrect plugin option
-- catch failure when running on root-squashed NFS
-
-* Tue Oct 13 2009 Clark Williams <williams@redhat.com> - 1.7-1
-- added kthread status to xml file
-- merged davids changes for option processing and additions
- to xml summary
-
-* Tue Oct 13 2009 Clark Williams <williams@redhat.com> - 1.6-1
-- changed stat calculation to loop less
-- added methods to grab service and kthread status
-
-* Mon Oct 12 2009 Clark Williams <williams@redhat.com> - 1.5-1
-- changed cyclictest to use less memory when doing statisics
- calculations
-- updated debug output to use module name prefixes
-- changed option processing to only process config file once
-
-* Fri Oct 9 2009 Clark Williams <williams@redhat.com> - 1.4-1
-- changed cyclictest to use histogram rather than sample array
-- calcuated statistics directly from histogram
-- changed sample interval to 100us
-- added -a (affinity) argument to force cpu affinity for
- measurement threads
-
-* Thu Sep 24 2009 David Sommerseth <davids@redhat.com> - 1.3-3
-- Cleaned up the spec file and made rpmlint happy
-
-* Wed Sep 23 2009 David Sommerseth <davids@redhat.com> - 1.3-2
-- Removed version number from /usr/share/rteval path
-
-* Tue Sep 22 2009 Clark Williams <williams@redhat.com> - 1.3-1
-- changes from davids:
- * changed report code to sort by processor id
- * added report submission retry logic
- * added emailer class
-
-* Fri Sep 18 2009 Clark Williams <williams@redhat.com> - 1.2-1
-- added config file handling for modifying load behavior and
- setting defaults
-- added units in report per IBM request
-
-* Wed Aug 26 2009 Clark Williams <williams@redhat.com> - 1.1-2
-- missed a version change in rteval/rteval.py
-
-* Wed Aug 26 2009 Clark Williams <williams@redhat.com> - 1.1-1
-- modified cyclictest.py to start cyclictest threads with a
- 'distance' of zero, meaning they all have the same measurement
- interval
-
-* Tue Aug 25 2009 Clark Williams <williams@redhat.com> - 1.0-1
-- merged davids XMLRPC fixes
-- fixed --workdir option
-- verion bump to 1.0
-
-* Thu Aug 13 2009 Clark Williams <williams@redhat.com> - 0.9-2
-- fixed problem with incorrect version in rteval.py
-
-* Tue Aug 4 2009 Clark Williams <williams@redhat.com> - 0.9-1
-- merged dsommers XMLRPC and database changes
-- Specify minimum python-dmidecode version, which got native XML support
-- Added rteval_dmi.xsl
-- Fixed permission issues in /usr/share/rteval-x.xx
-
-* Wed Jul 22 2009 Clark Williams <williams@redhat.com> - 0.8-1
-- added code to capture clocksource info
-- added code to copy dmesg info to report directory
-- added code to display clocksource info in report
-- added --summarize option to display summary of existing report
-- added helpfile target to Makefile
-
-* Thu Mar 26 2009 Clark Williams <williams@torg> - 0.7-1
-- added require for python-schedutils to specfile
-- added default for cyclictest output file
-- added help parameter to option parser data
-- renamed xml output file to summary.xml
-- added routine to create tarfile of result files
-
-* Wed Mar 18 2009 Clark Williams <williams@torg> - 0.6-6
-- added code to handle binary data coming from DMI tables
-
-* Wed Mar 18 2009 Clark Williams <williams@torg> - 0.6-5
-- fixed logic for locating XSL template (williams)
-- fixed another stupid typo in specfile (williams)
-
-* Wed Mar 18 2009 Clark Williams <williams@torg> - 0.6-4
-- fixed specfile to install rteval_text.xsl in /usr/share directory
-
-* Wed Mar 18 2009 Clark Williams <williams@torg> - 0.6-3
-- added Requires for libxslt-python (williams)
-- fixed race condition in xmlout constructor/destructor (williams)
-
-* Wed Mar 18 2009 Clark Williams <williams@torg> - 0.6-2
-- added Requires for libxslt (williams)
-- fixed stupid typo in rteval/rteval.py (williams)
-
-* Wed Mar 18 2009 Clark Williams <williams@torg> - 0.6-1
-- added xml output logic (williams, dsommers)
-- added xlst template for report generator (dsommers)
-- added dmi/smbios output to report (williams)
-- added __del__ method to hackbench to cleanup after run (williams)
-- modified to always keep run data (williams)
-
-* Fri Feb 20 2009 Clark Williams <williams@torg> - 0.5-1
-- fixed tab/space mix problem
-- added report path line to report
-
-* Fri Feb 20 2009 Clark Williams <williams@torg> - 0.4-1
-- reworked report output
-- handle keyboard interrupt better
-- removed duration mismatch between rteval and cyclictest
-
-* Mon Feb 2 2009 Clark Williams <williams@torg> - 0.3-1
-- initial checkin
--
2.41.0

View File

@ -1,45 +0,0 @@
From a5f3289e2ee6577cbbb78661bea58b821942ba56 Mon Sep 17 00:00:00 2001
From: John Kacur <jkacur@redhat.com>
Date: Thu, 2 May 2024 13:09:01 -0400
Subject: [PATCH 12/13] rteval: Use get instead of setdefault for calculating
range
As Crystal Wood <crwood@redhat.com> points out, there is no
need to setdefault when calculating the range, just use get
if there is no value.
Signed-off-by: John Kacur <jkacur@redhat.com>
---
rteval/modules/measurement/cyclictest.py | 2 +-
rteval/modules/measurement/timerlat.py | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/rteval/modules/measurement/cyclictest.py b/rteval/modules/measurement/cyclictest.py
index 925065367eaf..3301e1b45e11 100644
--- a/rteval/modules/measurement/cyclictest.py
+++ b/rteval/modules/measurement/cyclictest.py
@@ -115,7 +115,7 @@ class RunData:
low = i
break
high = keys[-1]
- while high and self.__samples.setdefault(high, 0) == 0:
+ while high and self.__samples.get(high, 0) == 0:
high -= 1
self.__range = high - low
diff --git a/rteval/modules/measurement/timerlat.py b/rteval/modules/measurement/timerlat.py
index 9fa931043e40..e8345fab1ad7 100644
--- a/rteval/modules/measurement/timerlat.py
+++ b/rteval/modules/measurement/timerlat.py
@@ -106,7 +106,7 @@ class TLRunData:
low = i
break
high = keys[-1]
- while high and self.__samples.setdefault(high, 0) == 0:
+ while high and self.__samples.get(high, 0) == 0:
high -= 1
self.__range = high - low
--
2.44.0

View File

@ -1,45 +0,0 @@
From 0a431278cc681270b54efea4eebce9571c237624 Mon Sep 17 00:00:00 2001
From: John Kacur <jkacur@redhat.com>
Date: Thu, 18 Apr 2024 12:39:33 -0400
Subject: [PATCH 03/13] rteval: cyclictest.py: Fix the description in the xml
report
If the __type is 'system' we should add the description to the xml
The output should be something like this
<system description="(12 cores) Intel(R) Core(TM) i7-9850H CPU @ 2.60GHz">
Before this fix it was
<system description="">
Signed-off-by: John Kacur <jkacur@redhat.com>
---
rteval/modules/measurement/cyclictest.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/rteval/modules/measurement/cyclictest.py b/rteval/modules/measurement/cyclictest.py
index 671426e13c4d..48b86a03cbfc 100644
--- a/rteval/modules/measurement/cyclictest.py
+++ b/rteval/modules/measurement/cyclictest.py
@@ -25,7 +25,7 @@ class RunData:
self.__id = coreid
self.__type = datatype
self.__priority = int(priority)
- self.__description = ''
+ self.description = ''
# histogram of data
self.__samples = {}
self.__numsamples = 0
@@ -130,7 +130,7 @@ class RunData:
def MakeReport(self):
rep_n = libxml2.newNode(self.__type)
if self.__type == 'system':
- rep_n.newProp('description', self.__description)
+ rep_n.newProp('description', self.description)
else:
rep_n.newProp('id', str(self.__id))
rep_n.newProp('priority', str(self.__priority))
--
2.44.0

View File

@ -1,60 +0,0 @@
From 071bd1be404f1b5c71f8b2f2d9fa1a85bd485ce9 Mon Sep 17 00:00:00 2001
From: John Kacur <jkacur@redhat.com>
Date: Thu, 25 Apr 2024 13:48:05 -0400
Subject: [PATCH 05/13] rteval: cyclictest.py: Fix the median calculation
Fix the calculation of the median in rteval for cyclictest
Signed-off-by: John Kacur <jkacur@redhat.com>
---
rteval/modules/measurement/cyclictest.py | 20 ++++++++++++++------
1 file changed, 14 insertions(+), 6 deletions(-)
diff --git a/rteval/modules/measurement/cyclictest.py b/rteval/modules/measurement/cyclictest.py
index 1ba8b8b2323c..cef73abd1b4b 100644
--- a/rteval/modules/measurement/cyclictest.py
+++ b/rteval/modules/measurement/cyclictest.py
@@ -80,26 +80,34 @@ class RunData:
return
self._log(Log.INFO, f"reducing {self.__id}")
- total = 0
+ total = 0 # total number of samples
+ total_us = 0
keys = list(self.__samples.keys())
keys.sort()
- mid = self.__numsamples / 2
+ # if numsamples is odd, then + 1 gives us the actual mid
+ # if numsamples is even, we avg mid and mid + 1, so we actually
+ # want to know mid + 1 since we will combine it with mid and
+ # the lastkey if the last key is at the end of a previous bucket
+ mid = int(self.__numsamples / 2) + 1
# mean, mode, and median
occurances = 0
lastkey = -1
for i in keys:
- if mid > total and mid <= (total + self.__samples[i]):
- if self.__numsamples & 1 and mid == total+1:
+ if mid > total and mid <= total + self.__samples[i]:
+ # Test if numsamples is even and if mid+1 is the next bucket
+ if self.__numsamples & 1 != 0 and mid == total+1:
self.__median = (lastkey + i) / 2
else:
self.__median = i
- total += (i * self.__samples[i])
+ lastkey = i
+ total += self.__samples[i]
+ total_us += (i * self.__samples[i])
if self.__samples[i] > occurances:
occurances = self.__samples[i]
self.__mode = i
- self.__mean = float(total) / float(self.__numsamples)
+ self.__mean = float(total_us) / float(self.__numsamples)
# range
for i in keys:
--
2.44.0

View File

@ -1,32 +0,0 @@
From 6a185e50bb9b0903e034a2361456b5742e60c47b Mon Sep 17 00:00:00 2001
From: John Kacur <jkacur@redhat.com>
Date: Fri, 19 Apr 2024 12:17:31 -0400
Subject: [PATCH 04/13] rteval: cyclictest.py: Remove unused method sample
Remove the unused method sample() in class RunData
Signed-off-by: John Kacur <jkacur@redhat.com>
---
rteval/modules/measurement/cyclictest.py | 6 ------
1 file changed, 6 deletions(-)
diff --git a/rteval/modules/measurement/cyclictest.py b/rteval/modules/measurement/cyclictest.py
index 48b86a03cbfc..1ba8b8b2323c 100644
--- a/rteval/modules/measurement/cyclictest.py
+++ b/rteval/modules/measurement/cyclictest.py
@@ -61,12 +61,6 @@ class RunData:
if value < self.__min:
self.__min = value
- def sample(self, value):
- self.__samples[value] += self.__samples.setdefault(value, 0) + 1
- self.update_max(value)
- self.update_min(value)
- self.__numsamples += 1
-
def bucket(self, index, value):
self.__samples[index] = self.__samples.setdefault(index, 0) + value
if value:
--
2.44.0

View File

@ -1,35 +0,0 @@
From eb344bffd1525bbb8cd95fb4f4501e467cdc21ce Mon Sep 17 00:00:00 2001
From: Crystal Wood <crwood@redhat.com>
Date: Wed, 1 May 2024 15:09:22 -0500
Subject: [PATCH 11/13] rteval: cyclictest.py: reduce: Fix exception with
missing samples
If cyclictest omits a line of zeroes rather than printing it,
__samples[high] will not exist (rather than be zero). Handle this
in preparation for cyclictest doing this.
Note that get() seems more suitable than setdefault(), but the latter
is used in order to match the code in timerlat.py.
Signed-off-by: Crystal Wood <crwood@redhat.com>
Signed-off-by: John Kacur <jkacur@redhat.com>
---
rteval/modules/measurement/cyclictest.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/rteval/modules/measurement/cyclictest.py b/rteval/modules/measurement/cyclictest.py
index cef73abd1b4b..925065367eaf 100644
--- a/rteval/modules/measurement/cyclictest.py
+++ b/rteval/modules/measurement/cyclictest.py
@@ -115,7 +115,7 @@ class RunData:
low = i
break
high = keys[-1]
- while high and self.__samples[high] == 0:
+ while high and self.__samples.setdefault(high, 0) == 0:
high -= 1
self.__range = high - low
--
2.44.0

View File

@ -1,358 +0,0 @@
From 53248cbad7b0b353e31a18b40181f38da0a721aa Mon Sep 17 00:00:00 2001
From: John Kacur <jkacur@redhat.com>
Date: Thu, 25 Apr 2024 13:59:27 -0400
Subject: [PATCH 06/13] rteval: timerlat.py Add statistics and generate xml
This adds calculating statitics such as samples (count), min, max, mean,
median, mode, range, absolute and standard deviations to xml
Currently it combines the kernel thread, IRQs and userspace threads into
one statistic like it does with cyclictest, but in the future we can
separate this out too.
To see this functioning from git, do this,
su -c 'python rteval/modules/measurement/timerlat.py '
Signed-off-by: John Kacur <jkacur@redhat.com>
---
rteval/modules/measurement/timerlat.py | 266 ++++++++++++++++++++++++-
1 file changed, 259 insertions(+), 7 deletions(-)
diff --git a/rteval/modules/measurement/timerlat.py b/rteval/modules/measurement/timerlat.py
index d4e78de8d2a2..9fa931043e40 100644
--- a/rteval/modules/measurement/timerlat.py
+++ b/rteval/modules/measurement/timerlat.py
@@ -8,12 +8,170 @@ import subprocess
import signal
import time
import tempfile
+import math
+import sys
import libxml2
from rteval.Log import Log
from rteval.modules import rtevalModulePrototype
from rteval.systopology import cpuinfo, SysTopology
from rteval.cpulist_utils import expand_cpulist, collapse_cpulist
+class TLRunData:
+ ''' class to store instance data from a timerlat run '''
+ def __init__(self, coreid, datatype, priority, logfnc):
+ self.__id = coreid
+ self.__type = datatype
+ self.__priority = int(priority)
+ self.description = ''
+ self._log = logfnc
+ self.duration = ''
+ # histogram data, irqs, kernel threads and user threads per core
+ self.irqs = {}
+ self.thrs = {}
+ self.usrs = {}
+ self.__samples = {}
+ self.__numsamples = 0
+ self.min = 100000000
+ self.max = 0
+ self.__stddev = 0.0
+ self.__mean = 0.0
+ self.__mode = 0.0
+ self.__median = 0.0
+ self.__range = 0.0
+
+ def update_max(self, value):
+ """ highest bucket with a value """
+ if value > self.max:
+ self.max = value
+
+ def update_min(self, value):
+ """ lowest bucket with a value """
+ if value < self.min:
+ self.min = value
+
+ def bucket(self, index, val1, val2, val3):
+ """ Store results index=bucket number, val1=IRQ, val2=thr, val3=usr """
+ values = val1 + val2 + val3
+ self.__samples[index] = self.__samples.setdefault(index, 0) + values
+ self.irqs[index] = val1
+ self.thrs[index] = val2
+ self.usrs[index] = val3
+ if values:
+ self.update_max(index)
+ self.update_min(index)
+ self.__numsamples += values
+
+ def reduce(self):
+ """ Calculate statistics """
+ # Check to see if we have any samples. If there are 1 or 0, return
+ if self.__numsamples <= 1:
+ self._log(Log.DEBUG, f"skipping {self.__id} ({self.__numsamples} sampples)")
+ self.__mad = 0
+ self.__stddev = 0
+ return
+
+ self._log(Log.INFO, f"reducing {self.__id}")
+ total = 0 # total number of samples
+ total_us = 0
+ keys = list(self.__samples.keys())
+ keys.sort()
+
+ # if numsamples is odd, then + 1 gives us the actual mid
+ # if numsamples is even, we avg mid and mid + 1, so we actually
+ # want to know mid + 1 since we will combine it with mid and
+ # the lastkey if the last key is at the end of a previous bucket
+ mid = int(self.__numsamples / 2) + 1
+
+ # mean, mode and median
+ occurances = 0
+ lastkey = -1
+ for i in keys:
+ if mid > total and mid <= total + self.__samples[i]:
+ # Test if numsamples is even and if mid+1 is the next bucket
+ if self.__numsamples & 1 != 0 and mid == total+1:
+ self.__median = (lastkey + i) / 2
+ else:
+ self.__median = i
+ lastkey = i
+ total += self.__samples[i]
+ total_us += i * self.__samples[i]
+ if self.__samples[i] > occurances:
+ occurances = self.__samples[i]
+ self.__mode = i
+ self.__mean = float(total_us) / float(self.__numsamples)
+
+ # range
+ for i in keys:
+ if self.__samples[i]:
+ low = i
+ break
+ high = keys[-1]
+ while high and self.__samples.setdefault(high, 0) == 0:
+ high -= 1
+ self.__range = high - low
+
+ # Mean Absolute Deviation and Standard Deviation
+ madsum = 0
+ varsum = 0
+ for i in keys:
+ madsum += float(abs(float(i) - self.__mean) * self.__samples[i])
+ varsum += float(((float(i) - self.__mean) ** 2) * self.__samples[i])
+ self.__mad = madsum / self.__numsamples
+ self.__stddev = math.sqrt(varsum / (self.__numsamples - 1))
+
+
+ def MakeReport(self):
+ rep_n = libxml2.newNode(self.__type)
+
+ if self.__type == 'system':
+ rep_n.newProp('description', self.description)
+ else:
+ rep_n.newProp('id', str(self.__id))
+ rep_n.newProp('priority', str(self.__priority))
+
+ stat_n = rep_n.newChild(None, 'statistics', None)
+ stat_n.newTextChild(None, 'samples', str(self.__numsamples))
+
+ if self.__numsamples > 0:
+ n = stat_n.newTextChild(None, 'minimum', str(self.min))
+ n.newProp('unit', 'us')
+
+ n = stat_n.newTextChild(None, 'maximum', str(self.max))
+ n.newProp('unit', 'us')
+
+ n = stat_n.newTextChild(None, 'median', str(self.__median))
+ n.newProp('unit', 'us')
+
+ n = stat_n.newTextChild(None, 'mode', str(self.__mode))
+ n.newProp('unit', 'us')
+
+ n = stat_n.newTextChild(None, 'range', str(self.__range))
+ n.newProp('unit', 'us')
+
+ n = stat_n.newTextChild(None, 'mean', str(self.__mean))
+ n.newProp('unit', 'us')
+
+ n = stat_n.newTextChild(None, 'mean_absolute_deviation', str(self.__mad))
+ n.newProp('unit', 'us')
+
+ n = stat_n.newTextChild(None, 'standard_deviation', str(self.__stddev))
+ n.newProp('unit', 'us')
+
+ hist_n = rep_n.newChild(None, 'histogram', None)
+ hist_n.newProp('nbuckets', str(len(self.__samples)))
+
+ keys = list(self.__samples.keys())
+ keys.sort()
+ for k in keys:
+ if self.__samples[k] == 0:
+ # Don't report buckets without any samples
+ continue
+ b_n = hist_n.newChild(None, 'bucket', None)
+ b_n.newProp('index', str(k))
+ b_n.newProp('value', str(self.__samples[k]))
+
+ return rep_n
+
class Timerlat(rtevalModulePrototype):
""" measurement modules for rteval """
def __init__(self, config, logger=None):
@@ -23,6 +181,8 @@ class Timerlat(rtevalModulePrototype):
self.__numanodes = int(self.__cfg.setdefault('numanodes', 0))
self.__priority = int(self.__cfg.setdefault('priority', 95))
+ default_buckets = ModuleParameters()["buckets"]["default"]
+ self.__buckets = int(self.__cfg.setdefault('buckets', default_buckets))
self.__cpulist = self.__cfg.setdefault('cpulist', "")
self.__cpus = [str(c) for c in expand_cpulist(self.__cpulist)]
@@ -31,6 +191,20 @@ class Timerlat(rtevalModulePrototype):
self.__timerlat_out = None
self.__timerlat_err = None
self.__started = False
+
+ # Create a TLRunData object for each core we'll measure
+ info = cpuinfo()
+ self.__timerlatdata = {}
+ for core in self.__cpus:
+ self.__timerlatdata[core] = TLRunData(core, 'core', self.__priority,
+ logfnc=self._log)
+ self.__timerlatdata[core].description = info[core]['model name']
+
+ # Create a TLRunData object for the overall system
+ self.__timerlatdata['system'] = TLRunData('system', 'system',
+ self.__priority,
+ logfnc=self._log)
+ self.__timerlatdata['system'].description = (f"({self.__numcores} cores) ") + info['0']['model name']
self._log(Log.DEBUG, f"system using {self.__numcores} cpu cores")
@@ -43,6 +217,7 @@ class Timerlat(rtevalModulePrototype):
def _WorkloadPrepare(self):
self.__cmd = ['rtla', 'timerlat', 'hist', '-P', f'f:{int(self.__priority)}', '-u']
self.__cmd.append(f'-c{self.__cpulist}')
+ self.__cmd.append(f'-E{self.__buckets}')
self._log(Log.DEBUG, f'self.__cmd = {self.__cmd}')
self.__timerlat_out = tempfile.SpooledTemporaryFile(mode='w+b')
self.__timerlat_err = tempfile.SpooledTemporaryFile(mode='w+b')
@@ -77,16 +252,82 @@ class Timerlat(rtevalModulePrototype):
os.kill(self.__timerlat_process.pid, signal.SIGINT)
time.sleep(2)
- self._setFinished()
- self.__started = False
-
- def MakeReport(self):
+ # Parse histogram output
self.__timerlat_out.seek(0)
for line in self.__timerlat_out:
line = bytes.decode(line)
- print(line)
+
+ # Skip any blank lines
+ if not line:
+ continue
+
+ if line.startswith('#'):
+ if line.startswith('# Duration:'):
+ duration = line.split()[2]
+ duration += line.split()[3]
+ self.__timerlatdata['system'].duration = duration
+ continue
+ elif line.startswith('Index'):
+ #print(line)
+ continue
+ elif line.startswith('over:'):
+ #print(line)
+ continue
+ elif line.startswith('count:'):
+ #print(line)
+ continue
+ elif line.startswith('min:'):
+ #print(line)
+ continue
+ elif line.startswith('avg:'):
+ #print(line)
+ continue
+ elif line.startswith('max:'):
+ #print(line)
+ continue
+ else:
+ pass
+ #print(line)
+
+ vals = line.split()
+ if not vals:
+ # If we don't have any values, don't try parsing
+ continue
+ try:
+ # The index corresponds to the bucket number
+ index = int(vals[0])
+ except:
+ self._log(Log.DEBUG, f'timerlat: unexpected output: {line}')
+ continue
+
+ for i, core in enumerate(self.__cpus):
+ self.__timerlatdata[core].bucket(index, int(vals[i*3+1]),
+ int(vals[i*3+2]),
+ int(vals[i*3+3]))
+ self.__timerlatdata['system'].bucket(index, int(vals[i*3+1]),
+ int(vals[i*3+2]),
+ int(vals[i*3+3]))
+ # Generate statistics for each RunData object
+ for n in list(self.__timerlatdata.keys()):
+ self.__timerlatdata[n].reduce()
+
self.__timerlat_out.close()
+ self._setFinished()
+ self.__started = False
+
+ def MakeReport(self):
+ rep_n = libxml2.newNode('timerlat')
+ rep_n.newProp('command_line', ' '.join(self.__cmd))
+
+ rep_n.addChild(self.__timerlatdata['system'].MakeReport())
+ for thr in self.__cpus:
+ if str(thr) not in self.__timerlatdata:
+ continue
+ rep_n.addChild(self.__timerlatdata[str(thr)].MakeReport())
+
+ return rep_n
+
def ModuleInfo():
""" Required measurement module information """
@@ -97,7 +338,10 @@ def ModuleParameters():
""" default parameters """
return {"priority": {"descr": "Run rtla timerlat with this priority",
"default": 95,
- "metavar": "PRIO" }
+ "metavar": "PRIO" },
+ "buckets": {"descr": "Number of buckets",
+ "default": 3500,
+ "metavar": "NUM"}
}
def create(params, logger):
@@ -107,6 +351,10 @@ def create(params, logger):
if __name__ == '__main__':
from rteval.rtevalConfig import rtevalConfig
+ if os.getuid() != 0:
+ print("Must be root to run timerlat!")
+ sys.exit(1)
+
l = Log()
l.SetLogVerbosity(Log.INFO|Log.DEBUG|Log.ERR|Log.WARN)
@@ -128,4 +376,8 @@ if __name__ == '__main__':
tl._WorkloadTask()
time.sleep(RUNTIME)
tl._WorkloadCleanup()
- tl.MakeReport()
+ rep_n = tl.MakeReport()
+
+ xml = libxml2.newDoc('1.0')
+ xml.setRootElement(rep_n)
+ xml.saveFormatFileEnc('-', 'UTF-8', 1)
--
2.44.0

View File

@ -1,6 +1,6 @@
Name: rteval Name: rteval
Version: 3.7 Version: 3.8
Release: 6%{?dist} Release: 1%{?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
@ -32,27 +32,6 @@ Requires: dmidecode
BuildArch: noarch BuildArch: noarch
# Patches # Patches
Patch1: rteval-Change-the-default-kernel-for-kcompile.patch
Patch2: rteval-Remove-upstream-spec-file.patch
Patch3: rteval-Makefile-More-rpm-cleanups.patch
Patch4: rteval-Disable-use-of-python-dmidecode.patch
Patch5: rteval-Refactor-collapse_cpulist-in-systopology.patch
Patch6: rteval-Minor-improvements-to-CpuList-class.patch
Patch7: rteval-Convert-CpuList-class-to-a-module.patch
Patch8: rteval-Add-relative-cpulists-for-measurements.patch
Patch9: rteval-Implement-initial-dmidecode-support.patch
Patch10: rteval-Add-relative-cpulists-for-loads.patch
Patch11: rteval-Cyclictest.py-Make-standalone-file-work-again.patch
Patch12: rteval-Add-rtla-timerlat-as-a-measurement-module.patch
Patch13: rteval-cyclictest.py-Fix-the-description-in-the-xml-.patch
Patch14: rteval-cyclictest.py-Remove-unused-method-sample.patch
Patch15: rteval-cyclictest.py-Fix-the-median-calculation.patch
Patch16: rteval-timerlat.py-Add-statistics-and-generate-xml.patch
Patch17: rteval-Add-summary-reporting-for-timerlat.patch
Patch18: rteval-Generate-raw-histogram-data-for-an-existing-t.patch
Patch19: rteval-Make-output-work-with-new-dmiinfo-format.patch
Patch20: rteval-cyclictest.py-reduce-Fix-exception-with-missi.patch
Patch21: rteval-Use-get-instead-of-setdefault-for-calculating.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
@ -65,27 +44,6 @@ to the screen.
%prep %prep
%setup -q %setup -q
%patch 1 -p1
%patch 2 -p1
%patch 3 -p1
%patch 4 -p1
%patch 5 -p1
%patch 6 -p1
%patch 7 -p1
%patch 8 -p1
%patch 9 -p1
%patch 10 -p1
%patch 11 -p1
%patch 12 -p1
%patch 13 -p1
%patch 14 -p1
%patch 15 -p1
%patch 16 -p1
%patch 17 -p1
%patch 18 -p1
%patch 19 -p1
%patch 20 -p1
%patch 21 -p1
%build %build
%{__python3} setup.py build %{__python3} setup.py build
@ -106,6 +64,10 @@ to the screen.
%{_bindir}/rteval %{_bindir}/rteval
%changelog %changelog
* Tue May 07 2024 John Kacur <jkacur@redhat.com> - 3.8-1
- Rebase rteval to upstream rteval-3.8
Resolves: RHEL-30165
* Mon May 06 2024 John Kacur <jkacur@redhat.com> - 3.7-6 * Mon May 06 2024 John Kacur <jkacur@redhat.com> - 3.7-6
- Add timerlat as a measurement module - Add timerlat as a measurement module
Resolves: RHEL-28058 Resolves: RHEL-28058

View File

@ -1,3 +1 @@
SHA512 (rteval-3.7.tar.xz) = f6010fae457144e21b122746808411a6071b0c1db7d763bcf9e409fb570fc542c7463647ded77118534574f8d476f68576902af191a4edf8c296233a63704660 SHA512 (rteval-3.8.tar.xz) = 25426b8f05d517b8b418975ff50bbc18ed406d3945eb0167af8e61687c872044a4fcfe39817f103bd4e2f4490c4613e64bfe28006c360698b039fbb10f1784c0
SHA512 (0001-rteval-Change-the-default-kernel-for-kcompile-to-lin.patch) = e127ed1a3a5c4596597f53eeacdb080dfaa000df86f4bc275dbc58867a3f3bf33c1f476ee56e892aa46039fc0b18d1410b26f5338e309314da8eb7f702088ff9
SHA512 (0002-rteval-Remove-upstream-spec-file.patch) = f240e551028f751ada510e7c6e7e06ffd4a6176c2a815a3d5719e8c33d00e0499bbc7285b99a69eeeabfd51fc23889691b740d40877c07a36d4afc4b9a6beda3