Optimize aligned memory used by the runtime (backport #17324) (#17334)

* Optimize aligned memory used by the runtime (#17324)

(cherry picked from commit 477898f682)

# Conflicts:
#	cli/Cargo.toml
#	programs/bpf/Cargo.toml
#	programs/bpf_loader/Cargo.toml
#	programs/bpf_loader/src/syscalls.rs

* resolve conflicts

Co-authored-by: Jack May <jack@solana.com>
This commit is contained in:
mergify[bot]
2021-05-19 23:21:47 +00:00
committed by GitHub
parent d2e98cb531
commit 0e9fe0847f
9 changed files with 155 additions and 13 deletions

4
Cargo.lock generated
View File

@ -5598,9 +5598,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.6.10" }
solana-faucet = { path = "../faucet", version = "=1.6.10" }
solana-logger = { path = "../logger", version = "=1.6.10" }
solana-net-utils = { path = "../net-utils", version = "=1.6.10" }
solana_rbpf = "=0.2.8"
solana_rbpf = "=0.2.9"
solana-remote-wallet = { path = "../remote-wallet", version = "=1.6.10" }
solana-sdk = { path = "../sdk", version = "=1.6.10" }
solana-stake-program = { path = "../programs/stake", version = "=1.6.10" }

View File

@ -3567,9 +3567,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

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

View File

@ -20,7 +20,7 @@ sha3 = "0.9.1"
solana-measure = { path = "../../measure", version = "=1.6.10" }
solana-runtime = { path = "../../runtime", version = "=1.6.10" }
solana-sdk = { path = "../../sdk", version = "=1.6.10" }
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

@ -147,7 +147,7 @@ pub fn create_vm<'a>(
parameter_accounts: &'a [KeyedAccount<'a>],
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(

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

@ -2701,7 +2701,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(),
@ -2728,7 +2728,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(),
@ -2754,7 +2754,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(),
@ -2781,7 +2781,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(),
@ -2822,6 +2822,7 @@ mod tests {
let bytes1 = "Gaggablaghblagh!";
let bytes2 = "flurbos";
#[allow(dead_code)]
struct MockSlice {
pub addr: u64,
pub len: usize,