aboutsummaryrefslogtreecommitdiffstats
path: root/checks/bench.cpp
diff options
context:
space:
mode:
authorlloyd <[email protected]>2009-09-24 16:44:26 +0000
committerlloyd <[email protected]>2009-09-24 16:44:26 +0000
commit6cb4b06db7855fa8bec60b2965fe34fb01e5896c (patch)
tree4c99b8d613ce1551f2a27cda05e1d67988563072 /checks/bench.cpp
parente06cb7dcf09e17cb0e76d42e096ca838c17a60bc (diff)
Modify the self test program to use the builtin runtime benchmarking goop.
Features dropped: RNG benchmarking, the --bench-type option. New feature: Anything the library understands can be benchmarked using --bench-algo. Use 3DES and Serpent for mode benchmarking along with AES-128.
Diffstat (limited to 'checks/bench.cpp')
-rw-r--r--checks/bench.cpp314
1 files changed, 191 insertions, 123 deletions
diff --git a/checks/bench.cpp b/checks/bench.cpp
index 1610bed1e..d0fff1114 100644
--- a/checks/bench.cpp
+++ b/checks/bench.cpp
@@ -1,162 +1,230 @@
#include <iostream>
#include <iomanip>
-#include <cmath>
-#include <string>
-#include <exception>
+#include <botan/benchmark.h>
+#include <botan/libstate.h>
+#include <botan/pipe.h>
#include <botan/filters.h>
-using Botan::byte;
-using Botan::u64bit;
+#include <botan/engine.h>
+#include <botan/parsing.h>
+#include <botan/symkey.h>
#include "common.h"
-#include "timer.h"
#include "bench.h"
-/* Discard output to reduce overhead */
-struct BitBucket : public Botan::Filter
+namespace {
+
+const std::string algos[] = {
+
+ /* Block ciphers */
+ "AES-128",
+ "AES-192",
+ "AES-256",
+ "Blowfish",
+ "CAST-128",
+ "CAST-256",
+ "DES",
+ "DESX",
+ "GOST",
+ "IDEA",
+ "KASUMI",
+ "Lion(SHA-256,Turing,8192)",
+ "Luby-Rackoff(SHA-512)",
+ "MARS",
+ "MISTY1",
+ "Noekeon",
+ "RC2",
+ "RC5(12)",
+ "RC5(16)",
+ "RC6",
+ "SAFER-SK(10)",
+ "SEED",
+ "Serpent",
+ "Skipjack",
+ "Square",
+ "TEA",
+ "TripleDES",
+ "Twofish",
+ "XTEA",
+
+ /* Cipher modes */
+ "TripleDES/CBC/PKCS7",
+ "TripleDES/CBC/CTS",
+ "TripleDES/CTR-BE",
+ "TripleDES/EAX",
+ "TripleDES/OFB",
+ "TripleDES/CFB(64)",
+ "TripleDES/CFB(32)",
+ "TripleDES/CFB(16)",
+ "TripleDES/CFB(8)",
+
+ "AES-128/CBC/PKCS7",
+ "AES-128/CBC/CTS",
+ "AES-128/CTR-BE",
+ "AES-128/EAX",
+ "AES-128/OFB",
+ "AES-128/XTS",
+ "AES-128/CFB(128)",
+ "AES-128/CFB(64)",
+ "AES-128/CFB(32)",
+ "AES-128/CFB(16)",
+ "AES-128/CFB(8)",
+
+ "Serpent/CBC/PKCS7",
+ "Serpent/CBC/CTS",
+ "Serpent/CTR-BE",
+ "Serpent/EAX",
+ "Serpent/OFB",
+ "Serpent/XTS",
+ "Serpent/CFB(128)",
+ "Serpent/CFB(64)",
+ "Serpent/CFB(32)",
+ "Serpent/CFB(16)",
+ "Serpent/CFB(8)",
+
+ /* Stream ciphers */
+ "ARC4",
+ "Salsa20",
+ "Turing",
+ "WiderWake4+1-BE",
+
+ /* Checksums */
+ "Adler32",
+ "CRC24",
+ "CRC32",
+
+ /* Hashes */
+ "BMW-512",
+ "FORK-256",
+ "GOST-34.11",
+ "HAS-160",
+ "MD2",
+ "MD4",
+ "MD5",
+ "RIPEMD-128",
+ "RIPEMD-160",
+ "SHA-160",
+ "SHA-256",
+ "SHA-384",
+ "SHA-512",
+ "Skein-512",
+ "Tiger",
+ "Whirlpool",
+
+ /* MACs */
+ "CMAC(AES-128)",
+ "HMAC(SHA-1)",
+ "X9.19-MAC",
+ "",
+};
+
+void report_results(const std::string& algo,
+ const std::map<std::string, double>& speeds)
{
- void write(const byte[], u32bit) {}
- };
+ // invert, showing fastest impl first
+ std::map<double, std::string> results;
-Botan::Filter* lookup(const std::string&,
- const std::vector<std::string>&,
- const std::string& = "All");
+ for(std::map<std::string, double>::const_iterator i = speeds.begin();
+ i != speeds.end(); ++i)
+ {
+ // Speeds might collide, tweak slightly to handle this
+ if(results[i->second] == "")
+ results[i->second] = i->first;
+ else
+ results[i->second - .01] = i->first;
+ }
-namespace {
+ std::cout << algo;
-double bench_filter(std::string name, Botan::Filter* filter,
- Botan::RandomNumberGenerator& rng,
- double seconds)
- {
- Botan::Pipe pipe(filter, new BitBucket);
+ for(std::map<double, std::string>::const_reverse_iterator i = results.rbegin();
+ i != results.rend(); ++i)
+ {
+ std::cout << " [" << i->second << "] "
+ << std::fixed << std::setprecision(2) << i->first;
+ }
+ std::cout << "\n";
+ }
+
+}
- std::vector<byte> buf(128 * 1024);
- rng.randomize(&buf[0], buf.size());
+bool bench_algo(const std::string& algo,
+ Botan::RandomNumberGenerator& rng,
+ double seconds)
+ {
+ Botan::Default_Benchmark_Timer timer;
+ Botan::Algorithm_Factory& af = Botan::global_state().algorithm_factory();
- pipe.start_msg();
+ u32bit milliseconds = static_cast<u32bit>(seconds * 1000);
- Timer timer(name, buf.size());
+ std::map<std::string, double> speeds =
+ algorithm_benchmark(algo, milliseconds, timer, rng, af);
- while(timer.seconds() < seconds)
+ if(speeds.empty()) // maybe a cipher mode, then?
{
- timer.start();
- pipe.write(&buf[0], buf.size());
- timer.stop();
- }
+ Botan::Algorithm_Factory::Engine_Iterator i(af);
- pipe.end_msg();
+ std::vector<std::string> algo_parts = Botan::split_on(algo, '/');
- double bytes_per_sec = timer.events() / timer.seconds();
- double mbytes_per_sec = bytes_per_sec / (1024.0 * 1024.0);
+ if(algo_parts.empty())
+ return false;
- std::cout.setf(std::ios::fixed, std::ios::floatfield);
- std::cout.precision(2);
- std::cout << name << " " << std::string(25 - name.length(), ' ');
- std::cout.width(6);
- std::cout << mbytes_per_sec << " MiB/sec" << std::endl;
- return (mbytes_per_sec);
- }
+ std::string cipher = algo_parts[0];
-double bench(const std::string& name, const std::string& filtername,
- double seconds, u32bit keylen, u32bit ivlen,
- Botan::RandomNumberGenerator& rng)
- {
- std::vector<std::string> params;
+ u32bit cipher_keylen =
+ af.prototype_block_cipher(cipher)->MAXIMUM_KEYLENGTH;
+ u32bit cipher_ivlen =
+ af.prototype_block_cipher(cipher)->BLOCK_SIZE;
- Botan::SecureVector<byte> key(keylen);
- rng.randomize(key, key.size());
- params.push_back(hex_encode(key, key.size()));
+ if(algo_parts[1] == "XTS")
+ cipher_keylen *= 2; // hack!
- //params.push_back(std::string(int(2*keylen), 'A'));
- params.push_back(std::string(int(2* ivlen), 'A'));
+ std::vector<byte> buf(16 * 1024);
+ rng.randomize(&buf[0], buf.size());
- Botan::Filter* filter = lookup(filtername, params);
+ while(Botan::Engine* engine = i.next())
+ {
+ u64bit nanoseconds_max = static_cast<u64bit>(seconds * 1000000000.0);
- if(filter)
- return bench_filter(name, filter, rng, seconds);
- return 0;
- }
+ Botan::Keyed_Filter* filt =
+ engine->get_cipher(algo, Botan::ENCRYPTION, af);
-}
+ if(!filt)
+ continue;
-void benchmark(const std::string& what,
- Botan::RandomNumberGenerator& rng,
- double seconds)
- {
- try {
- double sum = 0;
- u32bit how_many = 0;
+ filt->set_key(Botan::SymmetricKey(&buf[0], cipher_keylen));
+ filt->set_iv(Botan::InitializationVector(&buf[0], cipher_ivlen));
- std::vector<algorithm> algos = get_algos();
+ Botan::Pipe pipe(filt, new Botan::BitBucket);
+ pipe.start_msg();
- for(u32bit j = 0; j != algos.size(); j++)
- if(what == "All" || what == algos[j].type)
+ const u64bit start = timer.clock();
+ u64bit nanoseconds_used = 0;
+ u64bit reps = 0;
+
+ while(nanoseconds_used < nanoseconds_max)
{
- double speed = bench(algos[j].name, algos[j].filtername,
- seconds, algos[j].keylen,
- algos[j].ivlen, rng);
- if(speed > .00001) /* log(0) == -inf -> messed up average */
- sum += std::log(speed);
- how_many++;
+ pipe.write(&buf[0], buf.size());
+ ++reps;
+ nanoseconds_used = timer.clock() - start;
}
- double average = std::exp(sum / static_cast<double>(how_many));
+ double mbytes_per_second =
+ (953.67 * (buf.size() * reps)) / nanoseconds_used;
- if(what == "All")
- std::cout << "\nOverall speed average: " << average
- << std::endl;
- }
- catch(Botan::Exception& e)
- {
- std::cout << "Botan exception caught: " << e.what() << std::endl;
- return;
- }
- catch(std::exception& e)
- {
- std::cout << "Standard library exception caught: " << e.what()
- << std::endl;
- return;
- }
- catch(...)
- {
- std::cout << "Unknown exception caught." << std::endl;
- return;
+ speeds[engine->provider_name()] = mbytes_per_second;
+ }
}
+
+ if(!speeds.empty())
+ report_results(algo, speeds);
+
+ return !speeds.empty();
}
-u32bit bench_algo(const std::string& name,
- Botan::RandomNumberGenerator& rng,
- double seconds)
+void benchmark(Botan::RandomNumberGenerator& rng,
+ double seconds)
{
- try {
- std::vector<algorithm> algos = get_algos();
-
- for(u32bit j = 0; j != algos.size(); j++)
- {
- if(algos[j].name == name)
- {
- bench(algos[j].name, algos[j].filtername, seconds,
- algos[j].keylen, algos[j].ivlen, rng);
- return 1;
- }
- }
- return 0;
- }
- catch(Botan::Exception& e)
- {
- std::cout << "Botan exception caught: " << e.what() << std::endl;
- return 0;
- }
- catch(std::exception& e)
- {
- std::cout << "Standard library exception caught: " << e.what()
- << std::endl;
- return 0;
- }
- catch(...)
- {
- std::cout << "Unknown exception caught." << std::endl;
- return 0;
- }
+ for(u32bit i = 0; algos[i] != ""; ++i)
+ bench_algo(algos[i], rng, seconds);
}