/** * 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, Timer& timer, u64bit nanoseconds_max, const byte buf[], u32bit buf_len) { const u64bit start = timer.clock(); u64bit nanoseconds_used = 0; u64bit reps = 0; while(nanoseconds_used < nanoseconds_max) { buf_comp->update(buf, buf_len); ++reps; nanoseconds_used = timer.clock() - start; } return std::make_pair(reps * buf_len, nanoseconds_used); } /** * Benchmark block cipher */ std::pair bench_block_cipher(BlockCipher* block_cipher, Timer& timer, u64bit nanoseconds_max, byte buf[], u32bit buf_len) { const u64bit start = timer.clock(); u64bit nanoseconds_used = 0; u64bit reps = 0; const u32bit in_blocks = buf_len / block_cipher->BLOCK_SIZE; while(nanoseconds_used < nanoseconds_max) { for(u32bit i = 0; i != in_blocks; ++i) block_cipher->encrypt(buf + block_cipher->BLOCK_SIZE * i); ++reps; nanoseconds_used = timer.clock() - start; } return std::make_pair(reps * in_blocks * block_cipher->BLOCK_SIZE, nanoseconds_used); } /** * Benchmark stream */ std::pair bench_stream_cipher(StreamCipher* stream_cipher, Timer& timer, u64bit nanoseconds_max, byte buf[], u32bit buf_len) { const u64bit start = timer.clock(); u64bit nanoseconds_used = 0; u64bit reps = 0; while(nanoseconds_used < nanoseconds_max) { stream_cipher->encrypt(buf, buf_len); ++reps; nanoseconds_used = timer.clock() - start; } return std::make_pair(reps * buf_len, nanoseconds_used); } /** * Benchmark hash */ std::pair bench_hash(HashFunction* hash, Timer& timer, u64bit nanoseconds_max, const byte buf[], u32bit buf_len) { return bench_buf_comp(hash, timer, nanoseconds_max, buf, buf_len); } /** * Benchmark MAC */ std::pair bench_mac(MessageAuthenticationCode* mac, Timer& timer, u64bit nanoseconds_max, const byte buf[], u32bit buf_len) { mac->set_key(buf, mac->MAXIMUM_KEYLENGTH); return bench_buf_comp(mac, timer, nanoseconds_max, buf, buf_len); } } std::map algorithm_benchmark(const std::string& name, u32bit milliseconds, Timer& timer, RandomNumberGenerator& rng, Algorithm_Factory& af) { 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 = ((u64bit)milliseconds * 1000 * 1000) / providers.size(); std::vector buf(16 * 1024); rng.randomize(&buf[0], buf.size()); for(u32bit 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(), timer, 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(), timer, 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(), timer, 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(), timer, 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; } }