560 lines
12 KiB
C
560 lines
12 KiB
C
#include <errno.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "kvmgr.h"
|
|
#include "resreq.h"
|
|
#include "rusage.h"
|
|
#include "section.h"
|
|
#include "utils.h"
|
|
#include "xce_resreq.h"
|
|
#include "xlist.h"
|
|
#include "xvec.h"
|
|
|
|
static int get_parse_errmsg(char** errmsg, const char* data, int pos)
|
|
{
|
|
size_t bufsize = 0;
|
|
FILE* mem_stream = NULL;
|
|
int i;
|
|
|
|
if ((errmsg == NULL) || (data == NULL) || (pos < 0)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
mem_stream = open_memstream(errmsg, &bufsize);
|
|
if (mem_stream == NULL) {
|
|
return -errno;
|
|
}
|
|
|
|
fprintf(mem_stream, "%s\n", data);
|
|
for (i = 0; i < pos - 1; i++) {
|
|
fprintf(mem_stream, " ");
|
|
}
|
|
|
|
fprintf(mem_stream, "^Error\n");
|
|
|
|
fflush(mem_stream);
|
|
fclose(mem_stream);
|
|
|
|
return 1;
|
|
}
|
|
|
|
void kill_resreq_data(xce_resreq_data_t* data)
|
|
{
|
|
if (data == NULL) {
|
|
return;
|
|
}
|
|
|
|
FREEUP(data->selectString);
|
|
FREEUP(data->rusageString);
|
|
FREEUP(data->spanString);
|
|
FREEUP(data->sameString);
|
|
FREEUP(data->affinityString);
|
|
}
|
|
|
|
void kill_section_ctx(section_context_t* ctx)
|
|
{
|
|
if (ctx == NULL) {
|
|
return;
|
|
}
|
|
|
|
kill_resreq_data(&(ctx->data));
|
|
}
|
|
|
|
int parse_section(xce_resreq_data_t* resreq, char* data, char** errmsg)
|
|
{
|
|
section_context_t ctx = { 0 };
|
|
xce_section_context_t* p = NULL;
|
|
int rc = 1;
|
|
|
|
if ((resreq == NULL) || (data == NULL) || (errmsg == NULL)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
*errmsg = NULL;
|
|
ctx.input = data;
|
|
|
|
memset(resreq, 0x0, sizeof(*resreq));
|
|
|
|
p = xce_section_create(&ctx);
|
|
if (p == NULL) {
|
|
return -errno;
|
|
}
|
|
|
|
xce_section_parse(p, NULL);
|
|
|
|
if (ctx.has_error) {
|
|
get_parse_errmsg(errmsg, ctx.input, ctx.err_pos);
|
|
rc = -EINVAL;
|
|
} else {
|
|
MOVE_PTR(resreq->selectString, ctx.data.selectString);
|
|
MOVE_PTR(resreq->rusageString, ctx.data.rusageString);
|
|
MOVE_PTR(resreq->spanString, ctx.data.spanString);
|
|
MOVE_PTR(resreq->sameString, ctx.data.sameString);
|
|
MOVE_PTR(resreq->affinityString, ctx.data.affinityString);
|
|
}
|
|
|
|
kill_section_ctx(&ctx);
|
|
|
|
xce_section_destroy(p);
|
|
|
|
return rc;
|
|
}
|
|
|
|
void kill_rusage_value(rusage_value_t* val)
|
|
{
|
|
if (val == NULL) {
|
|
return;
|
|
}
|
|
|
|
FREEUP(val->res);
|
|
}
|
|
|
|
void kill_rusage_ctx(rusage_context_t* ctx)
|
|
{
|
|
if (ctx == NULL) {
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
|
|
int parse_rusage(xlist_t* rusages, char* data, char** errmsg)
|
|
{
|
|
rusage_context_t ctx = { 0 };
|
|
xce_rusage_context_t* p = NULL;
|
|
int rc = 1;
|
|
|
|
if ((rusages == NULL) || (data == NULL) || (errmsg == NULL)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
*errmsg = NULL;
|
|
ctx.input = data;
|
|
ctx.rusages = rusages;
|
|
|
|
p = xce_rusage_create(&ctx);
|
|
if (p == NULL) {
|
|
return -errno;
|
|
}
|
|
|
|
xce_rusage_parse(p, NULL);
|
|
|
|
if (ctx.has_error) {
|
|
get_parse_errmsg(errmsg, ctx.input, ctx.err_pos);
|
|
rc = -EINVAL;
|
|
/* FIXME: need to freeup partial data in rusages */
|
|
}
|
|
|
|
kill_rusage_ctx(&ctx);
|
|
|
|
xce_rusage_destroy(p);
|
|
|
|
return rc;
|
|
}
|
|
|
|
int parse_resreq_primary(xce_primary_resreq_t* primary, char* resreqString,
|
|
char** errmsg)
|
|
{
|
|
int rc;
|
|
xce_resreq_data_t data;
|
|
|
|
if ((primary == NULL) || (resreqString == NULL) || (errmsg == NULL)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
memset(primary, 0x0, sizeof(*primary));
|
|
|
|
rc = parse_section(&data, (char*)resreqString, errmsg);
|
|
if (rc < 0) {
|
|
return rc;
|
|
}
|
|
|
|
xlist_init(&(primary->rusages), 8);
|
|
|
|
if ((data.rusageString != NULL) && (strlen(data.rusageString) != 0)) {
|
|
rc = parse_rusage(&(primary->rusages), data.rusageString, errmsg);
|
|
if (rc < 0) {
|
|
kill_resreq_data(&data);
|
|
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
/* FIXME: add others later */
|
|
|
|
kill_resreq_data(&data);
|
|
primary->minTasks = 1;
|
|
primary->maxTasks = 1;
|
|
|
|
return rc;
|
|
}
|
|
|
|
void kill_resreq_ctx(resreq_context_t* ctx)
|
|
{
|
|
if (ctx == NULL) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
int parse_resreq(xce_resreq_t* resreq, char* data, char** errmsg)
|
|
{
|
|
resreq_context_t ctx = { 0 };
|
|
xce_resreq_context_t* p = NULL;
|
|
int rc = 1;
|
|
|
|
if ((resreq == NULL) || (data == NULL) || (errmsg == NULL)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
*errmsg = NULL;
|
|
memset(resreq, 0x0, sizeof(*resreq));
|
|
|
|
ctx.input = data;
|
|
ctx.resreq = resreq;
|
|
|
|
p = xce_resreq_create(&ctx);
|
|
if (p == NULL) {
|
|
return -errno;
|
|
}
|
|
|
|
xce_resreq_parse(p, NULL);
|
|
|
|
if (ctx.has_error) {
|
|
get_parse_errmsg(errmsg, ctx.input, ctx.err_pos);
|
|
rc = -EINVAL;
|
|
/* FIXME: need to freeup partial data in resreqs */
|
|
}
|
|
|
|
kill_resreq_ctx(&ctx);
|
|
|
|
xce_resreq_destroy(p);
|
|
|
|
return rc;
|
|
}
|
|
|
|
void kill_primary_resreq(xce_primary_resreq_t* resreq)
|
|
{
|
|
int i;
|
|
|
|
if (resreq == NULL) {
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < resreq->rusages.count; i++) {
|
|
rusage_value_t* v = (rusage_value_t*)xlist_get(&(resreq->rusages), i);
|
|
|
|
if (v == NULL) {
|
|
continue;
|
|
}
|
|
|
|
kill_rusage_value(v);
|
|
|
|
FREEUP(v);
|
|
}
|
|
|
|
xlist_fini(&(resreq->rusages));
|
|
}
|
|
|
|
void kill_compound_resreq(xce_compound_resreq_t* resreq)
|
|
{
|
|
int i;
|
|
|
|
if (resreq == NULL) {
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < resreq->primaries.count; i++) {
|
|
xce_primary_resreq_t* primary
|
|
= (xce_primary_resreq_t*)xlist_get(&(resreq->primaries), i);
|
|
|
|
if (primary == NULL) {
|
|
continue;
|
|
}
|
|
|
|
kill_primary_resreq(primary);
|
|
FREEUP(primary);
|
|
}
|
|
|
|
xlist_fini(&(resreq->primaries));
|
|
}
|
|
|
|
void kill_alter_resreq(xce_alter_resreq_t* resreq)
|
|
{
|
|
int i;
|
|
|
|
if (resreq == NULL) {
|
|
return;
|
|
}
|
|
|
|
for (i = 0; i < resreq->compounds.count; i++) {
|
|
xce_compound_resreq_t* c
|
|
= (xce_compound_resreq_t*)xlist_get(&(resreq->compounds), i);
|
|
|
|
if (c == NULL) {
|
|
continue;
|
|
}
|
|
|
|
kill_compound_resreq(c);
|
|
FREEUP(c);
|
|
}
|
|
|
|
xlist_fini(&(resreq->compounds));
|
|
}
|
|
|
|
void kill_resreq(xce_resreq_t* resreq)
|
|
{
|
|
if (resreq == NULL) {
|
|
return;
|
|
}
|
|
|
|
switch (resreq->tag) {
|
|
case XCE_RESREQ_PRIMARY:
|
|
kill_primary_resreq(resreq->u.primary);
|
|
FREEUP(resreq->u.primary);
|
|
break;
|
|
case XCE_RESREQ_COMPOUND:
|
|
kill_compound_resreq(resreq->u.compound);
|
|
FREEUP(resreq->u.compound);
|
|
break;
|
|
case XCE_RESREQ_ALTER:
|
|
kill_alter_resreq(resreq->u.alter);
|
|
FREEUP(resreq->u.alter);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static int print_rusages(FILE* fp, xlist_t* rusages, int level)
|
|
{
|
|
int i;
|
|
|
|
fprintf(fp, "%*sRusages:\n", (int)(2 * level), "");
|
|
for (i = 0; i < rusages->count; i++) {
|
|
rusage_value_t* v = (rusage_value_t*)xlist_get(rusages, i);
|
|
|
|
if (v == NULL) {
|
|
continue;
|
|
}
|
|
|
|
fprintf(fp, "%*s res %s value %f per %d duration %f decay %d\n",
|
|
(int)(2 * (level + 1)), "", v->res, v->value, v->per_flag,
|
|
v->duration, v->decay_flag);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
static int print_primary_resreq(FILE* fp, xce_primary_resreq_t* resreq,
|
|
int level)
|
|
{
|
|
fprintf(fp, "%*sPrimary:\n", (int)(2 * level), "");
|
|
fprintf(fp, "%*sTasks: min = %d, max = %d\n", (int)(2 * (level + 1)), "",
|
|
resreq->minTasks, resreq->maxTasks);
|
|
#if 0
|
|
fprintf(fp, "%*Select: %s\n", (int)(2*(level +1)),"", "Add later");
|
|
#endif
|
|
print_rusages(fp, &(resreq->rusages), level + 1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int print_compound_resreq(FILE* fp, xce_compound_resreq_t* resreq,
|
|
int level)
|
|
{
|
|
int i;
|
|
|
|
fprintf(fp, "%*sCompound:\n", (int)(2 * level), "");
|
|
for (i = 0; i < resreq->primaries.count; i++) {
|
|
xce_primary_resreq_t* primary
|
|
= (xce_primary_resreq_t*)xlist_get(&(resreq->primaries), i);
|
|
|
|
if (primary == NULL) {
|
|
continue;
|
|
}
|
|
|
|
print_primary_resreq(fp, primary, level + 1);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int print_alter_resreq(FILE* fp, xce_alter_resreq_t* resreq, int level)
|
|
{
|
|
int i;
|
|
|
|
fprintf(fp, "%*sAlternative:\n", (int)(2 * level), "");
|
|
for (i = 0; i < resreq->compounds.count; i++) {
|
|
xce_compound_resreq_t* c
|
|
= (xce_compound_resreq_t*)xlist_get(&(resreq->compounds), i);
|
|
if (c == NULL) {
|
|
continue;
|
|
}
|
|
|
|
print_compound_resreq(fp, c, level + 1);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int print_resreq(FILE* fp, xce_resreq_t* resreq, int level)
|
|
{
|
|
if ((fp == NULL) || (resreq == NULL) || (level < 0)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
switch (resreq->tag) {
|
|
case XCE_RESREQ_PRIMARY:
|
|
return print_primary_resreq(fp, resreq->u.primary, level);
|
|
case XCE_RESREQ_COMPOUND:
|
|
return print_compound_resreq(fp, resreq->u.compound, level);
|
|
case XCE_RESREQ_ALTER:
|
|
return print_alter_resreq(fp, resreq->u.alter, level);
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return -EINVAL;
|
|
}
|
|
|
|
int format_resreq(char** buf, xce_resreq_t* resreq)
|
|
{
|
|
size_t bufsize = 0;
|
|
FILE* fp = NULL;
|
|
int rc = 0;
|
|
|
|
if ((buf == NULL) || (resreq == NULL)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
fp = open_memstream(buf, &bufsize);
|
|
if (fp == NULL) {
|
|
return -errno;
|
|
}
|
|
|
|
rc = print_resreq(fp, resreq, 0);
|
|
|
|
fflush(fp);
|
|
fclose(fp);
|
|
|
|
return rc;
|
|
}
|
|
|
|
int calc_wanted_global_resvals(xvec_idval_t* resvals, var resmgr,
|
|
xlist_t* rusages, rusage_per_type_t perflag,
|
|
int nhosts, int nslots)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < rusages->count; i++) {
|
|
rusage_value_t* v = (rusage_value_t*)xlist_get(rusages, i);
|
|
xce_resource_t* r = NULL;
|
|
float val;
|
|
rusage_per_type_t perflag1;
|
|
int rc = 0;
|
|
|
|
if (v == NULL) {
|
|
continue;
|
|
}
|
|
|
|
lock(resmgr, RTTI_LOCK_READ);
|
|
rc = key_find(resmgr, (void*)v->res, (void**)&r);
|
|
unlock(resmgr);
|
|
|
|
if (rc <= 0) {
|
|
continue;
|
|
}
|
|
|
|
if (r == NULL) {
|
|
continue;
|
|
}
|
|
|
|
if ((r->flags & XCE_RESF_GLOBAL) == 0) {
|
|
continue;
|
|
}
|
|
|
|
perflag1 = v->per_flag;
|
|
if (perflag1 == PER_DEFAULT) {
|
|
perflag1 = perflag;
|
|
}
|
|
|
|
switch (perflag1) {
|
|
case PER_TASK:
|
|
val = v->value * nslots;
|
|
break;
|
|
case PER_JOB:
|
|
val = v->value;
|
|
break;
|
|
case PER_HOST:
|
|
val = v->value * nhosts;
|
|
break;
|
|
default:
|
|
/* something wrong */
|
|
val = 0.0;
|
|
break;
|
|
}
|
|
|
|
xvec_idval_store(resvals, r->idx, val);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int calc_wanted_host_resvals(xvec_idval_t* resvals, var resmgr,
|
|
xlist_t* rusages, rusage_per_type_t perflag,
|
|
int nhosts, int nslots)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < rusages->count; i++) {
|
|
rusage_value_t* v = (rusage_value_t*)xlist_get(rusages, i);
|
|
xce_resource_t* r = NULL;
|
|
float val;
|
|
rusage_per_type_t perflag1;
|
|
int rc = 0;
|
|
|
|
if (v == NULL) {
|
|
continue;
|
|
}
|
|
|
|
lock(resmgr, RTTI_LOCK_READ);
|
|
rc = key_find(resmgr, (void*)v->res, (void**)&r);
|
|
unlock(resmgr);
|
|
|
|
if (rc <= 0) {
|
|
continue;
|
|
}
|
|
|
|
if (r == NULL) {
|
|
continue;
|
|
}
|
|
|
|
if ((r->flags & XCE_RESF_GLOBAL) != 0) {
|
|
continue;
|
|
}
|
|
|
|
perflag1 = v->per_flag;
|
|
if (perflag1 == PER_DEFAULT) {
|
|
perflag1 = perflag;
|
|
}
|
|
|
|
if (perflag1 == PER_JOB) {
|
|
/* FIXME: PER_JOB should be global? */
|
|
continue;
|
|
}
|
|
switch (perflag1) {
|
|
case PER_TASK:
|
|
val = v->value * nslots;
|
|
break;
|
|
case PER_HOST:
|
|
val = v->value;
|
|
break;
|
|
default:
|
|
/* something wrong */
|
|
val = 0.0;
|
|
break;
|
|
}
|
|
|
|
xvec_idval_store(resvals, r->idx, val);
|
|
}
|
|
|
|
return 0;
|
|
}
|