* move `ExecuteTimings` from `runtime::bank` to `program_runtime::timings` (cherry picked from commit7d32909e17
) # Conflicts: # core/Cargo.toml # ledger/Cargo.toml # programs/bpf/Cargo.lock * Add execute metrics (cherry picked from commitb25e4a200b
) * Add metrics for executor creation (cherry picked from commit848b6dfbdd
) * Add helper macro for `AddAssign`ing with saturating arithmetic (cherry picked from commitdeb9344e49
) * Use saturating_add_assign macro (cherry picked from commit72fc6096a0
) * Consolidate process instruction execution timings to own struct (cherry picked from commit390ef0fbcd
) Co-authored-by: Trent Nelson <trent@solana.com> Co-authored-by: Carl Lin <carl@solana.com>
This commit is contained in:
@ -20,6 +20,7 @@ num-derive = { version = "0.3" }
|
||||
num-traits = { version = "0.2" }
|
||||
serde = { version = "1.0.129", features = ["derive", "rc"] }
|
||||
solana-logger = { path = "../logger", version = "=1.9.4" }
|
||||
solana-measure = { path = "../measure", version = "=1.9.4" }
|
||||
solana-sdk = { path = "../sdk", version = "=1.9.4" }
|
||||
thiserror = "1.0"
|
||||
|
||||
|
@ -1,9 +1,14 @@
|
||||
use {
|
||||
crate::{
|
||||
accounts_data_meter::AccountsDataMeter, ic_logger_msg, ic_msg,
|
||||
instruction_recorder::InstructionRecorder, log_collector::LogCollector,
|
||||
native_loader::NativeLoader, pre_account::PreAccount, timings::ExecuteDetailsTimings,
|
||||
accounts_data_meter::AccountsDataMeter,
|
||||
ic_logger_msg, ic_msg,
|
||||
instruction_recorder::InstructionRecorder,
|
||||
log_collector::LogCollector,
|
||||
native_loader::NativeLoader,
|
||||
pre_account::PreAccount,
|
||||
timings::{ExecuteDetailsTimings, ExecuteTimings},
|
||||
},
|
||||
solana_measure::measure::Measure,
|
||||
solana_sdk::{
|
||||
account::{AccountSharedData, ReadableAccount},
|
||||
account_utils::StateMut,
|
||||
@ -20,6 +25,7 @@ use {
|
||||
message::Message,
|
||||
pubkey::Pubkey,
|
||||
rent::Rent,
|
||||
saturating_add_assign,
|
||||
sysvar::Sysvar,
|
||||
},
|
||||
std::{cell::RefCell, collections::HashMap, fmt::Debug, rc::Rc, sync::Arc},
|
||||
@ -567,6 +573,7 @@ impl<'a> InvokeContext<'a> {
|
||||
&program_indices,
|
||||
&account_indices,
|
||||
&caller_write_privileges,
|
||||
&mut ExecuteTimings::default(),
|
||||
)
|
||||
.result?;
|
||||
|
||||
@ -709,12 +716,22 @@ impl<'a> InvokeContext<'a> {
|
||||
program_indices: &[usize],
|
||||
account_indices: &[usize],
|
||||
caller_write_privileges: &[bool],
|
||||
timings: &mut ExecuteTimings,
|
||||
) -> ProcessInstructionResult {
|
||||
let is_lowest_invocation_level = self.invoke_stack.is_empty();
|
||||
if !is_lowest_invocation_level {
|
||||
// Verify the calling program hasn't misbehaved
|
||||
let mut verify_caller_time = Measure::start("verify_caller_time");
|
||||
let result =
|
||||
self.verify_and_update(instruction, account_indices, caller_write_privileges);
|
||||
verify_caller_time.stop();
|
||||
saturating_add_assign!(
|
||||
timings
|
||||
.execute_accessories
|
||||
.process_instructions
|
||||
.verify_caller_us,
|
||||
verify_caller_time.as_us()
|
||||
);
|
||||
if result.is_err() {
|
||||
return ProcessInstructionResult {
|
||||
compute_units_consumed: 0,
|
||||
@ -727,22 +744,45 @@ impl<'a> InvokeContext<'a> {
|
||||
let result = self
|
||||
.push(message, instruction, program_indices, account_indices)
|
||||
.and_then(|_| {
|
||||
let mut process_executable_chain_time =
|
||||
Measure::start("process_executable_chain_time");
|
||||
self.return_data = (*instruction.program_id(&message.account_keys), Vec::new());
|
||||
let pre_remaining_units = self.compute_meter.borrow().get_remaining();
|
||||
let execution_result = self.process_executable_chain(&instruction.data);
|
||||
let post_remaining_units = self.compute_meter.borrow().get_remaining();
|
||||
compute_units_consumed = pre_remaining_units.saturating_sub(post_remaining_units);
|
||||
execution_result?;
|
||||
process_executable_chain_time.stop();
|
||||
|
||||
// Verify the called program has not misbehaved
|
||||
if is_lowest_invocation_level {
|
||||
self.verify(message, instruction, program_indices)
|
||||
} else {
|
||||
let write_privileges: Vec<bool> = (0..message.account_keys.len())
|
||||
.map(|i| message.is_writable(i))
|
||||
.collect();
|
||||
self.verify_and_update(instruction, account_indices, &write_privileges)
|
||||
}
|
||||
let mut verify_callee_time = Measure::start("verify_callee_time");
|
||||
let result = execution_result.and_then(|_| {
|
||||
if is_lowest_invocation_level {
|
||||
self.verify(message, instruction, program_indices)
|
||||
} else {
|
||||
let write_privileges: Vec<bool> = (0..message.account_keys.len())
|
||||
.map(|i| message.is_writable(i))
|
||||
.collect();
|
||||
self.verify_and_update(instruction, account_indices, &write_privileges)
|
||||
}
|
||||
});
|
||||
verify_callee_time.stop();
|
||||
|
||||
saturating_add_assign!(
|
||||
timings
|
||||
.execute_accessories
|
||||
.process_instructions
|
||||
.process_executable_chain_us,
|
||||
process_executable_chain_time.as_us()
|
||||
);
|
||||
saturating_add_assign!(
|
||||
timings
|
||||
.execute_accessories
|
||||
.process_instructions
|
||||
.verify_callee_us,
|
||||
verify_callee_time.as_us()
|
||||
);
|
||||
|
||||
result
|
||||
});
|
||||
|
||||
// Pop the invoke_stack to restore previous state
|
||||
@ -1387,6 +1427,7 @@ mod tests {
|
||||
&program_indices[1..],
|
||||
&account_indices,
|
||||
&caller_write_privileges,
|
||||
&mut ExecuteTimings::default(),
|
||||
)
|
||||
.result,
|
||||
Err(InstructionError::ExternalAccountDataModified)
|
||||
@ -1403,6 +1444,7 @@ mod tests {
|
||||
&program_indices[1..],
|
||||
&account_indices,
|
||||
&caller_write_privileges,
|
||||
&mut ExecuteTimings::default(),
|
||||
)
|
||||
.result,
|
||||
Err(InstructionError::ReadonlyDataModified)
|
||||
@ -1461,6 +1503,7 @@ mod tests {
|
||||
&program_indices[1..],
|
||||
&account_indices,
|
||||
&caller_write_privileges,
|
||||
&mut ExecuteTimings::default(),
|
||||
),
|
||||
case.1
|
||||
);
|
||||
@ -1712,6 +1755,7 @@ mod tests {
|
||||
&program_indices[1..],
|
||||
&account_indices,
|
||||
&caller_write_privileges,
|
||||
&mut ExecuteTimings::default(),
|
||||
);
|
||||
|
||||
// Because the instruction had compute cost > 0, then regardless of the execution result,
|
||||
@ -1786,6 +1830,7 @@ mod tests {
|
||||
&program_indices,
|
||||
&account_indices,
|
||||
&caller_write_privileges,
|
||||
&mut ExecuteTimings::default(),
|
||||
)
|
||||
.result;
|
||||
|
||||
@ -1816,6 +1861,7 @@ mod tests {
|
||||
&program_indices,
|
||||
&account_indices,
|
||||
&caller_write_privileges,
|
||||
&mut ExecuteTimings::default(),
|
||||
)
|
||||
.result;
|
||||
|
||||
@ -1846,6 +1892,7 @@ mod tests {
|
||||
&program_indices,
|
||||
&account_indices,
|
||||
&caller_write_privileges,
|
||||
&mut ExecuteTimings::default(),
|
||||
)
|
||||
.result;
|
||||
|
||||
|
@ -1,4 +1,7 @@
|
||||
use {solana_sdk::pubkey::Pubkey, std::collections::HashMap};
|
||||
use {
|
||||
solana_sdk::{pubkey::Pubkey, saturating_add_assign},
|
||||
std::collections::HashMap,
|
||||
};
|
||||
|
||||
#[derive(Default, Debug, PartialEq)]
|
||||
pub struct ProgramTiming {
|
||||
@ -15,23 +18,97 @@ impl ProgramTiming {
|
||||
for tx_error_compute_consumed in self.errored_txs_compute_consumed.drain(..) {
|
||||
let compute_units_update =
|
||||
std::cmp::max(current_estimated_program_cost, tx_error_compute_consumed);
|
||||
self.accumulated_units = self.accumulated_units.saturating_add(compute_units_update);
|
||||
self.count = self.count.saturating_add(1);
|
||||
saturating_add_assign!(self.accumulated_units, compute_units_update);
|
||||
saturating_add_assign!(self.count, 1);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn accumulate_program_timings(&mut self, other: &ProgramTiming) {
|
||||
self.accumulated_us = self.accumulated_us.saturating_add(other.accumulated_us);
|
||||
self.accumulated_units = self
|
||||
.accumulated_units
|
||||
.saturating_add(other.accumulated_units);
|
||||
self.count = self.count.saturating_add(other.count);
|
||||
saturating_add_assign!(self.accumulated_us, other.accumulated_us);
|
||||
saturating_add_assign!(self.accumulated_units, other.accumulated_units);
|
||||
saturating_add_assign!(self.count, other.count);
|
||||
// Clones the entire vector, maybe not great...
|
||||
self.errored_txs_compute_consumed
|
||||
.extend(other.errored_txs_compute_consumed.clone());
|
||||
self.total_errored_units = self
|
||||
.total_errored_units
|
||||
.saturating_add(other.total_errored_units);
|
||||
saturating_add_assign!(self.total_errored_units, other.total_errored_units);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct ExecuteTimings {
|
||||
pub check_us: u64,
|
||||
pub load_us: u64,
|
||||
pub execute_us: u64,
|
||||
pub store_us: u64,
|
||||
pub update_stakes_cache_us: u64,
|
||||
pub total_batches_len: usize,
|
||||
pub num_execute_batches: u64,
|
||||
pub collect_logs_us: u64,
|
||||
pub details: ExecuteDetailsTimings,
|
||||
pub execute_accessories: ExecuteAccessoryTimings,
|
||||
}
|
||||
|
||||
impl ExecuteTimings {
|
||||
pub fn accumulate(&mut self, other: &ExecuteTimings) {
|
||||
saturating_add_assign!(self.check_us, other.check_us);
|
||||
saturating_add_assign!(self.load_us, other.load_us);
|
||||
saturating_add_assign!(self.execute_us, other.execute_us);
|
||||
saturating_add_assign!(self.store_us, other.store_us);
|
||||
saturating_add_assign!(self.update_stakes_cache_us, other.update_stakes_cache_us);
|
||||
saturating_add_assign!(self.total_batches_len, other.total_batches_len);
|
||||
saturating_add_assign!(self.num_execute_batches, other.num_execute_batches);
|
||||
saturating_add_assign!(self.collect_logs_us, other.collect_logs_us);
|
||||
self.details.accumulate(&other.details);
|
||||
self.execute_accessories
|
||||
.accumulate(&other.execute_accessories);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct ExecuteProcessInstructionTimings {
|
||||
pub total_us: u64,
|
||||
pub verify_caller_us: u64,
|
||||
pub process_executable_chain_us: u64,
|
||||
pub verify_callee_us: u64,
|
||||
}
|
||||
|
||||
impl ExecuteProcessInstructionTimings {
|
||||
pub fn accumulate(&mut self, other: &ExecuteProcessInstructionTimings) {
|
||||
saturating_add_assign!(self.total_us, other.total_us);
|
||||
saturating_add_assign!(self.verify_caller_us, other.verify_caller_us);
|
||||
saturating_add_assign!(
|
||||
self.process_executable_chain_us,
|
||||
other.process_executable_chain_us
|
||||
);
|
||||
saturating_add_assign!(self.verify_callee_us, other.verify_callee_us);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct ExecuteAccessoryTimings {
|
||||
pub feature_set_clone_us: u64,
|
||||
pub compute_budget_process_transaction_us: u64,
|
||||
pub get_executors_us: u64,
|
||||
pub process_message_us: u64,
|
||||
pub update_executors_us: u64,
|
||||
pub process_instructions: ExecuteProcessInstructionTimings,
|
||||
}
|
||||
|
||||
impl ExecuteAccessoryTimings {
|
||||
pub fn accumulate(&mut self, other: &ExecuteAccessoryTimings) {
|
||||
saturating_add_assign!(
|
||||
self.compute_budget_process_transaction_us,
|
||||
other.feature_set_clone_us
|
||||
);
|
||||
saturating_add_assign!(
|
||||
self.compute_budget_process_transaction_us,
|
||||
other.compute_budget_process_transaction_us
|
||||
);
|
||||
saturating_add_assign!(self.get_executors_us, other.get_executors_us);
|
||||
saturating_add_assign!(self.process_message_us, other.process_message_us);
|
||||
saturating_add_assign!(self.update_executors_us, other.update_executors_us);
|
||||
self.process_instructions
|
||||
.accumulate(&other.process_instructions);
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,28 +118,47 @@ pub struct ExecuteDetailsTimings {
|
||||
pub create_vm_us: u64,
|
||||
pub execute_us: u64,
|
||||
pub deserialize_us: u64,
|
||||
pub get_or_create_executor_us: u64,
|
||||
pub changed_account_count: u64,
|
||||
pub total_account_count: u64,
|
||||
pub total_data_size: usize,
|
||||
pub data_size_changed: usize,
|
||||
pub create_executor_register_syscalls_us: u64,
|
||||
pub create_executor_load_elf_us: u64,
|
||||
pub create_executor_verify_code_us: u64,
|
||||
pub create_executor_jit_compile_us: u64,
|
||||
pub per_program_timings: HashMap<Pubkey, ProgramTiming>,
|
||||
}
|
||||
impl ExecuteDetailsTimings {
|
||||
pub fn accumulate(&mut self, other: &ExecuteDetailsTimings) {
|
||||
self.serialize_us = self.serialize_us.saturating_add(other.serialize_us);
|
||||
self.create_vm_us = self.create_vm_us.saturating_add(other.create_vm_us);
|
||||
self.execute_us = self.execute_us.saturating_add(other.execute_us);
|
||||
self.deserialize_us = self.deserialize_us.saturating_add(other.deserialize_us);
|
||||
self.changed_account_count = self
|
||||
.changed_account_count
|
||||
.saturating_add(other.changed_account_count);
|
||||
self.total_account_count = self
|
||||
.total_account_count
|
||||
.saturating_add(other.total_account_count);
|
||||
self.total_data_size = self.total_data_size.saturating_add(other.total_data_size);
|
||||
self.data_size_changed = self
|
||||
.data_size_changed
|
||||
.saturating_add(other.data_size_changed);
|
||||
saturating_add_assign!(self.serialize_us, other.serialize_us);
|
||||
saturating_add_assign!(self.create_vm_us, other.create_vm_us);
|
||||
saturating_add_assign!(self.execute_us, other.execute_us);
|
||||
saturating_add_assign!(self.deserialize_us, other.deserialize_us);
|
||||
saturating_add_assign!(
|
||||
self.get_or_create_executor_us,
|
||||
other.get_or_create_executor_us
|
||||
);
|
||||
saturating_add_assign!(self.changed_account_count, other.changed_account_count);
|
||||
saturating_add_assign!(self.total_account_count, other.total_account_count);
|
||||
saturating_add_assign!(self.total_data_size, other.total_data_size);
|
||||
saturating_add_assign!(self.data_size_changed, other.data_size_changed);
|
||||
saturating_add_assign!(
|
||||
self.create_executor_register_syscalls_us,
|
||||
other.create_executor_register_syscalls_us
|
||||
);
|
||||
saturating_add_assign!(
|
||||
self.create_executor_load_elf_us,
|
||||
other.create_executor_load_elf_us
|
||||
);
|
||||
saturating_add_assign!(
|
||||
self.create_executor_verify_code_us,
|
||||
other.create_executor_verify_code_us
|
||||
);
|
||||
saturating_add_assign!(
|
||||
self.create_executor_jit_compile_us,
|
||||
other.create_executor_jit_compile_us
|
||||
);
|
||||
for (id, other) in &other.per_program_timings {
|
||||
let program_timing = self.per_program_timings.entry(*id).or_default();
|
||||
program_timing.accumulate_program_timings(other);
|
||||
|
Reference in New Issue
Block a user