Botan
1.11.15
|
00001 /* 00002 * Runtime benchmarking 00003 * (C) 2008-2009,2013 Jack Lloyd 00004 * 00005 * Botan is released under the Simplified BSD License (see license.txt) 00006 */ 00007 00008 #include <botan/benchmark.h> 00009 #include <botan/internal/algo_registry.h> 00010 #include <botan/buf_comp.h> 00011 #include <botan/cipher_mode.h> 00012 #include <botan/block_cipher.h> 00013 #include <botan/stream_cipher.h> 00014 #include <botan/hash.h> 00015 #include <botan/mac.h> 00016 #include <vector> 00017 #include <chrono> 00018 00019 namespace Botan { 00020 00021 namespace { 00022 00023 double time_op(std::chrono::nanoseconds runtime, std::function<void ()> op) 00024 { 00025 std::chrono::nanoseconds time_used(0); 00026 size_t reps = 0; 00027 00028 auto start = std::chrono::high_resolution_clock::now(); 00029 00030 while(time_used < runtime) 00031 { 00032 op(); 00033 ++reps; 00034 time_used = std::chrono::high_resolution_clock::now() - start; 00035 } 00036 00037 const u64bit nsec_used = std::chrono::duration_cast<std::chrono::nanoseconds>(time_used).count(); 00038 00039 const double seconds_used = static_cast<double>(nsec_used) / 1000000000; 00040 00041 return reps / seconds_used; // ie, return ops per second 00042 } 00043 00044 std::map<std::string, double> 00045 time_algorithm_ops(const std::string& name, 00046 const std::string& provider, 00047 RandomNumberGenerator& rng, 00048 std::chrono::nanoseconds runtime, 00049 size_t buf_size) 00050 { 00051 const size_t Mebibyte = 1024*1024; 00052 00053 secure_vector<byte> buffer(buf_size * 1024); 00054 rng.randomize(&buffer[0], buffer.size()); 00055 00056 const double mb_mult = buffer.size() / static_cast<double>(Mebibyte); 00057 00058 if(BlockCipher* p = make_a<BlockCipher>(name, provider)) 00059 { 00060 std::unique_ptr<BlockCipher> bc(p); 00061 00062 const SymmetricKey key(rng, bc->maximum_keylength()); 00063 00064 return std::map<std::string, double>({ 00065 { "key schedule", time_op(runtime / 8, [&]() { bc->set_key(key); }) }, 00066 { "encrypt", mb_mult * time_op(runtime / 2, [&]() { bc->encrypt(buffer); }) }, 00067 { "decrypt", mb_mult * time_op(runtime / 2, [&]() { bc->decrypt(buffer); }) }, 00068 }); 00069 } 00070 else if(StreamCipher* p = make_a<StreamCipher>(name, provider)) 00071 { 00072 std::unique_ptr<StreamCipher> sc(p); 00073 00074 const SymmetricKey key(rng, sc->maximum_keylength()); 00075 00076 return std::map<std::string, double>({ 00077 { "key schedule", time_op(runtime / 8, [&]() { sc->set_key(key); }) }, 00078 { "", mb_mult * time_op(runtime, [&]() { sc->encipher(buffer); }) }, 00079 }); 00080 } 00081 else if(HashFunction* p = make_a<HashFunction>(name, provider)) 00082 { 00083 std::unique_ptr<HashFunction> h(p); 00084 00085 return std::map<std::string, double>({ 00086 { "", mb_mult * time_op(runtime, [&]() { h->update(buffer); }) }, 00087 }); 00088 } 00089 else if(MessageAuthenticationCode* p = make_a<MessageAuthenticationCode>(name, provider)) 00090 { 00091 std::unique_ptr<MessageAuthenticationCode> mac(p); 00092 00093 const SymmetricKey key(rng, mac->maximum_keylength()); 00094 00095 return std::map<std::string, double>({ 00096 { "key schedule", time_op(runtime / 8, [&]() { mac->set_key(key); }) }, 00097 { "", mb_mult * time_op(runtime, [&]() { mac->update(buffer); }) }, 00098 }); 00099 } 00100 else 00101 { 00102 std::unique_ptr<Cipher_Mode> enc(get_cipher_mode(name, ENCRYPTION)); 00103 std::unique_ptr<Cipher_Mode> dec(get_cipher_mode(name, DECRYPTION)); 00104 00105 if(enc && dec) 00106 { 00107 const SymmetricKey key(rng, enc->key_spec().maximum_keylength()); 00108 00109 return std::map<std::string, double>({ 00110 { "key schedule", time_op(runtime / 4, [&]() { enc->set_key(key); dec->set_key(key); }) / 2 }, 00111 { "encrypt", mb_mult * time_op(runtime / 2, [&]() { enc->update(buffer, 0); buffer.resize(buf_size*1024); }) }, 00112 { "decrypt", mb_mult * time_op(runtime / 2, [&]() { dec->update(buffer, 0); buffer.resize(buf_size*1024); }) }, 00113 }); 00114 } 00115 } 00116 00117 return std::map<std::string, double>(); 00118 } 00119 00120 double find_first_in(const std::map<std::string, double>& m, 00121 const std::vector<std::string>& keys) 00122 { 00123 for(auto key : keys) 00124 { 00125 auto i = m.find(key); 00126 if(i != m.end()) 00127 return i->second; 00128 } 00129 00130 throw std::runtime_error("In algo benchmark no usable keys found in result"); 00131 } 00132 00133 std::set<std::string> get_all_providers_of(const std::string& algo) 00134 { 00135 std::set<std::string> provs; 00136 00137 auto add_to_set = [&provs](const std::vector<std::string>& str) { for(auto&& s : str) { provs.insert(s); } }; 00138 00139 add_to_set(Algo_Registry<BlockCipher>::global_registry().providers_of(algo)); 00140 add_to_set(Algo_Registry<StreamCipher>::global_registry().providers_of(algo)); 00141 add_to_set(Algo_Registry<HashFunction>::global_registry().providers_of(algo)); 00142 add_to_set(Algo_Registry<MessageAuthenticationCode>::global_registry().providers_of(algo)); 00143 00144 return provs; 00145 } 00146 00147 } 00148 00149 std::map<std::string, double> 00150 algorithm_benchmark(const std::string& name, 00151 RandomNumberGenerator& rng, 00152 std::chrono::milliseconds milliseconds, 00153 size_t buf_size) 00154 { 00155 //Algorithm_Factory& af = global_state().algorithm_factory(); 00156 const auto providers = get_all_providers_of(name); 00157 00158 std::map<std::string, double> all_results; // provider -> ops/sec 00159 00160 if(!providers.empty()) 00161 { 00162 const std::chrono::nanoseconds ns_per_provider = milliseconds / providers.size(); 00163 00164 for(auto provider : providers) 00165 { 00166 auto results = time_algorithm_ops(name, provider, rng, ns_per_provider, buf_size); 00167 all_results[provider] = find_first_in(results, { "", "update", "encrypt" }); 00168 } 00169 } 00170 00171 return all_results; 00172 } 00173 00174 }