Skip to content

Watchdog

include/watchdog.h View source View on GitHub
struct watchdog_bucket {
    size_t  epoch;
    size_t  heartbeats;
};
struct watchdog_buckets {
    struct seqcount         seq;
    struct watchdog_bucket  buckets_internal[WATCHDOG_NUM_BUCKETS];
    size_t                  idx;
    size_t                  curr_epoch;
    time_ms_t               last_heartbeat_ms;
};
struct watchdog_bucket_snapshot {
    size_t                  idx;
    size_t                  curr_epoch;
    time_ms_t               last_heartbeat_ms;
    struct watchdog_bucket  buckets[WATCHDOG_NUM_BUCKETS];
};
struct watchdog_percpu_response {
    time_ms_t        finished_ms;
    struct seqcount  seqcount;
};
struct watchdog_callback {
    struct list_head  list;
    void              (*fn)(struct watchdog_callback *);
    void              *private;
};
struct watchdog_percpu {
    cpu_id_t                         id;
    bool                             pets_enabled;
    struct seqcount                  pets_seq;
    _Atomic size_t                   pets;
    _Atomic size_t                   anti_pets;
    _Atomic uint64_t                 heartbeat_seq;
    struct watchdog_percpu_response  response;
    struct watchdog_buckets          buckets;
    struct timer                     timer;
    struct locked_list               callback_list;
};
struct watchdog_master_cpu {
    cpu_id_t                    id;
    struct watchdog_percpu      *pcpu;
    enum watchdog_master_state  state;
    struct ewma                 lockup_ewma;
    fx32_32_t                   lockup_score;
    time_ms_t                   critical_tests[WATCHDOG_CRITICAL_IPI_TESTS];
    time_ms_t                   critical_test_start;
    size_t                      critical_tests_done;
    size_t                      critical_start_tick;
    size_t                      suspect_start_tick;
    uint64_t                    last_seen_heartbeat;
    size_t                      last_progress_tick;
};
struct watchdog_master {
    size_t                      tick;
    struct cpu_mask             cpu_masks[WATCHDOG_STATE_MAX];
    struct cpu_mask             scratch_mask;
    struct watchdog_master_cpu  *cpus;
    char                        msg_buf[WATCHDOG_MSG_LEN_MAX];
};
struct watchdog_config {
    time_ns_t  master_tick_interval;
    time_ns_t  worker_heartbeat_interval;
    time_ns_t  bucket_interval;
    fx32_32_t  master_panic_score;
    fx32_32_t  master_critical_score;
    time_ns_t  master_stall_timeout;
    time_ns_t  master_print_interval;
    fx32_32_t  master_suspect_score;
};
struct watchdog_globals {
    time_ms_t  bucket_interval_ms;
    size_t     expected_heartbeats_per_bucket;
    size_t     stall_timeout_ticks;
    irq_t      critical_test_irq;
};
enum watchdog_master_state {
    WATCHDOG_STATE_NORMAL,
    WATCHDOG_STATE_SUSPECT,
    WATCHDOG_STATE_CRITICAL,
    WATCHDOG_STATE_PANIC,
    WATCHDOG_STATE_MAX,
};
void watchdog_init(void);
void watchdog_start(void);
void watchdog_anti_pet(void);
void watchdog_pet(void);
void watchdog_callback_add(cpu_id_t cpu, struct watchdog_callback *cb);
void watchdog_callback_remove(cpu_id_t cpu, struct watchdog_callback *cb);
#define WATCHDOG_WINDOW_BUCKETS 8
#define WATCHDOG_MASTER_SEQCOUNT_SPINS 3
#define WATCHDOG_NUM_BUCKETS 64
#define WATCHDOG_MSG_LEN_MAX 512
#define WATCHDOG_EWMA_ALPHA FX(0.15)
#define WATCHDOG_SUSPECT_LOG_TICK_THRESHOLD (40)
#define WATCHDOG_CRITICAL_LOG_TICK_THRESHOLD (20)
#define WATCHDOG_CRITICAL_IPI_TESTS \
    40 /* Test an IPI ping pong \
        * times to get the avg, this is 4s */
#define WATCHDOG_CRITICAL_PASS_THRESHOLD_MS 250
#define WATCHDOG_CRITICAL_PANIC_THRESHOLD_MS \
    10000 /* If we delay this long, panic */
#define WATCHDOG_CRITICAL_TESTS_FACTOR FX(0.4)
#define WATCHDOG_CRITICAL_PETS_FACTOR FX(0.6)
#define WATCHDOG_STALL_TIMEOUT_DEFAULT_MS 15000
#define WATCHDOG_STALL_GRACE_TICKS 20
#define watchdog_cpu_for_each(__i, state) \
    cpu_mask_for_each(__i, watchdog_master.cpu_masks[state])