1+ use bdk_core:: CheckPoint ;
2+ use bitcoin:: BlockHash ;
3+ use bitcoin:: hashes:: Hash ;
4+ use criterion:: { black_box, criterion_group, criterion_main, Criterion , Bencher } ;
5+
6+ /// Create a checkpoint chain with the given length
7+ fn create_checkpoint_chain ( length : u32 ) -> CheckPoint < BlockHash > {
8+ let mut cp = CheckPoint :: new ( 0 , BlockHash :: all_zeros ( ) ) ;
9+ for height in 1 ..=length {
10+ let hash = BlockHash :: from_byte_array ( [ ( height % 256 ) as u8 ; 32 ] ) ;
11+ cp = cp. push ( height, hash) . unwrap ( ) ;
12+ }
13+ cp
14+ }
15+
16+ /// Benchmark get() operations at various depths
17+ fn bench_checkpoint_get ( c : & mut Criterion ) {
18+ // Small chain - get near start
19+ c. bench_function ( "get_100_near_start" , |b : & mut Bencher | {
20+ let cp = create_checkpoint_chain ( 100 ) ;
21+ let target = 10 ;
22+ b. iter ( || {
23+ black_box ( cp. get ( target) ) ;
24+ } ) ;
25+ } ) ;
26+
27+ // Medium chain - get middle
28+ c. bench_function ( "get_1000_middle" , |b : & mut Bencher | {
29+ let cp = create_checkpoint_chain ( 1000 ) ;
30+ let target = 500 ;
31+ b. iter ( || {
32+ black_box ( cp. get ( target) ) ;
33+ } ) ;
34+ } ) ;
35+
36+ // Large chain - get near end
37+ c. bench_function ( "get_10000_near_end" , |b : & mut Bencher | {
38+ let cp = create_checkpoint_chain ( 10000 ) ;
39+ let target = 9000 ;
40+ b. iter ( || {
41+ black_box ( cp. get ( target) ) ;
42+ } ) ;
43+ } ) ;
44+
45+ // Large chain - get near start (best case for skiplist)
46+ c. bench_function ( "get_10000_near_start" , |b : & mut Bencher | {
47+ let cp = create_checkpoint_chain ( 10000 ) ;
48+ let target = 100 ;
49+ b. iter ( || {
50+ black_box ( cp. get ( target) ) ;
51+ } ) ;
52+ } ) ;
53+ }
54+
55+ /// Benchmark floor_at() operations
56+ fn bench_checkpoint_floor_at ( c : & mut Criterion ) {
57+ c. bench_function ( "floor_at_1000" , |b : & mut Bencher | {
58+ let cp = create_checkpoint_chain ( 1000 ) ;
59+ let target = 750 ; // Target that might not exist exactly
60+ b. iter ( || {
61+ black_box ( cp. floor_at ( target) ) ;
62+ } ) ;
63+ } ) ;
64+
65+ c. bench_function ( "floor_at_10000" , |b : & mut Bencher | {
66+ let cp = create_checkpoint_chain ( 10000 ) ;
67+ let target = 7500 ;
68+ b. iter ( || {
69+ black_box ( cp. floor_at ( target) ) ;
70+ } ) ;
71+ } ) ;
72+ }
73+
74+ /// Benchmark range() iteration
75+ fn bench_checkpoint_range ( c : & mut Criterion ) {
76+ c. bench_function ( "range_1000_20pct" , |b : & mut Bencher | {
77+ let cp = create_checkpoint_chain ( 1000 ) ;
78+ let start = 400 ;
79+ let end = 600 ;
80+ b. iter ( || {
81+ let range: Vec < _ > = cp. range ( start..=end) . collect ( ) ;
82+ black_box ( range) ;
83+ } ) ;
84+ } ) ;
85+
86+ c. bench_function ( "range_10000_to_end" , |b : & mut Bencher | {
87+ let cp = create_checkpoint_chain ( 10000 ) ;
88+ let from = 5000 ;
89+ b. iter ( || {
90+ let range: Vec < _ > = cp. range ( from..) . collect ( ) ;
91+ black_box ( range) ;
92+ } ) ;
93+ } ) ;
94+ }
95+
96+ /// Benchmark insert() operations
97+ fn bench_checkpoint_insert ( c : & mut Criterion ) {
98+ c. bench_function ( "insert_sparse_1000" , |b : & mut Bencher | {
99+ // Create a sparse chain
100+ let mut cp = CheckPoint :: new ( 0 , BlockHash :: all_zeros ( ) ) ;
101+ for i in 1 ..=100 {
102+ let height = i * 10 ;
103+ let hash = BlockHash :: from_byte_array ( [ ( height % 256 ) as u8 ; 32 ] ) ;
104+ cp = cp. push ( height, hash) . unwrap ( ) ;
105+ }
106+
107+ let insert_height = 505 ;
108+ let insert_hash = BlockHash :: from_byte_array ( [ 255 ; 32 ] ) ;
109+
110+ b. iter ( || {
111+ let result = cp. clone ( ) . insert ( insert_height, insert_hash) ;
112+ black_box ( result) ;
113+ } ) ;
114+ } ) ;
115+ }
116+
117+ /// Compare linear traversal vs skiplist-enhanced get()
118+ fn bench_traversal_comparison ( c : & mut Criterion ) {
119+ // Linear traversal benchmark
120+ c. bench_function ( "linear_traversal_10000" , |b : & mut Bencher | {
121+ let cp = create_checkpoint_chain ( 10000 ) ;
122+ let target = 100 ; // Near the beginning
123+
124+ b. iter ( || {
125+ let mut current = cp. clone ( ) ;
126+ while current. height ( ) > target {
127+ if let Some ( prev) = current. prev ( ) {
128+ current = prev;
129+ } else {
130+ break ;
131+ }
132+ }
133+ black_box ( current) ;
134+ } ) ;
135+ } ) ;
136+
137+ // Skiplist-enhanced get() for comparison
138+ c. bench_function ( "skiplist_get_10000" , |b : & mut Bencher | {
139+ let cp = create_checkpoint_chain ( 10000 ) ;
140+ let target = 100 ; // Same target
141+
142+ b. iter ( || {
143+ black_box ( cp. get ( target) ) ;
144+ } ) ;
145+ } ) ;
146+ }
147+
148+ /// Analyze skip pointer distribution and usage
149+ fn bench_skip_pointer_analysis ( c : & mut Criterion ) {
150+ c. bench_function ( "count_skip_pointers_10000" , |b : & mut Bencher | {
151+ let cp = create_checkpoint_chain ( 10000 ) ;
152+
153+ b. iter ( || {
154+ let mut count = 0 ;
155+ let mut current = cp. clone ( ) ;
156+ loop {
157+ if current. skip ( ) . is_some ( ) {
158+ count += 1 ;
159+ }
160+ if let Some ( prev) = current. prev ( ) {
161+ current = prev;
162+ } else {
163+ break ;
164+ }
165+ }
166+ black_box ( count) ;
167+ } ) ;
168+ } ) ;
169+
170+ // Measure actual skip pointer usage during traversal
171+ c. bench_function ( "skip_usage_in_traversal" , |b : & mut Bencher | {
172+ let cp = create_checkpoint_chain ( 10000 ) ;
173+ let target = 100 ;
174+
175+ b. iter ( || {
176+ let mut current = cp. clone ( ) ;
177+ let mut skips_used = 0 ;
178+
179+ while current. height ( ) > target {
180+ if let Some ( skip_cp) = current. skip ( ) {
181+ if skip_cp. height ( ) >= target {
182+ current = skip_cp;
183+ skips_used += 1 ;
184+ continue ;
185+ }
186+ }
187+
188+ if let Some ( prev) = current. prev ( ) {
189+ current = prev;
190+ } else {
191+ break ;
192+ }
193+ }
194+ black_box ( ( current, skips_used) ) ;
195+ } ) ;
196+ } ) ;
197+ }
198+
199+ criterion_group ! (
200+ benches,
201+ bench_checkpoint_get,
202+ bench_checkpoint_floor_at,
203+ bench_checkpoint_range,
204+ bench_checkpoint_insert,
205+ bench_traversal_comparison,
206+ bench_skip_pointer_analysis
207+ ) ;
208+
209+ criterion_main ! ( benches) ;
0 commit comments