diff mbox series

[2/2] rteval: Add rtla timerlat as a measurement module

Message ID 20240412185052.87056-2-jkacur@redhat.com
State New
Headers show
Series [1/2] rteval: Cyclictest.py: Make standalone file work again | expand

Commit Message

John Kacur April 12, 2024, 6:50 p.m. UTC
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 mbox series

Patch

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()