2019-09-18 12:35:52 -07:00
|
|
|
#![feature(test)]
|
|
|
|
|
|
|
|
extern crate test;
|
|
|
|
|
2020-07-02 18:31:32 -07:00
|
|
|
use rand::seq::SliceRandom;
|
|
|
|
use raptorq::{Decoder, Encoder};
|
2019-10-18 09:28:51 -07:00
|
|
|
use solana_ledger::entry::{create_ticks, Entry};
|
|
|
|
use solana_ledger::shred::{
|
2020-07-02 18:31:32 -07:00
|
|
|
max_entries_per_n_shred, max_ticks_per_n_shreds, Shred, Shredder,
|
|
|
|
MAX_DATA_SHREDS_PER_FEC_BLOCK, RECOMMENDED_FEC_RATE, SHRED_PAYLOAD_SIZE,
|
|
|
|
SIZE_OF_DATA_SHRED_IGNORED_TAIL, SIZE_OF_DATA_SHRED_PAYLOAD,
|
2019-10-08 00:42:51 -07:00
|
|
|
};
|
2019-11-06 10:52:30 -08:00
|
|
|
use solana_perf::test_tx;
|
2019-10-08 00:42:51 -07:00
|
|
|
use solana_sdk::hash::Hash;
|
2020-04-02 21:56:38 -07:00
|
|
|
use solana_sdk::signature::Keypair;
|
2019-09-18 12:35:52 -07:00
|
|
|
use std::sync::Arc;
|
|
|
|
use test::Bencher;
|
|
|
|
|
2019-10-10 14:00:24 -07:00
|
|
|
fn make_test_entry(txs_per_entry: u64) -> Entry {
|
|
|
|
Entry {
|
|
|
|
num_hashes: 100_000,
|
|
|
|
hash: Hash::default(),
|
|
|
|
transactions: vec![test_tx::test_tx(); txs_per_entry as usize],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fn make_large_unchained_entries(txs_per_entry: u64, num_entries: u64) -> Vec<Entry> {
|
|
|
|
(0..num_entries)
|
|
|
|
.map(|_| make_test_entry(txs_per_entry))
|
|
|
|
.collect()
|
|
|
|
}
|
|
|
|
|
2020-07-02 18:31:32 -07:00
|
|
|
fn make_shreds(num_shreds: usize) -> Vec<Shred> {
|
|
|
|
let shred_size = SIZE_OF_DATA_SHRED_PAYLOAD;
|
|
|
|
let txs_per_entry = 128;
|
|
|
|
let num_entries = max_entries_per_n_shred(
|
|
|
|
&make_test_entry(txs_per_entry),
|
|
|
|
2 * num_shreds as u64,
|
|
|
|
Some(shred_size),
|
|
|
|
);
|
|
|
|
let entries = make_large_unchained_entries(txs_per_entry, num_entries);
|
|
|
|
let shredder =
|
|
|
|
Shredder::new(1, 0, RECOMMENDED_FEC_RATE, Arc::new(Keypair::new()), 0, 0).unwrap();
|
|
|
|
let data_shreds = shredder.entries_to_data_shreds(&entries, true, 0).0;
|
|
|
|
assert!(data_shreds.len() >= num_shreds);
|
|
|
|
data_shreds
|
|
|
|
}
|
|
|
|
|
|
|
|
fn make_concatenated_shreds(num_shreds: usize) -> Vec<u8> {
|
|
|
|
let data_shreds = make_shreds(num_shreds);
|
|
|
|
let valid_shred_data_len = (SHRED_PAYLOAD_SIZE - SIZE_OF_DATA_SHRED_IGNORED_TAIL) as usize;
|
|
|
|
let mut data: Vec<u8> = vec![0; num_shreds * valid_shred_data_len];
|
|
|
|
for (i, shred) in (data_shreds[0..num_shreds]).iter().enumerate() {
|
|
|
|
data[i * valid_shred_data_len..(i + 1) * valid_shred_data_len]
|
|
|
|
.copy_from_slice(&shred.payload[..valid_shred_data_len]);
|
|
|
|
}
|
|
|
|
|
|
|
|
data
|
|
|
|
}
|
|
|
|
|
2019-09-18 12:35:52 -07:00
|
|
|
#[bench]
|
2019-10-10 14:00:24 -07:00
|
|
|
fn bench_shredder_ticks(bencher: &mut Bencher) {
|
2019-09-18 12:35:52 -07:00
|
|
|
let kp = Arc::new(Keypair::new());
|
2019-10-21 12:46:16 -07:00
|
|
|
let shred_size = SIZE_OF_DATA_SHRED_PAYLOAD;
|
2019-10-08 00:42:51 -07:00
|
|
|
let num_shreds = ((1000 * 1000) + (shred_size - 1)) / shred_size;
|
|
|
|
// ~1Mb
|
2020-05-19 12:38:18 -07:00
|
|
|
let num_ticks = max_ticks_per_n_shreds(1, Some(SIZE_OF_DATA_SHRED_PAYLOAD)) * num_shreds as u64;
|
2019-10-31 13:38:50 -07:00
|
|
|
let entries = create_ticks(num_ticks, 0, Hash::default());
|
2019-09-18 12:35:52 -07:00
|
|
|
bencher.iter(|| {
|
2019-11-18 18:05:02 -08:00
|
|
|
let shredder = Shredder::new(1, 0, RECOMMENDED_FEC_RATE, kp.clone(), 0, 0).unwrap();
|
2019-10-08 00:42:51 -07:00
|
|
|
shredder.entries_to_shreds(&entries, true, 0);
|
2019-09-18 12:35:52 -07:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-10-10 14:00:24 -07:00
|
|
|
#[bench]
|
|
|
|
fn bench_shredder_large_entries(bencher: &mut Bencher) {
|
|
|
|
let kp = Arc::new(Keypair::new());
|
2019-10-21 12:46:16 -07:00
|
|
|
let shred_size = SIZE_OF_DATA_SHRED_PAYLOAD;
|
2019-10-10 14:00:24 -07:00
|
|
|
let num_shreds = ((1000 * 1000) + (shred_size - 1)) / shred_size;
|
|
|
|
let txs_per_entry = 128;
|
2020-05-19 12:38:18 -07:00
|
|
|
let num_entries = max_entries_per_n_shred(
|
|
|
|
&make_test_entry(txs_per_entry),
|
|
|
|
num_shreds as u64,
|
|
|
|
Some(shred_size),
|
|
|
|
);
|
2019-10-10 14:00:24 -07:00
|
|
|
let entries = make_large_unchained_entries(txs_per_entry, num_entries);
|
|
|
|
// 1Mb
|
|
|
|
bencher.iter(|| {
|
2019-11-18 18:05:02 -08:00
|
|
|
let shredder = Shredder::new(1, 0, RECOMMENDED_FEC_RATE, kp.clone(), 0, 0).unwrap();
|
2019-10-10 14:00:24 -07:00
|
|
|
shredder.entries_to_shreds(&entries, true, 0);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-09-18 12:35:52 -07:00
|
|
|
#[bench]
|
|
|
|
fn bench_deshredder(bencher: &mut Bencher) {
|
|
|
|
let kp = Arc::new(Keypair::new());
|
2019-10-21 12:46:16 -07:00
|
|
|
let shred_size = SIZE_OF_DATA_SHRED_PAYLOAD;
|
2019-10-08 00:42:51 -07:00
|
|
|
// ~10Mb
|
|
|
|
let num_shreds = ((10000 * 1000) + (shred_size - 1)) / shred_size;
|
2020-05-19 12:38:18 -07:00
|
|
|
let num_ticks = max_ticks_per_n_shreds(1, Some(shred_size)) * num_shreds as u64;
|
2019-10-31 13:38:50 -07:00
|
|
|
let entries = create_ticks(num_ticks, 0, Hash::default());
|
2019-11-18 18:05:02 -08:00
|
|
|
let shredder = Shredder::new(1, 0, RECOMMENDED_FEC_RATE, kp, 0, 0).unwrap();
|
2019-10-08 00:42:51 -07:00
|
|
|
let data_shreds = shredder.entries_to_shreds(&entries, true, 0).0;
|
2019-09-18 12:35:52 -07:00
|
|
|
bencher.iter(|| {
|
2019-10-08 00:42:51 -07:00
|
|
|
let raw = &mut Shredder::deshred(&data_shreds).unwrap();
|
2019-09-18 12:35:52 -07:00
|
|
|
assert_ne!(raw.len(), 0);
|
|
|
|
})
|
|
|
|
}
|
2019-10-15 15:18:23 -07:00
|
|
|
|
|
|
|
#[bench]
|
|
|
|
fn bench_deserialize_hdr(bencher: &mut Bencher) {
|
2019-10-21 12:46:16 -07:00
|
|
|
let data = vec![0; SIZE_OF_DATA_SHRED_PAYLOAD];
|
2019-10-15 15:18:23 -07:00
|
|
|
|
2019-12-12 16:50:29 -08:00
|
|
|
let shred = Shred::new_from_data(2, 1, 1, Some(&data), true, true, 0, 0, 1);
|
2019-10-15 15:18:23 -07:00
|
|
|
|
|
|
|
bencher.iter(|| {
|
|
|
|
let payload = shred.payload.clone();
|
|
|
|
let _ = Shred::new_from_serialized_shred(payload).unwrap();
|
|
|
|
})
|
|
|
|
}
|
2020-07-02 18:31:32 -07:00
|
|
|
|
|
|
|
#[bench]
|
|
|
|
fn bench_shredder_coding(bencher: &mut Bencher) {
|
|
|
|
let symbol_count = MAX_DATA_SHREDS_PER_FEC_BLOCK as usize;
|
|
|
|
let data_shreds = make_shreds(symbol_count);
|
|
|
|
bencher.iter(|| {
|
|
|
|
Shredder::generate_coding_shreds(0, RECOMMENDED_FEC_RATE, &data_shreds[..symbol_count], 0)
|
|
|
|
.len();
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[bench]
|
|
|
|
fn bench_shredder_decoding(bencher: &mut Bencher) {
|
|
|
|
let symbol_count = MAX_DATA_SHREDS_PER_FEC_BLOCK as usize;
|
|
|
|
let data_shreds = make_shreds(symbol_count);
|
|
|
|
let coding_shreds =
|
|
|
|
Shredder::generate_coding_shreds(0, RECOMMENDED_FEC_RATE, &data_shreds[..symbol_count], 0);
|
|
|
|
bencher.iter(|| {
|
|
|
|
Shredder::try_recovery(
|
|
|
|
coding_shreds[..].to_vec(),
|
|
|
|
symbol_count,
|
|
|
|
symbol_count,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
1,
|
|
|
|
)
|
|
|
|
.unwrap();
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[bench]
|
|
|
|
fn bench_shredder_coding_raptorq(bencher: &mut Bencher) {
|
|
|
|
let symbol_count = MAX_DATA_SHREDS_PER_FEC_BLOCK;
|
|
|
|
let data = make_concatenated_shreds(symbol_count as usize);
|
|
|
|
let valid_shred_data_len = (SHRED_PAYLOAD_SIZE - SIZE_OF_DATA_SHRED_IGNORED_TAIL) as usize;
|
|
|
|
bencher.iter(|| {
|
|
|
|
let encoder = Encoder::with_defaults(&data, valid_shred_data_len as u16);
|
|
|
|
encoder.get_encoded_packets(symbol_count);
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[bench]
|
|
|
|
fn bench_shredder_decoding_raptorq(bencher: &mut Bencher) {
|
|
|
|
let symbol_count = MAX_DATA_SHREDS_PER_FEC_BLOCK;
|
|
|
|
let data = make_concatenated_shreds(symbol_count as usize);
|
|
|
|
let valid_shred_data_len = (SHRED_PAYLOAD_SIZE - SIZE_OF_DATA_SHRED_IGNORED_TAIL) as usize;
|
|
|
|
let encoder = Encoder::with_defaults(&data, valid_shred_data_len as u16);
|
|
|
|
let mut packets = encoder.get_encoded_packets(symbol_count as u32);
|
|
|
|
packets.shuffle(&mut rand::thread_rng());
|
|
|
|
|
|
|
|
// Here we simulate losing 1 less than 50% of the packets randomly
|
|
|
|
packets.truncate(packets.len() - packets.len() / 2 + 1);
|
|
|
|
|
|
|
|
bencher.iter(|| {
|
|
|
|
let mut decoder = Decoder::new(encoder.get_config());
|
|
|
|
let mut result = None;
|
|
|
|
for packet in &packets {
|
|
|
|
result = decoder.decode(packet.clone());
|
|
|
|
if result != None {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert_eq!(result.unwrap(), data);
|
|
|
|
})
|
|
|
|
}
|