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