feat(libxce-alloc-preason-equality): public alloc_eq/host_alloc_eq/job_alloc_eq with first-difference description (task 2.1)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
8f25c1c3f3
commit
a6cbb323b0
6 changed files with 952 additions and 5 deletions
|
|
@ -1,4 +1,8 @@
|
|||
/* vasprintf() (GNU extension) builds the equality functions' difference
|
||||
* descriptions. */
|
||||
#define _GNU_SOURCE
|
||||
#include <errno.h>
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
|
@ -454,3 +458,225 @@ int merge_job_alloc(xce_job_alloc_t* dst, const xce_job_alloc_t* src)
|
|||
return merge_allocs(&(dst->nres_shared), &(dst->allocs_shared),
|
||||
src->nres_shared, src->allocs_shared);
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------
|
||||
* Allocation equality (libxce-alloc-preason-equality). Contract in
|
||||
* xcealloc.h. The description, when requested, is built bottom-up: the
|
||||
* innermost comparison formats the differing field, and each enclosing list
|
||||
* prefixes its own path segment and frees the inner string.
|
||||
* ---------------------------------------------------------------------- */
|
||||
|
||||
/* *why = formatted string, or NULL if the allocation fails (vasprintf leaves
|
||||
* its output undefined then). No-op when why is NULL. */
|
||||
static void eq_why(char** why, const char* fmt, ...)
|
||||
__attribute__((format(printf, 2, 3)));
|
||||
|
||||
static void eq_why(char** why, const char* fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
char* s = NULL;
|
||||
|
||||
if (why == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
va_start(ap, fmt);
|
||||
if (vasprintf(&s, fmt, ap) < 0) {
|
||||
s = NULL;
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
*why = s;
|
||||
}
|
||||
|
||||
/* Prefix an inner description with the list entry's path segment,
|
||||
* `list[i](key=label).`; a failed inner description stays NULL. */
|
||||
static void eq_why_wrap(char** why, const char* list, int i, const char* key,
|
||||
const char* label)
|
||||
{
|
||||
char* inner;
|
||||
|
||||
if ((why == NULL) || (*why == NULL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
inner = *why;
|
||||
eq_why(why, "%s[%d](%s=%s).%s", list, i, key, label, inner);
|
||||
free(inner);
|
||||
}
|
||||
|
||||
static const char* eq_label(const char* a, const char* b)
|
||||
{
|
||||
if (a != NULL) {
|
||||
return a;
|
||||
}
|
||||
return (b != NULL) ? b : "?";
|
||||
}
|
||||
|
||||
static const char* eq_nullness(const void* p)
|
||||
{
|
||||
return (p != NULL) ? "non-NULL" : "NULL";
|
||||
}
|
||||
|
||||
static int eq_str_field(const char* name, const char* a, const char* b,
|
||||
char** why)
|
||||
{
|
||||
if (str_eq(a, b)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
eq_why(why, "%s: %s%s%s != %s%s%s", name, (a != NULL) ? "\"" : "",
|
||||
(a != NULL) ? a : "NULL", (a != NULL) ? "\"" : "",
|
||||
(b != NULL) ? "\"" : "", (b != NULL) ? b : "NULL",
|
||||
(b != NULL) ? "\"" : "");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* In-order comparison of two `n`-entry xce_alloc_t lists named `list`. */
|
||||
static int eq_alloc_list(const char* list, xce_alloc_t* const* a,
|
||||
xce_alloc_t* const* b, int n, char** why)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
if (a[i] == b[i]) {
|
||||
continue;
|
||||
}
|
||||
if ((a[i] == NULL) || (b[i] == NULL)) {
|
||||
eq_why(why, "%s[%d]: %s != %s", list, i, eq_nullness(a[i]),
|
||||
eq_nullness(b[i]));
|
||||
return 0;
|
||||
}
|
||||
if (!alloc_eq(a[i], b[i], why)) {
|
||||
eq_why_wrap(why, list, i, "resname",
|
||||
eq_label(a[i]->resname, b[i]->resname));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int alloc_eq(const xce_alloc_t* a, const xce_alloc_t* b, char** why)
|
||||
{
|
||||
if (why != NULL) {
|
||||
*why = NULL;
|
||||
}
|
||||
if (a == b) {
|
||||
return 1;
|
||||
}
|
||||
if ((a == NULL) || (b == NULL)) {
|
||||
eq_why(why, "alloc: %s != %s", eq_nullness(a), eq_nullness(b));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!eq_str_field("resname", a->resname, b->resname, why)
|
||||
|| !eq_str_field("reserve", a->reserve, b->reserve, why)) {
|
||||
return 0;
|
||||
}
|
||||
if (a->value != b->value) {
|
||||
eq_why(why, "value: %.17g != %.17g", a->value, b->value);
|
||||
return 0;
|
||||
}
|
||||
if (a->duration != b->duration) {
|
||||
eq_why(why, "duration: %" PRId64 " != %" PRId64, a->duration,
|
||||
b->duration);
|
||||
return 0;
|
||||
}
|
||||
if (a->from != b->from) {
|
||||
eq_why(why, "from: %" PRIu64 " != %" PRIu64, a->from, b->from);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int host_alloc_eq(const xce_host_alloc_t* a, const xce_host_alloc_t* b,
|
||||
char** why)
|
||||
{
|
||||
if (why != NULL) {
|
||||
*why = NULL;
|
||||
}
|
||||
if (a == b) {
|
||||
return 1;
|
||||
}
|
||||
if ((a == NULL) || (b == NULL)) {
|
||||
eq_why(why, "host_alloc: %s != %s", eq_nullness(a), eq_nullness(b));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!eq_str_field("host", a->host, b->host, why)) {
|
||||
return 0;
|
||||
}
|
||||
if (a->nallocs != b->nallocs) {
|
||||
eq_why(why, "nallocs: %d != %d", a->nallocs, b->nallocs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return eq_alloc_list("allocs", a->allocs, b->allocs, a->nallocs, why);
|
||||
}
|
||||
|
||||
static void eq_fmt_jobid(char* buf, size_t sz, uint64_t jobid)
|
||||
{
|
||||
if (fmt_jobid(buf, sz, jobid) < 0) {
|
||||
snprintf(buf, sz, "%" PRIu64, jobid);
|
||||
}
|
||||
}
|
||||
|
||||
int job_alloc_eq(const xce_job_alloc_t* a, const xce_job_alloc_t* b,
|
||||
char** why)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (why != NULL) {
|
||||
*why = NULL;
|
||||
}
|
||||
if (a == b) {
|
||||
return 1;
|
||||
}
|
||||
if ((a == NULL) || (b == NULL)) {
|
||||
eq_why(why, "job_alloc: %s != %s", eq_nullness(a), eq_nullness(b));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (a->jobid != b->jobid) {
|
||||
if (why != NULL) {
|
||||
char ja[128];
|
||||
char jb[128];
|
||||
|
||||
eq_fmt_jobid(ja, sizeof(ja), a->jobid);
|
||||
eq_fmt_jobid(jb, sizeof(jb), b->jobid);
|
||||
eq_why(why, "jobid: %s != %s", ja, jb);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (a->nhosts != b->nhosts) {
|
||||
eq_why(why, "nhosts: %d != %d", a->nhosts, b->nhosts);
|
||||
return 0;
|
||||
}
|
||||
if (a->nres_shared != b->nres_shared) {
|
||||
eq_why(why, "nres_shared: %d != %d", a->nres_shared, b->nres_shared);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < a->nhosts; i++) {
|
||||
const xce_host_alloc_t* ha = a->allocs[i];
|
||||
const xce_host_alloc_t* hb = b->allocs[i];
|
||||
|
||||
if (ha == hb) {
|
||||
continue;
|
||||
}
|
||||
if ((ha == NULL) || (hb == NULL)) {
|
||||
eq_why(why, "allocs[%d]: %s != %s", i, eq_nullness(ha),
|
||||
eq_nullness(hb));
|
||||
return 0;
|
||||
}
|
||||
if (!host_alloc_eq(ha, hb, why)) {
|
||||
eq_why_wrap(why, "allocs", i, "host", eq_label(ha->host, hb->host));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return eq_alloc_list("allocs_shared", a->allocs_shared, b->allocs_shared,
|
||||
a->nres_shared, why);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue