[openssh-commits] [openssh] 02/02: upstream: basic benchmarking support for the unit test framework enable

git+noreply at mindrot.org git+noreply at mindrot.org
Tue Apr 15 15:33:19 AEST 2025


This is an automated email from the git hooks/post-receive script.

djm pushed a commit to branch master
in repository openssh.

commit f3d465530e75cb6c02e2cde1d15e6c4bb51ebfd9
Author: djm at openbsd.org <djm at openbsd.org>
AuthorDate: Tue Apr 15 04:00:42 2025 +0000

    upstream: basic benchmarking support for the unit test framework enable
    
    with "make UNITTEST_BENCHMARK=yes"
    
    ok dtucker@
    
    OpenBSD-Regress-ID: 7f16a2e247f860897ca46ff87bccbe6002a32564
---
 Makefile.in                                 |   7 +
 regress/Makefile                            |  31 ++--
 regress/unittests/Makefile.inc              |  25 +++-
 regress/unittests/authopt/Makefile          |   4 +-
 regress/unittests/authopt/tests.c           |   8 +-
 regress/unittests/bitmap/Makefile           |   7 +-
 regress/unittests/bitmap/tests.c            |  30 ++--
 regress/unittests/conversion/Makefile       |   4 +-
 regress/unittests/conversion/tests.c        |   8 +-
 regress/unittests/hostkeys/Makefile         |   4 +-
 regress/unittests/hostkeys/tests.c          |  11 +-
 regress/unittests/kex/Makefile              |   4 +-
 regress/unittests/kex/test_kex.c            |  68 ++++++---
 regress/unittests/kex/tests.c               |   9 +-
 regress/unittests/match/Makefile            |   4 +-
 regress/unittests/match/tests.c             |   8 +-
 regress/unittests/misc/Makefile             |   4 +-
 regress/unittests/misc/tests.c              |   8 +-
 regress/unittests/sshbuf/tests.c            |  10 +-
 regress/unittests/sshkey/test_sshkey.c      | 163 ++++++++++++++++++++-
 regress/unittests/sshkey/tests.c            |  10 +-
 regress/unittests/sshsig/tests.c            |   8 +-
 regress/unittests/test_helper/test_helper.c | 211 ++++++++++++++++++++++++----
 regress/unittests/test_helper/test_helper.h |  24 +++-
 regress/unittests/utf8/Makefile             |   7 +-
 regress/unittests/utf8/tests.c              |   8 +-
 26 files changed, 580 insertions(+), 105 deletions(-)

diff --git a/Makefile.in b/Makefile.in
index 4617cebcd..5a7a1bd10 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -782,6 +782,13 @@ unit: regress-unit-binaries
 		OBJ="$(BUILDDIR)/regress" \
 		$@ && echo $@ tests passed
 
+unit-bench: regress-unit-binaries
+	cd $(srcdir)/regress || exit $$?; \
+	$(MAKE) \
+		.CURDIR="$(abs_top_srcdir)/regress" \
+		.OBJDIR="$(BUILDDIR)/regress" \
+		OBJ="$(BUILDDIR)/regress" $@
+
 TEST_SSH_SSHD="$(BUILDDIR)/sshd"
 
 interop-tests t-exec file-tests extra-tests: regress-prep regress-binaries $(TARGETS)
diff --git a/regress/Makefile b/regress/Makefile
index 7e7f95b58..8b69e14e9 100644
--- a/regress/Makefile
+++ b/regress/Makefile
@@ -292,26 +292,33 @@ t-extra:	${EXTRA_TESTS:=.sh}
 interop: ${INTEROP_TARGETS}
 
 # Unit tests, built by top-level Makefile
-unit:
+unit unit-bench:
 	set -e ; if test -z "${SKIP_UNIT}" ; then \
 		V="" ; \
 		test "x${USE_VALGRIND}" = "x" || \
 		    V=${.CURDIR}/valgrind-unit.sh ; \
-		 $$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \
+		ARGS=""; \
+		test "x$@" = "xunit-bench" && ARGS="-b"; \
+		test "x${UNITTEST_FAST}" = "x" || ARGS="$$ARGS -f"; \
+		test "x${UNITTEST_SLOW}" = "x" || ARGS="$$ARGS -F"; \
+		test "x${UNITTEST_VERBOSE}" = "x" || ARGS="$$ARGS -v"; \
+		test "x${UNITTEST_BENCH_DETAIL}" = "x" || ARGS="$$ARGS -B"; \
+		test "x${UNITTEST_BENCH_ONLY}" = "x" || ARGS="$$ARGS -O ${UNITTEST_BENCH_ONLY}"; \
+		 $$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf $${ARGS}; \
 		 $$V ${.OBJDIR}/unittests/sshkey/test_sshkey \
-			-d ${.CURDIR}/unittests/sshkey/testdata ; \
+			-d ${.CURDIR}/unittests/sshkey/testdata $${ARGS}; \
 		$$V ${.OBJDIR}/unittests/sshsig/test_sshsig \
-			-d ${.CURDIR}/unittests/sshsig/testdata ; \
+			-d ${.CURDIR}/unittests/sshsig/testdata $${ARGS}; \
 		$$V ${.OBJDIR}/unittests/authopt/test_authopt \
-			-d ${.CURDIR}/unittests/authopt/testdata ; \
-		$$V ${.OBJDIR}/unittests/bitmap/test_bitmap ; \
-		$$V ${.OBJDIR}/unittests/conversion/test_conversion ; \
-		$$V ${.OBJDIR}/unittests/kex/test_kex ; \
+			-d ${.CURDIR}/unittests/authopt/testdata $${ARGS}; \
+		$$V ${.OBJDIR}/unittests/bitmap/test_bitmap $${ARGS}; \
+		$$V ${.OBJDIR}/unittests/conversion/test_conversion $${ARGS}; \
+		$$V ${.OBJDIR}/unittests/kex/test_kex $${ARGS}; \
 		$$V ${.OBJDIR}/unittests/hostkeys/test_hostkeys \
-			-d ${.CURDIR}/unittests/hostkeys/testdata ; \
-		$$V ${.OBJDIR}/unittests/match/test_match ; \
-		$$V ${.OBJDIR}/unittests/misc/test_misc ; \
+			-d ${.CURDIR}/unittests/hostkeys/testdata $${ARGS}; \
+		$$V ${.OBJDIR}/unittests/match/test_match $${ARGS}; \
+		$$V ${.OBJDIR}/unittests/misc/test_misc $${ARGS}; \
 		if test "x${TEST_SSH_UTF8}" = "xyes"  ; then \
-			$$V ${.OBJDIR}/unittests/utf8/test_utf8 ; \
+			$$V ${.OBJDIR}/unittests/utf8/test_utf8 $${ARGS}; \
 		fi \
 	fi
diff --git a/regress/unittests/Makefile.inc b/regress/unittests/Makefile.inc
index 98e280486..ad7fdad84 100644
--- a/regress/unittests/Makefile.inc
+++ b/regress/unittests/Makefile.inc
@@ -1,4 +1,4 @@
-#	$OpenBSD: Makefile.inc,v 1.16 2024/01/11 01:45:58 djm Exp $
+#	$OpenBSD: Makefile.inc,v 1.17 2025/04/15 04:00:42 djm Exp $
 
 .include <bsd.own.mk>
 .include <bsd.obj.mk>
@@ -7,6 +7,9 @@
 UNITTEST_FAST?= no	# Skip slow tests (e.g. less intensive fuzzing).
 UNITTEST_SLOW?= no	# Include slower tests (e.g. more intensive fuzzing).
 UNITTEST_VERBOSE?= no	# Verbose test output (inc. per-test names).
+UNITTEST_BENCHMARK?= no	# Run unit tests in benchmarking mode.
+UNITTEST_BENCH_DETAIL?=no # Detailed benchmark statistics.
+UNITTEST_BENCH_ONLY?=	# Run only these benchmarks
 
 MALLOC_OPTIONS?=	CFGJRSUX
 TEST_ENV?=		MALLOC_OPTIONS=${MALLOC_OPTIONS}
@@ -69,8 +72,8 @@ DPADD+=${.CURDIR}/../test_helper/libtest_helper.a
 
 .PATH: ${.CURDIR}/${SSHREL}
 
-LDADD+= -lutil
-DPADD+= ${LIBUTIL}
+LDADD+= -lutil -lm
+DPADD+= ${LIBUTIL} ${LIBM}
 
 .if (${OPENSSL:L} == "yes")
 LDADD+= -lcrypto
@@ -82,11 +85,21 @@ DPADD+= ${LIBFIDO2} ${LIBCBOR} ${LIBUSBHID}
 
 UNITTEST_ARGS?=
 
-.if (${UNITTEST_VERBOSE:L} != "no")
+.if (${UNITTEST_VERBOSE:L:R} != "no")
 UNITTEST_ARGS+= -v
 .endif
-.if (${UNITTEST_FAST:L} != "no")
+.if (${UNITTEST_FAST:L:R} != "no")
 UNITTEST_ARGS+= -f
-.elif (${UNITTEST_SLOW:L} != "no")
+.elif (${UNITTEST_SLOW:L:R} != "no")
 UNITTEST_ARGS+= -F
 .endif
+
+.if (${UNITTEST_BENCHMARK:L:R} != "no")
+UNITTEST_ARGS+= -b
+.endif
+.if (${UNITTEST_BENCH_DETAIL:L:R} != "no")
+UNITTEST_ARGS+= -B
+.endif
+.if (${UNITTEST_BENCH_ONLY:L} != "")
+UNITTEST_ARGS+= -O "${UNITTEST_BENCH_ONLY}"
+.endif
diff --git a/regress/unittests/authopt/Makefile b/regress/unittests/authopt/Makefile
index 3045ec708..8bed7a915 100644
--- a/regress/unittests/authopt/Makefile
+++ b/regress/unittests/authopt/Makefile
@@ -1,4 +1,4 @@
-#	$OpenBSD: Makefile,v 1.7 2023/01/15 23:35:10 djm Exp $
+#	$OpenBSD: Makefile,v 1.8 2025/04/15 04:00:42 djm Exp $
 
 PROG=test_authopt
 SRCS=tests.c
@@ -22,6 +22,6 @@ SRCS+=utf8.c
 REGRESS_TARGETS=run-regress-${PROG}
 
 run-regress-${PROG}: ${PROG}
-	env ${TEST_ENV} ./${PROG} -d ${.CURDIR}/testdata
+	env ${TEST_ENV} ./${PROG} ${UNITTEST_ARGS} -d ${.CURDIR}/testdata
 
 .include <bsd.regress.mk>
diff --git a/regress/unittests/authopt/tests.c b/regress/unittests/authopt/tests.c
index d9e190305..5285f0db5 100644
--- a/regress/unittests/authopt/tests.c
+++ b/regress/unittests/authopt/tests.c
@@ -1,4 +1,4 @@
-/* 	$OpenBSD: tests.c,v 1.3 2021/12/14 21:25:27 deraadt Exp $ */
+/* 	$OpenBSD: tests.c,v 1.4 2025/04/15 04:00:42 djm Exp $ */
 
 /*
  * Regress test for keys options functions.
@@ -576,3 +576,9 @@ tests(void)
 	test_cert_parse();
 	test_merge();
 }
+
+void
+benchmarks(void)
+{
+	printf("no benchmarks\n");
+}
diff --git a/regress/unittests/bitmap/Makefile b/regress/unittests/bitmap/Makefile
index fe30acc77..c38cc7918 100644
--- a/regress/unittests/bitmap/Makefile
+++ b/regress/unittests/bitmap/Makefile
@@ -1,14 +1,15 @@
-#	$OpenBSD: Makefile,v 1.4 2017/12/21 00:41:22 djm Exp $
+#	$OpenBSD: Makefile,v 1.5 2025/04/15 04:00:42 djm Exp $
 
 PROG=test_bitmap
 SRCS=tests.c
 
 # From usr.sbin/ssh
-SRCS+=bitmap.c atomicio.c
+SRCS+=bitmap.c atomicio.c misc.c xmalloc.c fatal.c log.c cleanup.c match.c
+SRCS+=sshbuf.c sshbuf-getput-basic.c sshbuf-misc.c ssherr.c addr.c addrmatch.c
 
 REGRESS_TARGETS=run-regress-${PROG}
 
 run-regress-${PROG}: ${PROG}
-	env ${TEST_ENV} ./${PROG}
+	env ${TEST_ENV} ./${PROG} ${UNITTEST_ARGS}
 
 .include <bsd.regress.mk>
diff --git a/regress/unittests/bitmap/tests.c b/regress/unittests/bitmap/tests.c
index 576b863f4..b8eae2313 100644
--- a/regress/unittests/bitmap/tests.c
+++ b/regress/unittests/bitmap/tests.c
@@ -1,4 +1,4 @@
-/* 	$OpenBSD: tests.c,v 1.2 2021/12/14 21:25:27 deraadt Exp $ */
+/* 	$OpenBSD: tests.c,v 1.3 2025/04/15 04:00:42 djm Exp $ */
 /*
  * Regress test for bitmap.h bitmap API
  *
@@ -23,7 +23,7 @@
 
 #include "bitmap.h"
 
-#define NTESTS 131
+#define DEFAULT_NTESTS 131
 
 void
 tests(void)
@@ -32,10 +32,15 @@ tests(void)
 	struct bitmap *b;
 	BIGNUM *bn;
 	size_t len;
-	int i, j, k, n;
+	int i, j, k, n, ntests = DEFAULT_NTESTS;
 	u_char bbuf[1024], bnbuf[1024];
 	int r;
 
+	if (test_is_fast())
+		ntests /= 4;
+	else if (test_is_slow())
+		ntests *= 2;
+
 	TEST_START("bitmap_new");
 	b = bitmap_new();
 	ASSERT_PTR_NE(b, NULL);
@@ -44,9 +49,9 @@ tests(void)
 	TEST_DONE();
 
 	TEST_START("bitmap_set_bit / bitmap_test_bit");
-	for (i = -1; i < NTESTS; i++) {
-		for (j = -1; j < NTESTS; j++) {
-			for (k = -1; k < NTESTS; k++) {
+	for (i = -1; i < ntests; i++) {
+		for (j = -1; j < ntests; j++) {
+			for (k = -1; k < ntests; k++) {
 				bitmap_zero(b);
 				BN_clear(bn);
 
@@ -67,7 +72,7 @@ tests(void)
 
 				/* Check perfect match between bitmap and bn */
 				test_subtest_info("match %d/%d/%d", i, j, k);
-				for (n = 0; n < NTESTS; n++) {
+				for (n = 0; n < ntests; n++) {
 					ASSERT_INT_EQ(BN_is_bit_set(bn, n),
 					    bitmap_test_bit(b, n));
 				}
@@ -99,7 +104,7 @@ tests(void)
 				bitmap_zero(b);
 				ASSERT_INT_EQ(bitmap_from_string(b, bnbuf,
 				    len), 0);
-				for (n = 0; n < NTESTS; n++) {
+				for (n = 0; n < ntests; n++) {
 					ASSERT_INT_EQ(BN_is_bit_set(bn, n),
 					    bitmap_test_bit(b, n));
 				}
@@ -107,7 +112,7 @@ tests(void)
 				/* Test clearing bits */
 				test_subtest_info("clear %d/%d/%d",
 				    i, j, k);
-				for (n = 0; n < NTESTS; n++) {
+				for (n = 0; n < ntests; n++) {
 					ASSERT_INT_EQ(bitmap_set_bit(b, n), 0);
 					ASSERT_INT_EQ(BN_set_bit(bn, n), 1);
 				}
@@ -123,7 +128,7 @@ tests(void)
 					bitmap_clear_bit(b, k);
 					BN_clear_bit(bn, k);
 				}
-				for (n = 0; n < NTESTS; n++) {
+				for (n = 0; n < ntests; n++) {
 					ASSERT_INT_EQ(BN_is_bit_set(bn, n),
 					    bitmap_test_bit(b, n));
 				}
@@ -135,4 +140,9 @@ tests(void)
 	TEST_DONE();
 #endif
 }
+void
+benchmarks(void)
+{
+	printf("no benchmarks\n");
+}
 
diff --git a/regress/unittests/conversion/Makefile b/regress/unittests/conversion/Makefile
index 5793c4934..f9f5859ac 100644
--- a/regress/unittests/conversion/Makefile
+++ b/regress/unittests/conversion/Makefile
@@ -1,4 +1,4 @@
-#	$OpenBSD: Makefile,v 1.4 2021/01/09 12:24:30 dtucker Exp $
+#	$OpenBSD: Makefile,v 1.5 2025/04/15 04:00:42 djm Exp $
 
 PROG=test_conversion
 SRCS=tests.c
@@ -11,6 +11,6 @@ SRCS+=match.c addr.c addrmatch.c
 REGRESS_TARGETS=run-regress-${PROG}
 
 run-regress-${PROG}: ${PROG}
-	env ${TEST_ENV} ./${PROG}
+	env ${TEST_ENV} ./${PROG} ${UNITTEST_ARGS}
 
 .include <bsd.regress.mk>
diff --git a/regress/unittests/conversion/tests.c b/regress/unittests/conversion/tests.c
index 5b526f7af..d65e6326f 100644
--- a/regress/unittests/conversion/tests.c
+++ b/regress/unittests/conversion/tests.c
@@ -1,4 +1,4 @@
-/* 	$OpenBSD: tests.c,v 1.4 2021/12/14 21:25:27 deraadt Exp $ */
+/* 	$OpenBSD: tests.c,v 1.5 2025/04/15 04:00:42 djm Exp $ */
 /*
  * Regress test for conversions
  *
@@ -50,3 +50,9 @@ tests(void)
 	ASSERT_INT_EQ(convtime("1000000000000000000000w"), -1);
 	TEST_DONE();
 }
+
+void
+benchmarks(void)
+{
+	printf("no benchmarks\n");
+}
diff --git a/regress/unittests/hostkeys/Makefile b/regress/unittests/hostkeys/Makefile
index 04d93359a..79a9d5745 100644
--- a/regress/unittests/hostkeys/Makefile
+++ b/regress/unittests/hostkeys/Makefile
@@ -1,4 +1,4 @@
-#	$OpenBSD: Makefile,v 1.10 2023/01/15 23:35:10 djm Exp $
+#	$OpenBSD: Makefile,v 1.11 2025/04/15 04:00:42 djm Exp $
 
 PROG=test_hostkeys
 SRCS=tests.c test_iterate.c
@@ -20,6 +20,6 @@ SRCS+=utf8.c
 REGRESS_TARGETS=run-regress-${PROG}
 
 run-regress-${PROG}: ${PROG}
-	env ${TEST_ENV} ./${PROG} -d ${.CURDIR}/testdata
+	env ${TEST_ENV} ./${PROG} ${UNITTEST_ARGS} -d ${.CURDIR}/testdata
 
 .include <bsd.regress.mk>
diff --git a/regress/unittests/hostkeys/tests.c b/regress/unittests/hostkeys/tests.c
index 92c7646ad..a14ba19b3 100644
--- a/regress/unittests/hostkeys/tests.c
+++ b/regress/unittests/hostkeys/tests.c
@@ -1,10 +1,14 @@
-/* 	$OpenBSD: tests.c,v 1.1 2015/02/16 22:18:34 djm Exp $ */
+/* 	$OpenBSD: tests.c,v 1.2 2025/04/15 04:00:42 djm Exp $ */
 /*
  * Regress test for known_hosts-related API.
  *
  * Placed in the public domain
  */
 
+#include <stdio.h>
+
+#include "../test_helper/test_helper.h"
+
 void tests(void);
 void test_iterate(void); /* test_iterate.c */
 
@@ -14,3 +18,8 @@ tests(void)
 	test_iterate();
 }
 
+void
+benchmarks(void)
+{
+	printf("no benchmarks\n");
+}
diff --git a/regress/unittests/kex/Makefile b/regress/unittests/kex/Makefile
index ca4f0ee38..b76ee8edc 100644
--- a/regress/unittests/kex/Makefile
+++ b/regress/unittests/kex/Makefile
@@ -1,4 +1,4 @@
-#	$OpenBSD: Makefile,v 1.16 2024/09/09 03:13:39 djm Exp $
+#	$OpenBSD: Makefile,v 1.17 2025/04/15 04:00:42 djm Exp $
 
 PROG=test_kex
 SRCS=tests.c test_kex.c test_proposal.c
@@ -35,7 +35,7 @@ SRCS+=digest-openssl.c
 REGRESS_TARGETS=run-regress-${PROG}
 
 run-regress-${PROG}: ${PROG}
-	env ${TEST_ENV} ./${PROG}
+	env ${TEST_ENV} ./${PROG} ${UNITTEST_ARGS}
 
 .include <bsd.regress.mk>
 
diff --git a/regress/unittests/kex/test_kex.c b/regress/unittests/kex/test_kex.c
index caf8f57f7..84dada301 100644
--- a/regress/unittests/kex/test_kex.c
+++ b/regress/unittests/kex/test_kex.c
@@ -1,4 +1,4 @@
-/* 	$OpenBSD: test_kex.c,v 1.9 2024/09/09 03:13:39 djm Exp $ */
+/* 	$OpenBSD: test_kex.c,v 1.10 2025/04/15 04:00:42 djm Exp $ */
 /*
  * Regress test KEX
  *
@@ -8,6 +8,7 @@
 #include "includes.h"
 
 #include <sys/types.h>
+#include <sys/time.h>
 #include <stdio.h>
 #ifdef HAVE_STDINT_H
 #include <stdint.h>
@@ -76,7 +77,8 @@ run_kex(struct ssh *client, struct ssh *server)
 }
 
 static void
-do_kex_with_key(char *kex, int keytype, int bits)
+do_kex_with_key(char *kex, char *cipher, char *mac,
+    struct sshkey *key, int keytype, int bits)
 {
 	struct ssh *client = NULL, *server = NULL, *server2 = NULL;
 	struct sshkey *private, *public;
@@ -85,9 +87,14 @@ do_kex_with_key(char *kex, int keytype, int bits)
 	char *myproposal[PROPOSAL_MAX] = { KEX_CLIENT };
 	char *keyname = NULL;
 
-	TEST_START("sshkey_generate");
-	ASSERT_INT_EQ(sshkey_generate(keytype, bits, &private), 0);
-	TEST_DONE();
+	if (key != NULL) {
+		private = key;
+		keytype = key->type;
+	} else {
+		TEST_START("sshkey_generate");
+		ASSERT_INT_EQ(sshkey_generate(keytype, bits, &private), 0);
+		TEST_DONE();
+	}
 
 	TEST_START("sshkey_from_private");
 	ASSERT_INT_EQ(sshkey_from_private(private, &public), 0);
@@ -97,6 +104,14 @@ do_kex_with_key(char *kex, int keytype, int bits)
 	memcpy(kex_params.proposal, myproposal, sizeof(myproposal));
 	if (kex != NULL)
 		kex_params.proposal[PROPOSAL_KEX_ALGS] = kex;
+	if (cipher != NULL) {
+		kex_params.proposal[PROPOSAL_ENC_ALGS_CTOS] = cipher;
+		kex_params.proposal[PROPOSAL_ENC_ALGS_STOC] = cipher;
+	}
+	if (mac != NULL) {
+		kex_params.proposal[PROPOSAL_MAC_ALGS_CTOS] = mac;
+		kex_params.proposal[PROPOSAL_MAC_ALGS_STOC] = mac;
+	}
 	keyname = strdup(sshkey_ssh_name(private));
 	ASSERT_PTR_NE(keyname, NULL);
 	kex_params.proposal[PROPOSAL_SERVER_HOST_KEY_ALGS] = keyname;
@@ -167,7 +182,8 @@ do_kex_with_key(char *kex, int keytype, int bits)
 	TEST_DONE();
 
 	TEST_START("cleanup");
-	sshkey_free(private);
+	if (key == NULL)
+		sshkey_free(private);
 	sshkey_free(public);
 	ssh_free(client);
 	ssh_free(server);
@@ -179,19 +195,37 @@ do_kex_with_key(char *kex, int keytype, int bits)
 static void
 do_kex(char *kex)
 {
-#if 0
-	log_init("test_kex", SYSLOG_LEVEL_DEBUG3, SYSLOG_FACILITY_AUTH, 1);
-#endif
+	struct sshkey *key = NULL;
+	char name[256];
+
+	if (test_is_benchmark()) {
+		snprintf(name, sizeof(name), "generate %s", kex);
+		TEST_START(name);
+		ASSERT_INT_EQ(sshkey_generate(KEY_ED25519, 0, &key), 0);
+		TEST_DONE();
+		snprintf(name, sizeof(name), "KEX %s", kex);
+		BENCH_START(name);
+		/*
+		 * NB. use a cipher/MAC here that requires minimal bits from
+		 * the KEX to avoid DH-GEX taking forever.
+		 */
+		do_kex_with_key(kex, "aes128-ctr", "hmac-sha2-256", key,
+		    KEY_ED25519, 256);
+		BENCH_FINISH("kex");
+		sshkey_free(key);
+		return;
+	}
+
 #ifdef WITH_OPENSSL
-	do_kex_with_key(kex, KEY_RSA, 2048);
-#ifdef WITH_DSA
-	do_kex_with_key(kex, KEY_DSA, 1024);
-#endif
-#ifdef OPENSSL_HAS_ECC
-	do_kex_with_key(kex, KEY_ECDSA, 256);
-#endif /* OPENSSL_HAS_ECC */
+	do_kex_with_key(kex, NULL, NULL, NULL, KEY_RSA, 2048);
+# ifdef WITH_DSA
+	do_kex_with_key(kex, NULL, NULL, NULL, KEY_DSA, 1024);
+# endif /* WITH_DSA */
+# ifdef OPENSSL_HAS_ECC
+	do_kex_with_key(kex, NULL, NULL, NULL, KEY_ECDSA, 256);
+# endif /* OPENSSL_HAS_ECC */
 #endif /* WITH_OPENSSL */
-	do_kex_with_key(kex, KEY_ED25519, 256);
+	do_kex_with_key(kex, NULL, NULL, NULL, KEY_ED25519, 256);
 }
 
 void
diff --git a/regress/unittests/kex/tests.c b/regress/unittests/kex/tests.c
index d3044f033..a3ef19ef4 100644
--- a/regress/unittests/kex/tests.c
+++ b/regress/unittests/kex/tests.c
@@ -1,4 +1,4 @@
-/* 	$OpenBSD: tests.c,v 1.3 2023/03/06 12:15:47 dtucker Exp $ */
+/* 	$OpenBSD: tests.c,v 1.4 2025/04/15 04:00:42 djm Exp $ */
 /*
  * Placed in the public domain
  */
@@ -16,3 +16,10 @@ tests(void)
 	kex_proposal_tests();
 	kex_proposal_populate_tests();
 }
+
+void
+benchmarks(void)
+{
+	printf("\n");
+	kex_tests();
+}
diff --git a/regress/unittests/match/Makefile b/regress/unittests/match/Makefile
index 939163d30..7b17e5689 100644
--- a/regress/unittests/match/Makefile
+++ b/regress/unittests/match/Makefile
@@ -1,4 +1,4 @@
-#	$OpenBSD: Makefile,v 1.5 2021/01/09 12:24:31 dtucker Exp $
+#	$OpenBSD: Makefile,v 1.6 2025/04/15 04:00:42 djm Exp $
 
 PROG=test_match
 SRCS=tests.c
@@ -11,6 +11,6 @@ SRCS+=cleanup.c atomicio.c addr.c
 REGRESS_TARGETS=run-regress-${PROG}
 
 run-regress-${PROG}: ${PROG}
-	env ${TEST_ENV} ./${PROG}
+	env ${TEST_ENV} ./${PROG} ${UNITTEST_ARGS}
 
 .include <bsd.regress.mk>
diff --git a/regress/unittests/match/tests.c b/regress/unittests/match/tests.c
index f00d1f934..2ca6c769a 100644
--- a/regress/unittests/match/tests.c
+++ b/regress/unittests/match/tests.c
@@ -1,4 +1,4 @@
-/* 	$OpenBSD: tests.c,v 1.8 2021/12/14 21:25:27 deraadt Exp $ */
+/* 	$OpenBSD: tests.c,v 1.9 2025/04/15 04:00:42 djm Exp $ */
 /*
  * Regress test for matching functions
  *
@@ -129,3 +129,9 @@ tests(void)
  * int      addr_match_cidr_list(const char *, const char *);
  */
 }
+
+void
+benchmarks(void)
+{
+	printf("no benchmarks\n");
+}
diff --git a/regress/unittests/misc/Makefile b/regress/unittests/misc/Makefile
index d2be393ad..7282be13a 100644
--- a/regress/unittests/misc/Makefile
+++ b/regress/unittests/misc/Makefile
@@ -1,4 +1,4 @@
-#	$OpenBSD: Makefile,v 1.9 2023/01/06 02:59:50 djm Exp $
+#	$OpenBSD: Makefile,v 1.10 2025/04/15 04:00:42 djm Exp $
 
 PROG=test_misc
 SRCS=tests.c
@@ -28,6 +28,6 @@ SRCS+=	atomicio.c cleanup.c fatal.c
 REGRESS_TARGETS=run-regress-${PROG}
 
 run-regress-${PROG}: ${PROG}
-	env ${TEST_ENV} ./${PROG}
+	env ${TEST_ENV} ./${PROG} ${UNITTEST_ARGS}
 
 .include <bsd.regress.mk>
diff --git a/regress/unittests/misc/tests.c b/regress/unittests/misc/tests.c
index 326995414..7611a0d3b 100644
--- a/regress/unittests/misc/tests.c
+++ b/regress/unittests/misc/tests.c
@@ -1,4 +1,4 @@
-/* 	$OpenBSD: tests.c,v 1.10 2023/01/06 02:59:50 djm Exp $ */
+/* 	$OpenBSD: tests.c,v 1.11 2025/04/15 04:00:42 djm Exp $ */
 /*
  * Regress test for misc helper functions.
  *
@@ -39,3 +39,9 @@ tests(void)
 	test_hpdelim();
 	test_ptimeout();
 }
+
+void
+benchmarks(void)
+{
+	printf("no benchmarks\n");
+}
diff --git a/regress/unittests/sshbuf/tests.c b/regress/unittests/sshbuf/tests.c
index 29916a10b..eb801fb3b 100644
--- a/regress/unittests/sshbuf/tests.c
+++ b/regress/unittests/sshbuf/tests.c
@@ -1,10 +1,12 @@
-/* 	$OpenBSD: tests.c,v 1.1 2014/04/30 05:32:00 djm Exp $ */
+/* 	$OpenBSD: tests.c,v 1.2 2025/04/15 04:00:42 djm Exp $ */
 /*
  * Regress test for sshbuf.h buffer API
  *
  * Placed in the public domain
  */
 
+#include <stdio.h>
+
 #include "../test_helper/test_helper.h"
 
 void sshbuf_tests(void);
@@ -28,3 +30,9 @@ tests(void)
 	sshbuf_getput_fuzz_tests();
 	sshbuf_fixed();
 }
+
+void
+benchmarks(void)
+{
+	printf("no benchmarks\n");
+}
diff --git a/regress/unittests/sshkey/test_sshkey.c b/regress/unittests/sshkey/test_sshkey.c
index 5bf4b65cc..fc744eb74 100644
--- a/regress/unittests/sshkey/test_sshkey.c
+++ b/regress/unittests/sshkey/test_sshkey.c
@@ -1,4 +1,4 @@
-/* 	$OpenBSD: test_sshkey.c,v 1.25 2024/08/15 00:52:23 djm Exp $ */
+/* 	$OpenBSD: test_sshkey.c,v 1.26 2025/04/15 04:00:42 djm Exp $ */
 /*
  * Regress test for sshkey.h key management API
  *
@@ -36,6 +36,7 @@
 #include "ssh2.h"
 
 void sshkey_tests(void);
+void sshkey_benchmarks(void);
 
 static void
 put_opt(struct sshbuf *b, const char *name, const char *value)
@@ -133,6 +134,55 @@ signature_test(struct sshkey *k, struct sshkey *bad, const char *sig_alg,
 	free(sig);
 }
 
+static void
+signature_bench(const char *name, int ktype, int bits, const char *sig_alg,
+    const u_char *d, size_t l)
+{
+	struct sshkey *k;
+	size_t len;
+	u_char *sig;
+	char testname[256];
+
+	snprintf(testname, sizeof(testname), "sign %s", name);
+	TEST_START(testname);
+	ASSERT_INT_EQ(sshkey_generate(ktype, bits, &k), 0);
+	ASSERT_PTR_NE(k, NULL);
+
+	BENCH_START(testname);
+	ASSERT_INT_EQ(sshkey_sign(k, &sig, &len, d, l, sig_alg,
+	    NULL, NULL, 0), 0);
+	free(sig);
+	BENCH_FINISH("sign");
+
+	sshkey_free(k);
+	TEST_DONE();
+}
+
+static void
+verify_bench(const char *name, int ktype, int bits, const char *sig_alg,
+    const u_char *d, size_t l)
+{
+	struct sshkey *k;
+	size_t len;
+	u_char *sig;
+	char testname[256];
+
+	snprintf(testname, sizeof(testname), "verify %s", name);
+	TEST_START(testname);
+	ASSERT_INT_EQ(sshkey_generate(ktype, bits, &k), 0);
+	ASSERT_PTR_NE(k, NULL);
+
+	ASSERT_INT_EQ(sshkey_sign(k, &sig, &len, d, l, sig_alg,
+	    NULL, NULL, 0), 0);
+	BENCH_START(testname);
+	ASSERT_INT_EQ(sshkey_verify(k, sig, len, d, l, NULL, 0, NULL), 0);
+	BENCH_FINISH("verify");
+
+	free(sig);
+	sshkey_free(k);
+	TEST_DONE();
+}
+
 static void
 banana(u_char *s, size_t l)
 {
@@ -165,6 +215,19 @@ signature_tests(struct sshkey *k, struct sshkey *bad, const char *sig_alg)
 	}
 }
 
+static void
+signature_benchmark(const char *name, int ktype, int bits,
+    const char *sig_alg, int bench_verify)
+{
+	u_char buf[256];
+
+	banana(buf, sizeof(buf));
+	if (bench_verify)
+		verify_bench(name, ktype, bits, sig_alg, buf, sizeof(buf));
+	else
+		signature_bench(name, ktype, bits, sig_alg, buf, sizeof(buf));
+}
+
 static struct sshkey *
 get_private(const char *n)
 {
@@ -537,3 +600,101 @@ sshkey_tests(void)
 	TEST_DONE();
 #endif /* WITH_OPENSSL */
 }
+
+void
+sshkey_benchmarks(void)
+{
+	struct sshkey *k = NULL;
+
+#ifdef WITH_OPENSSL
+	BENCH_START("generate RSA-1024");
+	TEST_START("generate KEY_RSA");
+	ASSERT_INT_EQ(sshkey_generate(KEY_RSA, 1024, &k), 0);
+	ASSERT_PTR_NE(k, NULL);
+	sshkey_free(k);
+	TEST_DONE();
+	BENCH_FINISH("keys");
+
+	BENCH_START("generate RSA-2048");
+	TEST_START("generate KEY_RSA");
+	ASSERT_INT_EQ(sshkey_generate(KEY_RSA, 2048, &k), 0);
+	ASSERT_PTR_NE(k, NULL);
+	sshkey_free(k);
+	TEST_DONE();
+	BENCH_FINISH("keys");
+
+#ifdef WITH_DSA
+	BENCH_START("generate DSA-1024");
+	TEST_START("generate KEY_DSA");
+	ASSERT_INT_EQ(sshkey_generate(KEY_DSA, 1024, &k), 0);
+	ASSERT_PTR_NE(k, NULL);
+	sshkey_free(k);
+	TEST_DONE();
+	BENCH_FINISH("keys");
+#endif
+
+	BENCH_START("generate ECDSA-256");
+	TEST_START("generate KEY_ECDSA");
+	ASSERT_INT_EQ(sshkey_generate(KEY_ECDSA, 256, &k), 0);
+	ASSERT_PTR_NE(k, NULL);
+	sshkey_free(k);
+	TEST_DONE();
+	BENCH_FINISH("keys");
+
+	BENCH_START("generate ECDSA-384");
+	TEST_START("generate KEY_ECDSA");
+	ASSERT_INT_EQ(sshkey_generate(KEY_ECDSA, 384, &k), 0);
+	ASSERT_PTR_NE(k, NULL);
+	sshkey_free(k);
+	TEST_DONE();
+	BENCH_FINISH("keys");
+
+	BENCH_START("generate ECDSA-521");
+	TEST_START("generate KEY_ECDSA");
+	ASSERT_INT_EQ(sshkey_generate(KEY_ECDSA, 521, &k), 0);
+	ASSERT_PTR_NE(k, NULL);
+	sshkey_free(k);
+	TEST_DONE();
+	BENCH_FINISH("keys");
+#endif /* WITH_OPENSSL */
+
+	BENCH_START("generate ED25519");
+	TEST_START("generate KEY_ED25519");
+	ASSERT_INT_EQ(sshkey_generate(KEY_ED25519, 256, &k), 0);
+	ASSERT_PTR_NE(k, NULL);
+	sshkey_free(k);
+	TEST_DONE();
+	BENCH_FINISH("keys");
+
+#ifdef WITH_OPENSSL
+	/* sign */
+	signature_benchmark("RSA-1024/SHA1", KEY_RSA, 1024, "ssh-rsa", 0);
+	signature_benchmark("RSA-1024/SHA256", KEY_RSA, 1024, "rsa-sha2-256", 0);
+	signature_benchmark("RSA-1024/SHA512", KEY_RSA, 1024, "rsa-sha2-512", 0);
+	signature_benchmark("RSA-2048/SHA1", KEY_RSA, 2048, "ssh-rsa", 0);
+	signature_benchmark("RSA-2048/SHA256", KEY_RSA, 2048, "rsa-sha2-256", 0);
+	signature_benchmark("RSA-2048/SHA512", KEY_RSA, 2048, "rsa-sha2-512", 0);
+#ifdef WITH_DSA
+	signature_benchmark("DSA-1024", KEY_DSA, 1024, NULL, 0);
+#endif
+	signature_benchmark("ECDSA-256", KEY_ECDSA, 256, NULL, 0);
+	signature_benchmark("ECDSA-384", KEY_ECDSA, 384, NULL, 0);
+	signature_benchmark("ECDSA-521", KEY_ECDSA, 521, NULL, 0);
+	signature_benchmark("ED25519", KEY_ED25519, 0, NULL, 0);
+
+	/* verify */
+	signature_benchmark("RSA-1024/SHA1", KEY_RSA, 1024, "ssh-rsa", 1);
+	signature_benchmark("RSA-1024/SHA256", KEY_RSA, 1024, "rsa-sha2-256", 1);
+	signature_benchmark("RSA-1024/SHA512", KEY_RSA, 1024, "rsa-sha2-512", 1);
+	signature_benchmark("RSA-2048/SHA1", KEY_RSA, 2048, "ssh-rsa", 1);
+	signature_benchmark("RSA-2048/SHA256", KEY_RSA, 2048, "rsa-sha2-256", 1);
+	signature_benchmark("RSA-2048/SHA512", KEY_RSA, 2048, "rsa-sha2-512", 1);
+#ifdef WITH_DSA
+	signature_benchmark("DSA-1024", KEY_DSA, 1024, NULL, 1);
+#endif
+	signature_benchmark("ECDSA-256", KEY_ECDSA, 256, NULL, 1);
+	signature_benchmark("ECDSA-384", KEY_ECDSA, 384, NULL, 1);
+	signature_benchmark("ECDSA-521", KEY_ECDSA, 521, NULL, 1);
+#endif /* WITH_OPENSSL */
+	signature_benchmark("ED25519", KEY_ED25519, 0, NULL, 1);
+}
diff --git a/regress/unittests/sshkey/tests.c b/regress/unittests/sshkey/tests.c
index 78aa9223d..5511e7b89 100644
--- a/regress/unittests/sshkey/tests.c
+++ b/regress/unittests/sshkey/tests.c
@@ -1,4 +1,4 @@
-/* 	$OpenBSD: tests.c,v 1.1 2014/06/24 01:14:18 djm Exp $ */
+/* 	$OpenBSD: tests.c,v 1.2 2025/04/15 04:00:42 djm Exp $ */
 /*
  * Regress test for sshbuf.h buffer API
  *
@@ -12,6 +12,7 @@
 void sshkey_tests(void);
 void sshkey_file_tests(void);
 void sshkey_fuzz_tests(void);
+void sshkey_benchmarks(void);
 
 void
 tests(void)
@@ -20,3 +21,10 @@ tests(void)
 	sshkey_file_tests();
 	sshkey_fuzz_tests();
 }
+
+void
+benchmarks(void)
+{
+	printf("\n");
+	sshkey_benchmarks();
+}
diff --git a/regress/unittests/sshsig/tests.c b/regress/unittests/sshsig/tests.c
index 80966bdd2..7fcf9488d 100644
--- a/regress/unittests/sshsig/tests.c
+++ b/regress/unittests/sshsig/tests.c
@@ -1,4 +1,4 @@
-/* 	$OpenBSD: tests.c,v 1.4 2024/01/11 01:45:59 djm Exp $ */
+/* 	$OpenBSD: tests.c,v 1.5 2025/04/15 04:00:42 djm Exp $ */
 /*
  * Regress test for sshbuf.h buffer API
  *
@@ -142,3 +142,9 @@ tests(void)
 	sshbuf_free(msg);
 	free(namespace);
 }
+
+void
+benchmarks(void)
+{
+	printf("no benchmarks\n");
+}
diff --git a/regress/unittests/test_helper/test_helper.c b/regress/unittests/test_helper/test_helper.c
index e23128aa5..b75f77014 100644
--- a/regress/unittests/test_helper/test_helper.c
+++ b/regress/unittests/test_helper/test_helper.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: test_helper.c,v 1.13 2021/12/14 21:25:27 deraadt Exp $	*/
+/*	$OpenBSD: test_helper.c,v 1.14 2025/04/15 04:00:42 djm Exp $	*/
 /*
  * Copyright (c) 2011 Damien Miller <djm at mindrot.org>
  *
@@ -21,18 +21,21 @@
 
 #include <sys/types.h>
 #include <sys/uio.h>
-
-#include <stdarg.h>
+#include <sys/time.h>
+ 
+#include <assert.h>
 #include <fcntl.h>
-#include <stdio.h>
+#include <limits.h>
+#include <math.h>
+#include <signal.h>
+#include <stdarg.h>
 #ifdef HAVE_STDINT_H
 # include <stdint.h>
 #endif
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
-#include <assert.h>
 #include <unistd.h>
-#include <signal.h>
 
 #ifdef WITH_OPENSSL
 #include <openssl/bn.h>
@@ -43,12 +46,21 @@
 # include <vis.h>
 #endif
 
-#define MINIMUM(a, b)    (((a) < (b)) ? (a) : (b))
-
 #include "entropy.h"
 #include "test_helper.h"
 #include "atomicio.h"
+#include "match.h"
+#include "misc.h"
+#include "xmalloc.h"
 
+#define BENCH_FAST_DEADLINE	1
+#define BENCH_NORMAL_DEADLINE	10
+#define BENCH_SLOW_DEADLINE	60
+#define BENCH_SAMPLES_ALLOC	8192
+#define BENCH_COLUMN_WIDTH	40
+
+#define MINIMUM(a, b)    (((a) < (b)) ? (a) : (b))
+ 
 #define TEST_CHECK_INT(r, pred) do {		\
 		switch (pred) {			\
 		case TEST_EQ:			\
@@ -123,6 +135,15 @@ static const char *data_dir = NULL;
 static char subtest_info[512];
 static int fast = 0;
 static int slow = 0;
+static int benchmark_detail_statistics = 0;
+
+static int benchmark = 0;
+static const char *bench_name = NULL;
+static char *benchmark_pattern = NULL;
+static struct timespec bench_start_time, bench_finish_time;
+static struct timespec *bench_samples;
+static int bench_skip, bench_nruns, bench_nalloc;
+double bench_accum_secs;
 
 int
 main(int argc, char **argv)
@@ -147,8 +168,17 @@ main(int argc, char **argv)
 		}
 	}
 
-	while ((ch = getopt(argc, argv, "Ffvqd:")) != -1) {
+	while ((ch = getopt(argc, argv, "O:bBFfvqd:")) != -1) {
 		switch (ch) {
+		case 'b':
+			benchmark = 1;
+			break;
+		case 'B':
+			benchmark = benchmark_detail_statistics = 1;
+			break;
+		case 'O':
+			benchmark_pattern = xstrdup(optarg);
+			break;
 		case 'F':
 			slow = 1;
 			break;
@@ -168,7 +198,8 @@ main(int argc, char **argv)
 			break;
 		default:
 			fprintf(stderr, "Unrecognised command line option\n");
-			fprintf(stderr, "Usage: %s [-v]\n", __progname);
+			fprintf(stderr, "Usage: %s [-vqfFbB] [-d data_dir] "
+			    "[-O pattern]\n", __progname);
 			exit(1);
 		}
 	}
@@ -178,9 +209,12 @@ main(int argc, char **argv)
 	if (verbose_mode)
 		printf("\n");
 
-	tests();
+	if (benchmark)
+		benchmarks();
+	else
+		tests();
 
-	if (!quiet_mode)
+	if (!quiet_mode && !benchmark)
 		printf(" %u tests ok\n", test_number);
 	return 0;
 }
@@ -274,7 +308,7 @@ test_done(void)
 	active_test_name = NULL;
 	if (verbose_mode)
 		printf("OK\n");
-	else if (!quiet_mode) {
+	else if (!quiet_mode && !benchmark) {
 		printf(".");
 		fflush(stdout);
 	}
@@ -290,6 +324,12 @@ test_subtest_info(const char *fmt, ...)
 	va_end(ap);
 }
 
+int
+test_is_benchmark(void)
+{
+	return benchmark;
+}
+
 void
 ssl_err_check(const char *file, int line)
 {
@@ -382,23 +422,6 @@ assert_string(const char *file, int line, const char *a1, const char *a2,
 	test_die();
 }
 
-static char *
-tohex(const void *_s, size_t l)
-{
-	u_int8_t *s = (u_int8_t *)_s;
-	size_t i, j;
-	const char *hex = "0123456789abcdef";
-	char *r = malloc((l * 2) + 1);
-
-	assert(r != NULL);
-	for (i = j = 0; i < l; i++) {
-		r[j++] = hex[(s[i] >> 4) & 0xf];
-		r[j++] = hex[s[i] & 0xf];
-	}
-	r[j] = '\0';
-	return r;
-}
-
 void
 assert_mem(const char *file, int line, const char *a1, const char *a2,
     const void *aa1, const void *aa2, size_t l, enum test_predicate pred)
@@ -593,3 +616,131 @@ assert_ptr(const char *file, int line, const char *a1, const char *a2,
 	test_die();
 }
 
+static double
+tstod(const struct timespec *ts)
+{
+	return (double)ts->tv_sec + ((double)ts->tv_nsec / 1000000000.0);
+}
+
+void
+bench_start(const char *file, int line, const char *name)
+{
+	char *cp;
+
+	if (bench_name != NULL) {
+		fprintf(stderr, "\n%s:%d internal error: BENCH_START() called "
+		    "while previous benchmark \"%s\" incomplete",
+		    file, line, bench_name);
+		abort();
+	}
+	cp = xstrdup(name);
+	lowercase(cp);
+	bench_skip = benchmark_pattern != NULL &&
+	    match_pattern_list(cp, benchmark_pattern, 1) != 1;
+	free(cp);
+
+	bench_name = name;
+	bench_nruns = 0;
+	if (bench_skip)
+		return;
+	free(bench_samples);
+	bench_nalloc = BENCH_SAMPLES_ALLOC;
+	bench_samples = xcalloc(sizeof(*bench_samples), bench_nalloc);
+	bench_accum_secs = 0;
+}
+
+int
+bench_done(void)
+{
+	return bench_skip || bench_accum_secs >= (fast ? BENCH_FAST_DEADLINE :
+	    (slow ? BENCH_SLOW_DEADLINE : BENCH_NORMAL_DEADLINE));
+}
+
+void
+bench_case_start(const char *file, int line)
+{
+	clock_gettime(CLOCK_REALTIME, &bench_start_time);
+}
+
+void
+bench_case_finish(const char *file, int line)
+{
+	struct timespec ts;
+
+	clock_gettime(CLOCK_REALTIME, &bench_finish_time);
+	timespecsub(&bench_finish_time, &bench_start_time, &ts);
+	if (bench_nruns >= bench_nalloc) {
+		if (bench_nalloc >= INT_MAX / 2) {
+			fprintf(stderr, "\n%s:%d benchmark %s too many samples",
+			    __FILE__, __LINE__, bench_name);
+			abort();
+		}
+		bench_samples = xrecallocarray(bench_samples, bench_nalloc,
+		    bench_nalloc * 2, sizeof(*bench_samples));
+		bench_nalloc *= 2;
+	}
+	bench_samples[bench_nruns++] = ts;
+	bench_accum_secs += tstod(&ts);
+}
+
+static int
+tscmp(const void *aa, const void *bb)
+{
+	const struct timespec *a = (const struct timespec *)aa;
+	const struct timespec *b = (const struct timespec *)bb;
+
+	if (timespeccmp(a, b, ==))
+		return 0;
+	return timespeccmp(a, b, <) ? -1 : 1;
+}
+
+void
+bench_finish(const char *file, int line, const char *unit)
+{
+	double std_dev = 0, mean_spr, mean_rps, med_spr, med_rps;
+	int i;
+
+	if (bench_skip)
+		goto done;
+
+	if (bench_nruns < 1) {
+		fprintf(stderr, "\n%s:%d benchmark %s never ran", file, line,
+		    bench_name);
+		abort();
+	}
+	/* median */
+	qsort(bench_samples, bench_nruns, sizeof(*bench_samples), tscmp);
+	i = bench_nruns / 2;
+	med_spr = tstod(&bench_samples[i]);
+	if (bench_nruns > 1 && bench_nruns & 1)
+		med_spr = (med_spr + tstod(&bench_samples[i - 1])) / 2.0;
+	med_rps = (med_spr == 0.0) ? INFINITY : 1.0/med_spr;
+	/* mean */
+	mean_spr = bench_accum_secs / (double)bench_nruns;
+	mean_rps = (mean_spr == 0.0) ? INFINITY : 1.0/mean_spr;
+	/* std. dev */
+	std_dev = 0;
+	for (i = 0; i < bench_nruns; i++) {
+		std_dev = tstod(&bench_samples[i]) - mean_spr;
+		std_dev *= std_dev;
+	}
+	std_dev /= (double)bench_nruns;
+	std_dev = sqrt(std_dev);
+	if (benchmark_detail_statistics) {
+		printf("%s: %d runs in %0.3fs, %0.03f/%0.03f ms/%s "
+		    "(mean/median), std.dev %0.03f ms, "
+		    "%0.2f/%0.2f %s/s (mean/median)\n",
+		    bench_name, bench_nruns, bench_accum_secs,
+		    mean_spr * 1000, med_spr * 1000, unit, std_dev * 1000,
+		    mean_rps, med_rps, unit);
+	} else {
+		printf("%-*s %0.2f %s/s\n", BENCH_COLUMN_WIDTH,
+		    bench_name, med_rps, unit);
+	}
+ done:
+	bench_name = NULL;
+	bench_nruns = 0;
+	free(bench_samples);
+	bench_samples = NULL;
+	bench_skip = 0;
+}
diff --git a/regress/unittests/test_helper/test_helper.h b/regress/unittests/test_helper/test_helper.h
index 66302201c..23338af38 100644
--- a/regress/unittests/test_helper/test_helper.h
+++ b/regress/unittests/test_helper/test_helper.h
@@ -1,4 +1,4 @@
-/*	$OpenBSD: test_helper.h,v 1.9 2018/10/17 23:28:05 djm Exp $	*/
+/*	$OpenBSD: test_helper.h,v 1.10 2025/04/15 04:00:42 djm Exp $	*/
 /*
  * Copyright (c) 2011 Damien Miller <djm at mindrot.org>
  *
@@ -39,6 +39,7 @@ typedef void (test_onerror_func_t)(void *);
 
 /* Supplied by test suite */
 void tests(void);
+void benchmarks(void);
 
 const char *test_data_file(const char *name);
 void test_start(const char *n);
@@ -49,6 +50,7 @@ int test_is_verbose(void);
 int test_is_quiet(void);
 int test_is_fast(void);
 int test_is_slow(void);
+int test_is_benchmark(void);
 void test_subtest_info(const char *fmt, ...)
     __attribute__((format(printf, 1, 2)));
 void ssl_err_check(const char *file, int line);
@@ -285,6 +287,26 @@ void assert_u64(const char *file, int line,
 #define ASSERT_U64_GE(a1, a2) \
 	assert_u64(__FILE__, __LINE__, #a1, #a2, a1, a2, TEST_GE)
 
+/* Benchmarking support */
+#define BENCH_START(name)	\
+	do { \
+		bench_start(__FILE__, __LINE__, name); \
+		while (!bench_done()) { \
+			bench_case_start(__FILE__, __LINE__); \
+			do {
+#define BENCH_FINISH(unit) \
+			} while (0); \
+			bench_case_finish(__FILE__, __LINE__); \
+		} \
+		bench_finish(__FILE__, __LINE__, unit); \
+	} while (0)
+
+void bench_start(const char *file, int line, const char *name);
+void bench_case_start(const char *file, int line);
+void bench_case_finish(const char *file, int line);
+void bench_finish(const char *file, int line, const char *unit);
+int bench_done(void);
+
 /* Fuzzing support */
 
 struct fuzz;
diff --git a/regress/unittests/utf8/Makefile b/regress/unittests/utf8/Makefile
index f8eec0484..e89536500 100644
--- a/regress/unittests/utf8/Makefile
+++ b/regress/unittests/utf8/Makefile
@@ -1,14 +1,15 @@
-#	$OpenBSD: Makefile,v 1.5 2017/12/21 00:41:22 djm Exp $
+#	$OpenBSD: Makefile,v 1.6 2025/04/15 04:00:42 djm Exp $
 
 PROG=test_utf8
 SRCS=tests.c
 
 # From usr.bin/ssh
-SRCS+=utf8.c atomicio.c
+SRCS+=utf8.c atomicio.c misc.c xmalloc.c match.c ssherr.c cleanup.c fatal.c
+SRCS+=sshbuf.c sshbuf-getput-basic.c sshbuf-misc.c addr.c addrmatch.c log.c
 
 REGRESS_TARGETS=run-regress-${PROG}
 
 run-regress-${PROG}: ${PROG}
-	env ${TEST_ENV} ./${PROG}
+	env ${TEST_ENV} ./${PROG} ${UNITTEST_ARGS}
 
 .include <bsd.regress.mk>
diff --git a/regress/unittests/utf8/tests.c b/regress/unittests/utf8/tests.c
index 8cf524ddb..3fb63415e 100644
--- a/regress/unittests/utf8/tests.c
+++ b/regress/unittests/utf8/tests.c
@@ -1,4 +1,4 @@
-/*	$OpenBSD: tests.c,v 1.4 2017/02/19 00:11:29 djm Exp $ */
+/*	$OpenBSD: tests.c,v 1.5 2025/04/15 04:00:42 djm Exp $ */
 /*
  * Regress test for the utf8.h *mprintf() API
  *
@@ -102,3 +102,9 @@ tests(void)
 	one(0, "double_fit", "a\343\201\201", 7, 5, -1, "a\\343");
 	one(0, "double_spc", "a\343\201\201", 13, 13, 13, "a\\343\\201\\201");
 }
+
+void
+benchmarks(void)
+{
+	printf("no benchmarks\n");
+}

-- 
To stop receiving notification emails like this one, please contact
djm at mindrot.org.


More information about the openssh-commits mailing list