Added tailpipe.py and improved redirecting test trace/log output over fifos

This mostly involved futzing around with some of the less intuitive
parts of Unix's named-pipes behavior.

This is a bit important since the tests can quickly generate several
gigabytes of trace output.
This commit is contained in:
Christopher Haster
2022-08-27 16:50:03 -05:00
parent 5279fc6022
commit c9a6e3a95b
5 changed files with 268 additions and 90 deletions
+83 -34
View File
@@ -1,4 +1,8 @@
#ifndef _POSIX_C_SOURCE
#define _POSIX_C_SOURCE 199309L
#endif
#include "runners/test_runner.h"
#include "bd/lfs_testbd.h"
@@ -6,6 +10,10 @@
#include <sys/types.h>
#include <errno.h>
#include <setjmp.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
// test suites in a custom ld section
@@ -219,10 +227,10 @@ static void run_powerloss_none(
size_t perm,
const lfs_testbd_powercycles_t *cycles,
size_t cycle_count);
static const test_powerloss_t *test_powerlosses = (const test_powerloss_t[]){
const test_powerloss_t *test_powerlosses = (const test_powerloss_t[]){
{'0', "none", run_powerloss_none, NULL, 0},
};
static size_t test_powerloss_count = 1;
size_t test_powerloss_count = 1;
typedef struct test_id {
@@ -233,23 +241,70 @@ typedef struct test_id {
size_t cycle_count;
} test_id_t;
static const test_id_t *test_ids = (const test_id_t[]) {
const test_id_t *test_ids = (const test_id_t[]) {
{NULL, NULL, -1, NULL, 0},
};
static size_t test_id_count = 1;
size_t test_id_count = 1;
static const char *test_geometry = NULL;
const char *test_geometry = NULL;
static size_t test_start = 0;
static size_t test_stop = -1;
static size_t test_step = 1;
size_t test_start = 0;
size_t test_stop = -1;
size_t test_step = 1;
static const char *test_disk = NULL;
FILE *test_trace = NULL;
static lfs_testbd_delay_t test_read_delay = 0.0;
static lfs_testbd_delay_t test_prog_delay = 0.0;
static lfs_testbd_delay_t test_erase_delay = 0.0;
const char *test_disk_path = NULL;
const char *test_trace_path = NULL;
FILE *test_trace_file = NULL;
uint32_t test_trace_cycles = 0;
lfs_testbd_delay_t test_read_delay = 0.0;
lfs_testbd_delay_t test_prog_delay = 0.0;
lfs_testbd_delay_t test_erase_delay = 0.0;
// trace printing
void test_trace(const char *fmt, ...) {
if (test_trace_path) {
if (!test_trace_file) {
// Tracing output is heavy and trying to open every trace
// call is slow, so we only try to open the trace file every
// so often. Note this doesn't affect successfully opened files
if (test_trace_cycles % 128 != 0) {
test_trace_cycles += 1;
return;
}
test_trace_cycles += 1;
int fd;
if (strcmp(test_trace_path, "-") == 0) {
fd = dup(1);
} else {
fd = open(
test_trace_path,
O_WRONLY | O_CREAT | O_APPEND | O_NONBLOCK,
0666);
}
if (fd < 0) {
return;
}
FILE *f = fdopen(fd, "a");
assert(f);
int err = setvbuf(f, NULL, _IOLBF, BUFSIZ);
assert(!err);
test_trace_file = f;
}
va_list va;
va_start(va, fmt);
int res = vfprintf(test_trace_file, fmt, va);
if (res < 0) {
fclose(test_trace_file);
test_trace_file = NULL;
}
va_end(va);
}
}
// how many permutations are there actually in a test case
@@ -613,13 +668,13 @@ static void run_powerloss_none(
.erase_value = ERASE_VALUE,
.erase_cycles = ERASE_CYCLES,
.badblock_behavior = BADBLOCK_BEHAVIOR,
.disk_path = test_disk,
.disk_path = test_disk_path,
.read_delay = test_read_delay,
.prog_delay = test_prog_delay,
.erase_delay = test_erase_delay,
};
int err = lfs_testbd_createcfg(&cfg, test_disk, &bdcfg);
int err = lfs_testbd_createcfg(&cfg, test_disk_path, &bdcfg);
if (err) {
fprintf(stderr, "error: could not create block device: %d\n", err);
exit(-1);
@@ -679,7 +734,7 @@ static void run_powerloss_linear(
.erase_value = ERASE_VALUE,
.erase_cycles = ERASE_CYCLES,
.badblock_behavior = BADBLOCK_BEHAVIOR,
.disk_path = test_disk,
.disk_path = test_disk_path,
.read_delay = test_read_delay,
.prog_delay = test_prog_delay,
.erase_delay = test_erase_delay,
@@ -689,7 +744,7 @@ static void run_powerloss_linear(
.powerloss_data = &powerloss_jmp,
};
int err = lfs_testbd_createcfg(&cfg, test_disk, &bdcfg);
int err = lfs_testbd_createcfg(&cfg, test_disk_path, &bdcfg);
if (err) {
fprintf(stderr, "error: could not create block device: %d\n", err);
exit(-1);
@@ -760,7 +815,7 @@ static void run_powerloss_exponential(
.erase_value = ERASE_VALUE,
.erase_cycles = ERASE_CYCLES,
.badblock_behavior = BADBLOCK_BEHAVIOR,
.disk_path = test_disk,
.disk_path = test_disk_path,
.read_delay = test_read_delay,
.prog_delay = test_prog_delay,
.erase_delay = test_erase_delay,
@@ -770,7 +825,7 @@ static void run_powerloss_exponential(
.powerloss_data = &powerloss_jmp,
};
int err = lfs_testbd_createcfg(&cfg, test_disk, &bdcfg);
int err = lfs_testbd_createcfg(&cfg, test_disk_path, &bdcfg);
if (err) {
fprintf(stderr, "error: could not create block device: %d\n", err);
exit(-1);
@@ -839,7 +894,7 @@ static void run_powerloss_cycles(
.erase_value = ERASE_VALUE,
.erase_cycles = ERASE_CYCLES,
.badblock_behavior = BADBLOCK_BEHAVIOR,
.disk_path = test_disk,
.disk_path = test_disk_path,
.read_delay = test_read_delay,
.prog_delay = test_prog_delay,
.erase_delay = test_erase_delay,
@@ -849,7 +904,7 @@ static void run_powerloss_cycles(
.powerloss_data = &powerloss_jmp,
};
int err = lfs_testbd_createcfg(&cfg, test_disk, &bdcfg);
int err = lfs_testbd_createcfg(&cfg, test_disk_path, &bdcfg);
if (err) {
fprintf(stderr, "error: could not create block device: %d\n", err);
exit(-1);
@@ -1025,7 +1080,7 @@ static void run_powerloss_exhaustive(
.erase_value = ERASE_VALUE,
.erase_cycles = ERASE_CYCLES,
.badblock_behavior = BADBLOCK_BEHAVIOR,
.disk_path = test_disk,
.disk_path = test_disk_path,
.read_delay = test_read_delay,
.prog_delay = test_prog_delay,
.erase_delay = test_erase_delay,
@@ -1034,7 +1089,7 @@ static void run_powerloss_exhaustive(
.powerloss_data = NULL,
};
int err = lfs_testbd_createcfg(&cfg, test_disk, &bdcfg);
int err = lfs_testbd_createcfg(&cfg, test_disk_path, &bdcfg);
if (err) {
fprintf(stderr, "error: could not create block device: %d\n", err);
exit(-1);
@@ -1153,6 +1208,9 @@ static void run_perms(
}
static void run(void) {
// ignore disconnected pipes
signal(SIGPIPE, SIG_IGN);
for (size_t t = 0; t < test_id_count; t++) {
for (size_t i = 0; i < TEST_SUITE_COUNT; i++) {
if (test_ids[t].suite && strcmp(
@@ -1563,19 +1621,10 @@ powerloss_next:
break;
}
case OPT_DISK:
test_disk = optarg;
test_disk_path = optarg;
break;
case OPT_TRACE:
if (strcmp(optarg, "-") == 0) {
test_trace = stdout;
} else {
test_trace = fopen(optarg, "w");
if (!test_trace) {
fprintf(stderr, "error: could not open for trace: %d\n",
-errno);
exit(-1);
}
}
test_trace_path = optarg;
break;
case OPT_READ_DELAY: {
char *parsed = NULL;
+22 -1
View File
@@ -1,7 +1,26 @@
#ifndef TEST_RUNNER_H
#define TEST_RUNNER_H
#include "lfs.h"
// override LFS_TRACE
void test_trace(const char *fmt, ...);
#define LFS_TRACE_(fmt, ...) \
test_trace("%s:%d:trace: " fmt "%s\n", \
__FILE__, \
__LINE__, \
__VA_ARGS__)
#define LFS_TRACE(...) LFS_TRACE_(__VA_ARGS__, "")
#define LFS_TESTBD_TRACE(...) LFS_TRACE_(__VA_ARGS__, "")
// note these are indirectly included in any generated files
#include "bd/lfs_testbd.h"
#include <stdio.h>
// give source a chance to define feature macros
#undef _FEATURES_H
#undef _STDIO_H
// generated test configurations
@@ -10,6 +29,8 @@ enum test_flags {
};
typedef uint8_t test_flags_t;
struct lfs_config;
struct test_case {
const char *id;
const char *name;