mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Daniel Gomez <da.gomez@kernel.org>
To: "Matthew Wilcox (Oracle)" <willy@infradead.org>,
	"Miguel Ojeda" <ojeda@kernel.org>,
	"Boqun Feng" <boqun@kernel.org>, "Gary Guo" <gary@garyguo.net>,
	"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
	"Benno Lossin" <lossin@kernel.org>,
	"Andreas Hindborg" <a.hindborg@kernel.org>,
	"Alice Ryhl" <aliceryhl@google.com>,
	"Trevor Gross" <tmgross@umich.edu>,
	"Danilo Krummrich" <dakr@kernel.org>,
	"Daniel Almeida" <daniel.almeida@collabora.com>,
	"Tamir Duberstein" <tamird@kernel.org>,
	"Alexandre Courbot" <acourbot@nvidia.com>,
	"Onur Özkan" <work@onurozkan.dev>,
	"Daniel Gomez" <da.gomez@kernel.org>,
	"Andrew Morton" <akpm@linux-foundation.org>
Cc: Julia Lawall <Julia.Lawall@inria.fr>,
	 Corinn Tiffany <corinn.tiffany@inria.fr>,
	 "Liam R. Howlett" <liam@infradead.org>,
	 Philipp Stanner <pstanner@redhat.com>,
	linux-kernel@vger.kernel.org,  rust-for-linux@vger.kernel.org,
	Samsung GOST <gost.dev@samsung.com>,
	 Daniel Gomez <da.gomez@samsung.com>
Subject: [PATCH 2/3] rust: kernel: add bench
Date: Wed, 23 Sep 2026 23:00:28 +0200	[thread overview]
Message-ID: <20260923-rxarray-next-v1-2-92eedf185649@samsung.com> (raw)
In-Reply-To: <20260923-rxarray-next-v1-0-92eedf185649@samsung.com>

From: Daniel Gomez <da.gomez@samsung.com>

Rust bench for sampled benchmarking with statistics.

The XArray benchmark will be the first user. The runner is a module so
other Rust benchmarks such as find_bit_benchmark_rust can share it. It
can also be extended with percentiles in the future.

Assisted-by: LLM
Signed-off-by: Daniel Gomez <da.gomez@samsung.com>
---
 MAINTAINERS          |   1 +
 rust/kernel/bench.rs | 173 +++++++++++++++++++++++++++++++++++++++++++++++++++
 rust/kernel/lib.rs   |   1 +
 3 files changed, 175 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index c40a254c35d3d..b8bdfe9e22226 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -29690,6 +29690,7 @@ W:	https://rust-for-linux.com
 B:	https://github.com/Rust-for-Linux/linux/issues
 C:	https://rust-for-linux.zulipchat.com
 T:	git git://git.kernel.org/pub/scm/linux/kernel/git/da.gomez/linux.git rxarray-next
+F:	rust/kernel/bench.rs
 F:	rust/kernel/rxarray.rs
 
 XBOX DVD IR REMOTE
diff --git a/rust/kernel/bench.rs b/rust/kernel/bench.rs
new file mode 100644
index 0000000000000..d1c85c49c7969
--- /dev/null
+++ b/rust/kernel/bench.rs
@@ -0,0 +1,173 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Sampled benchmarks with in-kernel statistics.
+//!
+//! Each sample times `iterations` of a workload. A [`Row`] prints the minimum, median, maximum and
+//! mean of the sample times in nanoseconds. The caller owns the timer and the printing:
+//!
+//! ```ignore
+//! let mut bench = Bencher::new(samples, entries)?;
+//! pr_info!("{samples} samples x {entries} entries, ns per sample:\n");
+//! pr_info!("{}\n", bench::Heading);
+//! pr_info!("{}\n", bench.run("store", XArray::new, store));
+//! pr_info!("total runtime {}\n", bench.runtime());
+//! ```
+
+use crate::{
+    fmt,
+    prelude::*,
+    time::{Delta, Instant, Monotonic}, //
+};
+
+/// The column headings of a table of [`Row`]s, in the same columns.
+pub struct Heading;
+
+impl fmt::Display for Heading {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_fmt(fmt!(
+            "{:<18} {:>12} {:>12} {:>12} {:>12} {:>12}",
+            "benchmark",
+            "min",
+            "median",
+            "max",
+            "mean",
+            "runtime"
+        ))
+    }
+}
+
+/// A wall time.
+pub struct Runtime(pub Delta);
+
+impl fmt::Display for Runtime {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        let ms = self.0.as_millis();
+        let secs = ms / 1000;
+        let mins = secs / 60;
+        let hours = mins / 60;
+        let width = f.width().unwrap_or(0);
+        if hours > 0 {
+            let w = width.saturating_sub(4);
+            write!(f, "{hours:w$}h{:02}m", mins % 60)
+        } else if mins > 0 {
+            let w = width.saturating_sub(4);
+            write!(f, "{mins:w$}m{:02}s", secs % 60)
+        } else {
+            let w = width.saturating_sub(5);
+            write!(f, "{secs:w$}.{:03}s", ms % 1000)
+        }
+    }
+}
+
+/// Stats across samples, in nanoseconds.
+pub struct Stats {
+    /// The fastest sample.
+    pub min: i64,
+    /// The middle sample.
+    pub median: i64,
+    /// The slowest sample.
+    pub max: i64,
+    /// The mean of the samples, rounded down.
+    pub mean: i64,
+}
+
+impl Stats {
+    /// Computes the statistics of the non-empty `samples`, sorting them in place.
+    pub fn new(samples: &mut [i64]) -> Self {
+        samples.sort_unstable();
+        let len = samples.len();
+        Self {
+            min: samples[0],
+            median: (samples[(len - 1) / 2] + samples[len / 2]) / 2,
+            max: samples[len - 1],
+            mean: samples.iter().sum::<i64>() / len as i64,
+        }
+    }
+}
+
+/// One row of the table: the benchmark's name, its statistics and its wall time, in the columns
+/// of [`Heading`].
+pub struct Row<'a> {
+    name: &'a str,
+    stats: Stats,
+    runtime: Runtime,
+}
+
+impl fmt::Display for Row<'_> {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        f.write_fmt(fmt!(
+            "{:<18} {:>12} {:>12} {:>12} {:>12} {:>12}",
+            self.name,
+            self.stats.min,
+            self.stats.median,
+            self.stats.max,
+            self.stats.mean,
+            self.runtime
+        ))
+    }
+}
+
+/// Benchmark runner.
+pub struct Bencher {
+    iterations: usize,
+    timings: KVVec<i64>,
+    runtime: Delta,
+}
+
+impl Bencher {
+    /// Allocates one timing slot per sample up front, outside the timed loops.
+    ///
+    /// Returns `EINVAL` if `samples` or `iterations` is 0.
+    pub fn new(samples: usize, iterations: usize) -> Result<Self> {
+        if samples == 0 || iterations == 0 {
+            return Err(EINVAL);
+        }
+        Ok(Self {
+            iterations,
+            timings: KVVec::from_elem(0, samples, GFP_KERNEL)?,
+            runtime: Delta::ZERO,
+        })
+    }
+
+    /// Runs `bench` on a fresh `setup` value once per sample and returns the table row of `name`.
+    ///
+    /// `bench` returns the [`Delta`] of the window it timed.
+    pub fn run<'a, A>(
+        &mut self,
+        name: &'a str,
+        setup: impl Fn() -> A,
+        bench: impl Fn(A, usize) -> Delta,
+    ) -> Row<'a> {
+        let start = Instant::<Monotonic>::now();
+        for ns in &mut self.timings {
+            *ns = bench(setup(), self.iterations).as_nanos();
+        }
+        let elapsed = start.elapsed();
+        self.runtime += elapsed;
+
+        Row {
+            name,
+            stats: Stats::new(&mut self.timings),
+            runtime: Runtime(elapsed),
+        }
+    }
+
+    /// The wall time of every run so far.
+    pub fn runtime(&self) -> Runtime {
+        Runtime(self.runtime)
+    }
+}
+
+#[macros::kunit_tests(rust_bench)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn stats() {
+        let odd = Stats::new(&mut [5, 1, 9]);
+        assert_eq!((odd.min, odd.median, odd.max, odd.mean), (1, 5, 9, 5));
+        // Median check for even samples.
+        let med = Stats::new(&mut [4, 1, 9, 5]);
+        assert_eq!(med.median, 4);
+    }
+}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 1e3c8d3051e53..95162ab0c3f13 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -48,6 +48,7 @@
 #[cfg(CONFIG_AUXILIARY_BUS)]
 pub mod auxiliary;
 pub mod bitfield;
+pub mod bench;
 pub mod bitmap;
 pub mod bits;
 #[cfg(CONFIG_BLOCK)]

-- 
2.55.0


  parent reply	other threads:[~2026-09-23 21:00 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-23 21:00 [PATCH 0/3] Rust XArray Daniel Gomez
2026-09-23 21:00 ` [PATCH 1/3] rust: rxarray: add rust xarray support Daniel Gomez
2026-09-23 21:00 ` Daniel Gomez [this message]
2026-09-23 21:00 ` [PATCH 3/3] lib/xarray_benchmark_rust: add module Daniel Gomez
2026-09-23 21:04 ` [PATCH 0/3] Rust XArray Daniel Gomez
2026-09-23 21:08 ` Daniel Almeida

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=20260923-rxarray-next-v1-2-92eedf185649@samsung.com \
    --to=da.gomez@kernel.org \
    --cc=Julia.Lawall@inria.fr \
    --cc=a.hindborg@kernel.org \
    --cc=acourbot@nvidia.com \
    --cc=akpm@linux-foundation.org \
    --cc=aliceryhl@google.com \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun@kernel.org \
    --cc=corinn.tiffany@inria.fr \
    --cc=da.gomez@samsung.com \
    --cc=dakr@kernel.org \
    --cc=daniel.almeida@collabora.com \
    --cc=gary@garyguo.net \
    --cc=gost.dev@samsung.com \
    --cc=liam@infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=lossin@kernel.org \
    --cc=ojeda@kernel.org \
    --cc=pstanner@redhat.com \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=tamird@kernel.org \
    --cc=tmgross@umich.edu \
    --cc=willy@infradead.org \
    --cc=work@onurozkan.dev \
    /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®