Optimize aligned memory used by the runtime (#17324)

This commit is contained in:
Jack May
2021-05-19 13:43:59 -07:00
committed by GitHub
parent e7073ecab1
commit 477898f682
9 changed files with 154 additions and 14 deletions

View File

@ -20,7 +20,7 @@ sha3 = "0.9.1"
solana-measure = { path = "../../measure", version = "=1.7.0" }
solana-runtime = { path = "../../runtime", version = "=1.7.0" }
solana-sdk = { path = "../../sdk", version = "=1.7.0" }
solana_rbpf = "=0.2.8"
solana_rbpf = "=0.2.9"
thiserror = "1.0"
[dev-dependencies]

View File

@ -0,0 +1,141 @@
#![feature(test)]
extern crate test;
use solana_bpf_loader_program::serialization::{
serialize_parameters_aligned, serialize_parameters_unaligned,
};
use solana_sdk::{
account::{Account, AccountSharedData},
bpf_loader,
};
use solana_sdk::{keyed_account::KeyedAccount, pubkey::Pubkey};
use std::cell::RefCell;
use test::Bencher;
fn create_inputs() -> (
Pubkey,
Vec<Pubkey>,
Vec<RefCell<AccountSharedData>>,
Vec<u8>,
) {
let program_id = solana_sdk::pubkey::new_rand();
let dup_key = solana_sdk::pubkey::new_rand();
let dup_key2 = solana_sdk::pubkey::new_rand();
let keys = vec![
dup_key,
dup_key,
solana_sdk::pubkey::new_rand(),
solana_sdk::pubkey::new_rand(),
dup_key2,
dup_key2,
solana_sdk::pubkey::new_rand(),
solana_sdk::pubkey::new_rand(),
];
let accounts = vec![
RefCell::new(AccountSharedData::from(Account {
lamports: 1,
data: vec![1u8, 2, 3, 4, 5],
owner: bpf_loader::id(),
executable: false,
rent_epoch: 100,
})),
// dup
RefCell::new(AccountSharedData::from(Account {
lamports: 1,
data: vec![1u8; 100000],
owner: bpf_loader::id(),
executable: false,
rent_epoch: 100,
})),
RefCell::new(AccountSharedData::from(Account {
lamports: 2,
data: vec![11u8; 100000],
owner: bpf_loader::id(),
executable: true,
rent_epoch: 200,
})),
RefCell::new(AccountSharedData::from(Account {
lamports: 3,
data: vec![],
owner: bpf_loader::id(),
executable: false,
rent_epoch: 3100,
})),
RefCell::new(AccountSharedData::from(Account {
lamports: 4,
data: vec![1u8; 100000],
owner: bpf_loader::id(),
executable: false,
rent_epoch: 100,
})),
// dup
RefCell::new(AccountSharedData::from(Account {
lamports: 4,
data: vec![1u8; 1000000],
owner: bpf_loader::id(),
executable: false,
rent_epoch: 100,
})),
RefCell::new(AccountSharedData::from(Account {
lamports: 5,
data: vec![11u8; 10000],
owner: bpf_loader::id(),
executable: true,
rent_epoch: 200,
})),
RefCell::new(AccountSharedData::from(Account {
lamports: 6,
data: vec![],
owner: bpf_loader::id(),
executable: false,
rent_epoch: 3100,
})),
];
let instruction_data = vec![1u8, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
(program_id, keys, accounts, instruction_data)
}
#[bench]
fn bench_serialize_unaligned(bencher: &mut Bencher) {
let (program_id, keys, accounts, instruction_data) = create_inputs();
let keyed_accounts: Vec<_> = keys
.iter()
.zip(&accounts)
.enumerate()
.map(|(i, (key, account))| {
if i <= accounts.len() / 2 {
KeyedAccount::new_readonly(&key, false, &account)
} else {
KeyedAccount::new(&key, false, &account)
}
})
.collect();
bencher.iter(|| {
let _ = serialize_parameters_unaligned(&program_id, &keyed_accounts, &instruction_data)
.unwrap();
});
}
#[bench]
fn bench_serialize_aligned(bencher: &mut Bencher) {
let (program_id, keys, accounts, instruction_data) = create_inputs();
let keyed_accounts: Vec<_> = keys
.iter()
.zip(&accounts)
.enumerate()
.map(|(i, (key, account))| {
if i <= accounts.len() / 2 {
KeyedAccount::new_readonly(&key, false, &account)
} else {
KeyedAccount::new(&key, false, &account)
}
})
.collect();
bencher.iter(|| {
let _ =
serialize_parameters_aligned(&program_id, &keyed_accounts, &instruction_data).unwrap();
});
}

View File

@ -148,7 +148,7 @@ pub fn create_vm<'a>(
parameter_bytes: &mut [u8],
invoke_context: &'a mut dyn InvokeContext,
) -> Result<EbpfVm<'a, BpfError, ThisInstructionMeter>, EbpfError<BpfError>> {
let heap = AlignedMemory::new(DEFAULT_HEAP_SIZE, HOST_ALIGN);
let heap = AlignedMemory::new_with_size(DEFAULT_HEAP_SIZE, HOST_ALIGN);
let heap_region = MemoryRegion::new_from_slice(heap.as_slice(), MM_HEAP_START, 0, true);
let mut vm = EbpfVm::new(program, parameter_bytes, &[heap_region])?;
syscalls::bind_syscall_context_objects(loader_id, &mut vm, invoke_context, heap)?;

View File

@ -231,7 +231,7 @@ pub fn serialize_parameters_aligned(
.map_err(|_| InstructionError::InvalidArgument)?;
v.write_all(&keyed_account.try_account_ref()?.data())
.map_err(|_| InstructionError::InvalidArgument)?;
v.fill(
v.resize(
MAX_PERMITTED_DATA_INCREASE
+ (v.write_index() as *const u8).align_offset(align_of::<u128>()),
0,

View File

@ -2689,7 +2689,7 @@ mod tests {
fn test_syscall_sol_alloc_free() {
// large alloc
{
let heap = AlignedMemory::new(100, HOST_ALIGN);
let heap = AlignedMemory::new_with_size(100, HOST_ALIGN);
let memory_mapping = MemoryMapping::new::<UserError>(
vec![MemoryRegion::new_from_slice(
heap.as_slice(),
@ -2716,7 +2716,7 @@ mod tests {
}
// many small unaligned allocs
{
let heap = AlignedMemory::new(100, HOST_ALIGN);
let heap = AlignedMemory::new_with_size(100, HOST_ALIGN);
let memory_mapping = MemoryMapping::new::<UserError>(
vec![MemoryRegion::new_from_slice(
heap.as_slice(),
@ -2742,7 +2742,7 @@ mod tests {
}
// many small aligned allocs
{
let heap = AlignedMemory::new(100, HOST_ALIGN);
let heap = AlignedMemory::new_with_size(100, HOST_ALIGN);
let memory_mapping = MemoryMapping::new::<UserError>(
vec![MemoryRegion::new_from_slice(
heap.as_slice(),
@ -2769,7 +2769,7 @@ mod tests {
// aligned allocs
fn check_alignment<T>() {
let heap = AlignedMemory::new(100, HOST_ALIGN);
let heap = AlignedMemory::new_with_size(100, HOST_ALIGN);
let memory_mapping = MemoryMapping::new::<UserError>(
vec![MemoryRegion::new_from_slice(
heap.as_slice(),
@ -2810,7 +2810,6 @@ mod tests {
let bytes1 = "Gaggablaghblagh!";
let bytes2 = "flurbos";
// lint warns field addr and len "never read"
#[allow(dead_code)]
struct MockSlice {
pub addr: u64,