diff options
Diffstat (limited to 'src/test/bench.c')
-rw-r--r-- | src/test/bench.c | 327 |
1 files changed, 327 insertions, 0 deletions
diff --git a/src/test/bench.c b/src/test/bench.c new file mode 100644 index 0000000000..ff2794e7c7 --- /dev/null +++ b/src/test/bench.c @@ -0,0 +1,327 @@ +/* Copyright (c) 2001-2004, Roger Dingledine. + * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson. + * Copyright (c) 2007-2011, The Tor Project, Inc. */ +/* See LICENSE for licensing information */ + +/* Ordinarily defined in tor_main.c; this bit is just here to provide one + * since we're not linking to tor_main.c */ +const char tor_git_revision[] = ""; + +/** + * \file bench.c + * \brief Benchmarks for lower level Tor modules. + **/ + +#include "orconfig.h" + +#define RELAY_PRIVATE + +#include "or.h" +#include "relay.h" + +#if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID) +static uint64_t nanostart; +static inline uint64_t +timespec_to_nsec(const struct timespec *ts) +{ + return ((uint64_t)ts->tv_sec)*1000000000 + ts->tv_nsec; +} + +static void +reset_perftime(void) +{ + struct timespec ts; + int r; + r = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); + tor_assert(r == 0); + nanostart = timespec_to_nsec(&ts); +} + +static uint64_t +perftime(void) +{ + struct timespec ts; + int r; + r = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); + tor_assert(r == 0); + return timespec_to_nsec(&ts) - nanostart; +} + +#else +static struct timeval tv_start = { 0, 0 }; +static void +reset_perftime(void) +{ + tor_gettimeofday(&tv_start); +} +static uint64_t +perftime(void) +{ + struct timeval now, out; + tor_gettimeofday(&now); + timersub(&now, &tv_start, &out); + return ((uint64_t)out.tv_sec)*1000000000 + out.tv_usec*1000; +} +#endif + +#define NANOCOUNT(start,end,iters) \ + ( ((double)((end)-(start))) / (iters) ) + +/** Run AES performance benchmarks. */ +static void +bench_aes(void) +{ + int len, i; + char *b1, *b2; + crypto_cipher_env_t *c; + uint64_t start, end; + const int bytes_per_iter = (1<<24); + reset_perftime(); + c = crypto_new_cipher_env(); + crypto_cipher_generate_key(c); + crypto_cipher_encrypt_init_cipher(c); + for (len = 1; len <= 8192; len *= 2) { + int iters = bytes_per_iter / len; + b1 = tor_malloc_zero(len); + b2 = tor_malloc_zero(len); + start = perftime(); + for (i = 0; i < iters; ++i) { + crypto_cipher_encrypt(c, b1, b2, len); + } + end = perftime(); + tor_free(b1); + tor_free(b2); + printf("%d bytes: %.2f nsec per byte\n", len, + NANOCOUNT(start, end, iters*len)); + } + crypto_free_cipher_env(c); +} + +static void +bench_cell_aes(void) +{ + uint64_t start, end; + const int len = 509; + const int iters = (1<<16); + const int max_misalign = 15; + char *b = tor_malloc(len+max_misalign); + crypto_cipher_env_t *c; + int i, misalign; + + c = crypto_new_cipher_env(); + crypto_cipher_generate_key(c); + crypto_cipher_encrypt_init_cipher(c); + + reset_perftime(); + for (misalign = 0; misalign <= max_misalign; ++misalign) { + start = perftime(); + for (i = 0; i < iters; ++i) { + crypto_cipher_crypt_inplace(c, b+misalign, len); + } + end = perftime(); + printf("%d bytes, misaligned by %d: %.2f nsec per byte\n", len, misalign, + NANOCOUNT(start, end, iters*len)); + } + + crypto_free_cipher_env(c); + tor_free(b); +} + +/** Run digestmap_t performance benchmarks. */ +static void +bench_dmap(void) +{ + smartlist_t *sl = smartlist_create(); + smartlist_t *sl2 = smartlist_create(); + uint64_t start, end, pt2, pt3, pt4; + int iters = 8192; + const int elts = 4000; + const int fpostests = 100000; + char d[20]; + int i,n=0, fp = 0; + digestmap_t *dm = digestmap_new(); + digestset_t *ds = digestset_new(elts); + + for (i = 0; i < elts; ++i) { + crypto_rand(d, 20); + smartlist_add(sl, tor_memdup(d, 20)); + } + for (i = 0; i < elts; ++i) { + crypto_rand(d, 20); + smartlist_add(sl2, tor_memdup(d, 20)); + } + printf("nbits=%d\n", ds->mask+1); + + reset_perftime(); + + start = perftime(); + for (i = 0; i < iters; ++i) { + SMARTLIST_FOREACH(sl, const char *, cp, digestmap_set(dm, cp, (void*)1)); + } + pt2 = perftime(); + printf("digestmap_set: %.2f ns per element\n", + NANOCOUNT(start, pt2, iters*elts)); + + for (i = 0; i < iters; ++i) { + SMARTLIST_FOREACH(sl, const char *, cp, digestmap_get(dm, cp)); + SMARTLIST_FOREACH(sl2, const char *, cp, digestmap_get(dm, cp)); + } + pt3 = perftime(); + printf("digestmap_get: %.2f ns per element\n", + NANOCOUNT(pt2, pt3, iters*elts*2)); + + for (i = 0; i < iters; ++i) { + SMARTLIST_FOREACH(sl, const char *, cp, digestset_add(ds, cp)); + } + pt4 = perftime(); + printf("digestset_add: %.2f ns per element\n", + NANOCOUNT(pt3, pt4, iters*elts)); + + for (i = 0; i < iters; ++i) { + SMARTLIST_FOREACH(sl, const char *, cp, n += digestset_isin(ds, cp)); + SMARTLIST_FOREACH(sl2, const char *, cp, n += digestset_isin(ds, cp)); + } + end = perftime(); + printf("digestset_isin: %.2f ns per element.\n", + NANOCOUNT(pt4, end, iters*elts*2)); + /* We need to use this, or else the whole loop gets optimized out. */ + printf("Hits == %d\n", n); + + for (i = 0; i < fpostests; ++i) { + crypto_rand(d, 20); + if (digestset_isin(ds, d)) ++fp; + } + printf("False positive rate on digestset: %.2f%%\n", + (fp/(double)fpostests)*100); + + digestmap_free(dm, NULL); + digestset_free(ds); + SMARTLIST_FOREACH(sl, char *, cp, tor_free(cp)); + SMARTLIST_FOREACH(sl2, char *, cp, tor_free(cp)); + smartlist_free(sl); + smartlist_free(sl2); +} + +static void +bench_cell_ops(void) +{ + const int iters = 1<<16; + int i; + + /* benchmarks for cell ops at relay. */ + or_circuit_t *or_circ = tor_malloc_zero(sizeof(or_circuit_t)); + cell_t *cell = tor_malloc(sizeof(cell_t)); + int outbound; + uint64_t start, end; + + crypto_rand((char*)cell->payload, sizeof(cell->payload)); + + /* Mock-up or_circuit_t */ + or_circ->_base.magic = OR_CIRCUIT_MAGIC; + or_circ->_base.purpose = CIRCUIT_PURPOSE_OR; + + /* Initialize crypto */ + or_circ->p_crypto = crypto_new_cipher_env(); + crypto_cipher_generate_key(or_circ->p_crypto); + crypto_cipher_encrypt_init_cipher(or_circ->p_crypto); + or_circ->n_crypto = crypto_new_cipher_env(); + crypto_cipher_generate_key(or_circ->n_crypto); + crypto_cipher_encrypt_init_cipher(or_circ->n_crypto); + or_circ->p_digest = crypto_new_digest_env(); + or_circ->n_digest = crypto_new_digest_env(); + + reset_perftime(); + + for (outbound = 0; outbound <= 1; ++outbound) { + cell_direction_t d = outbound ? CELL_DIRECTION_OUT : CELL_DIRECTION_IN; + start = perftime(); + for (i = 0; i < iters; ++i) { + char recognized = 0; + crypt_path_t *layer_hint = NULL; + relay_crypt(TO_CIRCUIT(or_circ), cell, d, &layer_hint, &recognized); + } + end = perftime(); + printf("%sbound cells: %.2f ns per cell. (%.2f ns per byte of payload)\n", + outbound?"Out":" In", + NANOCOUNT(start,end,iters), + NANOCOUNT(start,end,iters*CELL_PAYLOAD_SIZE)); + } + + crypto_free_digest_env(or_circ->p_digest); + crypto_free_digest_env(or_circ->n_digest); + crypto_free_cipher_env(or_circ->p_crypto); + crypto_free_cipher_env(or_circ->n_crypto); + tor_free(or_circ); + tor_free(cell); +} + +typedef void (*bench_fn)(void); + +typedef struct benchmark_t { + const char *name; + bench_fn fn; + int enabled; +} benchmark_t; + +#define ENT(s) { #s , bench_##s, 0 } + +static struct benchmark_t benchmarks[] = { + ENT(dmap), + ENT(aes), + ENT(cell_aes), + ENT(cell_ops), + {NULL,NULL,0} +}; + +static benchmark_t * +find_benchmark(const char *name) +{ + benchmark_t *b; + for (b = benchmarks; b->name; ++b) { + if (!strcmp(name, b->name)) { + return b; + } + } + return NULL; +} + +/** Main entry point for benchmark code: parse the command line, and run + * some benchmarks. */ +int +main(int argc, const char **argv) +{ + int i; + int list=0, n_enabled=0; + benchmark_t *b; + + tor_threads_init(); + + for (i = 1; i < argc; ++i) { + if (!strcmp(argv[i], "--list")) { + list = 1; + } else { + benchmark_t *b = find_benchmark(argv[i]); + ++n_enabled; + if (b) { + b->enabled = 1; + } else { + printf("No such benchmark as %s\n", argv[i]); + } + } + } + + reset_perftime(); + + crypto_seed_rng(1); + + for (b = benchmarks; b->name; ++b) { + if (b->enabled || n_enabled == 0) { + printf("===== %s =====\n", b->name); + if (!list) + b->fn(); + } + } + + return 0; +} + |