Added shortcut encoding for linear/log powerlosses in test-runner

The previous encoding was a bit problematic with our linear and log
heuristics, which can grow thousands of powerlosses deep. You know you
have a problem when you're copying a test id that spans a dozen lines.

It also meant we were spending O(n^2) time just encoding powerloss ids:

  before: 942.68s
  after:  921.94s (-2.2%)

This new encoding takes advantage of the unused characters in our leb16
encoding, with an 'x' prefix indicating linear-heuristic powerlosses
and a 'y' prefix indicating log-heuristic powerlosses ('w' is used for
negative leb16s).

Before:

  - explicit: 42q2q2
  - linear:   123456789abcdefg1h1i1j1k1l1m1n1o1p1q1r1s1t1u1v1
  - log:      1248g1g2g4g8gg1gg2gg4gg8

After:

  - explicit: 42q2q2
  - linear:   xg2
  - log:      yc
This commit is contained in:
Christopher Haster
2023-11-29 17:59:37 -06:00
parent d485795336
commit 4da7c88eb0
3 changed files with 185 additions and 178 deletions
+9 -17
View File
@@ -795,16 +795,15 @@ void bench_seen_cleanup(bench_seen_t *seen) {
static void case_forperm( static void case_forperm(
const struct bench_suite *suite, const struct bench_suite *suite,
const struct bench_case *case_, const struct bench_case *case_,
const bench_define_t *defines, const bench_id_t *id,
size_t define_count,
void (*cb)( void (*cb)(
void *data, void *data,
const struct bench_suite *suite, const struct bench_suite *suite,
const struct bench_case *case_), const struct bench_case *case_),
void *data) { void *data) {
// explicit permutation? // explicit permutation?
if (defines) { if (id && id->defines) {
bench_define_explicit(defines, define_count); bench_define_explicit(id->defines, id->define_count);
size_t permutations = bench_define_permutationpermutations(); size_t permutations = bench_define_permutationpermutations();
for (size_t p = 0; p < permutations; p++) { for (size_t p = 0; p < permutations; p++) {
@@ -861,7 +860,6 @@ void perm_count(
const struct bench_case *case_) { const struct bench_case *case_) {
struct perm_count_state *state = data; struct perm_count_state *state = data;
(void)suite; (void)suite;
(void)case_;
state->total += 1; state->total += 1;
@@ -900,8 +898,7 @@ static void summary(void) {
case_forperm( case_forperm(
bench_suites[i], bench_suites[i],
&bench_suites[i]->cases[j], &bench_suites[i]->cases[j],
bench_ids[t].defines, &bench_ids[t],
bench_ids[t].define_count,
perm_count, perm_count,
&perms); &perms);
} }
@@ -959,8 +956,7 @@ static void list_suites(void) {
case_forperm( case_forperm(
bench_suites[i], bench_suites[i],
&bench_suites[i]->cases[j], &bench_suites[i]->cases[j],
bench_ids[t].defines, &bench_ids[t],
bench_ids[t].define_count,
perm_count, perm_count,
&perms); &perms);
} }
@@ -1018,8 +1014,7 @@ static void list_cases(void) {
case_forperm( case_forperm(
bench_suites[i], bench_suites[i],
&bench_suites[i]->cases[j], &bench_suites[i]->cases[j],
bench_ids[t].defines, &bench_ids[t],
bench_ids[t].define_count,
perm_count, perm_count,
&perms); &perms);
@@ -1224,8 +1219,7 @@ static void list_defines(void) {
case_forperm( case_forperm(
bench_suites[i], bench_suites[i],
&bench_suites[i]->cases[j], &bench_suites[i]->cases[j],
bench_ids[t].defines, &bench_ids[t],
bench_ids[t].define_count,
perm_list_defines, perm_list_defines,
&defines); &defines);
} }
@@ -1270,8 +1264,7 @@ static void list_permutation_defines(void) {
case_forperm( case_forperm(
bench_suites[i], bench_suites[i],
&bench_suites[i]->cases[j], &bench_suites[i]->cases[j],
bench_ids[t].defines, &bench_ids[t],
bench_ids[t].define_count,
perm_list_permutation_defines, perm_list_permutation_defines,
&defines); &defines);
} }
@@ -1420,8 +1413,7 @@ static void run(void) {
case_forperm( case_forperm(
bench_suites[i], bench_suites[i],
&bench_suites[i]->cases[j], &bench_suites[i]->cases[j],
bench_ids[t].defines, &bench_ids[t],
bench_ids[t].define_count,
perm_run, perm_run,
NULL); NULL);
} }
+175 -160
View File
@@ -113,8 +113,7 @@ static uintmax_t leb16_parse(const char *s, char **tail) {
typedef struct test_powerloss { typedef struct test_powerloss {
const char *name; const char *name;
void (*run)( void (*run)(
const lfs_emubd_powercycles_t *cycles, const struct test_powerloss *powerloss,
size_t cycle_count,
const struct test_suite *suite, const struct test_suite *suite,
const struct test_case *case_); const struct test_case *case_);
const lfs_emubd_powercycles_t *cycles; const lfs_emubd_powercycles_t *cycles;
@@ -125,8 +124,7 @@ typedef struct test_id {
const char *name; const char *name;
const test_define_t *defines; const test_define_t *defines;
size_t define_count; size_t define_count;
const lfs_emubd_powercycles_t *cycles; test_powerloss_t powerloss;
size_t cycle_count;
} test_id_t; } test_id_t;
@@ -452,12 +450,8 @@ void test_define_cleanup(void) {
// test state // test state
extern const test_powerloss_t *test_powerlosses;
extern size_t test_powerloss_count;
size_t test_pls = 0;
const test_id_t *test_ids = (const test_id_t[]) { const test_id_t *test_ids = (const test_id_t[]) {
{NULL, NULL, 0, NULL, 0}, {NULL, NULL, 0, {NULL, NULL, NULL, 0}},
}; };
size_t test_id_count = 1; size_t test_id_count = 1;
@@ -478,6 +472,12 @@ lfs_emubd_sleep_t test_read_sleep = 0.0;
lfs_emubd_sleep_t test_prog_sleep = 0.0; lfs_emubd_sleep_t test_prog_sleep = 0.0;
lfs_emubd_sleep_t test_erase_sleep = 0.0; lfs_emubd_sleep_t test_erase_sleep = 0.0;
volatile size_t test_pls = 0;
extern const test_powerloss_t *test_powerlosses;
extern size_t test_powerloss_count;
// this determines both the backtrace buffer and the trace printf buffer, if // this determines both the backtrace buffer and the trace printf buffer, if
// trace ends up interleaved or truncated this may need to be increased // trace ends up interleaved or truncated this may need to be increased
#ifndef TEST_TRACE_BACKTRACE_BUFFER_SIZE #ifndef TEST_TRACE_BACKTRACE_BUFFER_SIZE
@@ -654,7 +654,7 @@ static void perm_printid(
} }
// only print power-cycles if any occured // only print power-cycles if any occured
if (cycles) { if (cycle_count) {
printf(":"); printf(":");
for (size_t i = 0; i < cycle_count; i++) { for (size_t i = 0; i < cycle_count; i++) {
leb16_print(cycles[i]); leb16_print(cycles[i]);
@@ -717,13 +717,11 @@ void test_seen_cleanup(test_seen_t *seen) {
} }
static void run_powerloss_none( static void run_powerloss_none(
const lfs_emubd_powercycles_t *cycles, const test_powerloss_t *powerloss,
size_t cycle_count,
const struct test_suite *suite, const struct test_suite *suite,
const struct test_case *case_); const struct test_case *case_);
static void run_powerloss_cycles( static void run_powerloss_cycles(
const lfs_emubd_powercycles_t *cycles, const test_powerloss_t *powerloss,
size_t cycle_count,
const struct test_suite *suite, const struct test_suite *suite,
const struct test_case *case_); const struct test_case *case_);
@@ -731,10 +729,7 @@ static void run_powerloss_cycles(
static void case_forperm( static void case_forperm(
const struct test_suite *suite, const struct test_suite *suite,
const struct test_case *case_, const struct test_case *case_,
const test_define_t *defines, const test_id_t *id,
size_t define_count,
const lfs_emubd_powercycles_t *cycles,
size_t cycle_count,
void (*cb)( void (*cb)(
void *data, void *data,
const struct test_suite *suite, const struct test_suite *suite,
@@ -742,8 +737,8 @@ static void case_forperm(
const test_powerloss_t *powerloss), const test_powerloss_t *powerloss),
void *data) { void *data) {
// explicit permutation? // explicit permutation?
if (defines) { if (id && id->defines) {
test_define_explicit(defines, define_count); test_define_explicit(id->defines, id->define_count);
size_t permutations = test_define_permutationpermutations(); size_t permutations = test_define_permutationpermutations();
for (size_t p = 0; p < permutations; p++) { for (size_t p = 0; p < permutations; p++) {
@@ -751,11 +746,8 @@ static void case_forperm(
test_define_permutation(p); test_define_permutation(p);
// explicit powerloss cycles? // explicit powerloss cycles?
if (cycles) { if (id && id->powerloss.run) {
cb(data, suite, case_, &(test_powerloss_t){ cb(data, suite, case_, &id->powerloss);
.run=run_powerloss_cycles,
.cycles=cycles,
.cycle_count=cycle_count});
} else { } else {
for (size_t p = 0; p < test_powerloss_count; p++) { for (size_t p = 0; p < test_powerloss_count; p++) {
// skip non-reentrant tests when powerloss testing // skip non-reentrant tests when powerloss testing
@@ -796,11 +788,9 @@ static void case_forperm(
continue; continue;
} }
if (cycles) { // explicit powerloss cycles?
cb(data, suite, case_, &(test_powerloss_t){ if (id && id->powerloss.run) {
.run=run_powerloss_cycles, cb(data, suite, case_, &id->powerloss);
.cycles=cycles,
.cycle_count=cycle_count});
} else { } else {
for (size_t p = 0; p < test_powerloss_count; p++) { for (size_t p = 0; p < test_powerloss_count; p++) {
// skip non-reentrant tests when powerloss testing // skip non-reentrant tests when powerloss testing
@@ -832,8 +822,6 @@ void perm_count(
const test_powerloss_t *powerloss) { const test_powerloss_t *powerloss) {
struct perm_count_state *state = data; struct perm_count_state *state = data;
(void)suite; (void)suite;
(void)case_;
(void)powerloss;
state->total += 1; state->total += 1;
@@ -874,10 +862,7 @@ static void summary(void) {
case_forperm( case_forperm(
test_suites[i], test_suites[i],
&test_suites[i]->cases[j], &test_suites[i]->cases[j],
test_ids[t].defines, &test_ids[t],
test_ids[t].define_count,
test_ids[t].cycles,
test_ids[t].cycle_count,
perm_count, perm_count,
&perms); &perms);
} }
@@ -936,10 +921,7 @@ static void list_suites(void) {
case_forperm( case_forperm(
test_suites[i], test_suites[i],
&test_suites[i]->cases[j], &test_suites[i]->cases[j],
test_ids[t].defines, &test_ids[t],
test_ids[t].define_count,
test_ids[t].cycles,
test_ids[t].cycle_count,
perm_count, perm_count,
&perms); &perms);
} }
@@ -998,10 +980,7 @@ static void list_cases(void) {
case_forperm( case_forperm(
test_suites[i], test_suites[i],
&test_suites[i]->cases[j], &test_suites[i]->cases[j],
test_ids[t].defines, &test_ids[t],
test_ids[t].define_count,
test_ids[t].cycles,
test_ids[t].cycle_count,
perm_count, perm_count,
&perms); &perms);
@@ -1212,10 +1191,7 @@ static void list_defines(void) {
case_forperm( case_forperm(
test_suites[i], test_suites[i],
&test_suites[i]->cases[j], &test_suites[i]->cases[j],
test_ids[t].defines, &test_ids[t],
test_ids[t].define_count,
test_ids[t].cycles,
test_ids[t].cycle_count,
perm_list_defines, perm_list_defines,
&defines); &defines);
} }
@@ -1260,10 +1236,7 @@ static void list_permutation_defines(void) {
case_forperm( case_forperm(
test_suites[i], test_suites[i],
&test_suites[i]->cases[j], &test_suites[i]->cases[j],
test_ids[t].defines, &test_ids[t],
test_ids[t].define_count,
test_ids[t].cycles,
test_ids[t].cycle_count,
perm_list_permutation_defines, perm_list_permutation_defines,
&defines); &defines);
} }
@@ -1322,13 +1295,10 @@ static void list_implicit_defines(void) {
// scenarios to run tests under power-loss // scenarios to run tests under power-loss
static void run_powerloss_none( static void run_powerloss_none(
const lfs_emubd_powercycles_t *cycles, const test_powerloss_t *powerloss,
size_t cycle_count,
const struct test_suite *suite, const struct test_suite *suite,
const struct test_case *case_) { const struct test_case *case_) {
(void)cycles; (void)powerloss;
(void)cycle_count;
(void)suite;
// create block device and configuration // create block device and configuration
lfs_emubd_t bd; lfs_emubd_t bd;
@@ -1384,18 +1354,15 @@ static void powerloss_longjmp(void *c) {
} }
static void run_powerloss_linear( static void run_powerloss_linear(
const lfs_emubd_powercycles_t *cycles, const test_powerloss_t *powerloss,
size_t cycle_count,
const struct test_suite *suite, const struct test_suite *suite,
const struct test_case *case_) { const struct test_case *case_) {
(void)cycles; // zero pls
(void)cycle_count; test_pls = 0;
(void)suite;
// create block device and configuration // create block device and configuration
lfs_emubd_t bd; lfs_emubd_t bd;
jmp_buf powerloss_jmp; jmp_buf powerloss_jmp;
volatile lfs_emubd_powercycles_t i = 1;
struct lfs_config cfg = { struct lfs_config cfg = {
.context = &bd, .context = &bd,
@@ -1411,7 +1378,9 @@ static void run_powerloss_linear(
.read_sleep = test_read_sleep, .read_sleep = test_read_sleep,
.prog_sleep = test_prog_sleep, .prog_sleep = test_prog_sleep,
.erase_sleep = test_erase_sleep, .erase_sleep = test_erase_sleep,
.power_cycles = i, .power_cycles = (test_pls < powerloss->cycle_count)
? test_pls+1
: 0,
.powerloss_behavior = POWERLOSS_BEHAVIOR, .powerloss_behavior = POWERLOSS_BEHAVIOR,
.powerloss_cb = powerloss_longjmp, .powerloss_cb = powerloss_longjmp,
.powerloss_data = &powerloss_jmp, .powerloss_data = &powerloss_jmp,
@@ -1429,9 +1398,6 @@ static void run_powerloss_linear(
perm_printid(suite, case_, NULL, 0); perm_printid(suite, case_, NULL, 0);
printf("\n"); printf("\n");
// zero pls before first run
test_pls = 0;
while (true) { while (true) {
if (!setjmp(powerloss_jmp)) { if (!setjmp(powerloss_jmp)) {
// run the test // run the test
@@ -1442,16 +1408,15 @@ static void run_powerloss_linear(
// power-loss! // power-loss!
printf("powerloss "); printf("powerloss ");
perm_printid(suite, case_, NULL, 0); perm_printid(suite, case_, NULL, 0);
printf(":"); printf(":x");
for (lfs_emubd_powercycles_t j = 1; j <= i; j++) { leb16_print(test_pls+1);
leb16_print(j);
}
printf("\n"); printf("\n");
// increment pls // increment pls
test_pls += 1; test_pls += 1;
i += 1; lfs_emubd_setpowercycles(&cfg, (test_pls < powerloss->cycle_count)
lfs_emubd_setpowercycles(&cfg, i); ? test_pls+1
: 0);
} }
printf("finished "); printf("finished ");
@@ -1467,18 +1432,15 @@ static void run_powerloss_linear(
} }
static void run_powerloss_log( static void run_powerloss_log(
const lfs_emubd_powercycles_t *cycles, const test_powerloss_t *powerloss,
size_t cycle_count,
const struct test_suite *suite, const struct test_suite *suite,
const struct test_case *case_) { const struct test_case *case_) {
(void)cycles; // zero pls
(void)cycle_count; test_pls = 0;
(void)suite;
// create block device and configuration // create block device and configuration
lfs_emubd_t bd; lfs_emubd_t bd;
jmp_buf powerloss_jmp; jmp_buf powerloss_jmp;
volatile lfs_emubd_powercycles_t i = 1;
struct lfs_config cfg = { struct lfs_config cfg = {
.context = &bd, .context = &bd,
@@ -1494,7 +1456,9 @@ static void run_powerloss_log(
.read_sleep = test_read_sleep, .read_sleep = test_read_sleep,
.prog_sleep = test_prog_sleep, .prog_sleep = test_prog_sleep,
.erase_sleep = test_erase_sleep, .erase_sleep = test_erase_sleep,
.power_cycles = i, .power_cycles = (test_pls < powerloss->cycle_count)
? 1 << test_pls
: 0,
.powerloss_behavior = POWERLOSS_BEHAVIOR, .powerloss_behavior = POWERLOSS_BEHAVIOR,
.powerloss_cb = powerloss_longjmp, .powerloss_cb = powerloss_longjmp,
.powerloss_data = &powerloss_jmp, .powerloss_data = &powerloss_jmp,
@@ -1512,9 +1476,6 @@ static void run_powerloss_log(
perm_printid(suite, case_, NULL, 0); perm_printid(suite, case_, NULL, 0);
printf("\n"); printf("\n");
// zero pls before first run
test_pls = 0;
while (true) { while (true) {
if (!setjmp(powerloss_jmp)) { if (!setjmp(powerloss_jmp)) {
// run the test // run the test
@@ -1525,16 +1486,15 @@ static void run_powerloss_log(
// power-loss! // power-loss!
printf("powerloss "); printf("powerloss ");
perm_printid(suite, case_, NULL, 0); perm_printid(suite, case_, NULL, 0);
printf(":"); printf(":y");
for (lfs_emubd_powercycles_t j = 1; j <= i; j *= 2) { leb16_print(test_pls+1);
leb16_print(j);
}
printf("\n"); printf("\n");
// increment pls // increment pls
test_pls += 1; test_pls += 1;
i *= 2; lfs_emubd_setpowercycles(&cfg, (test_pls < powerloss->cycle_count)
lfs_emubd_setpowercycles(&cfg, i); ? 1 << test_pls
: 0);
} }
printf("finished "); printf("finished ");
@@ -1550,16 +1510,15 @@ static void run_powerloss_log(
} }
static void run_powerloss_cycles( static void run_powerloss_cycles(
const lfs_emubd_powercycles_t *cycles, const test_powerloss_t *powerloss,
size_t cycle_count,
const struct test_suite *suite, const struct test_suite *suite,
const struct test_case *case_) { const struct test_case *case_) {
(void)suite; // zero pls
test_pls = 0;
// create block device and configuration // create block device and configuration
lfs_emubd_t bd; lfs_emubd_t bd;
jmp_buf powerloss_jmp; jmp_buf powerloss_jmp;
volatile size_t i = 0;
struct lfs_config cfg = { struct lfs_config cfg = {
.context = &bd, .context = &bd,
@@ -1575,7 +1534,9 @@ static void run_powerloss_cycles(
.read_sleep = test_read_sleep, .read_sleep = test_read_sleep,
.prog_sleep = test_prog_sleep, .prog_sleep = test_prog_sleep,
.erase_sleep = test_erase_sleep, .erase_sleep = test_erase_sleep,
.power_cycles = (i < cycle_count) ? cycles[i] : 0, .power_cycles = (test_pls < powerloss->cycle_count)
? powerloss->cycles[test_pls]
: 0,
.powerloss_behavior = POWERLOSS_BEHAVIOR, .powerloss_behavior = POWERLOSS_BEHAVIOR,
.powerloss_cb = powerloss_longjmp, .powerloss_cb = powerloss_longjmp,
.powerloss_data = &powerloss_jmp, .powerloss_data = &powerloss_jmp,
@@ -1593,9 +1554,6 @@ static void run_powerloss_cycles(
perm_printid(suite, case_, NULL, 0); perm_printid(suite, case_, NULL, 0);
printf("\n"); printf("\n");
// zero pls before first run
test_pls = 0;
while (true) { while (true) {
if (!setjmp(powerloss_jmp)) { if (!setjmp(powerloss_jmp)) {
// run the test // run the test
@@ -1604,16 +1562,16 @@ static void run_powerloss_cycles(
} }
// power-loss! // power-loss!
assert(i <= cycle_count); assert(test_pls <= powerloss->cycle_count);
printf("powerloss "); printf("powerloss ");
perm_printid(suite, case_, cycles, i+1); perm_printid(suite, case_, powerloss->cycles, test_pls+1);
printf("\n"); printf("\n");
// increment pls // increment pls
test_pls += 1; test_pls += 1;
i += 1; lfs_emubd_setpowercycles(&cfg, (test_pls < powerloss->cycle_count)
lfs_emubd_setpowercycles(&cfg, ? powerloss->cycles[test_pls]
(i < cycle_count) ? cycles[i] : 0); : 0);
} }
printf("finished "); printf("finished ");
@@ -1674,8 +1632,6 @@ static void run_powerloss_exhaustive_layer(
struct lfs_emubd_config *bdcfg, struct lfs_emubd_config *bdcfg,
size_t depth, size_t depth,
size_t pls) { size_t pls) {
(void)suite;
struct powerloss_exhaustive_state state = { struct powerloss_exhaustive_state state = {
.cfg = cfg, .cfg = cfg,
.branches = NULL, .branches = NULL,
@@ -1683,14 +1639,14 @@ static void run_powerloss_exhaustive_layer(
.branch_capacity = 0, .branch_capacity = 0,
}; };
// make the number of pls currently seen available to tests/debugging
test_pls = pls;
// run through the test without additional powerlosses, collecting possible // run through the test without additional powerlosses, collecting possible
// branches as we do so // branches as we do so
lfs_emubd_setpowercycles(state.cfg, depth > 0 ? 1 : 0); lfs_emubd_setpowercycles(state.cfg, depth > 0 ? 1 : 0);
bdcfg->powerloss_data = &state; bdcfg->powerloss_data = &state;
// make the number of pls currently seen available to tests/debugging
test_pls = pls;
// run the tests // run the tests
case_->run(cfg); case_->run(cfg);
@@ -1734,13 +1690,9 @@ static void run_powerloss_exhaustive_layer(
} }
static void run_powerloss_exhaustive( static void run_powerloss_exhaustive(
const lfs_emubd_powercycles_t *cycles, const test_powerloss_t *powerloss,
size_t cycle_count,
const struct test_suite *suite, const struct test_suite *suite,
const struct test_case *case_) { const struct test_case *case_) {
(void)cycles;
(void)suite;
// create block device and configuration // create block device and configuration
lfs_emubd_t bd; lfs_emubd_t bd;
@@ -1779,7 +1731,7 @@ static void run_powerloss_exhaustive(
run_powerloss_exhaustive_layer( run_powerloss_exhaustive_layer(
&(struct powerloss_exhaustive_cycles){NULL, 0, 0}, &(struct powerloss_exhaustive_cycles){NULL, 0, 0},
suite, case_, suite, case_,
&cfg, &bdcfg, cycle_count, 0); &cfg, &bdcfg, powerloss->cycle_count, 0);
printf("finished "); printf("finished ");
perm_printid(suite, case_, NULL, 0); perm_printid(suite, case_, NULL, 0);
@@ -1789,8 +1741,8 @@ static void run_powerloss_exhaustive(
const test_powerloss_t builtin_powerlosses[] = { const test_powerloss_t builtin_powerlosses[] = {
{"none", run_powerloss_none, NULL, 0}, {"none", run_powerloss_none, NULL, 0},
{"log", run_powerloss_log, NULL, 0}, {"log", run_powerloss_log, NULL, SIZE_MAX},
{"linear", run_powerloss_linear, NULL, 0}, {"linear", run_powerloss_linear, NULL, SIZE_MAX},
{"exhaustive", run_powerloss_exhaustive, NULL, SIZE_MAX}, {"exhaustive", run_powerloss_exhaustive, NULL, SIZE_MAX},
{NULL, NULL, NULL, 0}, {NULL, NULL, NULL, 0},
}; };
@@ -1809,7 +1761,7 @@ const char *const builtin_powerlosses_help[] = {
// running quickly // running quickly
const test_powerloss_t *test_powerlosses = (const test_powerloss_t[]){ const test_powerloss_t *test_powerlosses = (const test_powerloss_t[]){
{"none", run_powerloss_none, NULL, 0}, {"none", run_powerloss_none, NULL, 0},
{"linear", run_powerloss_linear, NULL, 0}, {"linear", run_powerloss_linear, NULL, SIZE_MAX},
}; };
size_t test_powerloss_count = 2; size_t test_powerloss_count = 2;
@@ -1870,9 +1822,7 @@ void perm_run(
} }
// run the test, possibly under powerloss // run the test, possibly under powerloss
powerloss->run( powerloss->run(powerloss, suite, case_);
powerloss->cycles, powerloss->cycle_count,
suite, case_);
} }
static void run(void) { static void run(void) {
@@ -1896,10 +1846,7 @@ static void run(void) {
case_forperm( case_forperm(
test_suites[i], test_suites[i],
&test_suites[i]->cases[j], &test_suites[i]->cases[j],
test_ids[t].defines, &test_ids[t],
test_ids[t].define_count,
test_ids[t].cycles,
test_ids[t].cycle_count,
perm_run, perm_run,
NULL); NULL);
} }
@@ -2295,43 +2242,68 @@ invalid_define:
} }
*powerloss = (test_powerloss_t){ *powerloss = (test_powerloss_t){
.run = run_powerloss_cycles, "explicit",
.cycles = cycles, run_powerloss_cycles,
.cycle_count = cycle_count, cycles,
}; cycle_count};
optarg = s; optarg = s;
goto powerloss_next; goto powerloss_next;
} }
// leb16-encoded permutation // leb16-encoded permutation
if (*optarg == ':') { if (*optarg == ':') {
lfs_emubd_powercycles_t *cycles = NULL; // special case for linear power cycles
size_t cycle_count = 0; if (optarg[1] == 'x') {
size_t cycle_capacity = 0; size_t cycle_count = leb16_parse(optarg+2, &optarg);
char *s = optarg + 1; *powerloss = (test_powerloss_t){
while (true) { "linear",
char *parsed = NULL; run_powerloss_linear,
uintmax_t x = leb16_parse(s, &parsed); NULL,
if (parsed == s) { cycle_count};
break; goto powerloss_next;
// special case for log power cycles
} else if (optarg[1] == 'y') {
size_t cycle_count = leb16_parse(optarg+2, &optarg);
*powerloss = (test_powerloss_t){
"log",
run_powerloss_log,
NULL,
cycle_count};
goto powerloss_next;
// otherwise explicit power cycles
} else {
lfs_emubd_powercycles_t *cycles = NULL;
size_t cycle_count = 0;
size_t cycle_capacity = 0;
char *s = optarg + 1;
while (true) {
char *parsed = NULL;
uintmax_t x = leb16_parse(s, &parsed);
if (parsed == s) {
break;
}
*(lfs_emubd_powercycles_t*)mappend(
(void**)&cycles,
sizeof(lfs_emubd_powercycles_t),
&cycle_count,
&cycle_capacity) = x;
s = parsed;
} }
*(lfs_emubd_powercycles_t*)mappend( *powerloss = (test_powerloss_t){
(void**)&cycles, "explicit",
sizeof(lfs_emubd_powercycles_t), run_powerloss_cycles,
&cycle_count, cycles,
&cycle_capacity) = x; cycle_count};
s = parsed; optarg = s;
goto powerloss_next;
} }
*powerloss = (test_powerloss_t){
.run = run_powerloss_cycles,
.cycles = cycles,
.cycle_count = cycle_count,
};
optarg = s;
goto powerloss_next;
} }
// exhaustive permutations // exhaustive permutations
@@ -2342,10 +2314,10 @@ invalid_define:
goto powerloss_unknown; goto powerloss_unknown;
} }
*powerloss = (test_powerloss_t){ *powerloss = (test_powerloss_t){
.run = run_powerloss_exhaustive, "exhaustive",
.cycles = NULL, run_powerloss_exhaustive,
.cycle_count = count, NULL,
}; count};
optarg = (char*)parsed; optarg = (char*)parsed;
goto powerloss_next; goto powerloss_next;
} }
@@ -2499,8 +2471,7 @@ getopt_done: ;
for (; argc > optind; optind++) { for (; argc > optind; optind++) {
test_define_t *defines = NULL; test_define_t *defines = NULL;
size_t define_count = 0; size_t define_count = 0;
lfs_emubd_powercycles_t *cycles = NULL; test_powerloss_t powerloss = {NULL, NULL, NULL, 0};
size_t cycle_count = 0;
// parse name, can be suite or case // parse name, can be suite or case
char *name = argv[optind]; char *name = argv[optind];
@@ -2550,8 +2521,47 @@ getopt_done: ;
defines[d] = TEST_LIT(v); defines[d] = TEST_LIT(v);
} }
if (cycles_) { // special case for linear power cycles
if (cycles_ && *cycles_ == 'x') {
char *parsed = NULL;
size_t cycle_count = leb16_parse(cycles_+1, &parsed);
if (parsed == cycles_+1) {
fprintf(stderr, "error: "
"could not parse test cycles: %s\n",
cycles_);
exit(-1);
}
cycles_ = parsed;
powerloss = (test_powerloss_t){
"linear",
run_powerloss_linear,
NULL,
cycle_count};
// special case for log power cycles
} else if (cycles_ && *cycles_ == 'y') {
char *parsed = NULL;
size_t cycle_count = leb16_parse(cycles_+1, &parsed);
if (parsed == cycles_+1) {
fprintf(stderr, "error: "
"could not parse test cycles: %s\n",
cycles_);
exit(-1);
}
cycles_ = parsed;
powerloss = (test_powerloss_t){
"log",
run_powerloss_log,
NULL,
cycle_count};
// otherwise explicit power cycles
} else if (cycles_) {
// parse power cycles // parse power cycles
lfs_emubd_powercycles_t *cycles = NULL;
size_t cycle_count = 0;
size_t cycle_capacity = 0; size_t cycle_capacity = 0;
while (*cycles_ != '\0') { while (*cycles_ != '\0') {
char *parsed = NULL; char *parsed = NULL;
@@ -2569,6 +2579,12 @@ getopt_done: ;
} }
cycles_ = parsed; cycles_ = parsed;
} }
powerloss = (test_powerloss_t){
"explicit",
run_powerloss_cycles,
cycles,
cycle_count};
} }
} }
@@ -2581,8 +2597,7 @@ getopt_done: ;
.name = name, .name = name,
.defines = defines, .defines = defines,
.define_count = define_count, .define_count = define_count,
.cycles = cycles, .powerloss = powerloss,
.cycle_count = cycle_count,
}; };
} }
@@ -2606,7 +2621,7 @@ getopt_done: ;
if (test_id_capacity) { if (test_id_capacity) {
for (size_t i = 0; i < test_id_count; i++) { for (size_t i = 0; i < test_id_count; i++) {
free((void*)test_ids[i].defines); free((void*)test_ids[i].defines);
free((void*)test_ids[i].cycles); free((void*)test_ids[i].powerloss.cycles);
} }
free((void*)test_ids); free((void*)test_ids);
} }
+1 -1
View File
@@ -74,7 +74,7 @@ extern const size_t test_suite_count;
// this variable tracks the number of powerlosses triggered during the // this variable tracks the number of powerlosses triggered during the
// current test permutation, this is useful for both tests and debugging // current test permutation, this is useful for both tests and debugging
extern size_t test_pls; extern volatile size_t test_pls;
#define TEST_PLS test_pls #define TEST_PLS test_pls