[PATCH 15/23] mcp-server: Add overflow bucket support and cyclictest compatibility

John Kacur <[email protected]>
Newsgroups org.kernel.vger.linux-rt-users
Message-ID <[email protected]>
Add support for the new overflow bucket feature in rteval XML output.
Overflow buckets track latency samples that exceeded the configured
histogram range (--buckets parameter).

Changes to extract_histogram_data():
- Handle overflow buckets to prevent ValueError when parsing
  index="overflow" attributes
- Add cyclictest support (was timerlat-only)
- Track overflow_count and overflow_bucket in extracted data
- Display overflow warnings when samples exceeded histogram range
- Support both system-wide and per-CPU overflow tracking

This fixes crashes when parsing rteval results with overflow samples
and provides visibility into histogram sizing issues.

Assisted-by: Claude:claude-sonnet-4-5
Signed-off-by: John Kacur <[email protected]>
---
 mcp-server/server.py | 55 +++++++++++++++++++++++++++++++++-----------
 1 file changed, 42 insertions(+), 13 deletions(-)

diff --git a/mcp-server/server.py b/mcp-server/server.py
index 6e4599e36eb1..a007c6a7f2f3 100755
--- a/mcp-server/server.py
+++ b/mcp-server/server.py
@@ -193,51 +193,74 @@ def extract_histogram_data(file_path: str) -> dict[str, Any]:
         "per_cpu_histograms": []
     }
 
-    # Extract system-wide histogram
-    timerlat = root.find(".//timerlat")
-    if timerlat is not None:
+    # Extract system-wide histogram - try timerlat first, then cyclictest
+    measurement = root.find(".//timerlat")
+    if measurement is None:
+        measurement = root.find(".//cyclictest")
+
+    if measurement is not None:
         # System-wide histogram is under <system> tag
-        system_elem = timerlat.find("system")
+        system_elem = measurement.find("system")
         system_histogram = None
         if system_elem is not None:
             system_histogram = system_elem.find("histogram")
 
         if system_histogram is not None:
             nbuckets = int(system_histogram.get("nbuckets", "0"))
+            overflow_count = int(system_histogram.get("overflow_count", "0"))
             buckets = []
+            overflow_bucket = None
 
             for bucket in system_histogram.findall("bucket"):
-                index = int(bucket.get("index"))
+                index_str = bucket.get("index")
                 count = int(bucket.get("value"))
-                buckets.append({"latency_us": index, "count": count})
+
+                # Handle overflow bucket specially
+                if index_str == "overflow":
+                    overflow_bucket = {"type": "overflow", "count": count}
+                else:
+                    index = int(index_str)
+                    buckets.append({"latency_us": index, "count": count})
 
             result["system_histogram"] = {
                 "nbuckets": nbuckets,
                 "buckets": buckets,
-                "total_samples": sum(b["count"] for b in buckets)
+                "total_samples": sum(b["count"] for b in buckets),
+                "overflow_count": overflow_count,
+                "overflow_bucket": overflow_bucket
             }
 
         # Extract per-CPU histograms
-        for core in timerlat.findall("core"):
+        for core in measurement.findall("core"):
             core_id = core.get("id")
             priority = core.get("priority")
             histogram = core.find("histogram")
 
             if histogram is not None:
                 nbuckets = int(histogram.get("nbuckets", "0"))
+                overflow_count = int(histogram.get("overflow_count", "0"))
                 buckets = []
+                overflow_bucket = None
 
                 for bucket in histogram.findall("bucket"):
-                    index = int(bucket.get("index"))
+                    index_str = bucket.get("index")
                     count = int(bucket.get("value"))
-                    buckets.append({"latency_us": index, "count": count})
+
+                    # Handle overflow bucket specially
+                    if index_str == "overflow":
+                        overflow_bucket = {"type": "overflow", "count": count}
+                    else:
+                        index = int(index_str)
+                        buckets.append({"latency_us": index, "count": count})
 
                 result["per_cpu_histograms"].append({
                     "cpu_id": core_id,
                     "priority": priority,
                     "nbuckets": nbuckets,
                     "buckets": buckets,
-                    "total_samples": sum(b["count"] for b in buckets)
+                    "total_samples": sum(b["count"] for b in buckets),
+                    "overflow_count": overflow_count,
+                    "overflow_bucket": overflow_bucket
                 })
 
     return result
@@ -1603,7 +1626,11 @@ async def call_tool(name: str, arguments: Any) -> list[TextContent]:
             result += "System-Wide Histogram:\n"
             result += f"  Total Buckets: {sys_hist['nbuckets']}\n"
             result += f"  Total Samples: {sys_hist['total_samples']:,}\n"
-            result += f"  Latency Range: {sys_hist['buckets'][0]['latency_us']} - {sys_hist['buckets'][-1]['latency_us']} µs\n\n"
+            result += f"  Latency Range: {sys_hist['buckets'][0]['latency_us']} - {sys_hist['buckets'][-1]['latency_us']} µs\n"
+            if sys_hist['overflow_count'] > 0:
+                overflow_pct = (sys_hist['overflow_count'] / (sys_hist['total_samples'] + sys_hist['overflow_count'])) * 100
+                result += f"  ⚠️  Overflow Samples: {sys_hist['overflow_count']:,} ({overflow_pct:.3f}%) - exceeded histogram range\n"
+            result += "\n"
 
             # Show top 10 buckets by count
             top_buckets = sorted(sys_hist['buckets'], key=lambda b: b['count'], reverse=True)[:10]
@@ -1620,7 +1647,9 @@ async def call_tool(name: str, arguments: Any) -> list[TextContent]:
                     cpu_id = cpu_hist["cpu_id"]
                     total = cpu_hist["total_samples"]
                     max_lat = cpu_hist["buckets"][-1]["latency_us"] if cpu_hist["buckets"] else 0
-                    result += f"  CPU {cpu_id}: {total:>12,} samples, max latency {max_lat} µs\n"
+                    overflow = cpu_hist["overflow_count"]
+                    overflow_str = f", overflow: {overflow}" if overflow > 0 else ""
+                    result += f"  CPU {cpu_id}: {total:>12,} samples, max latency {max_lat} µs{overflow_str}\n"
 
             return [TextContent(type="text", text=result)]
 
-- 
2.55.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.