performance optimization

This commit is contained in:
Wood
2025-10-07 00:08:41 +08:00
parent f9492b2c3a
commit ffc71cc1d8
7 changed files with 287 additions and 8 deletions
+198
View File
@@ -0,0 +1,198 @@
//! 🚀 快速计时模块 - 减少 Instant::now() 系统调用开销
//!
//! 使用 syscall_bypass 提供的快速时间戳避免频繁的系统调用
use std::time::{Duration, Instant};
use once_cell::sync::Lazy;
use crate::perf::syscall_bypass::SystemCallBypassManager;
/// 全局快速时间提供器
static FAST_TIMER: Lazy<FastTimer> = Lazy::new(|| FastTimer::new());
/// 快速计时器 - 减少系统调用开销
pub struct FastTimer {
bypass_manager: SystemCallBypassManager,
_base_instant: Instant,
_base_nanos: u64,
}
impl FastTimer {
fn new() -> Self {
use crate::perf::syscall_bypass::SyscallBypassConfig;
let bypass_manager = SystemCallBypassManager::new(SyscallBypassConfig::default())
.expect("Failed to create SystemCallBypassManager");
let base_instant = Instant::now();
let base_nanos = bypass_manager.fast_timestamp_nanos();
Self {
bypass_manager,
_base_instant: base_instant,
_base_nanos: base_nanos,
}
}
/// 🚀 获取当前时间戳(纳秒) - 使用快速系统调用绕过
#[inline(always)]
pub fn now_nanos(&self) -> u64 {
self.bypass_manager.fast_timestamp_nanos()
}
/// 🚀 获取当前时间戳(微秒)
#[inline(always)]
pub fn now_micros(&self) -> u64 {
self.now_nanos() / 1_000
}
/// 🚀 获取当前时间戳(毫秒)
#[inline(always)]
pub fn now_millis(&self) -> u64 {
self.now_nanos() / 1_000_000
}
/// 🚀 计算从开始到现在的耗时(纳秒)
#[inline(always)]
pub fn elapsed_nanos(&self, start_nanos: u64) -> u64 {
self.now_nanos().saturating_sub(start_nanos)
}
/// 🚀 计算从开始到现在的耗时(Duration)
#[inline(always)]
pub fn elapsed_duration(&self, start_nanos: u64) -> Duration {
Duration::from_nanos(self.elapsed_nanos(start_nanos))
}
}
/// 🚀 快速获取当前时间戳(纳秒)- 全局函数
///
/// 使用 syscall_bypass 避免频繁的 clock_gettime 系统调用
#[inline(always)]
pub fn fast_now_nanos() -> u64 {
FAST_TIMER.now_nanos()
}
/// 🚀 快速获取当前时间戳(微秒)
#[inline(always)]
pub fn fast_now_micros() -> u64 {
FAST_TIMER.now_micros()
}
/// 🚀 快速获取当前时间戳(毫秒)
#[inline(always)]
pub fn fast_now_millis() -> u64 {
FAST_TIMER.now_millis()
}
/// 🚀 计算耗时(纳秒)
#[inline(always)]
pub fn fast_elapsed_nanos(start_nanos: u64) -> u64 {
FAST_TIMER.elapsed_nanos(start_nanos)
}
/// 🚀 计算耗时(Duration
#[inline(always)]
pub fn fast_elapsed(start_nanos: u64) -> Duration {
FAST_TIMER.elapsed_duration(start_nanos)
}
/// 快速计时器句柄 - 用于测量代码块耗时
pub struct FastStopwatch {
start_nanos: u64,
#[allow(dead_code)]
label: &'static str,
}
impl FastStopwatch {
/// 创建并启动计时器
#[inline(always)]
pub fn start(label: &'static str) -> Self {
Self {
start_nanos: fast_now_nanos(),
label,
}
}
/// 获取已耗时(纳秒)
#[inline(always)]
pub fn elapsed_nanos(&self) -> u64 {
fast_elapsed_nanos(self.start_nanos)
}
/// 获取已耗时(Duration
#[inline(always)]
pub fn elapsed(&self) -> Duration {
fast_elapsed(self.start_nanos)
}
/// 获取已耗时(微秒)
#[inline(always)]
pub fn elapsed_micros(&self) -> u64 {
self.elapsed_nanos() / 1_000
}
/// 获取已耗时(毫秒)
#[inline(always)]
pub fn elapsed_millis(&self) -> u64 {
self.elapsed_nanos() / 1_000_000
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_fast_timing() {
let start = fast_now_nanos();
std::thread::sleep(Duration::from_millis(10));
let elapsed = fast_elapsed_nanos(start);
// 应该大约是 10ms = 10,000,000 纳秒
assert!(elapsed >= 9_000_000 && elapsed <= 12_000_000);
}
#[test]
fn test_stopwatch() {
let sw = FastStopwatch::start("test");
std::thread::sleep(Duration::from_millis(10));
let elapsed_ms = sw.elapsed_millis();
assert!(elapsed_ms >= 9 && elapsed_ms <= 12);
}
#[test]
fn test_fast_now_overhead() {
// 测试调用开销
let iterations = 10_000;
let start = Instant::now();
for _ in 0..iterations {
let _ = fast_now_nanos();
}
let total_elapsed = start.elapsed();
let avg_per_call = total_elapsed.as_nanos() / iterations;
println!("Average fast_now_nanos() call: {}ns", avg_per_call);
// 快速时间戳应该非常快(< 100ns per call
assert!(avg_per_call < 100);
}
#[test]
fn test_instant_now_overhead() {
// 对比标准 Instant::now() 的开销
let iterations = 10_000;
let start = Instant::now();
for _ in 0..iterations {
let _ = Instant::now();
}
let total_elapsed = start.elapsed();
let avg_per_call = total_elapsed.as_nanos() / iterations;
println!("Average Instant::now() call: {}ns", avg_per_call);
}
}
+1
View File
@@ -1,6 +1,7 @@
pub mod address_lookup_cache;
pub mod bonding_curve;
pub mod fast_fn;
pub mod fast_timing;
pub mod gas_fee_strategy;
pub mod global;
pub mod nonce_cache;
+2
View File
@@ -88,7 +88,9 @@ async fn parallel_execute(
{
return Err(anyhow!("No Rpc Default Swqos configured."));
}
// 🚀 获取 CPU 核心并优化亲和性分配
let cores = core_affinity::get_core_ids().unwrap();
let _num_cores = cores.len();
let mut handles: Vec<JoinHandle<Result<(bool, Signature, Option<anyhow::Error>)>>> =
Vec::with_capacity(swqos_clients.len());
+69 -2
View File
@@ -39,6 +39,30 @@ impl PreallocatedTxBuilder {
}
/// 🚀 零分配构建交易
///
/// # 交易版本自动选择
///
/// - **有地址查找表** (`lookup_table = Some`): 使用 `VersionedMessage::V0`
/// - 支持地址查找表压缩
/// - 减少交易大小
/// - 需要 RPC 支持 V0
///
/// - **无地址查找表** (`lookup_table = None`): 使用 `VersionedMessage::Legacy`
/// - 兼容所有 RPC 节点
/// - 无需地址查找表支持
/// - 适用于简单交易
///
/// # 示例
///
/// ```rust,ignore
/// // 无查找表 -> Legacy 消息
/// let msg = builder.build_zero_alloc(&payer, &ixs, None, blockhash);
/// assert!(matches!(msg, VersionedMessage::Legacy(_)));
///
/// // 有查找表 -> V0 消息
/// let msg = builder.build_zero_alloc(&payer, &ixs, Some(table_key), blockhash);
/// assert!(matches!(msg, VersionedMessage::V0(_)));
/// ```
#[inline(always)]
pub fn build_zero_alloc(
&mut self,
@@ -51,7 +75,7 @@ impl PreallocatedTxBuilder {
self.reset();
self.instructions.extend_from_slice(instructions);
// 如果有查找表,使用 V0 消息
// 如果有查找表,使用 V0 消息
if let Some(table_key) = lookup_table {
self.lookup_tables.push(v0::MessageAddressTableLookup {
account_key: table_key,
@@ -73,7 +97,7 @@ impl PreallocatedTxBuilder {
VersionedMessage::V0(message)
} else {
// 没有查找表,使用 legacy 消息
// 没有查找表,使用 Legacy 消息(兼容所有 RPC
let message = Message::new_with_blockhash(
&self.instructions,
Some(payer),
@@ -170,4 +194,47 @@ mod tests {
let final_count = get_pool_stats().0;
assert_eq!(final_count, initial_count);
}
#[test]
fn test_message_version_selection() {
use solana_sdk::signature::Keypair;
use solana_sdk::system_instruction;
let payer = Keypair::new();
let recipient = Keypair::new();
let blockhash = Hash::default();
let instructions = vec![
system_instruction::transfer(&payer.pubkey(), &recipient.pubkey(), 1000)
];
let mut builder = PreallocatedTxBuilder::new();
// 测试1: 无查找表 -> 应该返回 Legacy 消息
let msg_no_lookup = builder.build_zero_alloc(
&payer.pubkey(),
&instructions,
None, // ← 无查找表
blockhash,
);
assert!(
matches!(msg_no_lookup, VersionedMessage::Legacy(_)),
"Without lookup table, should use Legacy message"
);
// 测试2: 有查找表 -> 应该返回 V0 消息
let lookup_table_key = Pubkey::new_unique();
let msg_with_lookup = builder.build_zero_alloc(
&payer.pubkey(),
&instructions,
Some(lookup_table_key), // ← 有查找表
blockhash,
);
assert!(
matches!(msg_with_lookup, VersionedMessage::V0(_)),
"With lookup table, should use V0 message"
);
}
}
+10 -6
View File
@@ -9,7 +9,8 @@
/// * fee_basis_points = 10 -> 0.1% fee
/// * fee_basis_points = 25 -> 0.25% fee (common exchange rate)
/// * fee_basis_points = 100 -> 1% fee
pub fn compute_fee(amount: u128, fee_basis_points: u128) -> u128 {
#[inline(always)]
pub const fn compute_fee(amount: u128, fee_basis_points: u128) -> u128 {
ceil_div(amount * fee_basis_points, 10_000)
}
@@ -22,7 +23,8 @@ pub fn compute_fee(amount: u128, fee_basis_points: u128) -> u128 {
///
/// # Returns
/// Returns the ceiling result of a/b
pub fn ceil_div(a: u128, b: u128) -> u128 {
#[inline(always)]
pub const fn ceil_div(a: u128, b: u128) -> u128 {
(a + b - 1) / b
}
@@ -35,10 +37,11 @@ pub fn ceil_div(a: u128, b: u128) -> u128 {
///
/// # Examples
/// * basis_points = 1 -> 0.01% slippage
/// * basis_points = 10 -> 0.1% slippage
/// * basis_points = 10 -> 0.1% slippage
/// * basis_points = 100 -> 1% slippage
/// * basis_points = 500 -> 5% slippage
pub fn calculate_with_slippage_buy(amount: u64, basis_points: u64) -> u64 {
#[inline(always)]
pub const fn calculate_with_slippage_buy(amount: u64, basis_points: u64) -> u64 {
amount + (amount * basis_points / 10000)
}
@@ -51,10 +54,11 @@ pub fn calculate_with_slippage_buy(amount: u64, basis_points: u64) -> u64 {
///
/// # Examples
/// * basis_points = 1 -> 0.01% slippage
/// * basis_points = 10 -> 0.1% slippage
/// * basis_points = 10 -> 0.1% slippage
/// * basis_points = 100 -> 1% slippage
/// * basis_points = 500 -> 5% slippage
pub fn calculate_with_slippage_sell(amount: u64, basis_points: u64) -> u64 {
#[inline(always)]
pub const fn calculate_with_slippage_sell(amount: u64, basis_points: u64) -> u64 {
if amount <= basis_points / 10000 {
1
} else {
+2
View File
@@ -17,6 +17,7 @@ use crate::{
///
/// # Returns
/// The amount of tokens that will be received (in token's smallest unit)
#[inline]
pub fn get_buy_token_amount_from_sol_amount(
virtual_token_reserves: u128,
virtual_sol_reserves: u128,
@@ -74,6 +75,7 @@ pub fn get_buy_token_amount_from_sol_amount(
///
/// # Returns
/// The amount of SOL that will be received after fees (in lamports)
#[inline]
pub fn get_sell_sol_amount_from_token_amount(
virtual_token_reserves: u128,
virtual_sol_reserves: u128,
+5
View File
@@ -10,6 +10,7 @@ use crate::instruction::utils::raydium_cpmm::accounts::{
///
/// # Returns
/// The calculated trading fee
#[inline(always)]
fn compute_trading_fee(amount: u64, fee_rate: u64) -> u64 {
let numerator = (amount as u128) * (fee_rate as u128);
((numerator + FEE_RATE_DENOMINATOR_VALUE - 1) / FEE_RATE_DENOMINATOR_VALUE) as u64
@@ -23,6 +24,7 @@ fn compute_trading_fee(amount: u64, fee_rate: u64) -> u64 {
///
/// # Returns
/// The calculated protocol or fund fee
#[inline(always)]
fn compute_protocol_fund_fee(amount: u64, fee_rate: u64) -> u64 {
let numerator = (amount as u128) * (fee_rate as u128);
(numerator / FEE_RATE_DENOMINATOR_VALUE) as u64
@@ -36,6 +38,7 @@ fn compute_protocol_fund_fee(amount: u64, fee_rate: u64) -> u64 {
///
/// # Returns
/// The calculated creator fee
#[inline(always)]
fn compute_creator_fee_new(amount: u64, fee_rate: u64) -> u64 {
let numerator = (amount as u128) * (fee_rate as u128);
((numerator + FEE_RATE_DENOMINATOR_VALUE - 1) / FEE_RATE_DENOMINATOR_VALUE) as u64
@@ -93,6 +96,7 @@ pub struct SwapResult {
///
/// # Returns
/// A `SwapResult` containing all swap calculations and fees
#[inline]
fn swap_base_input(
input_amount: u64,
input_vault_amount: u64,
@@ -155,6 +159,7 @@ fn swap_base_input(
///
/// # Returns
/// A `ComputeSwapParams` struct containing all computed swap parameters
#[inline]
pub fn compute_swap_amount(
base_reserve: u64,
quote_reserve: u64,