diff --git a/src/include/pbs_ifl.h b/src/include/pbs_ifl.h index ae80dd7..1620ad0 100644 --- a/src/include/pbs_ifl.h +++ b/src/include/pbs_ifl.h @@ -181,6 +181,7 @@ #define ATTR_intcmd "inter_cmd" #define ATTR_P "proxy_user" #define ATTR_schedspec "sched_nodespec" +#define ATTR_total_resources "total_resources" #ifdef USEJOBCREATE #define ATTR_pagg "pagg_id" diff --git a/src/include/pbs_job.h b/src/include/pbs_job.h index 159f7e9..5e3232c 100644 --- a/src/include/pbs_job.h +++ b/src/include/pbs_job.h @@ -297,6 +297,7 @@ enum job_atr JOB_ATR_inter_cmd, /* command for interactive job */ JOB_ATR_proxy_user, JOB_ATR_sched_spec, /* schedulers nodespec sent during job run request */ + JOB_ATR_total_resources, /* total resources (read-only) */ #ifdef USEJOBCREATE JOB_ATR_pagg_id, #endif /* USEJOBCREATE */ diff --git a/src/server/job_attr_def.c b/src/server/job_attr_def.c index 9abaab7..28d789d 100644 --- a/src/server/job_attr_def.c +++ b/src/server/job_attr_def.c @@ -946,6 +946,19 @@ attribute_def job_attr_def[] = PARENT_TYPE_JOB }, + /* JOB_ATR_total_resources */ + { ATTR_total_resources, /* "total_resources" */ + decode_resc, + encode_resc, + set_resc, + comp_resc, + free_resc, + action_resc, + READ_ONLY, + ATR_TYPE_RESC, + PARENT_TYPE_JOB + }, + #ifdef USEJOBCREATE /* JOB_ATR_pagg_id */ diff --git a/src/server/node_manager.c b/src/server/node_manager.c index e8b9dc8..7dcb38a 100644 --- a/src/server/node_manager.c +++ b/src/server/node_manager.c @@ -2978,7 +2978,194 @@ static int proplist( return 0; } /* END proplist() */ +static int nodespec_to_proplist(char **str, int *cnodes, int *cprocs, struct prop **list) + { + int i = 0; + + /* determine number of nodes */ + if ((i = number(str, cnodes)) == -1) + { + return -1; + } + + if (i == 0) /* number exists */ + { + if (**str == ':') + { + /* there are properties */ + (*str)++; + + if (proplist(str, list, cprocs)) + { + return -1; + } + } + } + else /* no number */ + { + if (proplist(str, list, cprocs)) + { + /* must be a prop list with no number in front */ + + return -1; + } + } + + return 0; + } + +void regenerate_total_resources(job * pjob) + { + int cnodes = 0; + int cprocs = 0; + + /* cleanup any previous values */ + job_attr_def[(int)JOB_ATR_total_resources]. + at_free(&pjob->ji_wattr[(int)JOB_ATR_total_resources]); + + /* pass 1. + * - find nodespec + * - add each part that represents a counted resource into total resources + * - calculate total amount of procs and nodes + */ + if ((pjob->ji_wattr[(int)JOB_ATR_resource].at_flags & ATR_VFLAG_SET) != 0) + { + resource_def *rd; + resource *rs; + + rd = find_resc_def(svr_resc_def,"nodes",svr_resc_size); + if (rd != NULL) + rs = find_resc_entry(&pjob->ji_wattr[(int)JOB_ATR_resource],rd); + if (rd != NULL && rs != NULL) + { + char *buf, *part, *next; + + next = buf = part = strdup(rs->rs_value.at_val.at_str); + if (buf == NULL) + return; + + /* process each nodespec part (between + signs) */ + do + { + int procs = 1, nodes = 1; + struct prop *prop = NULL, *iter; + + part = next; + + next = strchr(part,'+'); + if (next != NULL) + { + *next = '\0'; + next++; + } + + /* parse this nodespec part */ + if (nodespec_to_proplist(&part,&nodes,&procs,&prop) == -1) + { + free(buf); + return; + } + + /* for each property determine if it is a counted resource */ + for (iter = prop;iter;iter = iter->next) + { + int total_count = 0; + int i, ret; + resource *value; + resource decoded; + resource_def *defin = find_resc_def(svr_resc_def,iter->name,svr_resc_size); + + if (defin != NULL) + { + /* only count per proc and per node resources in the nodespec */ + if ((defin->rs_flags & ATR_DFLAG_SELECT_MOM) != 0) + total_count = nodes; + if ((defin->rs_flags & ATR_DFLAG_SELECT_PROC) != 0) + total_count = nodes * procs; + + ret = defin->rs_decode(&decoded.rs_value,0,iter->name,iter->value); + if (ret != 0) + return; + + value = find_resc_entry(&pjob->ji_wattr[(int)JOB_ATR_total_resources],defin); + + for (i = 0;i < total_count;i++) + { + if (value == NULL) + { + value = add_resource_entry(&pjob->ji_wattr[(int)JOB_ATR_total_resources],defin); + ret = defin->rs_set(&value->rs_value,&decoded.rs_value,SET); + if (ret != 0) + return; + continue; + } + + ret = defin->rs_set(&value->rs_value,&decoded.rs_value,INCR); + if (ret != 0) + return; + } + } + } + + cnodes += nodes; + cprocs += nodes*procs; + } + while (next != NULL); + + free(buf); + } + else + { + /* if there is no nodes request, assume 1 proc and 1 node */ + cnodes = 1; + cprocs = 1; + } + } + + /* pass 2. + * - process all counted resources + */ + if ((pjob->ji_wattr[(int)JOB_ATR_resource].at_flags & ATR_VFLAG_SET) != 0) + { + resource *jbrc = (resource *)GET_NEXT(pjob->ji_wattr[(int)JOB_ATR_resource].at_val.at_list); + + while (jbrc != NULL) + { + int total_count = 1; + int i, ret; + resource *value; + + if ((jbrc->rs_defin->rs_flags & ATR_DFLAG_SELECT_MOM) != 0) + total_count = cnodes; + if ((jbrc->rs_defin->rs_flags & ATR_DFLAG_SELECT_PROC) != 0) + total_count = cprocs; + + value = find_resc_entry(&pjob->ji_wattr[(int)JOB_ATR_total_resources],jbrc->rs_defin); + + for (i = 0;i < total_count;i++) + { + if (value == NULL) + { + value = add_resource_entry(&pjob->ji_wattr[(int)JOB_ATR_total_resources],jbrc->rs_defin); + ret = jbrc->rs_defin->rs_set(&value->rs_value,&jbrc->rs_value,SET); + if (ret != 0) + return; + continue; + } + + ret = jbrc->rs_defin->rs_set(&value->rs_value,&jbrc->rs_value,INCR); + if (ret != 0) + return; + } + + + jbrc = (resource*)GET_NEXT(jbrc->rs_link); + } + } + + return; + } /* @@ -4894,7 +5081,6 @@ void adjust_resources_use(struct pbsnode *pnode, struct jobinfo *jp, int first, struct prop *prop = NULL, *iter = NULL; char *str, *spec, *token; int i,count,num; - resource *jbrc = NULL; if (jp->job->ji_expanded_spec == NULL) return; diff --git a/src/server/req_quejob.c b/src/server/req_quejob.c index 3b9fd77..13098ad 100644 --- a/src/server/req_quejob.c +++ b/src/server/req_quejob.c @@ -131,6 +131,7 @@ extern int svr_authorize_jobreq A_((struct batch_request *, job *)); extern int svr_chkque A_((job *, pbs_queue *, char *, int, char *)); extern int job_route A_((job *)); extern int node_avail_complex(char *, int *, int *, int *, int*); +void regenerate_total_resources(job *); /* Global Data Items: */ @@ -865,6 +866,13 @@ void req_quejob( NULL, server_name); + /* Generate the resources total job attribute + * + * This attribute contains all counted resources + * from both the nodespec request and resource requests. + */ + regenerate_total_resources(pj); + /* * See if the job is qualified to go into the requested queue. * Note, if an execution queue, then ji_qs.ji_un.ji_exect is set up @@ -1684,8 +1692,6 @@ void req_commit( } /* END req_commit() */ - - /* * locate_new_job - locate a "new" job which has been set up req_quejob on * the servers new job list. diff --git a/src/server/svr_jobfunc.c b/src/server/svr_jobfunc.c index 4a2cd32..3e87ae7 100644 --- a/src/server/svr_jobfunc.c +++ b/src/server/svr_jobfunc.c @@ -1721,7 +1721,7 @@ int svr_chkque( /* 6. resources of the job must be in the limits of the queue */ - if ((i = chk_resc_limits(&pjob->ji_wattr[(int)JOB_ATR_resource], pque, EMsg)) != 0) + if ((i = chk_resc_limits(&pjob->ji_wattr[(int)JOB_ATR_total_resources], pque, EMsg)) != 0) { /* FAILURE */