mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Dylan Yudaken <dyudaken@gmail.com>
To: mathieu.desnoyers@efficios.com, paulmck@kernel.org
Cc: mingo@redhat.com, peterz@infradead.org, juri.lelli@redhat.com,
	vincent.guittot@linaro.org, dietmar.eggemann@arm.com,
	rostedt@goodmis.org, bsegall@google.com, mgorman@suse.de,
	vschneid@redhat.com, shuah@kernel.org,
	linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org,
	Dylan Yudaken <dyudaken@gmail.com>
Subject: [PATCH 2/2] membarrier: self test for cpu specific calls
Date: Thu, 26 Jun 2025 16:52:57 +0100	[thread overview]
Message-ID: <20250626155257.81256-3-dyudaken@gmail.com> (raw)
In-Reply-To: <20250626155257.81256-1-dyudaken@gmail.com>

Add a self test for the cpu specific calls to membarrier.

This works by figuring out the number of interrupts on a given core
before/after calling membarrier(2) to assert that at least some
interrupts have happened.
This feels like it might be a bit flaky if for example the worker
thread was switched out. To mitigate this there are some checks such
as making sure it stays on one core, and also it asserts only 1
interrupt for every 2 calls to membarrier(2)

Signed-off-by: Dylan Yudaken <dyudaken@gmail.com>
---
 tools/testing/selftests/membarrier/.gitignore |   1 +
 tools/testing/selftests/membarrier/Makefile   |   3 +-
 .../membarrier/membarrier_test_expedited.c    | 135 ++++++++++++++++++
 .../membarrier/membarrier_test_impl.h         |   5 +
 4 files changed, 143 insertions(+), 1 deletion(-)
 create mode 100644 tools/testing/selftests/membarrier/membarrier_test_expedited.c

diff --git a/tools/testing/selftests/membarrier/.gitignore b/tools/testing/selftests/membarrier/.gitignore
index f2fbba178601..39cdadb11c01 100644
--- a/tools/testing/selftests/membarrier/.gitignore
+++ b/tools/testing/selftests/membarrier/.gitignore
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 membarrier_test_multi_thread
 membarrier_test_single_thread
+membarrier_test_expedited
diff --git a/tools/testing/selftests/membarrier/Makefile b/tools/testing/selftests/membarrier/Makefile
index fc840e06ff56..f3e7920a900c 100644
--- a/tools/testing/selftests/membarrier/Makefile
+++ b/tools/testing/selftests/membarrier/Makefile
@@ -3,6 +3,7 @@ CFLAGS += -g $(KHDR_INCLUDES)
 LDLIBS += -lpthread
 
 TEST_GEN_PROGS := membarrier_test_single_thread \
-		membarrier_test_multi_thread
+		membarrier_test_multi_thread \
+		membarrier_test_expedited
 
 include ../lib.mk
diff --git a/tools/testing/selftests/membarrier/membarrier_test_expedited.c b/tools/testing/selftests/membarrier/membarrier_test_expedited.c
new file mode 100644
index 000000000000..aaea36381282
--- /dev/null
+++ b/tools/testing/selftests/membarrier/membarrier_test_expedited.c
@@ -0,0 +1,135 @@
+// SPDX-License-Identifier: GPL-2.0
+#define _GNU_SOURCE
+#include <linux/membarrier.h>
+#include <syscall.h>
+#include <stdio.h>
+#include <string.h>
+#include <pthread.h>
+#include <stdatomic.h>
+
+#include "membarrier_test_impl.h"
+
+struct thread_state {
+	atomic_int thread_cpu;
+	atomic_bool end_thread;
+	pthread_mutex_t mutex;
+};
+
+void *test_membarrier_thread(void *arg)
+{
+	struct thread_state *ts = (struct thread_state *)arg;
+
+	ts->thread_cpu = sched_getcpu();
+	pthread_mutex_unlock(&ts->mutex);
+	if (ts->thread_cpu < 0)
+		return 0;
+	while (!ts->end_thread)
+		ts->thread_cpu = sched_getcpu();
+	return NULL;
+}
+
+static long read_interrupts(int cpu)
+{
+	char line[4096];
+	FILE *fp = fopen("/proc/interrupts", "r");
+	long res = 0;
+
+	if (!fp)
+		ksft_exit_fail_msg("unable to open /proc/interrupts\n");
+
+	fgets(line, sizeof(line), fp); /* skip first line */
+	while (fgets(line, sizeof(line), fp) != NULL) {
+		char *save;
+		int next_cpu = 0;
+
+		for (char *token = strtok_r(line, " ", &save); token;
+		     token = strtok_r(NULL, " ", &save)) {
+			if (*token < '0' || *token > '9')
+				continue;
+			if (next_cpu++ == cpu)
+				res += atol(token);
+		}
+	}
+	fclose(fp);
+	return res;
+}
+
+static int test_membarrier(const char *name, int cmd, int register_cmd)
+{
+	int runs = 0;
+	long irq = 0;
+	pthread_t test_thread;
+	int ret = 0;
+
+	struct thread_state ts = { .thread_cpu = -1,
+				   .end_thread = 0,
+				   .mutex = PTHREAD_MUTEX_INITIALIZER };
+	if (sys_membarrier_cpu(cmd, 0) == 0)
+		ksft_exit_fail_msg("%s: expected failure before register\n",
+				   name);
+	if (sys_membarrier(register_cmd, 0) != 0)
+		ksft_exit_fail_msg("%s: unable to register\n", name);
+
+	/* nothing interesting in single processor machines */
+	if (sysconf(_SC_NPROCESSORS_ONLN) == 1)
+		goto success;
+
+	pthread_mutex_lock(&ts.mutex);
+	pthread_create(&test_thread, NULL, test_membarrier_thread, &ts);
+
+	/* wait for thread to start */
+	pthread_mutex_lock(&ts.mutex);
+	pthread_mutex_unlock(&ts.mutex);
+
+	for (int i = 0; i < 1000; i++) {
+		int cpu_start, cpu_end, cpu_this;
+		long irq_start, irq_end;
+
+		cpu_start = ts.thread_cpu;
+		if (cpu_start < 0)
+			ksft_exit_fail_msg("sched_getcpu() failed\n");
+
+		irq_start = read_interrupts(cpu_start);
+		if (sys_membarrier_cpu(cmd, cpu_start))
+			ksft_exit_fail_msg("%s: sys_membarrier failed\n", name);
+		cpu_end = ts.thread_cpu;
+		cpu_this = sched_getcpu();
+
+		/* maybe it was moved to a different cpu, so we cannot trust the irq count */
+		/* If we are on the same cpu we wouldnt expect an interrupt */
+		if (cpu_end != cpu_start || cpu_this == cpu_end)
+			continue;
+		irq_end = read_interrupts(cpu_end);
+		irq += (irq_end - irq_start);
+		runs++;
+	}
+	ts.end_thread = 1;
+	pthread_join(test_thread, NULL);
+
+	if (!runs)
+		ksft_exit_fail_msg("%s: no successful runs\n", name);
+
+	/* Every run should probably have had an interrupt, but use at least half
+	 * to be safe.
+	 */
+	if (irq < runs / 2)
+		ksft_exit_fail_msg("%s: only had %d / %d irqs\n", name, irq,
+				   runs);
+success:
+	ksft_test_result_pass("expedited %s\n", name);
+	return 0;
+}
+
+int main(int argc, char **argv)
+{
+	ksft_print_header();
+	ksft_set_plan(3);
+
+	test_membarrier("EXPEDITED", MEMBARRIER_CMD_PRIVATE_EXPEDITED,
+			MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED);
+	test_membarrier("RSEQ", MEMBARRIER_CMD_PRIVATE_EXPEDITED_RSEQ,
+			MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_RSEQ);
+	test_membarrier("SYNC_CORE", MEMBARRIER_CMD_PRIVATE_EXPEDITED_SYNC_CORE,
+			MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED_SYNC_CORE);
+	ksft_exit_pass();
+}
diff --git a/tools/testing/selftests/membarrier/membarrier_test_impl.h b/tools/testing/selftests/membarrier/membarrier_test_impl.h
index af89855adb7b..c10a8af4612e 100644
--- a/tools/testing/selftests/membarrier/membarrier_test_impl.h
+++ b/tools/testing/selftests/membarrier/membarrier_test_impl.h
@@ -16,6 +16,11 @@ static int sys_membarrier(int cmd, int flags)
 	return syscall(__NR_membarrier, cmd, flags);
 }
 
+static int sys_membarrier_cpu(int cmd, int cpu)
+{
+	return syscall(__NR_membarrier, cmd, MEMBARRIER_CMD_FLAG_CPU, cpu);
+}
+
 static int test_membarrier_get_registrations(int cmd)
 {
 	int ret, flags = 0;
-- 
2.49.0


      parent reply	other threads:[~2025-06-26 15:53 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-06-26 15:52 [PATCH 0/2] membarrier: allow cpu_id to be set on more commands Dylan Yudaken
2025-06-26 15:52 ` [PATCH 1/2] " Dylan Yudaken
2025-06-26 16:07   ` Mathieu Desnoyers
2025-06-26 18:30     ` Dylan
2025-06-26 15:52 ` Dylan Yudaken [this message]

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=20250626155257.81256-3-dyudaken@gmail.com \
    --to=dyudaken@gmail.com \
    --cc=bsegall@google.com \
    --cc=dietmar.eggemann@arm.com \
    --cc=juri.lelli@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=mathieu.desnoyers@efficios.com \
    --cc=mgorman@suse.de \
    --cc=mingo@redhat.com \
    --cc=paulmck@kernel.org \
    --cc=peterz@infradead.org \
    --cc=rostedt@goodmis.org \
    --cc=shuah@kernel.org \
    --cc=vincent.guittot@linaro.org \
    --cc=vschneid@redhat.com \
    /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

all inboxes | Powered by JetHome®