diff --git a/rteval-Add-noload-option.patch b/rteval-Add-noload-option.patch new file mode 100644 index 0000000..8a73092 --- /dev/null +++ b/rteval-Add-noload-option.patch @@ -0,0 +1,190 @@ +From 1a76277bc6a5e94d858497fdc8fa721540fa6af7 Mon Sep 17 00:00:00 2001 +From: Crystal Wood +Date: Fri, 19 Jul 2024 14:58:41 -0500 +Subject: [PATCH 5/7] rteval: Add --noload option + +This option allows measurement to be done without any loads. + +Signed-off-by: Crystal Wood +Signed-off-by: John Kacur +--- + doc/rteval.8 | 3 +++ + rteval-cmd | 9 +++++++ + rteval/__init__.py | 54 ++++++++++++++++++++++-------------------- + rteval/rtevalReport.py | 3 ++- + rteval/rteval_text.xsl | 9 ++++++- + 5 files changed, 50 insertions(+), 28 deletions(-) + +diff --git a/doc/rteval.8 b/doc/rteval.8 +index 9e2b377752e5..1981ac7b3913 100644 +--- a/doc/rteval.8 ++++ b/doc/rteval.8 +@@ -108,6 +108,9 @@ Print rteval version and exit. + .TP + .B \-S KERNEL_VERSION, \-\-source\-download=KERNEL_VERSION + download a source kernel from kernel.org and exit ++.TP ++.B \-\-noload ++Only run the measurements (don't run loads) + + .SH GROUP OPTIONS + .TP +diff --git a/rteval-cmd b/rteval-cmd +index 5cb6d7a44523..36b167a034e5 100755 +--- a/rteval-cmd ++++ b/rteval-cmd +@@ -146,6 +146,9 @@ def parse_options(cfg, parser, cmdargs): + parser.add_argument("-S", "--source-download", nargs="*", dest="rteval___srcdownload", + type=str, default=None, metavar="KERNEL_VERSION", + help='download a source kernel from kernel.org and exit') ++ parser.add_argument("--noload", dest="rteval___noload", ++ action="store_true", default=False, ++ help="only run the measurements (don't run loads)") + + + if not cmdargs: +@@ -273,6 +276,12 @@ if __name__ == '__main__': + measuremods.SetupModuleOptions(parser) + cmd_args = parse_options(config, parser, sys.argv[1:]) + ++ if rtevcfg.noload: ++ if rtevcfg.onlyload: ++ # Make up your mind! ++ raise RuntimeError('The --noload and --onlyload options are incompatible.') ++ loadmods = None ++ + # download kernel tarball + if rtevcfg.srcdownload: + logger.log(Log.DEBUG, f"Kernel Version to download = {rtevcfg.srcdownload}") +diff --git a/rteval/__init__.py b/rteval/__init__.py +index 226d14f80f48..4d3e0c23e5ab 100644 +--- a/rteval/__init__.py ++++ b/rteval/__init__.py +@@ -46,9 +46,6 @@ class RtEval(rtevalReport): + if not isinstance(config, rtevalConfig.rtevalConfig): + raise TypeError("config variable is not an rtevalConfig object") + +- if not isinstance(loadmods, LoadModules): +- raise TypeError("loadmods variable is not a LoadModules object") +- + if not isinstance(measuremods, MeasurementModules): + raise TypeError("measuremods variable is not a MeasurementModules object") + +@@ -111,20 +108,21 @@ class RtEval(rtevalReport): + except Exception as err: + raise RuntimeError(f"Cannot create report directory (NFS with rootsquash on?) [{err}]]") + ++ params = {'workdir':self.__rtevcfg.workdir, ++ 'reportdir':self.__reportdir and self.__reportdir or "", ++ 'builddir':builddir, ++ 'srcdir':self.__rtevcfg.srcdir, ++ 'verbose': self.__rtevcfg.verbose, ++ 'debugging': self.__rtevcfg.debugging, ++ 'numcores':self._sysinfo.cpu_getCores(True), ++ 'logging':self.__rtevcfg.logging, ++ 'memsize':self._sysinfo.mem_get_size(), ++ 'numanodes':self._sysinfo.mem_get_numa_nodes(), ++ 'duration': float(self.__rtevcfg.duration), ++ } ++ + if self._loadmods: + self.__logger.log(Log.INFO, "Preparing load modules") +- params = {'workdir':self.__rtevcfg.workdir, +- 'reportdir':self.__reportdir and self.__reportdir or "", +- 'builddir':builddir, +- 'srcdir':self.__rtevcfg.srcdir, +- 'verbose': self.__rtevcfg.verbose, +- 'debugging': self.__rtevcfg.debugging, +- 'numcores':self._sysinfo.cpu_getCores(True), +- 'logging':self.__rtevcfg.logging, +- 'memsize':self._sysinfo.mem_get_size(), +- 'numanodes':self._sysinfo.mem_get_numa_nodes(), +- 'duration': float(self.__rtevcfg.duration), +- } + self._loadmods.Setup(params) + + self.__logger.log(Log.INFO, "Preparing measurement modules") +@@ -144,15 +142,18 @@ class RtEval(rtevalReport): + + print(f"rteval run on {os.uname()[2]} started at {time.asctime()}") + onlinecpus = self._sysinfo.cpu_getCores(True) +- cpulist = self._loadmods._cfg.GetSection("loads").cpulist +- if cpulist: +- print(f"started {self._loadmods.ModulesLoaded()} loads on cores {cpulist}", end=' ') +- else: +- print(f"started {self._loadmods.ModulesLoaded()} loads on {onlinecpus} cores", end=' ') +- if self._sysinfo.mem_get_numa_nodes() > 1: +- print(f" with {self._sysinfo.mem_get_numa_nodes()} numa nodes") +- else: +- print("") ++ if self._loadmods: ++ cpulist = self._loadmods._cfg.GetSection("loads").cpulist ++ if cpulist: ++ print(f"started {self._loadmods.ModulesLoaded()} loads on cores {cpulist}", ++ end=' ') ++ else: ++ print(f"started {self._loadmods.ModulesLoaded()} loads on {onlinecpus} cores", ++ end=' ') ++ if self._sysinfo.mem_get_numa_nodes() > 1: ++ print(f" with {self._sysinfo.mem_get_numa_nodes()} numa nodes") ++ else: ++ print("") + cpulist = self._measuremods._cfg.GetSection("measurement").cpulist + if cpulist: + print(f"started measurement threads on cores {cpulist}") +@@ -192,7 +193,7 @@ class RtEval(rtevalReport): + if threading.active_count() < nthreads: + raise RuntimeError("load thread died!") + +- if not load_avg_checked: ++ if self._loadmods and not load_avg_checked: + self._loadmods.SaveLoadAvg() + load_avg_checked = 5 + else: +@@ -202,7 +203,8 @@ class RtEval(rtevalReport): + left_to_run = stoptime - currtime + self.__show_remaining_time(left_to_run) + rpttime = currtime + report_interval +- print(f"load average: {self._loadmods.GetLoadAvg():.2f}") ++ if self._loadmods: ++ print(f"load average: {self._loadmods.GetLoadAvg():.2f}") + currtime = time.time() + + self.__logger.log(Log.DEBUG, "out of measurement loop") +diff --git a/rteval/rtevalReport.py b/rteval/rtevalReport.py +index 57d99f520f50..7379a7904f3f 100644 +--- a/rteval/rtevalReport.py ++++ b/rteval/rtevalReport.py +@@ -57,7 +57,8 @@ class rtevalReport: + self.__xmlreport.AppendXMLnodes(self._sysinfo.MakeReport()) + + # Add load info +- self.__xmlreport.AppendXMLnodes(self._loadmods.MakeReport()) ++ if self._loadmods: ++ self.__xmlreport.AppendXMLnodes(self._loadmods.MakeReport()) + + # Add measurement data + self.__xmlreport.AppendXMLnodes(self._measuremods.MakeReport()) +diff --git a/rteval/rteval_text.xsl b/rteval/rteval_text.xsl +index b801679abcc5..96846aaf4d54 100644 +--- a/rteval/rteval_text.xsl ++++ b/rteval/rteval_text.xsl +@@ -15,7 +15,14 @@ + + + Loads: +- loads run on cores ++ ++ ++ loads run on cores ++ ++ ++ none ++ ++ + + + Measurement: +-- +2.45.2 + diff --git a/rteval-Enforce-only-one-latency-measurement-module-a.patch b/rteval-Enforce-only-one-latency-measurement-module-a.patch new file mode 100644 index 0000000..ed252bd --- /dev/null +++ b/rteval-Enforce-only-one-latency-measurement-module-a.patch @@ -0,0 +1,84 @@ +From d6f62a5e52843e0b2651268e350a3c0ebe5c543b Mon Sep 17 00:00:00 2001 +From: Crystal Wood +Date: Thu, 20 Jun 2024 21:24:17 -0500 +Subject: [PATCH 4/7] rteval: Enforce only one latency measurement module at a + time + +Latency modules will step on each other's toes if run at the same time +(on the same CPU, though that's an enhancement for later), so only +run one of them. A priority mechanism allows selecting + +Signed-off-by: Crystal Wood +Signed-off-by: John Kacur +--- + rteval/modules/__init__.py | 11 +++++++++++ + rteval/modules/measurement/cyclictest.py | 1 + + rteval/modules/measurement/timerlat.py | 1 + + 3 files changed, 13 insertions(+) + +diff --git a/rteval/modules/__init__.py b/rteval/modules/__init__.py +index de1ddc4628c1..2a4eafae71c7 100644 +--- a/rteval/modules/__init__.py ++++ b/rteval/modules/__init__.py +@@ -40,6 +40,7 @@ class rtevalModulePrototype(threading.Thread): + "finished": threading.Event()} + self._donotrun = False + self._exclusive = False ++ self._latency = False + self.__timestamps = {} + self.__sleeptime = 2.0 + +@@ -67,6 +68,11 @@ class rtevalModulePrototype(threading.Thread): + self._exclusive = True + + ++ def set_latency(self): ++ """ Sets the module as an exclusive latency measurer """ ++ self._latency = True ++ ++ + def set_donotrun(self): + """ set a module's donotrun field to True """ + self._donotrun = True +@@ -412,9 +418,14 @@ class RtEvalModules: + + self._logger.log(Log.INFO, f"Preparing {self._module_type} modules") + exclusive = 0 ++ latency = False + for (modname, mod) in self.__modules: + if mod.is_exclusive() and mod.WorkloadWillRun(): + exclusive += 1 ++ if mod._latency: ++ if latency: ++ raise RuntimeError("More than one exclusive latency test") ++ latency = True + for (modname, mod) in self.__modules: + if exclusive >= 1: + if exclusive != 1: +diff --git a/rteval/modules/measurement/cyclictest.py b/rteval/modules/measurement/cyclictest.py +index 3a34c1b988d6..a9f5b0c4fba7 100644 +--- a/rteval/modules/measurement/cyclictest.py ++++ b/rteval/modules/measurement/cyclictest.py +@@ -216,6 +216,7 @@ class Cyclictest(rtevalModulePrototype): + self.__started = False + self.__cyclicoutput = None + self.__breaktraceval = None ++ self.set_latency() + + + @staticmethod +diff --git a/rteval/modules/measurement/timerlat.py b/rteval/modules/measurement/timerlat.py +index f3bdc7098bc0..e4b80c33552e 100644 +--- a/rteval/modules/measurement/timerlat.py ++++ b/rteval/modules/measurement/timerlat.py +@@ -216,6 +216,7 @@ class Timerlat(rtevalModulePrototype): + 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") ++ self.set_latency() + + + def _WorkloadSetup(self): +-- +2.45.2 + diff --git a/rteval-Fix-default-measurement-config.patch b/rteval-Fix-default-measurement-config.patch new file mode 100644 index 0000000..7cd427a --- /dev/null +++ b/rteval-Fix-default-measurement-config.patch @@ -0,0 +1,42 @@ +From 9a3d515636fcea17690a4639554f8dae5ebd1ca0 Mon Sep 17 00:00:00 2001 +From: Crystal Wood +Date: Fri, 19 Jul 2024 15:02:34 -0500 +Subject: [PATCH 6/7] rteval: Fix default measurement config + +Commit 761741d15d08e ("rteval: rteval-cmd: Some style changes suggested by pylint-3") +accidentally indented the check for missing measurement config, such that +it became part of the missing load conditional. This was harmless if +the cnofig file was missing entirely, but not if the config file +exists but the measurement section is empty. + +Also, remove timerlat from the default as it conflicts with cyclictest, +and we're not quite ready to make timerlat the default. + +Signed-off-by: Crystal Wood +--- + rteval-cmd | 9 ++++----- + 1 file changed, 4 insertions(+), 5 deletions(-) + +diff --git a/rteval-cmd b/rteval-cmd +index 36b167a034e5..19c82a0b64b3 100755 +--- a/rteval-cmd ++++ b/rteval-cmd +@@ -247,11 +247,10 @@ if __name__ == '__main__': + 'hackbench' : 'module', + 'stressng' : 'module'}) + +- if not config.HasSection('measurement'): +- config.AppendConfig('measurement', { +- 'cyclictest' : 'module', +- 'timerlat' : 'module', +- 'sysstat' : 'module'}) ++ if not config.HasSection('measurement'): ++ config.AppendConfig('measurement', { ++ 'cyclictest' : 'module', ++ 'sysstat' : 'module'}) + + # Prepare log levels before loading modules, not to have unwanted log messages + rtevcfg = config.GetSection('rteval') +-- +2.45.2 + diff --git a/rteval-Remove-MeasurementProfile.patch b/rteval-Remove-MeasurementProfile.patch new file mode 100644 index 0000000..44845d4 --- /dev/null +++ b/rteval-Remove-MeasurementProfile.patch @@ -0,0 +1,463 @@ +From 70d84e566ddef917373a5eb20acf9d7cbccb1f97 Mon Sep 17 00:00:00 2001 +From: Crystal Wood +Date: Thu, 20 Jun 2024 21:24:15 -0500 +Subject: [PATCH 2/7] rteval: Remove MeasurementProfile + +Now that the ModuleInfo() flags are gone, remove the remaining infrastructure +around measurement profiles. + +Signed-off-by: Crystal Wood +Signed-off-by: John Kacur +--- + rteval/__init__.py | 25 ++---- + rteval/modules/measurement/__init__.py | 117 ++++--------------------- + rteval/rteval_histogram_raw.xsl | 24 ++--- + rteval/rteval_text.xsl | 41 +++------ + 4 files changed, 54 insertions(+), 153 deletions(-) + +diff --git a/rteval/__init__.py b/rteval/__init__.py +index 4a6883e28e5b..226d14f80f48 100644 +--- a/rteval/__init__.py ++++ b/rteval/__init__.py +@@ -20,7 +20,7 @@ import time + from datetime import datetime + import sysconfig + from rteval.modules.loads import LoadModules +-from rteval.modules.measurement import MeasurementModules, MeasurementProfile ++from rteval.modules.measurement import MeasurementModules + from rteval.rtevalReport import rtevalReport + from rteval.Log import Log + from rteval import rtevalConfig +@@ -131,10 +131,8 @@ class RtEval(rtevalReport): + self._measuremods.Setup(params) + + +- def __RunMeasurementProfile(self, measure_profile): ++ def __RunMeasurement(self): + global earlystop +- if not isinstance(measure_profile, MeasurementProfile): +- raise Exception("measure_profile is not an MeasurementProfile object") + + measure_start = None + try: +@@ -155,15 +153,14 @@ class RtEval(rtevalReport): + print(f" with {self._sysinfo.mem_get_numa_nodes()} numa nodes") + else: + print("") +- cpulist = self._measuremods._MeasurementModules__cfg.GetSection("measurement").cpulist ++ cpulist = self._measuremods._cfg.GetSection("measurement").cpulist + if cpulist: + print(f"started measurement threads on cores {cpulist}") + else: + print(f"started measurement threads on {onlinecpus} cores") + print(f"Run duration: {str(self.__rtevcfg.duration)} seconds") + +- # start the cyclictest thread +- measure_profile.Start() ++ self._measuremods.Start() + + # Unleash the loads and measurement threads + report_interval = int(self.__rtevcfg.report_interval) +@@ -172,7 +169,7 @@ class RtEval(rtevalReport): + nthreads = threading.active_count() + else: + nthreads = None +- measure_profile.Unleash() ++ self._measuremods.Unleash() + measure_start = datetime.now() + + # wait for time to expire or thread to die +@@ -185,7 +182,7 @@ class RtEval(rtevalReport): + load_avg_checked = 5 + while (currtime <= stoptime) and not stopsig.is_set(): + stopsig.wait(min(stoptime - currtime, 60.0)) +- if not measure_profile.isAlive(): ++ if not self._measuremods.isAlive(): + stoptime = currtime + earlystop = True + self.__logger.log(Log.WARN, +@@ -218,7 +215,7 @@ class RtEval(rtevalReport): + + finally: + # stop measurement threads +- measure_profile.Stop() ++ self._measuremods.Stop() + + # stop the loads + if self._loadmods: +@@ -227,7 +224,7 @@ class RtEval(rtevalReport): + print(f"stopping run at {time.asctime()}") + + # wait for measurement modules to finish calculating stats +- measure_profile.WaitForCompletion() ++ self._measuremods.WaitForCompletion() + + return measure_start + +@@ -236,11 +233,7 @@ class RtEval(rtevalReport): + """ Run the full measurement suite with reports """ + global earlystop + rtevalres = 0 +- measure_start = None +- for meas_prf in self._measuremods: +- mstart = self.__RunMeasurementProfile(meas_prf) +- if measure_start is None: +- measure_start = mstart ++ measure_start = self.__RunMeasurement() + + self._report(measure_start, self.__rtevcfg.xslt_report) + if self.__rtevcfg.sysreport: +diff --git a/rteval/modules/measurement/__init__.py b/rteval/modules/measurement/__init__.py +index 7b1d84ef554d..ecadd0885991 100644 +--- a/rteval/modules/measurement/__init__.py ++++ b/rteval/modules/measurement/__init__.py +@@ -8,43 +8,14 @@ from rteval.modules import RtEvalModules, ModuleContainer + from rteval.systopology import parse_cpulist_from_config + import rteval.cpulist_utils as cpulist_utils + +-class MeasurementProfile(RtEvalModules): +- """Keeps and controls all the measurement modules with the same measurement profile""" +- +- def __init__(self, config, modules_root, logger): +- self._module_type = "measurement" +- self._module_config = "measurement" +- self._report_tag = "Profile" +- RtEvalModules.__init__(self, config, modules_root, logger) +- +- +- def ImportModule(self, module): +- "Imports an exported module from a ModuleContainer() class" +- return self._ImportModule(module) +- +- +- def Setup(self, modname): +- "Instantiates and prepares a measurement module" +- +- modobj = self._InstantiateModule(modname, self._cfg.GetSection(modname)) +- self._RegisterModuleObject(modname, modobj) +- +- +-class MeasurementModules: +- """Class which takes care of all measurement modules and groups them into +-measurement profiles, based on their characteristics""" ++class MeasurementModules(RtEvalModules): ++ """Module container for measurement modules""" + + def __init__(self, config, logger): +- self.__cfg = config +- self.__logger = logger +- self.__measureprofiles = [] +- self.__modules_root = "modules.measurement" +- self.__iter_item = None +- +- # Temporary module container, which is used to evalute measurement modules. +- # This will container will be destroyed after Setup() has been called +- self.__container = ModuleContainer(self.__modules_root, self.__logger) +- self.__LoadModules(self.__cfg.GetSection("measurement")) ++ self._module_type = "measurement" ++ self._report_tag = "Measurements" ++ RtEvalModules.__init__(self, config, "modules.measurement", logger) ++ self.__LoadModules(self._cfg.GetSection("measurement")) + + + def __LoadModules(self, modcfg): +@@ -54,37 +25,28 @@ measurement profiles, based on their characteristics""" + # hope to eventually have different kinds but module is only on + # for now (jcw) + if m[1].lower() == 'module': +- self.__container.LoadModule(m[0]) +- +- +- def GetProfile(self): +- "Returns the appropriate MeasurementProfile object, based on the profile type" +- +- for p in self.__measureprofiles: +- return p +- return None +- ++ self._LoadModule(m[0]) + + def SetupModuleOptions(self, parser): + "Sets up all the measurement modules' parameters for the option parser" +- grparser = self.__container.SetupModuleOptions(parser, self.__cfg) ++ grparser = super().SetupModuleOptions(parser) + + # Set up options specific for measurement module group + grparser.add_argument("--measurement-run-on-isolcpus", + dest="measurement___run_on_isolcpus", + action="store_true", +- default=self.__cfg.GetSection("measurement").setdefault("run-on-isolcpus", "false").lower() ++ default=self._cfg.GetSection("measurement").setdefault("run-on-isolcpus", "false").lower() + == "true", + help="Include isolated CPUs in default cpulist") + + + def Setup(self, modparams): +- "Loads all measurement modules and group them into different measurement profiles" ++ "Loads all measurement modules" + + if not isinstance(modparams, dict): + raise TypeError("modparams attribute is not of a dictionary type") + +- modcfg = self.__cfg.GetSection("measurement") ++ modcfg = self._cfg.GetSection("measurement") + cpulist = modcfg.cpulist + run_on_isolcpus = modcfg.run_on_isolcpus + if cpulist is None: +@@ -93,61 +55,20 @@ measurement profiles, based on their characteristics""" + + for (modname, modtype) in modcfg: + if isinstance(modtype, str) and modtype.lower() == 'module': # Only 'module' will be supported (ds) +- self.__container.LoadModule(modname) +- +- # Get the correct measurement profile container for this module +- mp = self.GetProfile() +- if mp is None: +- # If not found, create a new measurement profile +- mp = MeasurementProfile(self.__cfg, +- self.__modules_root, self.__logger) +- self.__measureprofiles.append(mp) +- +- # Export the module imported here and transfer it to the +- # measurement profile +- mp.ImportModule(self.__container.ExportModule(modname)) ++ self._cfg.AppendConfig(modname, modparams) ++ self._cfg.AppendConfig(modname, {'cpulist':cpulist}) ++ self._cfg.AppendConfig(modname, {'run-on-isolcpus':run_on_isolcpus}) + +- # Setup this imported module inside the appropriate measurement profile +- self.__cfg.AppendConfig(modname, modparams) +- self.__cfg.AppendConfig(modname, {'cpulist':cpulist}) +- self.__cfg.AppendConfig(modname, {'run-on-isolcpus':run_on_isolcpus}) +- mp.Setup(modname) +- +- del self.__container ++ modobj = self._InstantiateModule(modname, self._cfg.GetSection(modname)) ++ self._RegisterModuleObject(modname, modobj) + + + def MakeReport(self): +- "Generates an XML report for all measurement profiles" ++ rep_n = super().MakeReport() + +- # Get the reports from all meaurement modules in all measurement profiles +- rep_n = libxml2.newNode("Measurements") +- cpulist = self.__cfg.GetSection("measurement").cpulist +- run_on_isolcpus = self.__cfg.GetSection("measurement").run_on_isolcpus ++ cpulist = self._cfg.GetSection("measurement").cpulist ++ run_on_isolcpus = self._cfg.GetSection("measurement").run_on_isolcpus + cpulist = parse_cpulist_from_config(cpulist, run_on_isolcpus) + rep_n.newProp("measurecpus", cpulist_utils.collapse_cpulist(cpulist)) + +- for mp in self.__measureprofiles: +- mprep_n = mp.MakeReport() +- if mprep_n: +- rep_n.addChild(mprep_n) +- + return rep_n +- +- +- def __iter__(self): +- "Initiates an iteration loop for MeasurementProfile objects" +- +- self.__iter_item = len(self.__measureprofiles) +- return self +- +- +- def __next__(self): +- """Internal Python iterating method, returns the next +-MeasurementProfile object to be processed""" +- +- if self.__iter_item == 0: +- self.__iter_item = None +- raise StopIteration +- +- self.__iter_item -= 1 +- return self.__measureprofiles[self.__iter_item] +diff --git a/rteval/rteval_histogram_raw.xsl b/rteval/rteval_histogram_raw.xsl +index 00b2be34f305..35d8e8461f74 100644 +--- a/rteval/rteval_histogram_raw.xsl ++++ b/rteval/rteval_histogram_raw.xsl +@@ -11,25 +11,25 @@ + core index value + + +- ++ + +- ++ + + +- ++ + +- ++ + + + +- +- +- ++ ++ ++ + + +- +- +- ++ ++ ++ + + + +@@ -38,7 +38,7 @@ + + + +- ++ + + + +@@ -54,7 +54,7 @@ + + + +- ++ + + + +diff --git a/rteval/rteval_text.xsl b/rteval/rteval_text.xsl +index 7ca0ae3a4c66..b801679abcc5 100644 +--- a/rteval/rteval_text.xsl ++++ b/rteval/rteval_text.xsl +@@ -154,8 +154,8 @@ + + + +- +- ++ ++ + =================================================================== + + +@@ -178,21 +178,8 @@ + + + +- +- Measurement profile +- : +- +- With loads, +- Without loads, +- +- +- +- measurements in parallel +- +- +- measurements serialised +- +- ++ ++ Measurements: + + + +@@ -206,7 +193,7 @@ + + + +- ++ + Latency test + + Started: +@@ -238,7 +225,7 @@ + + + +- ++ + CPU core + + Priority: +@@ -251,7 +238,7 @@ + + + +- ++ + Samples: + + +@@ -301,7 +288,7 @@ + + + +- ++ + Latency test + + Started: +@@ -345,7 +332,7 @@ + + + +- ++ + CPU core + + Priority: +@@ -358,7 +345,7 @@ + + + +- ++ + Samples: + + +@@ -409,7 +396,7 @@ + + + +- ++ + Hardware latency detector + + Run duration: +@@ -434,12 +421,12 @@ + + + +- ++ + Hardware latency detector + ** WARNING ** hwlatedect failed to run + + +- ++ + - @ + + +@@ -448,7 +435,7 @@ + + + +- ++ + sysstat measurements + + Started: +-- +2.45.2 + diff --git a/rteval-RtEvalModules-Remove-unused-methods.patch b/rteval-RtEvalModules-Remove-unused-methods.patch new file mode 100644 index 0000000..6c792c1 --- /dev/null +++ b/rteval-RtEvalModules-Remove-unused-methods.patch @@ -0,0 +1,87 @@ +From 7a0bd39fad4fb017f41e32a125e7f4ef4284b8f0 Mon Sep 17 00:00:00 2001 +From: Crystal Wood +Date: Thu, 20 Jun 2024 21:24:16 -0500 +Subject: [PATCH 3/7] rteval: RtEvalModules: Remove unused methods + +With measurement profiles gone, remove methods that no longer have any +users. + +Signed-off-by: Crystal Wood +Signed-off-by: John Kacur +--- + rteval/modules/__init__.py | 37 ------------------------------------- + 1 file changed, 37 deletions(-) + +diff --git a/rteval/modules/__init__.py b/rteval/modules/__init__.py +index 0c0ce7202f77..de1ddc4628c1 100644 +--- a/rteval/modules/__init__.py ++++ b/rteval/modules/__init__.py +@@ -333,36 +333,11 @@ returned when a ModuleContainer object is iterated over""" + self.__modobjects[modname] = modobj + + +- def ExportModule(self, modname, modroot=None): +- "Export module info, used to transfer an imported module to another ModuleContainer" +- if modroot is None: +- modroot = self.__modules_root +- +- mod = f"{modroot}.{modname}" +- return (mod, self.__modsloaded[mod]) +- +- +- def ImportModule(self, module): +- "Imports an exported module from another ModuleContainer" +- (modname, moduleimp) = module +- self.__modsloaded[modname] = moduleimp +- +- + def ModulesLoaded(self): + "Returns number of registered module objects" + return len(self.__modobjects) + + +- def GetModulesList(self): +- "Returns a list of module names" +- return list(self.__modobjects.keys()) +- +- +- def GetNamedModuleObject(self, modname): +- "Looks up a named module and returns its registered module object" +- return self.__modobjects[modname] +- +- + def __iter__(self): + "Initiates the iterating process" + +@@ -406,10 +381,6 @@ class RtEvalModules: + # Export some of the internal module container methods + # Primarily to have better control of the module containers + # iteration API +- def _ImportModule(self, module): +- "Imports a module exported by ModuleContainer::ExportModule()" +- return self.__modules.ImportModule(module) +- + def _InstantiateModule(self, modname, modcfg, modroot=None): + "Imports a module and returns an instantiated object from the module" + return self.__modules.InstantiateModule(modname, modcfg, modroot) +@@ -426,17 +397,9 @@ class RtEvalModules: + "Returns number of imported modules" + return self.__modules.ModulesLoaded() + +- def GetModulesList(self): +- "Returns a list of module names" +- return self.__modules.GetModulesList() +- + def SetupModuleOptions(self, parser): + "Sets up argparse based argument groups for the loaded modules" + return self.__modules.SetupModuleOptions(parser, self._cfg) +- +- def GetNamedModuleObject(self, modname): +- "Returns a list of module names" +- return self.__modules.GetNamedModuleObject(modname) + # End of exports + + +-- +2.45.2 + diff --git a/rteval-measurement-Change-latency-flag-to-latency_te.patch b/rteval-measurement-Change-latency-flag-to-latency_te.patch new file mode 100644 index 0000000..01c2e79 --- /dev/null +++ b/rteval-measurement-Change-latency-flag-to-latency_te.patch @@ -0,0 +1,89 @@ +From 7cb8c1c14569426e867cbdbdb218d1d9bcd4d520 Mon Sep 17 00:00:00 2001 +From: Crystal Wood +Date: Fri, 26 Jul 2024 13:32:37 -0500 +Subject: [PATCH 7/7] rteval: measurement: Change latency flag to latency_test + +As requested by John, change the name of the latency flag to avoid +looking like it holds an actual latency value. + +Signed-off-by: Crystal Wood +Signed-off-by: John Kacur +--- + rteval/modules/__init__.py | 14 +++++++------- + rteval/modules/measurement/cyclictest.py | 2 +- + rteval/modules/measurement/timerlat.py | 2 +- + 3 files changed, 9 insertions(+), 9 deletions(-) + +diff --git a/rteval/modules/__init__.py b/rteval/modules/__init__.py +index 2a4eafae71c7..d7792108d5b8 100644 +--- a/rteval/modules/__init__.py ++++ b/rteval/modules/__init__.py +@@ -40,7 +40,7 @@ class rtevalModulePrototype(threading.Thread): + "finished": threading.Event()} + self._donotrun = False + self._exclusive = False +- self._latency = False ++ self._latency_test = False + self.__timestamps = {} + self.__sleeptime = 2.0 + +@@ -68,9 +68,9 @@ class rtevalModulePrototype(threading.Thread): + self._exclusive = True + + +- def set_latency(self): ++ def set_latency_test(self): + """ Sets the module as an exclusive latency measurer """ +- self._latency = True ++ self._latency_test = True + + + def set_donotrun(self): +@@ -418,14 +418,14 @@ class RtEvalModules: + + self._logger.log(Log.INFO, f"Preparing {self._module_type} modules") + exclusive = 0 +- latency = False ++ latency_test = False + for (modname, mod) in self.__modules: + if mod.is_exclusive() and mod.WorkloadWillRun(): + exclusive += 1 +- if mod._latency: +- if latency: ++ if mod._latency_test: ++ if latency_test: + raise RuntimeError("More than one exclusive latency test") +- latency = True ++ latency_test = True + for (modname, mod) in self.__modules: + if exclusive >= 1: + if exclusive != 1: +diff --git a/rteval/modules/measurement/cyclictest.py b/rteval/modules/measurement/cyclictest.py +index a9f5b0c4fba7..d919058e927f 100644 +--- a/rteval/modules/measurement/cyclictest.py ++++ b/rteval/modules/measurement/cyclictest.py +@@ -216,7 +216,7 @@ class Cyclictest(rtevalModulePrototype): + self.__started = False + self.__cyclicoutput = None + self.__breaktraceval = None +- self.set_latency() ++ self.set_latency_test() + + + @staticmethod +diff --git a/rteval/modules/measurement/timerlat.py b/rteval/modules/measurement/timerlat.py +index e4b80c33552e..92bc07051aa1 100644 +--- a/rteval/modules/measurement/timerlat.py ++++ b/rteval/modules/measurement/timerlat.py +@@ -216,7 +216,7 @@ class Timerlat(rtevalModulePrototype): + 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") +- self.set_latency() ++ self.set_latency_test() + + + def _WorkloadSetup(self): +-- +2.45.2 + diff --git a/rteval-measurement-Remove-ModuleInfo.patch b/rteval-measurement-Remove-ModuleInfo.patch new file mode 100644 index 0000000..0574238 --- /dev/null +++ b/rteval-measurement-Remove-ModuleInfo.patch @@ -0,0 +1,324 @@ +From 5b55c62ff271e9d9278d25f027590aca05bff959 Mon Sep 17 00:00:00 2001 +From: Crystal Wood +Date: Thu, 20 Jun 2024 21:24:14 -0500 +Subject: [PATCH 1/7] rteval: measurement: Remove ModuleInfo() + +All of the measurement modules have identical settings, and the use cases +for deviating seem questionable. While we do have a desire to keep +cyclictest and timerlat from running together, turning off run_parallel +would prevent sysstat from running at the same time. And if there's a +desire to run without loads, that seems like it belongs in the realm of +user configuration, rather than anything inherent to a given measurement +module. + +Any future module flags can be implemented similarly to what is done +in load modules (e.g. set_exclusive). + +Places that checked with_loads now check whether a LoadModules container +is present at all, which can be wired up to a command line option in the +future. + +Signed-off-by: Crystal Wood +Signed-off-by: John Kacur +--- + rteval/__init__.py | 39 ++++++------- + rteval/modules/__init__.py | 13 +---- + rteval/modules/measurement/__init__.py | 73 ++---------------------- + rteval/modules/measurement/cyclictest.py | 5 -- + rteval/modules/measurement/sysstat.py | 7 --- + rteval/modules/measurement/timerlat.py | 5 -- + 6 files changed, 26 insertions(+), 116 deletions(-) + +diff --git a/rteval/__init__.py b/rteval/__init__.py +index 1a61148ef327..4a6883e28e5b 100644 +--- a/rteval/__init__.py ++++ b/rteval/__init__.py +@@ -111,20 +111,21 @@ class RtEval(rtevalReport): + except Exception as err: + raise RuntimeError(f"Cannot create report directory (NFS with rootsquash on?) [{err}]]") + +- self.__logger.log(Log.INFO, "Preparing load modules") +- params = {'workdir':self.__rtevcfg.workdir, +- 'reportdir':self.__reportdir and self.__reportdir or "", +- 'builddir':builddir, +- 'srcdir':self.__rtevcfg.srcdir, +- 'verbose': self.__rtevcfg.verbose, +- 'debugging': self.__rtevcfg.debugging, +- 'numcores':self._sysinfo.cpu_getCores(True), +- 'logging':self.__rtevcfg.logging, +- 'memsize':self._sysinfo.mem_get_size(), +- 'numanodes':self._sysinfo.mem_get_numa_nodes(), +- 'duration': float(self.__rtevcfg.duration), +- } +- self._loadmods.Setup(params) ++ if self._loadmods: ++ self.__logger.log(Log.INFO, "Preparing load modules") ++ params = {'workdir':self.__rtevcfg.workdir, ++ 'reportdir':self.__reportdir and self.__reportdir or "", ++ 'builddir':builddir, ++ 'srcdir':self.__rtevcfg.srcdir, ++ 'verbose': self.__rtevcfg.verbose, ++ 'debugging': self.__rtevcfg.debugging, ++ 'numcores':self._sysinfo.cpu_getCores(True), ++ 'logging':self.__rtevcfg.logging, ++ 'memsize':self._sysinfo.mem_get_size(), ++ 'numanodes':self._sysinfo.mem_get_numa_nodes(), ++ 'duration': float(self.__rtevcfg.duration), ++ } ++ self._loadmods.Setup(params) + + self.__logger.log(Log.INFO, "Preparing measurement modules") + self._measuremods.Setup(params) +@@ -136,13 +137,11 @@ class RtEval(rtevalReport): + raise Exception("measure_profile is not an MeasurementProfile object") + + measure_start = None +- (with_loads, run_parallel) = measure_profile.GetProfile() +- self.__logger.log(Log.INFO, f"Using measurement profile [loads: {with_loads} parallel: {run_parallel}]") + try: + nthreads = 0 + + # start the loads +- if with_loads: ++ if self._loadmods: + self._loadmods.Start() + + print(f"rteval run on {os.uname()[2]} started at {time.asctime()}") +@@ -168,7 +167,7 @@ class RtEval(rtevalReport): + + # Unleash the loads and measurement threads + report_interval = int(self.__rtevcfg.report_interval) +- if with_loads: ++ if self._loadmods: + self._loadmods.Unleash() + nthreads = threading.active_count() + else: +@@ -192,7 +191,7 @@ class RtEval(rtevalReport): + self.__logger.log(Log.WARN, + "Measurement threads did not use the full time slot. Doing a controlled stop.") + +- if with_loads: ++ if nthreads: + if threading.active_count() < nthreads: + raise RuntimeError("load thread died!") + +@@ -222,7 +221,7 @@ class RtEval(rtevalReport): + measure_profile.Stop() + + # stop the loads +- if with_loads: ++ if self._loadmods: + self._loadmods.Stop() + + print(f"stopping run at {time.asctime()}") +diff --git a/rteval/modules/__init__.py b/rteval/modules/__init__.py +index 4330a839db6f..0c0ce7202f77 100644 +--- a/rteval/modules/__init__.py ++++ b/rteval/modules/__init__.py +@@ -269,14 +269,6 @@ reference from the first import""" + return mod + + +- def ModuleInfo(self, modname, modroot=None): +- """Imports a module and calls the modules' ModuleInfo() function and returns +-the information provided by the module""" +- +- mod = self.LoadModule(modname, modroot) +- return mod.ModuleInfo() +- +- + def SetupModuleOptions(self, parser, config): + """Sets up a separate argparse ArgumentGroup per module with its supported parameters""" + +@@ -495,9 +487,8 @@ class RtEvalModules: + + + def Unleash(self): +- """Unleashes all the loaded modules workloads""" ++ """Unleashes all the loaded modules""" + +- # turn loose the loads + nthreads = 0 + self._logger.log(Log.INFO, f"Sending start event to all {self._module_type} modules") + for (modname, mod) in self.__modules: +@@ -508,7 +499,7 @@ class RtEvalModules: + return nthreads + + +- def _isAlive(self): ++ def isAlive(self): + """Returns True if all modules are running""" + + for (modname, mod) in self.__modules: +diff --git a/rteval/modules/measurement/__init__.py b/rteval/modules/measurement/__init__.py +index 43c0fda30ce1..7b1d84ef554d 100644 +--- a/rteval/modules/measurement/__init__.py ++++ b/rteval/modules/measurement/__init__.py +@@ -11,24 +11,13 @@ import rteval.cpulist_utils as cpulist_utils + class MeasurementProfile(RtEvalModules): + """Keeps and controls all the measurement modules with the same measurement profile""" + +- def __init__(self, config, with_load, run_parallel, modules_root, logger): +- self.__with_load = with_load +- self.__run_parallel = run_parallel +- +- # Only used when running modules serialised +- self.__run_serialised_mods = None +- ++ def __init__(self, config, modules_root, logger): + self._module_type = "measurement" + self._module_config = "measurement" + self._report_tag = "Profile" + RtEvalModules.__init__(self, config, modules_root, logger) + + +- def GetProfile(self): +- "Returns the profile characteristic as (with_load, run_parallel)" +- return (self.__with_load, self.__run_parallel) +- +- + def ImportModule(self, module): + "Imports an exported module from a ModuleContainer() class" + return self._ImportModule(module) +@@ -41,54 +30,6 @@ class MeasurementProfile(RtEvalModules): + self._RegisterModuleObject(modname, modobj) + + +- def Unleash(self): +- """Unleashes all the measurement modules""" +- +- if self.__run_parallel: +- # Use the inherrited method if running +- # measurements in parallel +- return RtEvalModules.Unleash(self) +- +- # Get a list of all registered modules, +- # and start the first one +- self.__serialised_mods = self.GetModulesList() +- mod = self.GetNamedModuleObject(self.__serialised_mods[0]) +- mod.setStart() +- return 1 +- +- +- def MakeReport(self): +- "Generates an XML report for all run measurement modules in this profile" +- rep_n = RtEvalModules.MakeReport(self) +- rep_n.newProp("loads", self.__with_load and "1" or "0") +- rep_n.newProp("parallel", self.__run_parallel and "1" or "0") +- return rep_n +- +- +- def isAlive(self): +- """Returns True if all modules which are supposed to run runs""" +- +- if self.__run_parallel: +- return self._isAlive() +- +- if self.__serialised_mods: +- # If running serialised, first check if measurement is still running, +- # if so - return True. +- mod = self.GetNamedModuleObject(self.__serialised_mods[0]) +- if mod.WorkloadAlive(): +- return True +- +- # If not, go to next on the list and kick it off +- self.__serialised_mods.remove(self.__serialised_mods[0]) +- if self.__serialised_mods: +- mod = self.GetNamedModuleObject(self.__serialised_mods[0]) +- mod.setStart() +- return True +- +- # If we've been through everything, nothing is running +- return False +- +- + class MeasurementModules: + """Class which takes care of all measurement modules and groups them into + measurement profiles, based on their characteristics""" +@@ -116,13 +57,11 @@ measurement profiles, based on their characteristics""" + self.__container.LoadModule(m[0]) + + +- def GetProfile(self, with_load, run_parallel): ++ def GetProfile(self): + "Returns the appropriate MeasurementProfile object, based on the profile type" + + for p in self.__measureprofiles: +- mp = p.GetProfile() +- if mp == (with_load, run_parallel): +- return p ++ return p + return None + + +@@ -154,15 +93,13 @@ measurement profiles, based on their characteristics""" + + for (modname, modtype) in modcfg: + if isinstance(modtype, str) and modtype.lower() == 'module': # Only 'module' will be supported (ds) +- # Extract the measurement modules info +- modinfo = self.__container.ModuleInfo(modname) ++ self.__container.LoadModule(modname) + + # Get the correct measurement profile container for this module +- mp = self.GetProfile(modinfo["loads"], modinfo["parallel"]) ++ mp = self.GetProfile() + if mp is None: + # If not found, create a new measurement profile + mp = MeasurementProfile(self.__cfg, +- modinfo["loads"], modinfo["parallel"], + self.__modules_root, self.__logger) + self.__measureprofiles.append(mp) + +diff --git a/rteval/modules/measurement/cyclictest.py b/rteval/modules/measurement/cyclictest.py +index 3301e1b45e11..3a34c1b988d6 100644 +--- a/rteval/modules/measurement/cyclictest.py ++++ b/rteval/modules/measurement/cyclictest.py +@@ -394,11 +394,6 @@ 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", +diff --git a/rteval/modules/measurement/sysstat.py b/rteval/modules/measurement/sysstat.py +index d4646c1646f4..a0efd8953659 100644 +--- a/rteval/modules/measurement/sysstat.py ++++ b/rteval/modules/measurement/sysstat.py +@@ -93,13 +93,6 @@ class sysstat(rtevalModulePrototype): + + + +-def ModuleInfo(): +- # sysstat features - run in parallel with outher measurement modules with loads +- return {"parallel": True, +- "loads": True} +- +- +- + def ModuleParameters(): + return {} # No arguments available + +diff --git a/rteval/modules/measurement/timerlat.py b/rteval/modules/measurement/timerlat.py +index dc6226ccc991..f3bdc7098bc0 100644 +--- a/rteval/modules/measurement/timerlat.py ++++ b/rteval/modules/measurement/timerlat.py +@@ -499,11 +499,6 @@ class Timerlat(rtevalModulePrototype): + return rep_n + + +-def ModuleInfo(): +- """ Required measurement module information """ +- return {"parallel": True, +- "loads": True} +- + def ModuleParameters(): + """ default parameters """ + return {"priority": {"descr": "Run rtla timerlat with this priority", +-- +2.45.2 + diff --git a/rteval.spec b/rteval.spec index 714bdea..920ae47 100644 --- a/rteval.spec +++ b/rteval.spec @@ -1,6 +1,6 @@ Name: rteval Version: 3.8 -Release: 7%{?dist} +Release: 8%{?dist} Summary: Utility to evaluate system suitability for RT Linux Group: Development/Tools @@ -40,6 +40,13 @@ Patch3: rteval-timerlat-Add-timerlat-tracing-to-rteval.patch Patch4: rteval-sysstat-Convert-base64-data-to-text-before-wr.patch Patch5: rteval-Fix-sysreport-traceback-when-utility-sos-not-.patch Patch6: rteval-timerlat-tracing-clean-up.patch +Patch7: rteval-measurement-Remove-ModuleInfo.patch +Patch8: rteval-Remove-MeasurementProfile.patch +Patch9: rteval-RtEvalModules-Remove-unused-methods.patch +Patch10: rteval-Enforce-only-one-latency-measurement-module-a.patch +Patch11: rteval-Add-noload-option.patch +Patch12: rteval-Fix-default-measurement-config.patch +Patch13: rteval-measurement-Change-latency-flag-to-latency_te.patch %description The rteval script is a utility for measuring various aspects of @@ -51,13 +58,7 @@ a statistical analysis of the event response times is done and printed to the screen. %prep -%setup -q -%patch1 -p1 -%patch2 -p1 -%patch3 -p1 -%patch4 -p1 -%patch5 -p1 -%patch6 -p1 +%autosetup -p1 %build %{__python3} setup.py build @@ -78,6 +79,13 @@ to the screen. %{_bindir}/rteval %changelog +* Mon Jul 29 2024 Crystal Wood - 3.8-8 +- Prevent using cyclictest and timerlat and the same time +- Add a --noload option +- Switch to autosetup +Resolves: RHEL-35507 +Resolves: RHEL-50324 + * Mon Jun 24 2024 John Kacur - 3.8-7 - Rename some patches - Add timerlat tracing