Skip to content

Commit e467a08

Browse files
riptlripatel-fd
authored andcommitted
funk: optimize rec memory layout
Reduces fd_funk_rec_t footprint from 128 bytes to 96 bytes
1 parent e63c6a7 commit e467a08

File tree

4 files changed

+19
-55
lines changed

4 files changed

+19
-55
lines changed

src/funk/fd_funk_rec.c

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@
2020
#define MAP_KEY_HASH(k0,seed) fd_funk_xid_key_pair_hash((k0),(seed))
2121
#define MAP_IDX_T uint
2222
#define MAP_NEXT map_next
23-
#define MAP_MEMO map_hash
2423
#define MAP_MAGIC (0xf173da2ce77ecdb0UL) /* Firedancer rec db version 0 */
25-
#define MAP_MEMOIZE 1
2624
#define MAP_IMPL_STYLE 2
2725
#include "../util/tmpl/fd_map_chain_para.c"
2826

@@ -176,7 +174,7 @@ fd_funk_rec_query_try_global( fd_funk_t const * funk,
176174
!fd_funk_rec_map_iter_done( iter );
177175
iter = fd_funk_rec_map_iter_next( iter ) ) {
178176
fd_funk_rec_t const * ele = fd_funk_rec_map_iter_ele_const( iter );
179-
if( FD_LIKELY( hash == ele->map_hash ) && FD_LIKELY( fd_funk_rec_key_eq( key, ele->pair.key ) ) ) {
177+
if( FD_LIKELY( fd_funk_rec_key_eq( key, ele->pair.key ) ) ) {
180178

181179
/* For cur_txn in path from [txn] to [root] where root is NULL */
182180

@@ -293,10 +291,8 @@ fd_funk_rec_prepare( fd_funk_t * funk,
293291
fd_funk_val_init( rec );
294292
if( txn == NULL ) {
295293
fd_funk_txn_xid_set_root( rec->pair.xid );
296-
rec->txn_cidx = fd_funk_txn_cidx( FD_FUNK_TXN_IDX_NULL );
297294
} else {
298295
fd_funk_txn_xid_copy( rec->pair.xid, &txn->xid );
299-
rec->txn_cidx = fd_funk_txn_cidx( (ulong)( txn - funk->txn_pool->ele ) );
300296
prepare->rec_head_idx = &txn->rec_head_idx;
301297
prepare->rec_tail_idx = &txn->rec_tail_idx;
302298
}
@@ -485,7 +481,7 @@ fd_funk_rec_remove( fd_funk_t * funk,
485481
if( rec_out ) *rec_out = rec;
486482

487483
/* Access the flags atomically */
488-
ulong old_flags;
484+
uint old_flags;
489485
for(;;) {
490486
old_flags = rec->flags;
491487
if( FD_UNLIKELY( old_flags & FD_FUNK_REC_FLAG_ERASE ) ) {
@@ -547,8 +543,6 @@ int
547543
fd_funk_rec_verify( fd_funk_t * funk ) {
548544
fd_funk_rec_map_t * rec_map = funk->rec_map;
549545
fd_funk_rec_pool_t * rec_pool = funk->rec_pool;
550-
fd_funk_txn_pool_t * txn_pool = funk->txn_pool;
551-
ulong txn_max = fd_funk_txn_pool_ele_max( txn_pool );
552546
ulong rec_max = fd_funk_rec_pool_ele_max( rec_pool );
553547

554548
# define TEST(c) do { \
@@ -570,10 +564,9 @@ fd_funk_rec_verify( fd_funk_t * funk ) {
570564
/* Make sure every record either links up with the last published
571565
transaction or an in-prep transaction and the flags are sane. */
572566

573-
fd_funk_txn_xid_t const * xid = fd_funk_rec_xid( rec );
574-
ulong txn_idx = fd_funk_txn_idx( rec->txn_cidx );
567+
fd_funk_txn_xid_t const * xid = fd_funk_rec_xid( rec );
575568

576-
if( fd_funk_txn_idx_is_null( txn_idx ) ) { /* This is a record from the last published transaction */
569+
if( fd_funk_txn_xid_eq_root( xid ) ) { /* This is a record from the last published transaction */
577570

578571
TEST( fd_funk_txn_xid_eq_root( xid ) );
579572
/* No record linked list at the root txn */
@@ -582,10 +575,7 @@ fd_funk_rec_verify( fd_funk_t * funk ) {
582575

583576
} else { /* This is a record from an in-prep transaction */
584577

585-
TEST( txn_idx<txn_max );
586-
fd_funk_txn_t const * txn = fd_funk_txn_query( xid, funk->txn_map );
587-
TEST( txn );
588-
TEST( txn==(funk->txn_pool->ele+txn_idx) );
578+
TEST( fd_funk_txn_query( xid, funk->txn_map ) );
589579

590580
}
591581
}
@@ -609,10 +599,9 @@ fd_funk_rec_verify( fd_funk_t * funk ) {
609599
for( fd_funk_txn_all_iter_new( funk, txn_iter ); !fd_funk_txn_all_iter_done( txn_iter ); fd_funk_txn_all_iter_next( txn_iter ) ) {
610600
fd_funk_txn_t const * txn = fd_funk_txn_all_iter_ele_const( txn_iter );
611601

612-
ulong txn_idx = (ulong)(txn-txn_pool->ele);
613-
uint rec_idx = txn->rec_head_idx;
602+
uint rec_idx = txn->rec_head_idx;
614603
while( !fd_funk_rec_idx_is_null( rec_idx ) ) {
615-
TEST( (rec_idx<rec_max) && (fd_funk_txn_idx( rec_pool->ele[ rec_idx ].txn_cidx )==txn_idx) && rec_pool->ele[ rec_idx ].tag==0U );
604+
TEST( (rec_idx<rec_max) && rec_pool->ele[ rec_idx ].tag==0U );
616605
rec_pool->ele[ rec_idx ].tag = 1U;
617606
fd_funk_rec_query_t query[1];
618607
fd_funk_rec_t const * rec2 = fd_funk_rec_query_try_global( funk, &txn->xid, rec_pool->ele[ rec_idx ].pair.key, NULL, query );
@@ -632,10 +621,9 @@ fd_funk_rec_verify( fd_funk_t * funk ) {
632621
for( fd_funk_txn_all_iter_new( funk, txn_iter ); !fd_funk_txn_all_iter_done( txn_iter ); fd_funk_txn_all_iter_next( txn_iter ) ) {
633622
fd_funk_txn_t const * txn = fd_funk_txn_all_iter_ele_const( txn_iter );
634623

635-
ulong txn_idx = (ulong)(txn-txn_pool->ele);
636-
uint rec_idx = txn->rec_tail_idx;
624+
uint rec_idx = txn->rec_tail_idx;
637625
while( !fd_funk_rec_idx_is_null( rec_idx ) ) {
638-
TEST( (rec_idx<rec_max) && (fd_funk_txn_idx( rec_pool->ele[ rec_idx ].txn_cidx )==txn_idx) && rec_pool->ele[ rec_idx ].tag==1U );
626+
TEST( (rec_idx<rec_max) && rec_pool->ele[ rec_idx ].tag==1U );
639627
rec_pool->ele[ rec_idx ].tag = 2U;
640628
uint prev_idx = rec_pool->ele[ rec_idx ].prev_idx;
641629
if( !fd_funk_rec_idx_is_null( prev_idx ) ) TEST( rec_pool->ele[ prev_idx ].next_idx==rec_idx );

src/funk/fd_funk_rec.h

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,7 @@
11
#ifndef HEADER_fd_src_funk_fd_funk_rec_h
22
#define HEADER_fd_src_funk_fd_funk_rec_h
33

4-
/* This provides APIs for managing funk records. It is generally not
5-
meant to be included directly. Use fd_funk.h instead.
6-
7-
The following APIs are thread safe and can be interleaved arbirarily
8-
across threads:
9-
fd_funk_rec_query_try
10-
fd_funk_rec_query_test
11-
fd_funk_rec_query_try_global
12-
fd_funk_rec_prepare
13-
fd_funk_rec_publish
14-
fd_funk_rec_cancel
15-
fd_funk_rec_remove
16-
*/
4+
/* fd_funk_rec.h provides APIs for managing funk records */
175

186
#include "fd_funk_txn.h" /* Includes fd_funk_base.h */
197

@@ -22,7 +10,7 @@
2210
multiple of align. These are provided to facilitate compile time
2311
declarations. */
2412

25-
#define FD_FUNK_REC_ALIGN (64UL)
13+
#define FD_FUNK_REC_ALIGN (32UL)
2614

2715
/* FD_FUNK_REC_FLAG_* are flags that can be bit-ored together to specify
2816
how records are to be interpreted. The 5 most significant bytes of a
@@ -48,17 +36,15 @@ struct __attribute__((aligned(FD_FUNK_REC_ALIGN))) fd_funk_rec {
4836

4937
fd_funk_xid_key_pair_t pair; /* Transaction id and record key pair */
5038
uint map_next; /* Internal use by map */
51-
ulong map_hash; /* Internal use by map */
5239

5340
/* These fields are managed by funk. TODO: Consider using record
5441
index compression here (much more debatable than in txn itself). */
5542

5643
uint prev_idx; /* Record map index of previous record in its transaction */
5744
uint next_idx; /* Record map index of next record in its transaction */
5845

59-
uint txn_cidx; /* Compressed transaction map index (or compressed FD_FUNK_TXN_IDX if this is in the last published) */
6046
uint tag; /* Internal use only */
61-
ulong flags; /* Flags that indicate how to interpret a record */
47+
uint flags; /* Flags that indicate how to interpret a record */
6248

6349
/* Note: use of uint here requires FD_FUNK_REC_VAL_MAX to be at most
6450
UINT_MAX. */
@@ -70,12 +56,11 @@ struct __attribute__((aligned(FD_FUNK_REC_ALIGN))) fd_funk_rec {
7056
has tag wksp_tag) and the owner of the region will be the record. The allocator is
7157
fd_funk_alloc(). IMPORTANT! HAS NO GUARANTEED ALIGNMENT! */
7258

73-
/* Padding to FD_FUNK_REC_ALIGN here */
7459
};
7560

7661
typedef struct fd_funk_rec fd_funk_rec_t;
7762

78-
FD_STATIC_ASSERT( sizeof(fd_funk_rec_t) == 2U*FD_FUNK_REC_ALIGN, record size is wrong );
63+
FD_STATIC_ASSERT( sizeof(fd_funk_rec_t) == 3U*FD_FUNK_REC_ALIGN, record size is wrong );
7964

8065
/* fd_funk_rec_map allows for indexing records by their (xid,key) pair.
8166
It is used to store all records of the last published transaction and
@@ -100,13 +85,9 @@ FD_STATIC_ASSERT( sizeof(fd_funk_rec_t) == 2U*FD_FUNK_REC_ALIGN, record size is
10085
#define MAP_KEY_HASH(k0,seed) fd_funk_xid_key_pair_hash((k0),(seed))
10186
#define MAP_IDX_T uint
10287
#define MAP_NEXT map_next
103-
#define MAP_MEMO map_hash
10488
#define MAP_MAGIC (0xf173da2ce77ecdb0UL) /* Firedancer rec db version 0 */
105-
#define MAP_MEMOIZE 1
10689
#define MAP_IMPL_STYLE 1
10790
#include "../util/tmpl/fd_map_chain_para.c"
108-
#undef MAP_MEMOIZE
109-
#undef MAP_HASH
11091

11192
typedef fd_funk_rec_map_query_t fd_funk_rec_query_t;
11293

src/funk/fd_funk_txn.c

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -175,12 +175,11 @@ fd_funk_txn_cancel_childless( fd_funk_t * funk,
175175
while( !fd_funk_rec_idx_is_null( rec_idx ) ) {
176176

177177
if( FD_UNLIKELY( rec_idx>=rec_max ) ) FD_LOG_CRIT(( "memory corruption detected (bad idx)" ));
178-
if( FD_UNLIKELY( fd_funk_txn_idx( rec_pool->ele[ rec_idx ].txn_cidx )!=txn_idx ) )
178+
if( FD_UNLIKELY( !fd_funk_txn_xid_eq( rec_pool->ele[ rec_idx ].pair.xid, &txn->xid ) ) )
179179
FD_LOG_CRIT(( "memory corruption detected (cycle or bad idx)" ));
180180

181181
fd_funk_rec_t * rec = &rec_pool->ele[ rec_idx ];
182182
uint next_idx = rec->next_idx;
183-
rec->txn_cidx = fd_funk_txn_cidx( FD_FUNK_TXN_IDX_NULL );
184183

185184
for(;;) {
186185
fd_funk_rec_map_query_t rec_query[1];
@@ -444,11 +443,10 @@ fd_funk_txn_remove_published( fd_funk_t * funk ) {
444443
if( FD_UNLIKELY( err!=FD_MAP_SUCCESS ) ) FD_LOG_CRIT(( "fd_funk_rec_map_remove failed (%i-%s)", err, fd_map_strerror( err ) ));
445444

446445
/* Sanity check: Record belongs to last published XID */
447-
if( FD_UNLIKELY( !fd_funk_txn_idx_is_null( fd_funk_txn_idx( rec->txn_cidx ) ) ) ) {
446+
if( FD_UNLIKELY( !fd_funk_txn_xid_eq_root( rec->pair.xid ) ) ) {
448447
FD_LOG_ERR(( "Failed to remove published txns: concurrent in-prep record detected" ));
449448
}
450449

451-
452450
/* Free rec resources */
453451
fd_funk_val_flush( rec, alloc, wksp );
454452
fd_funk_rec_pool_release( rec_pool, rec, 1 );
@@ -502,7 +500,6 @@ static void
502500
fd_funk_txn_update( fd_funk_t * funk,
503501
uint * _dst_rec_head_idx, /* Pointer to the dst list head */
504502
uint * _dst_rec_tail_idx, /* Pointer to the dst list tail */
505-
ulong dst_txn_idx, /* Transaction index of the merge destination */
506503
fd_funk_txn_xid_t const * dst_xid, /* dst xid */
507504
ulong txn_idx ) { /* Transaction index of the records to merge */
508505
fd_wksp_t * wksp = funk->wksp;
@@ -544,7 +541,6 @@ fd_funk_txn_update( fd_funk_t * funk,
544541
}
545542
/* Clean up value */
546543
fd_funk_val_flush( rec2, alloc, wksp );
547-
rec2->txn_cidx = fd_funk_txn_cidx( FD_FUNK_TXN_IDX_NULL );
548544
fd_funk_rec_pool_release( rec_pool, rec2, 1 );
549545
break;
550546
}
@@ -557,7 +553,6 @@ fd_funk_txn_update( fd_funk_t * funk,
557553
property. */
558554

559555
rec->pair.xid[0] = *dst_xid;
560-
rec->txn_cidx = fd_funk_txn_cidx( dst_txn_idx );
561556

562557
rec->prev_idx = FD_FUNK_REC_IDX_NULL;
563558
if( _dst_rec_head_idx ) {
@@ -591,7 +586,7 @@ fd_funk_txn_publish_funk_child( fd_funk_t * const funk,
591586

592587
/* Apply the updates in txn to the last published transactions */
593588

594-
fd_funk_txn_update( funk, NULL, NULL, FD_FUNK_TXN_IDX_NULL, fd_funk_root( funk ), txn_idx );
589+
fd_funk_txn_update( funk, NULL, NULL, fd_funk_root( funk ), txn_idx );
595590

596591
/* Cancel all competing transaction histories */
597592

@@ -722,13 +717,13 @@ fd_funk_txn_publish_into_parent( fd_funk_t * funk,
722717
ulong parent_idx = fd_funk_txn_idx( txn->parent_cidx );
723718
if( fd_funk_txn_idx_is_null( parent_idx ) ) {
724719
/* Publish to root */
725-
fd_funk_txn_update( funk, NULL, NULL, FD_FUNK_TXN_IDX_NULL, fd_funk_root( funk ), txn_idx );
720+
fd_funk_txn_update( funk, NULL, NULL, fd_funk_root( funk ), txn_idx );
726721
/* Inherit the children */
727722
funk->shmem->child_head_cidx = txn->child_head_cidx;
728723
funk->shmem->child_tail_cidx = txn->child_tail_cidx;
729724
} else {
730725
fd_funk_txn_t * parent_txn = &txn_pool->ele[ parent_idx ];
731-
fd_funk_txn_update( funk, &parent_txn->rec_head_idx, &parent_txn->rec_tail_idx, parent_idx, &parent_txn->xid, txn_idx );
726+
fd_funk_txn_update( funk, &parent_txn->rec_head_idx, &parent_txn->rec_tail_idx, &parent_txn->xid, txn_idx );
732727
/* Inherit the children */
733728
parent_txn->child_head_cidx = txn->child_head_cidx;
734729
parent_txn->child_tail_cidx = txn->child_tail_cidx;

src/funk/test_funk_rec.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
#if FD_HAS_HOSTED
44

5-
FD_STATIC_ASSERT( FD_FUNK_REC_ALIGN == 64UL, unit_test );
5+
FD_STATIC_ASSERT( FD_FUNK_REC_ALIGN == 32UL, unit_test );
66

77
FD_STATIC_ASSERT( FD_FUNK_REC_FLAG_ERASE==1UL, unit_test );
88

0 commit comments

Comments
 (0)