diff --git a/NEWS b/NEWS index 77732b35107d1e7ec9b0d42bcc4af409b26817d3..db172b0b1ccafac77fda8b190090bba31b24adc8 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,8 @@ documents those changes that are of interest to users and admins. -- For task/affinity, force jobs to use a particular task binding by setting the TaskPluginParam configuration parameter rather than slurmd's SLURM_ENFORCED_CPU_BIND environment variable. + -- Enable full preemption of jobs by partition with select/cons_res + (cons_res_preempt.patch from Chris Holmes, HP). * Changes in SLURM 1.4.0-pre3 ============================= diff --git a/doc/html/selectplugins.shtml b/doc/html/selectplugins.shtml index 239f57ce8abaeba893bbd16191a9e8648854e283..aa1952b4ac25808decc742108c7f144f8f736be6 100644 --- a/doc/html/selectplugins.shtml +++ b/doc/html/selectplugins.shtml @@ -291,11 +291,14 @@ to the node for which information is requested.</p> <p style="margin-left:.2in"><b>Returns</b>: SLURM_SUCCESS if successful. On failure, the plugin should return SLURM_ERROR.</p> -<p class="commandline">int select_p_get_info_from_plugin(enum select_data_info info, void *data);</p> +<p class="commandline">int select_p_get_info_from_plugin(enum select_data_info info, +struct node_record *node_ptr, void *data);</p> <p style="margin-left:.2in"><b>Description</b>: Get plugin-specific information.</p> <p style="margin-left:.2in"><b>Arguments</b>:<br> <span class="commandline"> info</span> (input) identifies the type of data to be updated.<br> +<span class="commandline"> job_ptr</span> (input) pointer to +the job related to the query (if applicable; may be NULL).<br> <span class="commandline"> data</span> (output) the requested data.</p> <p style="margin-left:.2in"><b>Returns</b>: SLURM_SUCCESS if successful. On failure, the plugin should return SLURM_ERROR.</p> diff --git a/src/common/node_select.c b/src/common/node_select.c index 60a18685471fbf9be8bd417e704a0f6b9ab6e319..c8964aa00ff6ad17062821c87dbfc91c0a8606ef 100644 --- a/src/common/node_select.c +++ b/src/common/node_select.c @@ -98,6 +98,7 @@ typedef struct slurm_select_ops { int (*update_sub_node) (update_part_msg_t *part_desc_ptr); int (*get_info_from_plugin)(enum select_data_info cr_info, + struct job_record *job_ptr, void *data); int (*update_node_state) (int index, uint16_t state); int (*alter_node_cnt) (enum select_node_cnt type, @@ -448,12 +449,14 @@ extern int select_g_update_sub_node (update_part_msg_t *part_desc_ptr) * IN/OUT data - the data to get from node record */ extern int select_g_get_info_from_plugin (enum select_data_info cr_info, + struct job_record *job_ptr, void *data) { if (slurm_select_init() < 0) return SLURM_ERROR; - return (*(g_select_context->ops.get_info_from_plugin))(cr_info, data); + return (*(g_select_context->ops.get_info_from_plugin))(cr_info, job_ptr, + data); } /* diff --git a/src/common/node_select.h b/src/common/node_select.h index 6d60e982f18fa5cc30c3ea16af49ac54787e20d8..ce54a05b503cc8e2bc6bb1413f98526bcc751204 100644 --- a/src/common/node_select.h +++ b/src/common/node_select.h @@ -127,9 +127,11 @@ extern int select_g_update_sub_node (update_part_msg_t *part_desc_ptr); * IN node_pts - current node record * IN cr_info - type of data to get from the node record * (see enum select_data_info) + * IN job_ptr - pointer to the job that's related to this query (may be NULL) * IN/OUT data - the data to get from node record */ extern int select_g_get_info_from_plugin (enum select_data_info cr_info, + struct job_record *job_ptr, void *data); /* diff --git a/src/plugins/sched/gang/gang.c b/src/plugins/sched/gang/gang.c index c357719ff9062509aca54c5aef01366aa5feb061..446cd4f7c6fa8c1014d4962f334d53c8e5dbaa22 100644 --- a/src/plugins/sched/gang/gang.c +++ b/src/plugins/sched/gang/gang.c @@ -868,14 +868,14 @@ _remove_job_from_part(uint32_t job_id, struct gs_part *p_ptr) if (!job_id || !p_ptr) return; - debug3("sched/gang: _remove_job_from_part: removing job %u from %s", - job_id, p_ptr->part_name); /* find the job in the job_list */ i = _find_job_index(p_ptr, job_id); if (i < 0) /* job not found */ return; + debug3("sched/gang: _remove_job_from_part: removing job %u from %s", + job_id, p_ptr->part_name); j_ptr = p_ptr->job_list[i]; /* remove any shadow first */ @@ -918,7 +918,6 @@ _add_job_to_part(struct gs_part *p_ptr, struct job_record *job_ptr) debug3("sched/gang: _add_job_to_part: adding job %u to %s", job_ptr->job_id, p_ptr->part_name); - _print_jobs(p_ptr); /* take care of any memory needs */ if (!p_ptr->job_list) { @@ -962,7 +961,7 @@ _add_job_to_part(struct gs_part *p_ptr, struct job_record *job_ptr) /* determine the immediate fate of this job (run or suspend) */ if (_job_fits_in_active_row(job_ptr, p_ptr)) { - debug3("sched/gang: _add_job_to_part: adding job %u to active row", + debug3("sched/gang: _add_job_to_part: job %u remains running", job_ptr->job_id); _add_job_to_active(job_ptr, p_ptr); /* note that this job is a "filler" for this row */ @@ -1380,7 +1379,6 @@ _cycle_job_list(struct gs_part *p_ptr) struct gs_job *j_ptr; debug3("sched/gang: entering _cycle_job_list"); - _print_jobs(p_ptr); /* re-prioritize the job_list and set all row_states to GS_NO_ACTIVE */ for (i = 0; i < p_ptr->num_jobs; i++) { while (p_ptr->job_list[i]->row_state == GS_ACTIVE) { @@ -1397,7 +1395,6 @@ _cycle_job_list(struct gs_part *p_ptr) } debug3("sched/gang: _cycle_job_list reordered job list:"); - _print_jobs(p_ptr); /* Rebuild the active row. */ _build_active_row(p_ptr); debug3("sched/gang: _cycle_job_list new active job list:"); diff --git a/src/plugins/sched/wiki/hostlist.c b/src/plugins/sched/wiki/hostlist.c index 1f9b10ab234ac323ea3c6272a285b12959d8c552..2eb25e9d8a70a5986a0dc5455b4b328d50046f09 100644 --- a/src/plugins/sched/wiki/hostlist.c +++ b/src/plugins/sched/wiki/hostlist.c @@ -82,7 +82,7 @@ extern char * moab2slurm_task_list(char *moab_tasklist, int *task_cnt) static uint32_t cr_test = 0, cr_enabled = 0; if (cr_test == 0) { - select_g_get_info_from_plugin(SELECT_CR_PLUGIN, + select_g_get_info_from_plugin(SELECT_CR_PLUGIN, NULL, &cr_enabled); cr_test = 1; } diff --git a/src/plugins/sched/wiki/start_job.c b/src/plugins/sched/wiki/start_job.c index a327fc8ffe08841cab13f219a9ad6a77e68d64b5..284c8fd66f4fa295ceee782c72795a643a5b7842 100644 --- a/src/plugins/sched/wiki/start_job.c +++ b/src/plugins/sched/wiki/start_job.c @@ -147,7 +147,7 @@ static int _start_job(uint32_t jobid, int task_cnt, char *hostlist, static uint32_t cr_test = 0, cr_enabled = 0; if (cr_test == 0) { - select_g_get_info_from_plugin(SELECT_CR_PLUGIN, + select_g_get_info_from_plugin(SELECT_CR_PLUGIN, NULL, &cr_enabled); cr_test = 1; } diff --git a/src/plugins/sched/wiki2/get_jobs.c b/src/plugins/sched/wiki2/get_jobs.c index 709b572ff4ca1807c75d4e570d498e3cbe97bd79..fa816239f1ef0f1177a2124f214af78b4c1e1d2d 100644 --- a/src/plugins/sched/wiki2/get_jobs.c +++ b/src/plugins/sched/wiki2/get_jobs.c @@ -124,7 +124,7 @@ extern int get_jobs(char *cmd_ptr, int *err_code, char **err_msg) int job_rec_cnt = 0, buf_size = 0; if (cr_test == 0) { - select_g_get_info_from_plugin(SELECT_CR_PLUGIN, + select_g_get_info_from_plugin(SELECT_CR_PLUGIN, NULL, &cr_enabled); cr_test = 1; } diff --git a/src/plugins/sched/wiki2/hostlist.c b/src/plugins/sched/wiki2/hostlist.c index 9c3a95d4ca3c30c0edd4a49ebbc906b869053734..12b0d0bae1a256ae7c68ea7c4a334ed1d1557840 100644 --- a/src/plugins/sched/wiki2/hostlist.c +++ b/src/plugins/sched/wiki2/hostlist.c @@ -82,7 +82,7 @@ extern char * moab2slurm_task_list(char *moab_tasklist, int *task_cnt) static uint32_t cr_test = 0, cr_enabled = 0; if (cr_test == 0) { - select_g_get_info_from_plugin(SELECT_CR_PLUGIN, + select_g_get_info_from_plugin(SELECT_CR_PLUGIN, NULL, &cr_enabled); cr_test = 1; } diff --git a/src/plugins/sched/wiki2/start_job.c b/src/plugins/sched/wiki2/start_job.c index 7c2adf70b682b207989946c428ea248efba6d14a..7a4c12db838b2b836f8eaac3bf85cf2d1ce1efe8 100644 --- a/src/plugins/sched/wiki2/start_job.c +++ b/src/plugins/sched/wiki2/start_job.c @@ -190,7 +190,7 @@ static int _start_job(uint32_t jobid, int task_cnt, char *hostlist, static uint32_t cr_test = 0, cr_enabled = 0; if (cr_test == 0) { - select_g_get_info_from_plugin(SELECT_CR_PLUGIN, + select_g_get_info_from_plugin(SELECT_CR_PLUGIN, NULL, &cr_enabled); cr_test = 1; } diff --git a/src/plugins/select/bluegene/plugin/select_bluegene.c b/src/plugins/select/bluegene/plugin/select_bluegene.c index fe06a828c2ed799fc8a66d55c5731029b9b428eb..b9a7a898a84952462110107955cd0f72a5080b51 100644 --- a/src/plugins/select/bluegene/plugin/select_bluegene.c +++ b/src/plugins/select/bluegene/plugin/select_bluegene.c @@ -1111,6 +1111,7 @@ end_it: } extern int select_p_get_info_from_plugin (enum select_data_info info, + struct job_record *job_ptr, void *data) { return SLURM_SUCCESS; diff --git a/src/plugins/select/cons_res/job_test.c b/src/plugins/select/cons_res/job_test.c index 5392363841e7109470415e54a1543759b8c9ad3c..d17337a47409ef8a5abc51ac5ecbdcb6ff7bdedd 100644 --- a/src/plugins/select/cons_res/job_test.c +++ b/src/plugins/select/cons_res/job_test.c @@ -105,12 +105,6 @@ #include "select_cons_res.h" -/* The following variables are used to test for preemption, which - * requires a change to the resource selection process */ -static bool sched_gang_test = false; -static bool sched_gang = false; - - /* _allocate_sockets - Given the job requirements, determine which sockets * from the given node can be allocated (if any) to this * job. Returns the number of cpus that can be used by @@ -695,8 +689,7 @@ static int _verify_node_state(struct part_res_record *cr_part_ptr, struct node_use_record *node_usage, enum node_cr_state job_node_req) { - int i; - uint32_t free_mem, min_mem, size; + uint32_t i, free_mem, min_mem, size; min_mem = job_ptr->details->job_min_memory & (~MEM_PER_CPU); size = bit_size(bitmap); @@ -718,30 +711,21 @@ static int _verify_node_state(struct part_res_record *cr_part_ptr, } } - /* sched/gang preemption test */ - if (!sched_gang_test) { - char *sched_type = slurm_get_sched_type(); - if (strcmp(sched_type, "sched/gang") == 0) - sched_gang = true; - xfree(sched_type); - sched_gang_test = true; - } - /* if sched/gang is configured, then preemption has been - * enabled and we cannot rule out nodes just because - * Shared=NO (NODE_CR_ONE_ROW) or Shared=EXCLUSIVE - * (NODE_CR_RESERVED) */ - if (sched_gang) + /* if priority_selection (sched/gang) has been configured, + * then we cannot rule out nodes just because Shared=NO + * (NODE_CR_ONE_ROW) or Shared=EXCLUSIVE(NODE_CR_RESERVED) + */ + if (cr_priority_selection_enabled()) continue; /* exclusive node check */ - if (node_usage[i].node_state == NODE_CR_RESERVED) { + if (node_usage[i].node_state >= NODE_CR_RESERVED) { debug3("cons_res: _vns: node %s in exclusive use", select_node_record[i].node_ptr->name); goto clear_bit; /* non-resource-sharing node check */ - } else if (node_usage[i].node_state == - NODE_CR_ONE_ROW) { + } else if (node_usage[i].node_state >= NODE_CR_ONE_ROW) { if ((job_node_req == NODE_CR_RESERVED) || (job_node_req == NODE_CR_AVAILABLE)) { debug3("cons_res: _vns: node %s non-sharing", @@ -776,7 +760,7 @@ static int _verify_node_state(struct part_res_record *cr_part_ptr, } continue; /* node is usable, test next node */ - clear_bit: /* This node is not usable by this job */ +clear_bit: /* This node is not usable by this job */ bit_clear(bitmap, i); if (job_ptr->details->req_node_bitmap && bit_test(job_ptr->details->req_node_bitmap, i)) @@ -1169,7 +1153,7 @@ static int _choose_nodes(struct job_record *job_ptr, bitstr_t *node_map, req_nodes, cr_node_cnt, cpu_cnt, freq, size); if (ec == SLURM_SUCCESS) { - bit_free(origmap); + FREE_NULL_BITMAP(origmap); return ec; } @@ -1209,11 +1193,11 @@ static int _choose_nodes(struct job_record *job_ptr, bitstr_t *node_map, ec = _eval_nodes(job_ptr, node_map, min_nodes, max_nodes, req_nodes, cr_node_cnt, cpu_cnt, freq, size); if (ec == SLURM_SUCCESS) { - bit_free(origmap); + FREE_NULL_BITMAP(origmap); return ec; } } - bit_free(origmap); + FREE_NULL_BITMAP(origmap); return ec; } @@ -1368,9 +1352,9 @@ extern int cr_job_test(struct job_record *job_ptr, bitstr_t *bitmap, node_usage, cr_type); if (cpu_count == NULL) { /* job cannot fit */ - bit_free(orig_map); - bit_free(free_cores); - bit_free(avail_cores); + FREE_NULL_BITMAP(orig_map); + FREE_NULL_BITMAP(free_cores); + FREE_NULL_BITMAP(avail_cores); if (save_mem) job_ptr->details->job_min_memory = save_mem; debug3("cons_res: cr_job_test: test 0 fail: " @@ -1379,9 +1363,9 @@ extern int cr_job_test(struct job_record *job_ptr, bitstr_t *bitmap, } else if (test_only) { /* FIXME: does "test_only" expect struct_job_res * to be filled out? For now we assume NO */ - bit_free(orig_map); - bit_free(free_cores); - bit_free(avail_cores); + FREE_NULL_BITMAP(orig_map); + FREE_NULL_BITMAP(free_cores); + FREE_NULL_BITMAP(avail_cores); xfree(cpu_count); if (save_mem) job_ptr->details->job_min_memory = save_mem; @@ -1556,7 +1540,10 @@ extern int cr_job_test(struct job_record *job_ptr, bitstr_t *bitmap, } cr_sort_part_rows(jp_ptr); - for (i = 0; i < jp_ptr->num_rows; i++) { + c = jp_ptr->num_rows; + if (job_node_req != NODE_CR_AVAILABLE) + c = 1; + for (i = 0; i < c; i++) { if (!jp_ptr->row[i].row_bitmap) break; bit_copybits(bitmap, orig_map); @@ -1574,7 +1561,7 @@ extern int cr_job_test(struct job_record *job_ptr, bitstr_t *bitmap, debug3("cons_res: cr_job_test: test 4 fail - row %i", i); } - if (i < jp_ptr->num_rows && !jp_ptr->row[i].row_bitmap) { + if (i < c && !jp_ptr->row[i].row_bitmap) { /* we've found an empty row, so use it */ bit_copybits(bitmap, orig_map); bit_copybits(free_cores, avail_cores); @@ -1609,13 +1596,12 @@ alloc_job: * create the select_job_res struct, * distribute the job on the bits, and exit */ - bit_free(orig_map); - bit_free(avail_cores); - if (tmpcore) - bit_free(tmpcore); + FREE_NULL_BITMAP(orig_map); + FREE_NULL_BITMAP(avail_cores); + FREE_NULL_BITMAP(tmpcore); if (!cpu_count) { /* we were sent here to cleanup and exit */ - bit_free(free_cores); + FREE_NULL_BITMAP(free_cores); debug3("cons_res: exiting cr_job_test with no allocation"); return SLURM_ERROR; } @@ -1648,7 +1634,7 @@ alloc_job: } } if ((error_code != SLURM_SUCCESS) || (mode != SELECT_MODE_RUN_NOW)) { - bit_free(free_cores); + FREE_NULL_BITMAP(free_cores); return error_code; } @@ -1671,7 +1657,7 @@ alloc_job: select_fast_schedule); if (error_code != SLURM_SUCCESS) { free_select_job_res(&job_res); - bit_free(free_cores); + FREE_NULL_BITMAP(free_cores); return error_code; } @@ -1719,7 +1705,7 @@ alloc_job: debug3("cons_res: cr_job_test: job %u nprocs %u cbits %u/%u nbits %u", job_ptr->job_id, job_res->nprocs, bit_set_count(free_cores), bit_set_count(job_res->core_bitmap), job_res->nhosts); - bit_free(free_cores); + FREE_NULL_BITMAP(free_cores); /* distribute the tasks and clear any unused cores */ job_ptr->select_job = job_res; diff --git a/src/plugins/select/cons_res/select_cons_res.c b/src/plugins/select/cons_res/select_cons_res.c index 42b94f0d997fdb9d51b57fa61eca0b3450cec725..bcfd47b3fc8381ecbc8bb196f9da37328e251ea2 100644 --- a/src/plugins/select/cons_res/select_cons_res.c +++ b/src/plugins/select/cons_res/select_cons_res.c @@ -151,12 +151,13 @@ struct part_res_record *select_part_record = NULL; struct node_res_record *select_node_record = NULL; struct node_use_record *select_node_usage = NULL; static int select_node_cnt = 0; - +static bool cr_priority_test = false; +static bool cr_priority_selection = false; /* Procedure Declarations */ static int _will_run_test(struct job_record *job_ptr, bitstr_t *bitmap, uint32_t min_nodes, uint32_t max_nodes, - uint32_t req_nodes, enum node_cr_state job_node_req); + uint32_t req_nodes, uint16_t job_node_req); #if (CR_DEBUG) @@ -219,6 +220,19 @@ static void _dump_state(struct part_res_record *p_ptr) } #endif +/* */ +extern bool cr_priority_selection_enabled() +{ + if (!cr_priority_test) { + char *sched_type = slurm_get_sched_type(); + if (strcmp(sched_type, "sched/gang") == 0) + cr_priority_selection = true; + xfree(sched_type); + cr_priority_selection = true; + } + return cr_priority_selection; + +} #define CR_NUM_CORE_ARRAY_INCREMENT 8 @@ -374,6 +388,21 @@ static struct node_use_record *_dup_node_usage(struct node_use_record *orig_ptr) } +/* delete the given row data */ +static void _destroy_row_data(struct part_row_data *row, uint16_t num_rows) { + uint16_t i; + for (i = 0; i < num_rows; i++) { + FREE_NULL_BITMAP(row[i].row_bitmap); + if (row[i].job_list) { + uint32_t j; + for (j = 0; j < row[i].num_jobs; j++) + row[i].job_list[j] = NULL; + xfree(row[i].job_list); + } + } + xfree(row); +} + /* delete the given list of partition data */ static void _destroy_part_data(struct part_res_record *this_ptr) { @@ -383,22 +412,7 @@ static void _destroy_part_data(struct part_res_record *this_ptr) xfree(tmp->name); tmp->name = NULL; if (tmp->row) { - int i; - for (i = 0; i < tmp->num_rows; i++) { - if (tmp->row[i].row_bitmap) { - bit_free(tmp->row[i].row_bitmap); - tmp->row[i].row_bitmap = NULL; - } - if (tmp->row[i].job_list) { - int j; - for (j = 0; j < tmp->row[i].num_jobs; - j++) - tmp->row[i].job_list[j] = NULL; - xfree(tmp->row[i].job_list); - tmp->row[i].job_list = NULL; - } - } - xfree(tmp->row); + _destroy_row_data(tmp->row, tmp->num_rows); tmp->row = NULL; } xfree(tmp); @@ -420,6 +434,7 @@ static void _create_part_data() num_parts = list_count(part_list); if (!num_parts) return; + info("cons_res: preparing for %d partitions", num_parts); select_part_record = xmalloc(sizeof(struct part_res_record)); this_ptr = select_part_record; @@ -458,28 +473,6 @@ static int _cr_job_list_sort(void *x, void *y) } -/* Find a partition record from the global array based - * upon a pointer to the slurmctld part_record */ -struct part_res_record *_get_cr_part_ptr(struct part_record *part_ptr) -{ - struct part_res_record *p_ptr; - - if (part_ptr == NULL) - return NULL; - - if (!select_part_record) - _create_part_data(); - - for (p_ptr = select_part_record; p_ptr; p_ptr = p_ptr->next) { - if (strcmp(p_ptr->name, part_ptr->name) == 0) - return p_ptr; - } - error("cons_res: could not find partition %s", part_ptr->name); - - return NULL; -} - - /* delete the given select_node_record and select_node_usage arrays */ static void _destroy_node_data(struct node_use_record *node_usage, struct node_res_record *node_data) @@ -490,10 +483,11 @@ static void _destroy_node_data(struct node_use_record *node_usage, static void _add_job_to_row(struct select_job_res *job, - struct part_row_data *r_ptr, int first_job) + struct part_row_data *r_ptr) { /* add the job to the row_bitmap */ - if (r_ptr->row_bitmap && first_job) { + if (r_ptr->row_bitmap && r_ptr->num_jobs == 0) { + /* if no jobs, clear the existing row_bitmap first */ uint32_t size = bit_size(r_ptr->row_bitmap); bit_nclear(r_ptr->row_bitmap, 0, size-1); } @@ -572,16 +566,18 @@ extern void cr_sort_part_rows(struct part_res_record *p_ptr) /* - * _build_row_bitmaps: Optimize the jobs into the least number of rows, + * _build_row_bitmaps: A job has been removed from the given partition, + * so the row_bitmap(s) need to be reconstructed. + * Optimize the jobs into the least number of rows, * and make the lower rows as dense as possible. - * + * * IN/OUT: p_ptr - the partition that has jobs to be optimized */ static void _build_row_bitmaps(struct part_res_record *p_ptr) { uint32_t i, j, num_jobs, size; int x, *jstart; - struct part_row_data *this_row; + struct part_row_data *this_row, *orig_row; struct select_job_res **tmpjobs, *job; if (!p_ptr->row) @@ -604,10 +600,9 @@ static void _build_row_bitmaps(struct part_res_record *p_ptr) tmpjobs[i] = this_row->job_list[i]; this_row->job_list[i] = NULL; } - this_row->num_jobs = 0; - _add_job_to_row(tmpjobs[0], this_row, 1); - for (i = 1; i < num_jobs; i++) { - _add_job_to_row(tmpjobs[i], this_row, 0); + this_row->num_jobs = 0; /* this resets the row_bitmap */ + for (i = 0; i < num_jobs; i++) { + _add_job_to_row(tmpjobs[i], this_row); } xfree(tmpjobs); return; @@ -620,9 +615,23 @@ static void _build_row_bitmaps(struct part_res_record *p_ptr) num_jobs += p_ptr->row[i].num_jobs; } } + if (num_jobs == 0) + return; + +#if (CR_DEBUG) + info("DEBUG: _build_row_bitmaps (before):"); + _dump_part(p_ptr); +#endif debug3("cons_res: build_row_bitmaps reshuffling %u jobs", num_jobs); + + /* make a copy, in case we cannot do better than this */ + orig_row = _dup_row_data(p_ptr->row, p_ptr->num_rows); + if (orig_row == NULL) + return; - /* Question: should we try to avoid disrupting rows that are full? */ + /* get row_bitmap size from first row (we can safely assume that the + * first row_bitmap exists because there exists at least one job. */ + size = bit_size(p_ptr->row[0].row_bitmap); /* create a master job list and clear out ALL row data */ tmpjobs = xmalloc(num_jobs * sizeof(struct select_job_res *)); @@ -639,27 +648,10 @@ static void _build_row_bitmaps(struct part_res_record *p_ptr) } p_ptr->row[i].num_jobs = 0; if (p_ptr->row[i].row_bitmap) { - size = bit_size(p_ptr->row[i].row_bitmap); bit_nclear(p_ptr->row[i].row_bitmap, 0, size-1); } } -#if (CR_DEBUG) - for (i = 0; i < x; i++) { - char cstr[64], nstr[64]; - if (tmpjobs[i]->core_bitmap) - bit_fmt(cstr, 63, tmpjobs[i]->core_bitmap); - else - sprintf(cstr, "[no core_bitmap]"); - if (tmpjobs[i]->node_bitmap) - bit_fmt(nstr, 63, tmpjobs[i]->node_bitmap); - else - sprintf(nstr, "[no node_bitmap]"); - info ("DEBUG: jstart %d job nb %s cb %s", jstart[i], nstr, - cstr); - } -#endif - /* VERY difficult: Optimal placement of jobs in the matrix * - how to order jobs to be added to the matrix? * - "by size" does not guarantee optimal placement @@ -671,7 +663,8 @@ static void _build_row_bitmaps(struct part_res_record *p_ptr) */ for (i = 0; i < num_jobs; i++) { for (j = i+1; j < num_jobs; j++) { - if (jstart[j] < jstart[i]) { + if (jstart[j] < jstart[i] || (jstart[j] == jstart[i] && + tmpjobs[j]->nprocs > tmpjobs[i]->nprocs)) { x = jstart[i]; jstart[i] = jstart[j]; jstart[j] = x; @@ -682,19 +675,28 @@ static void _build_row_bitmaps(struct part_res_record *p_ptr) } } +#if (CR_DEBUG) + for (i = 0; i < num_jobs; i++) { + char cstr[64], nstr[64]; + if (tmpjobs[i]->core_bitmap) + bit_fmt(cstr, (sizeof(cstr)-1) , tmpjobs[i]->core_bitmap); + else + sprintf(cstr, "[no core_bitmap]"); + if (tmpjobs[i]->node_bitmap) + bit_fmt(nstr, (sizeof(nstr)-1), tmpjobs[i]->node_bitmap); + else + sprintf(nstr, "[no node_bitmap]"); + info ("DEBUG: jstart %d job nb %s cb %s", jstart[i], nstr, + cstr); + } +#endif + /* add jobs to the rows */ for (j = 0; j < num_jobs; j++) { for (i = 0; i < p_ptr->num_rows; i++) { - if (p_ptr->row[i].num_jobs == 0) { - /* add the job to this row */ - _add_job_to_row(tmpjobs[j], &(p_ptr->row[i]),1); - tmpjobs[j] = NULL; - break; - } - /* ELSE: test if the job can fit in this row */ if (_can_job_fit_in_row(tmpjobs[j], &(p_ptr->row[i]))) { /* job fits in row, so add it */ - _add_job_to_row(tmpjobs[j], &(p_ptr->row[i]),0); + _add_job_to_row(tmpjobs[j], &(p_ptr->row[i])); tmpjobs[j] = NULL; break; } @@ -705,20 +707,44 @@ static void _build_row_bitmaps(struct part_res_record *p_ptr) /* test for dangling jobs */ for (j = 0; j < num_jobs; j++) { - if (tmpjobs[j]) { - error("cons_res: ERROR: job overflow " - "during build_row_bitmap"); - /* just merge this job into the last row for now */ - _add_job_to_row(tmpjobs[j], - &(p_ptr->row[p_ptr->num_rows-1]),0); + if (tmpjobs[j]) + break; + } + if (j < num_jobs) { + /* we found a dangling job, which means our packing + * algorithm couldn't improve apon the existing layout. + * Thus, we'll restore the original layout here */ + debug3("cons_res: build_row_bitmap: dangling job found"); +#if (CR_DEBUG) + info("DEBUG: _build_row_bitmaps (post-algorithm):"); + _dump_part(p_ptr); +#endif + _destroy_row_data(p_ptr->row, p_ptr->num_rows); + p_ptr->row = orig_row; + orig_row = NULL; + + /* still need to rebuild row_bitmaps */ + for (i = 0; i < p_ptr->num_rows; i++) { + if (p_ptr->row[i].row_bitmap) + bit_nclear(p_ptr->row[i].row_bitmap, 0, size-1); + if (p_ptr->row[i].num_jobs == 0) + continue; + for (j = 0; j < p_ptr->row[i].num_jobs; j++) { + add_select_job_to_row(p_ptr->row[i].job_list[j], + &(p_ptr->row[i].row_bitmap), + cr_node_num_cores, + cr_num_core_count); + } } } #if (CR_DEBUG) - info("DEBUG: _build_row_bitmaps:"); + info("DEBUG: _build_row_bitmaps (after):"); _dump_part(p_ptr); #endif + if (orig_row) + _destroy_row_data(orig_row, p_ptr->num_rows); xfree(tmpjobs); xfree(jstart); return; @@ -801,48 +827,43 @@ static int _add_job_to_res(struct job_record *job_ptr, int action) /* add cores */ if (action != 1) { - p_ptr = _get_cr_part_ptr(job_ptr->part_ptr); - if (!p_ptr) + for (p_ptr = select_part_record; p_ptr; p_ptr = p_ptr->next) { + if (strcmp(p_ptr->name, job_ptr->part_ptr->name) == 0) + break; + } + if (!p_ptr) { + error("cons_res: could not find cr partition %s", + job_ptr->part_ptr->name); return SLURM_ERROR; - + } if (!p_ptr->row) { p_ptr->row = xmalloc(p_ptr->num_rows * sizeof(struct part_row_data)); - debug3("cons_res: adding job %u to part %s row 0", - job_ptr->job_id, p_ptr->name); - _add_job_to_row(job, &(p_ptr->row[0]), 1); - goto node_st; } /* find a row to add this job */ for (i = 0; i < p_ptr->num_rows; i++) { - if (p_ptr->row[i].num_jobs == 0) { - debug3("cons_res: adding job %u to part %s row %u", - job_ptr->job_id, p_ptr->name, i); - _add_job_to_row(job, &(p_ptr->row[i]), 1); - break; - } - if (_can_job_fit_in_row(job, &(p_ptr->row[i]))) { - debug3("cons_res: adding job %u to part %s row %u", - job_ptr->job_id, p_ptr->name, i); - _add_job_to_row(job, &(p_ptr->row[i]), 0); - break; - } + if (!_can_job_fit_in_row(job, &(p_ptr->row[i]))) + continue; + debug3("cons_res: adding job %u to part %s row %u", + job_ptr->job_id, p_ptr->name, i); + _add_job_to_row(job, &(p_ptr->row[i])); + break; } if (i >= p_ptr->num_rows) { /* ERROR: could not find a row for this job */ error("cons_res: ERROR: job overflow: " "could not find row for job"); /* just add the job to the last row for now */ - _add_job_to_row(job, &(p_ptr->row[p_ptr->num_rows-1]), 0); + _add_job_to_row(job, &(p_ptr->row[p_ptr->num_rows-1])); } /* update the node state */ node_st: for (i = 0; i < select_node_cnt; i++) { if (bit_test(job->node_bitmap, i)) - select_node_usage[i].node_state = job->node_req; + select_node_usage[i].node_state +=job->node_req; } #if (CR_DEBUG) - info("DEBUG: _add_job_to_res:"); + info("DEBUG: _add_job_to_res (after):"); _dump_part(p_ptr); #endif } @@ -851,32 +872,6 @@ node_st: for (i = 0; i < select_node_cnt; i++) { } -/* Helper function for _rm_job_from_res: - * - return 1 if node is available for general use, else return 0. - * if 'free' then the node can be NODE_CR_AVAILABLE. Otherwise, - * there's an existing job that may make the node either - * NODE_CR_RESERVED or NODE_CR_ONE_ROW. - */ -static int _is_node_free(struct part_res_record *p_ptr, uint32_t node_i) -{ - uint32_t c, cpu_begin = cr_get_coremap_offset(node_i); - uint32_t i, cpu_end = cr_get_coremap_offset(node_i+1); - - for (; p_ptr; p_ptr = p_ptr->next) { - if (!p_ptr->row) - continue; - for (i = 0; i < p_ptr->num_rows; i++) { - if (!p_ptr->row[i].row_bitmap) - continue; - for (c = cpu_begin; c < cpu_end; c++) { - if (bit_test(p_ptr->row[i].row_bitmap, c)) - return 0; - } - } - } - return 1; -} - /* deallocate resources to the given job * - subtract 'struct select_job_res' resources from 'struct part_res_record' * - subtract job's memory requirements from 'struct node_res_record' @@ -977,17 +972,18 @@ static int _rm_job_from_res(struct part_res_record *part_record_ptr, for (n = 0; n < select_node_cnt; n++) { if (bit_test(job->node_bitmap, n) == 0) continue; - if (node_usage[n].node_state == - NODE_CR_AVAILABLE) - continue; - if (_is_node_free(select_part_record, n)) - node_usage[n].node_state = - NODE_CR_AVAILABLE; + if (select_node_usage[n].node_state >= + job->node_req) + select_node_usage[n].node_state -= + job->node_req; + else { + error("cons_res:_rm_job_from_res: " + "node_state mis-count"); + select_node_usage[n].node_state = + NODE_CR_AVAILABLE; + } } } -#if (CR_DEBUG) - _dump_part(p_ptr); -#endif } return SLURM_SUCCESS; @@ -1036,40 +1032,10 @@ extern int fini(void) * node selection API. */ - -extern int select_p_state_save(char *dir_name) -{ - /* nothing to save */ - return SLURM_SUCCESS; -} - - -/* This is Part 2 of a 4-part procedure which can be found in - * src/slurmctld/read_config.c. See select_p_node_init for the - * whole story. - */ -extern int select_p_state_restore(char *dir_name) -{ - /* nothing to restore */ - return SLURM_SUCCESS; -} - -/* This is Part 3 of a 4-part procedure which can be found in - * src/slurmctld/read_config.c. See select_p_node_init for the - * whole story. - */ -extern int select_p_job_init(List job_list) -{ - /* nothing to initialize for jobs */ - return SLURM_SUCCESS; -} - - /* This is Part 1 of a 4-part procedure which can be found in * src/slurmctld/read_config.c. The whole story goes like this: * - * Step 1: select_g_node_init : initializes the 'select_node_record' - * global array + * Step 1: select_g_node_init : initializes the global node arrays * Step 2: select_g_state_restore : NO-OP - nothing to restore * Step 3: select_g_job_init : NO-OP - nothing to initialize * Step 4: select_g_update_nodeinfo : called from reset_job_bitmaps() with @@ -1093,13 +1059,13 @@ extern int select_p_node_init(struct node_record *node_ptr, int node_cnt) } /* initial global core data structures */ + select_fast_schedule = slurm_get_fast_schedule(); _init_global_core_data(node_ptr, node_cnt); _destroy_node_data(select_node_usage, select_node_record); select_node_cnt = node_cnt; select_node_record = xmalloc(node_cnt * sizeof(struct node_res_record)); select_node_usage = xmalloc(node_cnt * sizeof(struct node_use_record)); - select_fast_schedule = slurm_get_fast_schedule(); for (i = 0; i < select_node_cnt; i++) { select_node_record[i].node_ptr = &node_ptr[i]; @@ -1122,15 +1088,43 @@ extern int select_p_node_init(struct node_record *node_ptr, int node_cnt) } select_node_usage[i].node_state = NODE_CR_AVAILABLE; } + _create_part_data(); return SLURM_SUCCESS; } +extern int select_p_state_save(char *dir_name) +{ + /* nothing to save */ + return SLURM_SUCCESS; +} + +/* This is Part 2 of a 4-part procedure which can be found in + * src/slurmctld/read_config.c. See select_p_node_init for the + * whole story. + */ +extern int select_p_state_restore(char *dir_name) +{ + /* nothing to restore */ + return SLURM_SUCCESS; +} + +/* This is Part 3 of a 4-part procedure which can be found in + * src/slurmctld/read_config.c. See select_p_node_init for the + * whole story. + */ +extern int select_p_job_init(List job_list) +{ + /* nothing to initialize for jobs */ + return SLURM_SUCCESS; +} + extern int select_p_block_init(List part_list) { return SLURM_SUCCESS; } + static struct multi_core_data * _create_default_mc(void) { struct multi_core_data *mc_ptr; @@ -1153,7 +1147,7 @@ static struct multi_core_data * _create_default_mc(void) * - can the job run on shared nodes? (NODE_CR_ONE_ROW) * - can the job run on overcommitted resources? (NODE_CR_AVAILABLE) */ -static enum node_cr_state _get_job_node_req(struct job_record *job_ptr) +static uint16_t _get_job_node_req(struct job_record *job_ptr) { int max_share = job_ptr->part_ptr->max_share; @@ -1167,7 +1161,7 @@ static enum node_cr_state _get_job_node_req(struct job_record *job_ptr) if (job_ptr->details->shared == 0) /* user has requested exclusive nodes */ return NODE_CR_RESERVED; - if ((max_share > 1) && (job_ptr->details->shared == 2)) + if ((max_share > 1) && (job_ptr->details->shared == 1)) /* part allows sharing, and * the user has requested it */ return NODE_CR_AVAILABLE; @@ -1205,7 +1199,7 @@ extern int select_p_job_test(struct job_record *job_ptr, bitstr_t * bitmap, uint32_t req_nodes, int mode) { int rc; - enum node_cr_state job_node_req; + uint16_t job_node_req; xassert(bitmap); @@ -1216,7 +1210,7 @@ extern int select_p_job_test(struct job_record *job_ptr, bitstr_t * bitmap, job_ptr->details->mc_ptr = _create_default_mc(); job_node_req = _get_job_node_req(job_ptr); - debug3("cons_res: select_p_job_test: job %d node_req %d, mode %d", + debug3("cons_res: select_p_job_test: job %u node_req %u, mode %d", job_ptr->job_id, job_node_req, mode); debug3("cons_res: select_p_job_test: min_n %u max_n %u req_n %u nb %u", min_nodes, max_nodes, req_nodes, bit_set_count(bitmap)); @@ -1269,7 +1263,7 @@ extern int select_p_job_list_test(List req_list) * each one. */ static int _will_run_test(struct job_record *job_ptr, bitstr_t *bitmap, uint32_t min_nodes, uint32_t max_nodes, - uint32_t req_nodes, enum node_cr_state job_node_req) + uint32_t req_nodes, uint16_t job_node_req) { struct part_res_record *future_part; struct node_use_record *future_usage; @@ -1478,64 +1472,91 @@ extern int select_p_update_sub_node (update_part_msg_t *part_desc_ptr) /* Helper function for _synchronize_bitmap(). Check * if the given node has at least one available CPU */ -static uint16_t _is_node_avail(uint32_t node_i) +static uint16_t _is_node_avail(struct part_res_record *p_ptr, uint32_t node_i) { - struct part_res_record *p_ptr; uint32_t i, r, cpu_begin, cpu_end; - - /* check the node state */ - if (select_node_usage[node_i].node_state == NODE_CR_RESERVED) - return (uint16_t) 0; cpu_begin = cr_get_coremap_offset(node_i); cpu_end = cr_get_coremap_offset(node_i+1); - if (select_node_usage[node_i].node_state == NODE_CR_ONE_ROW) { - /* check the core_bitmaps in "single-row" partitions */ - for (p_ptr = select_part_record; p_ptr; p_ptr = p_ptr->next) { - if (p_ptr->num_rows > 1) + + if (select_node_usage[node_i].node_state >= NODE_CR_RESERVED) { + if (!cr_priority_selection_enabled()) + return (uint16_t) 0; + /* cr_priority_selection has been enabled: + * check to see if the existing job that reserved + * this node is in a partition with a priority that + * is equal-to or greater-than this partition. If it + * is, then this node is NOT available. Otherwise + * this node is available. + */ + struct part_res_record *s_ptr; + for (s_ptr = select_part_record; s_ptr; s_ptr = s_ptr->next) { + if (s_ptr->priority < p_ptr->priority) + continue; + if (!s_ptr->row || !s_ptr->row[0].row_bitmap) continue; - if (!p_ptr->row || !p_ptr->row[0].row_bitmap) - return (uint16_t) 1; for (i = cpu_begin; i < cpu_end; i++) { - if (!bit_test(p_ptr->row[0].row_bitmap, i)) - return (uint16_t) 1; + if (bit_test(s_ptr->row[0].row_bitmap, i)) + return (uint16_t) 0; } } + return (uint16_t) 1; + } + if (select_node_usage[node_i].node_state >= NODE_CR_ONE_ROW) { + /* An existing job has requested that it's CPUs + * NOT be shared, but any other CPUs on the same + * node can be used by other jobs with the same + * CPU restriction. + * Check whether or not there are free CPUs on this + * node in the given partition. + */ + if (!p_ptr->row || !p_ptr->row[0].row_bitmap) + return (uint16_t) 1; + for (i = cpu_begin; i < cpu_end; i++) { + if (!bit_test(p_ptr->row[0].row_bitmap, i)) + return (uint16_t) 1; + } } else { - /* check the core_bitmaps in all partitions */ - for (p_ptr = select_part_record; p_ptr; p_ptr = p_ptr->next) { - if (!p_ptr->row) + /* check the core_bitmap in all rows */ + if (!p_ptr->row) + return (uint16_t) 1; + for (r = 0; r < p_ptr->num_rows; r++) { + if (!p_ptr->row[r].row_bitmap) return (uint16_t) 1; - for (r = 0; r < p_ptr->num_rows; r++) { - if (!p_ptr->row[r].row_bitmap) + for (i = cpu_begin; i < cpu_end; i++) { + if (!bit_test(p_ptr->row[r].row_bitmap, i)) return (uint16_t) 1; - for (i = cpu_begin; i < cpu_end; i++) { - if (!bit_test(p_ptr->row[r].row_bitmap, - i)) - return (uint16_t) 1; - } } } - } return (uint16_t) 0; } /* Worker function for select_p_get_info_from_plugin() */ -static int _synchronize_bitmaps(bitstr_t ** partially_idle_bitmap) +static int _synchronize_bitmaps(struct job_record *job_ptr, + bitstr_t ** partially_idle_bitmap) { int size, i, idlecpus = bit_set_count(avail_node_bitmap); + struct part_res_record *p_ptr; size = bit_size(avail_node_bitmap); bitstr_t *bitmap = bit_alloc(size); if (bitmap == NULL) return SLURM_ERROR; - debug3("cons_res: synch_bm: size avail %d (%d set) size idle %d ", - size, idlecpus, bit_size(idle_node_bitmap)); + debug3("cons_res: synch_bm: avail %d of %d set, idle %d of %d set", + idlecpus, size, bit_set_count(idle_node_bitmap), size); + + if (!job_ptr) + fatal("cons_res: error: don't know what job I'm sync'ing"); + + for (p_ptr = select_part_record; p_ptr; p_ptr = p_ptr->next) { + if (job_ptr && strcmp(p_ptr->name,job_ptr->part_ptr->name) == 0) + break; + } for (i = 0; i < select_node_cnt; i++) { - if (bit_test(avail_node_bitmap, i) != 1) + if (bit_test(avail_node_bitmap, i) == 0) continue; if (bit_test(idle_node_bitmap, i) == 1) { @@ -1543,11 +1564,16 @@ static int _synchronize_bitmaps(bitstr_t ** partially_idle_bitmap) continue; } - if(_is_node_avail(i)) + if(!p_ptr || _is_node_avail(p_ptr, i)) bit_set(bitmap, i); } idlecpus = bit_set_count(bitmap); - debug3("cons_res: synch found %d partially idle nodes", idlecpus); + if (p_ptr) + debug3("cons_res: found %d partially idle nodes in part %s", + idlecpus, p_ptr->name); + else + debug3("cons_res: found %d partially idle nodes", + idlecpus); *partially_idle_bitmap = bitmap; return SLURM_SUCCESS; @@ -1555,7 +1581,7 @@ static int _synchronize_bitmaps(bitstr_t ** partially_idle_bitmap) extern int select_p_get_info_from_plugin(enum select_data_info info, - void *data) + struct job_record *job_ptr, void *data) { int rc = SLURM_SUCCESS; @@ -1565,7 +1591,7 @@ extern int select_p_get_info_from_plugin(enum select_data_info info, bitstr_t **bitmap = (bitstr_t **) data; bitstr_t *tmp_bitmap = NULL; - rc = _synchronize_bitmaps(&tmp_bitmap); + rc = _synchronize_bitmaps(job_ptr, &tmp_bitmap); if (rc != SLURM_SUCCESS) { FREE_NULL_BITMAP(tmp_bitmap); return rc; @@ -1608,17 +1634,11 @@ extern int select_p_reconfigure(void) int rc = SLURM_SUCCESS; info("cons_res: select_p_reconfigure"); - select_fast_schedule = slurm_get_fast_schedule(); - /* Refresh the select_node_record global array in case nodes - * have been added, removed, or modified. - */ + /* Rebuild the global data structures */ rc = select_p_node_init(node_record_table_ptr, node_record_count); if (rc != SLURM_SUCCESS) return rc; - - /* recreate the partition data structures (delete existing data) */ - _create_part_data(); /* reload job data */ job_iterator = list_iterator_create(job_list); diff --git a/src/plugins/select/cons_res/select_cons_res.h b/src/plugins/select/cons_res/select_cons_res.h index 573b452306463cf1892d4fc5f1acfcbf9e41e19b..beac2f9e00b80a4e87a8d46604276032d482266a 100644 --- a/src/plugins/select/cons_res/select_cons_res.h +++ b/src/plugins/select/cons_res/select_cons_res.h @@ -66,12 +66,16 @@ * * NOTES: * - If node is in use by Shared=NO part, some CPUs/memory may be available - * - Caution with NODE_CR_AVAILABLE: a Sharing partition could be full!! + * - Caution with NODE_CR_AVAILABLE: a Sharing partition could be full. + * + * - these values are staggered so that they can be incremented as multiple + * jobs are allocated to each node. This is needed to be able to support + * preemption, which can override these protections. */ enum node_cr_state { - NODE_CR_RESERVED = 0, /* node is in use by Shared=EXCLUSIVE part */ - NODE_CR_ONE_ROW = 1, /* node is in use by Shared=NO part */ - NODE_CR_AVAILABLE = 2 /* The node may be IDLE or IN USE (shared) */ + NODE_CR_AVAILABLE = 0, /* The node may be IDLE or IN USE (shared) */ + NODE_CR_ONE_ROW = 1, /* node is in use by Shared=NO part */ + NODE_CR_RESERVED = 100, /* node is in use by Shared=EXCLUSIVE part */ }; /* a partition's per-row CPU allocation data */ @@ -104,7 +108,7 @@ struct node_res_record { /* per-node resource usage record */ struct node_use_record { - enum node_cr_state node_state; /* see node_cr_state comments */ + uint16_t node_state; /* see node_cr_state comments */ uint32_t alloc_memory; /* real memory reserved by already * scheduled jobs */ }; @@ -119,5 +123,6 @@ extern struct node_use_record *select_node_usage; extern void cr_sort_part_rows(struct part_res_record *p_ptr); extern uint32_t cr_get_coremap_offset(uint32_t node_index); extern uint32_t cr_get_node_num_cores(uint32_t node_index); +extern bool cr_priority_selection_enabled(); #endif /* !_CONS_RES_H */ diff --git a/src/plugins/select/linear/select_linear.c b/src/plugins/select/linear/select_linear.c index d750863452dd2eb5fa831d6eaf99ad6271456d60..8554418156a73704f7a208b1eb5026a7046ac87e 100644 --- a/src/plugins/select/linear/select_linear.c +++ b/src/plugins/select/linear/select_linear.c @@ -1114,6 +1114,7 @@ extern int select_p_update_sub_node (update_part_msg_t *part_desc_ptr) } extern int select_p_get_info_from_plugin (enum select_data_info info, + struct job_record *job_ptr, void *data) { return SLURM_SUCCESS; diff --git a/src/slurmctld/node_scheduler.c b/src/slurmctld/node_scheduler.c index 427a139c8b45171daa6370e4b30f0d9e6efbc7e2..c474a4a53ca099ba6d9afea16a1468abf393b5e0 100644 --- a/src/slurmctld/node_scheduler.c +++ b/src/slurmctld/node_scheduler.c @@ -289,15 +289,15 @@ _resolve_shared_status(uint16_t user_flag, uint16_t part_max_share, return 0; /* sharing if part=FORCE */ if (part_max_share & SHARED_FORCE) - return 1; + return 2; if (cons_res_flag) { /* sharing unless user requested exclusive */ if (user_flag == 0) return 0; if (user_flag == 1) - return 2; - return 1; + return 1; + return 2; } else { /* no sharing if part=NO */ if (part_max_share == 1) @@ -557,7 +557,7 @@ _pick_best_nodes(struct node_set *node_set_ptr, int node_set_size, if (cr_enabled == NO_VAL) { cr_enabled = 0; /* select/linear and bluegene are no-ops */ error_code = select_g_get_info_from_plugin (SELECT_CR_PLUGIN, - &cr_enabled); + NULL, &cr_enabled); if (error_code != SLURM_SUCCESS) { cr_enabled = NO_VAL; return error_code; @@ -585,7 +585,7 @@ _pick_best_nodes(struct node_set *node_set_ptr, int node_set_size, /* Update partially_idle_node_bitmap to reflect the * idle and partially idle nodes */ error_code = select_g_get_info_from_plugin ( - SELECT_BITMAP, + SELECT_BITMAP, job_ptr, &partially_idle_node_bitmap); if (error_code != SLURM_SUCCESS) { FREE_NULL_BITMAP(partially_idle_node_bitmap);