diff --git a/programs/bpf/c/src/sanity/sanity.c b/programs/bpf/c/src/sanity/sanity.c index e77c4ce8ac..f531796ac8 100644 --- a/programs/bpf/c/src/sanity/sanity.c +++ b/programs/bpf/c/src/sanity/sanity.c @@ -18,5 +18,7 @@ extern uint64_t entrypoint(const uint8_t *input) { // program, no account keys or input data are expected but real // programs will have specific requirements so they can do their work. sol_log_params(¶ms); + + sol_log_compute_units(); return SUCCESS; } diff --git a/programs/bpf/rust/sanity/src/lib.rs b/programs/bpf/rust/sanity/src/lib.rs index 059a76d2e3..c4345d6306 100644 --- a/programs/bpf/rust/sanity/src/lib.rs +++ b/programs/bpf/rust/sanity/src/lib.rs @@ -61,6 +61,7 @@ fn process_instruction( panic!(); } + sol_log_compute_units(); Ok(()) } diff --git a/programs/bpf_loader/src/syscalls.rs b/programs/bpf_loader/src/syscalls.rs index c2b40a8106..81b7413e5d 100644 --- a/programs/bpf_loader/src/syscalls.rs +++ b/programs/bpf_loader/src/syscalls.rs @@ -15,6 +15,7 @@ use solana_sdk::{ entrypoint::{MAX_PERMITTED_DATA_INCREASE, SUCCESS}, feature_set::{ pubkey_log_syscall_enabled, ristretto_mul_syscall_enabled, sha256_syscall_enabled, + sol_log_compute_units_syscall, }, hash::{Hasher, HASH_BYTES}, instruction::{AccountMeta, Instruction, InstructionError}, @@ -120,6 +121,16 @@ pub fn register_syscalls<'a>( })), )?; + if invoke_context.is_feature_active(&sol_log_compute_units_syscall::id()) { + vm.register_syscall( + hash_symbol_name(b"sol_log_compute_units_"), + Syscall::Object(Box::new(SyscallLogBpfComputeUnits { + cost: 0, + compute_meter: invoke_context.get_compute_meter(), + logger: invoke_context.get_logger(), + })), + )?; + } if invoke_context.is_feature_active(&pubkey_log_syscall_enabled::id()) { vm.register_syscall( hash_symbol_name(b"sol_log_pubkey"), @@ -410,6 +421,37 @@ impl SyscallObject for SyscallLogU64 { } } +/// Log current compute consumption +pub struct SyscallLogBpfComputeUnits { + cost: u64, + compute_meter: Rc>, + logger: Rc>, +} +impl SyscallObject for SyscallLogBpfComputeUnits { + fn call( + &mut self, + _arg1: u64, + _arg2: u64, + _arg3: u64, + _arg4: u64, + _arg5: u64, + _memory_mapping: &MemoryMapping, + ) -> Result> { + self.compute_meter.consume(self.cost)?; + let mut logger = self + .logger + .try_borrow_mut() + .map_err(|_| SyscallError::InvokeContextBorrowFailed)?; + if logger.log_enabled() { + logger.log(&format!( + "Program consumption: {} units remaining", + self.compute_meter.borrow().get_remaining() + )); + } + Ok(0) + } +} + /// Log 5 64-bit values pub struct SyscallLogPubkey<'a> { cost: u64, diff --git a/sdk/bpf/c/inc/solana_sdk.h b/sdk/bpf/c/inc/solana_sdk.h index 0415c2505b..ff7c75f437 100644 --- a/sdk/bpf/c/inc/solana_sdk.h +++ b/sdk/bpf/c/inc/solana_sdk.h @@ -133,6 +133,12 @@ void sol_log_(const char *, uint64_t); void sol_log_64_(uint64_t, uint64_t, uint64_t, uint64_t, uint64_t); #define sol_log_64 sol_log_64_ +/** + * Prints the current compute unit consumption to stdout + */ +void sol_log_compute_units_(); +#define sol_log_compute_units() sol_log_compute_units_() + /** * Size of Public key in bytes */ diff --git a/sdk/program/src/log.rs b/sdk/program/src/log.rs index a94db5179a..132a102c0e 100644 --- a/sdk/program/src/log.rs +++ b/sdk/program/src/log.rs @@ -96,3 +96,19 @@ pub fn sol_log_params(accounts: &[AccountInfo], data: &[u8]) { info!("Instruction data"); sol_log_slice(data); } + +/// Logs the current compute unit consumption +#[inline] +pub fn sol_log_compute_units() { + #[cfg(target_arch = "bpf")] + unsafe { + sol_log_compute_units_(); + } + #[cfg(not(target_arch = "bpf"))] + crate::program_stubs::sol_log_compute_units(); +} + +#[cfg(target_arch = "bpf")] +extern "C" { + fn sol_log_compute_units_(); +} diff --git a/sdk/program/src/program_stubs.rs b/sdk/program/src/program_stubs.rs index 2a858582cd..9e696adab4 100644 --- a/sdk/program/src/program_stubs.rs +++ b/sdk/program/src/program_stubs.rs @@ -19,6 +19,9 @@ pub trait SyscallStubs: Sync + Send { fn sol_log(&self, message: &str) { println!("{}", message); } + fn sol_log_compute_units(&self) { + sol_log("SyscallStubs: sol_log_compute_units() not available"); + } fn sol_invoke_signed( &self, _instruction: &Instruction, @@ -41,6 +44,10 @@ pub(crate) fn sol_log_64(arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) sol_log(&format!("{} {} {} {} {}", arg1, arg2, arg3, arg4, arg5)); } +pub(crate) fn sol_log_compute_units() { + SYSCALL_STUBS.read().unwrap().sol_log_compute_units(); +} + pub(crate) fn sol_invoke_signed( instruction: &Instruction, account_infos: &[AccountInfo], diff --git a/sdk/src/feature_set.rs b/sdk/src/feature_set.rs index d2351d30a7..1fa6a7ce8a 100644 --- a/sdk/src/feature_set.rs +++ b/sdk/src/feature_set.rs @@ -66,6 +66,10 @@ pub mod cumulative_rent_related_fixes { solana_sdk::declare_id!("FtjnuAtJTWwX3Kx9m24LduNEhzaGuuPfDW6e14SX2Fy5"); } +pub mod sol_log_compute_units_syscall { + solana_sdk::declare_id!("BHuZqHAj7JdZc68wVgZZcy51jZykvgrx4zptR44RyChe"); +} + pub mod pubkey_log_syscall_enabled { solana_sdk::declare_id!("MoqiU1vryuCGQSxFKA1SZ316JdLEFFhoAu6cKUNk7dN"); } @@ -96,6 +100,7 @@ lazy_static! { (max_program_call_depth_64::id(), "max program call depth 64"), (timestamp_correction::id(), "correct bank timestamps"), (cumulative_rent_related_fixes::id(), "rent fixes (#10206, #10468, #11342)"), + (sol_log_compute_units_syscall::id(), "sol_log_compute_units syscall (#13243)"), (pubkey_log_syscall_enabled::id(), "pubkey log syscall"), (pull_request_ping_pong_check::id(), "ping-pong packet check #12794"), (bpf_just_in_time_compilation::id(), "bpf just-in-time compilation #12951"),