Pantheon/tests/test_bs_load.c

89 lines
3.2 KiB
C

/* SPDX-License-Identifier: AGPL-3.0-or-later */
/* Copyright (C) 2026 David (Corey) Herrera */
/*
* test_bs_load.c — bs_get_load() unit test (dispatch layer Phase G0).
*
* bs_get_load() is a pure read of a pn_batch_sched's slot states + queue depth
* under sched->mu (no engine, no GPU). This test hand-builds a pn_batch_sched
* on the stack with known slot statuses / n_queued and asserts the reported
* {capacity, active_slots, free_slots, queue_depth}, plus the sched==NULL
* single-user case (capacity 1 / free 1). It links batch_sched.c (which needs
* the engine for its OTHER functions), but exercises only this pure accessor.
*/
#include "../src/serve/batch_sched.h"
#include <pthread.h>
#include <stdio.h>
#include <string.h>
static int g_failed = 0;
#define CHECK(cond, msg) do { \
if (!(cond)) { \
fprintf(stderr, " FAIL: %s (%s:%d)\n", (msg), __FILE__, __LINE__); \
g_failed++; \
} \
} while (0)
int main(void)
{
fprintf(stderr, "test_bs_load: bs_get_load slot/queue snapshot\n");
/* --- sched == NULL: single-user path presents 1 always-free slot --- */
{
bs_load l;
memset(&l, 0xAA, sizeof l); /* poison to prove every field is written */
bs_get_load(NULL, &l);
CHECK(l.capacity == 1, "NULL sched: capacity == 1");
CHECK(l.active_slots == 0, "NULL sched: active_slots == 0");
CHECK(l.free_slots == 1, "NULL sched: free_slots == 1");
CHECK(l.queue_depth == 0, "NULL sched: queue_depth == 0");
}
/* --- hand-built scheduler, cap=4, mixed slot states, 2 queued --- */
{
pn_batch_sched sched;
memset(&sched, 0, sizeof sched);
pthread_mutex_init(&sched.mu, NULL);
sched.cap = 4;
sched.n_queued = 2;
/* 3 busy (PREFILL/BOUND/DECODE all count), 1 idle. */
sched.slots[0].status = BS_SLOT_PREFILL;
sched.slots[1].status = BS_SLOT_BOUND;
sched.slots[2].status = BS_SLOT_DECODE;
sched.slots[3].status = BS_SLOT_IDLE;
bs_load l;
memset(&l, 0xAA, sizeof l);
bs_get_load(&sched, &l);
CHECK(l.capacity == 4, "cap=4: capacity == 4");
CHECK(l.active_slots == 3, "cap=4: 3 non-idle slots busy");
CHECK(l.free_slots == 1, "cap=4: 1 free slot");
CHECK(l.queue_depth == 2, "cap=4: queue_depth reflects n_queued");
/* all idle → fully free, no queue */
for (int i = 0; i < 4; i++) sched.slots[i].status = BS_SLOT_IDLE;
sched.n_queued = 0;
bs_get_load(&sched, &l);
CHECK(l.active_slots == 0, "all idle: active_slots == 0");
CHECK(l.free_slots == 4, "all idle: free_slots == cap");
CHECK(l.queue_depth == 0, "all idle: queue_depth == 0");
/* all busy → zero free */
for (int i = 0; i < 4; i++) sched.slots[i].status = BS_SLOT_DECODE;
bs_get_load(&sched, &l);
CHECK(l.active_slots == 4, "all busy: active_slots == cap");
CHECK(l.free_slots == 0, "all busy: free_slots == 0");
pthread_mutex_destroy(&sched.mu);
}
if (g_failed) {
fprintf(stderr, "test_bs_load: %d CHECK(s) FAILED\n", g_failed);
return 1;
}
fprintf(stderr, "test_bs_load: OK\n");
return 0;
}