aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/benchmark/benchmark.cpp185
-rw-r--r--src/benchmark/benchmark.h36
-rw-r--r--src/benchmark/info.txt11
3 files changed, 232 insertions, 0 deletions
diff --git a/src/benchmark/benchmark.cpp b/src/benchmark/benchmark.cpp
new file mode 100644
index 000000000..41e41bfcc
--- /dev/null
+++ b/src/benchmark/benchmark.cpp
@@ -0,0 +1,185 @@
+/**
+* Runtime benchmarking
+* (C) 2008 Jack Lloyd
+*/
+
+#include <botan/benchmark.h>
+#include <botan/buf_comp.h>
+#include <botan/block_cipher.h>
+#include <botan/stream_cipher.h>
+#include <botan/hash.h>
+#include <botan/mac.h>
+#include <botan/util.h>
+#include <memory>
+
+namespace Botan {
+
+namespace {
+
+/**
+* Benchmark BufferedComputation (hash or MAC)
+*/
+std::pair<u32bit, u64bit> bench_buf_es(BufferedComputation* buf_comp,
+ Timer& timer,
+ u32bit nanoseconds_max,
+ const byte buf[], u32bit buf_len)
+ {
+ const u64bit start = timer.clock();
+ u64bit nanoseconds_used = 0;
+ u32bit 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<u32bit, u64bit>
+bench_block_cipher(BlockCipher* block_cipher,
+ Timer& timer,
+ u32bit nanoseconds_max,
+ byte buf[], u32bit buf_len)
+ {
+ const u64bit start = timer.clock();
+ u64bit nanoseconds_used = 0;
+ u32bit reps = 0;
+
+ buf_len = round_down(buf_len - 1, block_cipher->BLOCK_SIZE);
+
+ while(nanoseconds_used < nanoseconds_max)
+ {
+ for(u32bit j = 0; j <= buf_len; j += block_cipher->BLOCK_SIZE)
+ block_cipher->encrypt(&buf[j]);
+
+ ++reps;
+ nanoseconds_used = timer.clock() - start;
+ }
+
+ return std::make_pair(reps * buf_len, nanoseconds_used);
+ }
+
+/**
+* Benchmark stream
+*/
+std::pair<u32bit, u64bit>
+bench_stream_cipher(StreamCipher* stream_cipher,
+ Timer& timer,
+ u32bit nanoseconds_max,
+ byte buf[], u32bit buf_len)
+ {
+ const u64bit start = timer.clock();
+ u64bit nanoseconds_used = 0;
+ u32bit 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<u32bit, u64bit>
+bench_hash(HashFunction* hash, Timer& timer,
+ u32bit nanoseconds_max,
+ const byte buf[], u32bit buf_len)
+ {
+ return bench_buf_es(hash, timer, nanoseconds_max, buf, buf_len);
+ }
+
+/**
+* Benchmark MAC
+*/
+std::pair<u32bit, u64bit>
+bench_mac(MessageAuthenticationCode* mac,
+ Timer& timer,
+ u32bit nanoseconds_max,
+ const byte buf[], u32bit buf_len)
+ {
+ mac->set_key(buf, mac->MAXIMUM_KEYLENGTH);
+ return bench_buf_es(mac, timer, nanoseconds_max, buf, buf_len);
+ }
+
+}
+
+std::map<std::string, double>
+algorithm_benchmark(const std::string& name,
+ u32bit milliseconds,
+ Timer& timer,
+ RandomNumberGenerator& rng,
+ Algorithm_Factory& af)
+ {
+ std::vector<std::string> providers = af.providers_of(name);
+ std::map<std::string, double> all_results;
+
+ if(providers.empty()) // no providers, nothing to do
+ return all_results;
+
+ const u32bit ns_per_provider =
+ (milliseconds * 1000 * 1000) / providers.size();
+
+ std::vector<byte> buf(16 * 1024);
+ rng.randomize(&buf[0], buf.size());
+
+ for(u32bit i = 0; i != providers.size(); ++i)
+ {
+ const std::string provider = providers[i];
+
+ SCAN_Name request(name, provider);
+
+ std::pair<u32bit, u64bit> results = std::make_pair(0, 0);
+
+ if(const BlockCipher* proto = af.prototype_block_cipher(request))
+ {
+ std::auto_ptr<BlockCipher> 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(request))
+ {
+ std::auto_ptr<StreamCipher> 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(request))
+ {
+ std::auto_ptr<HashFunction> hash(proto->clone());
+ results = bench_hash(hash.get(), timer, ns_per_provider,
+ &buf[0], buf.size());
+ }
+ else if(const MessageAuthenticationCode* proto =
+ af.prototype_mac(request))
+ {
+ std::auto_ptr<MessageAuthenticationCode> 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;
+ }
+
+}
diff --git a/src/benchmark/benchmark.h b/src/benchmark/benchmark.h
new file mode 100644
index 000000000..176b038d9
--- /dev/null
+++ b/src/benchmark/benchmark.h
@@ -0,0 +1,36 @@
+/**
+* Runtime benchmarking
+* (C) 2008 Jack Lloyd
+*/
+
+#ifndef BOTAN_RUNTIME_BENCHMARK_H__
+#define BOTAN_RUNTIME_BENCHMARK_H__
+
+#include <botan/algo_factory.h>
+#include <botan/timers.h>
+#include <botan/rng.h>
+#include <map>
+#include <string>
+
+namespace Botan {
+
+/**
+Algorithm benchmark
+@param name the name of the algorithm to test (cipher, hash, or MAC)
+@param milliseconds total time for the benchmark to run
+@param timer the timer to use
+@param rng the rng to use to generate random inputs
+@param af the algorithm factory used to create objects
+@returns results a map from provider to speed in mebibytes per second
+*/
+std::map<std::string, double>
+algorithm_benchmark(const std::string& name,
+ u32bit milliseconds,
+ Timer& timer,
+ RandomNumberGenerator& rng,
+ Algorithm_Factory& af);
+
+}
+
+
+#endif
diff --git a/src/benchmark/info.txt b/src/benchmark/info.txt
new file mode 100644
index 000000000..e9718dbb3
--- /dev/null
+++ b/src/benchmark/info.txt
@@ -0,0 +1,11 @@
+realname "Benchmarking"
+
+define RUNTIME_BENCHMARKING
+
+load_on auto
+
+<add>
+benchmark.cpp
+benchmark.h
+</add>
+