Linux Trace Kernel
 help / color / mirror / Atom feed
From: Chaosheng Qu <chaosheng.qu.linux@gmail.com>
To: linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH] rtla: add tests for tracefs instance cleanup
Date: Sat, 17 Oct 2026 20:23:59 +0800	[thread overview]
Message-ID: <20261017122359.402696-1-chaosheng.qu.linux@gmail.com> (raw)

rtla creates a tracefs instance per run (osnoise_top, osnoise_hist,
timerlat_top, timerlat_hist) and is expected to remove it again on the way
out. Nothing verifies that today, so a cleanup regression would only show up
as a confusing failure of the *next* run: tracefs_instance_create() can fail
with -EEXIST, and an interrupted run can leave stale tracer state behind.

tests/engine.sh already works around this by rmdir-ing leftover instances
before every test ("remove any dangling instances created by improperly
exited rtla runs"), which shows the gap is known but untested.

Add a test for the abnormal-exit paths that are actually hit in practice:

  - SIGINT during a run (interactive Ctrl-C)
  - rtla's own -d/--duration timer
  - a failing --on-threshold shell action
  - several interrupted runs in a row, followed by a normal run

These need rtla running in the background while the test signals it, which
engine.sh's check() (a single foreground command) cannot express, so the new
cleanup.t drives a helper script and emits TAP itself.

SIGTERM is covered too, but reported as a TAP TODO comment: rtla installs
handlers for SIGINT and SIGALRM only, so SIGTERM terminates the process
without running the cleanup path and leaks the instance. Keeping it visible
rather than turning it into a pass means a future regression in the paths
that *do* work is still caught. Once SIGTERM is handled, drop the TODO
comment and the case becomes a plain assertion.

The test needs root, tracefs and CONFIG_OSNOISE_TRACER, and skips cleanly
when tracefs is not mounted writable.

Signed-off-by: Chaosheng Qu <chaosheng.qu.linux@gmail.com>
---
 tools/tracing/rtla/tests/cleanup.t            |  55 ++++++
 .../rtla/tests/scripts/check-cleanup.sh       | 187 ++++++++++++++++++
 2 files changed, 242 insertions(+)
 create mode 100755 tools/tracing/rtla/tests/cleanup.t
 create mode 100755 tools/tracing/rtla/tests/scripts/check-cleanup.sh

diff --git a/tools/tracing/rtla/tests/cleanup.t b/tools/tracing/rtla/tests/cleanup.t
new file mode 100755
index 000000000000..46e69c191792
--- /dev/null
+++ b/tools/tracing/rtla/tests/cleanup.t
@@ -0,0 +1,55 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+#
+# Verify that rtla removes the tracefs instance it created on the abnormal
+# exit paths users actually hit:
+#
+#   - SIGINT during a run            (interactive Ctrl-C)
+#   - rtla's own -d/--duration timer
+#   - a failing --on-threshold shell action
+#   - several interrupted runs in a row, followed by a normal run
+#
+# A leaked instance pollutes the next invocation, so this is worth pinning
+# down in CI. The SIGTERM case is reported as a TAP TODO comment because
+# rtla does not install a SIGTERM handler yet.
+source tests/engine.sh
+test_begin
+
+set_timeout 2m
+
+#
+# These cases need to run rtla in the background and signal it, which
+# engine.sh's check() (one foreground command) cannot express.
+#
+run_cleanup_cases() {
+	local helper="$testdir/scripts/check-cleanup.sh"
+	local out rc
+
+	ctr=$((ctr + 1))
+	[ -z "$TEST_COUNT" ] && return
+
+	if [ ! -x "$helper" ]; then
+		echo "not ok $ctr - cleanup helper is not executable"
+		return
+	fi
+
+	out=$("$helper" "$RTLA" 2>&1)
+	rc=$?
+	if [ $rc -eq 0 ]; then
+		# Surface known issues as TAP comments so they stay visible
+		# even when the case passes.
+		printf '%s\n' "$out" | grep '^TODO: ' | while read -r line; do
+			echo "# ${line#TODO: }"
+		done
+		echo "ok $ctr - instances cleaned up on SIGINT, timeout and action failure"
+	else
+		echo "not ok $ctr - instances cleaned up on SIGINT, timeout and action failure"
+		printf '%s\n' "$out" | while read -r line; do
+			echo "# $line"
+		done
+	fi
+}
+
+run_cleanup_cases
+
+test_end
diff --git a/tools/tracing/rtla/tests/scripts/check-cleanup.sh b/tools/tracing/rtla/tests/scripts/check-cleanup.sh
new file mode 100755
index 000000000000..1ead5ce3c517
--- /dev/null
+++ b/tools/tracing/rtla/tests/scripts/check-cleanup.sh
@@ -0,0 +1,187 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+#
+# Verify that rtla removes the tracefs instances it created, even when it is
+# interrupted (SIGINT/SIGTERM), killed by its own timeout, or when a shell
+# action fails.
+#
+# This is a *test* for tools/tracing/rtla; it does not change rtla behaviour.
+#
+# Requires: root, tracefs mounted at /sys/kernel/tracing, CONFIG_OSNOISE_TRACER.
+# Usage: rtla_cleanup_test.sh /path/to/rtla
+
+RTLA=${1:-rtla}
+TRACEFS=/sys/kernel/tracing
+INSTANCES=$TRACEFS/instances
+FAIL=0
+PASS=0
+
+log()  { printf '%s\n' "$*"; }
+pass() { PASS=$((PASS+1)); log "PASS: $*"; }
+fail() { FAIL=$((FAIL+1)); log "FAIL: $*"; }
+todo() { TODO_N=$((TODO_N+1)); log "TODO: $*"; }
+TODO_N=0
+
+cleanup_all() {
+	for i in osnoise_top osnoise_hist timerlat_top timerlat_hist hwnoise_top; do
+		[ -d "$INSTANCES/$i" ] && rmdir "$INSTANCES/$i" 2>/dev/null
+	done
+}
+
+# Wait up to $2 ms for $1 to disappear.
+wait_gone() {
+	_path=$1
+	_ms=${2:-5000}
+	_i=0
+	while [ -d "$_path" ] && [ $_i -lt $_ms ]; do
+		sleep 0.05
+		_i=$((_i+50))
+	done
+	[ ! -d "$_path" ]
+}
+
+# Wait until $1 exists (up to $2 ms).
+wait_present() {
+	_path=$1
+	_ms=${2:-10000}
+	_i=0
+	while [ ! -d "$_path" ] && [ $_i -lt $_ms ]; do
+		sleep 0.05
+		_i=$((_i+50))
+	done
+	[ -d "$_path" ]
+}
+
+check_instances_absent() {
+	_desc=$1
+	_left=""
+	for i in osnoise_top osnoise_hist timerlat_top timerlat_hist; do
+		[ -d "$INSTANCES/$i" ] && _left="$_left $i"
+	done
+	if [ -z "$_left" ]; then
+		pass "$_desc: no leftover instance"
+	else
+		fail "$_desc: leftover instance(s):$_left"
+	fi
+}
+
+if [ ! -d "$INSTANCES" ]; then
+	log "SKIP: tracefs not mounted at $TRACEFS"
+	exit 0
+fi
+
+# ---------------------------------------------------------------------------
+# 1. SIGINT during a long run
+# ---------------------------------------------------------------------------
+cleanup_all
+$RTLA osnoise top -q -d 30s -P F:1 >/dev/null 2>&1 &
+pid=$!
+wait_present "$INSTANCES/osnoise_top" 10000
+sleep 5
+
+if [ ! -d "$INSTANCES/osnoise_top" ]; then
+	fail "SIGINT: instance was never created (rtla did not start?)"
+else
+	pass "SIGINT: instance created while running"
+	kill -INT "$pid" 2>/dev/null
+	wait "$pid" 2>/dev/null
+	if wait_gone "$INSTANCES/osnoise_top"; then
+		pass "SIGINT: instance removed after interrupt"
+	else
+		fail "SIGINT: instance still present after interrupt"
+	fi
+fi
+
+# ---------------------------------------------------------------------------
+# 2. SIGTERM during a long run
+#
+# KNOWN ISSUE (not a test bug): rtla only installs a handler for SIGINT and
+# SIGALRM (src/common.c:set_signals). SIGTERM therefore kills rtla outright,
+# leaving the tracefs instance behind.
+#
+# Record it with TAP "not ok ... # TODO" rather than turning it into a pass:
+# a TODO is still visible in the log, keeps the suite green, and
+# - unlike "pass" - it does not hide a real cleanup regression if the
+#   SIGTERM path ever changes. Remove the TODO directive once rtla handles
+#   SIGTERM.
+# ---------------------------------------------------------------------------
+KNOWN_SIGTERM_LEAK=1
+cleanup_all
+$RTLA osnoise top -q -d 30s -P F:1 >/dev/null 2>&1 &
+pid=$!
+if ! wait_present "$INSTANCES/osnoise_top" 10000; then
+	fail "SIGTERM: instance was never created (rtla did not start)"
+	kill -TERM "$pid" 2>/dev/null
+	wait "$pid" 2>/dev/null
+else
+sleep 1
+
+if ! kill -0 "$pid" 2>/dev/null; then
+	fail "SIGTERM: rtla died before the signal was sent"
+else
+	kill -TERM "$pid" 2>/dev/null
+	wait "$pid" 2>/dev/null
+	if wait_gone "$INSTANCES/osnoise_top"; then
+		pass "SIGTERM: instance removed after terminate"
+	elif [ "$KNOWN_SIGTERM_LEAK" -eq 1 ]; then
+		todo "SIGTERM: instance leaked (rtla has no SIGTERM handler)"
+	else
+		fail "SIGTERM: instance still present after terminate"
+	fi
+fi
+fi
+
+# ---------------------------------------------------------------------------
+# 3. rtla's own -d timeout path
+# ---------------------------------------------------------------------------
+cleanup_all
+$RTLA osnoise top -q -d 2s -P F:1 >/dev/null 2>&1
+rc=$?
+if wait_gone "$INSTANCES/osnoise_top"; then
+	pass "self-timeout: instance removed (exit=$rc)"
+else
+	fail "self-timeout: instance still present (exit=$rc)"
+fi
+
+# ---------------------------------------------------------------------------
+# 4. shell action failure (-a / --on-threshold shell,command=...)
+# ---------------------------------------------------------------------------
+cleanup_all
+$RTLA osnoise top -q -d 5s -P F:1 -r 1000 -S 1 \
+	--on-threshold 'shell,command="/bin/false"' >/dev/null 2>&1
+rc=$?
+if wait_gone "$INSTANCES/osnoise_top"; then
+	pass "action-failure: instance removed (exit=$rc)"
+else
+	fail "action-failure: instance still present (exit=$rc)"
+fi
+
+# ---------------------------------------------------------------------------
+# 5. repeated interrupted runs must not poison the next run
+# ---------------------------------------------------------------------------
+cleanup_all
+for n in 1 2 3; do
+	$RTLA osnoise top -q -d 20s -P F:1 >/dev/null 2>&1 &
+	pid=$!
+	sleep 1
+	kill -INT "$pid" 2>/dev/null
+	wait "$pid" 2>/dev/null
+done
+
+$RTLA osnoise top -q -d 2s -P F:1 >/dev/null 2>&1
+rc=$?
+if [ "$rc" -eq 0 ]; then
+	pass "repeated interrupts: following run still succeeds"
+else
+	fail "repeated interrupts: following run failed (exit=$rc)"
+fi
+if wait_gone "$INSTANCES/osnoise_top"; then
+	pass "repeated interrupts: no leftover instance"
+else
+	fail "repeated interrupts: leftover instance"
+fi
+
+cleanup_all
+log ""
+log "SUMMARY: $PASS passed, $FAIL failed, $TODO_N known issues"
+[ "$FAIL" -eq 0 ]

base-commit: 2f2f7eeef8b0a1a9b9ca998231419873ccae8d4e
-- 
2.43.0


             reply	other threads:[~2026-10-17 12:24 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-17 12:23 Chaosheng Qu [this message]
2026-10-17 12:37 ` [PATCH] rtla: add tests for tracefs instance cleanup sashiko-bot

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261017122359.402696-1-chaosheng.qu.linux@gmail.com \
    --to=chaosheng.qu.linux@gmail.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-trace-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox