Botan  1.10.9
benchmark.cpp
Go to the documentation of this file.
1 /*
2 * Runtime benchmarking
3 * (C) 2008 Jack Lloyd
4 *
5 * Distributed under the terms of the Botan license
6 */
7 
8 #include <botan/benchmark.h>
9 #include <botan/buf_comp.h>
10 #include <botan/block_cipher.h>
11 #include <botan/stream_cipher.h>
12 #include <botan/hash.h>
13 #include <botan/mac.h>
14 #include <botan/time.h>
15 #include <memory>
16 
17 namespace Botan {
18 
19 namespace {
20 
21 /**
22 * Benchmark Buffered_Computation (hash or MAC)
23 */
24 std::pair<u64bit, u64bit> bench_buf_comp(Buffered_Computation* buf_comp,
25  u64bit nanoseconds_max,
26  const byte buf[], size_t buf_len)
27  {
28  u64bit reps = 0;
29  u64bit nanoseconds_used = 0;
30 
31  while(nanoseconds_used < nanoseconds_max)
32  {
33  const u64bit start = get_nanoseconds_clock();
34  buf_comp->update(buf, buf_len);
35  nanoseconds_used += get_nanoseconds_clock() - start;
36 
37  ++reps;
38  }
39 
40  return std::make_pair(reps * buf_len, nanoseconds_used);
41  }
42 
43 /**
44 * Benchmark block cipher
45 */
46 std::pair<u64bit, u64bit>
47 bench_block_cipher(BlockCipher* block_cipher,
48  u64bit nanoseconds_max,
49  byte buf[], size_t buf_len)
50  {
51  const size_t in_blocks = buf_len / block_cipher->block_size();
52 
53  u64bit reps = 0;
54  u64bit nanoseconds_used = 0;
55 
56  block_cipher->set_key(buf, block_cipher->maximum_keylength());
57 
58  while(nanoseconds_used < nanoseconds_max)
59  {
60  const u64bit start = get_nanoseconds_clock();
61  block_cipher->encrypt_n(buf, buf, in_blocks);
62  nanoseconds_used += get_nanoseconds_clock() - start;
63 
64  ++reps;
65  }
66 
67  return std::make_pair(reps * in_blocks * block_cipher->block_size(),
68  nanoseconds_used);
69  }
70 
71 /**
72 * Benchmark stream
73 */
74 std::pair<u64bit, u64bit>
75 bench_stream_cipher(StreamCipher* stream_cipher,
76  u64bit nanoseconds_max,
77  byte buf[], size_t buf_len)
78  {
79  u64bit reps = 0;
80  u64bit nanoseconds_used = 0;
81 
82  stream_cipher->set_key(buf, stream_cipher->maximum_keylength());
83 
84  while(nanoseconds_used < nanoseconds_max)
85  {
86  const u64bit start = get_nanoseconds_clock();
87  stream_cipher->cipher1(buf, buf_len);
88  nanoseconds_used += get_nanoseconds_clock() - start;
89 
90  ++reps;
91  }
92 
93  return std::make_pair(reps * buf_len, nanoseconds_used);
94  }
95 
96 /**
97 * Benchmark hash
98 */
99 std::pair<u64bit, u64bit>
100 bench_hash(HashFunction* hash,
101  u64bit nanoseconds_max,
102  const byte buf[], size_t buf_len)
103  {
104  return bench_buf_comp(hash, nanoseconds_max, buf, buf_len);
105  }
106 
107 /**
108 * Benchmark MAC
109 */
110 std::pair<u64bit, u64bit>
111 bench_mac(MessageAuthenticationCode* mac,
112  u64bit nanoseconds_max,
113  const byte buf[], size_t buf_len)
114  {
115  mac->set_key(buf, mac->maximum_keylength());
116  return bench_buf_comp(mac, nanoseconds_max, buf, buf_len);
117  }
118 
119 }
120 
121 std::map<std::string, double>
122 algorithm_benchmark(const std::string& name,
123  Algorithm_Factory& af,
125  u32bit milliseconds,
126  size_t buf_size)
127  {
128  std::vector<std::string> providers = af.providers_of(name);
129  std::map<std::string, double> all_results;
130 
131  if(providers.empty()) // no providers, nothing to do
132  return all_results;
133 
134  const u64bit ns_per_provider =
135  (static_cast<u64bit>(milliseconds) * 1000 * 1000) / providers.size();
136 
137  std::vector<byte> buf(buf_size * 1024);
138  rng.randomize(&buf[0], buf.size());
139 
140  for(size_t i = 0; i != providers.size(); ++i)
141  {
142  const std::string provider = providers[i];
143 
144  std::pair<u64bit, u64bit> results(0, 0);
145 
146  if(const BlockCipher* proto =
147  af.prototype_block_cipher(name, provider))
148  {
149  std::auto_ptr<BlockCipher> block_cipher(proto->clone());
150  results = bench_block_cipher(block_cipher.get(),
151  ns_per_provider,
152  &buf[0], buf.size());
153  }
154  else if(const StreamCipher* proto =
155  af.prototype_stream_cipher(name, provider))
156  {
157  std::auto_ptr<StreamCipher> stream_cipher(proto->clone());
158  results = bench_stream_cipher(stream_cipher.get(),
159  ns_per_provider,
160  &buf[0], buf.size());
161  }
162  else if(const HashFunction* proto =
163  af.prototype_hash_function(name, provider))
164  {
165  std::auto_ptr<HashFunction> hash(proto->clone());
166  results = bench_hash(hash.get(), ns_per_provider,
167  &buf[0], buf.size());
168  }
169  else if(const MessageAuthenticationCode* proto =
170  af.prototype_mac(name, provider))
171  {
172  std::auto_ptr<MessageAuthenticationCode> mac(proto->clone());
173  results = bench_mac(mac.get(), ns_per_provider,
174  &buf[0], buf.size());
175  }
176 
177  if(results.first && results.second)
178  {
179  /* 953.67 == 1000 * 1000 * 1000 / 1024 / 1024 - the conversion
180  factor from bytes per nanosecond to mebibytes per second.
181  */
182  double speed = (953.67 * results.first) / results.second;
183  all_results[provider] = speed;
184  }
185  }
186 
187  return all_results;
188  }
189 
190 }
virtual void randomize(byte output[], size_t length)=0
u64bit get_nanoseconds_clock()
Definition: time.cpp:93
const BlockCipher * prototype_block_cipher(const std::string &algo_spec, const std::string &provider="")
unsigned char byte
Definition: types.h:22
const HashFunction * prototype_hash_function(const std::string &algo_spec, const std::string &provider="")
unsigned long long u64bit
Definition: types.h:49
RandomNumberGenerator * rng
Definition: global_rng.cpp:165
MessageAuthenticationCode * mac
Definition: fpe_fe1.cpp:94
const MessageAuthenticationCode * prototype_mac(const std::string &algo_spec, const std::string &provider="")
std::vector< std::string > providers_of(const std::string &algo_spec)
std::map< std::string, double > algorithm_benchmark(const std::string &name, Algorithm_Factory &af, RandomNumberGenerator &rng, u32bit milliseconds, size_t buf_size)
Definition: benchmark.cpp:122
unsigned int u32bit
Definition: types.h:32
const StreamCipher * prototype_stream_cipher(const std::string &algo_spec, const std::string &provider="")