Added a benchmark.

This commit is contained in:
Mike Dilger
2023-10-01 09:09:17 +13:00
parent d2c0c9a745
commit b713074e8e
2 changed files with 82 additions and 0 deletions
+7
View File
@@ -1 +1,8 @@
Nostr NIP-44 encryption code
To test and benchmark:
````
cargo test --release -- --nocapture
```
+75
View File
@@ -490,3 +490,78 @@ const PADDING: [(usize, usize); 24] = [
(1020, 1024),
(74123, 81920),
];
#[test]
fn bench_encryption_inner() {
const SEC1HEX: &'static str =
"dc4b57c5fe856584b01aab34dad7454b0f715bdfab091bf0dbbe12f65c778838";
const SEC2HEX: &'static str =
"3072ab28ed7d5c2e4f5efbdcde5fb11455ab7f976225d1779a1751eb6400411a";
let sec1bytes = hex::decode(SEC1HEX).unwrap();
let sec1 = SecretKey::from_slice(&sec1bytes).unwrap();
let sec2bytes = hex::decode(SEC2HEX).unwrap();
let sec2 = SecretKey::from_slice(&sec2bytes).unwrap();
let (pub2, _) = sec2.x_only_public_key(&SECP256K1);
let shared = get_conversation_key(sec1, pub2);
let message = r##"
The compiler could theoretically make optimizations like the following:
needle and haystack are always the same, move the call to contains outside the loop and delete the loop
Inline contains
needle and haystack have values known at compile time, contains is always true. Remove the call and replace with true
Nothing is done with the result of contains: delete this function call entirely
benchmark now has no purpose: delete this function
It is not likely that all of the above happens, but the compiler is definitely able to make some optimizations that could result in a very inaccurate benchmark. This is where black_box comes in:
use std::hint::black_box;
// Same `contains` function
fn contains(haystack: &[&str], needle: &str) -> bool {
haystack.iter().any(|x| x == &needle)
}
pub fn benchmark() {
let haystack = vec!["abc", "def", "ghi", "jkl", "mno"];
let needle = "ghi";
for _ in 0..10 {
// Adjust our benchmark loop contents
black_box(contains(black_box(&haystack), black_box(needle)));
}
}
Run
This essentially tells the compiler to block optimizations across any calls to black_box. So, it now:
Treats both arguments to contains as unpredictable: the body of contains can no longer be optimized based on argument values
Treats the call to contains and its result as volatile: the body of benchmark cannot optimize this away
This makes our benchmark much more realistic to how the function would be used in situ, where arguments are usually not known at compile time and the result is used in some way.
"##;
let start = std::time::Instant::now();
let rounds = 32768;
for _ in 0..rounds {
std::hint::black_box({
let encrypted = encrypt(&shared, message).unwrap();
let _decrypted = decrypt(&shared, &*encrypted).unwrap();
});
}
let elapsed = start.elapsed();
let total_nanos = elapsed.as_nanos();
let nanos_per_encryption_and_decryption = total_nanos / rounds as u128;
let nanos_per_encryption_and_decryption_per_char =
10 * nanos_per_encryption_and_decryption / message.len() as u128;
println!(
"{}.{} nanoseconds per character (encrypt and decrypt)",
nanos_per_encryption_and_decryption_per_char / 10,
nanos_per_encryption_and_decryption_per_char % 10,
);
}