From patchwork Mon Jan 13 07:42:31 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gabriele Monaco X-Patchwork-Id: 13936822 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 12AFCE7719F for ; Mon, 13 Jan 2025 07:43:07 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 91CEE6B008A; Mon, 13 Jan 2025 02:43:06 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 8CC556B008C; Mon, 13 Jan 2025 02:43:06 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 795EF6B0092; Mon, 13 Jan 2025 02:43:06 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0015.hostedemail.com [216.40.44.15]) by kanga.kvack.org (Postfix) with ESMTP id 6475F6B008A for ; Mon, 13 Jan 2025 02:43:06 -0500 (EST) Received: from smtpin21.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay04.hostedemail.com (Postfix) with ESMTP id 350F81A1B08 for ; Mon, 13 Jan 2025 07:43:06 +0000 (UTC) X-FDA: 83001637572.21.1492FE9 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by imf08.hostedemail.com (Postfix) with ESMTP id 7ABD5160022 for ; Mon, 13 Jan 2025 07:43:04 +0000 (UTC) Authentication-Results: imf08.hostedemail.com; dkim=pass header.d=redhat.com header.s=mimecast20190719 header.b=AmJbvHjB; spf=pass (imf08.hostedemail.com: domain of gmonaco@redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=gmonaco@redhat.com; dmarc=pass (policy=none) header.from=redhat.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1736754184; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=WrSLXJgkncdYyrYbqneAfqqWPwYyj0iI94Z6Q+w4Jg4=; b=O7O55Ytv6amZRJTWg476O0E60LIsMEA68pzUbh/lw609824EVRyPGvVl7PPNQtH5ZAyRqg Zb28O7aZ7smRB1+kVNj+83W2ls7TMZAUwmfqM9J6rV0jShY0CZv8ReGGwPgEIbXz6x1Mrp 7ue9SqhnFoXAH8abXA6XPmGyS3iqjqM= ARC-Authentication-Results: i=1; imf08.hostedemail.com; dkim=pass header.d=redhat.com header.s=mimecast20190719 header.b=AmJbvHjB; spf=pass (imf08.hostedemail.com: domain of gmonaco@redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=gmonaco@redhat.com; dmarc=pass (policy=none) header.from=redhat.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1736754184; a=rsa-sha256; cv=none; b=WWQb/G44TfYGiwIAvnPveq4qBQbtETZzzn25Y2013fICJaixluHJB++RBfUwmbjz0JC8Yg Cwf4Bm/iE90WzIi0xkzcfBQdFG0JwbwKeYhVP92wF+WtOrYudPe98w1QAgRhvi4EWHFwv/ RErujhDCK6Y7UFmbxeTQKexXg7quDRc= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1736754183; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=WrSLXJgkncdYyrYbqneAfqqWPwYyj0iI94Z6Q+w4Jg4=; b=AmJbvHjBHSl0WvRCwuc8OdTTSVX9FQzvRVuFSmfVCnFziz2RBZv2TkoyzKpUUK5V8O1n0f a3TFkaoS/EBBJRarIB0yTv1iLVt32g+/iXRjd12vQSneflMXU99b2Oavkkxy/6uO621+qt U0luhktpmvxKSLwhGKlxWDsi5De8ItQ= Received: from mx-prod-mc-04.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-12-aWuxDwKKNIuLuC89j4p3NQ-1; Mon, 13 Jan 2025 02:43:01 -0500 X-MC-Unique: aWuxDwKKNIuLuC89j4p3NQ-1 X-Mimecast-MFC-AGG-ID: aWuxDwKKNIuLuC89j4p3NQ Received: from mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.15]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-04.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id A867919560B4; Mon, 13 Jan 2025 07:42:59 +0000 (UTC) Received: from gmonaco-thinkpadt14gen3.rmtit.com (unknown [10.39.192.91]) by mx-prod-int-02.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id 99FFC195608A; Mon, 13 Jan 2025 07:42:56 +0000 (UTC) From: Gabriele Monaco To: Mathieu Desnoyers , Peter Zijlstra , Ingo Molnar , linux-mm@kvack.org, linux-kernel@vger.kernel.org Cc: Juri Lelli , Gabriele Monaco , Shuah Khan Subject: [PATCH v4 3/3] rseq/selftests: Add test for mm_cid compaction Date: Mon, 13 Jan 2025 08:42:31 +0100 Message-ID: <20250113074231.61638-4-gmonaco@redhat.com> In-Reply-To: <20250113074231.61638-1-gmonaco@redhat.com> References: <20250113074231.61638-1-gmonaco@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.15 X-Rspamd-Server: rspam05 X-Stat-Signature: 6po4qhzwzc9bc7h1u71bx3csw8am3ocw X-Rspamd-Queue-Id: 7ABD5160022 X-Rspam-User: X-HE-Tag: 1736754184-893060 X-HE-Meta: U2FsdGVkX19F+GeFcmFMJWMB8FKh2yH31uN8fkhsnzNwWugN7jd4NDoJXfDdzvpj/nMbUvWXus8+BME67RTMeaXALMDrVVy9QlD1LRc0MoKzCeA5h2h24QZ+XaZGMlUdwxTQtLtvF/vqu9kEYsN8hjM+Q8Po20NKxB3zaHRYBdcL+mthKMh1hZBcRHFoTpffDXtX2q4MHm7RVdC/mMCftDeml1We+NkUkYZ8fDJffYXV9fM+Q5yTRXfn/AxMMpWgeTUkS/PfgCmgn2OvrO5WoYypggPgSWMRbyl49JCVP2pEl9UmmYGYQW0Qdf710/SVRXNneqDZNKWm1eg12soFDgBvjw/CmaP3B0Zp1CGyXdbFHq0hrgR9WCLrdzVYG8ElgIQ+CUQXabFTH0RrJpZZWmaIYZyOs4o/onhzCApqNfXWXg3HdR+0yGlGKHE3pmeMC1p1tlY8W3fwMsP1z7Had10Hf2ws5VwMKYI40MOEUgZVCoTBjsuMkw6aECe+gD9qxIK+vzy28b6GoGM+GuZ+phO56Z6xnralOZcl8RuadOm+ilXVMf51zYLvft7NlPQrkh1cysD+NUnvVqKL0srEdr3+REIuLwXjqPSWYZs/fwR430c+sdS1E2JAbgSe3GEsHwftk7TRr1yU3uT01OLGEnaBIIRSkQZ/NzIRl0JMkaaHcyyeVsmdQyQZS/ilG67AUZ/xEF0onu5TmdrUsrjIIwkDJGmDNMeLuJ6gi4f+M7PGSnCAcpOm7f4h220GqxoAg/xoHZESv0F6527Hwh63chpSK7W9dRB0SnScocp9BpGEIeke3qok0SbqHPhKeiFwO4mmJowNcJlsEWrdx0x7RwFZIRKdeZhtfAgS4a3pRD3hKhHV7B92PICE3p5eaVcjFIS7SRdAGQNFp9sUktKvnay53uo16qp914TPve1mw7VBn2vYxarFBte0LVBUL3uj8BEMzjdB1fsMv7P1CDr 7mL6o8Qv nYrVlXl6HmL9UlpwmmzxDWDxn48TM1WTYqCK4HzABM8O6F8g8zIUgi/Fznkf6wskGjJbzPWcvMb3xOETjrTjrta3nA1HERvATUZLX9AZmTaPvun/n3JFciLscjouZAjS1E79l0g0sxVBAtuexQToIxwLyW7N8YCKK9XN2Ortn9h0uPhoBPUfnx3jV/J7S4MXBhKsVMd8SpEQJtUSQ6CiBvbyq7HavUnS6XCUp/jjTr+Rp3rzMmLYlSXyPh/z6TdZrHtzTquOOtTalWuGpo8L4cN4dOvozbr08hPMqXLsWJ8WeLlUPf/zI4kGzMQy10PhVxOgrEWn6iYLMlg+uDflXpAfoMOt0Was5wE5oBiHSUHr9xwsK2AOf/bUFa8t01Plpb0k6L7Vfo9GBKhYZ1DImkcb6A5l4u2nG4FISXg7TyxvmWBXUkk43nR2utsuUwk4h98ow X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: A task in the kernel (task_mm_cid_work) runs somewhat periodically to compact the mm_cid for each process. Add a test to validate that it runs correctly and timely. The test spawns 1 thread pinned to each CPU, then each thread, including the main one, runs in short bursts for some time. During this period, the mm_cids should be spanning all numbers between 0 and nproc. At the end of this phase, a thread with high enough mm_cid (>= nproc/2) is selected to be the new leader, all other threads terminate. After some time, the only running thread should see 0 as mm_cid, if that doesn't happen, the compaction mechanism didn't work and the test fails. The test never fails if only 1 core is available, in which case, we cannot test anything as the only available mm_cid is 0. To: Mathieu Desnoyers Cc: Shuah Khan Signed-off-by: Gabriele Monaco --- tools/testing/selftests/rseq/.gitignore | 1 + tools/testing/selftests/rseq/Makefile | 2 +- .../selftests/rseq/mm_cid_compaction_test.c | 185 ++++++++++++++++++ 3 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 tools/testing/selftests/rseq/mm_cid_compaction_test.c diff --git a/tools/testing/selftests/rseq/.gitignore b/tools/testing/selftests/rseq/.gitignore index 16496de5f6ce4..2c89f97e4f737 100644 --- a/tools/testing/selftests/rseq/.gitignore +++ b/tools/testing/selftests/rseq/.gitignore @@ -3,6 +3,7 @@ basic_percpu_ops_test basic_percpu_ops_mm_cid_test basic_test basic_rseq_op_test +mm_cid_compaction_test param_test param_test_benchmark param_test_compare_twice diff --git a/tools/testing/selftests/rseq/Makefile b/tools/testing/selftests/rseq/Makefile index 5a3432fceb586..ce1b38f46a355 100644 --- a/tools/testing/selftests/rseq/Makefile +++ b/tools/testing/selftests/rseq/Makefile @@ -16,7 +16,7 @@ OVERRIDE_TARGETS = 1 TEST_GEN_PROGS = basic_test basic_percpu_ops_test basic_percpu_ops_mm_cid_test param_test \ param_test_benchmark param_test_compare_twice param_test_mm_cid \ - param_test_mm_cid_benchmark param_test_mm_cid_compare_twice + param_test_mm_cid_benchmark param_test_mm_cid_compare_twice mm_cid_compaction_test TEST_GEN_PROGS_EXTENDED = librseq.so diff --git a/tools/testing/selftests/rseq/mm_cid_compaction_test.c b/tools/testing/selftests/rseq/mm_cid_compaction_test.c new file mode 100644 index 0000000000000..618f874c53905 --- /dev/null +++ b/tools/testing/selftests/rseq/mm_cid_compaction_test.c @@ -0,0 +1,185 @@ +// SPDX-License-Identifier: LGPL-2.1 +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../kselftest.h" +#include "rseq.h" + +#define VERBOSE 0 +#define printf_verbose(fmt, ...) \ + do { \ + if (VERBOSE) \ + printf(fmt, ##__VA_ARGS__); \ + } while (0) + +/* 0.5 s */ +#define RUNNER_PERIOD 500000 +/* Number of runs before we terminate or get the token */ +#define THREAD_RUNS 5 + +/* + * Number of times we check that the mm_cid were compacted. + * Checks are repeated every RUNNER_PERIOD. + */ +#define MM_CID_COMPACT_TIMEOUT 10 + +struct thread_args { + int cpu; + int num_cpus; + pthread_mutex_t *token; + pthread_barrier_t *barrier; + pthread_t *tinfo; + struct thread_args *args_head; +}; + +static void __noreturn *thread_runner(void *arg) +{ + struct thread_args *args = arg; + int i, ret, curr_mm_cid; + cpu_set_t cpumask; + + CPU_ZERO(&cpumask); + CPU_SET(args->cpu, &cpumask); + ret = pthread_setaffinity_np(pthread_self(), sizeof(cpumask), &cpumask); + if (ret) { + errno = ret; + perror("Error: failed to set affinity"); + abort(); + } + pthread_barrier_wait(args->barrier); + + for (i = 0; i < THREAD_RUNS; i++) + usleep(RUNNER_PERIOD); + curr_mm_cid = rseq_current_mm_cid(); + /* + * We select one thread with high enough mm_cid to be the new leader + * all other threads (including the main thread) will terminate. + * After some time, the mm_cid of the only remaining thread should + * converge to 0, if not, the test fails. + */ + if (curr_mm_cid >= args->num_cpus / 2 && + !pthread_mutex_trylock(args->token)) { + printf_verbose( + "cpu%d has mm_cid=%d and will be the new leader.\n", + sched_getcpu(), curr_mm_cid); + for (i = 0; i < args->num_cpus; i++) { + if (args->tinfo[i] == pthread_self()) + continue; + ret = pthread_join(args->tinfo[i], NULL); + if (ret) { + errno = ret; + perror("Error: failed to join thread"); + abort(); + } + } + pthread_barrier_destroy(args->barrier); + free(args->tinfo); + free(args->token); + free(args->barrier); + free(args->args_head); + + for (i = 0; i < MM_CID_COMPACT_TIMEOUT; i++) { + curr_mm_cid = rseq_current_mm_cid(); + printf_verbose("run %d: mm_cid=%d on cpu%d.\n", i, + curr_mm_cid, sched_getcpu()); + if (curr_mm_cid == 0) + exit(EXIT_SUCCESS); + usleep(RUNNER_PERIOD); + } + exit(EXIT_FAILURE); + } + printf_verbose("cpu%d has mm_cid=%d and is going to terminate.\n", + sched_getcpu(), curr_mm_cid); + pthread_exit(NULL); +} + +void test_mm_cid_compaction(void) +{ + cpu_set_t affinity; + int i, j, ret, num_threads; + pthread_t *tinfo; + pthread_mutex_t *token; + pthread_barrier_t *barrier; + struct thread_args *args; + + sched_getaffinity(0, sizeof(affinity), &affinity); + num_threads = CPU_COUNT(&affinity); + tinfo = calloc(num_threads, sizeof(*tinfo)); + if (!tinfo) { + perror("Error: failed to allocate tinfo"); + abort(); + } + args = calloc(num_threads, sizeof(*args)); + if (!args) { + perror("Error: failed to allocate args"); + abort(); + } + token = malloc(sizeof(*token)); + if (!token) { + perror("Error: failed to allocate token"); + abort(); + } + token = malloc(sizeof(*token)); + barrier = malloc(sizeof(*barrier)); + if (!barrier) { + perror("Error: failed to allocate barrier"); + abort(); + } + token = malloc(sizeof(*token)); + if (num_threads == 1) { + fprintf(stderr, "cannot test on a single cpu. " + "Skipping mm_cid_compaction test.\n"); + return; + } + pthread_mutex_init(token, NULL); + ret = pthread_barrier_init(barrier, NULL, num_threads); + if (ret) { + errno = ret; + perror("Error: failed to initialise barrier"); + abort(); + } + for (i = 0, j = 0; i < CPU_SETSIZE && j < num_threads; i++) { + if (!CPU_ISSET(i, &affinity)) + continue; + args[j].num_cpus = num_threads; + args[j].tinfo = tinfo; + args[j].token = token; + args[j].barrier = barrier; + args[j].cpu = i; + args[j].args_head = args; + if (!j) { + /* The first thread is the main one */ + tinfo[0] = pthread_self(); + ++j; + continue; + } + ret = pthread_create(&tinfo[j], NULL, thread_runner, &args[j]); + if (ret) { + errno = ret; + perror("Error: failed to create thread"); + abort(); + } + ++j; + } + printf_verbose("Started %d threads.\n", num_threads); + + /* Also main thread will terminate if it is not selected as leader */ + thread_runner(&args[0]); +} + +int main(int argc, char **argv) +{ + if (!rseq_mm_cid_available()) { + fprintf(stderr, "Error: rseq_mm_cid unavailable\n"); + return -1; + } + test_mm_cid_compaction(); + return 0; +}