[libevl][PATCH 2/2] tests: sched-quota-accuracy: Add preempting FIFO thread

Jan Kiszka <[email protected]> Sun, 14 Jun 2026 21:37:26 +0200
Newsgroups dev.linux.lists.xenomai
Message-ID <[email protected]>
From: Jan Kiszka <[email protected]>

Test that higher-prio SCHED_FIFO threads do not run on the bill of
SCHED_QUOTA threads and that their accounting is not otherwise
disturbed.

Signed-off-by: Jan Kiszka <[email protected]>
---
 tests/sched-quota-accuracy.c | 55 +++++++++++++++++++++++++++++++-----
 1 file changed, 48 insertions(+), 7 deletions(-)

diff --git a/tests/sched-quota-accuracy.c b/tests/sched-quota-accuracy.c
index 278ff1b..f48f034 100644
--- a/tests/sched-quota-accuracy.c
+++ b/tests/sched-quota-accuracy.c
@@ -34,7 +34,7 @@ static struct quota_thread_desc {
 	pthread_t tid;
 	struct evl_sched_attrs attrs;
 	unsigned long count;
-} threads[MAX_THREADS];
+} threads[MAX_THREADS + 1];
 
 static int nrthreads = 3;
 
@@ -165,6 +165,41 @@ static void *quota_thread(void *arg)
 	return NULL;
 }
 
+static void *disruption_thread(void *arg)
+{
+	int serial = (int)(long)arg;
+	struct quota_thread_desc *t = threads + serial;
+	struct timespec now, to;
+	unsigned long loops;
+	int ret;
+
+	set_thread_affinity();
+
+	loops = crunch_per_sec / 1000; /* yield every 1 ms */
+
+	__Tcall_assert(t->efd, evl_attach_self("disrupt"));
+
+	evl_put_sem(&ready);
+
+	__Tcall_assert(ret, evl_lock_mutex(&lock));
+	for (;;) {
+		if (started)
+			break;
+		__Tcall_assert(ret, evl_wait_event(&barrier, &lock));
+	}
+	__Tcall_assert(ret, evl_unlock_mutex(&lock));
+
+	while (!done) {
+		do_work(loops, &t->count);
+
+		__Tcall_assert(ret, evl_read_clock(EVL_CLOCK_MONOTONIC, &now));
+		timespec_add_ns(&to, &now, 1000000);
+		__Tcall_assert(ret, evl_sleep_until(EVL_CLOCK_MONOTONIC, &to));
+	}
+
+	return NULL;
+}
+
 static void create_quota_thread(int tgid, int serial)
 {
 	struct quota_thread_desc *t = threads + serial;
@@ -175,13 +210,13 @@ static void create_quota_thread(int tgid, int serial)
 	new_thread(&t->tid, SCHED_FIFO, 1, quota_thread, (void *)(long)serial);
 }
 
-static void create_fifo_thread(int serial)
+static void create_fifo_thread(void *(*thread_func)(void *), int serial)
 {
 	struct quota_thread_desc *t = threads + serial;
 
 	t->attrs.sched_policy = SCHED_FIFO;
-	t->attrs.sched_priority = 1;
-	new_thread(&t->tid, SCHED_FIFO, 1, quota_thread, (void *)(long)serial);
+	t->attrs.sched_priority = 2;
+	new_thread(&t->tid, SCHED_FIFO, 2, thread_func, (void *)(long)serial);
 }
 
 static int cleanup_group(void)
@@ -235,6 +270,9 @@ static double run_quota(int quota)
 		__Tcall_assert(ret, evl_get_sem(&ready));
 	}
 
+	create_fifo_thread(disruption_thread, n);
+	__Tcall_assert(ret, evl_get_sem(&ready));
+
 	__Tcall_assert(ret, evl_lock_mutex(&lock));
 	started = true;
 	__Tcall_assert(ret, evl_broadcast_event(&barrier));
@@ -256,6 +294,8 @@ static double run_quota(int quota)
 	for (n = 0; n < nrthreads; n++)
 		pthread_join(threads[n].tid, NULL);
 
+	pthread_join(threads[nrthreads].tid, NULL);
+
 	/*
 	 * Percentage of completion of the SCHED_QUOTA run for the
 	 * given quota value, compared to the calibration run which
@@ -301,7 +341,7 @@ static unsigned long long calibrate(void)
 	crunch_per_sec = (((unsigned long long)count) * ONE_BILLION) / ns;
 
 	for (n = 0; n < nrthreads; n++) {
-		create_fifo_thread(n);
+		create_fifo_thread(quota_thread, n);
 		__Tcall_assert(ret, evl_get_sem(&ready));
 	}
 
@@ -400,12 +440,13 @@ int main(int argc, char *argv[])
 	effective = run_quota(quota);
 
 	if (verbose)	  /* Percentage of quota actually obtained. */
-		do_trace("CPU%d: %d thread%s: cap=%d%%, effective=%.1f%%",
+		do_trace("CPU%d: %d thread%s: cap=%d%%, effective=%.1f%%, disruption=%.1f%%",
 			test_cpu,
 			nrthreads,
 			nrthreads > 1 ?	"s": "",
 			quota,
-			effective);
+			effective,
+			threads[nrthreads].count * 100.0 / loops_per_sec);
 
 	/*
 	 * The accuracy value is the alignment of the observed runtime
-- 
2.47.3