Release v3.5.0: performance, constants, bilingual docs
- Bump version to 3.5.0 - Performance: hot-path timing only when log_enabled/simulate; execute_parallel takes &[Arc<SwqosClient>]; shared HTTP client constants for SWQoS - Code quality: validate_protocol_params extracted for buy/sell; BYTES_PER_ACCOUNT, MAX_INSTRUCTIONS_WARN, HTTP timeout constants; prefetch/syscall bypass comments - Documentation: bilingual (EN + 中文) doc comments in execution, executor, perf, swqos; README/README_CN version and What's new in 3.5.0 - Add release_notes_v3.5.0.md Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
//! 执行模块
|
||||
//! Execution: instruction preprocessing, cache prefetch, branch hints.
|
||||
//! 执行模块:指令预处理、缓存预取、分支提示。
|
||||
|
||||
use anyhow::Result;
|
||||
use solana_sdk::{
|
||||
@@ -12,7 +13,15 @@ use crate::perf::{
|
||||
simd::SIMDMemory,
|
||||
};
|
||||
|
||||
/// 预取工具
|
||||
/// Solana account key size in bytes (Pubkey). 每个账户(Pubkey)的字节数。
|
||||
pub const BYTES_PER_ACCOUNT: usize = 32;
|
||||
|
||||
/// Threshold above which we warn about large instruction count. 超过此次数会打 warning。
|
||||
pub const MAX_INSTRUCTIONS_WARN: usize = 64;
|
||||
|
||||
/// Prefetch helper: triggers CPU prefetch for soon-to-be-accessed data to reduce cache-miss latency.
|
||||
/// Call once on hot-path refs; no-op on non-x86_64. Safety: caller ensures valid read-only ref, no concurrent write.
|
||||
/// 缓存预取:对即将访问的数据做 CPU 预取以降低 cache-miss;热路径上调用一次即可;非 x86_64 为 no-op。安全:调用方保证有效只读、无并发写。
|
||||
pub struct Prefetch;
|
||||
|
||||
impl Prefetch {
|
||||
@@ -21,20 +30,15 @@ impl Prefetch {
|
||||
if instructions.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
||||
// 预取第一条指令
|
||||
// Prefetch first/middle/last instruction into L1 for subsequent build_transaction access. 预取首/中/尾指令到 L1。
|
||||
unsafe {
|
||||
BranchOptimizer::prefetch_read_data(&instructions[0]);
|
||||
}
|
||||
|
||||
// 预取中间指令
|
||||
if instructions.len() > 2 {
|
||||
unsafe {
|
||||
BranchOptimizer::prefetch_read_data(&instructions[instructions.len() / 2]);
|
||||
}
|
||||
}
|
||||
|
||||
// 预取最后一条指令
|
||||
if instructions.len() > 1 {
|
||||
unsafe {
|
||||
BranchOptimizer::prefetch_read_data(&instructions[instructions.len() - 1]);
|
||||
@@ -57,46 +61,40 @@ impl Prefetch {
|
||||
}
|
||||
}
|
||||
|
||||
/// 内存操作
|
||||
/// Memory operations (SIMD-accelerated where available). 内存操作(可用时走 SIMD 加速)。
|
||||
pub struct MemoryOps;
|
||||
|
||||
impl MemoryOps {
|
||||
#[inline(always)]
|
||||
pub unsafe fn copy(dst: *mut u8, src: *const u8, len: usize) {
|
||||
// 优先使用 AVX2 SIMD 加速
|
||||
SIMDMemory::copy_avx2(dst, src, len);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn compare(a: *const u8, b: *const u8, len: usize) -> bool {
|
||||
// 优先使用 AVX2 SIMD 比较
|
||||
SIMDMemory::compare_avx2(a, b, len)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub unsafe fn zero(ptr: *mut u8, len: usize) {
|
||||
// 优先使用 AVX2 SIMD 清零
|
||||
SIMDMemory::zero_avx2(ptr, len);
|
||||
}
|
||||
}
|
||||
|
||||
/// 指令处理器
|
||||
/// Instruction preprocessing and validation. 指令预处理与校验。
|
||||
pub struct InstructionProcessor;
|
||||
|
||||
impl InstructionProcessor {
|
||||
#[inline(always)]
|
||||
pub fn preprocess(instructions: &[Instruction]) -> Result<()> {
|
||||
// 分支预测: 大概率指令不为空
|
||||
if BranchOptimizer::unlikely(instructions.is_empty()) {
|
||||
return Err(anyhow::anyhow!("Instructions empty"));
|
||||
}
|
||||
|
||||
// 预取所有指令到缓存
|
||||
Prefetch::instructions(instructions);
|
||||
|
||||
// 分支预测: 大概率指令数量合理
|
||||
if BranchOptimizer::unlikely(instructions.len() > 64) {
|
||||
log::warn!("Large instruction count: {}", instructions.len());
|
||||
if BranchOptimizer::unlikely(instructions.len() > MAX_INSTRUCTIONS_WARN) {
|
||||
tracing::warn!(target: "sol_trade_sdk", "Large instruction count: {}", instructions.len());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -107,7 +105,7 @@ impl InstructionProcessor {
|
||||
let mut total_size = 0;
|
||||
|
||||
for (i, instr) in instructions.iter().enumerate() {
|
||||
// 预取下一条指令
|
||||
// Prefetch next instruction; safe: same slice, read-only. 预取下一条指令;安全:同 slice、只读。
|
||||
unsafe {
|
||||
if let Some(next_instr) = instructions.get(i + 1) {
|
||||
BranchOptimizer::prefetch_read_data(next_instr);
|
||||
@@ -115,20 +113,19 @@ impl InstructionProcessor {
|
||||
}
|
||||
|
||||
total_size += instr.data.len();
|
||||
total_size += instr.accounts.len() * 32; // 每个账户 32 字节
|
||||
total_size += instr.accounts.len() * BYTES_PER_ACCOUNT;
|
||||
}
|
||||
|
||||
total_size
|
||||
}
|
||||
}
|
||||
|
||||
/// 执行路径
|
||||
/// Trade direction / execution path helpers. 交易方向与执行路径辅助。
|
||||
pub struct ExecutionPath;
|
||||
|
||||
impl ExecutionPath {
|
||||
#[inline(always)]
|
||||
pub fn is_buy(input_mint: &Pubkey) -> bool {
|
||||
// 分支预测: 大概率是买入
|
||||
let is_buy = input_mint == &crate::constants::SOL_TOKEN_ACCOUNT
|
||||
|| input_mint == &crate::constants::WSOL_TOKEN_ACCOUNT
|
||||
|| input_mint == &crate::constants::USD1_TOKEN_ACCOUNT
|
||||
|
||||
Reference in New Issue
Block a user