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.)
This commit is contained in:
Christopher Haster
2026-01-30 13:15:04 -06:00
parent 91cbcfd389
commit 4405ad47e4
11 changed files with 409 additions and 310 deletions
+4 -2
View File
@@ -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) \
+1 -3
View File
@@ -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
+1 -3
View File
@@ -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
+103 -43
View File
@@ -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,7 +43,7 @@
// 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
@@ -61,6 +61,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
+34 -47
View File
@@ -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);
+45 -17
View File
@@ -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 <stdio.h>
#include <stdint.h>
@@ -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
+52 -32
View File
@@ -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
+134 -155
View File
@@ -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);
+29 -2
View File
@@ -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 <stdio.h>
#include <stdint.h>
@@ -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
+2 -2
View File
@@ -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()
+2 -2
View File
@@ -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()