Files
littlefs/tests/test_exhaustion.toml
T
Christopher Haster 4ff7c1f771 Commenting out outdated functions for now
This makes it easier to evaluate the code/stack/etc sizes and run tests
without bringing in all of the outdated code.

I guess this officially makes this branch more-or-less a full rewrite,
though the benefit of commenting vs deleting this code is that it can be
easily pulled back in when useful.
2023-06-16 01:51:29 -05:00

506 lines
17 KiB
TOML

## test running a filesystem to exhaustion
#[cases.test_exhaustion_normal]
#defines.ERASE_CYCLES = 10
#defines.BLOCK_COUNT = 256 # small bd so test runs faster
#defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2'
#defines.BADBLOCK_BEHAVIOR = [
# 'LFS_EMUBD_BADBLOCK_PROGERROR',
# 'LFS_EMUBD_BADBLOCK_ERASEERROR',
# 'LFS_EMUBD_BADBLOCK_READERROR',
# 'LFS_EMUBD_BADBLOCK_PROGNOOP',
# 'LFS_EMUBD_BADBLOCK_ERASENOOP',
#]
#defines.FILES = 10
#code = '''
# lfs_t lfs;
# lfs_format(&lfs, cfg) => 0;
# lfs_mount(&lfs, cfg) => 0;
# lfs_mkdir(&lfs, "roadrunner") => 0;
# lfs_unmount(&lfs) => 0;
#
# uint32_t cycle = 0;
# while (true) {
# lfs_mount(&lfs, cfg) => 0;
# for (uint32_t i = 0; i < FILES; i++) {
# // chose name, roughly random seed, and random 2^n size
# char path[1024];
# sprintf(path, "roadrunner/test%d", i);
# uint32_t prng = cycle * i;
# lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
#
# lfs_file_t file;
# lfs_file_open(&lfs, &file, path,
# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
#
# for (lfs_size_t j = 0; j < size; j++) {
# char c = 'a' + (TEST_PRNG(&prng) % 26);
# lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
# assert(res == 1 || res == LFS_ERR_NOSPC);
# if (res == LFS_ERR_NOSPC) {
# int err = lfs_file_close(&lfs, &file);
# assert(err == 0 || err == LFS_ERR_NOSPC);
# lfs_unmount(&lfs) => 0;
# goto exhausted;
# }
# }
#
# int err = lfs_file_close(&lfs, &file);
# assert(err == 0 || err == LFS_ERR_NOSPC);
# if (err == LFS_ERR_NOSPC) {
# lfs_unmount(&lfs) => 0;
# goto exhausted;
# }
# }
#
# for (uint32_t i = 0; i < FILES; i++) {
# // check for errors
# char path[1024];
# sprintf(path, "roadrunner/test%d", i);
# uint32_t prng = cycle * i;
# lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
#
# lfs_file_t file;
# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
# for (lfs_size_t j = 0; j < size; j++) {
# char c = 'a' + (TEST_PRNG(&prng) % 26);
# char r;
# lfs_file_read(&lfs, &file, &r, 1) => 1;
# assert(r == c);
# }
#
# lfs_file_close(&lfs, &file) => 0;
# }
# lfs_unmount(&lfs) => 0;
#
# cycle += 1;
# }
#
#exhausted:
# // should still be readable
# lfs_mount(&lfs, cfg) => 0;
# for (uint32_t i = 0; i < FILES; i++) {
# // check for errors
# char path[1024];
# sprintf(path, "roadrunner/test%d", i);
# struct lfs_info info;
# lfs_stat(&lfs, path, &info) => 0;
# }
# lfs_unmount(&lfs) => 0;
#
# LFS_WARN("completed %d cycles", cycle);
#'''
#
## test running a filesystem to exhaustion
## which also requires expanding superblocks
#[cases.test_exhaustion_superblocks]
#defines.ERASE_CYCLES = 10
#defines.BLOCK_COUNT = 256 # small bd so test runs faster
#defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2'
#defines.BADBLOCK_BEHAVIOR = [
# 'LFS_EMUBD_BADBLOCK_PROGERROR',
# 'LFS_EMUBD_BADBLOCK_ERASEERROR',
# 'LFS_EMUBD_BADBLOCK_READERROR',
# 'LFS_EMUBD_BADBLOCK_PROGNOOP',
# 'LFS_EMUBD_BADBLOCK_ERASENOOP',
#]
#defines.FILES = 10
#code = '''
# lfs_t lfs;
# lfs_format(&lfs, cfg) => 0;
#
# uint32_t cycle = 0;
# while (true) {
# lfs_mount(&lfs, cfg) => 0;
# for (uint32_t i = 0; i < FILES; i++) {
# // chose name, roughly random seed, and random 2^n size
# char path[1024];
# sprintf(path, "test%d", i);
# uint32_t prng = cycle * i;
# lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
#
# lfs_file_t file;
# lfs_file_open(&lfs, &file, path,
# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
#
# for (lfs_size_t j = 0; j < size; j++) {
# char c = 'a' + (TEST_PRNG(&prng) % 26);
# lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
# assert(res == 1 || res == LFS_ERR_NOSPC);
# if (res == LFS_ERR_NOSPC) {
# int err = lfs_file_close(&lfs, &file);
# assert(err == 0 || err == LFS_ERR_NOSPC);
# lfs_unmount(&lfs) => 0;
# goto exhausted;
# }
# }
#
# int err = lfs_file_close(&lfs, &file);
# assert(err == 0 || err == LFS_ERR_NOSPC);
# if (err == LFS_ERR_NOSPC) {
# lfs_unmount(&lfs) => 0;
# goto exhausted;
# }
# }
#
# for (uint32_t i = 0; i < FILES; i++) {
# // check for errors
# char path[1024];
# sprintf(path, "test%d", i);
# uint32_t prng = cycle * i;
# lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
#
# lfs_file_t file;
# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
# for (lfs_size_t j = 0; j < size; j++) {
# char c = 'a' + (TEST_PRNG(&prng) % 26);
# char r;
# lfs_file_read(&lfs, &file, &r, 1) => 1;
# assert(r == c);
# }
#
# lfs_file_close(&lfs, &file) => 0;
# }
# lfs_unmount(&lfs) => 0;
#
# cycle += 1;
# }
#
#exhausted:
# // should still be readable
# lfs_mount(&lfs, cfg) => 0;
# for (uint32_t i = 0; i < FILES; i++) {
# // check for errors
# char path[1024];
# struct lfs_info info;
# sprintf(path, "test%d", i);
# lfs_stat(&lfs, path, &info) => 0;
# }
# lfs_unmount(&lfs) => 0;
#
# LFS_WARN("completed %d cycles", cycle);
#'''
#
## These are a sort of high-level litmus test for wear-leveling. One definition
## of wear-leveling is that increasing a block device's space translates directly
## into increasing the block devices lifetime. This is something we can actually
## check for.
#
## wear-level test running a filesystem to exhaustion
#[cases.test_exhuastion_wear_leveling]
#defines.ERASE_CYCLES = 20
#defines.BLOCK_COUNT = 256 # small bd so test runs faster
#defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2'
#defines.FILES = 10
#code = '''
# uint32_t run_cycles[2];
# const uint32_t run_block_count[2] = {BLOCK_COUNT/2, BLOCK_COUNT};
#
# for (int run = 0; run < 2; run++) {
# for (lfs_block_t b = 0; b < BLOCK_COUNT; b++) {
# lfs_emubd_setwear(cfg, b,
# (b < run_block_count[run]) ? 0 : ERASE_CYCLES) => 0;
# }
#
# lfs_t lfs;
# lfs_format(&lfs, cfg) => 0;
# lfs_mount(&lfs, cfg) => 0;
# lfs_mkdir(&lfs, "roadrunner") => 0;
# lfs_unmount(&lfs) => 0;
#
# uint32_t cycle = 0;
# while (true) {
# lfs_mount(&lfs, cfg) => 0;
# for (uint32_t i = 0; i < FILES; i++) {
# // chose name, roughly random seed, and random 2^n size
# char path[1024];
# sprintf(path, "roadrunner/test%d", i);
# uint32_t prng = cycle * i;
# lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
#
# lfs_file_t file;
# lfs_file_open(&lfs, &file, path,
# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
#
# for (lfs_size_t j = 0; j < size; j++) {
# char c = 'a' + (TEST_PRNG(&prng) % 26);
# lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
# assert(res == 1 || res == LFS_ERR_NOSPC);
# if (res == LFS_ERR_NOSPC) {
# int err = lfs_file_close(&lfs, &file);
# assert(err == 0 || err == LFS_ERR_NOSPC);
# lfs_unmount(&lfs) => 0;
# goto exhausted;
# }
# }
#
# int err = lfs_file_close(&lfs, &file);
# assert(err == 0 || err == LFS_ERR_NOSPC);
# if (err == LFS_ERR_NOSPC) {
# lfs_unmount(&lfs) => 0;
# goto exhausted;
# }
# }
#
# for (uint32_t i = 0; i < FILES; i++) {
# // check for errors
# char path[1024];
# sprintf(path, "roadrunner/test%d", i);
# uint32_t prng = cycle * i;
# lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
#
# lfs_file_t file;
# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
# for (lfs_size_t j = 0; j < size; j++) {
# char c = 'a' + (TEST_PRNG(&prng) % 26);
# char r;
# lfs_file_read(&lfs, &file, &r, 1) => 1;
# assert(r == c);
# }
#
# lfs_file_close(&lfs, &file) => 0;
# }
# lfs_unmount(&lfs) => 0;
#
# cycle += 1;
# }
#
#exhausted:
# // should still be readable
# lfs_mount(&lfs, cfg) => 0;
# for (uint32_t i = 0; i < FILES; i++) {
# // check for errors
# char path[1024];
# struct lfs_info info;
# sprintf(path, "roadrunner/test%d", i);
# lfs_stat(&lfs, path, &info) => 0;
# }
# lfs_unmount(&lfs) => 0;
#
# run_cycles[run] = cycle;
# LFS_WARN("completed %d blocks %d cycles",
# run_block_count[run], run_cycles[run]);
# }
#
# // check we increased the lifetime by 2x with ~10% error
# LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]);
#'''
#
## wear-level test + expanding superblock
#[cases.test_exhaustion_wear_leveling_superblocks]
#defines.ERASE_CYCLES = 20
#defines.BLOCK_COUNT = 256 # small bd so test runs faster
#defines.BLOCK_CYCLES = 'ERASE_CYCLES / 2'
#defines.FILES = 10
#code = '''
# uint32_t run_cycles[2];
# const uint32_t run_block_count[2] = {BLOCK_COUNT/2, BLOCK_COUNT};
#
# for (int run = 0; run < 2; run++) {
# for (lfs_block_t b = 0; b < BLOCK_COUNT; b++) {
# lfs_emubd_setwear(cfg, b,
# (b < run_block_count[run]) ? 0 : ERASE_CYCLES) => 0;
# }
#
# lfs_t lfs;
# lfs_format(&lfs, cfg) => 0;
#
# uint32_t cycle = 0;
# while (true) {
# lfs_mount(&lfs, cfg) => 0;
# for (uint32_t i = 0; i < FILES; i++) {
# // chose name, roughly random seed, and random 2^n size
# char path[1024];
# sprintf(path, "test%d", i);
# uint32_t prng = cycle * i;
# lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
#
# lfs_file_t file;
# lfs_file_open(&lfs, &file, path,
# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
#
# for (lfs_size_t j = 0; j < size; j++) {
# char c = 'a' + (TEST_PRNG(&prng) % 26);
# lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
# assert(res == 1 || res == LFS_ERR_NOSPC);
# if (res == LFS_ERR_NOSPC) {
# int err = lfs_file_close(&lfs, &file);
# assert(err == 0 || err == LFS_ERR_NOSPC);
# lfs_unmount(&lfs) => 0;
# goto exhausted;
# }
# }
#
# int err = lfs_file_close(&lfs, &file);
# assert(err == 0 || err == LFS_ERR_NOSPC);
# if (err == LFS_ERR_NOSPC) {
# lfs_unmount(&lfs) => 0;
# goto exhausted;
# }
# }
#
# for (uint32_t i = 0; i < FILES; i++) {
# // check for errors
# char path[1024];
# sprintf(path, "test%d", i);
# uint32_t prng = cycle * i;
# lfs_size_t size = 1 << ((TEST_PRNG(&prng) % 10)+2);
#
# lfs_file_t file;
# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
# for (lfs_size_t j = 0; j < size; j++) {
# char c = 'a' + (TEST_PRNG(&prng) % 26);
# char r;
# lfs_file_read(&lfs, &file, &r, 1) => 1;
# assert(r == c);
# }
#
# lfs_file_close(&lfs, &file) => 0;
# }
# lfs_unmount(&lfs) => 0;
#
# cycle += 1;
# }
#
#exhausted:
# // should still be readable
# lfs_mount(&lfs, cfg) => 0;
# for (uint32_t i = 0; i < FILES; i++) {
# // check for errors
# char path[1024];
# struct lfs_info info;
# sprintf(path, "test%d", i);
# lfs_stat(&lfs, path, &info) => 0;
# }
# lfs_unmount(&lfs) => 0;
#
# run_cycles[run] = cycle;
# LFS_WARN("completed %d blocks %d cycles",
# run_block_count[run], run_cycles[run]);
# }
#
# // check we increased the lifetime by 2x with ~10% error
# LFS_ASSERT(run_cycles[1]*110/100 > 2*run_cycles[0]);
#'''
#
## test that we wear blocks roughly evenly
#[cases.test_exhaustion_wear_distribution]
#defines.ERASE_CYCLES = 0xffffffff
#defines.BLOCK_COUNT = 256 # small bd so test runs faster
#defines.BLOCK_CYCLES = [5, 4, 3, 2, 1]
#defines.CYCLES = 100
#defines.FILES = 10
#if = 'BLOCK_CYCLES < CYCLES/10'
#code = '''
# lfs_t lfs;
# lfs_format(&lfs, cfg) => 0;
# lfs_mount(&lfs, cfg) => 0;
# lfs_mkdir(&lfs, "roadrunner") => 0;
# lfs_unmount(&lfs) => 0;
#
# uint32_t cycle = 0;
# while (cycle < CYCLES) {
# lfs_mount(&lfs, cfg) => 0;
# for (uint32_t i = 0; i < FILES; i++) {
# // chose name, roughly random seed, and random 2^n size
# char path[1024];
# sprintf(path, "roadrunner/test%d", i);
# uint32_t prng = cycle * i;
# lfs_size_t size = 1 << 4; //((TEST_PRNG(&prng) % 10)+2);
#
# lfs_file_t file;
# lfs_file_open(&lfs, &file, path,
# LFS_O_WRONLY | LFS_O_CREAT | LFS_O_TRUNC) => 0;
#
# for (lfs_size_t j = 0; j < size; j++) {
# char c = 'a' + (TEST_PRNG(&prng) % 26);
# lfs_ssize_t res = lfs_file_write(&lfs, &file, &c, 1);
# assert(res == 1 || res == LFS_ERR_NOSPC);
# if (res == LFS_ERR_NOSPC) {
# int err = lfs_file_close(&lfs, &file);
# assert(err == 0 || err == LFS_ERR_NOSPC);
# lfs_unmount(&lfs) => 0;
# goto exhausted;
# }
# }
#
# int err = lfs_file_close(&lfs, &file);
# assert(err == 0 || err == LFS_ERR_NOSPC);
# if (err == LFS_ERR_NOSPC) {
# lfs_unmount(&lfs) => 0;
# goto exhausted;
# }
# }
#
# for (uint32_t i = 0; i < FILES; i++) {
# // check for errors
# char path[1024];
# sprintf(path, "roadrunner/test%d", i);
# uint32_t prng = cycle * i;
# lfs_size_t size = 1 << 4; //((TEST_PRNG(&prng) % 10)+2);
#
# lfs_file_t file;
# lfs_file_open(&lfs, &file, path, LFS_O_RDONLY) => 0;
# for (lfs_size_t j = 0; j < size; j++) {
# char c = 'a' + (TEST_PRNG(&prng) % 26);
# char r;
# lfs_file_read(&lfs, &file, &r, 1) => 1;
# assert(r == c);
# }
#
# lfs_file_close(&lfs, &file) => 0;
# }
# lfs_unmount(&lfs) => 0;
#
# cycle += 1;
# }
#
#exhausted:
# // should still be readable
# lfs_mount(&lfs, cfg) => 0;
# for (uint32_t i = 0; i < FILES; i++) {
# // check for errors
# char path[1024];
# struct lfs_info info;
# sprintf(path, "roadrunner/test%d", i);
# lfs_stat(&lfs, path, &info) => 0;
# }
# lfs_unmount(&lfs) => 0;
#
# LFS_WARN("completed %d cycles", cycle);
#
# // check the wear on our block device
# lfs_emubd_wear_t minwear = -1;
# lfs_emubd_wear_t totalwear = 0;
# lfs_emubd_wear_t maxwear = 0;
# // skip 0 and 1 as superblock movement is intentionally avoided
# for (lfs_block_t b = 2; b < BLOCK_COUNT; b++) {
# lfs_emubd_wear_t wear = lfs_emubd_wear(cfg, b);
# printf("%08x: wear %d\n", b, wear);
# assert(wear >= 0);
# if (wear < minwear) {
# minwear = wear;
# }
# if (wear > maxwear) {
# maxwear = wear;
# }
# totalwear += wear;
# }
# lfs_emubd_wear_t avgwear = totalwear / BLOCK_COUNT;
# LFS_WARN("max wear: %d cycles", maxwear);
# LFS_WARN("avg wear: %d cycles", totalwear / (int)BLOCK_COUNT);
# LFS_WARN("min wear: %d cycles", minwear);
#
# // find standard deviation^2
# lfs_emubd_wear_t dev2 = 0;
# for (lfs_block_t b = 2; b < BLOCK_COUNT; b++) {
# lfs_emubd_wear_t wear = lfs_emubd_wear(cfg, b);
# assert(wear >= 0);
# lfs_emubd_swear_t diff = wear - avgwear;
# dev2 += diff*diff;
# }
# dev2 /= totalwear;
# LFS_WARN("std dev^2: %d", dev2);
# assert(dev2 < 8);
#'''
#