Replaces MockInvokeContext by ThisInvokeContext in tests (#20881)

* Replaces MockInvokeContext by ThisInvokeContext in BpfLoader, SystemInstructionProcessor, CLIs, ConfigProcessor, StakeProcessor and VoteProcessor.

* Finally, removes MockInvokeContext, MockComputeMeter and MockLogger.

* Adjusts assert_instruction_count test.

* Moves ThisInvokeContext to the program-runtime crate.
This commit is contained in:
Alexander Meißner
2021-11-04 21:47:32 +01:00
committed by GitHub
parent 0597594943
commit 7200c5106e
33 changed files with 2640 additions and 2783 deletions

View File

@@ -18,18 +18,18 @@ use solana_runtime::{
genesis_utils::{create_genesis_config, GenesisConfigInfo},
loader_utils::load_program,
};
use solana_program_runtime::invoke_context::with_mock_invoke_context;
use solana_sdk::{
account::AccountSharedData,
bpf_loader,
client::SyncClient,
entrypoint::SUCCESS,
instruction::{AccountMeta, Instruction},
message::Message,
process_instruction::{InvokeContext, MockComputeMeter, MockInvokeContext},
process_instruction::InvokeContext,
pubkey::Pubkey,
signature::{Keypair, Signer},
};
use std::{cell::RefCell, env, fs::File, io::Read, mem, path::PathBuf, rc::Rc, sync::Arc};
use std::{env, fs::File, io::Read, mem, path::PathBuf, sync::Arc};
use test::Bencher;
/// BPF program file extension
@@ -94,93 +94,73 @@ fn bench_program_alu(bencher: &mut Bencher) {
.write_u64::<LittleEndian>(ARMSTRONG_LIMIT)
.unwrap();
inner_iter.write_u64::<LittleEndian>(0).unwrap();
let loader_id = bpf_loader::id();
let program_id = solana_sdk::pubkey::new_rand();
let accounts = [
(
program_id,
RefCell::new(AccountSharedData::new(0, 0, &loader_id)),
),
(
solana_sdk::pubkey::new_rand(),
RefCell::new(AccountSharedData::new(
1,
10000001,
&solana_sdk::pubkey::new_rand(),
)),
),
];
let keyed_accounts: Vec<_> = accounts
.iter()
.map(|(key, account)| solana_sdk::keyed_account::KeyedAccount::new(&key, false, &account))
.collect();
let mut invoke_context = MockInvokeContext::new(&program_id, keyed_accounts);
let elf = load_elf("bench_alu").unwrap();
let mut executable = <dyn Executable<BpfError, ThisInstructionMeter>>::from_elf(
&elf,
None,
Config::default(),
register_syscalls(&mut invoke_context).unwrap(),
)
.unwrap();
executable.jit_compile().unwrap();
let compute_meter = invoke_context.get_compute_meter();
let mut instruction_meter = ThisInstructionMeter { compute_meter };
let mut vm = create_vm(
&loader_id,
executable.as_ref(),
&mut inner_iter,
&mut invoke_context,
&[],
)
.unwrap();
let loader_id = bpf_loader::id();
with_mock_invoke_context(loader_id, 10000001, |invoke_context| {
let mut executable = <dyn Executable<BpfError, ThisInstructionMeter>>::from_elf(
&elf,
None,
Config::default(),
register_syscalls(invoke_context).unwrap(),
)
.unwrap();
executable.jit_compile().unwrap();
let compute_meter = invoke_context.get_compute_meter();
let mut instruction_meter = ThisInstructionMeter { compute_meter };
let mut vm = create_vm(
&loader_id,
executable.as_ref(),
&mut inner_iter,
invoke_context,
&[],
)
.unwrap();
println!("Interpreted:");
assert_eq!(
SUCCESS,
vm.execute_program_interpreted(&mut instruction_meter)
.unwrap()
);
assert_eq!(ARMSTRONG_LIMIT, LittleEndian::read_u64(&inner_iter));
assert_eq!(
ARMSTRONG_EXPECTED,
LittleEndian::read_u64(&inner_iter[mem::size_of::<u64>()..])
);
println!("Interpreted:");
assert_eq!(
SUCCESS,
vm.execute_program_interpreted(&mut instruction_meter)
.unwrap()
);
assert_eq!(ARMSTRONG_LIMIT, LittleEndian::read_u64(&inner_iter));
assert_eq!(
ARMSTRONG_EXPECTED,
LittleEndian::read_u64(&inner_iter[mem::size_of::<u64>()..])
);
bencher.iter(|| {
vm.execute_program_interpreted(&mut instruction_meter)
.unwrap();
bencher.iter(|| {
vm.execute_program_interpreted(&mut instruction_meter)
.unwrap();
});
let instructions = vm.get_total_instruction_count();
let summary = bencher.bench(|_bencher| {}).unwrap();
println!(" {:?} instructions", instructions);
println!(" {:?} ns/iter median", summary.median as u64);
assert!(0f64 != summary.median);
let mips = (instructions * (ns_per_s / summary.median as u64)) / one_million;
println!(" {:?} MIPS", mips);
println!("{{ \"type\": \"bench\", \"name\": \"bench_program_alu_interpreted_mips\", \"median\": {:?}, \"deviation\": 0 }}", mips);
println!("JIT to native:");
assert_eq!(
SUCCESS,
vm.execute_program_jit(&mut instruction_meter).unwrap()
);
assert_eq!(ARMSTRONG_LIMIT, LittleEndian::read_u64(&inner_iter));
assert_eq!(
ARMSTRONG_EXPECTED,
LittleEndian::read_u64(&inner_iter[mem::size_of::<u64>()..])
);
bencher.iter(|| vm.execute_program_jit(&mut instruction_meter).unwrap());
let summary = bencher.bench(|_bencher| {}).unwrap();
println!(" {:?} instructions", instructions);
println!(" {:?} ns/iter median", summary.median as u64);
assert!(0f64 != summary.median);
let mips = (instructions * (ns_per_s / summary.median as u64)) / one_million;
println!(" {:?} MIPS", mips);
println!("{{ \"type\": \"bench\", \"name\": \"bench_program_alu_jit_to_native_mips\", \"median\": {:?}, \"deviation\": 0 }}", mips);
});
let instructions = vm.get_total_instruction_count();
let summary = bencher.bench(|_bencher| {}).unwrap();
println!(" {:?} instructions", instructions);
println!(" {:?} ns/iter median", summary.median as u64);
assert!(0f64 != summary.median);
let mips = (instructions * (ns_per_s / summary.median as u64)) / one_million;
println!(" {:?} MIPS", mips);
println!("{{ \"type\": \"bench\", \"name\": \"bench_program_alu_interpreted_mips\", \"median\": {:?}, \"deviation\": 0 }}", mips);
println!("JIT to native:");
assert_eq!(
SUCCESS,
vm.execute_program_jit(&mut instruction_meter).unwrap()
);
assert_eq!(ARMSTRONG_LIMIT, LittleEndian::read_u64(&inner_iter));
assert_eq!(
ARMSTRONG_EXPECTED,
LittleEndian::read_u64(&inner_iter[mem::size_of::<u64>()..])
);
bencher.iter(|| vm.execute_program_jit(&mut instruction_meter).unwrap());
let summary = bencher.bench(|_bencher| {}).unwrap();
println!(" {:?} instructions", instructions);
println!(" {:?} ns/iter median", summary.median as u64);
assert!(0f64 != summary.median);
let mips = (instructions * (ns_per_s / summary.median as u64)) / one_million;
println!(" {:?} MIPS", mips);
println!("{{ \"type\": \"bench\", \"name\": \"bench_program_alu_jit_to_native_mips\", \"median\": {:?}, \"deviation\": 0 }}", mips);
}
#[bench]
@@ -220,125 +200,102 @@ fn bench_program_execute_noop(bencher: &mut Bencher) {
#[bench]
fn bench_create_vm(bencher: &mut Bencher) {
const BUDGET: u64 = 200_000;
let loader_id = bpf_loader::id();
let accounts = [RefCell::new(AccountSharedData::new(
1,
10000001,
&solana_sdk::pubkey::new_rand(),
))];
let keys = [solana_sdk::pubkey::new_rand()];
let keyed_accounts: Vec<_> = keys
.iter()
.zip(&accounts)
.map(|(key, account)| solana_sdk::keyed_account::KeyedAccount::new(&key, false, &account))
.collect();
let instruction_data = vec![0u8];
let mut invoke_context = MockInvokeContext::new(&loader_id, keyed_accounts);
invoke_context.compute_meter = Rc::new(RefCell::new(MockComputeMeter { remaining: BUDGET }));
// Serialize account data
let keyed_accounts = invoke_context.get_keyed_accounts().unwrap();
let (mut serialized, account_lengths) = serialize_parameters(
&loader_id,
&solana_sdk::pubkey::new_rand(),
keyed_accounts,
&instruction_data,
)
.unwrap();
let elf = load_elf("noop").unwrap();
let executable = <dyn Executable<BpfError, ThisInstructionMeter>>::from_elf(
&elf,
None,
Config::default(),
register_syscalls(&mut invoke_context).unwrap(),
)
.unwrap();
let loader_id = bpf_loader::id();
with_mock_invoke_context(loader_id, 10000001, |invoke_context| {
const BUDGET: u64 = 200_000;
let compute_meter = invoke_context.get_compute_meter();
{
let mut compute_meter = compute_meter.borrow_mut();
let to_consume = compute_meter.get_remaining() - BUDGET;
compute_meter.consume(to_consume).unwrap();
}
bencher.iter(|| {
let _ = create_vm(
&loader_id,
executable.as_ref(),
serialized.as_slice_mut(),
&mut invoke_context,
&account_lengths,
// Serialize account data
let keyed_accounts = invoke_context.get_keyed_accounts().unwrap();
let (mut serialized, account_lengths) = serialize_parameters(
&keyed_accounts[0].unsigned_key(),
&keyed_accounts[1].unsigned_key(),
&keyed_accounts[2..],
&[],
)
.unwrap();
let executable = <dyn Executable<BpfError, ThisInstructionMeter>>::from_elf(
&elf,
None,
Config::default(),
register_syscalls(invoke_context).unwrap(),
)
.unwrap();
bencher.iter(|| {
let _ = create_vm(
&loader_id,
executable.as_ref(),
serialized.as_slice_mut(),
invoke_context,
&account_lengths,
)
.unwrap();
});
});
}
#[bench]
fn bench_instruction_count_tuner(_bencher: &mut Bencher) {
const BUDGET: u64 = 200_000;
let loader_id = bpf_loader::id();
let program_id = solana_sdk::pubkey::new_rand();
let accounts = [
(
program_id,
RefCell::new(AccountSharedData::new(0, 0, &loader_id)),
),
(
solana_sdk::pubkey::new_rand(),
RefCell::new(AccountSharedData::new(
1,
10000001,
&solana_sdk::pubkey::new_rand(),
)),
),
];
let keyed_accounts: Vec<_> = accounts
.iter()
.map(|(key, account)| solana_sdk::keyed_account::KeyedAccount::new(&key, false, &account))
.collect();
let instruction_data = vec![0u8];
let mut invoke_context = MockInvokeContext::new(&program_id, keyed_accounts);
invoke_context.compute_meter = Rc::new(RefCell::new(MockComputeMeter { remaining: BUDGET }));
// Serialize account data
let (mut serialized, account_lengths) = serialize_parameters(
&loader_id,
&program_id,
&invoke_context.get_keyed_accounts().unwrap()[1..],
&instruction_data,
)
.unwrap();
let elf = load_elf("tuner").unwrap();
let executable = <dyn Executable<BpfError, ThisInstructionMeter>>::from_elf(
&elf,
None,
Config::default(),
register_syscalls(&mut invoke_context).unwrap(),
)
.unwrap();
let compute_meter = invoke_context.get_compute_meter();
let mut instruction_meter = ThisInstructionMeter { compute_meter };
let mut vm = create_vm(
&loader_id,
executable.as_ref(),
serialized.as_slice_mut(),
&mut invoke_context,
&account_lengths,
)
.unwrap();
let loader_id = bpf_loader::id();
with_mock_invoke_context(loader_id, 10000001, |invoke_context| {
const BUDGET: u64 = 200_000;
let compute_meter = invoke_context.get_compute_meter();
{
let mut compute_meter = compute_meter.borrow_mut();
let to_consume = compute_meter.get_remaining() - BUDGET;
compute_meter.consume(to_consume).unwrap();
}
let mut measure = Measure::start("tune");
let _ = vm.execute_program_interpreted(&mut instruction_meter);
measure.stop();
// Serialize account data
let keyed_accounts = invoke_context.get_keyed_accounts().unwrap();
let (mut serialized, account_lengths) = serialize_parameters(
&keyed_accounts[0].unsigned_key(),
&keyed_accounts[1].unsigned_key(),
&keyed_accounts[2..],
&[],
)
.unwrap();
assert_eq!(
0,
instruction_meter.get_remaining(),
"Tuner must consume the whole budget"
);
println!(
"{:?} compute units took {:?} us ({:?} instructions)",
BUDGET - instruction_meter.get_remaining(),
measure.as_us(),
vm.get_total_instruction_count(),
);
let executable = <dyn Executable<BpfError, ThisInstructionMeter>>::from_elf(
&elf,
None,
Config::default(),
register_syscalls(invoke_context).unwrap(),
)
.unwrap();
let mut instruction_meter = ThisInstructionMeter { compute_meter };
let mut vm = create_vm(
&loader_id,
executable.as_ref(),
serialized.as_slice_mut(),
invoke_context,
&account_lengths,
)
.unwrap();
let mut measure = Measure::start("tune");
let _ = vm.execute_program_interpreted(&mut instruction_meter);
measure.stop();
assert_eq!(
0,
instruction_meter.get_remaining(),
"Tuner must consume the whole budget"
);
println!(
"{:?} compute units took {:?} us ({:?} instructions)",
BUDGET - instruction_meter.get_remaining(),
measure.as_us(),
vm.get_total_instruction_count(),
);
});
}