Optimize aligned memory used by the runtime (#17324)
This commit is contained in:
parent
e7073ecab1
commit
477898f682
|
@ -5508,9 +5508,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana_rbpf"
|
name = "solana_rbpf"
|
||||||
version = "0.2.8"
|
version = "0.2.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7fcec120278017a67e2dd98494dfdd8e565f53f1d05ab558d1656c369c5dd95e"
|
checksum = "debbc13545a1d972955a4fd3014e7c9d6d81da16c3626ee5f64bf3aa619548f8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"combine",
|
"combine",
|
||||||
|
|
|
@ -38,7 +38,7 @@ solana-config-program = { path = "../programs/config", version = "=1.7.0" }
|
||||||
solana-faucet = { path = "../faucet", version = "=1.7.0" }
|
solana-faucet = { path = "../faucet", version = "=1.7.0" }
|
||||||
solana-logger = { path = "../logger", version = "=1.7.0" }
|
solana-logger = { path = "../logger", version = "=1.7.0" }
|
||||||
solana-net-utils = { path = "../net-utils", 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-remote-wallet = { path = "../remote-wallet", version = "=1.7.0" }
|
||||||
solana-sdk = { path = "../sdk", version = "=1.7.0" }
|
solana-sdk = { path = "../sdk", version = "=1.7.0" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "=1.7.0" }
|
solana-stake-program = { path = "../programs/stake", version = "=1.7.0" }
|
||||||
|
|
|
@ -3637,9 +3637,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana_rbpf"
|
name = "solana_rbpf"
|
||||||
version = "0.2.8"
|
version = "0.2.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7fcec120278017a67e2dd98494dfdd8e565f53f1d05ab558d1656c369c5dd95e"
|
checksum = "debbc13545a1d972955a4fd3014e7c9d6d81da16c3626ee5f64bf3aa619548f8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 1.3.4",
|
"byteorder 1.3.4",
|
||||||
"combine",
|
"combine",
|
||||||
|
|
|
@ -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-cli-output = { path = "../../cli-output", version = "=1.7.0" }
|
||||||
solana-logger = { path = "../../logger", version = "=1.7.0" }
|
solana-logger = { path = "../../logger", version = "=1.7.0" }
|
||||||
solana-measure = { path = "../../measure", 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-runtime = { path = "../../runtime", version = "=1.7.0" }
|
||||||
solana-sdk = { path = "../../sdk", version = "=1.7.0" }
|
solana-sdk = { path = "../../sdk", version = "=1.7.0" }
|
||||||
solana-transaction-status = { path = "../../transaction-status", version = "=1.7.0" }
|
solana-transaction-status = { path = "../../transaction-status", version = "=1.7.0" }
|
||||||
|
|
|
@ -20,7 +20,7 @@ sha3 = "0.9.1"
|
||||||
solana-measure = { path = "../../measure", version = "=1.7.0" }
|
solana-measure = { path = "../../measure", version = "=1.7.0" }
|
||||||
solana-runtime = { path = "../../runtime", version = "=1.7.0" }
|
solana-runtime = { path = "../../runtime", version = "=1.7.0" }
|
||||||
solana-sdk = { path = "../../sdk", 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"
|
thiserror = "1.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -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();
|
||||||
|
});
|
||||||
|
}
|
|
@ -148,7 +148,7 @@ pub fn create_vm<'a>(
|
||||||
parameter_bytes: &mut [u8],
|
parameter_bytes: &mut [u8],
|
||||||
invoke_context: &'a mut dyn InvokeContext,
|
invoke_context: &'a mut dyn InvokeContext,
|
||||||
) -> Result<EbpfVm<'a, BpfError, ThisInstructionMeter>, EbpfError<BpfError>> {
|
) -> 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 heap_region = MemoryRegion::new_from_slice(heap.as_slice(), MM_HEAP_START, 0, true);
|
||||||
let mut vm = EbpfVm::new(program, parameter_bytes, &[heap_region])?;
|
let mut vm = EbpfVm::new(program, parameter_bytes, &[heap_region])?;
|
||||||
syscalls::bind_syscall_context_objects(loader_id, &mut vm, invoke_context, heap)?;
|
syscalls::bind_syscall_context_objects(loader_id, &mut vm, invoke_context, heap)?;
|
||||||
|
|
|
@ -231,7 +231,7 @@ pub fn serialize_parameters_aligned(
|
||||||
.map_err(|_| InstructionError::InvalidArgument)?;
|
.map_err(|_| InstructionError::InvalidArgument)?;
|
||||||
v.write_all(&keyed_account.try_account_ref()?.data())
|
v.write_all(&keyed_account.try_account_ref()?.data())
|
||||||
.map_err(|_| InstructionError::InvalidArgument)?;
|
.map_err(|_| InstructionError::InvalidArgument)?;
|
||||||
v.fill(
|
v.resize(
|
||||||
MAX_PERMITTED_DATA_INCREASE
|
MAX_PERMITTED_DATA_INCREASE
|
||||||
+ (v.write_index() as *const u8).align_offset(align_of::<u128>()),
|
+ (v.write_index() as *const u8).align_offset(align_of::<u128>()),
|
||||||
0,
|
0,
|
||||||
|
|
|
@ -2689,7 +2689,7 @@ mod tests {
|
||||||
fn test_syscall_sol_alloc_free() {
|
fn test_syscall_sol_alloc_free() {
|
||||||
// large alloc
|
// large alloc
|
||||||
{
|
{
|
||||||
let heap = AlignedMemory::new(100, HOST_ALIGN);
|
let heap = AlignedMemory::new_with_size(100, HOST_ALIGN);
|
||||||
let memory_mapping = MemoryMapping::new::<UserError>(
|
let memory_mapping = MemoryMapping::new::<UserError>(
|
||||||
vec![MemoryRegion::new_from_slice(
|
vec![MemoryRegion::new_from_slice(
|
||||||
heap.as_slice(),
|
heap.as_slice(),
|
||||||
|
@ -2716,7 +2716,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
// many small unaligned allocs
|
// 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>(
|
let memory_mapping = MemoryMapping::new::<UserError>(
|
||||||
vec![MemoryRegion::new_from_slice(
|
vec![MemoryRegion::new_from_slice(
|
||||||
heap.as_slice(),
|
heap.as_slice(),
|
||||||
|
@ -2742,7 +2742,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
// many small aligned allocs
|
// 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>(
|
let memory_mapping = MemoryMapping::new::<UserError>(
|
||||||
vec![MemoryRegion::new_from_slice(
|
vec![MemoryRegion::new_from_slice(
|
||||||
heap.as_slice(),
|
heap.as_slice(),
|
||||||
|
@ -2769,7 +2769,7 @@ mod tests {
|
||||||
// aligned allocs
|
// aligned allocs
|
||||||
|
|
||||||
fn check_alignment<T>() {
|
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>(
|
let memory_mapping = MemoryMapping::new::<UserError>(
|
||||||
vec![MemoryRegion::new_from_slice(
|
vec![MemoryRegion::new_from_slice(
|
||||||
heap.as_slice(),
|
heap.as_slice(),
|
||||||
|
@ -2810,7 +2810,6 @@ mod tests {
|
||||||
let bytes1 = "Gaggablaghblagh!";
|
let bytes1 = "Gaggablaghblagh!";
|
||||||
let bytes2 = "flurbos";
|
let bytes2 = "flurbos";
|
||||||
|
|
||||||
// lint warns field addr and len "never read"
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
struct MockSlice {
|
struct MockSlice {
|
||||||
pub addr: u64,
|
pub addr: u64,
|
||||||
|
|
Loading…
Reference in New Issue