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
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 154 additions and 14 deletions

4
Cargo.lock generated
View File

@ -5508,9 +5508,9 @@ dependencies = [
[[package]]
name = "solana_rbpf"
version = "0.2.8"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcec120278017a67e2dd98494dfdd8e565f53f1d05ab558d1656c369c5dd95e"
checksum = "debbc13545a1d972955a4fd3014e7c9d6d81da16c3626ee5f64bf3aa619548f8"
dependencies = [
"byteorder",
"combine",

View File

@ -38,7 +38,7 @@ solana-config-program = { path = "../programs/config", version = "=1.7.0" }
solana-faucet = { path = "../faucet", version = "=1.7.0" }
solana-logger = { path = "../logger", version = "=1.7.0" }
solana-net-utils = { path = "../net-utils", version = "=1.7.0" }
solana_rbpf = "=0.2.8"
solana_rbpf = "=0.2.9"
solana-remote-wallet = { path = "../remote-wallet", version = "=1.7.0" }
solana-sdk = { path = "../sdk", version = "=1.7.0" }
solana-stake-program = { path = "../programs/stake", version = "=1.7.0" }

View File

@ -3637,9 +3637,9 @@ dependencies = [
[[package]]
name = "solana_rbpf"
version = "0.2.8"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fcec120278017a67e2dd98494dfdd8e565f53f1d05ab558d1656c369c5dd95e"
checksum = "debbc13545a1d972955a4fd3014e7c9d6d81da16c3626ee5f64bf3aa619548f8"
dependencies = [
"byteorder 1.3.4",
"combine",

View File

@ -30,7 +30,7 @@ solana-bpf-loader-program = { path = "../bpf_loader", version = "=1.7.0" }
solana-cli-output = { path = "../../cli-output", version = "=1.7.0" }
solana-logger = { path = "../../logger", version = "=1.7.0" }
solana-measure = { path = "../../measure", version = "=1.7.0" }
solana_rbpf = "=0.2.8"
solana_rbpf = "=0.2.9"
solana-runtime = { path = "../../runtime", version = "=1.7.0" }
solana-sdk = { path = "../../sdk", version = "=1.7.0" }
solana-transaction-status = { path = "../../transaction-status", version = "=1.7.0" }

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,