Skip to content

Nightmare test harness

include/nightmare/nightmare.h View source View on GitHub
struct nightmare_verdict {
    enum nightmare_result       result;
    enum nightmare_skip_reason  skip_reason;
    const char                  *reason;
    const char                  *msg;
};
struct nightmare_rng {
    uint64_t  state;
};
struct nightmare_worker {
    size_t                     index;
    const char                 *role;
    struct nightmare_rng       rng;
    _Atomic (struct thread *)  th;
    atomic_bool                parked;
};
struct nightmare_ctx {
    const struct nightmare    *nm;
    fx32_32_t                 intensity;
    size_t                    intensity_val;
    size_t                    worker_count;
    uint64_t                  seed;
    bool                      seed_present;
    enum nightmare_seed_mode  seed_mode;
    time_ms_t                 soft_deadline_ms;
    time_ms_t                 hard_deadline_ms;
    void                      *private;
};
struct nightmare_ops {
    struct nightmare_verdict  (*prepare)(struct nightmare_ctx *);
    void                      (*worker)(struct nightmare_ctx *, struct nightmare_worker *);
    struct nightmare_verdict  (*quiesce_check)(struct nightmare_ctx *);
    void                      (*probe)(struct nightmare_ctx *);
    struct nightmare_verdict  (*finish)(struct nightmare_ctx *);
};
struct nightmare {
    const char                  *name;
    const char                  *fname;
    const char                  *desc;
    const struct nightmare_ops  *ops;
    enum nightmare_seed_policy  seed_policy;
    enum nightmare_requires     requires;
    const char                  *const *perturb;
    fx32_32_t                   intensity;
    struct scaled_param         intensity_desc;
    time_ms_t                   default_duration_ms;
    size_t                      min_mem_mib;
};
struct nightmare_progress_counter {
    _Atomic uint64_t  count;
};
struct nightmare_finding_site {
    const char                   *kind;
    enum nightmare_finding_tier  tier;
    const char                   *file;
    uint32_t                     line;
};
struct nightmare_stall_evidence {
    time_ms_t  silent_ms;
    uint64_t   progress;
    cpu_id_t   observer_cpu;
};
enum nightmare_exit_code {
    NIGHTMARE_EXIT_OK = 0,
    NIGHTMARE_EXIT_FINDING = 3,
    NIGHTMARE_EXIT_FAIL = 4,
    NIGHTMARE_EXIT_STALL = 5,
    NIGHTMARE_EXIT_SKIP = 6,
};
enum nightmare_seed_policy : uint8_t {
    NIGHTMARE_SEED_IGNORED = 0,
    NIGHTMARE_SEED_OPTIONAL,
    NIGHTMARE_SEED_REQUIRED,
};
enum nightmare_seed_mode : uint8_t {
    NIGHTMARE_SEED_SPLIT = 0,
    NIGHTMARE_SEED_SEEDFUL,
    NIGHTMARE_SEED_SEEDLESS,
};
enum nightmare_requires : uint32_t {
    NIGHTMARE_REQ_NONE = 0,
    NIGHTMARE_REQ_SMP = 1 << 0,
    NIGHTMARE_REQ_PREEMPT = 1 << 1,
    NIGHTMARE_REQ_ASAN = 1 << 2,
    NIGHTMARE_REQ_INJECT = 1 << 3,
};
enum nightmare_result : uint8_t {
    NIGHTMARE_RESULT_OK = 0,
    NIGHTMARE_RESULT_FINDING,
    NIGHTMARE_RESULT_FAIL,
    NIGHTMARE_RESULT_STALL,
    NIGHTMARE_RESULT_SKIP,
};
enum nightmare_skip_reason : uint8_t {
    NIGHTMARE_SKIP_NONE = 0,
    NIGHTMARE_SKIP_NOT_COMPILED,
    NIGHTMARE_SKIP_NO_SUCH_NIGHTMARE,
    NIGHTMARE_SKIP_NEEDS_SMP,
    NIGHTMARE_SKIP_NEEDS_PREEMPT,
    NIGHTMARE_SKIP_NEEDS_ASAN,
    NIGHTMARE_SKIP_NEEDS_INJECT,
    NIGHTMARE_SKIP_RAM_LOW,
    NIGHTMARE_SKIP_SEED_UNUSED,
    NIGHTMARE_SKIP_SEED_MISSING,
    NIGHTMARE_SKIP_SERVICE_MISSING,
    NIGHTMARE_SKIP_PREPARE_REFUSED,
};
enum nightmare_stop : uint8_t {
    NM_RUN = 0,
    NM_STOP_BUDGET,
    NM_STOP_FINDING,
    NM_STOP_FAIL,
    NM_STOP_STALL,
};
enum nightmare_finding_tier : uint8_t {
    NIGHTMARE_TIER_AMBIGUOUS = 0,
    NIGHTMARE_TIER_CONFIDENT,
};
struct nightmare { const char *name; const char *fname; const char *desc; const struct nightmare_ops *ops; enum nightmare_seed_policy seed_policy; enum nightmare_requires requires; const char *const *perturb; fx32_32_t intensity; struct scaled_param intensity_desc; time_ms_t default_duration_ms; size_t min_mem_mib; } __aligned();
void nightmare_progress_tick(void);
void nightmare_run(void);
bool nightmare_must_stop(void);
bool nightmare_must_stop_irq(void);
void nightmare_stop_after_finding(void);
bool nightmare_must_park(void);
void nightmare_park(struct nightmare_worker *worker);
uint64_t nightmare_rand(struct nightmare_rng *rng);
uint64_t nightmare_progress_sum_irq(void);
void nightmare_report_stall(const struct nightmare_stall_evidence *evidence);
#define NIGHTMARE_INTENSITY_SENTINEL ((fx32_32_t) - 1LL)
#define NIGHTMARE_INTENSITY_DEFAULT FX(0.5)
#define NIGHTMARE_OK \
    ((struct nightmare_verdict) {.result = NIGHTMARE_RESULT_OK})
#define NIGHTMARE_FAIL(reason_, msg_) \
    ((struct nightmare_verdict) { \
        .result = NIGHTMARE_RESULT_FAIL, .reason = (reason_), .msg = (msg_)})
#define NIGHTMARE_SKIP(reason_) \
    ((struct nightmare_verdict) {.result = NIGHTMARE_RESULT_SKIP, \
                                 .skip_reason = (reason_)})
#define NIGHTMARE_DECLARE(id, ...) \
    extern struct nightmare __nightmare_##id; \
    LINKER_SECTION_OBJECT(struct nightmare, nightmares) \
    __nightmare_##id = {.name = #id, \
                        .fname = __RELFILE__, \
                        .seed_policy = NIGHTMARE_SEED_IGNORED, \
                        .requires = NIGHTMARE_REQ_NONE, \
                        .intensity = NIGHTMARE_INTENSITY_SENTINEL, \
                        __VA_ARGS__}
#define NIGHTMARE(id) (&__nightmare_##id)
#define NIGHTMARE_DEFINE(id) extern struct nightmare __nightmare_##id
#define NIGHTMARE_PERTURB(...) ((const char *const[]) {__VA_ARGS__, NULL})
#define NIGHTMARE_INTENSITY_CORES(min_, def_, max_, unit_) \
    .intensity_desc = {.curve = SCALE_CORE_MULTIPLIER, \
                       .min_val = (min_), \
                       .def_val = (def_), \
                       .max_val = (max_), \
                       .unit = (unit_)}
#define NIGHTMARE_WORKER(id) \
    static void id(struct nightmare_ctx *NM_CTX, \
                   struct nightmare_worker *NM_SELF)
#define NIGHTMARE_OPTIONS_DECLARE(id, struct_type, instance, ...) \
    static void *__nightmare_options_resolve_##id(const char *path, \
                                                  size_t path_len) { \
        return path_len == sizeof(#id) - 1 && \
                       strncmp(path, #id, path_len) == 0 \
                   ? &(instance) \
                   : NULL; \
    } \
    CMDLINE_SCHEMA_DECLARE(__nightmare_options_##id, "nightmare", #id, \
                           "Nightmare subject options", \
                           __nightmare_options_resolve_##id, __VA_ARGS__)
#define NIGHTMARE_PROGRESS() nightmare_progress_tick()
#define NIGHTMARE_FINDING(kind_, fmt, ...) \
    nightmare_finding_at( \
        &(const struct nightmare_finding_site) {.kind = (kind_), \
                                                .tier = \
                                                    NIGHTMARE_TIER_AMBIGUOUS, \
                                                .file = __RELFILE__, \
                                                .line = __LINE__}, \
        0, (fmt), ##__VA_ARGS__)
#define NIGHTMARE_FINDING_TIER(kind_, tier_, discriminator_, fmt, ...) \
    nightmare_finding_at( \
        &(const struct nightmare_finding_site) {.kind = (kind_), \
                                                .tier = (tier_), \
                                                .file = __RELFILE__, \
                                                .line = __LINE__}, \
        (discriminator_), (fmt), ##__VA_ARGS__)