feat(scheduler-sim-decision-trace): trace entry sequence and line budget
Task 1.4: requirement path push/pop with balanced begin/end entries carrying the full nesting path, one entry per traced event kind, and a line budget that stops storing at the bound and counts omitted lines. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
383e2a90e4
commit
4f951f2b52
5 changed files with 1567 additions and 2 deletions
|
|
@ -13,6 +13,14 @@
|
|||
* - finishing a record as a no-decision kind (Requirement 2.4);
|
||||
* - freeing a NULL record is a no-op.
|
||||
*
|
||||
* Task 1.4 adds the entry sequence and the line budget:
|
||||
* - requirement path push and pop, balanced requirement begin and end
|
||||
* entries, each storing its full nesting path (3.1, 3.3, 3.4, 3.6);
|
||||
* - every entry kind, one stored entry (= one rendered line) each, with
|
||||
* its payload copied (3.3-3.6, 4.3-4.5, 4.7, 4.8, 5.10);
|
||||
* - the line budget at bound-1, bound and bound+1, with the exact
|
||||
* omitted count (9.1, 9.2).
|
||||
*
|
||||
* Links only src/sched_trace.c (plus libxce for the jobid helpers).
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
|
|
@ -20,6 +28,7 @@
|
|||
|
||||
#include <unity/unity.h>
|
||||
|
||||
#include "sched/alloc_iter.h"
|
||||
#include "sched/trace.h"
|
||||
#include "utils.h"
|
||||
|
||||
|
|
@ -406,6 +415,827 @@ static void test_finish_rejects_non_no_decision_kinds(void)
|
|||
sched_trace_rec_free(rec);
|
||||
}
|
||||
|
||||
/* ---- entry sequence (task 1.4) ---------------------------------------- */
|
||||
|
||||
static xce_sched_trace_rec_t* new_rec(int line_bound)
|
||||
{
|
||||
xce_sched_trace_ctl_t ctl = make_ctl(NULL, 0);
|
||||
|
||||
ctl.level = XCE_TRACE_LEVEL_FULL;
|
||||
ctl.line_bound = line_bound;
|
||||
return sched_trace_rec_new(&ctl, PLAIN_ID(5), XCE_TRACE_REC_DECISION);
|
||||
}
|
||||
|
||||
static int count_entries(const xce_sched_trace_rec_t* rec)
|
||||
{
|
||||
const sched_trace_entry_t* e;
|
||||
int n = 0;
|
||||
|
||||
for (e = rec->entries; e != NULL; e = e->next) {
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static const sched_trace_entry_t* entry_at(const xce_sched_trace_rec_t* rec,
|
||||
int k)
|
||||
{
|
||||
const sched_trace_entry_t* e = rec->entries;
|
||||
|
||||
while ((e != NULL) && (k > 0)) {
|
||||
e = e->next;
|
||||
k--;
|
||||
}
|
||||
TEST_ASSERT_NOT_NULL_MESSAGE(e, "entry index out of range");
|
||||
return e;
|
||||
}
|
||||
|
||||
static void assert_path1(const sched_trace_entry_t* e,
|
||||
xce_sched_trace_path_kind_t kind, int i, int n)
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT(1, e->path.depth);
|
||||
TEST_ASSERT_EQUAL_INT(kind, e->path.lvl[0].kind);
|
||||
TEST_ASSERT_EQUAL_INT(i, e->path.lvl[0].i);
|
||||
TEST_ASSERT_EQUAL_INT(n, e->path.lvl[0].n);
|
||||
}
|
||||
|
||||
/* A primary with two requested resources; the xlist points at the
|
||||
* caller's arrays (no heap). */
|
||||
typedef struct {
|
||||
xce_primary_resreq_t p;
|
||||
rusage_value_t v[2];
|
||||
void* ptrs[2];
|
||||
char name0[16];
|
||||
char name1[16];
|
||||
} fixture_primary_t;
|
||||
|
||||
static void make_primary(fixture_primary_t* f, int min_tasks, int max_tasks)
|
||||
{
|
||||
memset(f, 0, sizeof(*f));
|
||||
strcpy(f->name0, "mem");
|
||||
strcpy(f->name1, "license");
|
||||
f->v[0].res = f->name0;
|
||||
f->v[0].value = 8192.0f;
|
||||
f->v[0].per_flag = PER_TASK;
|
||||
f->v[1].res = f->name1;
|
||||
f->v[1].value = 2.0f;
|
||||
f->v[1].per_flag = PER_JOB;
|
||||
f->ptrs[0] = &f->v[0];
|
||||
f->ptrs[1] = &f->v[1];
|
||||
f->p.minTasks = min_tasks;
|
||||
f->p.maxTasks = max_tasks;
|
||||
f->p.rusages.count = 2;
|
||||
f->p.rusages.caps = 2;
|
||||
f->p.rusages.delta = 1;
|
||||
f->p.rusages.data = f->ptrs;
|
||||
}
|
||||
|
||||
static void test_single_requirement_path_and_balance(void)
|
||||
{
|
||||
xce_sched_trace_rec_t* rec = new_rec(XCE_TRACE_LINE_BOUND_DEFAULT);
|
||||
fixture_primary_t fp;
|
||||
const sched_trace_entry_t* b;
|
||||
const sched_trace_entry_t* e;
|
||||
|
||||
TEST_ASSERT_NOT_NULL(rec);
|
||||
TEST_ASSERT_NULL(rec->entries);
|
||||
TEST_ASSERT_EQUAL_INT(0, rec->nentries);
|
||||
make_primary(&fp, 2, 4);
|
||||
|
||||
sched_trace_path_push(rec, XCE_TRACE_PATH_SINGLE, 1, 1);
|
||||
TEST_ASSERT_EQUAL_INT(1, rec->path.depth);
|
||||
sched_trace_resreq_begin(rec, &fp.p, 0);
|
||||
sched_trace_resreq_end(rec, 1, 0);
|
||||
sched_trace_path_pop(rec);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, rec->path.depth);
|
||||
TEST_ASSERT_EQUAL_INT(0, rec->resreq_open);
|
||||
TEST_ASSERT_EQUAL_INT(0, rec->depth);
|
||||
TEST_ASSERT_EQUAL_INT(2, rec->nentries);
|
||||
TEST_ASSERT_EQUAL_INT(2, count_entries(rec));
|
||||
|
||||
b = entry_at(rec, 0);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_RESREQ_BEGIN, b->type);
|
||||
TEST_ASSERT_EQUAL_INT(0, b->depth);
|
||||
assert_path1(b, XCE_TRACE_PATH_SINGLE, 1, 1);
|
||||
TEST_ASSERT_FALSE(b->u.resreq_begin.container);
|
||||
TEST_ASSERT_EQUAL_INT(2, b->u.resreq_begin.min_tasks);
|
||||
TEST_ASSERT_EQUAL_INT(4, b->u.resreq_begin.max_tasks);
|
||||
TEST_ASSERT_EQUAL_INT(2, b->u.resreq_begin.nreq);
|
||||
TEST_ASSERT_EQUAL_STRING("mem", b->u.resreq_begin.req[0].name);
|
||||
TEST_ASSERT_EQUAL_FLOAT(8192.0f, b->u.resreq_begin.req[0].value);
|
||||
TEST_ASSERT_EQUAL_INT(PER_TASK, b->u.resreq_begin.req[0].per);
|
||||
TEST_ASSERT_EQUAL_STRING("license", b->u.resreq_begin.req[1].name);
|
||||
TEST_ASSERT_EQUAL_FLOAT(2.0f, b->u.resreq_begin.req[1].value);
|
||||
TEST_ASSERT_EQUAL_INT(PER_JOB, b->u.resreq_begin.req[1].per);
|
||||
|
||||
e = entry_at(rec, 1);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_RESREQ_END, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(0, e->depth); /* same level as its begin */
|
||||
assert_path1(e, XCE_TRACE_PATH_SINGLE, 1, 1);
|
||||
TEST_ASSERT_EQUAL_INT(1, e->u.resreq_end.rc);
|
||||
TEST_ASSERT_EQUAL_INT(0, e->u.resreq_end.not_tried_after);
|
||||
TEST_ASSERT_TRUE(rec->entries_tail == e);
|
||||
|
||||
/* the requested resources are copies, not the scheduler's strings */
|
||||
TEST_ASSERT_TRUE(b->u.resreq_begin.req[0].name != fp.name0);
|
||||
strcpy(fp.name0, "XXX");
|
||||
fp.v[1].value = 99.0f;
|
||||
TEST_ASSERT_EQUAL_STRING("mem", b->u.resreq_begin.req[0].name);
|
||||
TEST_ASSERT_EQUAL_FLOAT(2.0f, b->u.resreq_begin.req[1].value);
|
||||
|
||||
sched_trace_rec_free(rec);
|
||||
}
|
||||
|
||||
static void test_alternative_member_nesting_stores_full_path(void)
|
||||
{
|
||||
xce_sched_trace_rec_t* rec = new_rec(XCE_TRACE_LINE_BOUND_DEFAULT);
|
||||
fixture_primary_t fp;
|
||||
const sched_trace_entry_t* e;
|
||||
int k;
|
||||
|
||||
TEST_ASSERT_NOT_NULL(rec);
|
||||
make_primary(&fp, 1, 1);
|
||||
|
||||
/* alternative 2/3 (a compound of 2 members): member 1/2 fails, so
|
||||
* member 2/2 is not tried */
|
||||
sched_trace_path_push(rec, XCE_TRACE_PATH_ALT, 2, 3);
|
||||
sched_trace_resreq_begin(rec, NULL, 2);
|
||||
sched_trace_path_push(rec, XCE_TRACE_PATH_MEMBER, 1, 2);
|
||||
TEST_ASSERT_EQUAL_INT(2, rec->path.depth);
|
||||
sched_trace_resreq_begin(rec, &fp.p, 0);
|
||||
sched_trace_resreq_end(rec, 0, 1);
|
||||
sched_trace_path_pop(rec);
|
||||
sched_trace_resreq_end(rec, 0, 0);
|
||||
sched_trace_path_pop(rec);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(0, rec->path.depth);
|
||||
TEST_ASSERT_EQUAL_INT(0, rec->resreq_open);
|
||||
TEST_ASSERT_EQUAL_INT(0, rec->depth);
|
||||
TEST_ASSERT_EQUAL_INT(4, count_entries(rec));
|
||||
|
||||
e = entry_at(rec, 0); /* container begin */
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_RESREQ_BEGIN, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(0, e->depth);
|
||||
assert_path1(e, XCE_TRACE_PATH_ALT, 2, 3);
|
||||
TEST_ASSERT_TRUE(e->u.resreq_begin.container);
|
||||
TEST_ASSERT_EQUAL_INT(2, e->u.resreq_begin.nmembers);
|
||||
TEST_ASSERT_EQUAL_INT(0, e->u.resreq_begin.nreq);
|
||||
|
||||
for (k = 1; k <= 2; k++) { /* member begin and end: two-level path */
|
||||
e = entry_at(rec, k);
|
||||
TEST_ASSERT_EQUAL_INT(1, e->depth);
|
||||
TEST_ASSERT_EQUAL_INT(2, e->path.depth);
|
||||
TEST_ASSERT_EQUAL_INT(XCE_TRACE_PATH_ALT, e->path.lvl[0].kind);
|
||||
TEST_ASSERT_EQUAL_INT(2, e->path.lvl[0].i);
|
||||
TEST_ASSERT_EQUAL_INT(3, e->path.lvl[0].n);
|
||||
TEST_ASSERT_EQUAL_INT(XCE_TRACE_PATH_MEMBER, e->path.lvl[1].kind);
|
||||
TEST_ASSERT_EQUAL_INT(1, e->path.lvl[1].i);
|
||||
TEST_ASSERT_EQUAL_INT(2, e->path.lvl[1].n);
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_RESREQ_BEGIN, entry_at(rec, 1)->type);
|
||||
TEST_ASSERT_FALSE(entry_at(rec, 1)->u.resreq_begin.container);
|
||||
e = entry_at(rec, 2);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_RESREQ_END, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(0, e->u.resreq_end.rc);
|
||||
TEST_ASSERT_EQUAL_INT(1, e->u.resreq_end.not_tried_after);
|
||||
|
||||
e = entry_at(rec, 3); /* container end */
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_RESREQ_END, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(0, e->depth);
|
||||
assert_path1(e, XCE_TRACE_PATH_ALT, 2, 3);
|
||||
|
||||
sched_trace_rec_free(rec);
|
||||
}
|
||||
|
||||
static void test_compound_container_path(void)
|
||||
{
|
||||
xce_sched_trace_rec_t* rec = new_rec(XCE_TRACE_LINE_BOUND_DEFAULT);
|
||||
fixture_primary_t fp;
|
||||
const sched_trace_entry_t* e;
|
||||
int j;
|
||||
int nbegin = 0;
|
||||
int nend = 0;
|
||||
|
||||
TEST_ASSERT_NOT_NULL(rec);
|
||||
make_primary(&fp, 1, 2);
|
||||
|
||||
sched_trace_path_push(rec, XCE_TRACE_PATH_COMPOUND, 1, 1);
|
||||
sched_trace_resreq_begin(rec, NULL, 3);
|
||||
for (j = 1; j <= 3; j++) {
|
||||
sched_trace_path_push(rec, XCE_TRACE_PATH_MEMBER, j, 3);
|
||||
sched_trace_resreq_begin(rec, &fp.p, 0);
|
||||
sched_trace_resreq_end(rec, 1, 0);
|
||||
sched_trace_path_pop(rec);
|
||||
}
|
||||
sched_trace_resreq_end(rec, 1, 0);
|
||||
sched_trace_path_pop(rec);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(8, count_entries(rec));
|
||||
e = entry_at(rec, 0);
|
||||
assert_path1(e, XCE_TRACE_PATH_COMPOUND, 1, 1);
|
||||
TEST_ASSERT_TRUE(e->u.resreq_begin.container);
|
||||
TEST_ASSERT_EQUAL_INT(3, e->u.resreq_begin.nmembers);
|
||||
e = entry_at(rec, 5); /* member 3/3 begin */
|
||||
TEST_ASSERT_EQUAL_INT(2, e->path.depth);
|
||||
TEST_ASSERT_EQUAL_INT(XCE_TRACE_PATH_COMPOUND, e->path.lvl[0].kind);
|
||||
TEST_ASSERT_EQUAL_INT(3, e->path.lvl[1].i);
|
||||
TEST_ASSERT_EQUAL_INT(3, e->path.lvl[1].n);
|
||||
|
||||
/* balanced: one end per begin, nesting back to the top */
|
||||
for (e = rec->entries; e != NULL; e = e->next) {
|
||||
nbegin += (e->type == SCHED_TRACE_E_RESREQ_BEGIN);
|
||||
nend += (e->type == SCHED_TRACE_E_RESREQ_END);
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT(4, nbegin);
|
||||
TEST_ASSERT_EQUAL_INT(nbegin, nend);
|
||||
TEST_ASSERT_EQUAL_INT(0, rec->resreq_open);
|
||||
TEST_ASSERT_EQUAL_INT(0, rec->depth);
|
||||
sched_trace_rec_free(rec);
|
||||
}
|
||||
|
||||
static void test_path_push_beyond_two_levels_stays_balanced(void)
|
||||
{
|
||||
xce_sched_trace_rec_t* rec = new_rec(XCE_TRACE_LINE_BOUND_DEFAULT);
|
||||
|
||||
TEST_ASSERT_NOT_NULL(rec);
|
||||
sched_trace_path_push(rec, XCE_TRACE_PATH_ALT, 1, 2);
|
||||
sched_trace_path_push(rec, XCE_TRACE_PATH_MEMBER, 1, 1);
|
||||
sched_trace_path_push(rec, XCE_TRACE_PATH_MEMBER, 1, 1); /* not kept */
|
||||
TEST_ASSERT_EQUAL_INT(2, rec->path.depth);
|
||||
TEST_ASSERT_EQUAL_INT(XCE_TRACE_PATH_MEMBER, rec->path.lvl[1].kind);
|
||||
sched_trace_path_pop(rec); /* pops the one not kept */
|
||||
TEST_ASSERT_EQUAL_INT(2, rec->path.depth);
|
||||
sched_trace_path_pop(rec);
|
||||
TEST_ASSERT_EQUAL_INT(1, rec->path.depth);
|
||||
sched_trace_path_pop(rec);
|
||||
TEST_ASSERT_EQUAL_INT(0, rec->path.depth);
|
||||
sched_trace_path_pop(rec); /* unbalanced pop: stays at the top */
|
||||
TEST_ASSERT_EQUAL_INT(0, rec->path.depth);
|
||||
TEST_ASSERT_EQUAL_INT(0, rec->nentries); /* the path is not an entry */
|
||||
sched_trace_rec_free(rec);
|
||||
}
|
||||
|
||||
static void test_requirement_level_entries(void)
|
||||
{
|
||||
xce_sched_trace_rec_t* rec = new_rec(XCE_TRACE_LINE_BOUND_DEFAULT);
|
||||
const sched_trace_entry_t* e;
|
||||
sched_trace_reason_count_t codes[2] = { { 3, 4 }, { 7, 1 } };
|
||||
char h0[8] = "n01";
|
||||
char h1[8] = "n02";
|
||||
char r0[16] = "license";
|
||||
const char* hosts[2] = { h0, h1 };
|
||||
const char* res[1] = { r0 };
|
||||
|
||||
TEST_ASSERT_NOT_NULL(rec);
|
||||
sched_trace_path_push(rec, XCE_TRACE_PATH_ALT, 1, 3);
|
||||
sched_trace_alt_skipped(rec, 1, 3);
|
||||
sched_trace_path_pop(rec);
|
||||
sched_trace_path_push(rec, XCE_TRACE_PATH_ALT, 2, 3);
|
||||
sched_trace_resreq_begin(rec, NULL, 2);
|
||||
sched_trace_member_failed(rec, 1, 2, -12);
|
||||
sched_trace_attempt_reasons(rec, codes, 2, hosts, 2, res, 1);
|
||||
sched_trace_resreq_end(rec, -12, 0);
|
||||
sched_trace_path_pop(rec);
|
||||
sched_trace_alt_result(rec, 3, 3);
|
||||
sched_trace_alt_result(rec, 0, 3);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(7, count_entries(rec));
|
||||
|
||||
e = entry_at(rec, 0);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_ALT_SKIPPED, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(1, e->u.alt.i);
|
||||
TEST_ASSERT_EQUAL_INT(3, e->u.alt.n);
|
||||
TEST_ASSERT_EQUAL_INT(0, e->depth);
|
||||
|
||||
e = entry_at(rec, 2);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_MEMBER_FAILED, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(1, e->depth); /* inside the alternative */
|
||||
assert_path1(e, XCE_TRACE_PATH_ALT, 2, 3);
|
||||
TEST_ASSERT_EQUAL_INT(1, e->u.member_failed.j);
|
||||
TEST_ASSERT_EQUAL_INT(2, e->u.member_failed.m);
|
||||
TEST_ASSERT_EQUAL_INT(-12, e->u.member_failed.err);
|
||||
|
||||
e = entry_at(rec, 3);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_ATTEMPT_REASONS, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(1, e->depth);
|
||||
TEST_ASSERT_EQUAL_INT(2, e->u.reasons.ncodes);
|
||||
TEST_ASSERT_EQUAL_INT(3, e->u.reasons.codes[0].code);
|
||||
TEST_ASSERT_EQUAL_INT(4, e->u.reasons.codes[0].count);
|
||||
TEST_ASSERT_EQUAL_INT(7, e->u.reasons.codes[1].code);
|
||||
TEST_ASSERT_EQUAL_INT(1, e->u.reasons.codes[1].count);
|
||||
TEST_ASSERT_EQUAL_INT(2, e->u.reasons.nhosts);
|
||||
TEST_ASSERT_EQUAL_INT(1, e->u.reasons.nres);
|
||||
TEST_ASSERT_TRUE(e->u.reasons.codes != codes);
|
||||
TEST_ASSERT_TRUE(e->u.reasons.hosts[0] != h0);
|
||||
codes[0].count = 99;
|
||||
strcpy(h0, "zz");
|
||||
strcpy(r0, "zz");
|
||||
TEST_ASSERT_EQUAL_INT(4, e->u.reasons.codes[0].count);
|
||||
TEST_ASSERT_EQUAL_STRING("n01", e->u.reasons.hosts[0]);
|
||||
TEST_ASSERT_EQUAL_STRING("n02", e->u.reasons.hosts[1]);
|
||||
TEST_ASSERT_EQUAL_STRING("license", e->u.reasons.res[0]);
|
||||
|
||||
e = entry_at(rec, 4);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_RESREQ_END, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(-12, e->u.resreq_end.rc);
|
||||
|
||||
e = entry_at(rec, 5);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_ALT_RESULT, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(3, e->u.alt.i);
|
||||
TEST_ASSERT_EQUAL_INT(3, e->u.alt.n);
|
||||
TEST_ASSERT_EQUAL_INT(0, e->path.depth); /* after the pop */
|
||||
e = entry_at(rec, 6);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_ALT_RESULT, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(0, e->u.alt.i); /* all alternatives failed */
|
||||
|
||||
sched_trace_rec_free(rec);
|
||||
}
|
||||
|
||||
static void test_attempt_reasons_empty_lists(void)
|
||||
{
|
||||
xce_sched_trace_rec_t* rec = new_rec(XCE_TRACE_LINE_BOUND_DEFAULT);
|
||||
const sched_trace_entry_t* e;
|
||||
|
||||
TEST_ASSERT_NOT_NULL(rec);
|
||||
sched_trace_attempt_reasons(rec, NULL, 0, NULL, 0, NULL, 0);
|
||||
TEST_ASSERT_EQUAL_INT(1, rec->nentries);
|
||||
e = entry_at(rec, 0);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_ATTEMPT_REASONS, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(0, e->u.reasons.ncodes);
|
||||
TEST_ASSERT_EQUAL_INT(0, e->u.reasons.nhosts);
|
||||
TEST_ASSERT_EQUAL_INT(0, e->u.reasons.nres);
|
||||
TEST_ASSERT_FALSE(rec->incomplete);
|
||||
sched_trace_rec_free(rec);
|
||||
}
|
||||
|
||||
/* A plan of `n` positions with `slots` tasks each, slot array owned by the
|
||||
* caller. */
|
||||
static xce_alloc_plan_t make_plan(int* slots, int n)
|
||||
{
|
||||
xce_alloc_plan_t plan;
|
||||
|
||||
memset(&plan, 0, sizeof(plan));
|
||||
plan.nbuckets = n;
|
||||
plan.bucket_slots = slots;
|
||||
return plan;
|
||||
}
|
||||
|
||||
static void test_check_and_plan_entries(void)
|
||||
{
|
||||
xce_sched_trace_rec_t* rec = new_rec(XCE_TRACE_LINE_BOUND_DEFAULT);
|
||||
fixture_primary_t fp;
|
||||
const sched_trace_entry_t* e;
|
||||
int s1[2] = { 3, 1 };
|
||||
int s2[1] = { 4 };
|
||||
int s3[2] = { 2, 2 };
|
||||
int s4[4] = { 1, 1, 1, 1 };
|
||||
xce_alloc_plan_t p1 = make_plan(s1, 2);
|
||||
xce_alloc_plan_t p2 = make_plan(s2, 1);
|
||||
xce_alloc_plan_t p3 = make_plan(s3, 2);
|
||||
xce_alloc_plan_t p4 = make_plan(s4, 4);
|
||||
const xce_sched_obj_t* obj = (const xce_sched_obj_t*)&fp;
|
||||
|
||||
TEST_ASSERT_NOT_NULL(rec);
|
||||
make_primary(&fp, 4, 4);
|
||||
sched_trace_path_push(rec, XCE_TRACE_PATH_SINGLE, 1, 1);
|
||||
sched_trace_resreq_begin(rec, &fp.p, 0); /* 0 */
|
||||
sched_trace_check_begin(rec, obj); /* no entry */
|
||||
TEST_ASSERT_TRUE(rec->scope_obj == obj);
|
||||
sched_trace_check_end(rec, 1, true); /* 1 */
|
||||
TEST_ASSERT_NULL(rec->scope_obj);
|
||||
sched_trace_plan_discarded(rec, &p1); /* 2: plan 1 */
|
||||
sched_trace_plan_begin(rec, &p2); /* 3: plan 2 */
|
||||
sched_trace_plan_end(rec, 0, 1); /* 4 */
|
||||
sched_trace_plan_begin(rec, &p3); /* 5: plan 3 */
|
||||
sched_trace_plan_end(rec, 1, 0); /* 6 */
|
||||
sched_trace_commit(rec); /* 7 */
|
||||
sched_trace_plan_not_tried(rec, &p4, -12); /* 8: plan 4 */
|
||||
sched_trace_finalize_failed(rec, -5); /* 9 */
|
||||
sched_trace_no_plan(rec, XCE_TRACE_NOPLAN_NONE_GENERATED); /* 10 */
|
||||
sched_trace_resreq_end(rec, 1, 0); /* 11 */
|
||||
sched_trace_path_pop(rec);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(12, count_entries(rec));
|
||||
|
||||
e = entry_at(rec, 1);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_CHECK_END, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(1, e->depth); /* inside the requirement */
|
||||
assert_path1(e, XCE_TRACE_PATH_SINGLE, 1, 1);
|
||||
TEST_ASSERT_EQUAL_INT(1, e->u.check_end.rc);
|
||||
TEST_ASSERT_TRUE(e->u.check_end.plans_follow);
|
||||
|
||||
e = entry_at(rec, 2);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_PLAN_DISCARDED, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(1, e->depth);
|
||||
TEST_ASSERT_EQUAL_INT(1, e->u.plan.plan_no);
|
||||
TEST_ASSERT_EQUAL_INT(2, e->u.plan.nbuckets);
|
||||
TEST_ASSERT_EQUAL_INT(3, e->u.plan.slots[0]);
|
||||
TEST_ASSERT_EQUAL_INT(1, e->u.plan.slots[1]);
|
||||
TEST_ASSERT_TRUE(e->u.plan.slots != s1);
|
||||
|
||||
e = entry_at(rec, 3);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_PLAN_BEGIN, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(1, e->depth);
|
||||
TEST_ASSERT_EQUAL_INT(2, e->u.plan.plan_no);
|
||||
TEST_ASSERT_EQUAL_INT(1, e->u.plan.nbuckets);
|
||||
TEST_ASSERT_EQUAL_INT(4, e->u.plan.slots[0]);
|
||||
|
||||
e = entry_at(rec, 4);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_PLAN_END, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(1, e->depth); /* same level as its begin */
|
||||
TEST_ASSERT_EQUAL_INT(2, e->u.plan_end.plan_no);
|
||||
TEST_ASSERT_EQUAL_INT(0, e->u.plan_end.rc);
|
||||
TEST_ASSERT_EQUAL_INT(1, e->u.plan_end.failed_pos);
|
||||
|
||||
e = entry_at(rec, 6);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_PLAN_END, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(3, e->u.plan_end.plan_no);
|
||||
TEST_ASSERT_EQUAL_INT(1, e->u.plan_end.rc);
|
||||
|
||||
e = entry_at(rec, 7);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_COMMIT, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(1, e->depth);
|
||||
TEST_ASSERT_EQUAL_INT(3, e->u.commit.plan_no); /* the last plan begun */
|
||||
|
||||
e = entry_at(rec, 8);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_PLAN_NOT_TRIED, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(4, e->u.plan.plan_no);
|
||||
TEST_ASSERT_EQUAL_INT(4, e->u.plan.nbuckets);
|
||||
TEST_ASSERT_EQUAL_INT(-12, e->u.plan.err);
|
||||
|
||||
e = entry_at(rec, 9);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_FINALIZE_FAILED, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(3, e->u.commit.plan_no);
|
||||
TEST_ASSERT_EQUAL_INT(-5, e->u.commit.err);
|
||||
|
||||
e = entry_at(rec, 10);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_NO_PLAN, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(XCE_TRACE_NOPLAN_NONE_GENERATED, e->u.no_plan.why);
|
||||
|
||||
e = entry_at(rec, 11);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_RESREQ_END, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(0, e->depth);
|
||||
TEST_ASSERT_EQUAL_INT(0, rec->depth);
|
||||
|
||||
/* plan numbers restart with the next requirement */
|
||||
sched_trace_path_push(rec, XCE_TRACE_PATH_SINGLE, 1, 1);
|
||||
sched_trace_resreq_begin(rec, &fp.p, 0);
|
||||
sched_trace_plan_begin(rec, &p2);
|
||||
TEST_ASSERT_EQUAL_INT(1, rec->entries_tail->u.plan.plan_no);
|
||||
sched_trace_plan_end(rec, 1, 0);
|
||||
sched_trace_resreq_end(rec, 1, 0);
|
||||
sched_trace_path_pop(rec);
|
||||
|
||||
sched_trace_rec_free(rec);
|
||||
}
|
||||
|
||||
static void test_check_failed_and_no_plan_reasons(void)
|
||||
{
|
||||
xce_sched_trace_rec_t* rec = new_rec(XCE_TRACE_LINE_BOUND_DEFAULT);
|
||||
|
||||
TEST_ASSERT_NOT_NULL(rec);
|
||||
sched_trace_check_begin(rec, NULL);
|
||||
sched_trace_check_end(rec, 0, false);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_CHECK_END, rec->entries_tail->type);
|
||||
TEST_ASSERT_EQUAL_INT(0, rec->entries_tail->u.check_end.rc);
|
||||
TEST_ASSERT_FALSE(rec->entries_tail->u.check_end.plans_follow);
|
||||
sched_trace_no_plan(rec, XCE_TRACE_NOPLAN_DECLINED);
|
||||
TEST_ASSERT_EQUAL_INT(XCE_TRACE_NOPLAN_DECLINED,
|
||||
rec->entries_tail->u.no_plan.why);
|
||||
sched_trace_no_plan(rec, XCE_TRACE_NOPLAN_GENERATOR_FAILED);
|
||||
TEST_ASSERT_EQUAL_INT(XCE_TRACE_NOPLAN_GENERATOR_FAILED,
|
||||
rec->entries_tail->u.no_plan.why);
|
||||
TEST_ASSERT_EQUAL_INT(3, rec->nentries);
|
||||
sched_trace_rec_free(rec);
|
||||
}
|
||||
|
||||
static xce_sched_worker_t make_worker(char* name, int idx)
|
||||
{
|
||||
xce_sched_worker_t w;
|
||||
|
||||
memset(&w, 0, sizeof(w));
|
||||
w.name = name;
|
||||
w.idx = idx;
|
||||
return w;
|
||||
}
|
||||
|
||||
static void test_position_and_host_entries(void)
|
||||
{
|
||||
xce_sched_trace_rec_t* rec = new_rec(XCE_TRACE_LINE_BOUND_DEFAULT);
|
||||
const sched_trace_entry_t* e;
|
||||
char n1[8] = "n01";
|
||||
char n2[8] = "n02";
|
||||
char n3[8] = "n03";
|
||||
char n4[8] = "n04";
|
||||
char n5[8] = "n05";
|
||||
xce_sched_worker_t w1 = make_worker(n1, 0);
|
||||
xce_sched_worker_t w2 = make_worker(n2, 1);
|
||||
xce_sched_worker_t w3 = make_worker(n3, 2);
|
||||
xce_sched_worker_t w4 = make_worker(n4, 3);
|
||||
xce_sched_worker_t w5 = make_worker(n5, 4);
|
||||
int s[2] = { 4, 2 };
|
||||
xce_alloc_plan_t plan = make_plan(s, 2);
|
||||
const xce_sched_obj_t* obj = (const xce_sched_obj_t*)&plan;
|
||||
|
||||
TEST_ASSERT_NOT_NULL(rec);
|
||||
sched_trace_plan_begin(rec, &plan); /* 0, depth 0 */
|
||||
sched_trace_pos_begin(rec, 1, 4); /* 1, depth 1 */
|
||||
sched_trace_host_begin(rec, obj, &w1); /* no entry */
|
||||
TEST_ASSERT_TRUE(rec->scope_obj == obj);
|
||||
TEST_ASSERT_TRUE(rec->scope_w == &w1);
|
||||
sched_trace_host_verdict(rec, XCE_TRACE_V_SELECT, 0); /* 2 */
|
||||
TEST_ASSERT_NULL(rec->scope_w); /* the host scope ended */
|
||||
TEST_ASSERT_NULL(rec->scope_obj);
|
||||
sched_trace_host_begin(rec, obj, &w2);
|
||||
sched_trace_host_verdict(rec, 0, 0); /* from rows: none -> SELECT */
|
||||
sched_trace_host_begin(rec, obj, &w3);
|
||||
rec->host_row_verdicts = XCE_TRACE_V_SHORTFALL | XCE_TRACE_V_LIMIT;
|
||||
sched_trace_host_verdict(rec, 0, 0); /* from rows */
|
||||
TEST_ASSERT_EQUAL_UINT(0, rec->host_row_verdicts);
|
||||
sched_trace_host_begin(rec, obj, &w4);
|
||||
sched_trace_host_verdict(rec, XCE_TRACE_V_CLAIMED, 0);
|
||||
sched_trace_host_begin(rec, obj, &w5);
|
||||
sched_trace_host_verdict(rec, XCE_TRACE_V_INTERNAL, -5);
|
||||
sched_trace_host_begin(rec, obj, &w3);
|
||||
sched_trace_host_verdict(rec, XCE_TRACE_V_ACCEPTED, 0);
|
||||
sched_trace_pos_end(rec, XCE_TRACE_POS_FILLED, n3); /* 8 */
|
||||
sched_trace_pos_begin(rec, 2, 2); /* 9 */
|
||||
sched_trace_host_begin(rec, obj, &w1);
|
||||
sched_trace_host_verdict(rec, XCE_TRACE_V_SELECT, 0); /* 10 */
|
||||
sched_trace_pos_scan_error(rec, -5); /* no entry */
|
||||
sched_trace_pos_end(rec, XCE_TRACE_POS_UNFILLED, NULL); /* 11 */
|
||||
sched_trace_pos_begin(rec, 2, 2); /* 12 */
|
||||
sched_trace_pos_end(rec, XCE_TRACE_POS_UNFILLED, NULL); /* 13 */
|
||||
sched_trace_pos_begin(rec, 2, 2); /* 14 */
|
||||
sched_trace_pos_end(rec, XCE_TRACE_POS_INTERNAL, n2); /* 15 */
|
||||
sched_trace_plan_end(rec, 0, 2); /* 16 */
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(17, count_entries(rec));
|
||||
TEST_ASSERT_EQUAL_INT(0, rec->depth);
|
||||
|
||||
e = entry_at(rec, 1);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_POS_BEGIN, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(1, e->depth);
|
||||
TEST_ASSERT_EQUAL_INT(1, e->u.pos_begin.pos);
|
||||
TEST_ASSERT_EQUAL_INT(4, e->u.pos_begin.slots);
|
||||
|
||||
e = entry_at(rec, 2);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_HOST, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(2, e->depth);
|
||||
TEST_ASSERT_EQUAL_STRING("n01", e->u.host.host);
|
||||
TEST_ASSERT_TRUE(e->u.host.host != n1);
|
||||
TEST_ASSERT_EQUAL_UINT(XCE_TRACE_V_SELECT, e->u.host.verdicts);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_PHASE_PREFILTER, e->u.host.phase);
|
||||
|
||||
e = entry_at(rec, 3);
|
||||
TEST_ASSERT_EQUAL_STRING("n02", e->u.host.host);
|
||||
TEST_ASSERT_EQUAL_UINT(XCE_TRACE_V_SELECT, e->u.host.verdicts);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_PHASE_PERHOST, e->u.host.phase);
|
||||
|
||||
e = entry_at(rec, 4);
|
||||
TEST_ASSERT_EQUAL_STRING("n03", e->u.host.host);
|
||||
TEST_ASSERT_EQUAL_UINT(XCE_TRACE_V_SHORTFALL | XCE_TRACE_V_LIMIT,
|
||||
e->u.host.verdicts);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_PHASE_PERHOST, e->u.host.phase);
|
||||
|
||||
e = entry_at(rec, 5);
|
||||
TEST_ASSERT_EQUAL_UINT(XCE_TRACE_V_CLAIMED, e->u.host.verdicts);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_PHASE_NONE, e->u.host.phase);
|
||||
|
||||
e = entry_at(rec, 6);
|
||||
TEST_ASSERT_EQUAL_STRING("n05", e->u.host.host);
|
||||
TEST_ASSERT_EQUAL_UINT(XCE_TRACE_V_INTERNAL, e->u.host.verdicts);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_PHASE_NONE, e->u.host.phase);
|
||||
TEST_ASSERT_EQUAL_INT(-5, e->u.host.err);
|
||||
|
||||
e = entry_at(rec, 7);
|
||||
TEST_ASSERT_EQUAL_UINT(XCE_TRACE_V_ACCEPTED, e->u.host.verdicts);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_PHASE_NONE, e->u.host.phase);
|
||||
|
||||
e = entry_at(rec, 8);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_POS_END, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(1, e->depth); /* same level as its begin */
|
||||
TEST_ASSERT_EQUAL_INT(1, e->u.pos_end.pos);
|
||||
TEST_ASSERT_EQUAL_INT(XCE_TRACE_POS_FILLED, e->u.pos_end.how);
|
||||
TEST_ASSERT_EQUAL_STRING("n03", e->u.pos_end.host);
|
||||
TEST_ASSERT_TRUE(e->u.pos_end.host != n3);
|
||||
|
||||
e = entry_at(rec, 11); /* UNFILLED after a scan error */
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_POS_END, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(2, e->u.pos_end.pos);
|
||||
TEST_ASSERT_EQUAL_INT(XCE_TRACE_POS_SCAN_ERROR, e->u.pos_end.how);
|
||||
TEST_ASSERT_EQUAL_INT(-5, e->u.pos_end.err);
|
||||
TEST_ASSERT_NULL(e->u.pos_end.host);
|
||||
|
||||
e = entry_at(rec, 13); /* the scan error belonged to the earlier one */
|
||||
TEST_ASSERT_EQUAL_INT(XCE_TRACE_POS_UNFILLED, e->u.pos_end.how);
|
||||
TEST_ASSERT_EQUAL_INT(0, e->u.pos_end.err);
|
||||
|
||||
e = entry_at(rec, 15);
|
||||
TEST_ASSERT_EQUAL_INT(XCE_TRACE_POS_INTERNAL, e->u.pos_end.how);
|
||||
TEST_ASSERT_EQUAL_STRING("n02", e->u.pos_end.host);
|
||||
|
||||
e = entry_at(rec, 16);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_PLAN_END, e->type);
|
||||
TEST_ASSERT_EQUAL_INT(0, e->depth);
|
||||
TEST_ASSERT_EQUAL_INT(2, e->u.plan_end.failed_pos);
|
||||
|
||||
/* the host names are copies */
|
||||
strcpy(n1, "zz");
|
||||
strcpy(n3, "zz");
|
||||
TEST_ASSERT_EQUAL_STRING("n01", entry_at(rec, 2)->u.host.host);
|
||||
TEST_ASSERT_EQUAL_STRING("n03", entry_at(rec, 8)->u.pos_end.host);
|
||||
|
||||
sched_trace_rec_free(rec);
|
||||
}
|
||||
|
||||
static void test_pos_end_scan_error_direct(void)
|
||||
{
|
||||
xce_sched_trace_rec_t* rec = new_rec(XCE_TRACE_LINE_BOUND_DEFAULT);
|
||||
|
||||
TEST_ASSERT_NOT_NULL(rec);
|
||||
sched_trace_pos_begin(rec, 1, 1);
|
||||
sched_trace_pos_end(rec, XCE_TRACE_POS_SCAN_ERROR, NULL);
|
||||
TEST_ASSERT_EQUAL_INT(2, rec->nentries);
|
||||
TEST_ASSERT_EQUAL_INT(XCE_TRACE_POS_SCAN_ERROR,
|
||||
rec->entries_tail->u.pos_end.how);
|
||||
TEST_ASSERT_EQUAL_INT(1, rec->entries_tail->u.pos_end.pos);
|
||||
sched_trace_rec_free(rec);
|
||||
}
|
||||
|
||||
/* Drives one call of every entry kind; returns the number of entries it
|
||||
* makes (every call below stores exactly one entry). */
|
||||
static int emit_every_kind(xce_sched_trace_rec_t* rec)
|
||||
{
|
||||
static int slots[1] = { 1 };
|
||||
static char hname[] = "n01";
|
||||
static fixture_primary_t fp;
|
||||
xce_alloc_plan_t plan = make_plan(slots, 1);
|
||||
xce_sched_worker_t w = make_worker(hname, 0);
|
||||
sched_trace_reason_count_t rc = { 1, 1 };
|
||||
|
||||
make_primary(&fp, 1, 1);
|
||||
sched_trace_path_push(rec, XCE_TRACE_PATH_ALT, 1, 2);
|
||||
sched_trace_alt_skipped(rec, 1, 2); /* 1 */
|
||||
sched_trace_path_pop(rec);
|
||||
sched_trace_path_push(rec, XCE_TRACE_PATH_ALT, 2, 2);
|
||||
sched_trace_resreq_begin(rec, NULL, 1); /* 2 */
|
||||
sched_trace_path_push(rec, XCE_TRACE_PATH_MEMBER, 1, 1);
|
||||
sched_trace_resreq_begin(rec, &fp.p, 0); /* 3 */
|
||||
sched_trace_check_begin(rec, NULL);
|
||||
sched_trace_check_end(rec, 1, true); /* 4 */
|
||||
sched_trace_no_plan(rec, XCE_TRACE_NOPLAN_DECLINED); /* 5 */
|
||||
sched_trace_plan_discarded(rec, &plan); /* 6 */
|
||||
sched_trace_plan_not_tried(rec, &plan, -12); /* 7 */
|
||||
sched_trace_plan_begin(rec, &plan); /* 8 */
|
||||
sched_trace_pos_begin(rec, 1, 1); /* 9 */
|
||||
sched_trace_host_begin(rec, NULL, &w);
|
||||
sched_trace_host_verdict(rec, XCE_TRACE_V_ACCEPTED, 0); /* 10 */
|
||||
sched_trace_pos_end(rec, XCE_TRACE_POS_FILLED, hname); /* 11 */
|
||||
sched_trace_plan_end(rec, 1, 0); /* 12 */
|
||||
sched_trace_commit(rec); /* 13 */
|
||||
sched_trace_finalize_failed(rec, -5); /* 14 */
|
||||
sched_trace_resreq_end(rec, 1, 0); /* 15 */
|
||||
sched_trace_path_pop(rec);
|
||||
sched_trace_member_failed(rec, 1, 1, -12); /* 16 */
|
||||
sched_trace_attempt_reasons(rec, &rc, 1, NULL, 0, NULL, 0); /* 17 */
|
||||
sched_trace_resreq_end(rec, 0, 0); /* 18 */
|
||||
sched_trace_path_pop(rec);
|
||||
sched_trace_alt_result(rec, 0, 2); /* 19 */
|
||||
return 19;
|
||||
}
|
||||
|
||||
static void test_every_entry_kind_is_one_entry(void)
|
||||
{
|
||||
xce_sched_trace_rec_t* rec = new_rec(XCE_TRACE_LINE_BOUND_DEFAULT);
|
||||
const sched_trace_entry_t* e;
|
||||
int seen[SCHED_TRACE_E_NTYPES];
|
||||
int n;
|
||||
int t;
|
||||
|
||||
TEST_ASSERT_NOT_NULL(rec);
|
||||
memset(seen, 0, sizeof(seen));
|
||||
n = emit_every_kind(rec);
|
||||
TEST_ASSERT_EQUAL_INT(n, rec->nentries);
|
||||
TEST_ASSERT_EQUAL_INT(n, count_entries(rec));
|
||||
TEST_ASSERT_EQUAL_INT(0, rec->counters.omitted_lines);
|
||||
TEST_ASSERT_EQUAL_INT(0, rec->depth);
|
||||
TEST_ASSERT_EQUAL_INT(0, rec->resreq_open);
|
||||
TEST_ASSERT_EQUAL_INT(0, rec->path.depth);
|
||||
TEST_ASSERT_FALSE(rec->incomplete);
|
||||
for (e = rec->entries; e != NULL; e = e->next) {
|
||||
TEST_ASSERT_TRUE(e->type < SCHED_TRACE_E_NTYPES);
|
||||
seen[e->type]++;
|
||||
}
|
||||
for (t = 0; t < SCHED_TRACE_E_NTYPES; t++) {
|
||||
TEST_ASSERT_TRUE_MESSAGE(seen[t] > 0, "entry kind never stored");
|
||||
}
|
||||
sched_trace_rec_free(rec);
|
||||
}
|
||||
|
||||
/* ---- line budget (9.1, 9.2) ------------------------------------------- */
|
||||
|
||||
/* Appends `k` entries (each alt_skipped call is one line). */
|
||||
static void emit_lines(xce_sched_trace_rec_t* rec, int k)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 1; i <= k; i++) {
|
||||
sched_trace_alt_skipped(rec, i, k);
|
||||
}
|
||||
}
|
||||
|
||||
static void check_budget(int bound, int k, int want_stored, int want_omitted)
|
||||
{
|
||||
xce_sched_trace_rec_t* rec = new_rec(bound);
|
||||
|
||||
TEST_ASSERT_NOT_NULL(rec);
|
||||
emit_lines(rec, k);
|
||||
TEST_ASSERT_EQUAL_INT(want_stored, rec->nentries);
|
||||
TEST_ASSERT_EQUAL_INT(want_stored, count_entries(rec));
|
||||
TEST_ASSERT_EQUAL_INT(want_omitted, rec->counters.omitted_lines);
|
||||
TEST_ASSERT_FALSE(rec->incomplete);
|
||||
/* the stored ones are the first ones, in order */
|
||||
if (want_stored > 0) {
|
||||
TEST_ASSERT_EQUAL_INT(1, rec->entries->u.alt.i);
|
||||
TEST_ASSERT_EQUAL_INT(want_stored, rec->entries_tail->u.alt.i);
|
||||
}
|
||||
sched_trace_rec_free(rec);
|
||||
}
|
||||
|
||||
static void test_budget_edges(void)
|
||||
{
|
||||
const int b = XCE_TRACE_LINE_BOUND_MIN;
|
||||
|
||||
check_budget(b, b - 1, b - 1, 0);
|
||||
check_budget(b, b, b, 0);
|
||||
check_budget(b, b + 1, b, 1);
|
||||
check_budget(b, b + 37, b, 37);
|
||||
check_budget(XCE_TRACE_LINE_BOUND_DEFAULT,
|
||||
XCE_TRACE_LINE_BOUND_DEFAULT - 1,
|
||||
XCE_TRACE_LINE_BOUND_DEFAULT - 1, 0);
|
||||
check_budget(XCE_TRACE_LINE_BOUND_DEFAULT, XCE_TRACE_LINE_BOUND_DEFAULT,
|
||||
XCE_TRACE_LINE_BOUND_DEFAULT, 0);
|
||||
check_budget(XCE_TRACE_LINE_BOUND_DEFAULT,
|
||||
XCE_TRACE_LINE_BOUND_DEFAULT + 1,
|
||||
XCE_TRACE_LINE_BOUND_DEFAULT, 1);
|
||||
}
|
||||
|
||||
/* Past the bound nothing more is stored or allocated, every kind counts
|
||||
* one omitted line, and the builder state stays balanced. */
|
||||
static void test_budget_counts_every_kind_and_keeps_state(void)
|
||||
{
|
||||
const int b = XCE_TRACE_LINE_BOUND_MIN;
|
||||
xce_sched_trace_rec_t* rec = new_rec(b);
|
||||
size_t bytes;
|
||||
int n;
|
||||
|
||||
TEST_ASSERT_NOT_NULL(rec);
|
||||
emit_lines(rec, b);
|
||||
TEST_ASSERT_EQUAL_INT(b, rec->nentries);
|
||||
bytes = sched_trace_rec_bytes(rec);
|
||||
|
||||
n = emit_every_kind(rec);
|
||||
TEST_ASSERT_EQUAL_INT(b, rec->nentries);
|
||||
TEST_ASSERT_EQUAL_INT(n, rec->counters.omitted_lines);
|
||||
TEST_ASSERT_EQUAL_UINT(bytes, sched_trace_rec_bytes(rec));
|
||||
TEST_ASSERT_EQUAL_INT(0, rec->depth);
|
||||
TEST_ASSERT_EQUAL_INT(0, rec->resreq_open);
|
||||
TEST_ASSERT_EQUAL_INT(0, rec->path.depth);
|
||||
TEST_ASSERT_NULL(rec->scope_w);
|
||||
TEST_ASSERT_NULL(rec->scope_obj);
|
||||
/* path push/pop and the scope-only calls are not lines */
|
||||
sched_trace_path_push(rec, XCE_TRACE_PATH_SINGLE, 1, 1);
|
||||
sched_trace_check_begin(rec, NULL);
|
||||
sched_trace_pos_scan_error(rec, -5);
|
||||
sched_trace_path_pop(rec);
|
||||
TEST_ASSERT_EQUAL_INT(n, rec->counters.omitted_lines);
|
||||
sched_trace_rec_free(rec);
|
||||
}
|
||||
|
||||
/* An entry that straddles the bound: the begin is stored, its end is not,
|
||||
* and the nesting level still returns to the top. */
|
||||
static void test_budget_cut_inside_a_scope(void)
|
||||
{
|
||||
const int b = XCE_TRACE_LINE_BOUND_MIN;
|
||||
xce_sched_trace_rec_t* rec = new_rec(b);
|
||||
int s[1] = { 1 };
|
||||
xce_alloc_plan_t plan = make_plan(s, 1);
|
||||
|
||||
TEST_ASSERT_NOT_NULL(rec);
|
||||
emit_lines(rec, b - 1);
|
||||
sched_trace_plan_begin(rec, &plan); /* the b-th line, stored */
|
||||
sched_trace_pos_begin(rec, 1, 1); /* omitted */
|
||||
sched_trace_pos_end(rec, XCE_TRACE_POS_UNFILLED, NULL);
|
||||
sched_trace_plan_end(rec, 0, 1);
|
||||
TEST_ASSERT_EQUAL_INT(b, rec->nentries);
|
||||
TEST_ASSERT_EQUAL_INT(SCHED_TRACE_E_PLAN_BEGIN, rec->entries_tail->type);
|
||||
TEST_ASSERT_EQUAL_INT(3, rec->counters.omitted_lines);
|
||||
TEST_ASSERT_EQUAL_INT(0, rec->depth);
|
||||
sched_trace_rec_free(rec);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
UNITY_BEGIN();
|
||||
|
|
@ -428,5 +1258,19 @@ int main(void)
|
|||
RUN_TEST(test_rec_free_null_is_noop);
|
||||
RUN_TEST(test_finish_records_kind_and_error);
|
||||
RUN_TEST(test_finish_rejects_non_no_decision_kinds);
|
||||
RUN_TEST(test_single_requirement_path_and_balance);
|
||||
RUN_TEST(test_alternative_member_nesting_stores_full_path);
|
||||
RUN_TEST(test_compound_container_path);
|
||||
RUN_TEST(test_path_push_beyond_two_levels_stays_balanced);
|
||||
RUN_TEST(test_requirement_level_entries);
|
||||
RUN_TEST(test_attempt_reasons_empty_lists);
|
||||
RUN_TEST(test_check_and_plan_entries);
|
||||
RUN_TEST(test_check_failed_and_no_plan_reasons);
|
||||
RUN_TEST(test_position_and_host_entries);
|
||||
RUN_TEST(test_pos_end_scan_error_direct);
|
||||
RUN_TEST(test_every_entry_kind_is_one_entry);
|
||||
RUN_TEST(test_budget_edges);
|
||||
RUN_TEST(test_budget_counts_every_kind_and_keeps_state);
|
||||
RUN_TEST(test_budget_cut_inside_a_scope);
|
||||
return UNITY_END();
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue