Add an option to configure bssl speed chunk size.
bsaes, in its current incarnation, hits various pathological behaviors
at different input sizes. Make it easy to experiment around them.
Bug: 256
Change-Id: Ib6c6ca7d06a570dbf7d4d2ea81c1db0d94d3d0c4
Reviewed-on: https://boringssl-review.googlesource.com/c/34876
Commit-Queue: David Benjamin <davidben@google.com>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/tool/speed.cc b/tool/speed.cc
index 41dbc50..14379cd 100644
--- a/tool/speed.cc
+++ b/tool/speed.cc
@@ -19,6 +19,7 @@
#include <vector>
#include <assert.h>
+#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@@ -98,6 +99,7 @@
#endif
static uint64_t g_timeout_seconds = 1;
+static std::vector<size_t> g_chunk_lengths = {16, 256, 1350, 8192};
static bool TimeFunction(TimeResults *results, std::function<bool()> func) {
// total_us is the total amount of time that we'll aim to measure a function
@@ -274,10 +276,19 @@
(static_cast<double>(num_calls) / us) * 1000000);
const size_t n = durations.size();
assert(n > 0);
+
+ // |min| and |max| must be stored in temporary variables to avoid an MSVC
+ // bug on x86. There, size_t is a typedef for unsigned, but MSVC's printf
+ // warning tries to retain the distinction and suggest %zu for size_t
+ // instead of %u. It gets confused if std::vector<unsigned> and
+ // std::vector<size_t> are both instantiated. Being typedefs, the two
+ // instantiations are identical, which somehow breaks the size_t vs unsigned
+ // metadata.
+ unsigned min = durations[0];
unsigned median = n & 1 ? durations[n / 2]
: (durations[n / 2 - 1] + durations[n / 2]) / 2;
- printf(" min: %uus, median: %uus, max: %uus\n", durations[0], median,
- durations[n - 1]);
+ unsigned max = durations[n - 1];
+ printf(" min: %uus, median: %uus, max: %uus\n", min, median, max);
}
return true;
@@ -289,11 +300,19 @@
~static_cast<size_t>(alignment - 1));
}
-static bool SpeedAEADChunk(const EVP_AEAD *aead, const std::string &name,
+static std::string ChunkLenSuffix(size_t chunk_len) {
+ char buf[32];
+ snprintf(buf, sizeof(buf), " (%zu byte%s)", chunk_len,
+ chunk_len != 1 ? "s" : "");
+ return buf;
+}
+
+static bool SpeedAEADChunk(const EVP_AEAD *aead, std::string name,
size_t chunk_len, size_t ad_len,
evp_aead_direction_t direction) {
static const unsigned kAlignment = 16;
+ name += ChunkLenSuffix(chunk_len);
bssl::ScopedEVP_AEAD_CTX ctx;
const size_t key_len = EVP_AEAD_key_length(aead);
const size_t nonce_len = EVP_AEAD_nonce_length(aead);
@@ -390,12 +409,12 @@
return true;
}
- return SpeedAEADChunk(aead, name + " (16 bytes)", 16, ad_len,
- evp_aead_seal) &&
- SpeedAEADChunk(aead, name + " (1350 bytes)", 1350, ad_len,
- evp_aead_seal) &&
- SpeedAEADChunk(aead, name + " (8192 bytes)", 8192, ad_len,
- evp_aead_seal);
+ for (size_t chunk_len : g_chunk_lengths) {
+ if (!SpeedAEADChunk(aead, name, chunk_len, ad_len, evp_aead_seal)) {
+ return false;
+ }
+ }
+ return true;
}
static bool SpeedAEADOpen(const EVP_AEAD *aead, const std::string &name,
@@ -404,15 +423,16 @@
return true;
}
- return SpeedAEADChunk(aead, name + " (16 bytes)", 16, ad_len,
- evp_aead_open) &&
- SpeedAEADChunk(aead, name + " (1350 bytes)", 1350, ad_len,
- evp_aead_open) &&
- SpeedAEADChunk(aead, name + " (8192 bytes)", 8192, ad_len,
- evp_aead_open);
+ for (size_t chunk_len : g_chunk_lengths) {
+ if (!SpeedAEADChunk(aead, name, chunk_len, ad_len, evp_aead_open)) {
+ return false;
+ }
+ }
+
+ return true;
}
-static bool SpeedHashChunk(const EVP_MD *md, const std::string &name,
+static bool SpeedHashChunk(const EVP_MD *md, std::string name,
size_t chunk_len) {
bssl::ScopedEVP_MD_CTX ctx;
uint8_t scratch[8192];
@@ -421,6 +441,7 @@
return false;
}
+ name += ChunkLenSuffix(chunk_len);
TimeResults results;
if (!TimeFunction(&results, [&ctx, md, chunk_len, &scratch]() -> bool {
uint8_t digest[EVP_MAX_MD_SIZE];
@@ -438,24 +459,30 @@
results.PrintWithBytes(name, chunk_len);
return true;
}
+
static bool SpeedHash(const EVP_MD *md, const std::string &name,
const std::string &selected) {
if (!selected.empty() && name.find(selected) == std::string::npos) {
return true;
}
- return SpeedHashChunk(md, name + " (16 bytes)", 16) &&
- SpeedHashChunk(md, name + " (256 bytes)", 256) &&
- SpeedHashChunk(md, name + " (8192 bytes)", 8192);
+ for (size_t chunk_len : g_chunk_lengths) {
+ if (!SpeedHashChunk(md, name, chunk_len)) {
+ return false;
+ }
+ }
+
+ return true;
}
-static bool SpeedRandomChunk(const std::string &name, size_t chunk_len) {
+static bool SpeedRandomChunk(std::string name, size_t chunk_len) {
uint8_t scratch[8192];
if (chunk_len > sizeof(scratch)) {
return false;
}
+ name += ChunkLenSuffix(chunk_len);
TimeResults results;
if (!TimeFunction(&results, [chunk_len, &scratch]() -> bool {
RAND_bytes(scratch, chunk_len);
@@ -473,9 +500,13 @@
return true;
}
- return SpeedRandomChunk("RNG (16 bytes)", 16) &&
- SpeedRandomChunk("RNG (256 bytes)", 256) &&
- SpeedRandomChunk("RNG (8192 bytes)", 8192);
+ for (size_t chunk_len : g_chunk_lengths) {
+ if (!SpeedRandomChunk("RNG", chunk_len)) {
+ return false;
+ }
+ }
+
+ return true;
}
static bool SpeedECDHCurve(const std::string &name, int nid,
@@ -802,15 +833,25 @@
static const struct argument kArguments[] = {
{
- "-filter", kOptionalArgument,
- "A filter on the speed tests to run",
+ "-filter",
+ kOptionalArgument,
+ "A filter on the speed tests to run",
},
{
- "-timeout", kOptionalArgument,
- "The number of seconds to run each test for (default is 1)",
+ "-timeout",
+ kOptionalArgument,
+ "The number of seconds to run each test for (default is 1)",
},
{
- "", kOptionalArgument, "",
+ "-chunks",
+ kOptionalArgument,
+ "A comma-separated list of input sizes to run tests at (default is "
+ "16,256,1350,8192)",
+ },
+ {
+ "",
+ kOptionalArgument,
+ "",
},
};
@@ -830,6 +871,32 @@
g_timeout_seconds = atoi(args_map["-timeout"].c_str());
}
+ if (args_map.count("-chunks") != 0) {
+ g_chunk_lengths.clear();
+ const char *start = args_map["-chunks"].data();
+ const char *end = start + args_map["-chunks"].size();
+ while (start != end) {
+ errno = 0;
+ char *ptr;
+ unsigned long long val = strtoull(start, &ptr, 10);
+ if (ptr == start /* no numeric characters found */ ||
+ errno == ERANGE /* overflow */ ||
+ static_cast<size_t>(val) != val) {
+ fprintf(stderr, "Error parsing -chunks argument\n");
+ return false;
+ }
+ g_chunk_lengths.push_back(static_cast<size_t>(val));
+ start = ptr;
+ if (start != end) {
+ if (*start != ',') {
+ fprintf(stderr, "Error parsing -chunks argument\n");
+ return false;
+ }
+ start++;
+ }
+ }
+ }
+
// kTLSADLen is the number of bytes of additional data that TLS passes to
// AEADs.
static const size_t kTLSADLen = 13;