Unified attr-list context into little attr arenas

The idea is for cases where we need to incrementally allocate attrs +
context, to allocate from both sides of a statically allocated attr
array. This keeps all of the attr-list state in one place, simplifying
state allocation:

  .---+---+---+---.
  |      attr     |
  +---+---+---+---+
  |      attr ----------.
  +---+---+---+---+     |
  |      attr --------. |
  +---+---+---+---+   | |
  |       |       |   | |
  |       v       |   | |
  |               |   | |
  |       ^       |   | |
  |       |       |   | |
  +---+---+---+---+   | |
  |      data     | <-' |
  +---+---+---+---+     |
  |  encoded bptr | <---'
  '---+---+---+---'

This is especially useful for the non-terminating tail-recursive
lfsr_btree_commit_, which needs to pass this state through a function
call.

Unfortunately, to make this work we needed to implement more-or-less a
full arena allocator, complete with annoying alignment handling. alignof
isn't even available in C99, so we needed a few more intrinsics:

- LFS_ALIGNOF(t)       - Alignment of type t
- LFS_ALIGNEDSIZEOF(t) - Necessary size to force alignment for t
- LFS_MIN(a, b)        - Compile-time min
- LFS_MAX(a, b)        - Compile-time max

Technically only LFS_ALIGNOF was required, but the others are nice to
have. LFS_MIN/LFS_MAX is also useful anywhere you need to calculate
complicated compile-time sizes.

At least in C11 we get alignof, so we won't need compiler extensions/
hacks for this in the future...

---

Unfortunately this ended up a net-negative. Pushing up the code/stack
cost to near pre-cat levels:

                   code          stack
  before cat:     33856           2824
  before scratch: 33812 (-0.1%)   2800 (-0.8%)
  after:          33844 (-0.0%)   2824 (+0.0%)

I think the two main culprits are 1. the extra logic needed to calculate
alignment, and 2. wasted stack due to aligning scratch space up to the
nearest lfsr_attr_t.
This commit is contained in:
Christopher Haster
2024-05-05 11:50:59 -05:00
parent 88a098c616
commit 8f3036f1e5
2 changed files with 122 additions and 86 deletions
+100 -78
View File
@@ -1631,6 +1631,29 @@ static inline lfsr_shrub_t *lfsr_attr_shrubtrunk(const lfsr_attr_t *attr) {
return (lfsr_shrub_t*)attr->cat.u.buf.buffer; return (lfsr_shrub_t*)attr->cat.u.buf.buffer;
} }
// sometimes we want some extra scratch space associated with an
// attribute list
#define LFSR_ATTR_SCRATCH(_size) \
(((_size)+sizeof(lfsr_attr_t)-1) / sizeof(lfsr_attr_t))
static inline void *lfsr_attr_scratch(
lfsr_attr_t *attr, lfs_size_t *attr_scratch,
lfs_size_t size) {
lfs_size_t attr_scratch_ = *attr_scratch - size;
*attr_scratch = attr_scratch_;
return &((uint8_t*)attr)[attr_scratch_];
}
static inline lfsr_data_t *lfsr_attr_scratchdata(
lfsr_attr_t *attr, lfs_size_t *attr_scratch) {
lfs_size_t attr_scratch_ = *attr_scratch - sizeof(lfsr_data_t);
// align down
attr_scratch_ -= (uintptr_t)&((uint8_t*)attr)[attr_scratch_]
% LFS_ALIGNOF(lfsr_data_t);
*attr_scratch = attr_scratch_;
return (lfsr_data_t*)&((uint8_t*)attr)[attr_scratch_];
}
// generalized info returned by traveral functions // generalized info returned by traveral functions
@@ -4374,6 +4397,11 @@ static int lfsr_btree_parent(lfs_t *lfs, const lfsr_btree_t *btree,
} }
// attrs needed for lfsr_btree_commit_
#define LFSR_BTREE_COMMIT_ATTRS \
(4 + LFSR_ATTR_SCRATCH( \
LFS_ALIGNEDSIZEOF(lfsr_data_t) + 2*LFSR_BRANCH_DSIZE))
// core btree algorithm // core btree algorithm
// //
// this commits up to the root, but stops if: // this commits up to the root, but stops if:
@@ -4382,10 +4410,7 @@ static int lfsr_btree_parent(lfs_t *lfs, const lfsr_btree_t *btree,
// //
static int lfsr_btree_commit_(lfs_t *lfs, lfsr_btree_t *btree, static int lfsr_btree_commit_(lfs_t *lfs, lfsr_btree_t *btree,
lfsr_bid_t *bid_, const lfsr_attr_t **attrs_, lfs_size_t *attr_count_, lfsr_bid_t *bid_, const lfsr_attr_t **attrs_, lfs_size_t *attr_count_,
lfsr_attr_t attrs__[static 4], lfsr_attr_t attrs__[static LFSR_BTREE_COMMIT_ATTRS]) {
uint8_t buf__[static 2*LFSR_BRANCH_DSIZE],
// TODO can we carve this out of buf__?
lfsr_data_t split_data__[static 1]) {
lfsr_bid_t bid = *bid_; lfsr_bid_t bid = *bid_;
LFS_ASSERT(bid <= (lfsr_bid_t)btree->weight); LFS_ASSERT(bid <= (lfsr_bid_t)btree->weight);
const lfsr_attr_t *attrs = *attrs_; const lfsr_attr_t *attrs = *attrs_;
@@ -4506,16 +4531,17 @@ static int lfsr_btree_commit_(lfs_t *lfs, lfsr_btree_t *btree,
// note that since we defer merges to compaction time, we can // note that since we defer merges to compaction time, we can
// end up removing an rbyd here // end up removing an rbyd here
attr_count = 0; attr_count = 0;
lfs_size_t buf_size = 0; lfs_size_t attr_scratch = LFSR_BTREE_COMMIT_ATTRS*sizeof(lfsr_attr_t);
bid -= pid - (rbyd.weight-1); bid -= pid - (rbyd.weight-1);
if (rbyd_.weight == 0) { if (rbyd_.weight == 0) {
attrs__[attr_count++] = LFSR_ATTR( attrs__[attr_count++] = LFSR_ATTR(
LFSR_TAG_RM, -rbyd.weight, LFSR_CAT_NULL()); LFSR_TAG_RM, -rbyd.weight, LFSR_CAT_NULL());
} else { } else {
uint8_t *buf = lfsr_attr_scratch(attrs__, &attr_scratch,
LFSR_BRANCH_DSIZE);
attrs__[attr_count++] = LFSR_ATTR( attrs__[attr_count++] = LFSR_ATTR(
LFSR_TAG_BRANCH, 0, LFSR_TAG_BRANCH, 0,
lfsr_cat_frombranch(&rbyd_, &buf__[buf_size])); lfsr_cat_frombranch(&rbyd_, buf));
buf_size += LFSR_BRANCH_DSIZE;
if (rbyd_.weight != rbyd.weight) { if (rbyd_.weight != rbyd.weight) {
attrs__[attr_count++] = LFSR_ATTR( attrs__[attr_count++] = LFSR_ATTR(
LFSR_TAG_GROW, -rbyd.weight + rbyd_.weight, LFSR_TAG_GROW, -rbyd.weight + rbyd_.weight,
@@ -4762,58 +4788,65 @@ static int lfsr_btree_commit_(lfs_t *lfs, lfsr_btree_t *btree,
goto finalize; goto finalize;
} }
// prepare commit to parent, tail recursing upwards
LFS_ASSERT(rbyd_.weight > 0);
LFS_ASSERT(sibling.weight > 0);
attr_count = 0;
attr_scratch = LFSR_BTREE_COMMIT_ATTRS*sizeof(lfsr_attr_t);
// lookup first name in sibling to use as the split name // lookup first name in sibling to use as the split name
// //
// note we need to do this after playing out pending attrs in case // note we need to do this after playing out pending attrs in case
// they introduce a new name! // they introduce a new name!
lfsr_tag_t split_tag; lfsr_tag_t split_tag;
lfsr_data_t *split_data = lfsr_attr_scratchdata(
attrs__, &attr_scratch);
err = lfsr_rbyd_lookupnext(lfs, &sibling, 0, LFSR_TAG_NAME, err = lfsr_rbyd_lookupnext(lfs, &sibling, 0, LFSR_TAG_NAME,
NULL, &split_tag, NULL, &split_data__[0]); NULL, &split_tag, NULL, split_data);
if (err) { if (err) {
LFS_ASSERT(err != LFS_ERR_NOENT); LFS_ASSERT(err != LFS_ERR_NOENT);
return err; return err;
} }
// prepare commit to parent, tail recursing upwards
LFS_ASSERT(rbyd_.weight > 0);
LFS_ASSERT(sibling.weight > 0);
attr_count = 0;
buf_size = 0;
// new root? // new root?
if (!lfsr_rbyd_trunk(&parent)) { if (!lfsr_rbyd_trunk(&parent)) {
uint8_t *buf = lfsr_attr_scratch(attrs__, &attr_scratch,
LFSR_BRANCH_DSIZE);
attrs__[attr_count++] = LFSR_ATTR( attrs__[attr_count++] = LFSR_ATTR(
LFSR_TAG_BRANCH, +rbyd_.weight, LFSR_TAG_BRANCH, +rbyd_.weight,
lfsr_cat_frombranch(&rbyd_, &buf__[buf_size])); lfsr_cat_frombranch(&rbyd_, buf));
buf_size += LFSR_BRANCH_DSIZE; buf = lfsr_attr_scratch(attrs__, &attr_scratch,
LFSR_BRANCH_DSIZE);
attrs__[attr_count++] = LFSR_ATTR( attrs__[attr_count++] = LFSR_ATTR(
LFSR_TAG_BRANCH, +sibling.weight, LFSR_TAG_BRANCH, +sibling.weight,
lfsr_cat_frombranch(&sibling, &buf__[buf_size])); lfsr_cat_frombranch(&sibling, buf));
buf_size += LFSR_BRANCH_DSIZE;
if (lfsr_tag_suptype(split_tag) == LFSR_TAG_NAME) { if (lfsr_tag_suptype(split_tag) == LFSR_TAG_NAME) {
attrs__[attr_count++] = LFSR_ATTR( attrs__[attr_count++] = LFSR_ATTR(
LFSR_TAG_NAME, 0, LFSR_TAG_NAME, 0,
lfsr_cat_fromdatas(&split_data__[0], 1)); LFSR_CAT_DATA(split_data));
} }
// split root? // split root?
} else { } else {
bid -= pid - (rbyd.weight-1); bid -= pid - (rbyd.weight-1);
uint8_t *buf = lfsr_attr_scratch(attrs__, &attr_scratch,
LFSR_BRANCH_DSIZE);
attrs__[attr_count++] = LFSR_ATTR( attrs__[attr_count++] = LFSR_ATTR(
LFSR_TAG_BRANCH, 0, LFSR_TAG_BRANCH, 0,
lfsr_cat_frombranch(&rbyd_, &buf__[buf_size])); lfsr_cat_frombranch(&rbyd_, buf));
buf_size += LFSR_BRANCH_DSIZE;
if (rbyd_.weight != rbyd.weight) { if (rbyd_.weight != rbyd.weight) {
attrs__[attr_count++] = LFSR_ATTR( attrs__[attr_count++] = LFSR_ATTR(
LFSR_TAG_GROW, -rbyd.weight + rbyd_.weight, LFSR_TAG_GROW, -rbyd.weight + rbyd_.weight,
LFSR_CAT_NULL()); LFSR_CAT_NULL());
} }
buf = lfsr_attr_scratch(attrs__, &attr_scratch,
LFSR_BRANCH_DSIZE);
attrs__[attr_count++] = LFSR_ATTR( attrs__[attr_count++] = LFSR_ATTR(
LFSR_TAG_BRANCH, +sibling.weight, LFSR_TAG_BRANCH, +sibling.weight,
lfsr_cat_frombranch(&sibling, &buf__[buf_size])); lfsr_cat_frombranch(&sibling, buf));
buf_size += LFSR_BRANCH_DSIZE;
if (lfsr_tag_suptype(split_tag) == LFSR_TAG_NAME) { if (lfsr_tag_suptype(split_tag) == LFSR_TAG_NAME) {
attrs__[attr_count++] = LFSR_ATTR( attrs__[attr_count++] = LFSR_ATTR(
LFSR_TAG_NAME, 0, LFSR_TAG_NAME, 0,
lfsr_cat_fromdatas(&split_data__[0], 1)); LFSR_CAT_DATA(split_data));
} }
} }
attrs = attrs__; attrs = attrs__;
@@ -4876,14 +4909,15 @@ static int lfsr_btree_commit_(lfs_t *lfs, lfsr_btree_t *btree,
// prepare commit to parent, tail recursing upwards // prepare commit to parent, tail recursing upwards
LFS_ASSERT(rbyd_.weight > 0); LFS_ASSERT(rbyd_.weight > 0);
attr_count = 0; attr_count = 0;
buf_size = 0; attr_scratch = LFSR_BTREE_COMMIT_ATTRS*sizeof(lfsr_attr_t);
bid -= pid - (rbyd.weight-1); bid -= pid - (rbyd.weight-1);
attrs__[attr_count++] = LFSR_ATTR( attrs__[attr_count++] = LFSR_ATTR(
LFSR_TAG_RM, -sibling.weight, LFSR_CAT_NULL()); LFSR_TAG_RM, -sibling.weight, LFSR_CAT_NULL());
uint8_t *buf = lfsr_attr_scratch(attrs__, &attr_scratch,
LFSR_BRANCH_DSIZE);
attrs__[attr_count++] = LFSR_ATTR( attrs__[attr_count++] = LFSR_ATTR(
LFSR_TAG_BRANCH, 0, LFSR_TAG_BRANCH, 0,
lfsr_cat_frombranch(&rbyd_, &buf__[buf_size])); lfsr_cat_frombranch(&rbyd_, buf));
buf_size += LFSR_BRANCH_DSIZE;
if (rbyd_.weight != rbyd.weight) { if (rbyd_.weight != rbyd.weight) {
attrs__[attr_count++] = LFSR_ATTR( attrs__[attr_count++] = LFSR_ATTR(
LFSR_TAG_GROW, -rbyd.weight + rbyd_.weight, LFSR_TAG_GROW, -rbyd.weight + rbyd_.weight,
@@ -4900,15 +4934,11 @@ static int lfsr_btree_commit_(lfs_t *lfs, lfsr_btree_t *btree,
// this is atomic // this is atomic
static int lfsr_btree_commit(lfs_t *lfs, lfsr_btree_t *btree, static int lfsr_btree_commit(lfs_t *lfs, lfsr_btree_t *btree,
lfsr_bid_t bid, const lfsr_attr_t *attrs, lfs_size_t attr_count) { lfsr_bid_t bid, const lfsr_attr_t *attrs, lfs_size_t attr_count) {
// we need some scratch space for tail-recursive attrs
lfsr_attr_t attrs__[4];
uint8_t buffer[2*LFSR_BRANCH_DSIZE];
lfsr_data_t split_data__[1];
// try to commit to the btree // try to commit to the btree
lfsr_attr_t attrs__[LFSR_BTREE_COMMIT_ATTRS];
int err = lfsr_btree_commit_(lfs, btree, int err = lfsr_btree_commit_(lfs, btree,
&bid, &attrs, &attr_count, &bid, &attrs, &attr_count,
attrs__, buffer, split_data__); attrs__);
if (err && err != LFS_ERR_RANGE) { if (err && err != LFS_ERR_RANGE) {
return err; return err;
} }
@@ -5687,10 +5717,7 @@ static bool lfsr_mid_isopen(lfs_t *lfs, lfsr_smid_t mid) {
.u.mptr.weight=(LFSR_MTREE_ISMPTR | (_weight)), \ .u.mptr.weight=(LFSR_MTREE_ISMPTR | (_weight)), \
.u.mptr.mptr=_mptr}) .u.mptr.mptr=_mptr})
#define LFSR_MTREE_DSIZE ( \ #define LFSR_MTREE_DSIZE LFS_MAX(LFSR_MPTR_DSIZE, LFSR_BTREE_DSIZE)
(LFSR_MPTR_DSIZE > LFSR_BTREE_DSIZE) \
? LFSR_MPTR_DSIZE \
: LFSR_BTREE_DSIZE)
static inline bool lfsr_mtree_isnull(const lfsr_mtree_t *mtree) { static inline bool lfsr_mtree_isnull(const lfsr_mtree_t *mtree) {
return mtree->u.weight == (LFSR_MTREE_ISMPTR | 0); return mtree->u.weight == (LFSR_MTREE_ISMPTR | 0);
@@ -10153,15 +10180,11 @@ static int lfsr_bshrub_commit(lfs_t *lfs, lfsr_file_t *file,
} }
} }
// we need some scratch space for tail-recursive attrs
lfsr_attr_t attrs__[4];
uint8_t buffer[2*LFSR_BRANCH_DSIZE];
lfsr_data_t split_data__[1];
// try to commit to the btree // try to commit to the btree
lfsr_attr_t attrs__[LFSR_BTREE_COMMIT_ATTRS];
int err = lfsr_btree_commit_(lfs, &file->bshrub.u.btree, int err = lfsr_btree_commit_(lfs, &file->bshrub.u.btree,
&bid, &attrs, &attr_count, &bid, &attrs, &attr_count,
attrs__, buffer, split_data__); attrs__);
if (err && err != LFS_ERR_RANGE) { if (err && err != LFS_ERR_RANGE) {
return err; return err;
} }
@@ -10304,10 +10327,10 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
// try to merge commits where possible // try to merge commits where possible
lfsr_bid_t bid = lfsr_bshrub_size(&file->bshrub); lfsr_bid_t bid = lfsr_bshrub_size(&file->bshrub);
lfsr_attr_t attrs[5]; lfsr_attr_t attrs[5 + LFSR_ATTR_SCRATCH(
2*LFS_MAX(LFS_ALIGNEDSIZEOF(lfsr_data_t), LFSR_BPTR_DSIZE))];
lfs_size_t attr_count = 0; lfs_size_t attr_count = 0;
uint8_t buf[2*LFSR_BPTR_DSIZE]; lfs_size_t attr_scratch = sizeof(attrs);
lfs_size_t buf_size = 0;
// always convert to bshrub/btree when this function is called // always convert to bshrub/btree when this function is called
if (!lfsr_bshrub_isbshruborbtree(&file->bshrub)) { if (!lfsr_bshrub_isbshruborbtree(&file->bshrub)) {
@@ -10319,10 +10342,11 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
LFSR_TAG_DATA, +lfsr_bshrub_size(&file->bshrub), LFSR_TAG_DATA, +lfsr_bshrub_size(&file->bshrub),
LFSR_CAT_DATA(&file->bshrub.u.bsprout)); LFSR_CAT_DATA(&file->bshrub.u.bsprout));
} else if (lfsr_bshrub_isbptr(&file->m.mdir, &file->bshrub)) { } else if (lfsr_bshrub_isbptr(&file->m.mdir, &file->bshrub)) {
uint8_t *buf = lfsr_attr_scratch(attrs, &attr_scratch,
LFSR_BPTR_DSIZE);
attrs[attr_count++] = LFSR_ATTR( attrs[attr_count++] = LFSR_ATTR(
LFSR_TAG_BLOCK, +lfsr_bshrub_size(&file->bshrub), LFSR_TAG_BLOCK, +lfsr_bshrub_size(&file->bshrub),
lfsr_cat_frombptr(&file->bshrub.u.bptr, &buf[buf_size])); lfsr_cat_frombptr(&file->bshrub.u.bptr, buf));
buf_size += LFSR_BPTR_DSIZE;
} }
file->bshrub.u.bshrub.blocks[0] = file->m.mdir.rbyd.blocks[0]; file->bshrub.u.bshrub.blocks[0] = file->m.mdir.rbyd.blocks[0];
@@ -10332,8 +10356,7 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
file->bshrub.u.bshrub.estimate = -1; file->bshrub.u.bshrub.estimate = -1;
if (attr_count > 0) { if (attr_count > 0) {
LFS_ASSERT(attr_count <= sizeof(attrs)/sizeof(lfsr_attr_t)); LFS_ASSERT(attr_count*sizeof(lfsr_attr_t) <= attr_scratch);
LFS_ASSERT(buf_size <= sizeof(buf));
int err = lfsr_bshrub_commit(lfs, file, 0, attrs, attr_count); int err = lfsr_bshrub_commit(lfs, file, 0, attrs, attr_count);
if (err) { if (err) {
@@ -10342,7 +10365,7 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
} }
attr_count = 0; attr_count = 0;
buf_size = 0; attr_scratch = sizeof(attrs);
} }
// need a hole? // need a hole?
@@ -10367,9 +10390,6 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
lfsr_tag_t right_tag_ = 0; lfsr_tag_t right_tag_ = 0;
lfsr_bid_t right_weight_; lfsr_bid_t right_weight_;
lfsr_bptr_t right_bptr_; lfsr_bptr_t right_bptr_;
// TODO should we handle left/right slice/bptr differently? allocate
// from buf maybe?
lfsr_data_t left_slice_;
while (pos < lfsr_bshrub_size(&file->bshrub)) { while (pos < lfsr_bshrub_size(&file->bshrub)) {
lfsr_tag_t tag_; lfsr_tag_t tag_;
lfsr_bid_t weight_; lfsr_bid_t weight_;
@@ -10382,7 +10402,7 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
} }
// note, an entry can be both a left and right sibling // note, an entry can be both a left and right sibling
left_slice_ = lfsr_data_slice(bptr_.data, lfsr_data_t left_slice_ = lfsr_data_slice(bptr_.data,
-1, -1,
pos - (bid-(weight_-1))); pos - (bid-(weight_-1)));
lfsr_data_t right_slice_ = lfsr_data_slice(bptr_.data, lfsr_data_t right_slice_ = lfsr_data_slice(bptr_.data,
@@ -10458,13 +10478,18 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
// carve fragment? // carve fragment?
} else if (tag_ == LFSR_TAG_DATA) { } else if (tag_ == LFSR_TAG_DATA) {
lfsr_data_t *data = lfsr_attr_scratchdata(
attrs, &attr_scratch);
*data = left_slice_;
attrs[attr_count++] = LFSR_ATTR( attrs[attr_count++] = LFSR_ATTR(
LFSR_TAG_GROW | LFSR_TAG_SUB | LFSR_TAG_DATA, LFSR_TAG_GROW | LFSR_TAG_SUB | LFSR_TAG_DATA,
-(bid+1 - pos), -(bid+1 - pos),
LFSR_CAT_DATA(&left_slice_)); LFSR_CAT_DATA(data));
// carve bptr? // carve bptr?
} else if (tag_ == LFSR_TAG_BLOCK) { } else if (tag_ == LFSR_TAG_BLOCK) {
uint8_t *buf = lfsr_attr_scratch(attrs, &attr_scratch,
LFSR_BPTR_DSIZE);
attrs[attr_count++] = LFSR_ATTR( attrs[attr_count++] = LFSR_ATTR(
LFSR_TAG_GROW | LFSR_TAG_SUB | LFSR_TAG_BLOCK, LFSR_TAG_GROW | LFSR_TAG_SUB | LFSR_TAG_BLOCK,
-(bid+1 - pos), -(bid+1 - pos),
@@ -10473,8 +10498,7 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
.data = left_slice_, .data = left_slice_,
.cksize = bptr_.cksize, .cksize = bptr_.cksize,
.cksum = bptr_.cksum}, .cksum = bptr_.cksum},
&buf[buf_size])); buf));
buf_size += LFSR_BPTR_DSIZE;
} else { } else {
LFS_UNREACHABLE(); LFS_UNREACHABLE();
@@ -10490,8 +10514,7 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
// so commit what we have and move on to next entry // so commit what we have and move on to next entry
if (pos+weight > bid+1) { if (pos+weight > bid+1) {
LFS_ASSERT(lfsr_data_size(right_slice_) == 0); LFS_ASSERT(lfsr_data_size(right_slice_) == 0);
LFS_ASSERT(attr_count <= sizeof(attrs)/sizeof(lfsr_attr_t)); LFS_ASSERT(attr_count*sizeof(lfsr_attr_t) <= attr_scratch);
LFS_ASSERT(buf_size <= sizeof(buf));
err = lfsr_bshrub_commit(lfs, file, bid, err = lfsr_bshrub_commit(lfs, file, bid,
attrs, attr_count); attrs, attr_count);
@@ -10502,7 +10525,7 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
delta += lfs_min32(weight, bid+1 - pos); delta += lfs_min32(weight, bid+1 - pos);
weight -= lfs_min32(weight, bid+1 - pos); weight -= lfs_min32(weight, bid+1 - pos);
attr_count = 0; attr_count = 0;
buf_size = 0; attr_scratch = sizeof(attrs);
continue; continue;
} }
@@ -10564,16 +10587,19 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
if (right_tag_) { if (right_tag_) {
// right fragment? // right fragment?
if (right_tag_ == LFSR_TAG_DATA) { if (right_tag_ == LFSR_TAG_DATA) {
lfsr_data_t *data = lfsr_attr_scratchdata(attrs, &attr_scratch);
*data = right_bptr_.data;
attrs[attr_count++] = LFSR_ATTR( attrs[attr_count++] = LFSR_ATTR(
LFSR_TAG_DATA, +right_weight_, LFSR_TAG_DATA, +right_weight_,
LFSR_CAT_DATA(&right_bptr_.data)); LFSR_CAT_DATA(data));
// right bptr? // right bptr?
} else if (right_tag_ == LFSR_TAG_BLOCK) { } else if (right_tag_ == LFSR_TAG_BLOCK) {
uint8_t *buf = lfsr_attr_scratch(attrs, &attr_scratch,
LFSR_BPTR_DSIZE);
attrs[attr_count++] = LFSR_ATTR( attrs[attr_count++] = LFSR_ATTR(
LFSR_TAG_BLOCK, +right_weight_, LFSR_TAG_BLOCK, +right_weight_,
lfsr_cat_frombptr(&right_bptr_, &buf[buf_size])); lfsr_cat_frombptr(&right_bptr_, buf));
buf_size += LFSR_BPTR_DSIZE;
} else { } else {
LFS_UNREACHABLE(); LFS_UNREACHABLE();
@@ -10582,8 +10608,7 @@ static int lfsr_file_carve(lfs_t *lfs, lfsr_file_t *file,
// commit pending attrs // commit pending attrs
if (attr_count > 0) { if (attr_count > 0) {
LFS_ASSERT(attr_count <= sizeof(attrs)/sizeof(lfsr_attr_t)); LFS_ASSERT(attr_count*sizeof(lfsr_attr_t) <= attr_scratch);
LFS_ASSERT(buf_size <= sizeof(buf));
int err = lfsr_bshrub_commit(lfs, file, bid, int err = lfsr_bshrub_commit(lfs, file, bid,
attrs, attr_count); attrs, attr_count);
@@ -11399,17 +11424,16 @@ int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file) {
lfs_alloc_ckpoint(lfs); lfs_alloc_ckpoint(lfs);
// commit our file's metadata // commit our file's metadata
lfsr_attr_t attrs[2]; lfsr_attr_t attrs[2 + LFSR_ATTR_SCRATCH(
LFS_ALIGNEDSIZEOF(lfsr_data_t) + LFSR_BTREE_DSIZE)];
lfs_size_t attr_count = 0; lfs_size_t attr_count = 0;
uint8_t buf[LFSR_BTREE_DSIZE]; lfs_size_t attr_scratch = sizeof(attrs);
lfs_size_t buf_size = 0;
// TODO should we carve this out of buf?
lfsr_data_t data;
// not created yet? need to convert orphan to normal file // not created yet? need to convert orphan to normal file
if (lfsr_f_isorphan(file->m.flags)) { if (lfsr_f_isorphan(file->m.flags)) {
lfsr_data_t *data = lfsr_attr_scratchdata(attrs, &attr_scratch);
err = lfsr_mdir_lookup(lfs, &file->m.mdir, LFSR_TAG_ORPHAN, err = lfsr_mdir_lookup(lfs, &file->m.mdir, LFSR_TAG_ORPHAN,
&data); data);
if (err) { if (err) {
// we must have an orphan at this point // we must have an orphan at this point
LFS_ASSERT(err != LFS_ERR_NOENT); LFS_ASSERT(err != LFS_ERR_NOENT);
@@ -11418,7 +11442,7 @@ int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file) {
attrs[attr_count++] = LFSR_ATTR( attrs[attr_count++] = LFSR_ATTR(
LFSR_TAG_SUB | LFSR_TAG_REG, 0, LFSR_TAG_SUB | LFSR_TAG_REG, 0,
LFSR_CAT_DATA(&data)); LFSR_CAT_DATA(data));
} }
// commit the file state // commit the file state
@@ -11440,18 +11464,16 @@ int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file) {
&file->bshrub_.u.bshrub); &file->bshrub_.u.bshrub);
// btree? // btree?
} else if (lfsr_bshrub_isbtree(&file->m.mdir, &file->bshrub)) { } else if (lfsr_bshrub_isbtree(&file->m.mdir, &file->bshrub)) {
uint8_t *buf = lfsr_attr_scratch(attrs, &attr_scratch,
LFSR_BTREE_DSIZE);
attrs[attr_count++] = LFSR_ATTR( attrs[attr_count++] = LFSR_ATTR(
LFSR_TAG_SUB | LFSR_TAG_BTREE, 0, LFSR_TAG_SUB | LFSR_TAG_BTREE, 0,
lfsr_cat_frombtree( lfsr_cat_frombtree(&file->bshrub.u.btree, buf));
&file->bshrub.u.btree,
&buf[buf_size]));
buf_size += LFSR_BTREE_DSIZE;
} else { } else {
LFS_UNREACHABLE(); LFS_UNREACHABLE();
} }
LFS_ASSERT(attr_count <= sizeof(attrs)/sizeof(lfsr_attr_t)); LFS_ASSERT(attr_count*sizeof(lfsr_attr_t) <= attr_scratch);
LFS_ASSERT(buf_size <= sizeof(buf));
err = lfsr_mdir_commit(lfs, &file->m.mdir, err = lfsr_mdir_commit(lfs, &file->m.mdir,
attrs, attr_count); attrs, attr_count);
+22 -8
View File
@@ -142,16 +142,16 @@ extern "C"
// toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more // toolchain-specific implementations. LFS_NO_INTRINSICS falls back to a more
// expensive basic C implementation for debugging purposes // expensive basic C implementation for debugging purposes
// Min/max functions for unsigned 32-bit numbers // Compile time min/max
static inline uint32_t lfs_max(uint32_t a, uint32_t b) { #define LFS_MIN(a, b) ((a < b) ? a : b)
return (a > b) ? a : b; #define LFS_MAX(a, b) ((a > b) ? a : b)
}
// Min/max functions for unsigned 32-bit numbers
static inline uint32_t lfs_min(uint32_t a, uint32_t b) { static inline uint32_t lfs_min(uint32_t a, uint32_t b) {
return (a < b) ? a : b; return (a < b) ? a : b;
} }
static inline uint32_t lfs_max32(uint32_t a, uint32_t b) { static inline uint32_t lfs_max(uint32_t a, uint32_t b) {
return (a > b) ? a : b; return (a > b) ? a : b;
} }
@@ -159,7 +159,7 @@ static inline uint32_t lfs_min32(uint32_t a, uint32_t b) {
return (a < b) ? a : b; return (a < b) ? a : b;
} }
static inline int32_t lfs_smax32(int32_t a, int32_t b) { static inline uint32_t lfs_max32(uint32_t a, uint32_t b) {
return (a > b) ? a : b; return (a > b) ? a : b;
} }
@@ -167,15 +167,19 @@ static inline int32_t lfs_smin32(int32_t a, int32_t b) {
return (a < b) ? a : b; return (a < b) ? a : b;
} }
// TODO other 16-bit ops? static inline int32_t lfs_smax32(int32_t a, int32_t b) {
static inline uint16_t lfs_max16(uint16_t a, uint16_t b) {
return (a > b) ? a : b; return (a > b) ? a : b;
} }
// TODO other 16-bit ops?
static inline uint16_t lfs_min16(uint16_t a, uint16_t b) { static inline uint16_t lfs_min16(uint16_t a, uint16_t b) {
return (a < b) ? a : b; return (a < b) ? a : b;
} }
static inline uint16_t lfs_max16(uint16_t a, uint16_t b) {
return (a > b) ? a : b;
}
// Clamp is useful as the logic for min/max when clamping can become confusing // Clamp is useful as the logic for min/max when clamping can become confusing
static inline uint32_t lfs_clamp32(uint32_t a, uint32_t min, uint32_t max) { static inline uint32_t lfs_clamp32(uint32_t a, uint32_t min, uint32_t max) {
return lfs_min32(lfs_max32(a, min), max); return lfs_min32(lfs_max32(a, min), max);
@@ -217,6 +221,16 @@ static inline void lfs_sswap32(int32_t *a, int32_t *b) {
*b = t; *b = t;
} }
// Find alignment of a type at compile time
#if !defined(LFS_NO_INTRINSICS)
#define LFS_ALIGNOF(t) __alignof__(t)
#else
#define LFS_ALIGNOF(t) ((size_t)&((struct {char a; t b;}*)0)->b)
#endif
// Find size necessary to align type at compile time
#define LFS_ALIGNEDSIZEOF(t) (sizeof(t) + LFS_ALIGNOF(t)-1)
// Align to nearest multiple of a size // Align to nearest multiple of a size
static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) { static inline uint32_t lfs_aligndown(uint32_t a, uint32_t alignment) {
return a - (a % alignment); return a - (a % alignment);