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