Add timerlat as a measurement module

Add timerlat as a measurement module

Resolves: RHEL-28058
Signed-off-by: John Kacur <jkacur@redhat.com>
This commit is contained in:
John Kacur 2024-05-06 17:15:09 -04:00
parent d83dcd1eee
commit 3db03791e8
14 changed files with 1260 additions and 4 deletions

View File

@ -1,6 +1,6 @@
--- !Policy
product_versions:
- rhel-9
- rhel-10
decision_context: osci_compose_gate
rules:
- !PassingTestCaseRule {test_case_name: osci.brew-build.tier0.functional}

View File

@ -0,0 +1,70 @@
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

@ -0,0 +1,189 @@
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

@ -0,0 +1,178 @@
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

@ -0,0 +1,88 @@
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

@ -0,0 +1,69 @@
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

@ -0,0 +1,60 @@
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

@ -0,0 +1,45 @@
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

@ -0,0 +1,45 @@
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

@ -0,0 +1,60 @@
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

@ -0,0 +1,32 @@
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

@ -0,0 +1,35 @@
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

@ -0,0 +1,358 @@
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
Version: 3.7
Release: 5%{?dist}
Release: 6%{?dist}
Summary: Utility to evaluate system suitability for RT Linux
Group: Development/Tools
@ -41,7 +41,18 @@ 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
The rteval script is a utility for measuring various aspects of
@ -63,6 +74,18 @@ to the screen.
%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
%{__python3} setup.py build
@ -83,7 +106,11 @@ to the screen.
%{_bindir}/rteval
%changelog
* Thu Apr 05 2024 Tomas Glozar <tglozar@redhat.com> - 3.7-5
* Mon May 06 2024 John Kacur <jkacur@redhat.com> - 3.7-6
- Add timerlat as a measurement module
Resolves: RHEL-28058
* Thu Apr 04 2024 Tomas Glozar <tglozar@redhat.com> - 3.7-5
- Replace python-dmidecode with initial dmidecode output parsing
Resolves: RHEL-30158