Merge branch 'maint-0.4.5' into release-0.4.5
[tor.git] / src / test / bench.c
blob7a8c04e802237f9a115cdf22ea1d738051b42f76
1 /* Copyright (c) 2001-2004, Roger Dingledine.
2 * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
3 * Copyright (c) 2007-2020, The Tor Project, Inc. */
4 /* See LICENSE for licensing information */
6 /**
7 * \file bench.c
8 * \brief Benchmarks for lower level Tor modules.
9 **/
11 #include "orconfig.h"
13 #include "core/or/or.h"
14 #include "core/crypto/onion_tap.h"
15 #include "core/crypto/relay_crypto.h"
17 #include "lib/intmath/weakrng.h"
19 #ifdef ENABLE_OPENSSL
20 #include <openssl/opensslv.h>
21 #include <openssl/evp.h>
22 #include <openssl/ec.h>
23 #include <openssl/ecdh.h>
24 #include <openssl/obj_mac.h>
25 #endif /* defined(ENABLE_OPENSSL) */
27 #include "core/or/circuitlist.h"
28 #include "app/config/config.h"
29 #include "app/main/subsysmgr.h"
30 #include "lib/crypt_ops/crypto_curve25519.h"
31 #include "lib/crypt_ops/crypto_dh.h"
32 #include "core/crypto/onion_ntor.h"
33 #include "lib/crypt_ops/crypto_ed25519.h"
34 #include "lib/crypt_ops/crypto_rand.h"
35 #include "feature/dircommon/consdiff.h"
36 #include "lib/compress/compress.h"
38 #include "core/or/cell_st.h"
39 #include "core/or/or_circuit_st.h"
41 #include "lib/crypt_ops/digestset.h"
42 #include "lib/crypt_ops/crypto_init.h"
44 #include "feature/dirparse/microdesc_parse.h"
45 #include "feature/nodelist/microdesc.h"
47 #if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID)
48 static uint64_t nanostart;
49 static inline uint64_t
50 timespec_to_nsec(const struct timespec *ts)
52 return ((uint64_t)ts->tv_sec)*1000000000 + ts->tv_nsec;
55 static void
56 reset_perftime(void)
58 struct timespec ts;
59 int r;
60 r = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
61 tor_assert(r == 0);
62 nanostart = timespec_to_nsec(&ts);
65 static uint64_t
66 perftime(void)
68 struct timespec ts;
69 int r;
70 r = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
71 tor_assert(r == 0);
72 return timespec_to_nsec(&ts) - nanostart;
75 #else /* !(defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID)) */
76 static struct timeval tv_start = { 0, 0 };
77 static void
78 reset_perftime(void)
80 tor_gettimeofday(&tv_start);
82 static uint64_t
83 perftime(void)
85 struct timeval now, out;
86 tor_gettimeofday(&now);
87 timersub(&now, &tv_start, &out);
88 return ((uint64_t)out.tv_sec)*1000000000 + out.tv_usec*1000;
90 #endif /* defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID) */
92 #define NANOCOUNT(start,end,iters) \
93 ( ((double)((end)-(start))) / (iters) )
95 #define MICROCOUNT(start,end,iters) \
96 ( NANOCOUNT((start), (end), (iters)) / 1000.0 )
98 /** Run AES performance benchmarks. */
99 static void
100 bench_aes(void)
102 int len, i;
103 char *b1, *b2;
104 crypto_cipher_t *c;
105 uint64_t start, end;
106 const int bytes_per_iter = (1<<24);
107 reset_perftime();
108 char key[CIPHER_KEY_LEN];
109 crypto_rand(key, sizeof(key));
110 c = crypto_cipher_new(key);
112 for (len = 1; len <= 8192; len *= 2) {
113 int iters = bytes_per_iter / len;
114 b1 = tor_malloc_zero(len);
115 b2 = tor_malloc_zero(len);
116 start = perftime();
117 for (i = 0; i < iters; ++i) {
118 crypto_cipher_encrypt(c, b1, b2, len);
120 end = perftime();
121 tor_free(b1);
122 tor_free(b2);
123 printf("%d bytes: %.2f nsec per byte\n", len,
124 NANOCOUNT(start, end, iters*len));
126 crypto_cipher_free(c);
129 static void
130 bench_onion_TAP(void)
132 const int iters = 1<<9;
133 int i;
134 crypto_pk_t *key, *key2;
135 uint64_t start, end;
136 char os[TAP_ONIONSKIN_CHALLENGE_LEN];
137 char or[TAP_ONIONSKIN_REPLY_LEN];
138 crypto_dh_t *dh_out = NULL;
140 key = crypto_pk_new();
141 key2 = crypto_pk_new();
142 if (crypto_pk_generate_key_with_bits(key, 1024) < 0)
143 goto done;
144 if (crypto_pk_generate_key_with_bits(key2, 1024) < 0)
145 goto done;
147 reset_perftime();
148 start = perftime();
149 for (i = 0; i < iters; ++i) {
150 onion_skin_TAP_create(key, &dh_out, os);
151 crypto_dh_free(dh_out);
153 end = perftime();
154 printf("Client-side, part 1: %f usec.\n", NANOCOUNT(start, end, iters)/1e3);
156 onion_skin_TAP_create(key, &dh_out, os);
157 start = perftime();
158 for (i = 0; i < iters; ++i) {
159 char key_out[CPATH_KEY_MATERIAL_LEN];
160 onion_skin_TAP_server_handshake(os, key, NULL, or,
161 key_out, sizeof(key_out));
163 end = perftime();
164 printf("Server-side, key guessed right: %f usec\n",
165 NANOCOUNT(start, end, iters)/1e3);
167 start = perftime();
168 for (i = 0; i < iters; ++i) {
169 char key_out[CPATH_KEY_MATERIAL_LEN];
170 onion_skin_TAP_server_handshake(os, key2, key, or,
171 key_out, sizeof(key_out));
173 end = perftime();
174 printf("Server-side, key guessed wrong: %f usec.\n",
175 NANOCOUNT(start, end, iters)/1e3);
177 start = perftime();
178 for (i = 0; i < iters; ++i) {
179 crypto_dh_t *dh;
180 char key_out[CPATH_KEY_MATERIAL_LEN];
181 int s;
182 dh = crypto_dh_dup(dh_out);
183 s = onion_skin_TAP_client_handshake(dh, or, key_out, sizeof(key_out),
184 NULL);
185 crypto_dh_free(dh);
186 tor_assert(s == 0);
188 end = perftime();
189 printf("Client-side, part 2: %f usec.\n",
190 NANOCOUNT(start, end, iters)/1e3);
192 done:
193 crypto_dh_free(dh_out);
194 crypto_pk_free(key);
195 crypto_pk_free(key2);
198 static void
199 bench_onion_ntor_impl(void)
201 const int iters = 1<<10;
202 int i;
203 curve25519_keypair_t keypair1, keypair2;
204 uint64_t start, end;
205 uint8_t os[NTOR_ONIONSKIN_LEN];
206 uint8_t or[NTOR_REPLY_LEN];
207 ntor_handshake_state_t *state = NULL;
208 uint8_t nodeid[DIGEST_LEN];
209 di_digest256_map_t *keymap = NULL;
211 curve25519_secret_key_generate(&keypair1.seckey, 0);
212 curve25519_public_key_generate(&keypair1.pubkey, &keypair1.seckey);
213 curve25519_secret_key_generate(&keypair2.seckey, 0);
214 curve25519_public_key_generate(&keypair2.pubkey, &keypair2.seckey);
215 dimap_add_entry(&keymap, keypair1.pubkey.public_key, &keypair1);
216 dimap_add_entry(&keymap, keypair2.pubkey.public_key, &keypair2);
217 crypto_rand((char *)nodeid, sizeof(nodeid));
219 reset_perftime();
220 start = perftime();
221 for (i = 0; i < iters; ++i) {
222 onion_skin_ntor_create(nodeid, &keypair1.pubkey, &state, os);
223 ntor_handshake_state_free(state);
224 state = NULL;
226 end = perftime();
227 printf("Client-side, part 1: %f usec.\n", NANOCOUNT(start, end, iters)/1e3);
229 state = NULL;
230 onion_skin_ntor_create(nodeid, &keypair1.pubkey, &state, os);
231 start = perftime();
232 for (i = 0; i < iters; ++i) {
233 uint8_t key_out[CPATH_KEY_MATERIAL_LEN];
234 onion_skin_ntor_server_handshake(os, keymap, NULL, nodeid, or,
235 key_out, sizeof(key_out));
237 end = perftime();
238 printf("Server-side: %f usec\n",
239 NANOCOUNT(start, end, iters)/1e3);
241 start = perftime();
242 for (i = 0; i < iters; ++i) {
243 uint8_t key_out[CPATH_KEY_MATERIAL_LEN];
244 int s;
245 s = onion_skin_ntor_client_handshake(state, or, key_out, sizeof(key_out),
246 NULL);
247 tor_assert(s == 0);
249 end = perftime();
250 printf("Client-side, part 2: %f usec.\n",
251 NANOCOUNT(start, end, iters)/1e3);
253 ntor_handshake_state_free(state);
254 dimap_free(keymap, NULL);
257 static void
258 bench_onion_ntor(void)
260 int ed;
262 for (ed = 0; ed <= 1; ++ed) {
263 printf("Ed25519-based basepoint multiply = %s.\n",
264 (ed == 0) ? "disabled" : "enabled");
265 curve25519_set_impl_params(ed);
266 bench_onion_ntor_impl();
270 static void
271 bench_ed25519_impl(void)
273 uint64_t start, end;
274 const int iters = 1<<12;
275 int i;
276 const uint8_t msg[] = "but leaving, could not tell what they had heard";
277 ed25519_signature_t sig;
278 ed25519_keypair_t kp;
279 curve25519_keypair_t curve_kp;
280 ed25519_public_key_t pubkey_tmp;
282 ed25519_secret_key_generate(&kp.seckey, 0);
283 start = perftime();
284 for (i = 0; i < iters; ++i) {
285 ed25519_public_key_generate(&kp.pubkey, &kp.seckey);
287 end = perftime();
288 printf("Generate public key: %.2f usec\n",
289 MICROCOUNT(start, end, iters));
291 start = perftime();
292 for (i = 0; i < iters; ++i) {
293 ed25519_sign(&sig, msg, sizeof(msg), &kp);
295 end = perftime();
296 printf("Sign a short message: %.2f usec\n",
297 MICROCOUNT(start, end, iters));
299 start = perftime();
300 for (i = 0; i < iters; ++i) {
301 ed25519_checksig(&sig, msg, sizeof(msg), &kp.pubkey);
303 end = perftime();
304 printf("Verify signature: %.2f usec\n",
305 MICROCOUNT(start, end, iters));
307 curve25519_keypair_generate(&curve_kp, 0);
308 start = perftime();
309 for (i = 0; i < iters; ++i) {
310 ed25519_public_key_from_curve25519_public_key(&pubkey_tmp,
311 &curve_kp.pubkey, 1);
313 end = perftime();
314 printf("Convert public point from curve25519: %.2f usec\n",
315 MICROCOUNT(start, end, iters));
317 curve25519_keypair_generate(&curve_kp, 0);
318 start = perftime();
319 for (i = 0; i < iters; ++i) {
320 ed25519_public_blind(&pubkey_tmp, &kp.pubkey, msg);
322 end = perftime();
323 printf("Blind a public key: %.2f usec\n",
324 MICROCOUNT(start, end, iters));
327 static void
328 bench_ed25519(void)
330 int donna;
332 for (donna = 0; donna <= 1; ++donna) {
333 printf("Ed25519-donna = %s.\n",
334 (donna == 0) ? "disabled" : "enabled");
335 ed25519_set_impl_params(donna);
336 bench_ed25519_impl();
340 static void
341 bench_rand_len(int len)
343 const int N = 100000;
344 int i;
345 char *buf = tor_malloc(len);
346 uint64_t start,end;
348 start = perftime();
349 for (i = 0; i < N; ++i) {
350 crypto_rand(buf, len);
352 end = perftime();
353 printf("crypto_rand(%d): %f nsec.\n", len, NANOCOUNT(start,end,N));
355 crypto_fast_rng_t *fr = crypto_fast_rng_new();
356 start = perftime();
357 for (i = 0; i < N; ++i) {
358 crypto_fast_rng_getbytes(fr,(uint8_t*)buf,len);
360 end = perftime();
361 printf("crypto_fast_rng_getbytes(%d): %f nsec.\n", len,
362 NANOCOUNT(start,end,N));
363 crypto_fast_rng_free(fr);
365 if (len <= 32) {
366 start = perftime();
367 for (i = 0; i < N; ++i) {
368 crypto_strongest_rand((uint8_t*)buf, len);
370 end = perftime();
371 printf("crypto_strongest_rand(%d): %f nsec.\n", len,
372 NANOCOUNT(start,end,N));
375 if (len == 4) {
376 tor_weak_rng_t weak;
377 tor_init_weak_random(&weak, 1337);
379 start = perftime();
380 uint32_t t=0;
381 for (i = 0; i < N; ++i) {
382 t += tor_weak_random(&weak);
384 end = perftime();
385 printf("weak_rand(4): %f nsec.\n", NANOCOUNT(start,end,N));
388 tor_free(buf);
391 static void
392 bench_rand(void)
394 bench_rand_len(4);
395 bench_rand_len(16);
396 bench_rand_len(128);
399 static void
400 bench_cell_aes(void)
402 uint64_t start, end;
403 const int len = 509;
404 const int iters = (1<<16);
405 const int max_misalign = 15;
406 char *b = tor_malloc(len+max_misalign);
407 crypto_cipher_t *c;
408 int i, misalign;
409 char key[CIPHER_KEY_LEN];
410 crypto_rand(key, sizeof(key));
411 c = crypto_cipher_new(key);
413 reset_perftime();
414 for (misalign = 0; misalign <= max_misalign; ++misalign) {
415 start = perftime();
416 for (i = 0; i < iters; ++i) {
417 crypto_cipher_crypt_inplace(c, b+misalign, len);
419 end = perftime();
420 printf("%d bytes, misaligned by %d: %.2f nsec per byte\n", len, misalign,
421 NANOCOUNT(start, end, iters*len));
424 crypto_cipher_free(c);
425 tor_free(b);
428 /** Run digestmap_t performance benchmarks. */
429 static void
430 bench_dmap(void)
432 smartlist_t *sl = smartlist_new();
433 smartlist_t *sl2 = smartlist_new();
434 uint64_t start, end, pt2, pt3, pt4;
435 int iters = 8192;
436 const int elts = 4000;
437 const int fpostests = 100000;
438 char d[20];
439 int i,n=0, fp = 0;
440 digestmap_t *dm = digestmap_new();
441 digestset_t *ds = digestset_new(elts);
443 for (i = 0; i < elts; ++i) {
444 crypto_rand(d, 20);
445 smartlist_add(sl, tor_memdup(d, 20));
447 for (i = 0; i < elts; ++i) {
448 crypto_rand(d, 20);
449 smartlist_add(sl2, tor_memdup(d, 20));
451 //printf("nbits=%d\n", ds->mask+1);
453 reset_perftime();
455 start = perftime();
456 for (i = 0; i < iters; ++i) {
457 SMARTLIST_FOREACH(sl, const char *, cp, digestmap_set(dm, cp, (void*)1));
459 pt2 = perftime();
460 printf("digestmap_set: %.2f ns per element\n",
461 NANOCOUNT(start, pt2, iters*elts));
463 for (i = 0; i < iters; ++i) {
464 SMARTLIST_FOREACH(sl, const char *, cp, digestmap_get(dm, cp));
465 SMARTLIST_FOREACH(sl2, const char *, cp, digestmap_get(dm, cp));
467 pt3 = perftime();
468 printf("digestmap_get: %.2f ns per element\n",
469 NANOCOUNT(pt2, pt3, iters*elts*2));
471 for (i = 0; i < iters; ++i) {
472 SMARTLIST_FOREACH(sl, const char *, cp, digestset_add(ds, cp));
474 pt4 = perftime();
475 printf("digestset_add: %.2f ns per element\n",
476 NANOCOUNT(pt3, pt4, iters*elts));
478 for (i = 0; i < iters; ++i) {
479 SMARTLIST_FOREACH(sl, const char *, cp,
480 n += digestset_probably_contains(ds, cp));
481 SMARTLIST_FOREACH(sl2, const char *, cp,
482 n += digestset_probably_contains(ds, cp));
484 end = perftime();
485 printf("digestset_probably_contains: %.2f ns per element.\n",
486 NANOCOUNT(pt4, end, iters*elts*2));
487 /* We need to use this, or else the whole loop gets optimized out. */
488 printf("Hits == %d\n", n);
490 for (i = 0; i < fpostests; ++i) {
491 crypto_rand(d, 20);
492 if (digestset_probably_contains(ds, d)) ++fp;
494 printf("False positive rate on digestset: %.2f%%\n",
495 (fp/(double)fpostests)*100);
497 digestmap_free(dm, NULL);
498 digestset_free(ds);
499 SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp));
500 SMARTLIST_FOREACH(sl2, char *, cp, tor_free(cp));
501 smartlist_free(sl);
502 smartlist_free(sl2);
505 static void
506 bench_siphash(void)
508 char buf[128];
509 int lens[] = { 7, 8, 15, 16, 20, 32, 111, 128, -1 };
510 int i, j;
511 uint64_t start, end;
512 const int N = 300000;
513 crypto_rand(buf, sizeof(buf));
515 for (i = 0; lens[i] > 0; ++i) {
516 reset_perftime();
517 start = perftime();
518 for (j = 0; j < N; ++j) {
519 siphash24g(buf, lens[i]);
521 end = perftime();
522 printf("siphash24g(%d): %.2f ns per call\n",
523 lens[i], NANOCOUNT(start,end,N));
527 static void
528 bench_digest(void)
530 char buf[8192];
531 char out[DIGEST512_LEN];
532 const int lens[] = { 1, 16, 32, 64, 128, 512, 1024, 2048, -1 };
533 const int N = 300000;
534 uint64_t start, end;
535 crypto_rand(buf, sizeof(buf));
537 for (int alg = 0; alg < N_DIGEST_ALGORITHMS; alg++) {
538 for (int i = 0; lens[i] > 0; ++i) {
539 reset_perftime();
540 start = perftime();
541 int failures = 0;
542 for (int j = 0; j < N; ++j) {
543 switch (alg) {
544 case DIGEST_SHA1:
545 failures += crypto_digest(out, buf, lens[i]) < 0;
546 break;
547 case DIGEST_SHA256:
548 case DIGEST_SHA3_256:
549 failures += crypto_digest256(out, buf, lens[i], alg) < 0;
550 break;
551 case DIGEST_SHA512:
552 case DIGEST_SHA3_512:
553 failures += crypto_digest512(out, buf, lens[i], alg) < 0;
554 break;
555 default:
556 tor_assert(0);
559 end = perftime();
560 printf("%s(%d): %.2f ns per call\n",
561 crypto_digest_algorithm_get_name(alg),
562 lens[i], NANOCOUNT(start,end,N));
563 if (failures)
564 printf("ERROR: crypto_digest failed %d times.\n", failures);
569 static void
570 bench_cell_ops(void)
572 const int iters = 1<<16;
573 int i;
575 /* benchmarks for cell ops at relay. */
576 or_circuit_t *or_circ = tor_malloc_zero(sizeof(or_circuit_t));
577 cell_t *cell = tor_malloc(sizeof(cell_t));
578 int outbound;
579 uint64_t start, end;
581 crypto_rand((char*)cell->payload, sizeof(cell->payload));
583 /* Mock-up or_circuit_t */
584 or_circ->base_.magic = OR_CIRCUIT_MAGIC;
585 or_circ->base_.purpose = CIRCUIT_PURPOSE_OR;
587 /* Initialize crypto */
588 char key1[CIPHER_KEY_LEN], key2[CIPHER_KEY_LEN];
589 crypto_rand(key1, sizeof(key1));
590 crypto_rand(key2, sizeof(key2));
591 or_circ->crypto.f_crypto = crypto_cipher_new(key1);
592 or_circ->crypto.b_crypto = crypto_cipher_new(key2);
593 or_circ->crypto.f_digest = crypto_digest_new();
594 or_circ->crypto.b_digest = crypto_digest_new();
596 reset_perftime();
598 for (outbound = 0; outbound <= 1; ++outbound) {
599 cell_direction_t d = outbound ? CELL_DIRECTION_OUT : CELL_DIRECTION_IN;
600 start = perftime();
601 for (i = 0; i < iters; ++i) {
602 char recognized = 0;
603 crypt_path_t *layer_hint = NULL;
604 relay_decrypt_cell(TO_CIRCUIT(or_circ), cell, d,
605 &layer_hint, &recognized);
607 end = perftime();
608 printf("%sbound cells: %.2f ns per cell. (%.2f ns per byte of payload)\n",
609 outbound?"Out":" In",
610 NANOCOUNT(start,end,iters),
611 NANOCOUNT(start,end,iters*CELL_PAYLOAD_SIZE));
614 relay_crypto_clear(&or_circ->crypto);
615 tor_free(or_circ);
616 tor_free(cell);
619 static void
620 bench_dh(void)
622 const int iters = 1<<10;
623 int i;
624 uint64_t start, end;
626 reset_perftime();
627 start = perftime();
628 for (i = 0; i < iters; ++i) {
629 char dh_pubkey_a[DH1024_KEY_LEN], dh_pubkey_b[DH1024_KEY_LEN];
630 char secret_a[DH1024_KEY_LEN], secret_b[DH1024_KEY_LEN];
631 ssize_t slen_a, slen_b;
632 crypto_dh_t *dh_a = crypto_dh_new(DH_TYPE_TLS);
633 crypto_dh_t *dh_b = crypto_dh_new(DH_TYPE_TLS);
634 crypto_dh_generate_public(dh_a);
635 crypto_dh_generate_public(dh_b);
636 crypto_dh_get_public(dh_a, dh_pubkey_a, sizeof(dh_pubkey_a));
637 crypto_dh_get_public(dh_b, dh_pubkey_b, sizeof(dh_pubkey_b));
638 slen_a = crypto_dh_compute_secret(LOG_NOTICE,
639 dh_a, dh_pubkey_b, sizeof(dh_pubkey_b),
640 secret_a, sizeof(secret_a));
641 slen_b = crypto_dh_compute_secret(LOG_NOTICE,
642 dh_b, dh_pubkey_a, sizeof(dh_pubkey_a),
643 secret_b, sizeof(secret_b));
644 tor_assert(slen_a == slen_b);
645 tor_assert(fast_memeq(secret_a, secret_b, slen_a));
646 crypto_dh_free(dh_a);
647 crypto_dh_free(dh_b);
649 end = perftime();
650 printf("Complete DH handshakes (1024 bit, public and private ops):\n"
651 " %f millisec each.\n", NANOCOUNT(start, end, iters)/1e6);
654 #ifdef ENABLE_OPENSSL
655 static void
656 bench_ecdh_impl(int nid, const char *name)
658 const int iters = 1<<10;
659 int i;
660 uint64_t start, end;
662 reset_perftime();
663 start = perftime();
664 for (i = 0; i < iters; ++i) {
665 char secret_a[DH1024_KEY_LEN], secret_b[DH1024_KEY_LEN];
666 ssize_t slen_a, slen_b;
667 EC_KEY *dh_a = EC_KEY_new_by_curve_name(nid);
668 EC_KEY *dh_b = EC_KEY_new_by_curve_name(nid);
669 if (!dh_a || !dh_b) {
670 puts("Skipping. (No implementation?)");
671 return;
674 EC_KEY_generate_key(dh_a);
675 EC_KEY_generate_key(dh_b);
676 slen_a = ECDH_compute_key(secret_a, DH1024_KEY_LEN,
677 EC_KEY_get0_public_key(dh_b), dh_a,
678 NULL);
679 slen_b = ECDH_compute_key(secret_b, DH1024_KEY_LEN,
680 EC_KEY_get0_public_key(dh_a), dh_b,
681 NULL);
683 tor_assert(slen_a == slen_b);
684 tor_assert(fast_memeq(secret_a, secret_b, slen_a));
685 EC_KEY_free(dh_a);
686 EC_KEY_free(dh_b);
688 end = perftime();
689 printf("Complete ECDH %s handshakes (2 public and 2 private ops):\n"
690 " %f millisec each.\n", name, NANOCOUNT(start, end, iters)/1e6);
693 static void
694 bench_ecdh_p256(void)
696 bench_ecdh_impl(NID_X9_62_prime256v1, "P-256");
699 static void
700 bench_ecdh_p224(void)
702 bench_ecdh_impl(NID_secp224r1, "P-224");
704 #endif /* defined(ENABLE_OPENSSL) */
706 static void
707 bench_md_parse(void)
709 uint64_t start, end;
710 const int N = 100000;
711 // selected arbitrarily
712 const char md_text[] =
713 "@last-listed 2018-12-14 18:14:14\n"
714 "onion-key\n"
715 "-----BEGIN RSA PUBLIC KEY-----\n"
716 "MIGJAoGBAMHkZeXNDX/49JqM2BVLmh1Fnb5iMVnatvZZTLJyedqDLkbXZ1WKP5oh\n"
717 "7ec14dj/k3ntpwHD4s2o3Lb6nfagWbug4+F/rNJ7JuFru/PSyOvDyHGNAuegOXph\n"
718 "3gTGjdDpv/yPoiadGebbVe8E7n6hO+XxM2W/4dqheKimF0/s9B7HAgMBAAE=\n"
719 "-----END RSA PUBLIC KEY-----\n"
720 "ntor-onion-key QgF/EjqlNG1wRHLIop/nCekEH+ETGZSgYOhu26eiTF4=\n"
721 "family $00E9A86E7733240E60D8435A7BBD634A23894098 "
722 "$329BD7545DEEEBBDC8C4285F243916F248972102 "
723 "$69E06EBB2573A4F89330BDF8BC869794A3E10E4D "
724 "$DCA2A3FAE50B3729DAA15BC95FB21AF03389818B\n"
725 "p accept 53,80,443,5222-5223,25565\n"
726 "id ed25519 BzffzY99z6Q8KltcFlUTLWjNTBU7yKK+uQhyi1Ivb3A\n";
728 reset_perftime();
729 start = perftime();
730 for (int i = 0; i < N; ++i) {
731 smartlist_t *s = microdescs_parse_from_string(md_text, NULL, 1,
732 SAVED_IN_CACHE, NULL);
733 SMARTLIST_FOREACH(s, microdesc_t *, md, microdesc_free(md));
734 smartlist_free(s);
737 end = perftime();
738 printf("Microdesc parse: %f nsec\n", NANOCOUNT(start, end, N));
741 typedef void (*bench_fn)(void);
743 typedef struct benchmark_t {
744 const char *name;
745 bench_fn fn;
746 int enabled;
747 } benchmark_t;
749 #define ENT(s) { #s , bench_##s, 0 }
751 static struct benchmark_t benchmarks[] = {
752 ENT(dmap),
753 ENT(siphash),
754 ENT(digest),
755 ENT(aes),
756 ENT(onion_TAP),
757 ENT(onion_ntor),
758 ENT(ed25519),
759 ENT(rand),
761 ENT(cell_aes),
762 ENT(cell_ops),
763 ENT(dh),
765 #ifdef ENABLE_OPENSSL
766 ENT(ecdh_p256),
767 ENT(ecdh_p224),
768 #endif
770 ENT(md_parse),
771 {NULL,NULL,0}
774 static benchmark_t *
775 find_benchmark(const char *name)
777 benchmark_t *b;
778 for (b = benchmarks; b->name; ++b) {
779 if (!strcmp(name, b->name)) {
780 return b;
783 return NULL;
786 /** Main entry point for benchmark code: parse the command line, and run
787 * some benchmarks. */
789 main(int argc, const char **argv)
791 int i;
792 int list=0, n_enabled=0;
793 char *errmsg;
794 or_options_t *options;
796 subsystems_init_upto(SUBSYS_LEVEL_LIBS);
797 flush_log_messages_from_startup();
799 tor_compress_init();
801 if (argc == 4 && !strcmp(argv[1], "diff")) {
802 const int N = 200;
803 char *f1 = read_file_to_str(argv[2], RFTS_BIN, NULL);
804 char *f2 = read_file_to_str(argv[3], RFTS_BIN, NULL);
805 if (! f1 || ! f2) {
806 perror("X");
807 return 1;
809 size_t f1len = strlen(f1);
810 size_t f2len = strlen(f2);
811 for (i = 0; i < N; ++i) {
812 char *diff = consensus_diff_generate(f1, f1len, f2, f2len);
813 tor_free(diff);
815 char *diff = consensus_diff_generate(f1, f1len, f2, f2len);
816 printf("%s", diff);
817 tor_free(f1);
818 tor_free(f2);
819 tor_free(diff);
820 return 0;
823 for (i = 1; i < argc; ++i) {
824 if (!strcmp(argv[i], "--list")) {
825 list = 1;
826 } else {
827 benchmark_t *benchmark = find_benchmark(argv[i]);
828 ++n_enabled;
829 if (benchmark) {
830 benchmark->enabled = 1;
831 } else {
832 printf("No such benchmark as %s\n", argv[i]);
837 reset_perftime();
839 if (crypto_global_init(0, NULL, NULL) < 0) {
840 printf("Couldn't seed RNG; exiting.\n");
841 return 1;
844 init_protocol_warning_severity_level();
845 options = options_new();
846 options->command = CMD_RUN_UNITTESTS;
847 options->DataDirectory = tor_strdup("");
848 options->KeyDirectory = tor_strdup("");
849 options->CacheDirectory = tor_strdup("");
850 options_init(options);
851 if (set_options(options, &errmsg) < 0) {
852 printf("Failed to set initial options: %s\n", errmsg);
853 tor_free(errmsg);
854 return 1;
857 for (benchmark_t *b = benchmarks; b->name; ++b) {
858 if (b->enabled || n_enabled == 0) {
859 printf("===== %s =====\n", b->name);
860 if (!list)
861 b->fn();
865 return 0;