xref: /openbsd/regress/lib/libcrypto/bn/bn_general.c (revision b2cabbc1)
1 /*	$OpenBSD: bn_general.c,v 1.2 2023/04/11 05:53:53 jsing Exp $ */
2 /*
3  * Copyright (c) 2022, 2023 Joel Sing <jsing@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/resource.h>
19 #include <sys/time.h>
20 
21 #include <err.h>
22 #include <signal.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <time.h>
26 #include <unistd.h>
27 
28 #include <openssl/bn.h>
29 
30 static void
benchmark_bn_copy_setup(BIGNUM * dst,BIGNUM * src,int n)31 benchmark_bn_copy_setup(BIGNUM *dst, BIGNUM *src, int n)
32 {
33 	if (!BN_set_bit(dst, n - 1))
34 		errx(1, "BN_set_bit");
35 	if (!BN_set_bit(src, n - 1))
36 		errx(1, "BN_set_bit");
37 }
38 
39 static void
benchmark_bn_copy_run_once(BIGNUM * dst,BIGNUM * src)40 benchmark_bn_copy_run_once(BIGNUM *dst, BIGNUM *src)
41 {
42 	if (BN_copy(dst, src) == NULL)
43 		errx(1, "BN_copy");
44 }
45 
46 struct benchmark {
47 	const char *desc;
48 	void (*setup)(BIGNUM *, BIGNUM *, int);
49 	void (*run_once)(BIGNUM *, BIGNUM *);
50 	int bits;
51 };
52 
53 struct benchmark benchmarks[] = {
54 	{
55 		.desc = "BN_copy() 32 bits",
56 		.setup = benchmark_bn_copy_setup,
57 		.run_once = benchmark_bn_copy_run_once,
58 		.bits = 32,
59 	},
60 	{
61 		.desc = "BN_copy() 256 bits",
62 		.setup = benchmark_bn_copy_setup,
63 		.run_once = benchmark_bn_copy_run_once,
64 		.bits = 256,
65 	},
66 	{
67 		.desc = "BN_copy() 320 bits",
68 		.setup = benchmark_bn_copy_setup,
69 		.run_once = benchmark_bn_copy_run_once,
70 		.bits = 320,
71 	},
72 	{
73 		.desc = "BN_copy() 512 bits",
74 		.setup = benchmark_bn_copy_setup,
75 		.run_once = benchmark_bn_copy_run_once,
76 		.bits = 512,
77 	},
78 	{
79 		.desc = "BN_copy() 1024 bits",
80 		.setup = benchmark_bn_copy_setup,
81 		.run_once = benchmark_bn_copy_run_once,
82 		.bits = 1024,
83 	},
84 	{
85 		.desc = "BN_copy() 2048 bits",
86 		.setup = benchmark_bn_copy_setup,
87 		.run_once = benchmark_bn_copy_run_once,
88 		.bits = 2048,
89 	},
90 	{
91 		.desc = "BN_copy() 4096 bits",
92 		.setup = benchmark_bn_copy_setup,
93 		.run_once = benchmark_bn_copy_run_once,
94 		.bits = 4096,
95 	},
96 	{
97 		.desc = "BN_copy() 16384 bits",
98 		.setup = benchmark_bn_copy_setup,
99 		.run_once = benchmark_bn_copy_run_once,
100 		.bits = 16384,
101 	},
102 };
103 
104 #define N_BENCHMARKS (sizeof(benchmarks) / sizeof(benchmarks[0]))
105 
106 static int benchmark_stop;
107 
108 static void
benchmark_sig_alarm(int sig)109 benchmark_sig_alarm(int sig)
110 {
111 	benchmark_stop = 1;
112 }
113 
114 static void
benchmark_run(const struct benchmark * bm,int seconds)115 benchmark_run(const struct benchmark *bm, int seconds)
116 {
117 	struct timespec start, end, duration;
118 	struct rusage rusage;
119 	BIGNUM *dst, *src;
120 	int i;
121 
122 	signal(SIGALRM, benchmark_sig_alarm);
123 
124 	if ((src = BN_new()) == NULL)
125 		errx(1, "BN_new");
126 	if ((dst = BN_new()) == NULL)
127 		errx(1, "BN_new");
128 
129 	bm->setup(dst, src, bm->bits);
130 
131 	benchmark_stop = 0;
132 	i = 0;
133 	alarm(seconds);
134 
135 	if (getrusage(RUSAGE_SELF, &rusage) == -1)
136 		err(1, "getrusage failed");
137 	TIMEVAL_TO_TIMESPEC(&rusage.ru_utime, &start);
138 
139 	fprintf(stderr, "Benchmarking %s for %ds: ", bm->desc, seconds);
140 	while (!benchmark_stop) {
141 		bm->run_once(dst, src);
142 		i++;
143 	}
144 	if (getrusage(RUSAGE_SELF, &rusage) == -1)
145 		err(1, "getrusage failed");
146 	TIMEVAL_TO_TIMESPEC(&rusage.ru_utime, &end);
147 
148 	timespecsub(&end, &start, &duration);
149 	fprintf(stderr, "%d iterations in %f seconds - %llu op/s\n", i,
150 	    duration.tv_sec + duration.tv_nsec / 1000000000.0,
151 	    (uint64_t)i * 1000000000 /
152 	    (duration.tv_sec * 1000000000 + duration.tv_nsec));
153 
154 	BN_free(src);
155 	BN_free(dst);
156 }
157 
158 static void
benchmark_bn_general(void)159 benchmark_bn_general(void)
160 {
161 	const struct benchmark *bm;
162 	size_t i;
163 
164 	for (i = 0; i < N_BENCHMARKS; i++) {
165 		bm = &benchmarks[i];
166 		benchmark_run(bm, 5);
167 	}
168 }
169 
170 int
main(int argc,char ** argv)171 main(int argc, char **argv)
172 {
173 	int benchmark = 0, failed = 0;
174 
175 	if (argc == 2 && strcmp(argv[1], "--benchmark") == 0)
176 		benchmark = 1;
177 
178 	if (benchmark && !failed)
179 		benchmark_bn_general();
180 
181 	return failed;
182 }
183