From nobody Sun Oct 5 21:50:42 2025 Received: from mail-pf1-f201.google.com (mail-pf1-f201.google.com [209.85.210.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5BE5B185E7F for ; Wed, 30 Jul 2025 02:24:06 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753842248; cv=none; b=F2AwBYE29M+BM9tvpkXuIJchs3l1PnWuF1SLP/O5oiEwXtWSieTKT+RFe+CaZeQa0LbO6ewir0FO0GRVGIMvW3qc882byh87Jih3UG90nny/3kWxpNWl43ssIJ4kU8dGBCsQ+UCfBIK9UJ7HjeLigITE1fC77/YWPOppV536d+g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1753842248; c=relaxed/simple; bh=nS5WfiJyDN++X6i4GiHHq5GyaBNmUkSAVJNYFeAMNTI=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Wc+hdUYJDXuKDE49TJAx2dToZGG2PV6sCWx4NeJLk9TBbcyRVhKuZRqplQMJsYnZlTyVLx6cVX0F/QfKbu9MaG5SP8Q/BBddXPWrKrG1Kh47vXEhalLwXhPpjCd/QlU+z/x8rcG3Rb7C23EHJKCKjULdWYnSSrRqw8Gu0i2eaCM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--yuzhuo.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=3BS8FYHY; arc=none smtp.client-ip=209.85.210.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--yuzhuo.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="3BS8FYHY" Received: by mail-pf1-f201.google.com with SMTP id d2e1a72fcca58-74b29ee4f8bso5756184b3a.2 for ; Tue, 29 Jul 2025 19:24:06 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1753842246; x=1754447046; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=YSnVBVITeOzZAfMv7RC5y4cK3Twu/w5tupUEloHTubA=; b=3BS8FYHYNA83lJiFLyPLKNW0+Mld0mPVXquHzfZrAhRG06kpILinyxgx3rthTsoyB1 W2EKRFBhTMfwNsQEbGA2LCuRJp+EaDNUB22gEfP7C9wV8QoEQ7sFLUe3j/FMufvNDgBM S6a5QnY63EhlmVkrkVAaZC/mIesAdcLE6cX6JuSJOrTqHkyV3eZr1M+LfMcNno4cTmMX OyxygtLuwEG7Yv/UrhfDqnJMaRokTaUtT1SBLYnbZDNjlpWpeRuxc44gwfDpRK0pctCs Daibxpn6vFjBtm2zBJuNeWWRiuQuhes9cIt5cP5PbGH63UlXMGWJWLDeibKV4Pz7gf8P C04g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1753842246; x=1754447046; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=YSnVBVITeOzZAfMv7RC5y4cK3Twu/w5tupUEloHTubA=; b=bIfnpPO1OXddHlwkaATz54K0wZH9w+uMPaaF2zx7drVo705TAy9BKWUN9hiMwA2bfB prwrLfAUT0tf06dqMq2ve6ILHedURk1cd6Y4qzWEOZQPm/mERYnS7o5y6jmsq0TfzFVq 7MQRCj5PpKqGJtgSlDlzrU2JwaVApcnrgiGsmJsuoKL+TRBGvzplys8b/W3Y0Mc2+0rC jfF5iP7BMWmGIZsIFs2SaUySK2x5wHOAUjDUMIEjEfaJjsKmjiflgh3zIeYOchls7rQf jrjj8VF9ZEw1PmlKH5CXM/tk7MMWV/awByq98a+9DNzLTB2W/Mg0VVAEp7Ueh8/LAOMu SdSw== X-Forwarded-Encrypted: i=1; AJvYcCUz8xHh1s/cOLBmtoQpForT0V5mKvI74jlLbJn7G6Jt4egMr/+UJ8e+apmMfC2kJisvgqFnGr5Y7/b9n74=@vger.kernel.org X-Gm-Message-State: AOJu0Ywh1Z2K9s+CYIwwnMXTgwhYh2QNWM6ijP5wIyvKHwkUgRqSCwEt wTRE+W353KrwnrSmJF8tjrcbL4b3PR0+G7E0dXJysjdeK+dcAGv0qdMN0aiNuX5T2voGYYmIDDY +5wryXQ== X-Google-Smtp-Source: AGHT+IHoQsKozsPlh4E8P2d5oMA0zeGN4kDg69cefdHKKRDMh6Tt1jgzcPFhnMiLARA1JMxVUy4YUoynsJM= X-Received: from pfbic11.prod.google.com ([2002:a05:6a00:8a0b:b0:756:c6cf:2462]) (user=yuzhuo job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a20:3d0c:b0:234:cd25:735 with SMTP id adf61e73a8af0-23dc0e967afmr2202881637.38.1753842245632; Tue, 29 Jul 2025 19:24:05 -0700 (PDT) Date: Tue, 29 Jul 2025 19:23:44 -0700 In-Reply-To: <20250730022347.71722-1-yuzhuo@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250730022347.71722-1-yuzhuo@google.com> X-Mailer: git-send-email 2.50.1.552.g942d659e1b-goog Message-ID: <20250730022347.71722-2-yuzhuo@google.com> Subject: [PATCH v1 1/4] rcuscale: Create debugfs file for writer durations From: Yuzhuo Jing To: Ian Rogers , Yuzhuo Jing , Jonathan Corbet , Davidlohr Bueso , "Paul E . McKenney" , Josh Triplett , Frederic Weisbecker , Neeraj Upadhyay , Joel Fernandes , Boqun Feng , Uladzislau Rezki , Steven Rostedt , Mathieu Desnoyers , Lai Jiangshan , Zqiang , Andrew Morton , Ingo Molnar , Borislav Petkov , Arnd Bergmann , Frank van der Linden , linux-doc@vger.kernel.org, linux-kernel@vger.kernel.org, rcu@vger.kernel.org Cc: Yuzhuo Jing Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Creates an "rcuscale" folder in debugfs and creates a "writer_durations" file in the folder. This file is in CSV format. Each line represents one duration record, with columns defined as: writer_id,duration Added an option "writer_no_print" to skip printing writer durations on cleanup. This allows external tools to read structured data and also drastically improves cleanup performance on large core count machines. On a 256C 512T machines running nreaders=3D1 nwriters=3D511: Before: $ time modprobe -r rcuscale; modprobe -r torture real 3m17.349s user 0m0.000s sys 3m15.288s After: $ time cat /sys/kernel/debug/rcuscale/writer_durations > durations.csv real 0m0.005s user 0m0.000s sys 0m0.005s $ time modprobe -r rcuscale; modprobe -r torture real 0m0.388s user 0m0.000s sys 0m0.335s Signed-off-by: Yuzhuo Jing --- .../admin-guide/kernel-parameters.txt | 5 + kernel/rcu/rcuscale.c | 142 +++++++++++++++++- 2 files changed, 139 insertions(+), 8 deletions(-) diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentatio= n/admin-guide/kernel-parameters.txt index f1f2c0874da9..7b62a84a19d4 100644 --- a/Documentation/admin-guide/kernel-parameters.txt +++ b/Documentation/admin-guide/kernel-parameters.txt @@ -5583,6 +5583,11 @@ periods, but in jiffies. The default of zero says no holdoff. =20 + rcuscale.writer_no_print=3D [KNL] + Do not print writer durations to kernel ring buffer. + Instead, users can read them from the + rcuscale/writer_durations file in debugfs. + rcutorture.fqs_duration=3D [KNL] Set duration of force_quiescent_state bursts in microseconds. diff --git a/kernel/rcu/rcuscale.c b/kernel/rcu/rcuscale.c index b521d0455992..ad10b42be6fc 100644 --- a/kernel/rcu/rcuscale.c +++ b/kernel/rcu/rcuscale.c @@ -40,6 +40,8 @@ #include #include #include +#include +#include =20 #include "rcu.h" =20 @@ -97,6 +99,7 @@ torture_param(bool, shutdown, RCUSCALE_SHUTDOWN, torture_param(int, verbose, 1, "Enable verbose debugging printk()s"); torture_param(int, writer_holdoff, 0, "Holdoff (us) between GPs, zero to d= isable"); torture_param(int, writer_holdoff_jiffies, 0, "Holdoff (jiffies) between G= Ps, zero to disable"); +torture_param(bool, writer_no_print, false, "Do not print writer durations= to ring buffer"); torture_param(int, kfree_rcu_test, 0, "Do we run a kfree_rcu() scale test?= "); torture_param(int, kfree_mult, 1, "Multiple of kfree_obj size to allocate.= "); torture_param(int, kfree_by_call_rcu, 0, "Use call_rcu() to emulate kfree_= rcu()?"); @@ -138,6 +141,9 @@ static u64 t_rcu_scale_writer_finished; static unsigned long b_rcu_gp_test_started; static unsigned long b_rcu_gp_test_finished; =20 +static struct dentry *debugfs_dir; +static struct dentry *debugfs_writer_durations; + #define MAX_MEAS 10000 #define MIN_MEAS 100 =20 @@ -607,6 +613,7 @@ rcu_scale_writer(void *arg) t =3D ktime_get_mono_fast_ns(); *wdp =3D t - *wdp; i_max =3D i; + writer_n_durations[me] =3D i_max + 1; if (!started && atomic_read(&n_rcu_scale_writer_started) >=3D nrealwriters) started =3D true; @@ -620,6 +627,7 @@ rcu_scale_writer(void *arg) nrealwriters) { schedule_timeout_interruptible(10); rcu_ftrace_dump(DUMP_ALL); + WRITE_ONCE(test_complete, true); SCALEOUT_STRING("Test complete"); t_rcu_scale_writer_finished =3D t; if (gp_exp) { @@ -666,7 +674,6 @@ rcu_scale_writer(void *arg) rcu_scale_free(wmbp); cur_ops->gp_barrier(); } - writer_n_durations[me] =3D i_max + 1; torture_kthread_stopping("rcu_scale_writer"); return 0; } @@ -941,6 +948,117 @@ kfree_scale_init(void) return firsterr; } =20 +/* + * A seq_file for writer_durations. Content is only visible when all writ= ers + * finish. Element i of the sequence is writer_durations + i. + */ +static void *writer_durations_start(struct seq_file *m, loff_t *pos) +{ + loff_t writer_id =3D *pos; + + if (!test_complete || writer_id < 0 || writer_id >=3D nrealwriters) + return NULL; + + return writer_durations + writer_id; +} + +static void *writer_durations_next(struct seq_file *m, void *v, loff_t *po= s) +{ + (*pos)++; + return writer_durations_start(m, pos); +} + +static void writer_durations_stop(struct seq_file *m, void *v) +{ +} + +/* + * Each element in the seq_file is an array of one writer's durations. + * Each element prints writer_n_durations[writer_id] lines, and each line + * contains one duration record, in CSV format: + * writer_id,duration + */ +static int writer_durations_show(struct seq_file *m, void *v) +{ + u64 **durations =3D v; + loff_t writer_id =3D durations - writer_durations; + + for (int i =3D 0; i < writer_n_durations[writer_id]; ++i) + seq_printf(m, "%lld,%lld\n", writer_id, durations[0][i]); + + return 0; +} + +static const struct seq_operations writer_durations_op =3D { + .start =3D writer_durations_start, + .next =3D writer_durations_next, + .stop =3D writer_durations_stop, + .show =3D writer_durations_show +}; + +static int writer_durations_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &writer_durations_op); +} + +static const struct file_operations writer_durations_fops =3D { + .owner =3D THIS_MODULE, + .open =3D writer_durations_open, + .read =3D seq_read, + .llseek =3D seq_lseek, + .release =3D seq_release, +}; + +/* + * Create an rcuscale directory exposing run states and results. + */ +static int register_debugfs(void) +{ +#define try_create_file(variable, name, mode, parent, data, fops) \ +({ \ + variable =3D debugfs_create_file((name), (mode), (parent), (data), (fops)= ); \ + err =3D PTR_ERR_OR_ZERO(variable); \ + err; \ +}) + + int err; + + debugfs_dir =3D debugfs_create_dir("rcuscale", NULL); + err =3D PTR_ERR_OR_ZERO(debugfs_dir); + if (err) + goto fail; + + if (try_create_file(debugfs_writer_durations, "writer_durations", 0444, + debugfs_dir, NULL, &writer_durations_fops)) + goto fail; + + return 0; +fail: + pr_err("rcu-scale: Failed to create debugfs file."); + /* unregister_debugfs is called by rcu_scale_cleanup, avoid + * calling it twice. + */ + return err; +#undef try_create_file +} + +static void unregister_debugfs(void) +{ +#define try_remove(variable) \ +do { \ + if (!IS_ERR_OR_NULL(variable)) \ + debugfs_remove(variable); \ + variable =3D NULL; \ +} while (0) + + try_remove(debugfs_writer_durations); + + /* Remove directory after files. */ + try_remove(debugfs_dir); + +#undef try_remove +} + static void rcu_scale_cleanup(void) { @@ -961,6 +1079,8 @@ rcu_scale_cleanup(void) if (gp_exp && gp_async) SCALEOUT_ERRSTRING("No expedited async GPs, so went with async!"); =20 + unregister_debugfs(); + // If built-in, just report all of the GP kthread's CPU time. if (IS_BUILTIN(CONFIG_RCU_SCALE_TEST) && !kthread_tp && cur_ops->rso_gp_k= thread) kthread_tp =3D cur_ops->rso_gp_kthread(); @@ -1020,13 +1140,15 @@ rcu_scale_cleanup(void) wdpp =3D writer_durations[i]; if (!wdpp) continue; - for (j =3D 0; j < writer_n_durations[i]; j++) { - wdp =3D &wdpp[j]; - pr_alert("%s%s %4d writer-duration: %5d %llu\n", - scale_type, SCALE_FLAG, - i, j, *wdp); - if (j % 100 =3D=3D 0) - schedule_timeout_uninterruptible(1); + if (!writer_no_print) { + for (j =3D 0; j < writer_n_durations[i]; j++) { + wdp =3D &wdpp[j]; + pr_alert("%s%s %4d writer-duration: %5d %llu\n", + scale_type, SCALE_FLAG, + i, j, *wdp); + if (j % 100 =3D=3D 0) + schedule_timeout_uninterruptible(1); + } } kfree(writer_durations[i]); if (writer_freelists) { @@ -1202,6 +1324,10 @@ rcu_scale_init(void) if (torture_init_error(firsterr)) goto unwind; } + + if (register_debugfs()) + goto unwind; + torture_init_end(); return 0; =20 --=20 2.50.1.552.g942d659e1b-goog