Added LFS_O_SYNC, for implicit syncs during file writes
The motivation for this comes from the observation that many users call
sync on every file write. Much more than I expected. I think one reason
is in embedded systems it's common to just write structs to disk, either
the whole file or to a log.
O_SYNC exists in POSIX/Lunix/etc, so it makes sense to provide in
littlefs. In theory it's just one extra function call, and may even save
in total application cost (though we don't measure this) by reducing the
number of function calls at the application-level.
---
Unfortunately in-practice turned out to be quite a bit different than
in-theory... The main culprit being the improved guarantees around error
atomicity...
The ideal guarantee is that if there is an error during a write, the
entire write operation is reverted. Combining this with O_SYNC means we
need to hold a copy of the origin file state all thwe way through our
sync call. This got a bit messy...
The annoying part isn't even the functionality! Our system of tracking
btree/bshrub snapshots is quite robust! The problems were entirely with:
1. Figuring out how the heck to avoid clobbering the old file buffer
state.
2. Figuring out how the internal APIs should work while passing around a
bunch of staging state.
For 1., fortunately, thanks to bypassing writes, and some careful
pointer manipulation, we can void buffer clobbing. And for 2. just some
internal API work was needed. Internally all syncs end up in
lfsr_ftree_sync, though this feels a bit clumsy since the functionality
is not really ftree related...
Unfortunately, all of this added up to quite a bit more code cost than
I had hoped. In theory, adding some sort of LFS_CERAMIC/LFS_GLASS modes
that relax error atomicity for code size could help with most of this?
But it needs some thought:
code stack
before: 33324 3072
after: 33544 (+0.7%) 3072 (+0.0%)
This commit is contained in:
@@ -9241,6 +9241,10 @@ static inline bool lfsr_o_isappend(uint32_t flags) {
|
||||
return flags & LFS_O_APPEND;
|
||||
}
|
||||
|
||||
static inline bool lfsr_o_issync(uint32_t flags) {
|
||||
return flags & LFS_O_SYNC;
|
||||
}
|
||||
|
||||
static inline bool lfsr_o_isdesync(uint32_t flags) {
|
||||
return flags & LFS_O_DESYNC;
|
||||
}
|
||||
@@ -10454,6 +10458,74 @@ static int lfsr_ftree_flush(lfs_t *lfs, lfsr_ftree_t *ftree,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lfsr_ftree_sync(lfs_t *lfs, lfsr_ftree_t *ftree, bool unflushed,
|
||||
lfs_off_t buffer_pos, const uint8_t *buffer, lfs_size_t buffer_size) {
|
||||
// note because of small-file caching and our current write
|
||||
// strategy, we never actually end up with only a direct data
|
||||
// or bptr
|
||||
//
|
||||
// this is convenient because bptrs are a bit annoying to commit
|
||||
LFS_ASSERT(!lfsr_ftree_isbsprout(ftree));
|
||||
LFS_ASSERT(!lfsr_ftree_isbleaf(ftree));
|
||||
// small files should start as zero, const prop should optimize this out
|
||||
LFS_ASSERT(!unflushed || buffer_pos == 0);
|
||||
// small files/ftree should be exclusive here
|
||||
LFS_ASSERT(!unflushed || lfsr_ftree_size(ftree) == 0);
|
||||
// small files must be inlined entirely in our buffer
|
||||
LFS_ASSERT(!unflushed
|
||||
|| (buffer_size <= lfs->cfg->cache_size
|
||||
&& buffer_size <= lfs->cfg->inline_size
|
||||
&& buffer_size <= lfs->cfg->fragment_size));
|
||||
|
||||
// commit our file's metadata
|
||||
uint8_t buf[LFSR_BTREE_DSIZE];
|
||||
int err = lfsr_mdir_commit(lfs, &ftree->mdir, LFSR_ATTRS(
|
||||
(unflushed && buffer_size == 0)
|
||||
? LFSR_ATTR(ftree->mdir.mid,
|
||||
WIDE(RM(STRUCT)), 0,
|
||||
NULL())
|
||||
: (unflushed)
|
||||
? LFSR_ATTR(ftree->mdir.mid,
|
||||
WIDE(DATA), 0,
|
||||
BUF(buffer, buffer_size))
|
||||
: (lfsr_ftree_isbshrub(ftree))
|
||||
? LFSR_ATTR(ftree->mdir.mid,
|
||||
WIDE(SHRUBTRUNK), 0,
|
||||
SHRUBTRUNK(&ftree->u.bshrub))
|
||||
: LFSR_ATTR(ftree->mdir.mid,
|
||||
WIDE(BTREE), 0,
|
||||
FROMBTREE(&ftree->u.btree, buf))));
|
||||
if (err) {
|
||||
return err;
|
||||
}
|
||||
|
||||
// update other file handles
|
||||
for (lfsr_openedmdir_t *opened = lfs->opened[
|
||||
LFS_TYPE_REG-LFS_TYPE_REG];
|
||||
opened;
|
||||
opened = opened->next) {
|
||||
lfsr_file_t *file_ = (lfsr_file_t*)opened;
|
||||
if (file_->ftree.mdir.mid == ftree->mdir.mid
|
||||
// don't double update
|
||||
&& &file_->ftree != ftree
|
||||
// don't update desynced file handles
|
||||
&& !lfsr_o_isdesync(file_->flags)) {
|
||||
if (unflushed) {
|
||||
file_->size = buffer_size;
|
||||
} else {
|
||||
file_->size = lfsr_ftree_size(ftree);
|
||||
}
|
||||
file_->ftree.u = ftree->u;
|
||||
file_->buffer_pos = buffer_pos;
|
||||
LFS_ASSERT(buffer_size <= lfs->cfg->cache_size);
|
||||
memcpy(file_->buffer, buffer, buffer_size);
|
||||
file_->buffer_size = buffer_size;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// our high-level file operations
|
||||
|
||||
// needed in lfsr_file_read
|
||||
@@ -10567,9 +10639,9 @@ lfs_ssize_t lfsr_file_write(lfs_t *lfs, lfsr_file_t *file,
|
||||
}
|
||||
|
||||
// copy state so we can recover from errors
|
||||
lfs_off_t pos_ = file->pos;
|
||||
bool unflushed_ = lfsr_f_isunflushed(file->flags);
|
||||
lfs_off_t buffer_pos_ = file->buffer_pos;
|
||||
const uint8_t *buffer_ = file->buffer;
|
||||
lfs_size_t buffer_size_ = file->buffer_size;
|
||||
lfsr_ftree_t ftree_ = file->ftree;
|
||||
// add to tracked mdirs
|
||||
@@ -10580,24 +10652,25 @@ lfs_ssize_t lfsr_file_write(lfs_t *lfs, lfsr_file_t *file,
|
||||
lfs_alloc_ckpoint(lfs);
|
||||
|
||||
// update pos if we are appending
|
||||
lfs_off_t pos__ = file->pos;
|
||||
if (lfsr_o_isappend(file->flags)) {
|
||||
pos_ = file->size;
|
||||
pos__ = file->size;
|
||||
}
|
||||
|
||||
// if we're a small file, we may need to append zeros
|
||||
if (pos_ > file->size
|
||||
&& pos_ <= lfs->cfg->cache_size
|
||||
&& pos_ <= lfs->cfg->inline_size
|
||||
&& pos_ <= lfs->cfg->fragment_size) {
|
||||
if (pos__ > file->size
|
||||
&& pos__ <= lfs->cfg->cache_size
|
||||
&& pos__ <= lfs->cfg->inline_size
|
||||
&& pos__ <= lfs->cfg->fragment_size) {
|
||||
LFS_ASSERT(unflushed_);
|
||||
LFS_ASSERT(file->size == buffer_size_);
|
||||
memset(&file->buffer[buffer_size_],
|
||||
0,
|
||||
pos_ - buffer_size_);
|
||||
buffer_size_ = pos_;
|
||||
pos__ - buffer_size_);
|
||||
buffer_size_ = pos__;
|
||||
}
|
||||
|
||||
const uint8_t *buffer_ = buffer;
|
||||
const uint8_t *buffer__ = buffer;
|
||||
while (size > 0) {
|
||||
// bypass buffer?
|
||||
//
|
||||
@@ -10607,7 +10680,7 @@ lfs_ssize_t lfsr_file_write(lfs_t *lfs, lfsr_file_t *file,
|
||||
//
|
||||
if (!unflushed_ && size >= lfs->cfg->cache_size) {
|
||||
err = lfsr_ftree_flush(lfs, &ftree_,
|
||||
pos_, buffer_, size);
|
||||
pos__, buffer__, size);
|
||||
if (err) {
|
||||
goto failed;
|
||||
}
|
||||
@@ -10616,14 +10689,12 @@ lfs_ssize_t lfsr_file_write(lfs_t *lfs, lfsr_file_t *file,
|
||||
//
|
||||
// note we need to clear the buffer anyways to avoid any
|
||||
// out-of-date data
|
||||
memcpy(file->buffer,
|
||||
&buffer_[size - lfs->cfg->cache_size],
|
||||
lfs->cfg->cache_size);
|
||||
buffer_pos_ = pos_ + size - lfs->cfg->cache_size;
|
||||
buffer_pos_ = pos__ + size - lfs->cfg->cache_size;
|
||||
buffer_ = &buffer__[size - lfs->cfg->cache_size];
|
||||
buffer_size_ = lfs->cfg->cache_size;
|
||||
|
||||
pos_ += size;
|
||||
buffer_ += size;
|
||||
pos__ += size;
|
||||
buffer__ += size;
|
||||
size -= size;
|
||||
continue;
|
||||
}
|
||||
@@ -10639,57 +10710,101 @@ lfs_ssize_t lfsr_file_write(lfs_t *lfs, lfsr_file_t *file,
|
||||
// buffer once, and flush at most twice.
|
||||
//
|
||||
if (!unflushed_
|
||||
|| (pos_ >= buffer_pos_
|
||||
&& pos_ <= buffer_pos_ + buffer_size_
|
||||
&& pos_ < buffer_pos_ + lfs->cfg->cache_size)) {
|
||||
|| (pos__ >= buffer_pos_
|
||||
&& pos__ <= buffer_pos_ + buffer_size_
|
||||
&& pos__ < buffer_pos_ + lfs->cfg->cache_size)) {
|
||||
// unused buffer? we can move it where we need it
|
||||
lfs_size_t d;
|
||||
if (!unflushed_) {
|
||||
buffer_pos_ = pos_;
|
||||
buffer_size_ = 0;
|
||||
d = lfs_min32(
|
||||
size,
|
||||
lfs->cfg->cache_size);
|
||||
buffer_pos_ = pos__;
|
||||
buffer_ = buffer__;
|
||||
buffer_size_ = d;
|
||||
} else {
|
||||
d = lfs_min32(
|
||||
size,
|
||||
lfs->cfg->cache_size - (pos__ - buffer_pos_));
|
||||
LFS_ASSERT(file->buffer == buffer_);
|
||||
memcpy(&file->buffer[pos__ - buffer_pos_], buffer__, d);
|
||||
buffer_size_ = lfs_max32(
|
||||
buffer_size_,
|
||||
pos__+d - buffer_pos_);
|
||||
}
|
||||
|
||||
lfs_size_t d = lfs_min32(
|
||||
size,
|
||||
lfs->cfg->cache_size - (pos_ - buffer_pos_));
|
||||
memcpy(&file->buffer[pos_ - buffer_pos_], buffer_, d);
|
||||
buffer_size_ = lfs_max32(
|
||||
buffer_size_,
|
||||
pos_+d - buffer_pos_);
|
||||
|
||||
unflushed_ = true;
|
||||
pos_ += d;
|
||||
buffer_ += d;
|
||||
pos__ += d;
|
||||
buffer__ += d;
|
||||
size -= d;
|
||||
continue;
|
||||
}
|
||||
|
||||
// flush our buffer so the above can't fail
|
||||
err = lfsr_ftree_flush(lfs, &ftree_,
|
||||
buffer_pos_, file->buffer, buffer_size_);
|
||||
buffer_pos_, buffer_, buffer_size_);
|
||||
if (err) {
|
||||
goto failed;
|
||||
}
|
||||
unflushed_ = false;
|
||||
}
|
||||
|
||||
// sync if requested
|
||||
lfs_off_t size__ = lfs_max32(file->size, pos__);
|
||||
bool unsynced_ = true;
|
||||
if (lfsr_o_issync(file->flags)) {
|
||||
// syncing requires a flush for non-small files
|
||||
if (unflushed_ && !(
|
||||
size__ <= lfs->cfg->cache_size
|
||||
&& size__ <= lfs->cfg->inline_size
|
||||
&& size__ <= lfs->cfg->fragment_size)) {
|
||||
// flush
|
||||
err = lfsr_ftree_flush(lfs, &ftree_,
|
||||
buffer_pos_, buffer_, buffer_size_);
|
||||
if (err) {
|
||||
goto failed;
|
||||
}
|
||||
unflushed_ = false;
|
||||
}
|
||||
|
||||
// sync
|
||||
err = lfsr_ftree_sync(lfs, &ftree_, unflushed_,
|
||||
buffer_pos_, buffer_, buffer_size_);
|
||||
if (err) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
// mark as in-sync
|
||||
unsynced_ = false;
|
||||
file->flags &= ~LFS_O_DESYNC;
|
||||
}
|
||||
|
||||
// remove from tracked mdirs
|
||||
lfsr_mdir_removeopened(lfs, LFS_TYPE_REG, (lfsr_openedmdir_t*)&ftree_);
|
||||
// mark as unflushed and unsynced, update file, and return amount written
|
||||
lfs_size_t written;
|
||||
if (lfsr_o_isappend(file->flags)) {
|
||||
written = pos_ - file->size;
|
||||
written = pos__ - file->size;
|
||||
} else {
|
||||
written = pos_ - file->pos;
|
||||
written = pos__ - file->pos;
|
||||
}
|
||||
if (unsynced_) {
|
||||
file->flags |= LFS_F_UNSYNCED;
|
||||
} else {
|
||||
file->flags &= ~LFS_F_UNSYNCED;
|
||||
}
|
||||
file->flags |= LFS_F_UNSYNCED;
|
||||
if (unflushed_) {
|
||||
file->flags |= LFS_F_UNFLUSHED;
|
||||
} else {
|
||||
file->flags &= ~LFS_F_UNFLUSHED;
|
||||
}
|
||||
file->pos = pos_;
|
||||
file->size = lfs_max32(file->size, pos_);
|
||||
file->pos = pos__;
|
||||
file->size = size__;
|
||||
file->buffer_pos = buffer_pos_;
|
||||
if (buffer_ != file->buffer) {
|
||||
LFS_ASSERT(buffer_size_ <= lfs->cfg->cache_size);
|
||||
memcpy(file->buffer, buffer_, buffer_size_);
|
||||
}
|
||||
file->buffer_size = buffer_size_;
|
||||
file->ftree.u = ftree_.u;
|
||||
return written;
|
||||
@@ -10799,66 +10914,20 @@ int lfsr_file_sync(lfs_t *lfs, lfsr_file_t *file) {
|
||||
// checkpoint the allocator again
|
||||
lfs_alloc_ckpoint(lfs);
|
||||
|
||||
// note because of small-file caching and our current write
|
||||
// strategy, we never actually end up with only a direct data
|
||||
// or bptr
|
||||
//
|
||||
// this is convenient because bpts are a bit annoying to commit
|
||||
LFS_ASSERT(!lfsr_ftree_isbsprout(&file->ftree));
|
||||
LFS_ASSERT(!lfsr_ftree_isbleaf(&file->ftree));
|
||||
// if this invariant breaks something has gone horribly wrong
|
||||
LFS_ASSERT(file->size == lfs_max32(
|
||||
file->buffer_pos + file->buffer_size,
|
||||
lfsr_ftree_size(&file->ftree)));
|
||||
// small files must be inlined entirely in our buffer
|
||||
LFS_ASSERT(!(file->size <= lfs->cfg->cache_size
|
||||
&& file->size <= lfs->cfg->inline_size
|
||||
&& file->size <= lfs->cfg->fragment_size)
|
||||
|| file->size == file->buffer_size);
|
||||
|
||||
// commit our file's metadata
|
||||
uint8_t buf[LFSR_BTREE_DSIZE];
|
||||
err = lfsr_mdir_commit(lfs, &file->ftree.mdir, LFSR_ATTRS(
|
||||
(file->size == 0)
|
||||
? LFSR_ATTR(file->ftree.mdir.mid,
|
||||
WIDE(RM(STRUCT)), 0,
|
||||
NULL())
|
||||
: (file->size <= lfs->cfg->cache_size
|
||||
&& file->size <= lfs->cfg->inline_size
|
||||
&& file->size <= lfs->cfg->fragment_size)
|
||||
? LFSR_ATTR(file->ftree.mdir.mid,
|
||||
WIDE(DATA), 0,
|
||||
BUF(file->buffer, file->size))
|
||||
: (lfsr_ftree_isbshrub(&file->ftree))
|
||||
? LFSR_ATTR(file->ftree.mdir.mid,
|
||||
WIDE(SHRUBTRUNK), 0,
|
||||
SHRUBTRUNK(&file->ftree.u.bshrub))
|
||||
: LFSR_ATTR(file->ftree.mdir.mid,
|
||||
WIDE(BTREE), 0,
|
||||
FROMBTREE(&file->ftree.u.btree, buf))));
|
||||
err = lfsr_ftree_sync(lfs, &file->ftree, lfsr_f_isunflushed(file->flags),
|
||||
file->buffer_pos, file->buffer, file->buffer_size);
|
||||
if (err) {
|
||||
goto failed;
|
||||
}
|
||||
|
||||
// mark as synced
|
||||
file->flags &= ~LFS_F_UNSYNCED & ~LFS_O_DESYNC;
|
||||
// update other file handles
|
||||
for (lfsr_openedmdir_t *opened = lfs->opened[
|
||||
LFS_TYPE_REG-LFS_TYPE_REG];
|
||||
opened;
|
||||
opened = opened->next) {
|
||||
lfsr_file_t *file_ = (lfsr_file_t*)opened;
|
||||
if (file_->ftree.mdir.mid == file->ftree.mdir.mid
|
||||
// don't update desynced file handles
|
||||
&& !lfsr_o_isdesync(file_->flags)) {
|
||||
file_->size = file->size;
|
||||
file_->ftree.u = file->ftree.u;
|
||||
file_->buffer_pos = file->buffer_pos;
|
||||
memcpy(file_->buffer, file->buffer, file->buffer_size);
|
||||
file_->buffer_size = file->buffer_size;
|
||||
}
|
||||
}
|
||||
|
||||
// mark as in-sync
|
||||
file->flags &= ~LFS_O_SYNC & ~LFS_O_DESYNC;
|
||||
return 0;
|
||||
|
||||
failed:;
|
||||
|
||||
@@ -162,7 +162,8 @@ enum lfs_open_flags {
|
||||
LFS_O_EXCL = 0x0200, // Fail if a file already exists
|
||||
LFS_O_TRUNC = 0x0400, // Truncate the existing file to zero size
|
||||
LFS_O_APPEND = 0x0800, // Move to end of file on every write
|
||||
LFS_O_DESYNC = 0x1000, // Do not sync or recieve file updates
|
||||
LFS_O_SYNC = 0x1000, // Sync metadata on every write
|
||||
LFS_O_DESYNC = 0x2000, // Do not sync or recieve file updates
|
||||
#endif
|
||||
|
||||
// internally used flags
|
||||
|
||||
+90
-42
@@ -116,7 +116,8 @@ code = '''
|
||||
defines.R = 4
|
||||
# 0 => no sync, readers not updated
|
||||
# 1 => sync via lfsr_file_sync
|
||||
defines.SYNC = [0, 1]
|
||||
# 2 => sync via LFS_O_SYNC
|
||||
defines.SYNC = [0, 1, 2]
|
||||
defines.SIZE = [
|
||||
'0',
|
||||
'CACHE_SIZE/2',
|
||||
@@ -151,7 +152,8 @@ code = '''
|
||||
// write 1 handle, read R handles in parallel
|
||||
lfsr_file_t writer;
|
||||
lfsr_file_t readers[R];
|
||||
lfsr_file_open(&lfs, &writer, "jello", LFS_O_WRONLY) => 0;
|
||||
lfsr_file_open(&lfs, &writer, "jello",
|
||||
LFS_O_WRONLY | ((SYNC == 2) ? LFS_O_SYNC : 0)) => 0;
|
||||
for (lfs_size_t r = 0; r < R; r++) {
|
||||
lfsr_file_open(&lfs, &readers[r], "jello", LFS_O_RDONLY) => 0;
|
||||
}
|
||||
@@ -162,7 +164,7 @@ code = '''
|
||||
}
|
||||
lfsr_file_write(&lfs, &writer, wbuf, CHUNK) => CHUNK;
|
||||
memcpy(&after[i], wbuf, CHUNK);
|
||||
if (SYNC != 0) {
|
||||
if (SYNC == 1) {
|
||||
lfsr_file_sync(&lfs, &writer) => 0;
|
||||
}
|
||||
|
||||
@@ -195,7 +197,8 @@ code = '''
|
||||
defines.R = 4
|
||||
# 0 => no sync, readers not updated
|
||||
# 1 => sync via lfsr_file_sync
|
||||
defines.SYNC = [0, 1]
|
||||
# 2 => sync via LFS_O_SYNC
|
||||
defines.SYNC = [0, 1, 2]
|
||||
defines.SEED = 'range(10)'
|
||||
defines.N = 20
|
||||
defines.SIZE = [
|
||||
@@ -232,7 +235,8 @@ code = '''
|
||||
// write 1 handle, read R handles in parallel
|
||||
lfsr_file_t writer;
|
||||
lfsr_file_t readers[R];
|
||||
lfsr_file_open(&lfs, &writer, "jello", LFS_O_WRONLY) => 0;
|
||||
lfsr_file_open(&lfs, &writer, "jello",
|
||||
LFS_O_WRONLY | ((SYNC == 2) ? LFS_O_SYNC : 0)) => 0;
|
||||
for (lfs_size_t r = 0; r < R; r++) {
|
||||
lfsr_file_open(&lfs, &readers[r], "jello", LFS_O_RDONLY) => 0;
|
||||
}
|
||||
@@ -249,7 +253,7 @@ code = '''
|
||||
}
|
||||
lfsr_file_write(&lfs, &writer, wbuf, size) => size;
|
||||
memcpy(&after[off], wbuf, size);
|
||||
if (SYNC != 0) {
|
||||
if (SYNC == 1) {
|
||||
lfsr_file_sync(&lfs, &writer) => 0;
|
||||
}
|
||||
|
||||
@@ -289,7 +293,8 @@ code = '''
|
||||
defines.W = 4
|
||||
# 0 => no sync, readers not updated
|
||||
# 1 => sync via lfsr_file_sync
|
||||
defines.SYNC = [0, 1]
|
||||
# 2 => sync via LFS_O_SYNC
|
||||
defines.SYNC = [0, 1, 2]
|
||||
defines.SIZE = [
|
||||
'0',
|
||||
'CACHE_SIZE/2',
|
||||
@@ -324,7 +329,8 @@ code = '''
|
||||
// write W handles in parallel
|
||||
lfsr_file_t writers[W];
|
||||
for (lfs_size_t w = 0; w < W; w++) {
|
||||
lfsr_file_open(&lfs, &writers[w], "jello", LFS_O_WRONLY) => 0;
|
||||
lfsr_file_open(&lfs, &writers[w], "jello",
|
||||
LFS_O_WRONLY | ((SYNC == 2) ? LFS_O_SYNC : 0)) => 0;
|
||||
}
|
||||
for (lfs_size_t i = 0; i < SIZE; i += CHUNK) {
|
||||
for (lfs_size_t w = 0; w < W; w++) {
|
||||
@@ -338,7 +344,9 @@ code = '''
|
||||
memcpy(&after[i], wbuf, CHUNK);
|
||||
}
|
||||
} else {
|
||||
lfsr_file_sync(&lfs, &writers[w]) => 0;
|
||||
if (SYNC == 1) {
|
||||
lfsr_file_sync(&lfs, &writers[w]) => 0;
|
||||
}
|
||||
memcpy(&after[i], wbuf, CHUNK);
|
||||
}
|
||||
}
|
||||
@@ -361,7 +369,8 @@ code = '''
|
||||
defines.W = 4
|
||||
# 0 => no sync, readers not updated
|
||||
# 1 => sync via lfsr_file_sync
|
||||
defines.SYNC = [0, 1]
|
||||
# 2 => sync via LFS_O_SYNC
|
||||
defines.SYNC = [0, 1, 2]
|
||||
defines.SEED = 'range(10)'
|
||||
defines.N = 20
|
||||
defines.SIZE = [
|
||||
@@ -398,7 +407,8 @@ code = '''
|
||||
// write W files in parallel
|
||||
lfsr_file_t writers[W];
|
||||
for (lfs_size_t w = 0; w < W; w++) {
|
||||
lfsr_file_open(&lfs, &writers[w], "jello", LFS_O_WRONLY) => 0;
|
||||
lfsr_file_open(&lfs, &writers[w], "jello",
|
||||
LFS_O_WRONLY | ((SYNC == 2) ? LFS_O_SYNC : 0)) => 0;
|
||||
}
|
||||
for (lfs_size_t i = 0; i < SIZE; i += CHUNK) {
|
||||
for (lfs_size_t w = 0; w < W; w++) {
|
||||
@@ -418,7 +428,9 @@ code = '''
|
||||
memcpy(&after[off], wbuf, size);
|
||||
}
|
||||
} else {
|
||||
lfsr_file_sync(&lfs, &writers[w]) => 0;
|
||||
if (SYNC == 1) {
|
||||
lfsr_file_sync(&lfs, &writers[w]) => 0;
|
||||
}
|
||||
memcpy(&after[off], wbuf, size);
|
||||
}
|
||||
}
|
||||
@@ -443,7 +455,8 @@ defines.W = 4
|
||||
defines.R = 4
|
||||
# 0 => no sync, readers not updated
|
||||
# 1 => sync via lfsr_file_sync
|
||||
defines.SYNC = [0, 1]
|
||||
# 2 => sync via LFS_O_SYNC
|
||||
defines.SYNC = [0, 1, 2]
|
||||
defines.SIZE = [
|
||||
'0',
|
||||
'CACHE_SIZE/2',
|
||||
@@ -479,7 +492,8 @@ code = '''
|
||||
lfsr_file_t writers[W];
|
||||
lfsr_file_t readers[R];
|
||||
for (lfs_size_t w = 0; w < W; w++) {
|
||||
lfsr_file_open(&lfs, &writers[w], "jello", LFS_O_WRONLY) => 0;
|
||||
lfsr_file_open(&lfs, &writers[w], "jello",
|
||||
LFS_O_WRONLY | ((SYNC == 2) ? LFS_O_SYNC : 0)) => 0;
|
||||
}
|
||||
for (lfs_size_t r = 0; r < R; r++) {
|
||||
lfsr_file_open(&lfs, &readers[r], "jello", LFS_O_RDONLY) => 0;
|
||||
@@ -496,7 +510,9 @@ code = '''
|
||||
memcpy(&after[i], wbuf, CHUNK);
|
||||
}
|
||||
} else {
|
||||
lfsr_file_sync(&lfs, &writers[w]) => 0;
|
||||
if (SYNC == 1) {
|
||||
lfsr_file_sync(&lfs, &writers[w]) => 0;
|
||||
}
|
||||
memcpy(&after[i], wbuf, CHUNK);
|
||||
}
|
||||
}
|
||||
@@ -532,7 +548,8 @@ defines.W = 4
|
||||
defines.R = 4
|
||||
# 0 => no sync, readers not updated
|
||||
# 1 => sync via lfsr_file_sync
|
||||
defines.SYNC = [0, 1]
|
||||
# 2 => sync via LFS_O_SYNC
|
||||
defines.SYNC = [0, 1, 2]
|
||||
defines.SEED = 'range(10)'
|
||||
defines.N = 20
|
||||
defines.SIZE = [
|
||||
@@ -570,7 +587,8 @@ code = '''
|
||||
lfsr_file_t writers[W];
|
||||
lfsr_file_t readers[R];
|
||||
for (lfs_size_t w = 0; w < W; w++) {
|
||||
lfsr_file_open(&lfs, &writers[w], "jello", LFS_O_WRONLY) => 0;
|
||||
lfsr_file_open(&lfs, &writers[w], "jello",
|
||||
LFS_O_WRONLY | ((SYNC == 2) ? LFS_O_SYNC : 0)) => 0;
|
||||
}
|
||||
for (lfs_size_t r = 0; r < R; r++) {
|
||||
lfsr_file_open(&lfs, &readers[r], "jello", LFS_O_RDONLY) => 0;
|
||||
@@ -593,7 +611,9 @@ code = '''
|
||||
memcpy(&after[off], wbuf, size);
|
||||
}
|
||||
} else {
|
||||
lfsr_file_sync(&lfs, &writers[w]) => 0;
|
||||
if (SYNC == 1) {
|
||||
lfsr_file_sync(&lfs, &writers[w]) => 0;
|
||||
}
|
||||
memcpy(&after[off], wbuf, size);
|
||||
}
|
||||
}
|
||||
@@ -635,7 +655,8 @@ code = '''
|
||||
defines.RW = 4
|
||||
# 0 => no sync, readers not updated
|
||||
# 1 => sync via lfsr_file_sync
|
||||
defines.SYNC = [0, 1]
|
||||
# 2 => sync via LFS_O_SYNC
|
||||
defines.SYNC = [0, 1, 2]
|
||||
defines.SIZE = [
|
||||
'0',
|
||||
'CACHE_SIZE/2',
|
||||
@@ -674,7 +695,8 @@ code = '''
|
||||
// write RW rdwrs in parallel
|
||||
lfsr_file_t rdwrs[RW];
|
||||
for (lfs_size_t rw = 0; rw < RW; rw++) {
|
||||
lfsr_file_open(&lfs, &rdwrs[rw], "jello", LFS_O_RDWR) => 0;
|
||||
lfsr_file_open(&lfs, &rdwrs[rw], "jello",
|
||||
LFS_O_RDWR | ((SYNC == 2) ? LFS_O_SYNC : 0)) => 0;
|
||||
}
|
||||
for (lfs_size_t i = 0; i < SIZE; i += CHUNK) {
|
||||
for (lfs_size_t rw = 0; rw < RW; rw++) {
|
||||
@@ -690,7 +712,9 @@ code = '''
|
||||
memcpy(&after[i], wbuf, CHUNK);
|
||||
}
|
||||
} else {
|
||||
lfsr_file_sync(&lfs, &rdwrs[rw]) => 0;
|
||||
if (SYNC == 1) {
|
||||
lfsr_file_sync(&lfs, &rdwrs[rw]) => 0;
|
||||
}
|
||||
memcpy(&after[i], wbuf, CHUNK);
|
||||
}
|
||||
}
|
||||
@@ -723,7 +747,8 @@ code = '''
|
||||
defines.RW = 4
|
||||
# 0 => no sync, readers not updated
|
||||
# 1 => sync via lfsr_file_sync
|
||||
defines.SYNC = [0, 1]
|
||||
# 2 => sync via LFS_O_SYNC
|
||||
defines.SYNC = [0, 1, 2]
|
||||
defines.SEED = 'range(10)'
|
||||
defines.N = 20
|
||||
defines.SIZE = [
|
||||
@@ -764,7 +789,8 @@ code = '''
|
||||
// write RW rdwrs in parallel
|
||||
lfsr_file_t rdwrs[RW];
|
||||
for (lfs_size_t rw = 0; rw < RW; rw++) {
|
||||
lfsr_file_open(&lfs, &rdwrs[rw], "jello", LFS_O_RDWR) => 0;
|
||||
lfsr_file_open(&lfs, &rdwrs[rw], "jello",
|
||||
LFS_O_RDWR | ((SYNC == 2) ? LFS_O_SYNC : 0)) => 0;
|
||||
}
|
||||
for (lfs_size_t i = 0; i < SIZE; i += CHUNK) {
|
||||
for (lfs_size_t rw = 0; rw < RW; rw++) {
|
||||
@@ -785,7 +811,9 @@ code = '''
|
||||
memcpy(&after[off], wbuf, size);
|
||||
}
|
||||
} else {
|
||||
lfsr_file_sync(&lfs, &rdwrs[rw]) => 0;
|
||||
if (SYNC == 1) {
|
||||
lfsr_file_sync(&lfs, &rdwrs[rw]) => 0;
|
||||
}
|
||||
memcpy(&after[off], wbuf, size);
|
||||
}
|
||||
}
|
||||
@@ -827,7 +855,8 @@ code = '''
|
||||
defines.R = 4
|
||||
# 0 => no sync, readers not updated
|
||||
# 1 => sync via lfsr_file_sync
|
||||
defines.SYNC = [0, 1]
|
||||
# 2 => sync via LFS_O_SYNC
|
||||
defines.SYNC = [0, 1, 2]
|
||||
defines.SIZE = [
|
||||
'0',
|
||||
'CACHE_SIZE/2',
|
||||
@@ -863,7 +892,9 @@ code = '''
|
||||
lfsr_file_t writer;
|
||||
lfsr_file_t readers[R];
|
||||
lfsr_file_open(&lfs, &writer, "jello",
|
||||
LFS_O_WRONLY | LFS_O_DESYNC) => 0;
|
||||
LFS_O_WRONLY
|
||||
| LFS_O_DESYNC
|
||||
| ((SYNC == 2) ? LFS_O_SYNC : 0)) => 0;
|
||||
for (lfs_size_t r = 0; r < R; r++) {
|
||||
lfsr_file_open(&lfs, &readers[r], "jello", LFS_O_RDONLY) => 0;
|
||||
}
|
||||
@@ -874,7 +905,7 @@ code = '''
|
||||
}
|
||||
lfsr_file_write(&lfs, &writer, wbuf, CHUNK) => CHUNK;
|
||||
memcpy(&after[i], wbuf, CHUNK);
|
||||
if (SYNC != 0) {
|
||||
if (SYNC == 1) {
|
||||
lfsr_file_sync(&lfs, &writer) => 0;
|
||||
}
|
||||
|
||||
@@ -911,7 +942,8 @@ code = '''
|
||||
defines.R = 4
|
||||
# 0 => no sync, readers not updated
|
||||
# 1 => sync via lfsr_file_sync
|
||||
defines.SYNC = [0, 1]
|
||||
# 2 => sync via LFS_O_SYNC
|
||||
defines.SYNC = [0, 1, 2]
|
||||
defines.SEED = 'range(10)'
|
||||
defines.N = 20
|
||||
defines.SIZE = [
|
||||
@@ -949,7 +981,9 @@ code = '''
|
||||
lfsr_file_t writer;
|
||||
lfsr_file_t readers[R];
|
||||
lfsr_file_open(&lfs, &writer, "jello",
|
||||
LFS_O_WRONLY | LFS_O_DESYNC) => 0;
|
||||
LFS_O_WRONLY
|
||||
| LFS_O_DESYNC
|
||||
| ((SYNC == 2) ? LFS_O_SYNC : 0)) => 0;
|
||||
for (lfs_size_t r = 0; r < R; r++) {
|
||||
lfsr_file_open(&lfs, &readers[r], "jello", LFS_O_RDONLY) => 0;
|
||||
}
|
||||
@@ -966,7 +1000,7 @@ code = '''
|
||||
}
|
||||
lfsr_file_write(&lfs, &writer, wbuf, size) => size;
|
||||
memcpy(&after[off], wbuf, size);
|
||||
if (SYNC != 0) {
|
||||
if (SYNC == 1) {
|
||||
lfsr_file_sync(&lfs, &writer) => 0;
|
||||
}
|
||||
|
||||
@@ -1010,7 +1044,8 @@ code = '''
|
||||
defines.R = 4
|
||||
# 0 => no sync, readers not updated
|
||||
# 1 => sync via lfsr_file_sync
|
||||
defines.SYNC = [0, 1]
|
||||
# 2 => sync via LFS_O_SYNC
|
||||
defines.SYNC = [0, 1, 2]
|
||||
defines.SIZE = [
|
||||
'0',
|
||||
'CACHE_SIZE/2',
|
||||
@@ -1045,7 +1080,8 @@ code = '''
|
||||
// write 1 handle, read R handles in parallel
|
||||
lfsr_file_t writer;
|
||||
lfsr_file_t readers[R];
|
||||
lfsr_file_open(&lfs, &writer, "jello", LFS_O_WRONLY) => 0;
|
||||
lfsr_file_open(&lfs, &writer, "jello",
|
||||
LFS_O_WRONLY | ((SYNC == 2) ? LFS_O_SYNC : 0)) => 0;
|
||||
for (lfs_size_t r = 0; r < R; r++) {
|
||||
lfsr_file_open(&lfs, &readers[r], "jello",
|
||||
LFS_O_RDONLY | LFS_O_DESYNC) => 0;
|
||||
@@ -1057,7 +1093,7 @@ code = '''
|
||||
}
|
||||
lfsr_file_write(&lfs, &writer, wbuf, CHUNK) => CHUNK;
|
||||
memcpy(&after[i], wbuf, CHUNK);
|
||||
if (SYNC != 0) {
|
||||
if (SYNC == 1) {
|
||||
lfsr_file_sync(&lfs, &writer) => 0;
|
||||
}
|
||||
|
||||
@@ -1086,7 +1122,8 @@ code = '''
|
||||
defines.R = 4
|
||||
# 0 => no sync, readers not updated
|
||||
# 1 => sync via lfsr_file_sync
|
||||
defines.SYNC = [0, 1]
|
||||
# 2 => sync via LFS_O_SYNC
|
||||
defines.SYNC = [0, 1, 2]
|
||||
defines.SEED = 'range(10)'
|
||||
defines.N = 20
|
||||
defines.SIZE = [
|
||||
@@ -1123,7 +1160,8 @@ code = '''
|
||||
// write 1 handle, read R handles in parallel
|
||||
lfsr_file_t writer;
|
||||
lfsr_file_t readers[R];
|
||||
lfsr_file_open(&lfs, &writer, "jello", LFS_O_WRONLY) => 0;
|
||||
lfsr_file_open(&lfs, &writer, "jello",
|
||||
LFS_O_WRONLY | ((SYNC == 2) ? LFS_O_SYNC : 0)) => 0;
|
||||
for (lfs_size_t r = 0; r < R; r++) {
|
||||
lfsr_file_open(&lfs, &readers[r], "jello",
|
||||
LFS_O_RDONLY | LFS_O_DESYNC) => 0;
|
||||
@@ -1141,7 +1179,7 @@ code = '''
|
||||
}
|
||||
lfsr_file_write(&lfs, &writer, wbuf, size) => size;
|
||||
memcpy(&after[off], wbuf, size);
|
||||
if (SYNC != 0) {
|
||||
if (SYNC == 1) {
|
||||
lfsr_file_sync(&lfs, &writer) => 0;
|
||||
}
|
||||
|
||||
@@ -1177,7 +1215,8 @@ code = '''
|
||||
defines.RW = 4
|
||||
# 0 => no sync, readers not updated
|
||||
# 1 => sync via lfsr_file_sync
|
||||
defines.SYNC = [0, 1]
|
||||
# 2 => sync via LFS_O_SYNC
|
||||
defines.SYNC = [0, 1, 2]
|
||||
defines.SIZE = [
|
||||
'0',
|
||||
'CACHE_SIZE/2',
|
||||
@@ -1217,7 +1256,9 @@ code = '''
|
||||
lfsr_file_t rdwrs[RW];
|
||||
for (lfs_size_t rw = 0; rw < RW; rw++) {
|
||||
lfsr_file_open(&lfs, &rdwrs[rw], "jello",
|
||||
LFS_O_RDWR | LFS_O_DESYNC) => 0;
|
||||
LFS_O_RDWR
|
||||
| LFS_O_DESYNC
|
||||
| ((SYNC == 2) ? LFS_O_SYNC : 0)) => 0;
|
||||
}
|
||||
for (lfs_size_t i = 0; i < SIZE; i += CHUNK) {
|
||||
for (lfs_size_t rw = 0; rw < RW; rw++) {
|
||||
@@ -1233,7 +1274,9 @@ code = '''
|
||||
memcpy(&after[i], wbuf, CHUNK);
|
||||
}
|
||||
} else {
|
||||
lfsr_file_sync(&lfs, &rdwrs[rw]) => 0;
|
||||
if (SYNC == 1) {
|
||||
lfsr_file_sync(&lfs, &rdwrs[rw]) => 0;
|
||||
}
|
||||
if (i == 0) {
|
||||
memcpy(after, between[rw], SIZE);
|
||||
} else {
|
||||
@@ -1274,7 +1317,8 @@ code = '''
|
||||
defines.RW = 4
|
||||
# 0 => no sync, readers not updated
|
||||
# 1 => sync via lfsr_file_sync
|
||||
defines.SYNC = [0, 1]
|
||||
# 2 => sync via LFS_O_SYNC
|
||||
defines.SYNC = [0, 1, 2]
|
||||
defines.SEED = 'range(10)'
|
||||
defines.N = 20
|
||||
defines.SIZE = [
|
||||
@@ -1316,7 +1360,9 @@ code = '''
|
||||
lfsr_file_t rdwrs[RW];
|
||||
for (lfs_size_t rw = 0; rw < RW; rw++) {
|
||||
lfsr_file_open(&lfs, &rdwrs[rw], "jello",
|
||||
LFS_O_RDWR | LFS_O_DESYNC) => 0;
|
||||
LFS_O_RDWR
|
||||
| LFS_O_DESYNC
|
||||
| ((SYNC == 2) ? LFS_O_SYNC : 0)) => 0;
|
||||
}
|
||||
for (lfs_size_t i = 0; i < SIZE; i += CHUNK) {
|
||||
for (lfs_size_t rw = 0; rw < RW; rw++) {
|
||||
@@ -1337,7 +1383,9 @@ code = '''
|
||||
memcpy(&after[off], wbuf, size);
|
||||
}
|
||||
} else {
|
||||
lfsr_file_sync(&lfs, &rdwrs[rw]) => 0;
|
||||
if (SYNC == 1) {
|
||||
lfsr_file_sync(&lfs, &rdwrs[rw]) => 0;
|
||||
}
|
||||
if (i == 0) {
|
||||
memcpy(after, between[rw], SIZE);
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user