[PATCH 2/3] rteval: Add container detection and warning

John Kacur <[email protected]> Tue, 16 Jun 2026 12:30:14 -0400
Newsgroups org.kernel.vger.linux-rt-users
Message-ID <[email protected]>
Detect when rteval is running inside a container and warn the user.
Container environments are unlikely to get the same real-time latency
performance results as bare metal. In addition, depending on how the
container is configured, not everything will work as expected.

The warning appears during rteval startup, is recorded in the log, and
container status is included in the XML report and summary output.

Container detection checks:
- /.dockerenv file presence
- /proc/1/cgroup for docker/lxc/kubepods/libpod
- container environment variable
- KUBERNETES_SERVICE_HOST environment variable
- systemd-detect-virt -c output

Assisted-by: Claude:claude-sonnet-4-5
Signed-off-by: John Kacur <[email protected]>
---
 rteval-cmd                       |  5 +++++
 rteval/rteval_text.xsl           |  4 ++++
 rteval/sysinfo/__init__.py       |  5 ++++-
 rteval/sysinfo/containercheck.py | 24 ++++++++++++++++++++++++
 4 files changed, 37 insertions(+), 1 deletion(-)

diff --git a/rteval-cmd b/rteval-cmd
index c48c3d89b82e..82531e915833 100755
--- a/rteval-cmd
+++ b/rteval-cmd
@@ -34,6 +34,7 @@ from rteval.version import RTEVAL_VERSION
 from rteval.systopology import SysTopology, parse_cpulist_from_config, validate_housekeeping_cpus, validate_core_sharing
 from rteval.modules.loads.kcompile import ModuleParameters
 from rteval.cpulist_utils import CpuList, is_relative, collapse_cpulist
+from rteval.sysinfo import containercheck
 
 def summarize(repfile, xslt):
     """ Summarize an already existing XML report """
@@ -339,6 +340,10 @@ if __name__ == '__main__':
             if hasattr(msrcfg, 'timerlat'):
                 msrcfg.timerlat = None
 
+        # Check if running in a container and warn the user
+        if containercheck.is_container():
+            logger.log(Log.WARN, "rteval is running in a container")
+
         if rtevcfg.noload:
             if rtevcfg.onlyload:
                 # Make up your mind!
diff --git a/rteval/rteval_text.xsl b/rteval/rteval_text.xsl
index 54dc7d2f9a07..da7084289f87 100644
--- a/rteval/rteval_text.xsl
+++ b/rteval/rteval_text.xsl
@@ -122,6 +122,10 @@
     <xsl:value-of select="SystemInfo/uname/baseos|uname/baseos"/>
     <xsl:text>&#10;</xsl:text>
 
+    <xsl:if test="SystemInfo/ContainerInfo/container = 'true'">
+      <xsl:text>   Container:    Running in a container&#10;</xsl:text>
+    </xsl:if>
+
     <xsl:text>   Architecture: </xsl:text>
     <xsl:value-of select="SystemInfo/uname/arch|uname/arch"/>
     <xsl:text>&#10;</xsl:text>
diff --git a/rteval/sysinfo/__init__.py b/rteval/sysinfo/__init__.py
index 56a0c57b2cbc..f23ee5d54958 100644
--- a/rteval/sysinfo/__init__.py
+++ b/rteval/sysinfo/__init__.py
@@ -16,10 +16,11 @@ from rteval.sysinfo.osinfo import OSInfo
 from rteval.sysinfo.newnet import NetworkInfo
 from rteval.sysinfo.cmdline import cmdlineInfo
 from rteval.sysinfo.tuned import TunedInfo
+from rteval.sysinfo.containercheck import ContainerInfo
 from rteval.sysinfo import dmi
 
 class SystemInfo(KernelInfo, SystemServices, dmi.DMIinfo, CPUtopology,
-                 MemoryInfo, OSInfo, NetworkInfo, cmdlineInfo, TunedInfo):
+                 MemoryInfo, OSInfo, NetworkInfo, cmdlineInfo, TunedInfo, ContainerInfo):
     def __init__(self, config, logger=None):
         self.__logger = logger
         KernelInfo.__init__(self, logger=logger)
@@ -30,6 +31,7 @@ class SystemInfo(KernelInfo, SystemServices, dmi.DMIinfo, CPUtopology,
         cmdlineInfo.__init__(self, logger=logger)
         NetworkInfo.__init__(self, logger=logger)
         TunedInfo.__init__(self, logger=logger)
+        ContainerInfo.__init__(self, logger=logger)
 
         # Parse initial DMI decoding errors
         self.ProcessWarnings()
@@ -55,6 +57,7 @@ class SystemInfo(KernelInfo, SystemServices, dmi.DMIinfo, CPUtopology,
         report_n.addChild(dmi.DMIinfo.MakeReport(self))
         report_n.addChild(cmdlineInfo.MakeReport(self))
         report_n.addChild(TunedInfo.MakeReport(self))
+        report_n.addChild(ContainerInfo.MakeReport(self))
 
         return report_n
 
diff --git a/rteval/sysinfo/containercheck.py b/rteval/sysinfo/containercheck.py
index c558ee05dd8c..12d7d1fce3c9 100644
--- a/rteval/sysinfo/containercheck.py
+++ b/rteval/sysinfo/containercheck.py
@@ -8,6 +8,8 @@
 import os
 import re
 import subprocess
+import libxml2
+from rteval.Log import Log
 
 
 def is_container():
@@ -54,6 +56,28 @@ def is_container():
     return False
 
 
+class ContainerInfo:
+    """Class for collecting container information for XML report"""
+    def __init__(self, logger=None):
+        self.__logger = logger
+
+    def __log(self, logtype, msg):
+        if self.__logger:
+            self.__logger.log(logtype, msg)
+
+    def MakeReport(self):
+        """Generate XML report node for container status"""
+        rep_n = libxml2.newNode("ContainerInfo")
+        container_n = libxml2.newNode("container")
+
+        in_container = is_container()
+        container_n.addContent("true" if in_container else "false")
+        self.__log(Log.DEBUG, f"Container detection: {in_container}")
+        rep_n.addChild(container_n)
+
+        return rep_n
+
+
 def unit_test(rootdir):
     """Simple test of container detection"""
     result = is_container()
-- 
2.54.0