Skip to main content

sol_trade_sdk/trading/core/
execution.rs

1//! Execution: instruction preprocessing, cache prefetch, branch hints.
2//! 执行模块:指令预处理、缓存预取、分支提示。
3
4use anyhow::Result;
5use solana_sdk::{instruction::Instruction, pubkey::Pubkey, signature::Keypair};
6
7use crate::perf::{hardware_optimizations::BranchOptimizer, simd::SIMDMemory};
8
9/// Solana account key size in bytes (Pubkey). 每个账户(Pubkey)的字节数。
10pub const BYTES_PER_ACCOUNT: usize = 32;
11
12/// Threshold above which we warn about large instruction count. 超过此次数会打 warning。
13pub const MAX_INSTRUCTIONS_WARN: usize = 64;
14
15/// Prefetch helper: triggers CPU prefetch for soon-to-be-accessed data to reduce cache-miss latency.
16/// Call once on hot-path refs; no-op on non-x86_64. Safety: caller ensures valid read-only ref, no concurrent write.
17/// 缓存预取:对即将访问的数据做 CPU 预取以降低 cache-miss;热路径上调用一次即可;非 x86_64 为 no-op。安全:调用方保证有效只读、无并发写。
18pub struct Prefetch;
19
20impl Prefetch {
21    #[inline(always)]
22    pub fn instructions(instructions: &[Instruction]) {
23        if instructions.is_empty() {
24            return;
25        }
26        // Prefetch first/middle/last instruction into L1 for subsequent build_transaction access. 预取首/中/尾指令到 L1。
27        unsafe {
28            BranchOptimizer::prefetch_read_data(&instructions[0]);
29        }
30        if instructions.len() > 2 {
31            unsafe {
32                BranchOptimizer::prefetch_read_data(&instructions[instructions.len() / 2]);
33            }
34        }
35        if instructions.len() > 1 {
36            unsafe {
37                BranchOptimizer::prefetch_read_data(&instructions[instructions.len() - 1]);
38            }
39        }
40    }
41
42    #[inline(always)]
43    pub fn pubkey(pubkey: &Pubkey) {
44        unsafe {
45            BranchOptimizer::prefetch_read_data(pubkey);
46        }
47    }
48
49    #[inline(always)]
50    pub fn keypair(keypair: &Keypair) {
51        unsafe {
52            BranchOptimizer::prefetch_read_data(keypair);
53        }
54    }
55}
56
57/// Memory operations (SIMD-accelerated where available). 内存操作(可用时走 SIMD 加速)。
58pub struct MemoryOps;
59
60impl MemoryOps {
61    #[inline(always)]
62    pub unsafe fn copy(dst: *mut u8, src: *const u8, len: usize) {
63        SIMDMemory::copy_avx2(dst, src, len);
64    }
65
66    #[inline(always)]
67    pub unsafe fn compare(a: *const u8, b: *const u8, len: usize) -> bool {
68        SIMDMemory::compare_avx2(a, b, len)
69    }
70
71    #[inline(always)]
72    pub unsafe fn zero(ptr: *mut u8, len: usize) {
73        SIMDMemory::zero_avx2(ptr, len);
74    }
75}
76
77/// Instruction preprocessing and validation. 指令预处理与校验。
78pub struct InstructionProcessor;
79
80impl InstructionProcessor {
81    #[inline(always)]
82    pub fn preprocess(instructions: &[Instruction]) -> Result<()> {
83        if BranchOptimizer::unlikely(instructions.is_empty()) {
84            return Err(anyhow::anyhow!("Instructions empty"));
85        }
86
87        Prefetch::instructions(instructions);
88
89        if BranchOptimizer::unlikely(instructions.len() > MAX_INSTRUCTIONS_WARN) {
90            tracing::warn!(target: "sol_trade_sdk", "Large instruction count: {}", instructions.len());
91        }
92
93        Ok(())
94    }
95
96    #[inline(always)]
97    pub fn calculate_size(instructions: &[Instruction]) -> usize {
98        let mut total_size = 0;
99
100        for (i, instr) in instructions.iter().enumerate() {
101            // Prefetch next instruction; safe: same slice, read-only. 预取下一条指令;安全:同 slice、只读。
102            unsafe {
103                if let Some(next_instr) = instructions.get(i + 1) {
104                    BranchOptimizer::prefetch_read_data(next_instr);
105                }
106            }
107
108            total_size += instr.data.len();
109            total_size += instr.accounts.len() * BYTES_PER_ACCOUNT;
110        }
111
112        total_size
113    }
114}
115
116/// Trade direction / execution path helpers. 交易方向与执行路径辅助。
117pub struct ExecutionPath;
118
119impl ExecutionPath {
120    #[inline(always)]
121    pub fn is_buy(input_mint: &Pubkey) -> bool {
122        let is_buy = input_mint == &crate::constants::SOL_TOKEN_ACCOUNT
123            || input_mint == &crate::constants::WSOL_TOKEN_ACCOUNT
124            || input_mint == &crate::constants::USD1_TOKEN_ACCOUNT
125            || input_mint == &crate::constants::USDC_TOKEN_ACCOUNT;
126
127        if BranchOptimizer::likely(is_buy) {
128            return true;
129        }
130
131        false
132    }
133
134    #[inline(always)]
135    pub fn select<T>(
136        condition: bool,
137        fast_path: impl FnOnce() -> T,
138        slow_path: impl FnOnce() -> T,
139    ) -> T {
140        if BranchOptimizer::likely(condition) {
141            fast_path()
142        } else {
143            slow_path()
144        }
145    }
146}