Skip to main content

blvm_consensus/
script_profile.rs

1//! Script sub-timing for IBD profiling (sighash, interpreter, multisig, P2PKH fast path).
2//! Used by block.rs to extend [PERF] with breakdown when profile feature is enabled.
3
4#![cfg(all(feature = "production", feature = "profile"))]
5
6use std::sync::atomic::{AtomicU64, Ordering};
7
8static SCRIPT_SIGHASH_NS: AtomicU64 = AtomicU64::new(0);
9static SCRIPT_INTERPRETER_NS: AtomicU64 = AtomicU64::new(0);
10static SCRIPT_MULTISIG_NS: AtomicU64 = AtomicU64::new(0);
11static SCRIPT_P2PKH_PARSE_NS: AtomicU64 = AtomicU64::new(0);
12static SCRIPT_P2PKH_HASH160_NS: AtomicU64 = AtomicU64::new(0);
13static SCRIPT_P2PKH_COLLECT_NS: AtomicU64 = AtomicU64::new(0);
14/// Time from collect() entry to before lock (fetch_add, shard_idx)
15static COLLECT_SLOT_NS: AtomicU64 = AtomicU64::new(0);
16/// Time waiting for EcdsaSoA shard lock (contention indicator)
17static COLLECT_SHARD_LOCK_NS: AtomicU64 = AtomicU64::new(0);
18/// Time copying into shard after lock acquired
19static COLLECT_COPY_NS: AtomicU64 = AtomicU64::new(0);
20/// Time in chunk_ready logic (fetch_add, ready_queue push) after lock released
21static COLLECT_CHUNK_NS: AtomicU64 = AtomicU64::new(0);
22/// Worker: build_p2pkh_hash_map (batch)
23static WORKER_P2PKH_MAP_NS: AtomicU64 = AtomicU64::new(0);
24/// Worker: refs extraction (batch)
25static WORKER_REFS_NS: AtomicU64 = AtomicU64::new(0);
26/// Worker: time to acquire tx_contexts, buffer, spi, pv read locks (contention indicator)
27static WORKER_REFS_LOCK_NS: AtomicU64 = AtomicU64::new(0);
28/// Worker: run_check_with_refs loop (per-check work, excludes refs + p2pkh_map)
29static WORKER_RUN_CHECK_LOOP_NS: AtomicU64 = AtomicU64::new(0);
30/// Worker: results.push() time (per batch; SegQueue, lock-free)
31static WORKER_RESULTS_EXTEND_NS: AtomicU64 = AtomicU64::new(0);
32/// Caller: entry to try_verify_p2pkh_fast_path (before parse)
33static P2PKH_FAST_PATH_ENTRY_NS: AtomicU64 = AtomicU64::new(0);
34/// Caller: BIP66 check (check_bip66)
35static P2PKH_BIP66_NS: AtomicU64 = AtomicU64::new(0);
36/// Caller: SECP256K1_CONTEXT.with closure (verify_signature body)
37static P2PKH_SECP_CONTEXT_NS: AtomicU64 = AtomicU64::new(0);
38/// Batch phase: SoA extraction (parse raw → compact, cache lookup)
39static BATCH_SOA_EXTRACT_NS: AtomicU64 = AtomicU64::new(0);
40/// Batch phase: secp256k1 batch verify
41static BATCH_SECP_VERIFY_NS: AtomicU64 = AtomicU64::new(0);
42/// Batch phase: sig cache writes after verify
43static BATCH_CACHE_WRITE_NS: AtomicU64 = AtomicU64::new(0);
44/// Drain threads: copy from shards under lock
45static DRAIN_SHARD_COPY_NS: AtomicU64 = AtomicU64::new(0);
46/// Drain threads: parse_raw_to_compact + cache lookup (outside lock)
47static DRAIN_PARSE_NS: AtomicU64 = AtomicU64::new(0);
48/// Drain threads: secp256k1 verify_batch_from_raw
49static DRAIN_SECP_NS: AtomicU64 = AtomicU64::new(0);
50/// ECDSA sig cache hits (per block)
51static ECDSA_CACHE_HITS: AtomicU64 = AtomicU64::new(0);
52/// ECDSA sig cache misses (per block)
53static ECDSA_CACHE_MISSES: AtomicU64 = AtomicU64::new(0);
54
55#[inline(always)]
56pub fn add_sighash_ns(ns: u64) {
57    SCRIPT_SIGHASH_NS.fetch_add(ns, Ordering::Relaxed);
58}
59
60#[inline(always)]
61pub fn add_interpreter_ns(ns: u64) {
62    SCRIPT_INTERPRETER_NS.fetch_add(ns, Ordering::Relaxed);
63}
64
65#[inline(always)]
66pub fn add_multisig_ns(ns: u64) {
67    SCRIPT_MULTISIG_NS.fetch_add(ns, Ordering::Relaxed);
68}
69
70#[inline(always)]
71pub fn add_p2pkh_parse_ns(ns: u64) {
72    SCRIPT_P2PKH_PARSE_NS.fetch_add(ns, Ordering::Relaxed);
73}
74
75#[inline(always)]
76pub fn add_p2pkh_hash160_ns(ns: u64) {
77    SCRIPT_P2PKH_HASH160_NS.fetch_add(ns, Ordering::Relaxed);
78}
79
80#[inline(always)]
81pub fn add_p2pkh_collect_ns(ns: u64) {
82    SCRIPT_P2PKH_COLLECT_NS.fetch_add(ns, Ordering::Relaxed);
83}
84
85#[inline(always)]
86pub fn add_collect_slot_ns(ns: u64) {
87    COLLECT_SLOT_NS.fetch_add(ns, Ordering::Relaxed);
88}
89
90#[inline(always)]
91pub fn add_collect_shard_lock_ns(ns: u64) {
92    COLLECT_SHARD_LOCK_NS.fetch_add(ns, Ordering::Relaxed);
93}
94
95#[inline(always)]
96pub fn add_collect_copy_ns(ns: u64) {
97    COLLECT_COPY_NS.fetch_add(ns, Ordering::Relaxed);
98}
99
100#[inline(always)]
101pub fn add_collect_chunk_ns(ns: u64) {
102    COLLECT_CHUNK_NS.fetch_add(ns, Ordering::Relaxed);
103}
104
105#[inline(always)]
106pub fn add_worker_p2pkh_map_ns(ns: u64) {
107    WORKER_P2PKH_MAP_NS.fetch_add(ns, Ordering::Relaxed);
108}
109
110#[inline(always)]
111pub fn add_worker_refs_ns(ns: u64) {
112    WORKER_REFS_NS.fetch_add(ns, Ordering::Relaxed);
113}
114
115#[inline(always)]
116pub fn add_worker_refs_lock_ns(ns: u64) {
117    WORKER_REFS_LOCK_NS.fetch_add(ns, Ordering::Relaxed);
118}
119
120#[inline(always)]
121pub fn add_worker_run_check_loop_ns(ns: u64) {
122    WORKER_RUN_CHECK_LOOP_NS.fetch_add(ns, Ordering::Relaxed);
123}
124
125#[inline(always)]
126pub fn add_worker_results_extend_ns(ns: u64) {
127    WORKER_RESULTS_EXTEND_NS.fetch_add(ns, Ordering::Relaxed);
128}
129
130#[inline(always)]
131pub fn add_p2pkh_fast_path_entry_ns(ns: u64) {
132    P2PKH_FAST_PATH_ENTRY_NS.fetch_add(ns, Ordering::Relaxed);
133}
134
135#[inline(always)]
136pub fn add_p2pkh_bip66_ns(ns: u64) {
137    P2PKH_BIP66_NS.fetch_add(ns, Ordering::Relaxed);
138}
139
140#[inline(always)]
141pub fn add_p2pkh_secp_context_ns(ns: u64) {
142    P2PKH_SECP_CONTEXT_NS.fetch_add(ns, Ordering::Relaxed);
143}
144
145#[inline(always)]
146pub fn add_batch_soa_extract_ns(ns: u64) {
147    BATCH_SOA_EXTRACT_NS.fetch_add(ns, Ordering::Relaxed);
148}
149
150#[inline(always)]
151pub fn add_batch_secp_verify_ns(ns: u64) {
152    BATCH_SECP_VERIFY_NS.fetch_add(ns, Ordering::Relaxed);
153}
154
155#[inline(always)]
156pub fn add_batch_cache_write_ns(ns: u64) {
157    BATCH_CACHE_WRITE_NS.fetch_add(ns, Ordering::Relaxed);
158}
159
160#[inline(always)]
161pub fn add_drain_shard_copy_ns(ns: u64) {
162    DRAIN_SHARD_COPY_NS.fetch_add(ns, Ordering::Relaxed);
163}
164
165#[inline(always)]
166pub fn add_drain_parse_ns(ns: u64) {
167    DRAIN_PARSE_NS.fetch_add(ns, Ordering::Relaxed);
168}
169
170#[inline(always)]
171pub fn add_drain_secp_ns(ns: u64) {
172    DRAIN_SECP_NS.fetch_add(ns, Ordering::Relaxed);
173}
174
175#[inline(always)]
176pub fn add_ecdsa_cache_hit() {
177    ECDSA_CACHE_HITS.fetch_add(1, Ordering::Relaxed);
178}
179
180#[inline(always)]
181pub fn add_ecdsa_cache_miss() {
182    ECDSA_CACHE_MISSES.fetch_add(1, Ordering::Relaxed);
183}
184
185pub fn get_and_reset_drain_timing() -> (u64, u64, u64) {
186    (
187        DRAIN_SHARD_COPY_NS.swap(0, Ordering::Relaxed),
188        DRAIN_PARSE_NS.swap(0, Ordering::Relaxed),
189        DRAIN_SECP_NS.swap(0, Ordering::Relaxed),
190    )
191}
192
193pub fn get_and_reset_ecdsa_cache_stats() -> (u64, u64) {
194    (
195        ECDSA_CACHE_HITS.swap(0, Ordering::Relaxed),
196        ECDSA_CACHE_MISSES.swap(0, Ordering::Relaxed),
197    )
198}
199
200pub fn get_and_reset_script_sub_timing() -> (u64, u64, u64) {
201    (
202        SCRIPT_SIGHASH_NS.swap(0, Ordering::Relaxed),
203        SCRIPT_INTERPRETER_NS.swap(0, Ordering::Relaxed),
204        SCRIPT_MULTISIG_NS.swap(0, Ordering::Relaxed),
205    )
206}
207
208pub fn get_and_reset_p2pkh_timing() -> (u64, u64, u64, u64, u64, u64) {
209    (
210        SCRIPT_P2PKH_PARSE_NS.swap(0, Ordering::Relaxed),
211        SCRIPT_P2PKH_HASH160_NS.swap(0, Ordering::Relaxed),
212        SCRIPT_P2PKH_COLLECT_NS.swap(0, Ordering::Relaxed),
213        P2PKH_FAST_PATH_ENTRY_NS.swap(0, Ordering::Relaxed),
214        P2PKH_BIP66_NS.swap(0, Ordering::Relaxed),
215        P2PKH_SECP_CONTEXT_NS.swap(0, Ordering::Relaxed),
216    )
217}
218
219pub fn get_and_reset_collect_timing() -> (u64, u64, u64, u64) {
220    (
221        COLLECT_SLOT_NS.swap(0, Ordering::Relaxed),
222        COLLECT_SHARD_LOCK_NS.swap(0, Ordering::Relaxed),
223        COLLECT_COPY_NS.swap(0, Ordering::Relaxed),
224        COLLECT_CHUNK_NS.swap(0, Ordering::Relaxed),
225    )
226}
227
228pub fn get_and_reset_worker_timing() -> (u64, u64, u64, u64, u64) {
229    (
230        WORKER_P2PKH_MAP_NS.swap(0, Ordering::Relaxed),
231        WORKER_REFS_NS.swap(0, Ordering::Relaxed),
232        WORKER_REFS_LOCK_NS.swap(0, Ordering::Relaxed),
233        WORKER_RUN_CHECK_LOOP_NS.swap(0, Ordering::Relaxed),
234        WORKER_RESULTS_EXTEND_NS.swap(0, Ordering::Relaxed),
235    )
236}
237
238pub fn get_and_reset_batch_phase_timing() -> (u64, u64, u64) {
239    (
240        BATCH_SOA_EXTRACT_NS.swap(0, Ordering::Relaxed),
241        BATCH_SECP_VERIFY_NS.swap(0, Ordering::Relaxed),
242        BATCH_CACHE_WRITE_NS.swap(0, Ordering::Relaxed),
243    )
244}