use std::{
sync::{
Arc,
atomic::{AtomicU64, Ordering},
},
time::Instant,
};
use solana_address::Address;
use solana_transaction::InstructionError;
use crate::programs::jit_policy::JitPolicy;
pub(crate) fn load_program_uncompiled(
loader_key: &Address,
env: &solana_program_runtime::loaded_programs::ProgramRuntimeEnvironment,
elf_bytes: &[u8],
) -> Result<solana_program_runtime::program_cache_entry::ProgramCacheEntry, InstructionError> {
use solana_program_runtime::{
program_cache_entry::{ProgramCacheEntry, ProgramCacheEntryOwner, ProgramCacheEntryType},
solana_sbpf::{elf::Executable, verifier::RequisiteVerifier},
};
use crate::accounts_db::IMMEDIATE_DEPLOYMENT_SLOT;
let loader: Arc<
solana_program_runtime::solana_sbpf::program::BuiltinProgram<
solana_program_runtime::invoke_context::InvokeContext<'static, 'static>,
>,
> = Arc::clone(env);
let executable =
Executable::load(elf_bytes, loader).map_err(|_| InstructionError::InvalidAccountData)?;
executable.verify::<RequisiteVerifier>().map_err(|_| InstructionError::InvalidAccountData)?;
let owner = ProgramCacheEntryOwner::try_from(loader_key)
.map_err(|()| InstructionError::IncorrectProgramId)?;
Ok(ProgramCacheEntry {
program: ProgramCacheEntryType::Loaded(executable),
account_owner: owner,
deployment_slot: IMMEDIATE_DEPLOYMENT_SLOT,
stats: Arc::new(solana_program_runtime::program_metrics::ProgramStatistics::default()),
latest_access_slot: std::sync::atomic::AtomicU64::new(0),
})
}
#[must_use]
pub(crate) fn has_compiled_program(
entry: &solana_program_runtime::program_cache_entry::ProgramCacheEntry,
) -> bool {
#[cfg(all(not(target_os = "windows"), target_arch = "x86_64"))]
{
use solana_program_runtime::program_cache_entry::ProgramCacheEntryType;
match &entry.program {
ProgramCacheEntryType::Loaded(executable) => {
executable.get_compiled_program().is_some()
}
_ => false,
}
}
#[cfg(not(all(not(target_os = "windows"), target_arch = "x86_64")))]
{
let _ = entry;
false
}
}
#[derive(Debug, Default)]
pub(crate) struct PromotionStats {
pub(crate) attempted: AtomicU64,
pub(crate) succeeded: AtomicU64,
pub(crate) failed: AtomicU64,
pub(crate) compile_us: AtomicU64,
pub(crate) dropped: AtomicU64,
}
impl PromotionStats {
pub(crate) fn snapshot(&self) -> PromotionStatsSnapshot {
let ord = Ordering::Relaxed;
PromotionStatsSnapshot {
attempted: self.attempted.load(ord),
succeeded: self.succeeded.load(ord),
failed: self.failed.load(ord),
compile_us: self.compile_us.load(ord),
dropped: self.dropped.load(ord),
}
}
}
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub(crate) struct PromotionStatsSnapshot {
pub(crate) attempted: u64,
pub(crate) succeeded: u64,
pub(crate) failed: u64,
pub(crate) compile_us: u64,
pub(crate) dropped: u64,
}
pub(crate) struct TierPromoter {
enabled: bool,
threshold: usize,
pool: Option<rayon::ThreadPool>,
pending: Arc<AtomicU64>,
max_pending: u64,
stats: Arc<PromotionStats>,
#[cfg(test)]
inject_failure: Arc<AtomicU64>,
}
impl std::fmt::Debug for TierPromoter {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("TierPromoter")
.field("enabled", &self.enabled)
.field("threshold", &self.threshold)
.field("stats", &self.stats.snapshot())
.finish_non_exhaustive()
}
}
impl TierPromoter {
pub(crate) fn new(policy: JitPolicy) -> Self {
let effective = policy.effective();
let (enabled, threshold) = match effective {
JitPolicy::Lazy { hot_threshold } => (true, hot_threshold),
JitPolicy::Eager | JitPolicy::Off => (false, usize::MAX),
};
let enabled = enabled && cfg!(target_arch = "x86_64");
let pool = if enabled {
let cpus = std::thread::available_parallelism().map_or(4, |n| n.get());
let threads = cpus.div_ceil(2).clamp(1, 4);
rayon::ThreadPoolBuilder::new()
.num_threads(threads)
.thread_name(|i| format!("hpsvm-tier-promoter-{i}"))
.build()
.ok()
} else {
None
};
let enabled = enabled && pool.is_some();
Self {
enabled,
threshold,
pool,
pending: Arc::new(AtomicU64::new(0)),
max_pending: 64,
stats: Arc::new(PromotionStats::default()),
#[cfg(test)]
inject_failure: Arc::new(AtomicU64::new(0)),
}
}
pub(crate) fn disabled() -> Self {
Self {
enabled: false,
threshold: usize::MAX,
pool: None,
pending: Arc::new(AtomicU64::new(0)),
max_pending: 64,
stats: Arc::new(PromotionStats::default()),
#[cfg(test)]
inject_failure: Arc::new(AtomicU64::new(0)),
}
}
pub(crate) const fn is_enabled(&self) -> bool {
self.enabled
}
pub(crate) fn stats_handle(&self) -> Arc<PromotionStats> {
Arc::clone(&self.stats)
}
#[cfg(test)]
pub(crate) fn set_inject_failure(&self, fail: bool) {
self.inject_failure.store(u64::from(fail), Ordering::Relaxed);
}
#[cfg(test)]
fn injects_failure(&self) -> bool {
self.inject_failure.load(Ordering::Relaxed) != 0
}
pub(crate) fn observe(&self, accounts: &crate::accounts_db::Accounts) {
if !self.enabled {
return;
}
let entries = accounts.program_entries_snapshot();
if self.threshold == 0 {
for entry in entries {
if has_compiled_program(&entry) {
continue;
}
if !is_loaded(&entry) {
continue;
}
self.promote_blocking(entry);
}
return;
}
for entry in entries {
if has_compiled_program(&entry) {
continue;
}
if !is_loaded(&entry) {
continue;
}
let interpreted = entry.stats.interpreted_invocations.load(Ordering::Relaxed);
if interpreted < self.threshold as u64 {
continue;
}
self.promote(entry);
}
}
pub(crate) fn promote(
&self,
entry: Arc<solana_program_runtime::program_cache_entry::ProgramCacheEntry>,
) {
if !self.enabled {
return;
}
if has_compiled_program(&entry) {
return;
}
let pending = self.pending.fetch_add(1, Ordering::Relaxed);
if pending >= self.max_pending {
self.pending.fetch_sub(1, Ordering::Relaxed);
self.stats.dropped.fetch_add(1, Ordering::Relaxed);
return;
}
let stats = Arc::clone(&self.stats);
let pending = Arc::clone(&self.pending);
#[cfg(test)]
let inject = self.injects_failure();
#[cfg(not(test))]
let inject = false;
let Some(pool) = self.pool.as_ref() else {
self.pending.fetch_sub(1, Ordering::Relaxed);
return;
};
pool.spawn(move || {
let _guard = PendingGuard { pending };
stats.attempted.fetch_add(1, Ordering::Relaxed);
if inject {
stats.failed.fetch_add(1, Ordering::Relaxed);
return;
}
let start = Instant::now();
let outcome = compile_entry(&entry);
let elapsed = u64::try_from(start.elapsed().as_micros()).unwrap_or(u64::MAX);
stats.compile_us.fetch_add(elapsed, Ordering::Relaxed);
if outcome {
entry.stats.jit_compiled(elapsed);
stats.succeeded.fetch_add(1, Ordering::Relaxed);
} else {
stats.failed.fetch_add(1, Ordering::Relaxed);
}
});
}
pub(crate) fn promote_blocking(
&self,
entry: Arc<solana_program_runtime::program_cache_entry::ProgramCacheEntry>,
) {
if !self.enabled {
return;
}
if has_compiled_program(&entry) {
return;
}
self.stats.attempted.fetch_add(1, Ordering::Relaxed);
#[cfg(test)]
if self.injects_failure() {
self.stats.failed.fetch_add(1, Ordering::Relaxed);
return;
}
let start = Instant::now();
let outcome = compile_entry(&entry);
let elapsed = u64::try_from(start.elapsed().as_micros()).unwrap_or(u64::MAX);
self.stats.compile_us.fetch_add(elapsed, Ordering::Relaxed);
if outcome {
entry.stats.jit_compiled(elapsed);
self.stats.succeeded.fetch_add(1, Ordering::Relaxed);
} else {
self.stats.failed.fetch_add(1, Ordering::Relaxed);
}
}
}
fn is_loaded(entry: &solana_program_runtime::program_cache_entry::ProgramCacheEntry) -> bool {
use solana_program_runtime::program_cache_entry::ProgramCacheEntryType;
matches!(entry.program, ProgramCacheEntryType::Loaded(_))
}
fn compile_entry(entry: &solana_program_runtime::program_cache_entry::ProgramCacheEntry) -> bool {
#[cfg(all(not(target_os = "windows"), target_arch = "x86_64"))]
{
use solana_program_runtime::program_cache_entry::ProgramCacheEntryType;
match &entry.program {
ProgramCacheEntryType::Loaded(executable) => {
if executable.get_compiled_program().is_some() {
return true;
}
if executable.jit_compile().is_err() {
return false;
}
executable.get_compiled_program().is_some()
}
_ => false,
}
}
#[cfg(not(all(not(target_os = "windows"), target_arch = "x86_64")))]
{
let _ = entry;
false
}
}
struct PendingGuard {
pending: Arc<AtomicU64>,
}
impl Drop for PendingGuard {
fn drop(&mut self) {
self.pending.fetch_sub(1, Ordering::Relaxed);
}
}
#[cfg(test)]
mod tests {
use proptest::prelude::*;
use super::*;
#[test]
fn disabled_promoter_never_enables() {
let promoter = TierPromoter::disabled();
assert!(!promoter.is_enabled());
}
#[test]
fn eager_and_off_are_disabled() {
assert!(!TierPromoter::new(JitPolicy::Eager).is_enabled());
assert!(!TierPromoter::new(JitPolicy::Off).is_enabled());
}
#[test]
fn lazy_enabled_only_on_x86_64() {
let promoter = TierPromoter::new(JitPolicy::Lazy { hot_threshold: 8 });
assert_eq!(promoter.is_enabled(), cfg!(target_arch = "x86_64"));
}
#[test]
fn is_loaded_distinguishes_loaded_from_tombstones() {
use solana_program_runtime::program_cache_entry::{
ProgramCacheEntry, ProgramCacheEntryOwner, ProgramCacheEntryType,
};
let loaded = {
use solana_program_runtime::{
loaded_programs::ProgramRuntimeEnvironment, solana_sbpf::program::BuiltinProgram,
};
let env =
ProgramRuntimeEnvironment::from(BuiltinProgram::new_loader(Default::default()));
let elf = include_bytes!("../../elf/spl_memo-3.0.0.so");
let loader = solana_sdk_ids::bpf_loader::id();
load_program_uncompiled(&loader, &env, elf).expect("load should succeed")
};
assert!(is_loaded(&loaded));
let closed = ProgramCacheEntry {
program: ProgramCacheEntryType::Closed,
account_owner: ProgramCacheEntryOwner::LoaderV3,
deployment_slot: 0,
stats: std::sync::Arc::new(
solana_program_runtime::program_metrics::ProgramStatistics::default(),
),
latest_access_slot: std::sync::atomic::AtomicU64::new(0),
};
assert!(!is_loaded(&closed));
}
#[test]
fn pending_guard_releases_on_drop() {
let pending = std::sync::Arc::new(AtomicU64::new(1));
{
let _guard = PendingGuard { pending: std::sync::Arc::clone(&pending) };
assert_eq!(pending.load(Ordering::Relaxed), 1);
}
assert_eq!(pending.load(Ordering::Relaxed), 0);
}
proptest! {
#[test]
fn observe_is_idempotent_and_never_promotes_under_eager_or_off(
threshold in any::<usize>(),
) {
use crate::accounts_db::Accounts;
for policy in [
JitPolicy::Eager,
JitPolicy::Off,
JitPolicy::Lazy { hot_threshold: threshold },
] {
let promoter = TierPromoter::new(policy);
let accounts = Accounts::default();
let before = promoter.stats_handle().snapshot();
promoter.observe(&accounts);
promoter.observe(&accounts);
let after = promoter.stats_handle().snapshot();
if matches!(policy.effective(), JitPolicy::Eager | JitPolicy::Off) {
prop_assert!(!promoter.is_enabled());
prop_assert_eq!(before.attempted, after.attempted);
prop_assert_eq!(after.attempted, 0);
} else {
prop_assert_eq!(after.attempted, 0);
}
}
}
}
}