Rbpf v0.2.1 (#13732)
* Refactoring to match rbpf-v0.2.1 and add JIT compilation caching. * Removes obsolete bpf-trace.py which has been replaced by the rbpf CLI tool.
This commit is contained in:
parent
32cb8d1462
commit
c833ede4af
|
@ -84,9 +84,9 @@ checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ascii"
|
name = "ascii"
|
||||||
version = "0.7.1"
|
version = "0.9.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3ae7d751998c189c1d4468cf0a39bb2eae052a9c58d50ebb3b9591ee3813ad50"
|
checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "assert_cmd"
|
name = "assert_cmd"
|
||||||
|
@ -572,12 +572,15 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "combine"
|
name = "combine"
|
||||||
version = "2.5.2"
|
version = "3.8.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1645a65a99c7c8d345761f4b75a6ffe5be3b3b27a93ee731fccc5050ba6be97c"
|
checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ascii",
|
"ascii",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
|
"either",
|
||||||
|
"memchr 2.3.3",
|
||||||
|
"unreachable",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -5151,9 +5154,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana_rbpf"
|
name = "solana_rbpf"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "09e18fa1e1b6cac20a5f2571882b7580a65ae685b1413fc498f975d07d4c968f"
|
checksum = "8fad65297e2bd080468cb57a97e6a62e9a92928a45960496338e997e8270fa00"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"combine",
|
"combine",
|
||||||
|
@ -6289,6 +6292,15 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unreachable"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
||||||
|
dependencies = [
|
||||||
|
"void",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "untrusted"
|
name = "untrusted"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
|
|
@ -37,7 +37,7 @@ solana-config-program = { path = "../programs/config", version = "1.5.0" }
|
||||||
solana-faucet = { path = "../faucet", version = "1.5.0" }
|
solana-faucet = { path = "../faucet", version = "1.5.0" }
|
||||||
solana-logger = { path = "../logger", version = "1.5.0" }
|
solana-logger = { path = "../logger", version = "1.5.0" }
|
||||||
solana-net-utils = { path = "../net-utils", version = "1.5.0" }
|
solana-net-utils = { path = "../net-utils", version = "1.5.0" }
|
||||||
solana_rbpf = "=0.2.0"
|
solana_rbpf = "=0.2.1"
|
||||||
solana-remote-wallet = { path = "../remote-wallet", version = "1.5.0" }
|
solana-remote-wallet = { path = "../remote-wallet", version = "1.5.0" }
|
||||||
solana-sdk = { path = "../sdk", version = "1.5.0" }
|
solana-sdk = { path = "../sdk", version = "1.5.0" }
|
||||||
solana-stake-program = { path = "../programs/stake", version = "1.5.0" }
|
solana-stake-program = { path = "../programs/stake", version = "1.5.0" }
|
||||||
|
|
|
@ -9,7 +9,7 @@ use log::*;
|
||||||
use num_traits::FromPrimitive;
|
use num_traits::FromPrimitive;
|
||||||
use serde_json::{self, json, Value};
|
use serde_json::{self, json, Value};
|
||||||
use solana_account_decoder::{UiAccount, UiAccountEncoding};
|
use solana_account_decoder::{UiAccount, UiAccountEncoding};
|
||||||
use solana_bpf_loader_program::{bpf_verifier, BPFError};
|
use solana_bpf_loader_program::{bpf_verifier, BPFError, ThisInstructionMeter};
|
||||||
use solana_clap_utils::{
|
use solana_clap_utils::{
|
||||||
self,
|
self,
|
||||||
commitment::commitment_arg_with_default,
|
commitment::commitment_arg_with_default,
|
||||||
|
@ -39,7 +39,7 @@ use solana_client::{
|
||||||
use solana_faucet::faucet::request_airdrop_transaction;
|
use solana_faucet::faucet::request_airdrop_transaction;
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use solana_faucet::faucet_mock::request_airdrop_transaction;
|
use solana_faucet::faucet_mock::request_airdrop_transaction;
|
||||||
use solana_rbpf::vm::Executable;
|
use solana_rbpf::vm::{Config, Executable};
|
||||||
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
use solana_remote_wallet::remote_wallet::RemoteWalletManager;
|
||||||
use solana_sdk::{
|
use solana_sdk::{
|
||||||
bpf_loader, bpf_loader_deprecated,
|
bpf_loader, bpf_loader_deprecated,
|
||||||
|
@ -1227,8 +1227,12 @@ fn do_process_deploy(
|
||||||
CliError::DynamicProgramError(format!("Unable to read program file: {}", err))
|
CliError::DynamicProgramError(format!("Unable to read program file: {}", err))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
Executable::<BPFError>::from_elf(&program_data, Some(|x| bpf_verifier::check(x, false)))
|
Executable::<BPFError, ThisInstructionMeter>::from_elf(
|
||||||
.map_err(|err| CliError::DynamicProgramError(format!("ELF error: {}", err)))?;
|
&program_data,
|
||||||
|
Some(|x| bpf_verifier::check(x, false)),
|
||||||
|
Config::default(),
|
||||||
|
)
|
||||||
|
.map_err(|err| CliError::DynamicProgramError(format!("ELF error: {}", err)))?;
|
||||||
|
|
||||||
let loader_id = if use_deprecated_loader {
|
let loader_id = if use_deprecated_loader {
|
||||||
bpf_loader_deprecated::id()
|
bpf_loader_deprecated::id()
|
||||||
|
|
|
@ -57,9 +57,9 @@ checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ascii"
|
name = "ascii"
|
||||||
version = "0.7.1"
|
version = "0.9.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3ae7d751998c189c1d4468cf0a39bb2eae052a9c58d50ebb3b9591ee3813ad50"
|
checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "assert_matches"
|
name = "assert_matches"
|
||||||
|
@ -289,12 +289,15 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "combine"
|
name = "combine"
|
||||||
version = "2.5.2"
|
version = "3.8.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1645a65a99c7c8d345761f4b75a6ffe5be3b3b27a93ee731fccc5050ba6be97c"
|
checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ascii",
|
"ascii",
|
||||||
"byteorder 1.3.4",
|
"byteorder 1.3.4",
|
||||||
|
"either",
|
||||||
|
"memchr",
|
||||||
|
"unreachable",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1475,6 +1478,7 @@ dependencies = [
|
||||||
"rand_chacha",
|
"rand_chacha",
|
||||||
"rand_core",
|
"rand_core",
|
||||||
"rand_hc",
|
"rand_hc",
|
||||||
|
"rand_pcg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1505,6 +1509,15 @@ dependencies = [
|
||||||
"rand_core",
|
"rand_core",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rand_pcg"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rayon"
|
name = "rayon"
|
||||||
version = "1.4.1"
|
version = "1.4.1"
|
||||||
|
@ -2347,9 +2360,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "solana_rbpf"
|
name = "solana_rbpf"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "09e18fa1e1b6cac20a5f2571882b7580a65ae685b1413fc498f975d07d4c968f"
|
checksum = "8fad65297e2bd080468cb57a97e6a62e9a92928a45960496338e997e8270fa00"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder 1.3.4",
|
"byteorder 1.3.4",
|
||||||
"combine",
|
"combine",
|
||||||
|
@ -2805,6 +2818,15 @@ version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unreachable"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56"
|
||||||
|
dependencies = [
|
||||||
|
"void",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "untrusted"
|
name = "untrusted"
|
||||||
version = "0.7.1"
|
version = "0.7.1"
|
||||||
|
@ -2828,6 +2850,12 @@ version = "0.9.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
|
checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "void"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "walkdir"
|
name = "walkdir"
|
||||||
version = "2.3.1"
|
version = "2.3.1"
|
||||||
|
|
|
@ -27,7 +27,7 @@ solana-logger = { path = "../../logger", version = "1.5.0" }
|
||||||
solana-measure = { path = "../../measure", version = "1.5.0" }
|
solana-measure = { path = "../../measure", version = "1.5.0" }
|
||||||
solana-runtime = { path = "../../runtime", version = "1.5.0" }
|
solana-runtime = { path = "../../runtime", version = "1.5.0" }
|
||||||
solana-sdk = { path = "../../sdk", version = "1.5.0" }
|
solana-sdk = { path = "../../sdk", version = "1.5.0" }
|
||||||
solana_rbpf = "=0.2.0"
|
solana_rbpf = "=0.2.1"
|
||||||
|
|
||||||
[[bench]]
|
[[bench]]
|
||||||
name = "bpf_loader"
|
name = "bpf_loader"
|
||||||
|
|
|
@ -6,9 +6,12 @@ extern crate test;
|
||||||
extern crate solana_bpf_loader_program;
|
extern crate solana_bpf_loader_program;
|
||||||
|
|
||||||
use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};
|
use byteorder::{ByteOrder, LittleEndian, WriteBytesExt};
|
||||||
use solana_bpf_loader_program::ThisInstructionMeter;
|
use solana_bpf_loader_program::{
|
||||||
|
create_vm, serialization::serialize_parameters, syscalls::register_syscalls, BPFError,
|
||||||
|
ThisInstructionMeter,
|
||||||
|
};
|
||||||
use solana_measure::measure::Measure;
|
use solana_measure::measure::Measure;
|
||||||
use solana_rbpf::vm::{Executable, InstructionMeter};
|
use solana_rbpf::vm::{Config, Executable, InstructionMeter};
|
||||||
use solana_runtime::{
|
use solana_runtime::{
|
||||||
bank::Bank,
|
bank::Bank,
|
||||||
bank_client::BankClient,
|
bank_client::BankClient,
|
||||||
|
@ -72,7 +75,9 @@ fn bench_program_create_executable(bencher: &mut Bencher) {
|
||||||
let elf = load_elf("bench_alu").unwrap();
|
let elf = load_elf("bench_alu").unwrap();
|
||||||
|
|
||||||
bencher.iter(|| {
|
bencher.iter(|| {
|
||||||
let _ = Executable::<solana_bpf_loader_program::BPFError>::from_elf(&elf, None).unwrap();
|
let _ =
|
||||||
|
Executable::<BPFError, ThisInstructionMeter>::from_elf(&elf, None, Config::default())
|
||||||
|
.unwrap();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,11 +94,14 @@ fn bench_program_alu(bencher: &mut Bencher) {
|
||||||
let mut invoke_context = MockInvokeContext::default();
|
let mut invoke_context = MockInvokeContext::default();
|
||||||
|
|
||||||
let elf = load_elf("bench_alu").unwrap();
|
let elf = load_elf("bench_alu").unwrap();
|
||||||
let executable =
|
let mut executable =
|
||||||
Executable::<solana_bpf_loader_program::BPFError>::from_elf(&elf, None).unwrap();
|
Executable::<BPFError, ThisInstructionMeter>::from_elf(&elf, None, Config::default())
|
||||||
|
.unwrap();
|
||||||
|
executable.set_syscall_registry(register_syscalls(&mut invoke_context).unwrap());
|
||||||
|
executable.jit_compile().unwrap();
|
||||||
let compute_meter = invoke_context.get_compute_meter();
|
let compute_meter = invoke_context.get_compute_meter();
|
||||||
let mut instruction_meter = ThisInstructionMeter { compute_meter };
|
let mut instruction_meter = ThisInstructionMeter { compute_meter };
|
||||||
let mut vm = solana_bpf_loader_program::create_vm(
|
let mut vm = create_vm(
|
||||||
&loader_id,
|
&loader_id,
|
||||||
executable.as_ref(),
|
executable.as_ref(),
|
||||||
&mut inner_iter,
|
&mut inner_iter,
|
||||||
|
@ -128,22 +136,17 @@ fn bench_program_alu(bencher: &mut Bencher) {
|
||||||
println!("{{ \"type\": \"bench\", \"name\": \"bench_program_alu_interpreted_mips\", \"median\": {:?}, \"deviation\": 0 }}", mips);
|
println!("{{ \"type\": \"bench\", \"name\": \"bench_program_alu_interpreted_mips\", \"median\": {:?}, \"deviation\": 0 }}", mips);
|
||||||
|
|
||||||
println!("JIT to native:");
|
println!("JIT to native:");
|
||||||
vm.jit_compile().unwrap();
|
assert_eq!(
|
||||||
unsafe {
|
SUCCESS,
|
||||||
assert_eq!(
|
vm.execute_program_jit(&mut instruction_meter).unwrap()
|
||||||
SUCCESS,
|
);
|
||||||
vm.execute_program_jit(&mut instruction_meter).unwrap()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
assert_eq!(ARMSTRONG_LIMIT, LittleEndian::read_u64(&inner_iter));
|
assert_eq!(ARMSTRONG_LIMIT, LittleEndian::read_u64(&inner_iter));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ARMSTRONG_EXPECTED,
|
ARMSTRONG_EXPECTED,
|
||||||
LittleEndian::read_u64(&inner_iter[mem::size_of::<u64>()..])
|
LittleEndian::read_u64(&inner_iter[mem::size_of::<u64>()..])
|
||||||
);
|
);
|
||||||
|
|
||||||
bencher.iter(|| unsafe {
|
bencher.iter(|| vm.execute_program_jit(&mut instruction_meter).unwrap());
|
||||||
vm.execute_program_jit(&mut instruction_meter).unwrap();
|
|
||||||
});
|
|
||||||
let summary = bencher.bench(|_bencher| {}).unwrap();
|
let summary = bencher.bench(|_bencher| {}).unwrap();
|
||||||
println!(" {:?} instructions", instructions);
|
println!(" {:?} instructions", instructions);
|
||||||
println!(" {:?} ns/iter median", summary.median as u64);
|
println!(" {:?} ns/iter median", summary.median as u64);
|
||||||
|
@ -208,7 +211,7 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) {
|
||||||
let instruction_data = vec![0u8];
|
let instruction_data = vec![0u8];
|
||||||
|
|
||||||
// Serialize account data
|
// Serialize account data
|
||||||
let serialized = solana_bpf_loader_program::serialization::serialize_parameters(
|
let mut serialized = serialize_parameters(
|
||||||
&bpf_loader::id(),
|
&bpf_loader::id(),
|
||||||
&solana_sdk::pubkey::new_rand(),
|
&solana_sdk::pubkey::new_rand(),
|
||||||
&keyed_accounts,
|
&keyed_accounts,
|
||||||
|
@ -217,14 +220,16 @@ fn bench_instruction_count_tuner(_bencher: &mut Bencher) {
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let elf = load_elf("tuner").unwrap();
|
let elf = load_elf("tuner").unwrap();
|
||||||
let executable =
|
let mut executable =
|
||||||
Executable::<solana_bpf_loader_program::BPFError>::from_elf(&elf, None).unwrap();
|
Executable::<BPFError, ThisInstructionMeter>::from_elf(&elf, None, Config::default())
|
||||||
|
.unwrap();
|
||||||
|
executable.set_syscall_registry(register_syscalls(&mut invoke_context).unwrap());
|
||||||
let compute_meter = invoke_context.get_compute_meter();
|
let compute_meter = invoke_context.get_compute_meter();
|
||||||
let mut instruction_meter = ThisInstructionMeter { compute_meter };
|
let mut instruction_meter = ThisInstructionMeter { compute_meter };
|
||||||
let mut vm = solana_bpf_loader_program::create_vm(
|
let mut vm = create_vm(
|
||||||
&loader_id,
|
&loader_id,
|
||||||
executable.as_ref(),
|
executable.as_ref(),
|
||||||
&serialized,
|
&mut serialized,
|
||||||
&[],
|
&[],
|
||||||
&mut invoke_context,
|
&mut invoke_context,
|
||||||
)
|
)
|
||||||
|
|
|
@ -6,9 +6,10 @@ extern crate solana_bpf_loader_program;
|
||||||
use solana_bpf_loader_program::{
|
use solana_bpf_loader_program::{
|
||||||
create_vm,
|
create_vm,
|
||||||
serialization::{deserialize_parameters, serialize_parameters},
|
serialization::{deserialize_parameters, serialize_parameters},
|
||||||
|
syscalls::register_syscalls,
|
||||||
ThisInstructionMeter,
|
ThisInstructionMeter,
|
||||||
};
|
};
|
||||||
use solana_rbpf::vm::Executable;
|
use solana_rbpf::vm::{Config, Executable, Tracer};
|
||||||
use solana_runtime::{
|
use solana_runtime::{
|
||||||
bank::Bank,
|
bank::Bank,
|
||||||
bank_client::BankClient,
|
bank_client::BankClient,
|
||||||
|
@ -85,23 +86,62 @@ fn run_program(
|
||||||
let compute_meter = invoke_context.get_compute_meter();
|
let compute_meter = invoke_context.get_compute_meter();
|
||||||
let mut instruction_meter = ThisInstructionMeter { compute_meter };
|
let mut instruction_meter = ThisInstructionMeter { compute_meter };
|
||||||
|
|
||||||
let executable = Executable::from_elf(&data, None).unwrap();
|
let config = Config {
|
||||||
let mut vm = create_vm(
|
max_call_depth: 20,
|
||||||
&loader_id,
|
stack_frame_size: 4096,
|
||||||
executable.as_ref(),
|
enable_instruction_meter: true,
|
||||||
¶meter_bytes,
|
enable_instruction_tracing: true,
|
||||||
parameter_accounts,
|
};
|
||||||
&mut invoke_context,
|
let mut executable = Executable::from_elf(&data, None, config).unwrap();
|
||||||
)
|
executable.set_syscall_registry(register_syscalls(&mut invoke_context).unwrap());
|
||||||
.unwrap();
|
executable.jit_compile().unwrap();
|
||||||
|
|
||||||
assert_eq!(
|
let mut instruction_count = 0;
|
||||||
SUCCESS,
|
let mut tracer = None;
|
||||||
vm.execute_program_interpreted(&mut instruction_meter)
|
for i in 0..2 {
|
||||||
.unwrap()
|
let mut parameter_bytes = parameter_bytes.clone();
|
||||||
);
|
let mut vm = create_vm(
|
||||||
deserialize_parameters(&bpf_loader::id(), parameter_accounts, ¶meter_bytes).unwrap();
|
&loader_id,
|
||||||
Ok(vm.get_total_instruction_count())
|
executable.as_ref(),
|
||||||
|
&mut parameter_bytes,
|
||||||
|
parameter_accounts,
|
||||||
|
&mut invoke_context,
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
let result = if i == 0 {
|
||||||
|
vm.execute_program_interpreted(&mut instruction_meter)
|
||||||
|
} else {
|
||||||
|
vm.execute_program_jit(&mut instruction_meter)
|
||||||
|
};
|
||||||
|
assert_eq!(SUCCESS, result.unwrap());
|
||||||
|
deserialize_parameters(&bpf_loader::id(), parameter_accounts, ¶meter_bytes).unwrap();
|
||||||
|
if i == 1 {
|
||||||
|
assert_eq!(instruction_count, vm.get_total_instruction_count());
|
||||||
|
}
|
||||||
|
instruction_count = vm.get_total_instruction_count();
|
||||||
|
if config.enable_instruction_tracing {
|
||||||
|
if i == 1 {
|
||||||
|
if !Tracer::compare(tracer.as_ref().unwrap(), vm.get_tracer()) {
|
||||||
|
let mut tracer_display = String::new();
|
||||||
|
tracer
|
||||||
|
.as_ref()
|
||||||
|
.unwrap()
|
||||||
|
.write(&mut tracer_display, vm.get_program())
|
||||||
|
.unwrap();
|
||||||
|
println!("TRACE (interpreted): {}", tracer_display);
|
||||||
|
let mut tracer_display = String::new();
|
||||||
|
vm.get_tracer()
|
||||||
|
.write(&mut tracer_display, vm.get_program())
|
||||||
|
.unwrap();
|
||||||
|
println!("TRACE (jit): {}", tracer_display);
|
||||||
|
assert!(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tracer = Some(vm.get_tracer().clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(instruction_count)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_transaction_and_record_inner(
|
fn process_transaction_and_record_inner(
|
||||||
|
|
|
@ -16,7 +16,7 @@ num-derive = "0.3"
|
||||||
num-traits = "0.2"
|
num-traits = "0.2"
|
||||||
solana-runtime = { path = "../../runtime", version = "1.5.0" }
|
solana-runtime = { path = "../../runtime", version = "1.5.0" }
|
||||||
solana-sdk = { path = "../../sdk", version = "1.5.0" }
|
solana-sdk = { path = "../../sdk", version = "1.5.0" }
|
||||||
solana_rbpf = "=0.2.0"
|
solana_rbpf = "=0.2.1"
|
||||||
thiserror = "1.0"
|
thiserror = "1.0"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
|
|
@ -45,6 +45,8 @@ pub enum BPFLoaderError {
|
||||||
VirtualMachineCreationFailed = 0x0b9f_0001,
|
VirtualMachineCreationFailed = 0x0b9f_0001,
|
||||||
#[error("virtual machine failed to run the program to completion")]
|
#[error("virtual machine failed to run the program to completion")]
|
||||||
VirtualMachineFailedToRunProgram = 0x0b9f_0002,
|
VirtualMachineFailedToRunProgram = 0x0b9f_0002,
|
||||||
|
#[error("failed to compile program")]
|
||||||
|
JustInTimeCompilationFailed = 0x0b9f_0003,
|
||||||
}
|
}
|
||||||
impl<E> DecodeError<E> for BPFLoaderError {
|
impl<E> DecodeError<E> for BPFLoaderError {
|
||||||
fn type_of() -> &'static str {
|
fn type_of() -> &'static str {
|
||||||
|
@ -89,12 +91,24 @@ fn map_ebpf_error(
|
||||||
InstructionError::InvalidAccountData
|
InstructionError::InvalidAccountData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const IS_JIT_ENABLED: bool = false;
|
||||||
|
|
||||||
pub fn create_and_cache_executor(
|
pub fn create_and_cache_executor(
|
||||||
program: &KeyedAccount,
|
program: &KeyedAccount,
|
||||||
invoke_context: &mut dyn InvokeContext,
|
invoke_context: &mut dyn InvokeContext,
|
||||||
) -> Result<Arc<BPFExecutor>, InstructionError> {
|
) -> Result<Arc<BPFExecutor>, InstructionError> {
|
||||||
let executable = Executable::from_elf(&program.try_account_ref()?.data, None)
|
let bpf_compute_budget = invoke_context.get_bpf_compute_budget();
|
||||||
.map_err(|e| map_ebpf_error(invoke_context, e))?;
|
let mut executable = Executable::<BPFError, ThisInstructionMeter>::from_elf(
|
||||||
|
&program.try_account_ref()?.data,
|
||||||
|
None,
|
||||||
|
Config {
|
||||||
|
max_call_depth: bpf_compute_budget.max_call_depth,
|
||||||
|
stack_frame_size: bpf_compute_budget.stack_frame_size,
|
||||||
|
enable_instruction_meter: true,
|
||||||
|
enable_instruction_tracing: false,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.map_err(|e| map_ebpf_error(invoke_context, e))?;
|
||||||
let (_, elf_bytes) = executable
|
let (_, elf_bytes) = executable
|
||||||
.get_text_bytes()
|
.get_text_bytes()
|
||||||
.map_err(|e| map_ebpf_error(invoke_context, e))?;
|
.map_err(|e| map_ebpf_error(invoke_context, e))?;
|
||||||
|
@ -103,6 +117,12 @@ pub fn create_and_cache_executor(
|
||||||
!invoke_context.is_feature_active(&bpf_compute_budget_balancing::id()),
|
!invoke_context.is_feature_active(&bpf_compute_budget_balancing::id()),
|
||||||
)
|
)
|
||||||
.map_err(|e| map_ebpf_error(invoke_context, EbpfError::UserError(e)))?;
|
.map_err(|e| map_ebpf_error(invoke_context, EbpfError::UserError(e)))?;
|
||||||
|
let syscall_registry = syscalls::register_syscalls(invoke_context)
|
||||||
|
.map_err(|e| map_ebpf_error(invoke_context, e))?;
|
||||||
|
executable.set_syscall_registry(syscall_registry);
|
||||||
|
if IS_JIT_ENABLED && executable.jit_compile().is_err() {
|
||||||
|
return Err(BPFLoaderError::JustInTimeCompilationFailed.into());
|
||||||
|
}
|
||||||
let executor = Arc::new(BPFExecutor { executable });
|
let executor = Arc::new(BPFExecutor { executable });
|
||||||
invoke_context.add_executor(program.unsigned_key(), executor.clone());
|
invoke_context.add_executor(program.unsigned_key(), executor.clone());
|
||||||
Ok(executor)
|
Ok(executor)
|
||||||
|
@ -115,24 +135,21 @@ const DEFAULT_HEAP_SIZE: usize = 32 * 1024;
|
||||||
/// Create the BPF virtual machine
|
/// Create the BPF virtual machine
|
||||||
pub fn create_vm<'a>(
|
pub fn create_vm<'a>(
|
||||||
loader_id: &'a Pubkey,
|
loader_id: &'a Pubkey,
|
||||||
executable: &'a dyn Executable<BPFError>,
|
executable: &'a dyn Executable<BPFError, ThisInstructionMeter>,
|
||||||
parameter_bytes: &[u8],
|
parameter_bytes: &mut [u8],
|
||||||
parameter_accounts: &'a [KeyedAccount<'a>],
|
parameter_accounts: &'a [KeyedAccount<'a>],
|
||||||
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 = vec![0_u8; DEFAULT_HEAP_SIZE];
|
let heap = vec![0_u8; DEFAULT_HEAP_SIZE];
|
||||||
let heap_region = MemoryRegion::new_from_slice(&heap, MM_HEAP_START, true);
|
let heap_region = MemoryRegion::new_from_slice(&heap, MM_HEAP_START, 0, true);
|
||||||
let bpf_compute_budget = invoke_context.get_bpf_compute_budget();
|
let mut vm = EbpfVm::new(executable, parameter_bytes, &[heap_region])?;
|
||||||
let mut vm = EbpfVm::new(
|
syscalls::bind_syscall_context_objects(
|
||||||
executable,
|
loader_id,
|
||||||
Config {
|
&mut vm,
|
||||||
max_call_depth: bpf_compute_budget.max_call_depth,
|
parameter_accounts,
|
||||||
stack_frame_size: bpf_compute_budget.stack_frame_size,
|
invoke_context,
|
||||||
},
|
heap,
|
||||||
parameter_bytes,
|
|
||||||
&[heap_region],
|
|
||||||
)?;
|
)?;
|
||||||
syscalls::register_syscalls(loader_id, &mut vm, parameter_accounts, invoke_context, heap)?;
|
|
||||||
Ok(vm)
|
Ok(vm)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,7 +236,7 @@ impl InstructionMeter for ThisInstructionMeter {
|
||||||
|
|
||||||
/// BPF Loader's Executor implementation
|
/// BPF Loader's Executor implementation
|
||||||
pub struct BPFExecutor {
|
pub struct BPFExecutor {
|
||||||
executable: Box<dyn Executable<BPFError>>,
|
executable: Box<dyn Executable<BPFError, ThisInstructionMeter>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Well, implement Debug for solana_rbpf::vm::Executable in solana-rbpf...
|
// Well, implement Debug for solana_rbpf::vm::Executable in solana-rbpf...
|
||||||
|
@ -244,7 +261,7 @@ impl Executor for BPFExecutor {
|
||||||
let program = next_keyed_account(&mut keyed_accounts_iter)?;
|
let program = next_keyed_account(&mut keyed_accounts_iter)?;
|
||||||
|
|
||||||
let parameter_accounts = keyed_accounts_iter.as_slice();
|
let parameter_accounts = keyed_accounts_iter.as_slice();
|
||||||
let parameter_bytes = serialize_parameters(
|
let mut parameter_bytes = serialize_parameters(
|
||||||
program_id,
|
program_id,
|
||||||
program.unsigned_key(),
|
program.unsigned_key(),
|
||||||
parameter_accounts,
|
parameter_accounts,
|
||||||
|
@ -255,7 +272,7 @@ impl Executor for BPFExecutor {
|
||||||
let mut vm = match create_vm(
|
let mut vm = match create_vm(
|
||||||
program_id,
|
program_id,
|
||||||
self.executable.as_ref(),
|
self.executable.as_ref(),
|
||||||
parameter_bytes.as_slice(),
|
&mut parameter_bytes,
|
||||||
¶meter_accounts,
|
¶meter_accounts,
|
||||||
invoke_context,
|
invoke_context,
|
||||||
) {
|
) {
|
||||||
|
@ -269,12 +286,8 @@ impl Executor for BPFExecutor {
|
||||||
stable_log::program_invoke(&logger, program.unsigned_key(), invoke_depth);
|
stable_log::program_invoke(&logger, program.unsigned_key(), invoke_depth);
|
||||||
let mut instruction_meter = ThisInstructionMeter::new(compute_meter.clone());
|
let mut instruction_meter = ThisInstructionMeter::new(compute_meter.clone());
|
||||||
let before = compute_meter.borrow().get_remaining();
|
let before = compute_meter.borrow().get_remaining();
|
||||||
const IS_JIT_ENABLED: bool = false;
|
|
||||||
let result = if IS_JIT_ENABLED {
|
let result = if IS_JIT_ENABLED {
|
||||||
if vm.jit_compile().is_err() {
|
vm.execute_program_jit(&mut instruction_meter)
|
||||||
return Err(BPFLoaderError::VirtualMachineCreationFailed.into());
|
|
||||||
}
|
|
||||||
unsafe { vm.execute_program_jit(&mut instruction_meter) }
|
|
||||||
} else {
|
} else {
|
||||||
vm.execute_program_interpreted(&mut instruction_meter)
|
vm.execute_program_interpreted(&mut instruction_meter)
|
||||||
};
|
};
|
||||||
|
@ -357,14 +370,14 @@ mod tests {
|
||||||
];
|
];
|
||||||
let input = &mut [0x00];
|
let input = &mut [0x00];
|
||||||
|
|
||||||
let executable = Executable::<BPFError>::from_text_bytes(program, None).unwrap();
|
let executable = Executable::<BPFError, TestInstructionMeter>::from_text_bytes(
|
||||||
let mut vm = EbpfVm::<BPFError, TestInstructionMeter>::new(
|
program,
|
||||||
executable.as_ref(),
|
None,
|
||||||
Config::default(),
|
Config::default(),
|
||||||
input,
|
|
||||||
&[],
|
|
||||||
)
|
)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
let mut vm =
|
||||||
|
EbpfVm::<BPFError, TestInstructionMeter>::new(executable.as_ref(), input, &[]).unwrap();
|
||||||
let mut instruction_meter = TestInstructionMeter { remaining: 10 };
|
let mut instruction_meter = TestInstructionMeter { remaining: 10 };
|
||||||
vm.execute_program_interpreted(&mut instruction_meter)
|
vm.execute_program_interpreted(&mut instruction_meter)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,138 +0,0 @@
|
||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
#
|
|
||||||
# Prints a BPF program call trace with instruction counts for each call
|
|
||||||
#
|
|
||||||
# This script requires a dump file containing the instruction dump of the ELF
|
|
||||||
# and a trace file that contains the trace output of the BPF VM
|
|
||||||
#
|
|
||||||
# You can create the dump file by passing the --dump flag to `cargo build-bpf`,
|
|
||||||
# or directly:
|
|
||||||
# $ llvm-objdump -print-imm-hex --source --disassemble <ELF file path>
|
|
||||||
#
|
|
||||||
# You can create the trace file by running the program and setting RUST_LOG:
|
|
||||||
# Set RUST_LOG
|
|
||||||
# $ export RUST_LOG=solana_rbpf=trace
|
|
||||||
# Capture output via `> trace.txt 2>&1`
|
|
||||||
#
|
|
||||||
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
|
|
||||||
# regular expressions to search for
|
|
||||||
rxs_symbols = {
|
|
||||||
'start' : re.compile(r'Disassembly of section \.text.*\n'),
|
|
||||||
'symbol': re.compile(r'^(?!LBB)([<\S].+)\n'),
|
|
||||||
}
|
|
||||||
rxs_ixs = {
|
|
||||||
'ixs': re.compile(r' *(\d+) *.*\n'),
|
|
||||||
}
|
|
||||||
rxs_call = {
|
|
||||||
'entry': re.compile(r'BPF: +0 .+pc *(\d+) *.*\n'),
|
|
||||||
'call' : re.compile(r'BPF: +(\d+) .+pc *(\d+) *call.*\n'),
|
|
||||||
'exit' : re.compile(r'BPF: +(\d+) .+exit\n'),
|
|
||||||
}
|
|
||||||
rxs_called = {
|
|
||||||
'pc': re.compile(r'BPF: +\d+ .+pc +(\d+).*\n'),
|
|
||||||
}
|
|
||||||
|
|
||||||
# parse a line
|
|
||||||
def parse_line(rxs, line):
|
|
||||||
for key, rx in rxs.items():
|
|
||||||
match = rx.search(line)
|
|
||||||
if match:
|
|
||||||
return key, match
|
|
||||||
return None, None
|
|
||||||
|
|
||||||
# main
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
|
||||||
if len(sys.argv) < 3:
|
|
||||||
print('Error: Must specify a dump and trace file')
|
|
||||||
sys.exit(' Usage: ' + sys.argv[0] + ' dump_file trace_file')
|
|
||||||
dumppath = sys.argv[1]
|
|
||||||
tracepath = sys.argv[2]
|
|
||||||
|
|
||||||
# parse the dump file to create a map
|
|
||||||
# of instruction numbers to symbols
|
|
||||||
symbols = {}
|
|
||||||
with open(dumppath, 'r') as file_object:
|
|
||||||
line = file_object.readline()
|
|
||||||
while line:
|
|
||||||
key, match = parse_line(rxs_symbols, line)
|
|
||||||
if key == 'start':
|
|
||||||
line = file_object.readline()
|
|
||||||
while line:
|
|
||||||
key, match = parse_line(rxs_symbols, line)
|
|
||||||
if key == 'symbol':
|
|
||||||
symbol = match.group(1)
|
|
||||||
line = file_object.readline()
|
|
||||||
key, match = parse_line(rxs_ixs, line)
|
|
||||||
if key == 'ixs':
|
|
||||||
ixs = int(match.group(1))
|
|
||||||
symbols[ixs] = symbol
|
|
||||||
line = file_object.readline()
|
|
||||||
line = file_object.readline()
|
|
||||||
if len(symbols) == 0:
|
|
||||||
sys.exit("Error: No instruction dump in: " + dumppath)
|
|
||||||
|
|
||||||
# parse the trace file to build a call list
|
|
||||||
calls = [] # all the calls made
|
|
||||||
with open(tracepath, 'r') as file_object:
|
|
||||||
exits = [] # instruction counts at each call exit
|
|
||||||
call_nums = [] # used to match up exits to calls
|
|
||||||
frame = 1
|
|
||||||
max_frame = 0
|
|
||||||
num_calls = 0
|
|
||||||
line = file_object.readline()
|
|
||||||
while line:
|
|
||||||
# print line
|
|
||||||
key, match = parse_line(rxs_call, line)
|
|
||||||
if key == 'call':
|
|
||||||
ixs_count = int(match.group(1))
|
|
||||||
calling_pc = int(match.group(2))
|
|
||||||
line = file_object.readline()
|
|
||||||
key, match = parse_line(rxs_called, line)
|
|
||||||
while key != 'pc':
|
|
||||||
line = file_object.readline()
|
|
||||||
key, match = parse_line(rxs_called, line)
|
|
||||||
called_pc = int(match.group(1))
|
|
||||||
if calling_pc + 1 == called_pc:
|
|
||||||
calls.append((ixs_count, frame, 'Solana system call'))
|
|
||||||
exits.append(ixs_count)
|
|
||||||
num_calls += 1
|
|
||||||
else:
|
|
||||||
calls.append((ixs_count, frame, symbols[called_pc]))
|
|
||||||
call_nums.append(num_calls)
|
|
||||||
exits.append(0)
|
|
||||||
num_calls += 1
|
|
||||||
frame += 1
|
|
||||||
max_frame = max(frame, max_frame)
|
|
||||||
else:
|
|
||||||
if key == 'entry':
|
|
||||||
pc = int(match.group(1))
|
|
||||||
calls.append((0, 0, symbols[pc]))
|
|
||||||
call_nums.append(num_calls)
|
|
||||||
exits.append(0)
|
|
||||||
num_calls += 1
|
|
||||||
elif key == 'exit':
|
|
||||||
ixs_count = int(match.group(1))
|
|
||||||
num = call_nums.pop()
|
|
||||||
exits[num] = ixs_count
|
|
||||||
frame -= 1
|
|
||||||
line = file_object.readline()
|
|
||||||
if len(calls) == 0:
|
|
||||||
sys.exit("Error: No valid trace in : " + tracepath)
|
|
||||||
|
|
||||||
# print the call trace with instruction counts for each call
|
|
||||||
print "Max frame depth: ", max_frame - 1
|
|
||||||
print "Call trace:"
|
|
||||||
print "Ins num (Ins count): Symbol called"
|
|
||||||
for call, exit in zip(calls, exits):
|
|
||||||
if exit == 0:
|
|
||||||
count = " No return"
|
|
||||||
else:
|
|
||||||
count = "%9d" % (exit - call[0])
|
|
||||||
print("%9d (%s): %s %s" % (call[0], count, ' | ' * call[1], call[2]))
|
|
||||||
if frame != 0:
|
|
||||||
print "Error: Program did not exit gracefully"
|
|
Loading…
Reference in New Issue