From 4405ad47e40812f62c2e3ee6dd778f1876c72244 Mon Sep 17 00:00:00 2001 From: Christopher Haster Date: Fri, 30 Jan 2026 13:15:04 -0600 Subject: [PATCH] runners: Reworked test/bench for out-of-tree extensions The main changes: - Added TEST_DEFINES and BENCH_DEFINES to allow overriding the default test/bench define header: -DTEST_DEFINES=my_test_defines.h Note these are VERY different from LFS_DEFINES upstream. They aren't a typical header file, and are included multiple times with various query macros. It's hacky, but works surprisingly well. Or maybe I'll just do anything to avoid having to write multiline macros. Ugh, backslashes. - Moved more logic into bench/test_defines.h, including everything needed to integrate other filesystems out-of-tree. This mostly meant moving all of the cfg initialization logic into its own query macro (replacing the BENCH/TEST_CFG field macros). But this also includes a bunch of small tweaks encountered while trying to get external benchmarks running again. The external benchmarks include several other filesystems (littlefs2, SPIFFS, Yaffs2), and I'm hoping this injectable/queryable header thing will do a good job at avoiding a maintenance headache. (At least a better job than forking bench_runner.c, which was the previous solution.) --- Makefile | 6 +- bd/lfs3_emubd.h | 4 +- bd/lfs3_kiwibd.h | 4 +- runners/bench_defines.h | 150 ++++++++++++++------- runners/bench_runner.c | 81 +++++------ runners/bench_runner.h | 62 ++++++--- runners/test_defines.h | 84 +++++++----- runners/test_runner.c | 289 +++++++++++++++++++--------------------- runners/test_runner.h | 31 ++++- scripts/bench.py | 4 +- scripts/test.py | 4 +- 11 files changed, 409 insertions(+), 310 deletions(-) diff --git a/Makefile b/Makefile index 4fa1cf47..fcbc9f1f 100644 --- a/Makefile +++ b/Makefile @@ -20,7 +20,8 @@ TESTS ?= $(wildcard tests/*.toml) TEST_SRC ?= \ $(SRC) \ $(filter-out %.t.c %.b.c %.a.c,$(wildcard bd/*.c)) \ - runners/test_runner.c + $(filter-out %.t.c %.b.c %.a.c,$(wildcard runners/test_*.c)) \ + $(filter-out %.t.c %.b.c %.a.c,$(wildcard tests/*.c)) TEST_RUNNER ?= $(BUILDDIR)/runners/test_runner TEST_C := \ $(TESTS:%.toml=$(BUILDDIR)/%.t.c) \ @@ -39,7 +40,8 @@ BENCHES ?= $(wildcard benches/*.toml) BENCH_SRC ?= \ $(SRC) \ $(filter-out %.t.c %.b.c %.a.c,$(wildcard bd/*.c)) \ - runners/bench_runner.c + $(filter-out %.t.c %.b.c %.a.c,$(wildcard runners/bench_*.c)) \ + $(filter-out %.t.c %.b.c %.a.c,$(wildcard benches/*.c)) BENCH_RUNNER ?= $(BUILDDIR)/runners/bench_runner BENCH_C := \ $(BENCHES:%.toml=$(BUILDDIR)/%.b.c) \ diff --git a/bd/lfs3_emubd.h b/bd/lfs3_emubd.h index 9c8eecd4..56dd027a 100644 --- a/bd/lfs3_emubd.h +++ b/bd/lfs3_emubd.h @@ -215,12 +215,10 @@ int lfs3_emubd_sync(const struct lfs3_cfg *cfg); /// Additional emubd features for testing /// -// Get total simulated runtime +// Get simulated runtime in nanoseconds lfs3_emubd_sns_t lfs3_emubd_simtime(const struct lfs3_cfg *cfg); // Reset simulation counters -// -// You probably shouldn't call this, instead diff before/after simtimes int lfs3_emubd_simreset(const struct lfs3_cfg *cfg); // Get total number of read transactions diff --git a/bd/lfs3_kiwibd.h b/bd/lfs3_kiwibd.h index f3d00c99..f459471d 100644 --- a/bd/lfs3_kiwibd.h +++ b/bd/lfs3_kiwibd.h @@ -137,12 +137,10 @@ int lfs3_kiwibd_sync(const struct lfs3_cfg *cfg); /// Additional kiwibd features /// -// Get total simulated runtime +// Get simulated runtime in nanoseconds lfs3_kiwibd_sns_t lfs3_kiwibd_simtime(const struct lfs3_cfg *cfg); // Reset simulation counters -// -// You probably shouldn't call this, instead diff before/after simtimes int lfs3_kiwibd_simreset(const struct lfs3_cfg *cfg); // Get total number of read transactions diff --git a/runners/bench_defines.h b/runners/bench_defines.h index 3d5a79a8..45d1ada3 100644 --- a/runners/bench_defines.h +++ b/runners/bench_defines.h @@ -25,10 +25,10 @@ BENCH_DEFINE(CRYSTAL_THRESH, BLOCK_SIZE/8 ) BENCH_DEFINE(LOOKGBMAP_THRESH, BLOCK_COUNT/4 ) BENCH_DEFINE(ERASE_VALUE, 0xff ) - // the default timings here are based on NOR flash, specifically - // w25q64jv: - // - // https://www.winbond.com/resource-files/W25Q256JV%20SPI%20RevQ%2002072025%20Plus.pdf + #ifndef BENCH_NAND + // default timings for NOR flash, based on w25q64jv: + // https://www.winbond.com/resource-files/ + // W25Q256JV%20SPI%20RevQ%2002072025%20Plus.pdf // // note one thing unique to NOR flash is the extreme erase cost // @@ -43,24 +43,58 @@ // progs=400000ns tPP=0.4 ms, page=256 // erases=45000000ns tSE=45 ms, sector=4096 // readed=40ns/B fR=50 MHz, quad read (20 ns * 8/4) - // progged=1484ns/B tPP=0.4 ms (((4096/256)*0.4 ms - 0.4 ms)/4096 + bus) + // progged=1484ns/B tPP=0.4 ms (((4096/256)*0.4ms - 0.4ms)/4096 + bus) // erased=0ns/B (no per-byte cost) // #ifdef BENCH_SIMPLE BENCH_DEFINE(READS_TIMING, 0 ) BENCH_DEFINE(PROGS_TIMING, 0 ) - BENCH_DEFINE(ERASES_TIMING, 0 ) + BENCH_DEFINE(ERASES_TIMING, 0 ) BENCH_DEFINE(READED_TIMING, 40 ) BENCH_DEFINE(PROGGED_TIMING, 1582 ) BENCH_DEFINE(ERASED_TIMING, 10986 ) #else BENCH_DEFINE(READS_TIMING, 0 ) BENCH_DEFINE(PROGS_TIMING, 400000 ) - BENCH_DEFINE(ERASES_TIMING, 45000000 ) + BENCH_DEFINE(ERASES_TIMING, 45000000 ) BENCH_DEFINE(READED_TIMING, 40 ) BENCH_DEFINE(PROGGED_TIMING, 1484 ) BENCH_DEFINE(ERASED_TIMING, 0 ) #endif + #else + // default timings for NAND flash, based on w25n01gv: + // https://www.winbond.com/resource-files/W25N01GV%20Rev%20R%20070323.pdf + // + // FR=104 MHz, quad read/prog (9.6 ns * 8/4) + // => +~19 ns for bus + // + // readed=31ns/B tRD1=25 us, p=2048, s=512 (25 us / 2048 + bus) + // progged=141ns/B tPP=250 us, p=2048, s=512 (250 us / 2048 + bus) + // erased=15ns/B tBE=2 ms, block=131072 (2 ms / 131072) + // + // reads=25000ns tRD1=25 us, p=2048, s=512 + // progs=250000ns tPP=250 us, p=2048, s=512 + // erases=2000000ns tBE=2 ms, block=131072 + // readed=31ns/B tRD1=25 us (((131072/2048)*25us - 25us)/131072 + bus) + // progged=139ns/B tPP=250 us (((131072/2048)*250us - 250us)/131072 + bus) + // erased=0ns/B (no per-byte cost) + // + #ifdef BENCH_SIMPLE + BENCH_DEFINE(READS_TIMING, 0 ) + BENCH_DEFINE(PROGS_TIMING, 0 ) + BENCH_DEFINE(ERASES_TIMING, 0 ) + BENCH_DEFINE(READED_TIMING, 31 ) + BENCH_DEFINE(PROGGED_TIMING, 141 ) + BENCH_DEFINE(ERASED_TIMING, 15 ) + #else + BENCH_DEFINE(READS_TIMING, 25000 ) + BENCH_DEFINE(PROGS_TIMING, 250000 ) + BENCH_DEFINE(ERASES_TIMING, 2000000 ) + BENCH_DEFINE(READED_TIMING, 31 ) + BENCH_DEFINE(PROGGED_TIMING, 139 ) + BENCH_DEFINE(ERASED_TIMING, 0 ) + #endif + #endif #ifndef BENCH_KIWIBD BENCH_DEFINE(ERASE_CYCLES, 0 ) BENCH_DEFINE(BADBLOCK_BEHAVIOR, LFS3_EMUBD_BADBLOCK_PROGERROR ) @@ -70,50 +104,76 @@ #endif -// struct lfs3_cfg fields +// struct lfs3_cfg definition #ifdef BENCH_CFG - BENCH_CFG(read_size, READ_SIZE ) - BENCH_CFG(prog_size, PROG_SIZE ) - BENCH_CFG(block_size, BLOCK_SIZE ) - BENCH_CFG(block_count, BLOCK_COUNT ) - BENCH_CFG(block_recycles, BLOCK_RECYCLES ) - BENCH_CFG(rcache_size, RCACHE_SIZE ) - BENCH_CFG(pcache_size, PCACHE_SIZE ) - BENCH_CFG(fcache_size, FCACHE_SIZE ) - BENCH_CFG(lookahead_size, LOOKAHEAD_SIZE ) - #ifdef LFS3_GBMAP - BENCH_CFG(gc_lookgbmap_thresh, GC_LOOKGBMAP_THRESH ) - BENCH_CFG(lookgbmap_thresh, LOOKGBMAP_THRESH ) - #endif - #ifdef LFS3_PREERASE - BENCH_CFG(gc_preerase_count, GC_PREERASE_COUNT ) - #endif - #ifdef LFS3_GC - BENCH_CFG(gc_flags, GC_FLAGS ) - BENCH_CFG(gc_steps, GC_STEPS ) - #endif - BENCH_CFG(gc_lookahead_thresh, GC_LOOKAHEAD_THRESH ) - BENCH_CFG(gc_compact_thresh, GC_COMPACT_THRESH ) - BENCH_CFG(shrub_size, SHRUB_SIZE ) - BENCH_CFG(fragment_size, FRAGMENT_SIZE ) - BENCH_CFG(crystal_thresh, CRYSTAL_THRESH ) + struct lfs3_cfg _cfg = { + #ifdef BENCH_CFG_CFG + BENCH_CFG_CFG + #endif + .read_size = READ_SIZE, + .prog_size = PROG_SIZE, + .block_size = BLOCK_SIZE, + .block_count = BLOCK_COUNT, + .block_recycles = BLOCK_RECYCLES, + .rcache_size = RCACHE_SIZE, + .pcache_size = PCACHE_SIZE, + .fcache_size = FCACHE_SIZE, + .lookahead_size = LOOKAHEAD_SIZE, + #ifdef LFS3_GBMAP + .gc_lookgbmap_thresh = GC_LOOKGBMAP_THRESH, + .lookgbmap_thresh = LOOKGBMAP_THRESH, + #endif + #ifdef LFS3_PREERASE + .gc_preerase_count = GC_PREERASE_COUNT, + #endif + #ifdef LFS3_GC + .gc_flags = GC_FLAGS, + .gc_steps = GC_STEPS, + #endif + .gc_lookahead_thresh = GC_LOOKAHEAD_THRESH, + .gc_compact_thresh = GC_COMPACT_THRESH, + .shrub_size = SHRUB_SIZE, + .fragment_size = FRAGMENT_SIZE, + .crystal_thresh = CRYSTAL_THRESH, + }; + struct lfs3_cfg *BENCH_CFG = &_cfg; #endif -// struct lfs3_*bd_cfg fields +// struct lfs3_*bd_cfg definition #ifdef BENCH_BDCFG - BENCH_BDCFG(erase_value, ERASE_VALUE ) - BENCH_BDCFG(reads_timing, READS_TIMING ) - BENCH_BDCFG(progs_timing, PROGS_TIMING ) - BENCH_BDCFG(erases_timing, ERASES_TIMING ) - BENCH_BDCFG(readed_timing, READED_TIMING ) - BENCH_BDCFG(progged_timing, PROGGED_TIMING ) - BENCH_BDCFG(erased_timing, ERASED_TIMING ) #ifndef BENCH_KIWIBD - BENCH_BDCFG(erase_cycles, ERASE_CYCLES ) - BENCH_BDCFG(badblock_behavior, BADBLOCK_BEHAVIOR ) - BENCH_BDCFG(powerloss_behavior, POWERLOSS_BEHAVIOR ) - BENCH_BDCFG(seed, BD_SEED ) + struct lfs3_emubd_cfg _bdcfg = { + #ifdef BENCH_BDCFG_CFG + BENCH_BDCFG_CFG + #endif + .erase_value = ERASE_VALUE, + .reads_timing = READS_TIMING, + .progs_timing = PROGS_TIMING, + .erases_timing = ERASES_TIMING, + .readed_timing = READED_TIMING, + .progged_timing = PROGGED_TIMING, + .erased_timing = ERASED_TIMING, + .erase_cycles = ERASE_CYCLES, + .badblock_behavior = BADBLOCK_BEHAVIOR, + .powerloss_behavior = POWERLOSS_BEHAVIOR, + .seed = BD_SEED, + }; + struct lfs3_emubd_cfg *BENCH_BDCFG = &_bdcfg; + #else + struct lfs3_kiwibd_cfg _bdcfg = { + #ifdef BENCH_BDCFG_CFG + BENCH_BDCFG_CFG + #endif + .erase_value = ERASE_VALUE, + .reads_timing = READS_TIMING, + .progs_timing = PROGS_TIMING, + .erases_timing = ERASES_TIMING, + .readed_timing = READED_TIMING, + .progged_timing = PROGGED_TIMING, + .erased_timing = ERASED_TIMING, + }; + struct lfs3_kiwibd_cfg *BENCH_BDCFG = &_bdcfg; #endif #endif diff --git a/runners/bench_runner.c b/runners/bench_runner.c index 1710452e..c7594351 100644 --- a/runners/bench_runner.c +++ b/runners/bench_runner.c @@ -137,7 +137,7 @@ typedef struct bench_id { // implicit defines declared here #define BENCH_DEFINE(k, v) \ intmax_t k; - #include "bench_defines.h" + #include BENCH_STRINGIFY(BENCH_DEFINES) #undef BENCH_DEFINE #define BENCH_DEFINE(k, v) \ @@ -146,13 +146,13 @@ typedef struct bench_id { (void)i; \ return v; \ } - #include "bench_defines.h" + #include BENCH_STRINGIFY(BENCH_DEFINES) #undef BENCH_DEFINE const bench_define_t bench_implicit_defines[] = { #define BENCH_DEFINE(k, v) \ {#k, &k, bench_define_##k, NULL, 1}, - #include "bench_defines.h" + #include BENCH_STRINGIFY(BENCH_DEFINES) #undef BENCH_DEFINE }; const size_t bench_implicit_define_count @@ -731,7 +731,7 @@ void bench_heap_resume(void) { #endif #ifdef BENCH_YES_HEAP -static void bench_heap_inc(size_t size) { +void bench_heap_inc(size_t size) { if (bench_heap_entered & 1) { bench_heap_watermark += size; // keep track of the deepest heap @@ -743,7 +743,7 @@ static void bench_heap_inc(size_t size) { #endif #ifdef BENCH_YES_HEAP -static void bench_heap_dec(size_t size) { +void bench_heap_dec(size_t size) { if (bench_heap_entered & 1) { assert(bench_heap_watermark >= size); bench_heap_watermark -= size; @@ -842,12 +842,12 @@ typedef struct bench_record { bench_ns_t last_simtime; } bench_record_t; -static struct lfs3_cfg *bench_cfg = NULL; +static const struct lfs3_cfg *bench_cfg = NULL; static bench_record_t *bench_records; size_t bench_record_count; size_t bench_record_capacity; -void bench_reset(struct lfs3_cfg *cfg) { +void bench_reset(const struct lfs3_cfg *cfg) { bench_cfg = cfg; bench_record_count = 0; } @@ -1807,49 +1807,36 @@ void perm_run( lfs3_kiwibd_t bd; #endif - struct lfs3_cfg cfg = { - .context = &bd, - .read = bench_bd_read, - .prog = bench_bd_prog, - .erase = bench_bd_erase, - .sync = bench_bd_sync, - #define BENCH_CFG(k, v) \ - .k = v, - #include "bench_defines.h" - #undef BENCH_CFG - }; + #define BENCH_CFG CFG + #define BENCH_CFG_CFG \ + .context = &bd, \ + .read = bench_bd_read, \ + .prog = bench_bd_prog, \ + .erase = bench_bd_erase, \ + .sync = bench_bd_sync, + #include BENCH_STRINGIFY(BENCH_DEFINES) + #undef BENCH_CFG_CFG + #undef BENCH_CFG - // using emubd? + #define BENCH_BDCFG BDCFG + #define BENCH_BDCFG_CFG \ + .read_sleep = bench_read_sleep, \ + .prog_sleep = bench_prog_sleep, \ + .erase_sleep = bench_erase_sleep, + #include BENCH_STRINGIFY(BENCH_DEFINES) + #undef BENCH_BDCFG_CFG + #undef BENCH_BDCFG + + // init emubd? #ifndef BENCH_KIWIBD - struct lfs3_emubd_cfg bdcfg = { - .read_sleep = bench_read_sleep, - .prog_sleep = bench_prog_sleep, - .erase_sleep = bench_erase_sleep, - #define BENCH_BDCFG(k, v) \ - .k = v, - #include "bench_defines.h" - #undef BENCH_CFG - }; - - int err = lfs3_emubd_createcfg(&cfg, bench_disk_path, &bdcfg); + int err = lfs3_emubd_createcfg(CFG, bench_disk_path, BDCFG); if (err) { fprintf(stderr, "error: could not create emubd: %d\n", err); exit(-1); } - - // using kiwibd? + // init kiwibd? #else - struct lfs3_kiwibd_cfg bdcfg = { - .read_sleep = bench_read_sleep, - .prog_sleep = bench_prog_sleep, - .erase_sleep = bench_erase_sleep, - #define BENCH_BDCFG(k, v) \ - .k = v, - #include "bench_defines.h" - #undef BENCH_CFG - }; - - int err = lfs3_kiwibd_createcfg(&cfg, bench_disk_path, &bdcfg); + int err = lfs3_kiwibd_createcfg(CFG, bench_disk_path, BDCFG); if (err) { fprintf(stderr, "error: could not create kiwibd: %d\n", err); exit(-1); @@ -1860,7 +1847,7 @@ void perm_run( printf("running "); perm_printid(suite, case_); printf("\n"); - bench_reset(&cfg); + bench_reset(CFG); #ifdef BENCH_YES_STACK bench_stack_enter(); #endif @@ -1868,7 +1855,7 @@ void perm_run( bench_heap_enter(); #endif - case_->run(&cfg); + case_->run(CFG); #ifdef BENCH_YES_HEAP bench_heap_exit(); @@ -1882,13 +1869,13 @@ void perm_run( // cleanup #ifndef BENCH_KIWIBD - err = lfs3_emubd_destroy(&cfg); + err = lfs3_emubd_destroy(CFG); if (err) { fprintf(stderr, "error: could not destroy emubd: %d\n", err); exit(-1); } #else - err = lfs3_kiwibd_destroy(&cfg); + err = lfs3_kiwibd_destroy(CFG); if (err) { fprintf(stderr, "error: could not destroy kiwibd: %d\n", err); exit(-1); diff --git a/runners/bench_runner.h b/runners/bench_runner.h index 4e5be2fd..072bbb75 100644 --- a/runners/bench_runner.h +++ b/runners/bench_runner.h @@ -7,6 +7,24 @@ #ifndef BENCH_RUNNER_H #define BENCH_RUNNER_H +#define BENCH_STRINGIFY_(x) #x +#define BENCH_STRINGIFY(x) BENCH_STRINGIFY_(x) + +// the default BENCH_DEFINES path can be overridden to add shims for +// other filesystems out-of-tree +// +// note this is an unusual header file! instead of being included once, +// BENCH_DEFINES is included several times with various "query macros" +// defined before inclusion: +// +// - BENCH_INCLUDE - common includes (optional) +// - BENCH_DEFINE(name, value) - name and default values for bench defines +// - BENCH_CFG[+_CFG] - struct lfs3_cfg definition +// - BENCH_BDCFG[+_CFG] - struct lfs3_*bd_cfg definition +// +#ifndef BENCH_DEFINES +#define BENCH_DEFINES runners/bench_defines.h +#endif // default to using kiwibd for benches #if !defined(BENCH_EMUBD) && !defined(BENCH_KIWIBD) @@ -37,28 +55,18 @@ void bench_trace(const char *fmt, ...); #define LFS3_EMUBD_TRACE(...) LFS3_TRACE_(__VA_ARGS__, "") #define LFS3_KIWIBD_TRACE(...) LFS3_TRACE_(__VA_ARGS__, "") -// BENCH_START/BENCH_STOP macros measure readed/progged/erased bytes -// through emubd -void bench_start(const char *probe); -void bench_stop(const char *probe, uintmax_t n); - -#define BENCH_START(probe) bench_start(probe) -#define BENCH_STOP(probe, n) bench_stop(probe, n) - -// BENCH_RESULT/BENCH_FRESULT allow for explicit non-io measurements -void bench_result(const char *probe, uintmax_t n, uintmax_t result); -void bench_fresult(const char *probe, uintmax_t n, double result); - -#define BENCH_RESULT(probe, n, result) bench_result(probe, n, result) -#define BENCH_FRESULT(probe, n, result) bench_fresult(probe, n, result) - // note these are indirectly included in any generated files +#define BENCH_INCLUDE + #include BENCH_STRINGIFY(BENCH_DEFINES) +#undef BENCH_INCLUDE + #ifndef BENCH_KIWIBD #include "bd/lfs3_emubd.h" #else #include "bd/lfs3_kiwibd.h" #endif +#include "lfs3_util.h" #include #include @@ -93,7 +101,7 @@ struct bench_case { size_t permutations; bool (*if_)(void); - void (*run)(struct lfs3_cfg *cfg); + void (*run)(const struct lfs3_cfg *cfg); }; struct bench_suite { @@ -112,6 +120,22 @@ extern const struct bench_suite *const bench_suites[]; extern const size_t bench_suite_count; +// BENCH_START/BENCH_STOP macros measure readed/progged/erased bytes +// through emubd +void bench_start(const char *probe); +void bench_stop(const char *probe, uintmax_t n); + +#define BENCH_START(probe) bench_start(probe) +#define BENCH_STOP(probe, n) bench_stop(probe, n) + +// BENCH_RESULT/BENCH_FRESULT allow for explicit non-io measurements +void bench_result(const char *probe, uintmax_t n, uintmax_t result); +void bench_fresult(const char *probe, uintmax_t n, double result); + +#define BENCH_RESULT(probe, n, result) bench_result(probe, n, result) +#define BENCH_FRESULT(probe, n, result) bench_fresult(probe, n, result) + + // deterministic prng for pseudo-randomness in benches uint32_t bench_prng(uint32_t *state); @@ -145,18 +169,22 @@ size_t bench_heap(void); size_t bench_heap_current(void); void bench_heap_pause(void); void bench_heap_resume(void); +void bench_heap_inc(size_t size); +void bench_heap_dec(size_t size); #define BENCH_HEAP() bench_heap() #define BENCH_HEAP_CURRENT() bench_heap_current() #define BENCH_HEAP_PAUSE() bench_heap_pause() #define BENCH_HEAP_RESUME() bench_heap_resume() +#define BENCH_HEAP_INC(size) bench_heap_inc(size) +#define BENCH_HEAP_DEC(size) bench_heap_dec(size) #endif // declare implicit defines as global intmax_ts #define BENCH_DEFINE(k, v) \ extern intmax_t k; - #include "bench_defines.h" + #include BENCH_STRINGIFY(BENCH_DEFINES) #undef BENCH_DEFINE diff --git a/runners/test_defines.h b/runners/test_defines.h index 525df9fb..3adad7e2 100644 --- a/runners/test_defines.h +++ b/runners/test_defines.h @@ -34,44 +34,64 @@ #endif -// struct lfs3_cfg fields +// struct lfs3_cfg definition #ifdef TEST_CFG - TEST_CFG(read_size, READ_SIZE ) - TEST_CFG(prog_size, PROG_SIZE ) - TEST_CFG(block_size, BLOCK_SIZE ) - TEST_CFG(block_count, BLOCK_COUNT ) - TEST_CFG(block_recycles, BLOCK_RECYCLES ) - TEST_CFG(rcache_size, RCACHE_SIZE ) - TEST_CFG(pcache_size, PCACHE_SIZE ) - TEST_CFG(fcache_size, FCACHE_SIZE ) - TEST_CFG(lookahead_size, LOOKAHEAD_SIZE ) - #ifdef LFS3_GBMAP - TEST_CFG(gc_lookgbmap_thresh, GC_LOOKGBMAP_THRESH ) - TEST_CFG(lookgbmap_thresh, LOOKGBMAP_THRESH ) - #endif - #ifdef LFS3_PREERASE - TEST_CFG(gc_preerase_count, GC_PREERASE_COUNT ) - #endif - #ifdef LFS3_GC - TEST_CFG(gc_flags, GC_FLAGS ) - TEST_CFG(gc_steps, GC_STEPS ) - #endif - TEST_CFG(gc_lookahead_thresh, GC_LOOKAHEAD_THRESH ) - TEST_CFG(gc_compact_thresh, GC_COMPACT_THRESH ) - TEST_CFG(shrub_size, SHRUB_SIZE ) - TEST_CFG(fragment_size, FRAGMENT_SIZE ) - TEST_CFG(crystal_thresh, CRYSTAL_THRESH ) + struct lfs3_cfg _cfg = { + #ifdef TEST_CFG_CFG + TEST_CFG_CFG + #endif + .read_size = READ_SIZE, + .prog_size = PROG_SIZE, + .block_size = BLOCK_SIZE, + .block_count = BLOCK_COUNT, + .block_recycles = BLOCK_RECYCLES, + .rcache_size = RCACHE_SIZE, + .pcache_size = PCACHE_SIZE, + .fcache_size = FCACHE_SIZE, + .lookahead_size = LOOKAHEAD_SIZE, + #ifdef LFS3_GBMAP + .gc_lookgbmap_thresh = GC_LOOKGBMAP_THRESH, + .lookgbmap_thresh = LOOKGBMAP_THRESH, + #endif + #ifdef LFS3_PREERASE + .gc_preerase_count = GC_PREERASE_COUNT, + #endif + #ifdef LFS3_GC + .gc_flags = GC_FLAGS, + .gc_steps = GC_STEPS, + #endif + .gc_lookahead_thresh = GC_LOOKAHEAD_THRESH, + .gc_compact_thresh = GC_COMPACT_THRESH, + .shrub_size = SHRUB_SIZE, + .fragment_size = FRAGMENT_SIZE, + .crystal_thresh = CRYSTAL_THRESH, + }; + struct lfs3_cfg *TEST_CFG = &_cfg; #endif -// struct lfs3_*bd_cfg fields +// struct lfs3_*bd_cfg definition #ifdef TEST_BDCFG - TEST_BDCFG(erase_value, ERASE_VALUE ) #ifndef TEST_KIWIBD - TEST_BDCFG(erase_cycles, ERASE_CYCLES ) - TEST_BDCFG(badblock_behavior, BADBLOCK_BEHAVIOR ) - TEST_BDCFG(powerloss_behavior, POWERLOSS_BEHAVIOR ) - TEST_BDCFG(seed, BD_SEED ) + struct lfs3_emubd_cfg _bdcfg = { + #ifdef TEST_BDCFG_CFG + TEST_BDCFG_CFG + #endif + .erase_value = ERASE_VALUE, + .erase_cycles = ERASE_CYCLES, + .badblock_behavior = BADBLOCK_BEHAVIOR, + .powerloss_behavior = POWERLOSS_BEHAVIOR, + .seed = BD_SEED, + }; + struct lfs3_emubd_cfg *TEST_BDCFG = &_bdcfg; + #else + struct lfs3_kiwibd_cfg _bdcfg = { + #ifdef TEST_BDCFG_CFG + TEST_BDCFG_CFG + #endif + .erase_value = ERASE_VALUE, + }; + struct lfs3_kiwibd_cfg *TEST_BDCFG = &_bdcfg; #endif #endif diff --git a/runners/test_runner.c b/runners/test_runner.c index b47103ee..efe7a59b 100644 --- a/runners/test_runner.c +++ b/runners/test_runner.c @@ -148,7 +148,7 @@ typedef struct test_id { // implicit defines declared here #define TEST_DEFINE(k, v) \ intmax_t k; - #include "test_defines.h" + #include TEST_STRINGIFY(TEST_DEFINES) #undef TEST_DEFINE #define TEST_DEFINE(k, v) \ @@ -157,13 +157,13 @@ typedef struct test_id { (void)i; \ return v; \ } - #include "test_defines.h" + #include TEST_STRINGIFY(TEST_DEFINES) #undef TEST_DEFINE const test_define_t test_implicit_defines[] = { #define TEST_DEFINE(k, v) \ {#k, &k, test_define_##k, NULL, 1}, - #include "test_defines.h" + #include TEST_STRINGIFY(TEST_DEFINES) #undef TEST_DEFINE }; const size_t test_implicit_define_count @@ -747,7 +747,7 @@ void test_heap_resume(void) { #endif #ifdef TEST_YES_HEAP -static void test_heap_inc(size_t size) { +void test_heap_inc(size_t size) { if (test_heap_entered & 1) { test_heap_watermark += size; // keep track of the deepest heap @@ -759,7 +759,7 @@ static void test_heap_inc(size_t size) { #endif #ifdef TEST_YES_HEAP -static void test_heap_dec(size_t size) { +void test_heap_dec(size_t size) { if (test_heap_entered & 1) { assert(test_heap_watermark >= size); test_heap_watermark -= size; @@ -1646,49 +1646,36 @@ static void run_powerloss_none( lfs3_kiwibd_t bd; #endif - struct lfs3_cfg cfg = { - .context = &bd, - .read = test_bd_read, - .prog = test_bd_prog, - .erase = test_bd_erase, - .sync = test_bd_sync, - #define TEST_CFG(k, v) \ - .k = v, - #include "test_defines.h" - #undef TEST_CFG - }; + #define TEST_CFG CFG + #define TEST_CFG_CFG \ + .context = &bd, \ + .read = test_bd_read, \ + .prog = test_bd_prog, \ + .erase = test_bd_erase, \ + .sync = test_bd_sync, + #include TEST_STRINGIFY(TEST_DEFINES) + #undef TEST_CFG_CFG + #undef TEST_CFG - // using emubd? + #define TEST_BDCFG BDCFG + #define TEST_BDCFG_CFG \ + .read_sleep = test_read_sleep, \ + .prog_sleep = test_prog_sleep, \ + .erase_sleep = test_erase_sleep, + #include TEST_STRINGIFY(TEST_DEFINES) + #undef TEST_BDCFG_CFG + #undef TEST_BDCFG + + // init emubd? #ifndef TEST_KIWIBD - struct lfs3_emubd_cfg bdcfg = { - .read_sleep = test_read_sleep, - .prog_sleep = test_prog_sleep, - .erase_sleep = test_erase_sleep, - #define TEST_BDCFG(k, v) \ - .k = v, - #include "test_defines.h" - #undef TEST_BDCFG - }; - - int err = lfs3_emubd_createcfg(&cfg, test_disk_path, &bdcfg); + int err = lfs3_emubd_createcfg(CFG, test_disk_path, BDCFG); if (err) { fprintf(stderr, "error: could not create emubd: %d\n", err); exit(-1); } - - // using kiwibd? + // init kiwibd? #else - struct lfs3_kiwibd_cfg bdcfg = { - .read_sleep = test_read_sleep, - .prog_sleep = test_prog_sleep, - .erase_sleep = test_erase_sleep, - #define TEST_BDCFG(k, v) \ - .k = v, - #include "test_defines.h" - #undef TEST_CFG - }; - - int err = lfs3_kiwibd_createcfg(&cfg, test_disk_path, &bdcfg); + int err = lfs3_kiwibd_createcfg(CFG, test_disk_path, BDCFG); if (err) { fprintf(stderr, "error: could not create kiwibd: %d\n", err); exit(-1); @@ -1706,7 +1693,7 @@ static void run_powerloss_none( test_heap_enter(); #endif - case_->run(&cfg); + case_->run(CFG); #ifdef TEST_YES_HEAP test_heap_exit(); @@ -1720,13 +1707,13 @@ static void run_powerloss_none( // cleanup #ifndef TEST_KIWIBD - err = lfs3_emubd_destroy(&cfg); + err = lfs3_emubd_destroy(CFG); if (err) { fprintf(stderr, "error: could not destroy emubd: %d\n", err); exit(-1); } #else - err = lfs3_kiwibd_destroy(&cfg); + err = lfs3_kiwibd_destroy(CFG); if (err) { fprintf(stderr, "error: could not destroy kiwibd: %d\n", err); exit(-1); @@ -1753,34 +1740,32 @@ static void run_powerloss_linear( lfs3_emubd_t bd; jmp_buf powerloss_jmp; - struct lfs3_cfg cfg = { - .context = &bd, - .read = test_bd_read, - .prog = test_bd_prog, - .erase = test_bd_erase, - .sync = test_bd_sync, - #define TEST_CFG(k, v) \ - .k = v, - #include "test_defines.h" - #undef TEST_CFG - }; + #define TEST_CFG CFG + #define TEST_CFG_CFG \ + .context = &bd, \ + .read = test_bd_read, \ + .prog = test_bd_prog, \ + .erase = test_bd_erase, \ + .sync = test_bd_sync, + #include TEST_STRINGIFY(TEST_DEFINES) + #undef TEST_CFG_CFG + #undef TEST_CFG - struct lfs3_emubd_cfg bdcfg = { - .read_sleep = test_read_sleep, - .prog_sleep = test_prog_sleep, - .erase_sleep = test_erase_sleep, - .power_cycles = (TEST_PLS < powerloss->cycle_count) - ? TEST_PLS+1 - : 0, - .powerloss_cb = powerloss_longjmp, - .powerloss_data = &powerloss_jmp, - #define TEST_BDCFG(k, v) \ - .k = v, - #include "test_defines.h" - #undef TEST_BDCFG - }; + #define TEST_BDCFG BDCFG + #define TEST_BDCFG_CFG \ + .read_sleep = test_read_sleep, \ + .prog_sleep = test_prog_sleep, \ + .erase_sleep = test_erase_sleep, \ + .power_cycles = (TEST_PLS < powerloss->cycle_count) \ + ? TEST_PLS+1 \ + : 0, \ + .powerloss_cb = powerloss_longjmp, \ + .powerloss_data = &powerloss_jmp, + #include TEST_STRINGIFY(TEST_DEFINES) + #undef TEST_BDCFG_CFG + #undef TEST_BDCFG - int err = lfs3_emubd_createcfg(&cfg, test_disk_path, &bdcfg); + int err = lfs3_emubd_createcfg(CFG, test_disk_path, BDCFG); if (err) { fprintf(stderr, "error: could not create emubd: %d\n", err); exit(-1); @@ -1801,7 +1786,7 @@ static void run_powerloss_linear( #endif // run the test - case_->run(&cfg); + case_->run(CFG); #ifdef TEST_YES_HEAP test_heap_exit(); @@ -1821,7 +1806,7 @@ static void run_powerloss_linear( // increment pls TEST_PLS += 1; - lfs3_emubd_setpowercycles(&cfg, (TEST_PLS < powerloss->cycle_count) + lfs3_emubd_setpowercycles(CFG, (TEST_PLS < powerloss->cycle_count) ? TEST_PLS+1 : 0); } @@ -1831,7 +1816,7 @@ static void run_powerloss_linear( printf("\n"); // cleanup - err = lfs3_emubd_destroy(&cfg); + err = lfs3_emubd_destroy(CFG); if (err) { fprintf(stderr, "error: could not destroy emubd: %d\n", err); exit(-1); @@ -1851,34 +1836,32 @@ static void run_powerloss_log( lfs3_emubd_t bd; jmp_buf powerloss_jmp; - struct lfs3_cfg cfg = { - .context = &bd, - .read = test_bd_read, - .prog = test_bd_prog, - .erase = test_bd_erase, - .sync = test_bd_sync, - #define TEST_CFG(k, v) \ - .k = v, - #include "test_defines.h" - #undef TEST_CFG - }; + #define TEST_CFG CFG + #define TEST_CFG_CFG \ + .context = &bd, \ + .read = test_bd_read, \ + .prog = test_bd_prog, \ + .erase = test_bd_erase, \ + .sync = test_bd_sync, + #include TEST_STRINGIFY(TEST_DEFINES) + #undef TEST_CFG_CFG + #undef TEST_CFG - struct lfs3_emubd_cfg bdcfg = { - .read_sleep = test_read_sleep, - .prog_sleep = test_prog_sleep, - .erase_sleep = test_erase_sleep, - .power_cycles = (TEST_PLS < powerloss->cycle_count) - ? 1 << TEST_PLS - : 0, - .powerloss_cb = powerloss_longjmp, - .powerloss_data = &powerloss_jmp, - #define TEST_BDCFG(k, v) \ - .k = v, - #include "test_defines.h" - #undef TEST_BDCFG - }; + #define TEST_BDCFG BDCFG + #define TEST_BDCFG_CFG \ + .read_sleep = test_read_sleep, \ + .prog_sleep = test_prog_sleep, \ + .erase_sleep = test_erase_sleep, \ + .power_cycles = (TEST_PLS < powerloss->cycle_count) \ + ? 1 << TEST_PLS \ + : 0, \ + .powerloss_cb = powerloss_longjmp, \ + .powerloss_data = &powerloss_jmp, + #include TEST_STRINGIFY(TEST_DEFINES) + #undef TEST_BDCFG_CFG + #undef TEST_BDCFG - int err = lfs3_emubd_createcfg(&cfg, test_disk_path, &bdcfg); + int err = lfs3_emubd_createcfg(CFG, test_disk_path, BDCFG); if (err) { fprintf(stderr, "error: could not create emubd: %d\n", err); exit(-1); @@ -1899,7 +1882,7 @@ static void run_powerloss_log( #endif // run the test - case_->run(&cfg); + case_->run(CFG); #ifdef TEST_YES_HEAP test_heap_exit(); @@ -1919,7 +1902,7 @@ static void run_powerloss_log( // increment pls TEST_PLS += 1; - lfs3_emubd_setpowercycles(&cfg, (TEST_PLS < powerloss->cycle_count) + lfs3_emubd_setpowercycles(CFG, (TEST_PLS < powerloss->cycle_count) ? 1 << TEST_PLS : 0); } @@ -1929,7 +1912,7 @@ static void run_powerloss_log( printf("\n"); // cleanup - err = lfs3_emubd_destroy(&cfg); + err = lfs3_emubd_destroy(CFG); if (err) { fprintf(stderr, "error: could not destroy emubd: %d\n", err); exit(-1); @@ -1949,34 +1932,32 @@ static void run_powerloss_cycles( lfs3_emubd_t bd; jmp_buf powerloss_jmp; - struct lfs3_cfg cfg = { - .context = &bd, - .read = test_bd_read, - .prog = test_bd_prog, - .erase = test_bd_erase, - .sync = test_bd_sync, - #define TEST_CFG(k, v) \ - .k = v, - #include "test_defines.h" - #undef TEST_CFG - }; + #define TEST_CFG CFG + #define TEST_CFG_CFG \ + .context = &bd, \ + .read = test_bd_read, \ + .prog = test_bd_prog, \ + .erase = test_bd_erase, \ + .sync = test_bd_sync, + #include TEST_STRINGIFY(TEST_DEFINES) + #undef TEST_CFG_CFG + #undef TEST_CFG - struct lfs3_emubd_cfg bdcfg = { - .read_sleep = test_read_sleep, - .prog_sleep = test_prog_sleep, - .erase_sleep = test_erase_sleep, - .power_cycles = (TEST_PLS < powerloss->cycle_count) - ? powerloss->cycles[TEST_PLS] - : 0, - .powerloss_cb = powerloss_longjmp, - .powerloss_data = &powerloss_jmp, - #define TEST_BDCFG(k, v) \ - .k = v, - #include "test_defines.h" - #undef TEST_BDCFG - }; + #define TEST_BDCFG BDCFG + #define TEST_BDCFG_CFG \ + .read_sleep = test_read_sleep, \ + .prog_sleep = test_prog_sleep, \ + .erase_sleep = test_erase_sleep, \ + .power_cycles = (TEST_PLS < powerloss->cycle_count) \ + ? powerloss->cycles[TEST_PLS] \ + : 0, \ + .powerloss_cb = powerloss_longjmp, \ + .powerloss_data = &powerloss_jmp, + #include TEST_STRINGIFY(TEST_DEFINES) + #undef TEST_BDCFG_CFG + #undef TEST_BDCFG - int err = lfs3_emubd_createcfg(&cfg, test_disk_path, &bdcfg); + int err = lfs3_emubd_createcfg(CFG, test_disk_path, BDCFG); if (err) { fprintf(stderr, "error: could not create emubd: %d\n", err); exit(-1); @@ -1997,7 +1978,7 @@ static void run_powerloss_cycles( #endif // run the test - case_->run(&cfg); + case_->run(CFG); #ifdef TEST_YES_HEAP test_heap_exit(); @@ -2016,7 +1997,7 @@ static void run_powerloss_cycles( // increment pls TEST_PLS += 1; - lfs3_emubd_setpowercycles(&cfg, (TEST_PLS < powerloss->cycle_count) + lfs3_emubd_setpowercycles(CFG, (TEST_PLS < powerloss->cycle_count) ? powerloss->cycles[TEST_PLS] : 0); } @@ -2026,7 +2007,7 @@ static void run_powerloss_cycles( printf("\n"); // cleanup - err = lfs3_emubd_destroy(&cfg); + err = lfs3_emubd_destroy(CFG); if (err) { fprintf(stderr, "error: could not destroy emubd: %d\n", err); exit(-1); @@ -2167,31 +2148,29 @@ static void run_powerloss_exhaustive( // create block device and configuration lfs3_emubd_t bd; - struct lfs3_cfg cfg = { - .context = &bd, - .read = test_bd_read, - .prog = test_bd_prog, - .erase = test_bd_erase, - .sync = test_bd_sync, - #define TEST_CFG(k, v) \ - .k = v, - #include "test_defines.h" - #undef TEST_CFG - }; + #define TEST_CFG CFG + #define TEST_CFG_CFG \ + .context = &bd, \ + .read = test_bd_read, \ + .prog = test_bd_prog, \ + .erase = test_bd_erase, \ + .sync = test_bd_sync, + #include TEST_STRINGIFY(TEST_DEFINES) + #undef TEST_CFG_CFG + #undef TEST_CFG - struct lfs3_emubd_cfg bdcfg = { - .read_sleep = test_read_sleep, - .prog_sleep = test_prog_sleep, - .erase_sleep = test_erase_sleep, - .powerloss_cb = powerloss_exhaustive_branch, - .powerloss_data = NULL, - #define TEST_BDCFG(k, v) \ - .k = v, - #include "test_defines.h" - #undef TEST_BDCFG - }; + #define TEST_BDCFG BDCFG + #define TEST_BDCFG_CFG \ + .read_sleep = test_read_sleep, \ + .prog_sleep = test_prog_sleep, \ + .erase_sleep = test_erase_sleep, \ + .powerloss_cb = powerloss_exhaustive_branch, \ + .powerloss_data = NULL, + #include TEST_STRINGIFY(TEST_DEFINES) + #undef TEST_BDCFG_CFG + #undef TEST_BDCFG - int err = lfs3_emubd_createcfg(&cfg, test_disk_path, &bdcfg); + int err = lfs3_emubd_createcfg(CFG, test_disk_path, BDCFG); if (err) { fprintf(stderr, "error: could not create emubd: %d\n", err); exit(-1); @@ -2206,7 +2185,7 @@ static void run_powerloss_exhaustive( run_powerloss_exhaustive_layer( &(struct powerloss_exhaustive_cycles){NULL, 0, 0}, suite, case_, - &cfg, &bdcfg, powerloss->cycle_count, 0); + CFG, BDCFG, powerloss->cycle_count, 0); printf("finished "); perm_printid(suite, case_, NULL, 0); diff --git a/runners/test_runner.h b/runners/test_runner.h index 8a661eb8..666241b9 100644 --- a/runners/test_runner.h +++ b/runners/test_runner.h @@ -7,6 +7,24 @@ #ifndef TEST_RUNNER_H #define TEST_RUNNER_H +#define TEST_STRINGIFY_(x) #x +#define TEST_STRINGIFY(x) TEST_STRINGIFY_(x) + +// the default TEST_DEFINES path can be overridden to add shims for +// other filesystems out-of-tree +// +// note this is an unusual header file! instead of being included once, +// TEST_DEFINES is included several times with various "query macros" +// defined before inclusion: +// +// - TEST_INCLUDE - common includes (optional) +// - TEST_DEFINE(name, value) - name and default values for test defines +// - TEST_CFG[+_CFG] - struct lfs3_cfg definition +// - TEST_BDCFG[+_CFG] - struct lfs3_*bd_cfg definition +// +#ifndef TEST_DEFINES +#define TEST_DEFINES runners/test_defines.h +#endif // default to using emubd for tests #if !defined(TEST_EMUBD) && !defined(TEST_KIWIBD) @@ -39,11 +57,16 @@ void test_trace(const char *fmt, ...); // note these are indirectly included in any generated files +#define TEST_INCLUDE + #include TEST_STRINGIFY(TEST_DEFINES) +#undef TEST_INCLUDE + #ifndef TEST_KIWIBD #include "bd/lfs3_emubd.h" #else #include "bd/lfs3_kiwibd.h" #endif +#include "lfs3_util.h" #include #include @@ -80,7 +103,7 @@ struct test_case { size_t permutations; bool (*if_)(void); - void (*run)(struct lfs3_cfg *cfg); + void (*run)(const struct lfs3_cfg *cfg); }; struct test_suite { @@ -136,18 +159,22 @@ size_t test_heap(void); size_t test_heap_current(void); void test_heap_pause(void); void test_heap_resume(void); +void test_heap_inc(size_t size); +void test_heap_dec(size_t size); #define TEST_HEAP() test_heap() #define TEST_HEAP_CURRENT() test_heap_current() #define TEST_HEAP_PAUSE() test_heap_pause() #define TEST_HEAP_RESUME() test_heap_resume() +#define TEST_HEAP_INC(size) test_heap_inc(size) +#define TEST_HEAP_DEC(size) test_heap_dec(size) #endif // declare implicit defines as global intmax_ts #define TEST_DEFINE(k, v) \ extern intmax_t k; - #include "test_defines.h" + #include TEST_STRINGIFY(TEST_DEFINES) #undef TEST_DEFINE diff --git a/scripts/bench.py b/scripts/bench.py index 5fdf9d0d..2cdadb1e 100755 --- a/scripts/bench.py +++ b/scripts/bench.py @@ -483,7 +483,7 @@ def compile(bench_paths, **args): # create case run function f.writeln('void __bench__%s__run(' '__attribute__((unused)) ' - 'struct lfs3_cfg *CFG) {' % ( + 'const struct lfs3_cfg *CFG) {' % ( case.name)) f.writeln(4*' '+'// bench case %s' % case.name) if case.code_lineno is not None: @@ -550,7 +550,7 @@ def compile(bench_paths, **args): 'void);' % ( case.name)) f.writeln('extern void __bench__%s__run(' - 'struct lfs3_cfg *CFG);' % ( + 'const struct lfs3_cfg *CFG);' % ( case.name)) f.writeln() diff --git a/scripts/test.py b/scripts/test.py index ae570030..f67da9bf 100755 --- a/scripts/test.py +++ b/scripts/test.py @@ -495,7 +495,7 @@ def compile(test_paths, **args): # create case run function f.writeln('void __test__%s__run(' '__attribute__((unused)) ' - 'struct lfs3_cfg *CFG) {' % ( + 'const struct lfs3_cfg *CFG) {' % ( case.name)) f.writeln(4*' '+'// test case %s' % case.name) if case.code_lineno is not None: @@ -562,7 +562,7 @@ def compile(test_paths, **args): 'void);' % ( case.name)) f.writeln('extern void __test__%s__run(' - 'struct lfs3_cfg *CFG);' % ( + 'const struct lfs3_cfg *CFG);' % ( case.name)) f.writeln()