From patchwork Mon Dec 16 13:09:09 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Gabriele Monaco X-Patchwork-Id: 13909719 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 C0711E7717F for ; Mon, 16 Dec 2024 13:10:00 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 550976B0099; Mon, 16 Dec 2024 08:10:00 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 4FEC76B009A; Mon, 16 Dec 2024 08:10:00 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 39FE96B009B; Mon, 16 Dec 2024 08:10:00 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0017.hostedemail.com [216.40.44.17]) by kanga.kvack.org (Postfix) with ESMTP id 1A2F56B0099 for ; Mon, 16 Dec 2024 08:10:00 -0500 (EST) Received: from smtpin09.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay03.hostedemail.com (Postfix) with ESMTP id 9505DA0ECA for ; Mon, 16 Dec 2024 13:09:34 +0000 (UTC) X-FDA: 82900852146.09.3ECA892 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by imf11.hostedemail.com (Postfix) with ESMTP id 04AE140023 for ; Mon, 16 Dec 2024 13:09:05 +0000 (UTC) Authentication-Results: imf11.hostedemail.com; dkim=pass header.d=redhat.com header.s=mimecast20190719 header.b=fbli0Etb; spf=pass (imf11.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=1734354559; 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=uZtDN64Xh2i1EouKa8fldcRUrzUUze6qMnOFRIwRqYA=; b=MNLs1esKPl7znnuyjY27WUz/fRlxe3IkV3NT3bzDWkQz7wz6slp9Gs5z0v/dn25Pf5g2fd NcIrrhLWFvTSzU4d6eiIkJyojTqIaBgOhRIa4vu3wQnCpZmodG+9YhWHKii+8U3RgpsUmE fPIP8Cx7LUhBuhD5euRLaZGTQ24/pnM= ARC-Authentication-Results: i=1; imf11.hostedemail.com; dkim=pass header.d=redhat.com header.s=mimecast20190719 header.b=fbli0Etb; spf=pass (imf11.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=1734354559; a=rsa-sha256; cv=none; b=7pd9y4VcWHVplyZS6th0n2uZQiqbBO2mkDb1Tdzty3BlEaei3dOg5isRR+wcNlZbSyaviI sNwKkyGNNoFjBlr7gbO4fUWsNXkrkQt2WwPvYPpPtr/lXooLC4hY69s5vSjOeLgOwZJ1yg 82sragrVPtGIRsqs/G+73p45i3gj1gs= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1734354572; 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=uZtDN64Xh2i1EouKa8fldcRUrzUUze6qMnOFRIwRqYA=; b=fbli0Etb69xd47RyS7Jvx34l+cvwN+zS0JYqfzeyqmPvxpLa0zJ3IsEnTJ21xAMGC4MGGj UQ6IeuVFaRRDsg2qlG54wsSnH5u4IuecA/a8kTzolY5dZaN6ApksGiTXPR8fODP1Rq4qsi /KwT2t/5h3DudZVg0VARVDvjqZbRfD0= 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-70-MiaLR4PnNt-nwN18nbzrrQ-1; Mon, 16 Dec 2024 08:09:29 -0500 X-MC-Unique: MiaLR4PnNt-nwN18nbzrrQ-1 X-Mimecast-MFC-AGG-ID: MiaLR4PnNt-nwN18nbzrrQ Received: from mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.17]) (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 101CD19560B3; Mon, 16 Dec 2024 13:09:28 +0000 (UTC) Received: from gmonaco-thinkpadt14gen3.rmtit.com (unknown [10.39.193.102]) by mx-prod-int-05.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id E51BA1956052; Mon, 16 Dec 2024 13:09:24 +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 v3 3/3] rseq/selftests: Add test for mm_cid compaction Date: Mon, 16 Dec 2024 14:09:09 +0100 Message-ID: <20241216130909.240042-4-gmonaco@redhat.com> In-Reply-To: <20241216130909.240042-1-gmonaco@redhat.com> References: <20241216130909.240042-1-gmonaco@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.0 on 10.30.177.17 X-Rspamd-Queue-Id: 04AE140023 X-Stat-Signature: xfpmmonr6aawf771afzq7a9kkyjshui7 X-Rspam-User: X-Rspamd-Server: rspam11 X-HE-Tag: 1734354545-840271 X-HE-Meta: U2FsdGVkX1/b40ZG0pJ0ADuS2AvnBlO46d5vqW1HGEbMHuk0Sn4PgtMT7B7T/ZLPHmzLAuOxda3Pc7GI63kFd2hU5BAbEDYPxTk7PsKWQGOqeaxpKTJq7r8OjfZzG1sp0Zvh/S67zZKsMvsCw8XZHPpmCU+JFqfDfylBBf6/SsMpfRB+mYlsH2ryKy8yeXdt7VBLiHxnRJjoCnPgUq++r72tCIJ/AI1i47s439soKZCFTgJmSXHBkbQsZfovvzz/6sd/X7pmnp0z8TS1X69ZpTrh0ATG4VNCdkw+UaixWdxRx3OsTwTEoC/S12utrkK+ekDJPcW/QFkoSVV9DjTJtOLjydNeaEaA9/OaUEvaAGa12qmmaBoZp6w60qStWQHhI/oNlY5osPd0Q/q03RAnlQiichwQ6he14GQT/ZIoAvySLAJqhjBWHELAfHixTz4+kPiAGxJLtcA1xVAZbcTX/5bESI/M+V4X0aPbdCzt8WHNZEfOe33WJehSEowNfwgVltop+sAsizJCHQHzG1ixyxaeiDi6apg4JGbLv4fQDKN3HkhgH7BRgLfwGM0Ev65jBcAmocTx09tKUjdiZwpQC2/b+Wee6ktQOWrJJC2cRBvtQfg1GJjmElYZpb+EB2suhfB12v4InBhI/zr3DMfviw4Ir5h4j3V6tXQqB9O63UxLJR+KjJwyY4IDC+UHtbQTrepFaQNfi554MXwsljd94ZFVFiVVr5JQVw5DD49yK3PgLaMJu9ea7Br+Fqb2QFVBzBkOoCCNLPAlGSDoicUwF4TS3RRF8kx4zcCw+ufizPAZvAis6yVe9UrgvDHqxa1dX+Z0PJFvOP69HMj//O/sMIFKGawEEQPkIJSjhe65EzyHEV2h547uqAP0Wcd+cvJwTdCPFA4Kk6beYS6OmbX5SkwadCqbo0DrelAYDV3FNi+FLQL/KTmaNjTnYAql1HiWjHCRNoC51yZFlsmsYQ3 PtJu32Tj F8zCcKF++vjVT7VJI4XizJlZZwtilFdsZp6vLWbZwNJcs6dNIpuEfA2lsl0Nq5k+Je946zP3MrOqSQ6upyAoBr6IPDi2jzePUI6y5ugzCkf+Hcj4VtBtXWZNew6h1byKTanVX+FzKs9b9VBrbDYg3H7Rwn+Zg5caltGvOpn9u3pjJD+bM6Fwz4e3glDY4Qe1lryAkDkVjTc5kgCI6ys2DwP1b3vBI+aLmj9VGy8wydyAI+N7RIS1yP+cFnOF4LR3v4AZzgHT/gABrUubLJlqVvLkpyxIDUn1kTUEdI/cOw+am+9SG/pY40m69JajgAvOnqKWVurNqXsAllMQfpibW/WTCWl4tUD766oZbbFc5W+o2M1rTBF64iZ9C1vRVDvEONLcbyO01vdZQKZL3O6j2PPCToQt0T5K1yabIoLLeFd4eVWxnUkKucp+5TFtmNF2L4P0tyvwf1QqOKnkdf1xu5v6b2Kmcyh9VpWq7 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, this test tries 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 | 190 ++++++++++++++++++ 3 files changed, 192 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 16496de5f6ce..2c89f97e4f73 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 5a3432fceb58..ce1b38f46a35 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 000000000000..e5557b38a4e9 --- /dev/null +++ b/tools/testing/selftests/rseq/mm_cid_compaction_test.c @@ -0,0 +1,190 @@ +// 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_t *tinfo; + struct thread_args *args_head; +}; + +static void *thread_runner(void *arg) +{ + struct thread_args *args = arg; + int i, ret, curr_mm_cid; + cpu_set_t affinity; + + CPU_ZERO(&affinity); + CPU_SET(args->cpu, &affinity); + ret = pthread_setaffinity_np(pthread_self(), sizeof(affinity), &affinity); + if (ret) { + fprintf(stderr, + "Error: failed to set affinity to thread %d (%d): %s\n", + args->cpu, ret, strerror(ret)); + assert(ret == 0); + } + 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 %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) { + fprintf(stderr, + "Error: failed to join thread %d (%d): %s\n", + i, ret, strerror(ret)); + assert(ret == 0); + } + } + free(args->tinfo); + free(args->token); + 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) { + printf_verbose( + "mm_cids successfully compacted, exiting\n"); + pthread_exit(NULL); + } + usleep(RUNNER_PERIOD); + } + assert(false); + } + printf_verbose("cpu%d has %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; + struct thread_args *args; + + sched_getaffinity(0, sizeof(affinity), &affinity); + num_threads = CPU_COUNT(&affinity); + tinfo = calloc(num_threads, sizeof(*tinfo)); + if (!tinfo) { + fprintf(stderr, "Error: failed to allocate tinfo(%d): %s\n", + errno, strerror(errno)); + assert(ret == 0); + } + args = calloc(num_threads, sizeof(*args)); + if (!args) { + fprintf(stderr, "Error: failed to allocate args(%d): %s\n", + errno, strerror(errno)); + assert(ret == 0); + } + token = calloc(num_threads, sizeof(*token)); + if (!token) { + fprintf(stderr, "Error: failed to allocate token(%d): %s\n", + errno, strerror(errno)); + assert(ret == 0); + } + if (num_threads == 1) { + printf_verbose( + "Running on a single cpu, cannot test anything\n"); + return; + } + pthread_mutex_init(token, NULL); + /* The main thread runs on CPU0 */ + for (i = 0, j = 0; i < CPU_SETSIZE && j < num_threads; i++) { + if (CPU_ISSET(i, &affinity)) { + args[j].num_cpus = num_threads; + args[j].tinfo = tinfo; + args[j].token = token; + 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) { + fprintf(stderr, + "Error: failed to create thread(%d): %s\n", + ret, strerror(ret)); + assert(ret == 0); + } + ++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_register_current_thread()) { + fprintf(stderr, + "Error: rseq_register_current_thread(...) failed(%d): %s\n", + errno, strerror(errno)); + goto error; + } + if (!rseq_mm_cid_available()) { + fprintf(stderr, "Error: rseq_mm_cid unavailable\n"); + goto error; + } + test_mm_cid_compaction(); + if (rseq_unregister_current_thread()) { + fprintf(stderr, + "Error: rseq_unregister_current_thread(...) failed(%d): %s\n", + errno, strerror(errno)); + goto error; + } + return 0; + +error: + return -1; +}