Decomposed lfsr_bptr_t in lfsr_file_flush_ until the last minute
This breaks down the in-progress lfsr_bptr_t in lfsr_file_flush_ into
its components (block, off, eoff, cksum), until right before we write it
to disk.
This may seem counterproductive. Some paths, such as block appends,
start with an lfsr_bptr_t, but breaking it down this way avoids the
lfsr_bptr_t encoding noise and gives the compiler a better chance to
optimize things.
The end result is a nice bit of code/stack savings, and a slightly more
readable function:
code stack ctx
before: 36320 2584 640
after: 36304 (-0.0%) 2576 (-0.3%) 640 (+0.0%)
This commit is contained in:
@@ -11544,7 +11544,11 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
lfs_off_t crystal_start = pos;
|
lfs_off_t crystal_start = pos;
|
||||||
lfs_off_t crystal_end = pos + size;
|
lfs_off_t crystal_end = pos + size;
|
||||||
lfs_off_t block_start;
|
lfs_off_t block_start;
|
||||||
lfsr_bptr_t bptr;
|
lfs_off_t block_end;
|
||||||
|
lfs_sblock_t block;
|
||||||
|
lfs_size_t off;
|
||||||
|
lfs_size_t eoff;
|
||||||
|
uint32_t cksum;
|
||||||
|
|
||||||
// within our tree? find left crystal neighbor
|
// within our tree? find left crystal neighbor
|
||||||
if (pos > 0
|
if (pos > 0
|
||||||
@@ -11556,6 +11560,7 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
&& !aligned) {
|
&& !aligned) {
|
||||||
lfsr_bid_t bid;
|
lfsr_bid_t bid;
|
||||||
lfsr_bid_t weight;
|
lfsr_bid_t weight;
|
||||||
|
lfsr_bptr_t bptr;
|
||||||
int err = lfsr_file_lookupnext(lfs, file,
|
int err = lfsr_file_lookupnext(lfs, file,
|
||||||
lfs_smax(pos - (lfs->cfg->crystal_thresh-1), 0),
|
lfs_smax(pos - (lfs->cfg->crystal_thresh-1), 0),
|
||||||
&bid, &weight, &bptr);
|
&bid, &weight, &bptr);
|
||||||
@@ -11595,6 +11600,11 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
|
|
||||||
// try to use erased-state
|
// try to use erased-state
|
||||||
block_start = bid-(weight-1);
|
block_start = bid-(weight-1);
|
||||||
|
block_end = block_start + lfsr_data_size(bptr.data);
|
||||||
|
block = bptr.data.u.disk.block;
|
||||||
|
off = bptr.data.u.disk.off;
|
||||||
|
eoff = lfsr_bptr_cksize(&bptr);
|
||||||
|
cksum = lfsr_bptr_cksum(&bptr);
|
||||||
goto compact;
|
goto compact;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -11606,6 +11616,7 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
&& file->b.shrub.weight > 0) {
|
&& file->b.shrub.weight > 0) {
|
||||||
lfsr_bid_t bid;
|
lfsr_bid_t bid;
|
||||||
lfsr_bid_t weight;
|
lfsr_bid_t weight;
|
||||||
|
lfsr_bptr_t bptr;
|
||||||
int err = lfsr_file_lookupnext(lfs, file,
|
int err = lfsr_file_lookupnext(lfs, file,
|
||||||
lfs_min(
|
lfs_min(
|
||||||
crystal_start + (lfs->cfg->crystal_thresh-1),
|
crystal_start + (lfs->cfg->crystal_thresh-1),
|
||||||
@@ -11650,6 +11661,7 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
&& !aligned) {
|
&& !aligned) {
|
||||||
lfsr_bid_t bid;
|
lfsr_bid_t bid;
|
||||||
lfsr_bid_t weight;
|
lfsr_bid_t weight;
|
||||||
|
lfsr_bptr_t bptr;
|
||||||
int err = lfsr_file_lookupnext(lfs, file,
|
int err = lfsr_file_lookupnext(lfs, file,
|
||||||
lfs_min(
|
lfs_min(
|
||||||
crystal_start-1,
|
crystal_start-1,
|
||||||
@@ -11679,6 +11691,11 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
file->eoff = -1;
|
file->eoff = -1;
|
||||||
|
|
||||||
// try to use erased-state
|
// try to use erased-state
|
||||||
|
block_end = block_start + lfsr_data_size(bptr.data);
|
||||||
|
block = bptr.data.u.disk.block;
|
||||||
|
off = bptr.data.u.disk.off;
|
||||||
|
eoff = lfsr_bptr_cksize(&bptr);
|
||||||
|
cksum = lfsr_bptr_cksum(&bptr);
|
||||||
goto compact;
|
goto compact;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11696,45 +11713,45 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
//
|
//
|
||||||
// note if we relocate, we rewrite the entire block from block_start
|
// note if we relocate, we rewrite the entire block from block_start
|
||||||
// using what we can find in our tree
|
// using what we can find in our tree
|
||||||
lfs_sblock_t block = lfs_alloc(lfs, true);
|
block = lfs_alloc(lfs, true);
|
||||||
if (block < 0) {
|
if (block < 0) {
|
||||||
return block;
|
return block;
|
||||||
}
|
}
|
||||||
|
|
||||||
lfsr_bptr_init(&bptr, LFSR_DATA_DISK(block, 0, 0), 0, 0);
|
block_end = block_start;
|
||||||
|
off = 0;
|
||||||
|
eoff = 0;
|
||||||
|
cksum = 0;
|
||||||
|
|
||||||
compact:;
|
compact:;
|
||||||
// compact data into our block
|
// compact data into our block
|
||||||
//
|
//
|
||||||
// eagerly merge any right neighbors we see unless that would
|
// eagerly merge any right neighbors we see unless that would
|
||||||
// put us over our block size
|
// put us over our block size
|
||||||
lfs_off_t pos_ = block_start + lfsr_data_size(bptr.data);
|
while (block_end < lfs_min(
|
||||||
while (pos_ < lfs_min(
|
|
||||||
block_start
|
block_start
|
||||||
+ (lfs->cfg->block_size - bptr.data.u.disk.off),
|
+ (lfs->cfg->block_size - off),
|
||||||
lfs_max(
|
lfs_max(
|
||||||
pos + size,
|
pos + size,
|
||||||
file->b.shrub.weight))) {
|
file->b.shrub.weight))) {
|
||||||
// keep track of the next highest priority data offset
|
// keep track of the next highest priority data offset
|
||||||
lfs_ssize_t d = lfs_min(
|
lfs_ssize_t d = lfs_min(
|
||||||
block_start
|
block_start
|
||||||
+ (lfs->cfg->block_size - bptr.data.u.disk.off),
|
+ (lfs->cfg->block_size - off),
|
||||||
lfs_max(
|
lfs_max(
|
||||||
pos + size,
|
pos + size,
|
||||||
file->b.shrub.weight)) - pos_;
|
file->b.shrub.weight)) - block_end;
|
||||||
|
|
||||||
// any data in our buffer?
|
// any data in our buffer?
|
||||||
if (pos_ < pos + size && size > 0) {
|
if (block_end < pos + size && size > 0) {
|
||||||
if (pos_ >= pos) {
|
if (block_end >= pos) {
|
||||||
lfs_ssize_t d_ = lfs_min(
|
lfs_ssize_t d_ = lfs_min(
|
||||||
d,
|
d,
|
||||||
size - (pos_ - pos));
|
size - (block_end - pos));
|
||||||
int err = lfsr_bd_prog(lfs, bptr.data.u.disk.block,
|
int err = lfsr_bd_prog(lfs, block,
|
||||||
lfsr_bptr_cksize(&bptr),
|
eoff,
|
||||||
&buffer[pos_ - pos], d_,
|
&buffer[block_end - pos], d_,
|
||||||
LFS_IFDEF_CKDATACKSUMS(
|
&cksum, true);
|
||||||
&bptr.data.u.disk.cksum,
|
|
||||||
&bptr.cksum), true);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||||
// bad prog? try another block
|
// bad prog? try another block
|
||||||
@@ -11744,23 +11761,21 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
pos_ += d_;
|
block_end += d_;
|
||||||
LFS_IFDEF_CKDATACKSUMS(
|
eoff += d_;
|
||||||
bptr.data.u.disk.cksize,
|
|
||||||
bptr.cksize) += d_;
|
|
||||||
d -= d_;
|
d -= d_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// buffered data takes priority
|
// buffered data takes priority
|
||||||
d = lfs_min(d, pos - pos_);
|
d = lfs_min(d, pos - block_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
// any data on disk?
|
// any data on disk?
|
||||||
if (pos_ < file->b.shrub.weight) {
|
if (block_end < file->b.shrub.weight) {
|
||||||
lfsr_bid_t bid_;
|
lfsr_bid_t bid_;
|
||||||
lfsr_bid_t weight_;
|
lfsr_bid_t weight_;
|
||||||
lfsr_bptr_t bptr_;
|
lfsr_bptr_t bptr_;
|
||||||
int err = lfsr_file_lookupnext(lfs, file, pos_,
|
int err = lfsr_file_lookupnext(lfs, file, block_end,
|
||||||
&bid_, &weight_, &bptr_);
|
&bid_, &weight_, &bptr_);
|
||||||
if (err) {
|
if (err) {
|
||||||
LFS_ASSERT(err != LFS_ERR_NOENT);
|
LFS_ASSERT(err != LFS_ERR_NOENT);
|
||||||
@@ -11783,7 +11798,7 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
if (bid_-(weight_-1) >= crystal_end
|
if (bid_-(weight_-1) >= crystal_end
|
||||||
// is this data a pure hole? stop early to better
|
// is this data a pure hole? stop early to better
|
||||||
// leverage erased-state in sparse files
|
// leverage erased-state in sparse files
|
||||||
&& (pos_ >= bid_-(weight_-1)
|
&& (block_end >= bid_-(weight_-1)
|
||||||
+ lfsr_data_size(bptr_.data)
|
+ lfsr_data_size(bptr_.data)
|
||||||
// does this data exceed our block_size?
|
// does this data exceed our block_size?
|
||||||
// stop early to try to avoid messing up
|
// stop early to try to avoid messing up
|
||||||
@@ -11794,21 +11809,20 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pos_ < bid_-(weight_-1) + lfsr_data_size(bptr_.data)) {
|
if (block_end
|
||||||
|
< bid_-(weight_-1) + lfsr_data_size(bptr_.data)) {
|
||||||
// note one important side-effect here is a strict
|
// note one important side-effect here is a strict
|
||||||
// data hint
|
// data hint
|
||||||
lfs_ssize_t d_ = lfs_min(
|
lfs_ssize_t d_ = lfs_min(
|
||||||
d,
|
d,
|
||||||
lfsr_data_size(bptr_.data)
|
lfsr_data_size(bptr_.data)
|
||||||
- (pos_ - (bid_-(weight_-1))));
|
- (block_end - (bid_-(weight_-1))));
|
||||||
err = lfsr_bd_progdata(lfs, bptr.data.u.disk.block,
|
err = lfsr_bd_progdata(lfs, block,
|
||||||
lfsr_bptr_cksize(&bptr),
|
eoff,
|
||||||
LFSR_DATA_SLICE(bptr_.data,
|
LFSR_DATA_SLICE(bptr_.data,
|
||||||
pos_ - (bid_-(weight_-1)),
|
block_end - (bid_-(weight_-1)),
|
||||||
d_),
|
d_),
|
||||||
LFS_IFDEF_CKDATACKSUMS(
|
&cksum, true);
|
||||||
&bptr.data.u.disk.cksum,
|
|
||||||
&bptr.cksum), true);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||||
// bad prog? try another block
|
// bad prog? try another block
|
||||||
@@ -11818,24 +11832,20 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
pos_ += d_;
|
block_end += d_;
|
||||||
LFS_IFDEF_CKDATACKSUMS(
|
eoff += d_;
|
||||||
bptr.data.u.disk.cksize,
|
|
||||||
bptr.cksize) += d_;
|
|
||||||
d -= d_;
|
d -= d_;
|
||||||
}
|
}
|
||||||
|
|
||||||
// found a hole? just make sure next leaf takes priority
|
// found a hole? just make sure next leaf takes priority
|
||||||
d = lfs_min(d, bid_+1 - pos_);
|
d = lfs_min(d, bid_+1 - block_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
// found a hole? fill with zeros
|
// found a hole? fill with zeros
|
||||||
int err = lfsr_bd_set(lfs,
|
int err = lfsr_bd_set(lfs, block,
|
||||||
bptr.data.u.disk.block, lfsr_bptr_cksize(&bptr),
|
eoff,
|
||||||
0, d,
|
0, d,
|
||||||
LFS_IFDEF_CKDATACKSUMS(
|
&cksum, true);
|
||||||
&bptr.data.u.disk.cksum,
|
|
||||||
&bptr.cksum), true);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
LFS_ASSERT(err != LFS_ERR_RANGE);
|
LFS_ASSERT(err != LFS_ERR_RANGE);
|
||||||
// bad prog? try another block
|
// bad prog? try another block
|
||||||
@@ -11845,27 +11855,22 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
pos_ += d;
|
block_end += d;
|
||||||
LFS_IFDEF_CKDATACKSUMS(
|
eoff += d;
|
||||||
bptr.data.u.disk.cksize,
|
|
||||||
bptr.cksize) += d;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A bit of a hack here, we need to truncate our block to prog_size
|
// A bit of a hack here, we need to truncate our block to prog_size
|
||||||
// alignment to avoid padding issues. Doing this retroactively to
|
// alignment to avoid padding issues. Doing this retroactively to
|
||||||
// the pcache greatly simplifies the above loop, though we may end
|
// the pcache greatly simplifies the above loop, though we may end
|
||||||
// up reading more than is strictly necessary.
|
// up reading more than is strictly necessary.
|
||||||
lfs_ssize_t d = lfsr_bptr_cksize(&bptr) % lfs->cfg->prog_size;
|
lfs_ssize_t d = eoff % lfs->cfg->prog_size;
|
||||||
lfs->pcache.size -= d;
|
lfs->pcache.size -= d;
|
||||||
LFS_IFDEF_CKDATACKSUMS(
|
block_end -= d;
|
||||||
bptr.data.u.disk.cksize,
|
eoff -= d;
|
||||||
bptr.cksize) -= d;
|
|
||||||
|
|
||||||
// finalize our write
|
// finalize our write
|
||||||
int err = lfsr_bd_flush(lfs,
|
int err = lfsr_bd_flush(lfs,
|
||||||
LFS_IFDEF_CKDATACKSUMS(
|
&cksum, true);
|
||||||
&bptr.data.u.disk.cksum,
|
|
||||||
&bptr.cksum), true);
|
|
||||||
if (err) {
|
if (err) {
|
||||||
// bad prog? try another block
|
// bad prog? try another block
|
||||||
if (err == LFS_ERR_CORRUPT) {
|
if (err == LFS_ERR_CORRUPT) {
|
||||||
@@ -11875,16 +11880,15 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// prepare our block pointer
|
// prepare our block pointer
|
||||||
LFS_ASSERT(lfsr_bptr_cksize(&bptr) > 0);
|
LFS_ASSERT(eoff > 0);
|
||||||
LFS_ASSERT(lfsr_bptr_cksize(&bptr) <= lfs->cfg->block_size);
|
LFS_ASSERT(eoff <= lfs->cfg->block_size);
|
||||||
|
lfsr_bptr_t bptr;
|
||||||
lfsr_bptr_init(&bptr,
|
lfsr_bptr_init(&bptr,
|
||||||
LFSR_DATA_DISK(
|
LFSR_DATA_DISK(
|
||||||
bptr.data.u.disk.block,
|
block,
|
||||||
bptr.data.u.disk.off,
|
off,
|
||||||
lfsr_bptr_cksize(&bptr) - bptr.data.u.disk.off),
|
eoff - off),
|
||||||
lfsr_bptr_cksize(&bptr),
|
eoff, cksum);
|
||||||
lfsr_bptr_cksum(&bptr));
|
|
||||||
lfs_off_t block_end = block_start + lfsr_data_size(bptr.data);
|
|
||||||
|
|
||||||
// and write it into our tree
|
// and write it into our tree
|
||||||
uint8_t bptr_buf[LFSR_BPTR_DSIZE];
|
uint8_t bptr_buf[LFSR_BPTR_DSIZE];
|
||||||
@@ -11898,9 +11902,9 @@ static int lfsr_file_flush_(lfs_t *lfs, lfsr_file_t *file,
|
|||||||
}
|
}
|
||||||
|
|
||||||
// keep track of any remaining erased-state
|
// keep track of any remaining erased-state
|
||||||
if (lfsr_bptr_cksize(&bptr) < lfs->cfg->block_size) {
|
if (eoff < lfs->cfg->block_size) {
|
||||||
file->eblock = bptr.data.u.disk.block;
|
file->eblock = block;
|
||||||
file->eoff = lfsr_bptr_cksize(&bptr);
|
file->eoff = eoff;
|
||||||
}
|
}
|
||||||
|
|
||||||
// note compacting fragments -> blocks may not actually make any
|
// note compacting fragments -> blocks may not actually make any
|
||||||
|
|||||||
Reference in New Issue
Block a user