diff options
Diffstat (limited to 'checks/bench.cpp')
-rw-r--r-- | checks/bench.cpp | 314 |
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); } |