lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20260129004328.102770-1-teknoraver@meta.com>
Date: Thu, 29 Jan 2026 01:43:28 +0100
From: Matteo Croce <technoboy85@...il.com>
To: linux-kernel@...r.kernel.org,
	Andrew Morton <akpm@...ux-foundation.org>
Subject: [PATCH] KUnit: memcpy: add benchmark

Add optional benchmarks for memcpy() and memmove() functions.
Each benchmark is run twice: first with buffers aligned and then with
buffers unaligned, to spot unaligned accesses on platforms where they
have a noticeable performance impact.

Signed-off-by: Matteo Croce <teknoraver@...a.com>
---
 lib/Kconfig.debug        |   9 ++++
 lib/tests/memcpy_kunit.c | 108 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 117 insertions(+)

diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index ba36939fda79..02868c4397cb 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2880,6 +2880,15 @@ config MEMCPY_KUNIT_TEST
 
 	  If unsure, say N.
 
+config MEMCPY_KUNIT_BENCHMARK
+	bool "Benchmark string functions"
+	depends on MEMCPY_KUNIT_TEST
+	help
+	  A benchmark for memcpy() and memmove() functions,
+	  with both aligned and unaligned buffers.
+
+	  If unsure, say N.
+
 config IS_SIGNED_TYPE_KUNIT_TEST
 	tristate "Test is_signed_type() macro" if !KUNIT_ALL_TESTS
 	depends on KUNIT
diff --git a/lib/tests/memcpy_kunit.c b/lib/tests/memcpy_kunit.c
index d36933554e46..33080dddc58e 100644
--- a/lib/tests/memcpy_kunit.c
+++ b/lib/tests/memcpy_kunit.c
@@ -493,6 +493,110 @@ static void memmove_overlap_test(struct kunit *test)
 	}
 }
 
+#ifdef CONFIG_MEMCPY_KUNIT_BENCHMARK
+
+#define COPY_SIZE	(4 * 1024 * 1024)
+#define COPIES_NUM	100
+
+static int memcpy_bench_align(struct kunit *test, bool unalign)
+{
+	u64 start, end, total_ns = 0;
+	char *buf1;
+	char *buf2;
+	int ret = 0;
+
+	buf1 = kzalloc(COPY_SIZE, GFP_KERNEL);
+	if (!buf1)
+		return -ENOMEM;
+
+	buf2 = kzalloc(COPY_SIZE, GFP_KERNEL);
+	if (!buf2) {
+		ret = -ENOMEM;
+		goto out_free;
+	}
+
+	preempt_disable();
+	for (int i = 0; i < COPIES_NUM; i++) {
+		start = ktime_get_ns();
+		memcpy(buf1 + unalign, buf2, COPY_SIZE - unalign);
+		end = ktime_get_ns();
+		total_ns += end - start;
+		cond_resched();
+	}
+	preempt_enable();
+
+	/* Avoid division by zero */
+	if (!total_ns)
+		total_ns = 1;
+
+	kunit_info(test, "memcpy: %saligned copy of %lu MBytes in %lld msecs (%lld MB/s)\n",
+		   unalign ? "un" : "",
+		   (unsigned long)(COPIES_NUM * COPY_SIZE) / (1024 * 1024),
+		   total_ns / 1000000,
+		   (COPIES_NUM * COPY_SIZE * 1000000000ULL / total_ns) / (1024 * 1024));
+
+	kfree(buf2);
+
+out_free:
+	kfree(buf1);
+
+	return ret;
+}
+
+static void memcpy_bench_test(struct kunit *test)
+{
+	KUNIT_ASSERT_EQ_MSG(test, memcpy_bench_align(test, false), 0,
+			   "aligned memcpy benchmark failed");
+	KUNIT_ASSERT_EQ_MSG(test, memcpy_bench_align(test, true), 0,
+			   "unaligned memcpy benchmark failed");
+}
+
+#define POS_SHIFT (2 * PAGE_SIZE)
+
+static int memmove_bench_align(struct kunit *test, bool unalign)
+{
+	u64 start, end, total_ns = 0;
+	char *buf;
+	int ret = 0;
+
+	buf = kzalloc(COPY_SIZE, GFP_KERNEL);
+	if (!buf)
+		return -ENOMEM;
+
+	preempt_disable();
+	for (int i = 0; i < COPIES_NUM; i++) {
+		start = ktime_get_ns();
+		memmove(buf + POS_SHIFT + unalign, buf, COPY_SIZE - POS_SHIFT - unalign);
+		end = ktime_get_ns();
+		total_ns += end - start;
+		cond_resched();
+	}
+	preempt_enable();
+
+	if (!total_ns)
+		total_ns = 1;
+
+	kunit_info(test, "memmove: %saligned move of %lu MBytes in %lld msecs (%lld MB/s)\n",
+		   unalign ? "un" : "",
+		   (unsigned long)(COPIES_NUM * (COPY_SIZE - POS_SHIFT)) / (1024 * 1024),
+		   total_ns / 1000000,
+		   (COPIES_NUM * (COPY_SIZE - POS_SHIFT) * 1000000000ULL / total_ns) /
+			(1024 * 1024));
+
+	kfree(buf);
+
+	return ret;
+}
+
+static void memmove_bench_test(struct kunit *test)
+{
+	KUNIT_ASSERT_EQ_MSG(test, memmove_bench_align(test, false), 0,
+			   "aligned memmove benchmark failed");
+	KUNIT_ASSERT_EQ_MSG(test, memmove_bench_align(test, true), 0,
+			   "unaligned memmove benchmark failed");
+}
+#endif
+
 static struct kunit_case memcpy_test_cases[] = {
 	KUNIT_CASE(memset_test),
 	KUNIT_CASE(memcpy_test),
@@ -500,6 +604,10 @@ static struct kunit_case memcpy_test_cases[] = {
 	KUNIT_CASE_SLOW(memmove_test),
 	KUNIT_CASE_SLOW(memmove_large_test),
 	KUNIT_CASE_SLOW(memmove_overlap_test),
+#ifdef CONFIG_MEMCPY_KUNIT_BENCHMARK
+	KUNIT_CASE_SLOW(memcpy_bench_test),
+	KUNIT_CASE_SLOW(memmove_bench_test),
+#endif
 	{}
 };
 
-- 
2.52.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ