runners: Added stack/heap measurement functions
These have been battle-tested in external benchmarks, and have proven useful for finding a runtime estimate on stack+heap usage. Of course, to be realistic they need to be cross-compiled and run under QEMU (which does work!), but even on x86_64 they provide a nice insight into RAM usage. In practice the only real difference is pointer width anyways. --- Enabled by default for the bench runner, these are available if TEST/BENCH_YES_HEAP and/or TEST/BENCH_YES_STACK are defined. (This default is provided by the Makefile. At least heap measurements rely on linker flags, so it probably doesn't make sense to default enable in the bench runner itself.) Stack vs heap rely on slightly different mechanisms: - Stack: Uses GCC's __builtin_frame_address(0) to measure the current stack usage on entry to every bd operation. - Heap: Relies on GCC's -Wl,--wrap flags to intercept every malloc/free call, to track the current heap usage. These are available via bench/test macros: - BENCH_STACK() - Maximum stack usage of the current run - BENCH_STACK_CURRENT() - Current stack usage - BENCH_HEAP() - Maximum heap usage of the current run - BENCH_HEAP_CURRENT() - Current heap usage Note BENCH_STACK_CURRENT() can be useful for separating out the bench's ctx from total stack usage, similarly to our static analysis. --- One surprising outcome is that these heap hooks trivially implement a memory leak detector. Maybe that could be useful in the test_runner as a cheaper alternative to Valgrind?
This commit is contained in:
@@ -99,9 +99,27 @@ CFLAGS += $(foreach d,$(filter LFS3_%,$(.VARIABLES)),-D$d=$($d))
|
|||||||
|
|
||||||
TEST_CFLAGS += -Wno-unused-function
|
TEST_CFLAGS += -Wno-unused-function
|
||||||
TEST_CFLAGS += -Wno-format-overflow
|
TEST_CFLAGS += -Wno-format-overflow
|
||||||
|
ifdef STACK
|
||||||
|
TEST_CFLAGS += -DTEST_YES_STACK
|
||||||
|
endif
|
||||||
|
ifdef HEAP
|
||||||
|
TEST_CFLAGS += -DTEST_YES_HEAP
|
||||||
|
TEST_CFLAGS += -Wl,--wrap=malloc
|
||||||
|
TEST_CFLAGS += -Wl,--wrap=free
|
||||||
|
TEST_CFLAGS += -Wl,--wrap=realloc
|
||||||
|
endif
|
||||||
|
|
||||||
BENCH_CFLAGS += -Wno-unused-function
|
BENCH_CFLAGS += -Wno-unused-function
|
||||||
BENCH_CFLAGS += -Wno-format-overflow
|
BENCH_CFLAGS += -Wno-format-overflow
|
||||||
|
ifndef NO_STACK
|
||||||
|
BENCH_CFLAGS += -DBENCH_YES_STACK
|
||||||
|
endif
|
||||||
|
ifndef NO_HEAP
|
||||||
|
BENCH_CFLAGS += -DBENCH_YES_HEAP
|
||||||
|
BENCH_CFLAGS += -Wl,--wrap=malloc
|
||||||
|
BENCH_CFLAGS += -Wl,--wrap=free
|
||||||
|
BENCH_CFLAGS += -Wl,--wrap=realloc
|
||||||
|
endif
|
||||||
|
|
||||||
ifdef VERBOSE
|
ifdef VERBOSE
|
||||||
CODEFLAGS += -v
|
CODEFLAGS += -v
|
||||||
|
|||||||
+388
-13
@@ -614,6 +614,222 @@ void bench_permutation(size_t i, uint32_t *buffer, size_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// stack hooks
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
uint8_t *bench_stack_watermark_enter;
|
||||||
|
uint8_t *bench_stack_watermark_depth;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// call me when entering/exiting a bench!
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
__attribute__((noinline))
|
||||||
|
void bench_stack_enter(void) {
|
||||||
|
bench_stack_watermark_enter = __builtin_frame_address(0);
|
||||||
|
bench_stack_watermark_depth = bench_stack_watermark_enter;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
void bench_stack_exit(void) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// call me when entering/exiting a bd op!
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
__attribute__((noinline))
|
||||||
|
void bench_stack_pause(void) {
|
||||||
|
uint8_t *watermark = __builtin_frame_address(0);
|
||||||
|
|
||||||
|
// keep track of the deepest stack
|
||||||
|
ssize_t depth = bench_stack_watermark_depth - bench_stack_watermark_enter;
|
||||||
|
if (depth < 0) {
|
||||||
|
depth = -depth;
|
||||||
|
}
|
||||||
|
ssize_t depth_ = watermark - bench_stack_watermark_enter;
|
||||||
|
if (depth_ < 0) {
|
||||||
|
depth_ = -depth_;
|
||||||
|
}
|
||||||
|
if (depth_ > depth) {
|
||||||
|
bench_stack_watermark_depth = watermark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
void bench_stack_resume(void) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// get the worst-case stack usage
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
size_t bench_stack(void) {
|
||||||
|
ssize_t depth = bench_stack_watermark_depth - bench_stack_watermark_enter;
|
||||||
|
if (depth < 0) {
|
||||||
|
depth = -depth;
|
||||||
|
}
|
||||||
|
return depth;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// get the current stack usage, note this is included in bench_stack
|
||||||
|
//
|
||||||
|
// note note the noinline here is important for forcing a new stack frame
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
__attribute__((noinline))
|
||||||
|
size_t bench_stack_current(void) {
|
||||||
|
uint8_t *watermark = __builtin_frame_address(0);
|
||||||
|
|
||||||
|
ssize_t depth = watermark - bench_stack_watermark_enter;
|
||||||
|
if (depth < 0) {
|
||||||
|
depth = -depth;
|
||||||
|
}
|
||||||
|
return depth;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// heap hooks
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
uint32_t bench_heap_entered = 0;
|
||||||
|
size_t bench_heap_watermark = 0;
|
||||||
|
size_t bench_heap_watermark_depth = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// call me when entering/exiting a bench!
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
void bench_heap_enter(void) {
|
||||||
|
bench_heap_entered = 1;
|
||||||
|
bench_heap_watermark = 0;
|
||||||
|
bench_heap_watermark_depth = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
void bench_heap_exit(void) {
|
||||||
|
bench_heap_entered = 0;
|
||||||
|
if (bench_heap_watermark != 0) {
|
||||||
|
fprintf(stderr, "warning: memory leak detected (%zd > 0)\n",
|
||||||
|
bench_heap_watermark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// call me when entering/exiting a bd op!
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
void bench_heap_pause(void) {
|
||||||
|
// haha, a little 32-bit stack
|
||||||
|
bench_heap_entered <<= 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
void bench_heap_resume(void) {
|
||||||
|
bench_heap_entered >>= 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
static void bench_heap_inc(size_t size) {
|
||||||
|
if (bench_heap_entered & 1) {
|
||||||
|
bench_heap_watermark += size;
|
||||||
|
// keep track of the deepest heap
|
||||||
|
if (bench_heap_watermark > bench_heap_watermark_depth) {
|
||||||
|
bench_heap_watermark_depth = bench_heap_watermark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
static void bench_heap_dec(size_t size) {
|
||||||
|
if (bench_heap_entered & 1) {
|
||||||
|
assert(bench_heap_watermark >= size);
|
||||||
|
bench_heap_watermark -= size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// get the worst-case heap usage
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
size_t bench_heap(void) {
|
||||||
|
return bench_heap_watermark_depth;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// get the current heap usage
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
size_t bench_heap_current(void) {
|
||||||
|
return bench_heap_watermark;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// __real_malloc stubs, gcc's --wrap wraps these over the original symbols
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
extern void *__real_malloc(size_t size);
|
||||||
|
extern void __real_free(void *p);
|
||||||
|
extern void *__real_realloc(void *p, size_t size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// the actual malloc hooks
|
||||||
|
//
|
||||||
|
// these only work if wrapped via gcc's --wrap
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
void *__wrap_malloc(size_t size) {
|
||||||
|
// prefix with allocation size, note we use uintptr_t to hopefully
|
||||||
|
// keep things aligned
|
||||||
|
uintptr_t *p_ = __real_malloc(sizeof(uintptr_t) + size);
|
||||||
|
if (!p_) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bench_heap_inc(size);
|
||||||
|
*p_ = size;
|
||||||
|
return p_ + 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
void __wrap_free(void *p) {
|
||||||
|
if (!p) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t *p_ = ((uintptr_t*)p) - 1;
|
||||||
|
size_t size = *p_;
|
||||||
|
bench_heap_dec(size);
|
||||||
|
|
||||||
|
__real_free(p_);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
void *__wrap_realloc(void *p, size_t size) {
|
||||||
|
uintptr_t *p_;
|
||||||
|
size_t old;
|
||||||
|
if (p) {
|
||||||
|
p_ = ((uintptr_t*)p) - 1;
|
||||||
|
old = *p_;
|
||||||
|
} else {
|
||||||
|
p_ = NULL;
|
||||||
|
old = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(size != 0);
|
||||||
|
p_ = __real_realloc(p_, sizeof(uintptr_t) + size);
|
||||||
|
if (!p_) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
bench_heap_dec(old);
|
||||||
|
bench_heap_inc(size);
|
||||||
|
*p_ = size;
|
||||||
|
return p_ + 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// bench recording state
|
// bench recording state
|
||||||
typedef struct bench_record {
|
typedef struct bench_record {
|
||||||
const char *probe;
|
const char *probe;
|
||||||
@@ -637,6 +853,13 @@ void bench_reset(struct lfs3_cfg *cfg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void bench_start(const char *probe) {
|
void bench_start(const char *probe) {
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
BENCH_STACK_PAUSE();
|
||||||
|
#endif
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
BENCH_HEAP_PAUSE();
|
||||||
|
#endif
|
||||||
|
|
||||||
// measure current read/prog/erase
|
// measure current read/prog/erase
|
||||||
assert(bench_cfg);
|
assert(bench_cfg);
|
||||||
#ifndef BENCH_KIWIBD
|
#ifndef BENCH_KIWIBD
|
||||||
@@ -685,9 +908,23 @@ void bench_start(const char *probe) {
|
|||||||
record->last_progged = progged;
|
record->last_progged = progged;
|
||||||
record->last_erased = erased;
|
record->last_erased = erased;
|
||||||
record->last_simtime = simtime;
|
record->last_simtime = simtime;
|
||||||
|
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
BENCH_HEAP_RESUME();
|
||||||
|
#endif
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
BENCH_STACK_RESUME();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void bench_stop(const char *probe, uintmax_t n) {
|
void bench_stop(const char *probe, uintmax_t n) {
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
BENCH_STACK_PAUSE();
|
||||||
|
#endif
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
BENCH_HEAP_PAUSE();
|
||||||
|
#endif
|
||||||
|
|
||||||
// measure current read/prog/erase
|
// measure current read/prog/erase
|
||||||
assert(bench_cfg);
|
assert(bench_cfg);
|
||||||
#ifndef BENCH_KIWIBD
|
#ifndef BENCH_KIWIBD
|
||||||
@@ -759,7 +996,7 @@ void bench_stop(const char *probe, uintmax_t n) {
|
|||||||
&bench_records[i+1],
|
&bench_records[i+1],
|
||||||
bench_record_count-(i+1));
|
bench_record_count-(i+1));
|
||||||
bench_record_count -= 1;
|
bench_record_count -= 1;
|
||||||
return;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -768,22 +1005,58 @@ void bench_stop(const char *probe, uintmax_t n) {
|
|||||||
probe);
|
probe);
|
||||||
assert(false);
|
assert(false);
|
||||||
exit(-1);
|
exit(-1);
|
||||||
|
|
||||||
|
done:;
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
BENCH_HEAP_RESUME();
|
||||||
|
#endif
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
BENCH_STACK_RESUME();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void bench_result(const char *probe, uintmax_t n, uintmax_t result) {
|
void bench_result(const char *probe, uintmax_t n, uintmax_t result) {
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
BENCH_STACK_PAUSE();
|
||||||
|
#endif
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
BENCH_HEAP_PAUSE();
|
||||||
|
#endif
|
||||||
|
|
||||||
// we just print these directly
|
// we just print these directly
|
||||||
printf("benched %s %jd %"PRIu64"\n",
|
printf("benched %s %jd %"PRIu64"\n",
|
||||||
probe,
|
probe,
|
||||||
n,
|
n,
|
||||||
result);
|
result);
|
||||||
|
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
BENCH_HEAP_RESUME();
|
||||||
|
#endif
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
BENCH_STACK_RESUME();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void bench_fresult(const char *probe, uintmax_t n, double result) {
|
void bench_fresult(const char *probe, uintmax_t n, double result) {
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
BENCH_STACK_PAUSE();
|
||||||
|
#endif
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
BENCH_HEAP_PAUSE();
|
||||||
|
#endif
|
||||||
|
|
||||||
// we just print these directly
|
// we just print these directly
|
||||||
printf("benched %s %jd %.6f\n",
|
printf("benched %s %jd %.6f\n",
|
||||||
probe,
|
probe,
|
||||||
n,
|
n,
|
||||||
result);
|
result);
|
||||||
|
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
BENCH_HEAP_RESUME();
|
||||||
|
#endif
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
BENCH_STACK_RESUME();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1404,6 +1677,103 @@ static void list_implicit_defines(void) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// bench bd wrappers for heap/stack tracking
|
||||||
|
int bench_bd_read(const struct lfs3_cfg *cfg, lfs3_block_t block,
|
||||||
|
lfs3_off_t off, void *buffer, lfs3_size_t size) {
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
BENCH_STACK_PAUSE();
|
||||||
|
#endif
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
BENCH_HEAP_PAUSE();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BENCH_KIWIBD
|
||||||
|
int err = lfs3_kiwibd_read(cfg, block, off, buffer, size);
|
||||||
|
#else
|
||||||
|
int err = lfs3_emubd_read(cfg, block, off, buffer, size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
BENCH_HEAP_RESUME();
|
||||||
|
#endif
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
BENCH_STACK_RESUME();
|
||||||
|
#endif
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bench_bd_prog(const struct lfs3_cfg *cfg, lfs3_block_t block,
|
||||||
|
lfs3_off_t off, const void *buffer, lfs3_size_t size) {
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
BENCH_STACK_PAUSE();
|
||||||
|
#endif
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
BENCH_HEAP_PAUSE();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BENCH_KIWIBD
|
||||||
|
int err = lfs3_kiwibd_prog(cfg, block, off, buffer, size);
|
||||||
|
#else
|
||||||
|
int err = lfs3_emubd_prog(cfg, block, off, buffer, size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
BENCH_HEAP_RESUME();
|
||||||
|
#endif
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
BENCH_STACK_RESUME();
|
||||||
|
#endif
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bench_bd_erase(const struct lfs3_cfg *cfg, lfs3_block_t block) {
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
BENCH_STACK_PAUSE();
|
||||||
|
#endif
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
BENCH_HEAP_PAUSE();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BENCH_KIWIBD
|
||||||
|
int err = lfs3_kiwibd_erase(cfg, block);
|
||||||
|
#else
|
||||||
|
int err = lfs3_emubd_erase(cfg, block);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
BENCH_HEAP_RESUME();
|
||||||
|
#endif
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
BENCH_STACK_RESUME();
|
||||||
|
#endif
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int bench_bd_sync(const struct lfs3_cfg *cfg) {
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
BENCH_STACK_PAUSE();
|
||||||
|
#endif
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
BENCH_HEAP_PAUSE();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BENCH_KIWIBD
|
||||||
|
int err = lfs3_kiwibd_sync(cfg);
|
||||||
|
#else
|
||||||
|
int err = lfs3_emubd_sync(cfg);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
BENCH_HEAP_RESUME();
|
||||||
|
#endif
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
BENCH_STACK_RESUME();
|
||||||
|
#endif
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// global bench step count
|
// global bench step count
|
||||||
size_t bench_step = 0;
|
size_t bench_step = 0;
|
||||||
|
|
||||||
@@ -1439,17 +1809,10 @@ void perm_run(
|
|||||||
|
|
||||||
struct lfs3_cfg cfg = {
|
struct lfs3_cfg cfg = {
|
||||||
.context = &bd,
|
.context = &bd,
|
||||||
#ifndef BENCH_KIWIBD
|
.read = bench_bd_read,
|
||||||
.read = lfs3_emubd_read,
|
.prog = bench_bd_prog,
|
||||||
.prog = lfs3_emubd_prog,
|
.erase = bench_bd_erase,
|
||||||
.erase = lfs3_emubd_erase,
|
.sync = bench_bd_sync,
|
||||||
.sync = lfs3_emubd_sync,
|
|
||||||
#else
|
|
||||||
.read = lfs3_kiwibd_read,
|
|
||||||
.prog = lfs3_kiwibd_prog,
|
|
||||||
.erase = lfs3_kiwibd_erase,
|
|
||||||
.sync = lfs3_kiwibd_sync,
|
|
||||||
#endif
|
|
||||||
#define BENCH_CFG(k, v) \
|
#define BENCH_CFG(k, v) \
|
||||||
.k = v,
|
.k = v,
|
||||||
#include "bench_defines.h"
|
#include "bench_defines.h"
|
||||||
@@ -1494,13 +1857,25 @@ void perm_run(
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// run the bench
|
// run the bench
|
||||||
bench_reset(&cfg);
|
|
||||||
printf("running ");
|
printf("running ");
|
||||||
perm_printid(suite, case_);
|
perm_printid(suite, case_);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
bench_reset(&cfg);
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
bench_stack_enter();
|
||||||
|
#endif
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
bench_heap_enter();
|
||||||
|
#endif
|
||||||
|
|
||||||
case_->run(&cfg);
|
case_->run(&cfg);
|
||||||
|
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
bench_heap_exit();
|
||||||
|
#endif
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
bench_stack_exit();
|
||||||
|
#endif
|
||||||
printf("finished ");
|
printf("finished ");
|
||||||
perm_printid(suite, case_);
|
perm_printid(suite, case_);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
|||||||
@@ -124,6 +124,34 @@ void bench_permutation(size_t i, uint32_t *buffer, size_t size);
|
|||||||
#define BENCH_FACTORIAL(x) bench_factorial(x)
|
#define BENCH_FACTORIAL(x) bench_factorial(x)
|
||||||
#define BENCH_PERMUTATION(i, buffer, size) bench_permutation(i, buffer, size)
|
#define BENCH_PERMUTATION(i, buffer, size) bench_permutation(i, buffer, size)
|
||||||
|
|
||||||
|
#ifdef BENCH_YES_STACK
|
||||||
|
// get the maximum/current stack usage for this run
|
||||||
|
size_t bench_stack(void);
|
||||||
|
__attribute__((noinline))
|
||||||
|
size_t bench_stack_current(void);
|
||||||
|
__attribute__((noinline))
|
||||||
|
void bench_stack_pause(void);
|
||||||
|
void bench_stack_resume(void);
|
||||||
|
|
||||||
|
#define BENCH_STACK() bench_stack()
|
||||||
|
#define BENCH_STACK_CURRENT() bench_stack_current()
|
||||||
|
#define BENCH_STACK_PAUSE() bench_stack_pause()
|
||||||
|
#define BENCH_STACK_RESUME() bench_stack_resume()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BENCH_YES_HEAP
|
||||||
|
// get the maximum/current heap usage for this run
|
||||||
|
size_t bench_heap(void);
|
||||||
|
size_t bench_heap_current(void);
|
||||||
|
void bench_heap_pause(void);
|
||||||
|
void bench_heap_resume(void);
|
||||||
|
|
||||||
|
#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()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// declare implicit defines as global intmax_ts
|
// declare implicit defines as global intmax_ts
|
||||||
#define BENCH_DEFINE(k, v) \
|
#define BENCH_DEFINE(k, v) \
|
||||||
|
|||||||
+404
-30
@@ -630,6 +630,222 @@ void test_permutation(size_t i, uint32_t *buffer, size_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// stack hooks
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
|
uint8_t *test_stack_watermark_enter;
|
||||||
|
uint8_t *test_stack_watermark_depth;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// call me when entering/exiting a test!
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
|
__attribute__((noinline))
|
||||||
|
void test_stack_enter(void) {
|
||||||
|
test_stack_watermark_enter = __builtin_frame_address(0);
|
||||||
|
test_stack_watermark_depth = test_stack_watermark_enter;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
|
void test_stack_exit(void) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// call me when entering/exiting a bd op!
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
|
__attribute__((noinline))
|
||||||
|
void test_stack_pause(void) {
|
||||||
|
uint8_t *watermark = __builtin_frame_address(0);
|
||||||
|
|
||||||
|
// keep track of the deepest stack
|
||||||
|
ssize_t depth = test_stack_watermark_depth - test_stack_watermark_enter;
|
||||||
|
if (depth < 0) {
|
||||||
|
depth = -depth;
|
||||||
|
}
|
||||||
|
ssize_t depth_ = watermark - test_stack_watermark_enter;
|
||||||
|
if (depth_ < 0) {
|
||||||
|
depth_ = -depth_;
|
||||||
|
}
|
||||||
|
if (depth_ > depth) {
|
||||||
|
test_stack_watermark_depth = watermark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
|
void test_stack_resume(void) {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// get the worst-case stack usage
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
|
size_t test_stack(void) {
|
||||||
|
ssize_t depth = test_stack_watermark_depth - test_stack_watermark_enter;
|
||||||
|
if (depth < 0) {
|
||||||
|
depth = -depth;
|
||||||
|
}
|
||||||
|
return depth;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// get the current stack usage, note this is included in test_stack
|
||||||
|
//
|
||||||
|
// note note the noinline here is important for forcing a new stack frame
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
|
__attribute__((noinline))
|
||||||
|
size_t test_stack_current(void) {
|
||||||
|
uint8_t *watermark = __builtin_frame_address(0);
|
||||||
|
|
||||||
|
ssize_t depth = watermark - test_stack_watermark_enter;
|
||||||
|
if (depth < 0) {
|
||||||
|
depth = -depth;
|
||||||
|
}
|
||||||
|
return depth;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// heap hooks
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
uint32_t test_heap_entered = 0;
|
||||||
|
size_t test_heap_watermark = 0;
|
||||||
|
size_t test_heap_watermark_depth = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// call me when entering/exiting a test!
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
void test_heap_enter(void) {
|
||||||
|
test_heap_entered = 1;
|
||||||
|
test_heap_watermark = 0;
|
||||||
|
test_heap_watermark_depth = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
void test_heap_exit(void) {
|
||||||
|
test_heap_entered = 0;
|
||||||
|
if (test_heap_watermark != 0) {
|
||||||
|
fprintf(stderr, "warning: memory leak detected (%zd > 0)\n",
|
||||||
|
test_heap_watermark);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// call me when entering/exiting a bd op!
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
void test_heap_pause(void) {
|
||||||
|
// haha, a little 32-bit stack
|
||||||
|
test_heap_entered <<= 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
void test_heap_resume(void) {
|
||||||
|
test_heap_entered >>= 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
static void test_heap_inc(size_t size) {
|
||||||
|
if (test_heap_entered & 1) {
|
||||||
|
test_heap_watermark += size;
|
||||||
|
// keep track of the deepest heap
|
||||||
|
if (test_heap_watermark > test_heap_watermark_depth) {
|
||||||
|
test_heap_watermark_depth = test_heap_watermark;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
static void test_heap_dec(size_t size) {
|
||||||
|
if (test_heap_entered & 1) {
|
||||||
|
assert(test_heap_watermark >= size);
|
||||||
|
test_heap_watermark -= size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// get the worst-case heap usage
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
size_t test_heap(void) {
|
||||||
|
return test_heap_watermark_depth;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// get the current heap usage
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
size_t test_heap_current(void) {
|
||||||
|
return test_heap_watermark;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// __real_malloc stubs, gcc's --wrap wraps these over the original symbols
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
extern void *__real_malloc(size_t size);
|
||||||
|
extern void __real_free(void *p);
|
||||||
|
extern void *__real_realloc(void *p, size_t size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// the actual malloc hooks
|
||||||
|
//
|
||||||
|
// these only work if wrapped via gcc's --wrap
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
void *__wrap_malloc(size_t size) {
|
||||||
|
// prefix with allocation size, note we use uintptr_t to hopefully
|
||||||
|
// keep things aligned
|
||||||
|
uintptr_t *p_ = __real_malloc(sizeof(uintptr_t) + size);
|
||||||
|
if (!p_) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
test_heap_inc(size);
|
||||||
|
*p_ = size;
|
||||||
|
return p_ + 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
void __wrap_free(void *p) {
|
||||||
|
if (!p) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uintptr_t *p_ = ((uintptr_t*)p) - 1;
|
||||||
|
size_t size = *p_;
|
||||||
|
test_heap_dec(size);
|
||||||
|
|
||||||
|
__real_free(p_);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
void *__wrap_realloc(void *p, size_t size) {
|
||||||
|
uintptr_t *p_;
|
||||||
|
size_t old;
|
||||||
|
if (p) {
|
||||||
|
p_ = ((uintptr_t*)p) - 1;
|
||||||
|
old = *p_;
|
||||||
|
} else {
|
||||||
|
p_ = NULL;
|
||||||
|
old = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(size != 0);
|
||||||
|
p_ = __real_realloc(p_, sizeof(uintptr_t) + size);
|
||||||
|
if (!p_) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
test_heap_dec(old);
|
||||||
|
test_heap_inc(size);
|
||||||
|
*p_ = size;
|
||||||
|
return p_ + 1;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// encode our permutation into a reusable id
|
// encode our permutation into a reusable id
|
||||||
static void perm_printid(
|
static void perm_printid(
|
||||||
const struct test_suite *suite,
|
const struct test_suite *suite,
|
||||||
@@ -1315,6 +1531,103 @@ static void list_implicit_defines(void) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// test bd wrappers for heap/stack tracking
|
||||||
|
int test_bd_read(const struct lfs3_cfg *cfg, lfs3_block_t block,
|
||||||
|
lfs3_off_t off, void *buffer, lfs3_size_t size) {
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
|
TEST_STACK_PAUSE();
|
||||||
|
#endif
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
TEST_HEAP_PAUSE();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TEST_KIWIBD
|
||||||
|
int err = lfs3_kiwibd_read(cfg, block, off, buffer, size);
|
||||||
|
#else
|
||||||
|
int err = lfs3_emubd_read(cfg, block, off, buffer, size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
TEST_HEAP_RESUME();
|
||||||
|
#endif
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
|
TEST_STACK_RESUME();
|
||||||
|
#endif
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_bd_prog(const struct lfs3_cfg *cfg, lfs3_block_t block,
|
||||||
|
lfs3_off_t off, const void *buffer, lfs3_size_t size) {
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
|
TEST_STACK_PAUSE();
|
||||||
|
#endif
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
TEST_HEAP_PAUSE();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TEST_KIWIBD
|
||||||
|
int err = lfs3_kiwibd_prog(cfg, block, off, buffer, size);
|
||||||
|
#else
|
||||||
|
int err = lfs3_emubd_prog(cfg, block, off, buffer, size);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
TEST_HEAP_RESUME();
|
||||||
|
#endif
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
|
TEST_STACK_RESUME();
|
||||||
|
#endif
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_bd_erase(const struct lfs3_cfg *cfg, lfs3_block_t block) {
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
|
TEST_STACK_PAUSE();
|
||||||
|
#endif
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
TEST_HEAP_PAUSE();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TEST_KIWIBD
|
||||||
|
int err = lfs3_kiwibd_erase(cfg, block);
|
||||||
|
#else
|
||||||
|
int err = lfs3_emubd_erase(cfg, block);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
TEST_HEAP_RESUME();
|
||||||
|
#endif
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
|
TEST_STACK_RESUME();
|
||||||
|
#endif
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_bd_sync(const struct lfs3_cfg *cfg) {
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
|
TEST_STACK_PAUSE();
|
||||||
|
#endif
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
TEST_HEAP_PAUSE();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TEST_KIWIBD
|
||||||
|
int err = lfs3_kiwibd_sync(cfg);
|
||||||
|
#else
|
||||||
|
int err = lfs3_emubd_sync(cfg);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
TEST_HEAP_RESUME();
|
||||||
|
#endif
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
|
TEST_STACK_RESUME();
|
||||||
|
#endif
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// scenarios to run tests under powerloss
|
// scenarios to run tests under powerloss
|
||||||
|
|
||||||
static void run_powerloss_none(
|
static void run_powerloss_none(
|
||||||
@@ -1323,6 +1636,9 @@ static void run_powerloss_none(
|
|||||||
const struct test_case *case_) {
|
const struct test_case *case_) {
|
||||||
(void)powerloss;
|
(void)powerloss;
|
||||||
|
|
||||||
|
// zero pls
|
||||||
|
TEST_PLS = 0;
|
||||||
|
|
||||||
// create block device and configuration
|
// create block device and configuration
|
||||||
#ifndef TEST_KIWIBD
|
#ifndef TEST_KIWIBD
|
||||||
lfs3_emubd_t bd;
|
lfs3_emubd_t bd;
|
||||||
@@ -1332,17 +1648,10 @@ static void run_powerloss_none(
|
|||||||
|
|
||||||
struct lfs3_cfg cfg = {
|
struct lfs3_cfg cfg = {
|
||||||
.context = &bd,
|
.context = &bd,
|
||||||
#ifndef TEST_KIWIBD
|
.read = test_bd_read,
|
||||||
.read = lfs3_emubd_read,
|
.prog = test_bd_prog,
|
||||||
.prog = lfs3_emubd_prog,
|
.erase = test_bd_erase,
|
||||||
.erase = lfs3_emubd_erase,
|
.sync = test_bd_sync,
|
||||||
.sync = lfs3_emubd_sync,
|
|
||||||
#else
|
|
||||||
.read = lfs3_kiwibd_read,
|
|
||||||
.prog = lfs3_kiwibd_prog,
|
|
||||||
.erase = lfs3_kiwibd_erase,
|
|
||||||
.sync = lfs3_kiwibd_sync,
|
|
||||||
#endif
|
|
||||||
#define TEST_CFG(k, v) \
|
#define TEST_CFG(k, v) \
|
||||||
.k = v,
|
.k = v,
|
||||||
#include "test_defines.h"
|
#include "test_defines.h"
|
||||||
@@ -1390,12 +1699,21 @@ static void run_powerloss_none(
|
|||||||
printf("running ");
|
printf("running ");
|
||||||
perm_printid(suite, case_, NULL, 0);
|
perm_printid(suite, case_, NULL, 0);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
// zero pls
|
test_stack_enter();
|
||||||
TEST_PLS = 0;
|
#endif
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
test_heap_enter();
|
||||||
|
#endif
|
||||||
|
|
||||||
case_->run(&cfg);
|
case_->run(&cfg);
|
||||||
|
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
test_heap_exit();
|
||||||
|
#endif
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
|
test_stack_exit();
|
||||||
|
#endif
|
||||||
printf("finished ");
|
printf("finished ");
|
||||||
perm_printid(suite, case_, NULL, 0);
|
perm_printid(suite, case_, NULL, 0);
|
||||||
printf("\n");
|
printf("\n");
|
||||||
@@ -1437,10 +1755,10 @@ static void run_powerloss_linear(
|
|||||||
|
|
||||||
struct lfs3_cfg cfg = {
|
struct lfs3_cfg cfg = {
|
||||||
.context = &bd,
|
.context = &bd,
|
||||||
.read = lfs3_emubd_read,
|
.read = test_bd_read,
|
||||||
.prog = lfs3_emubd_prog,
|
.prog = test_bd_prog,
|
||||||
.erase = lfs3_emubd_erase,
|
.erase = test_bd_erase,
|
||||||
.sync = lfs3_emubd_sync,
|
.sync = test_bd_sync,
|
||||||
#define TEST_CFG(k, v) \
|
#define TEST_CFG(k, v) \
|
||||||
.k = v,
|
.k = v,
|
||||||
#include "test_defines.h"
|
#include "test_defines.h"
|
||||||
@@ -1475,8 +1793,22 @@ static void run_powerloss_linear(
|
|||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (!setjmp(powerloss_jmp)) {
|
if (!setjmp(powerloss_jmp)) {
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
|
test_stack_enter();
|
||||||
|
#endif
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
test_heap_enter();
|
||||||
|
#endif
|
||||||
|
|
||||||
// run the test
|
// run the test
|
||||||
case_->run(&cfg);
|
case_->run(&cfg);
|
||||||
|
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
test_heap_exit();
|
||||||
|
#endif
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
|
test_stack_exit();
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1521,10 +1853,10 @@ static void run_powerloss_log(
|
|||||||
|
|
||||||
struct lfs3_cfg cfg = {
|
struct lfs3_cfg cfg = {
|
||||||
.context = &bd,
|
.context = &bd,
|
||||||
.read = lfs3_emubd_read,
|
.read = test_bd_read,
|
||||||
.prog = lfs3_emubd_prog,
|
.prog = test_bd_prog,
|
||||||
.erase = lfs3_emubd_erase,
|
.erase = test_bd_erase,
|
||||||
.sync = lfs3_emubd_sync,
|
.sync = test_bd_sync,
|
||||||
#define TEST_CFG(k, v) \
|
#define TEST_CFG(k, v) \
|
||||||
.k = v,
|
.k = v,
|
||||||
#include "test_defines.h"
|
#include "test_defines.h"
|
||||||
@@ -1559,8 +1891,22 @@ static void run_powerloss_log(
|
|||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (!setjmp(powerloss_jmp)) {
|
if (!setjmp(powerloss_jmp)) {
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
|
test_stack_enter();
|
||||||
|
#endif
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
test_heap_enter();
|
||||||
|
#endif
|
||||||
|
|
||||||
// run the test
|
// run the test
|
||||||
case_->run(&cfg);
|
case_->run(&cfg);
|
||||||
|
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
test_heap_exit();
|
||||||
|
#endif
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
|
test_stack_exit();
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1605,10 +1951,10 @@ static void run_powerloss_cycles(
|
|||||||
|
|
||||||
struct lfs3_cfg cfg = {
|
struct lfs3_cfg cfg = {
|
||||||
.context = &bd,
|
.context = &bd,
|
||||||
.read = lfs3_emubd_read,
|
.read = test_bd_read,
|
||||||
.prog = lfs3_emubd_prog,
|
.prog = test_bd_prog,
|
||||||
.erase = lfs3_emubd_erase,
|
.erase = test_bd_erase,
|
||||||
.sync = lfs3_emubd_sync,
|
.sync = test_bd_sync,
|
||||||
#define TEST_CFG(k, v) \
|
#define TEST_CFG(k, v) \
|
||||||
.k = v,
|
.k = v,
|
||||||
#include "test_defines.h"
|
#include "test_defines.h"
|
||||||
@@ -1643,8 +1989,22 @@ static void run_powerloss_cycles(
|
|||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (!setjmp(powerloss_jmp)) {
|
if (!setjmp(powerloss_jmp)) {
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
|
test_stack_enter();
|
||||||
|
#endif
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
test_heap_enter();
|
||||||
|
#endif
|
||||||
|
|
||||||
// run the test
|
// run the test
|
||||||
case_->run(&cfg);
|
case_->run(&cfg);
|
||||||
|
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
test_heap_exit();
|
||||||
|
#endif
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
|
test_stack_exit();
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1742,9 +2102,23 @@ static void run_powerloss_exhaustive_layer(
|
|||||||
lfs3_emubd_setpowercycles(state.cfg, (depth > 0) ? 1 : 0);
|
lfs3_emubd_setpowercycles(state.cfg, (depth > 0) ? 1 : 0);
|
||||||
bdcfg->powerloss_data = &state;
|
bdcfg->powerloss_data = &state;
|
||||||
|
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
|
test_stack_enter();
|
||||||
|
#endif
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
test_heap_enter();
|
||||||
|
#endif
|
||||||
|
|
||||||
// run the tests
|
// run the tests
|
||||||
case_->run(cfg);
|
case_->run(cfg);
|
||||||
|
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
test_heap_exit();
|
||||||
|
#endif
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
|
test_stack_exit();
|
||||||
|
#endif
|
||||||
|
|
||||||
// aggressively clean up memory here to try to keep our memory usage low
|
// aggressively clean up memory here to try to keep our memory usage low
|
||||||
int err = lfs3_emubd_destroy(cfg);
|
int err = lfs3_emubd_destroy(cfg);
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -1795,10 +2169,10 @@ static void run_powerloss_exhaustive(
|
|||||||
|
|
||||||
struct lfs3_cfg cfg = {
|
struct lfs3_cfg cfg = {
|
||||||
.context = &bd,
|
.context = &bd,
|
||||||
.read = lfs3_emubd_read,
|
.read = test_bd_read,
|
||||||
.prog = lfs3_emubd_prog,
|
.prog = test_bd_prog,
|
||||||
.erase = lfs3_emubd_erase,
|
.erase = test_bd_erase,
|
||||||
.sync = lfs3_emubd_sync,
|
.sync = test_bd_sync,
|
||||||
#define TEST_CFG(k, v) \
|
#define TEST_CFG(k, v) \
|
||||||
.k = v,
|
.k = v,
|
||||||
#include "test_defines.h"
|
#include "test_defines.h"
|
||||||
|
|||||||
@@ -115,6 +115,34 @@ void test_permutation(size_t i, uint32_t *buffer, size_t size);
|
|||||||
#define TEST_FACTORIAL(x) test_factorial(x)
|
#define TEST_FACTORIAL(x) test_factorial(x)
|
||||||
#define TEST_PERMUTATION(i, buffer, size) test_permutation(i, buffer, size)
|
#define TEST_PERMUTATION(i, buffer, size) test_permutation(i, buffer, size)
|
||||||
|
|
||||||
|
#ifdef TEST_YES_STACK
|
||||||
|
// get the maximum/current stack usage for this run
|
||||||
|
size_t test_stack(void);
|
||||||
|
__attribute__((noinline))
|
||||||
|
size_t test_stack_current(void);
|
||||||
|
__attribute__((noinline))
|
||||||
|
void test_stack_pause(void);
|
||||||
|
void test_stack_resume(void);
|
||||||
|
|
||||||
|
#define TEST_STACK() test_stack()
|
||||||
|
#define TEST_STACK_CURRENT() test_stack_current()
|
||||||
|
#define TEST_STACK_PAUSE() test_stack_pause()
|
||||||
|
#define TEST_STACK_RESUME() test_stack_resume()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef TEST_YES_HEAP
|
||||||
|
// get the maximum/current heap usage for this run
|
||||||
|
size_t test_heap(void);
|
||||||
|
size_t test_heap_current(void);
|
||||||
|
void test_heap_pause(void);
|
||||||
|
void test_heap_resume(void);
|
||||||
|
|
||||||
|
#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()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
// declare implicit defines as global intmax_ts
|
// declare implicit defines as global intmax_ts
|
||||||
#define TEST_DEFINE(k, v) \
|
#define TEST_DEFINE(k, v) \
|
||||||
|
|||||||
Reference in New Issue
Block a user