Line data Source code
1 : /* fd_solfuzz.c contains support routines */
2 :
3 : #define _GNU_SOURCE
4 : #include "fd_solfuzz.h"
5 : #include "../fd_bank.h"
6 : #include "../fd_runtime_stack.h"
7 : #include "../fd_runtime.h"
8 : #include "../fd_acc_pool.h"
9 : #include "../../accdb/fd_accdb_admin_v1.h"
10 : #include "../../accdb/fd_accdb_impl_v1.h"
11 : #include <errno.h>
12 : #include <sys/mman.h>
13 : #include "../../../util/shmem/fd_shmem_private.h"
14 :
15 : fd_wksp_t *
16 : fd_wksp_demand_paged_new( char const * name,
17 : uint seed,
18 : ulong part_max,
19 1 : ulong data_max ) {
20 1 : ulong footprint = fd_wksp_footprint( part_max, data_max );
21 1 : if( FD_UNLIKELY( !footprint ) ) {
22 0 : FD_LOG_WARNING(( "invalid workspace params (part_max=%lu data_max=%lu)", part_max, data_max ));
23 0 : return NULL;
24 0 : }
25 :
26 : /* Round up footprint to nearest huge page size */
27 1 : footprint = fd_ulong_align_up( footprint, FD_SHMEM_HUGE_PAGE_SZ );
28 :
29 : /* Acquire anonymous demand-paged memory */
30 1 : void * mem = fd_shmem_private_map_rand( footprint, FD_SHMEM_HUGE_PAGE_SZ, PROT_READ|PROT_WRITE );
31 1 : if( FD_UNLIKELY( mem==MAP_FAILED ) ) {
32 0 : FD_LOG_WARNING(( "fd_shmem_private_map_rand() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
33 0 : return NULL;
34 0 : }
35 :
36 : /* Indicate to kernel that hugepages are a fine backing store
37 : (Transparent Huge Pages) */
38 1 : if( FD_UNLIKELY( 0!=madvise( mem, footprint, MADV_HUGEPAGE ) ) ) {
39 0 : FD_LOG_WARNING(( "madvise() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
40 0 : munmap( mem, footprint );
41 0 : return NULL;
42 0 : }
43 :
44 : /* Create workspace */
45 1 : fd_wksp_t * wksp = fd_wksp_join( fd_wksp_new( mem, name, seed, part_max, data_max ) );
46 1 : if( FD_UNLIKELY( !wksp ) ) {
47 0 : FD_LOG_WARNING(( "fd_wksp_new() failed (%i-%s)", errno, fd_io_strerror( errno ) ));
48 0 : munmap( mem, footprint );
49 0 : return NULL;
50 0 : }
51 :
52 : /* Register shared memory region */
53 1 : ulong fake_page_cnt = footprint>>FD_SHMEM_HUGE_LG_PAGE_SZ;
54 1 : int join_err = fd_shmem_join_anonymous(
55 1 : name,
56 1 : FD_SHMEM_JOIN_MODE_READ_WRITE,
57 1 : wksp,
58 1 : mem,
59 1 : FD_SHMEM_HUGE_PAGE_SZ,
60 1 : fake_page_cnt
61 1 : );
62 1 : if( FD_UNLIKELY( join_err ) ) {
63 0 : FD_LOG_WARNING(( "fd_shmem_join_anonymous() failed (%i-%s)", join_err, fd_io_strerror( join_err ) ));
64 0 : fd_wksp_delete( fd_wksp_leave( wksp ) );
65 0 : munmap( mem, footprint );
66 0 : return NULL;
67 0 : }
68 :
69 1 : return wksp;
70 1 : }
71 :
72 : void
73 1 : fd_wksp_demand_paged_delete( fd_wksp_t * wksp ) {
74 1 : fd_shmem_leave_anonymous( wksp, NULL );
75 1 : FD_TEST( fd_wksp_delete( fd_wksp_leave( wksp ) ) );
76 1 : }
77 :
78 : fd_solfuzz_runner_t *
79 : fd_solfuzz_runner_new( fd_wksp_t * wksp,
80 : ulong wksp_tag,
81 12 : fd_solfuzz_runner_options_t const * options ) {
82 :
83 : /* Allocate objects */
84 12 : ulong const txn_max = 16UL;
85 12 : ulong const rec_max = 1024UL;
86 12 : ulong const spad_max = 1500000000UL; /* 1.5GB to accommodate 128 accounts 10MB each */
87 12 : ulong const bank_max = 2UL;
88 12 : ulong const fork_max = 2UL;
89 12 : fd_solfuzz_runner_t * runner = fd_wksp_alloc_laddr( wksp, alignof(fd_solfuzz_runner_t), sizeof(fd_solfuzz_runner_t), wksp_tag );
90 12 : void * funk_mem = fd_wksp_alloc_laddr( wksp, fd_funk_align(), fd_funk_shmem_footprint( txn_max, rec_max ), wksp_tag );
91 12 : void * funk_locks = fd_wksp_alloc_laddr( wksp, fd_funk_align(), fd_funk_locks_footprint( txn_max, rec_max ), wksp_tag );
92 12 : void * pcache_mem = fd_wksp_alloc_laddr( wksp, fd_progcache_shmem_align(), fd_progcache_shmem_footprint( txn_max, rec_max ), wksp_tag );
93 12 : uchar * scratch = fd_wksp_alloc_laddr( wksp, FD_PROGCACHE_SCRATCH_ALIGN, FD_PROGCACHE_SCRATCH_FOOTPRINT, wksp_tag );
94 12 : void * spad_mem = fd_wksp_alloc_laddr( wksp, fd_spad_align(), fd_spad_footprint( spad_max ), wksp_tag );
95 12 : void * banks_mem = fd_wksp_alloc_laddr( wksp, fd_banks_align(), fd_banks_footprint( bank_max, fork_max, 2048UL, 2048UL ), wksp_tag );
96 12 : void * acc_pool_mem = fd_wksp_alloc_laddr( wksp, fd_acc_pool_align(), fd_acc_pool_footprint( FD_ACC_POOL_MIN_ACCOUNT_CNT_PER_TX ), wksp_tag );
97 12 : if( FD_UNLIKELY( !runner ) ) { FD_LOG_WARNING(( "fd_wksp_alloc(solfuzz_runner) failed" )); goto bail1; }
98 12 : if( FD_UNLIKELY( !funk_mem ) ) { FD_LOG_WARNING(( "fd_wksp_alloc(funk) failed" )); goto bail1; }
99 12 : if( FD_UNLIKELY( !funk_locks ) ) { FD_LOG_WARNING(( "fd_wksp_alloc(funk_locks) failed" )); goto bail1; }
100 12 : if( FD_UNLIKELY( !pcache_mem ) ) { FD_LOG_WARNING(( "fd_wksp_alloc(pcache) failed" )); goto bail1; }
101 12 : if( FD_UNLIKELY( !scratch ) ) { FD_LOG_WARNING(( "fd_wksp_alloc(scratch) failed" )); goto bail1; }
102 12 : if( FD_UNLIKELY( !spad_mem ) ) { FD_LOG_WARNING(( "fd_wksp_alloc(spad) failed (spad_max=%g)", (double)spad_max )); goto bail1; }
103 12 : if( FD_UNLIKELY( !banks_mem ) ) { FD_LOG_WARNING(( "fd_wksp_alloc(banks) failed (bank_max=%lu fork_max=%lu)", bank_max, fork_max )); goto bail1; }
104 12 : if( FD_UNLIKELY( !acc_pool_mem ) ) { FD_LOG_WARNING(( "fd_wksp_alloc(acc_pool) failed (account_cnt=FD_ACC_POOL_MIN_ACCOUNT_CNT_PER_TX)" )); goto bail1; }
105 :
106 : /* Create objects */
107 12 : fd_memset( runner, 0, sizeof(fd_solfuzz_runner_t) );
108 12 : runner->wksp = wksp;
109 12 : runner->wksp_tag = wksp_tag;
110 :
111 12 : void * shfunk = fd_funk_shmem_new ( funk_mem, wksp_tag, 1UL, txn_max, rec_max );
112 12 : void * shpcache = fd_progcache_shmem_new( pcache_mem, wksp_tag, 1UL, txn_max, rec_max );
113 12 : if( FD_UNLIKELY( !shfunk ) ) goto bail1;
114 12 : if( FD_UNLIKELY( !shpcache ) ) goto bail1;
115 12 : FD_TEST( fd_funk_locks_new( funk_locks, txn_max, rec_max ) );
116 :
117 12 : if( FD_UNLIKELY( !fd_accdb_admin_v1_init( runner->accdb_admin, funk_mem, funk_locks ) ) ) goto bail2;
118 12 : if( FD_UNLIKELY( !fd_accdb_user_v1_init ( runner->accdb, funk_mem, funk_locks, txn_max ) ) ) goto bail2;
119 12 : if( FD_UNLIKELY( !fd_progcache_join( runner->progcache, pcache_mem, scratch, FD_PROGCACHE_SCRATCH_FOOTPRINT ) ) ) goto bail2;
120 :
121 12 : runner->runtime = fd_wksp_alloc_laddr( wksp, alignof(fd_runtime_t), sizeof(fd_runtime_t), wksp_tag );
122 12 : if( FD_UNLIKELY( !runner->runtime ) ) goto bail2;
123 12 : runner->runtime->accounts.executable_cnt = 0UL;
124 12 : runner->runtime_stack = fd_wksp_alloc_laddr( wksp, fd_runtime_stack_align(), fd_runtime_stack_footprint( 2048UL, 2048UL, 2048UL ), wksp_tag );
125 12 : if( FD_UNLIKELY( !runner->runtime_stack ) ) goto bail2;
126 12 : if( FD_UNLIKELY( !fd_runtime_stack_join( fd_runtime_stack_new( runner->runtime_stack, 2048UL, 2048UL, 2048UL, 999UL ) ) ) ) goto bail2;
127 :
128 12 : # if FD_HAS_FLATCC
129 : /* TODO: Consider implementing custom allocators and emitters.
130 : The default builder / emitter uses libc allocators */
131 12 : int builder_err = flatcc_builder_init( runner->fb_builder );
132 12 : if( FD_UNLIKELY( builder_err ) ) goto bail2;
133 12 : # endif
134 :
135 12 : runner->spad = fd_spad_join( fd_spad_new( spad_mem, spad_max ) );
136 12 : if( FD_UNLIKELY( !runner->spad ) ) goto bail2;
137 12 : fd_banks_locks_t * banks_locks = fd_wksp_alloc_laddr( wksp, alignof(fd_banks_locks_t), sizeof(fd_banks_locks_t), wksp_tag );
138 12 : fd_banks_locks_init( banks_locks );
139 : /* Use 2048 for max_vote_accounts to match fd_banks_footprint above (avoids buffer overrun) */
140 12 : if( FD_UNLIKELY( !fd_banks_join( runner->banks, fd_banks_new( banks_mem, bank_max, fork_max, 2048UL, 2048UL, 0, 8888UL ), banks_locks ) ) ) goto bail2;
141 12 : if( FD_UNLIKELY( !fd_banks_init_bank( runner->bank, runner->banks ) ) ) goto bail2;
142 12 : runner->acc_pool = fd_acc_pool_join( fd_acc_pool_new( acc_pool_mem, FD_ACC_POOL_MIN_ACCOUNT_CNT_PER_TX ) );
143 12 : if( FD_UNLIKELY( !runner->acc_pool ) ) goto bail2;
144 12 : fd_bank_slot_set( runner->bank, 0UL );
145 :
146 12 : runner->enable_vm_tracing = options->enable_vm_tracing;
147 12 : FD_TEST( runner->progcache->join->shmem );
148 :
149 12 : ulong tags[1] = { wksp_tag };
150 12 : fd_wksp_usage_t usage[1];
151 12 : fd_wksp_usage( wksp, tags, 1UL, usage );
152 12 : runner->wksp_baseline_used_sz = usage->used_sz;
153 :
154 12 : return runner;
155 :
156 0 : bail2:
157 0 : if( runner->spad ) fd_spad_delete( fd_spad_leave( runner->spad ) );
158 0 : if( shfunk ) fd_funk_delete( shfunk ); /* free underlying fd_alloc instance */
159 0 : if( shpcache ) fd_progcache_shmem_delete( shpcache );
160 0 : bail1:
161 0 : fd_wksp_free_laddr( scratch );
162 0 : fd_wksp_free_laddr( pcache_mem );
163 0 : fd_wksp_free_laddr( funk_locks );
164 0 : fd_wksp_free_laddr( funk_mem );
165 0 : fd_wksp_free_laddr( spad_mem );
166 0 : fd_wksp_free_laddr( banks_mem );
167 0 : fd_wksp_free_laddr( runner );
168 0 : fd_wksp_free_laddr( acc_pool_mem );
169 0 : FD_LOG_WARNING(( "fd_solfuzz_runner_new failed" ));
170 0 : return NULL;
171 0 : }
172 :
173 : void
174 12 : fd_solfuzz_runner_delete( fd_solfuzz_runner_t * runner ) {
175 :
176 12 : void * shfunk = fd_accdb_user_v1_funk( runner->accdb )->shmem;
177 12 : void * shfunk_lock = (void *)fd_accdb_user_v1_funk( runner->accdb )->txn_lock;
178 12 : fd_accdb_user_fini( runner->accdb );
179 12 : fd_accdb_admin_fini( runner->accdb_admin );
180 12 : fd_wksp_free_laddr( shfunk_lock );
181 12 : fd_wksp_free_laddr( fd_funk_delete( shfunk ) );
182 :
183 12 : fd_progcache_shmem_t * shpcache = NULL;
184 12 : fd_progcache_leave( runner->progcache, &shpcache );
185 12 : if( shpcache ) fd_wksp_free_laddr( fd_progcache_shmem_delete( shpcache ) );
186 :
187 12 : # if FD_HAS_FLATCC
188 12 : flatcc_builder_clear( runner->fb_builder );
189 12 : # endif
190 :
191 12 : if( runner->spad ) fd_wksp_free_laddr( fd_spad_delete( fd_spad_leave( runner->spad ) ) );
192 12 : fd_wksp_free_laddr( runner->banks->data );
193 12 : fd_wksp_free_laddr( runner->banks->locks );
194 12 : fd_wksp_free_laddr( runner );
195 12 : }
196 :
197 : void
198 0 : fd_solfuzz_runner_leak_check( fd_solfuzz_runner_t * runner ) {
199 0 : if( FD_UNLIKELY( fd_spad_frame_used( runner->spad ) ) ) {
200 0 : FD_LOG_CRIT(( "leaked spad frame" ));
201 0 : }
202 :
203 0 : fd_funk_t * accdb_funk = fd_accdb_admin_v1_funk( runner->accdb_admin );
204 0 : if( FD_UNLIKELY( !fd_funk_txn_idx_is_null( fd_funk_txn_idx( accdb_funk->shmem->child_head_cidx ) ) ) ) {
205 0 : FD_LOG_CRIT(( "leaked a funk txn in accdb" ));
206 0 : }
207 0 : if( FD_UNLIKELY( !fd_funk_txn_idx_is_null( runner->progcache->join->shmem->txn.child_head_idx ) ) ) {
208 0 : FD_LOG_CRIT(( "leaked a funk txn in progcache" ));
209 0 : }
210 :
211 0 : ulong tags[1] = { runner->wksp_tag };
212 0 : fd_wksp_usage_t usage[1];
213 0 : fd_wksp_usage( runner->wksp, tags, 1UL, usage );
214 0 : if( FD_UNLIKELY( usage->used_sz != runner->wksp_baseline_used_sz ) ) {
215 0 : FD_LOG_CRIT(( "leaked wksp allocations: %lu bytes with tag %lu (baseline %lu bytes, delta %+ld)",
216 0 : usage->used_sz, runner->wksp_tag,
217 0 : runner->wksp_baseline_used_sz,
218 0 : (long)usage->used_sz - (long)runner->wksp_baseline_used_sz ));
219 0 : }
220 0 : }
|