/* * Runtime benchmarking * (C) 2008 Jack Lloyd * * Distributed under the terms of the Botan license */ #include #include #include #include #include #include #include #include namespace Botan { namespace { /** * Benchmark BufferedComputation (hash or MAC) */ std::pair bench_buf_comp(BufferedComputation* buf_comp, u64bit nanoseconds_max, const byte buf[], size_t buf_len) { u64bit reps = 0; u64bit nanoseconds_used = 0; while(nanoseconds_used < nanoseconds_max) { const u64bit start = get_nanoseconds_clock(); buf_comp->update(buf, buf_len); nanoseconds_used += get_nanoseconds_clock() - start; ++reps; } return std::make_pair(reps * buf_len, nanoseconds_used); } /** * Benchmark block cipher */ std::pair bench_block_cipher(BlockCipher* block_cipher, u64bit nanoseconds_max, byte buf[], size_t buf_len) { const size_t in_blocks = buf_len / block_cipher->block_size(); u64bit reps = 0; u64bit nanoseconds_used = 0; block_cipher->set_key(buf, block_cipher->MAXIMUM_KEYLENGTH); while(nanoseconds_used < nanoseconds_max) { const u64bit start = get_nanoseconds_clock(); block_cipher->encrypt_n(buf, buf, in_blocks); nanoseconds_used += get_nanoseconds_clock() - start; ++reps; } return std::make_pair(reps * in_blocks * block_cipher->block_size(), nanoseconds_used); } /** * Benchmark stream */ std::pair bench_stream_cipher(StreamCipher* stream_cipher, u64bit nanoseconds_max, byte buf[], size_t buf_len) { u64bit reps = 0; u64bit nanoseconds_used = 0; stream_cipher->set_key(buf, stream_cipher->MAXIMUM_KEYLENGTH); while(nanoseconds_used < nanoseconds_max) { const u64bit start = get_nanoseconds_clock(); stream_cipher->cipher1(buf, buf_len); nanoseconds_used += get_nanoseconds_clock() - start; ++reps; } return std::make_pair(reps * buf_len, nanoseconds_used); } /** * Benchmark hash */ std::pair bench_hash(HashFunction* hash, u64bit nanoseconds_max, const byte buf[], size_t buf_len) { return bench_buf_comp(hash, nanoseconds_max, buf, buf_len); } /** * Benchmark MAC */ std::pair bench_mac(MessageAuthenticationCode* mac, u64bit nanoseconds_max, const byte buf[], size_t buf_len) { mac->set_key(buf, mac->MAXIMUM_KEYLENGTH); return bench_buf_comp(mac, nanoseconds_max, buf, buf_len); } } std::map algorithm_benchmark(const std::string& name, Algorithm_Factory& af, RandomNumberGenerator& rng, u32bit milliseconds, size_t buf_size) { std::vector providers = af.providers_of(name); std::map all_results; if(providers.empty()) // no providers, nothing to do return all_results; const u64bit ns_per_provider = (static_cast(milliseconds) * 1000 * 1000) / providers.size(); std::vector buf(buf_size * 1024); rng.randomize(&buf[0], buf.size()); for(size_t i = 0; i != providers.size(); ++i) { const std::string provider = providers[i]; std::pair results(0, 0); if(const BlockCipher* proto = af.prototype_block_cipher(name, provider)) { std::auto_ptr block_cipher(proto->clone()); results = bench_block_cipher(block_cipher.get(), ns_per_provider, &buf[0], buf.size()); } else if(const StreamCipher* proto = af.prototype_stream_cipher(name, provider)) { std::auto_ptr stream_cipher(proto->clone()); results = bench_stream_cipher(stream_cipher.get(), ns_per_provider, &buf[0], buf.size()); } else if(const HashFunction* proto = af.prototype_hash_function(name, provider)) { std::auto_ptr hash(proto->clone()); results = bench_hash(hash.get(), ns_per_provider, &buf[0], buf.size()); } else if(const MessageAuthenticationCode* proto = af.prototype_mac(name, provider)) { std::auto_ptr mac(proto->clone()); results = bench_mac(mac.get(), ns_per_provider, &buf[0], buf.size()); } if(results.first && results.second) { /* 953.67 == 1000 * 1000 * 1000 / 1024 / 1024 - the conversion factor from bytes per nanosecond to mebibytes per second. */ double speed = (953.67 * results.first) / results.second; all_results[provider] = speed; } } return all_results; } }