/* * find_resources() identifies the all of the resource candidates for * the job. The set of resources returned could be more than the job * requires. A later call to select_resources() will cull this list * down to the most appropriate set for the job. * * Inputs: resrcs - hash table of all resources * resrc_reqst - the resources the job requests * Returns: nfound - the number of resources found * found_tree - a resource tree containing resources that satisfy the * job's request or NULL if none are found */ int64_t find_resources (flux_t *h, resrc_t *resrc, resrc_reqst_t *resrc_reqst, resrc_tree_t **found_tree) { int64_t nfound = 0; if (!resrc || !resrc_reqst) { flux_log (h, LOG_ERR, "%s: invalid arguments", __FUNCTION__); goto ret; } /* * A start time of zero is used to restrict the search to now * (appropriate for FCFS) and prevent any search into the future. */ if (resrc_reqst_set_starttime (resrc_reqst, 0) || resrc_reqst_set_endtime (resrc_reqst, 0)) goto ret; *found_tree = NULL; nfound = resrc_tree_search (resrc, resrc_reqst, found_tree, true); if (!nfound && *found_tree) { resrc_tree_destroy (*found_tree, false); *found_tree = NULL; } ret: return nfound; }
int resrc_reqst_set_starttime (resrc_reqst_t *resrc_reqst, int64_t time) { if (resrc_reqst) { resrc_reqst->starttime = time; if (resrc_reqst_num_children (resrc_reqst)) { resrc_reqst_t *child = resrc_reqst_list_first (resrc_reqst->children); while (child) { resrc_reqst_set_starttime (child, time); child = resrc_reqst_list_next (resrc_reqst->children); } } return 0; } return -1; }
/* * select_resources() selects from the set of resource candidates the * best resources for the job. * * Inputs: found_tree - tree of resource tree candidates * resrc_reqst - the resources the job requests * selected_parent - parent of the selected resource tree * Returns: a resource tree of however many resources were selected */ resrc_tree_t *select_resources (flux_t *h, resrc_tree_t *found_tree, resrc_reqst_t *resrc_reqst, resrc_tree_t *selected_parent) { resrc_t *resrc; resrc_tree_list_t *children = NULL; resrc_tree_t *child_tree; resrc_tree_t *selected_tree = NULL; if (!resrc_reqst) { flux_log (h, LOG_ERR, "%s: called with empty request", __FUNCTION__); return NULL; } /* * A start time of zero is used to restrict the search to now * (appropriate for FCFS) and prevent any search into the future. */ if (resrc_reqst_set_starttime (resrc_reqst, 0) || resrc_reqst_set_endtime (resrc_reqst, 0)) return NULL; resrc = resrc_tree_resrc (found_tree); if (resrc_match_resource (resrc, resrc_reqst, true)) { if (resrc_reqst_num_children (resrc_reqst)) { if (resrc_tree_num_children (found_tree)) { selected_tree = resrc_tree_new (selected_parent, resrc); if (select_children (h, resrc_tree_children (found_tree), resrc_reqst_children (resrc_reqst), selected_tree)) { resrc_stage_resrc (resrc, resrc_reqst_reqrd_size (resrc_reqst), resrc_reqst_graph_reqs (resrc_reqst)); resrc_reqst_add_found (resrc_reqst, 1); flux_log (h, LOG_DEBUG, "selected %s", resrc_name (resrc)); } else { resrc_tree_destroy (selected_tree, false); } } } else { selected_tree = resrc_tree_new (selected_parent, resrc); resrc_stage_resrc (resrc, resrc_reqst_reqrd_size (resrc_reqst), resrc_reqst_graph_reqs (resrc_reqst)); resrc_reqst_add_found (resrc_reqst, 1); flux_log (h, LOG_DEBUG, "selected %s", resrc_name (resrc)); } } else if (resrc_tree_num_children (found_tree)) { /* * This clause visits the children of the current resource * searching for a match to the resource request. The selected * tree must be extended to include this intermediate * resource. * * This also allows the resource request to be sparsely * defined. E.g., it might only stipulate a node with 4 cores * and omit the intervening socket. */ selected_tree = resrc_tree_new (selected_parent, resrc); children = resrc_tree_children (found_tree); child_tree = resrc_tree_list_first (children); while (child_tree) { if (select_resources (h, child_tree, resrc_reqst, selected_tree) && resrc_reqst_nfound (resrc_reqst) >= resrc_reqst_reqrd_qty (resrc_reqst)) break; child_tree = resrc_tree_list_next (children); } } return selected_tree; }
/* * reserve_resources() reserves resources for the specified job id. * Unlike the FCFS version where selected_tree provides the tree of * resources to reserve, this backfill version will search into the * future to find a time window when all of the required resources are * available, reserve those, and return the pointer to the selected * tree. */ int reserve_resources (flux_t h, resrc_tree_t **selected_tree, int64_t job_id, int64_t starttime, int64_t walltime, resrc_t *resrc, resrc_reqst_t *resrc_reqst) { int rc = -1; int64_t *completion_time = NULL; int64_t nfound = 0; int64_t prev_completion_time = -1; resrc_tree_t *found_tree = NULL; if (reservation_depth > 0 && (curr_reservation_depth >= reservation_depth)) { goto ret; } else if (!resrc || !resrc_reqst) { flux_log (h, LOG_ERR, "%s: invalid arguments", __FUNCTION__); goto ret; } if (*selected_tree) { resrc_tree_destroy (*selected_tree, false); *selected_tree = NULL; } zlist_sort (completion_times, compare_int64_ascending); for (completion_time = zlist_first (completion_times); completion_time; completion_time = zlist_next (completion_times)) { /* Purge past times from consideration */ if (*completion_time < starttime) { zlist_remove (completion_times, completion_time); continue; } /* Don't test the same time multiple times */ if (prev_completion_time == *completion_time) continue; resrc_reqst_set_starttime (resrc_reqst, *completion_time + 1); resrc_reqst_set_endtime (resrc_reqst, *completion_time + 1 + walltime); flux_log (h, LOG_DEBUG, "Attempting to reserve %"PRId64" nodes for job " "%"PRId64" at time %"PRId64"", resrc_reqst_reqrd_qty (resrc_reqst), job_id, *completion_time + 1); nfound = resrc_tree_search (resrc, resrc_reqst, &found_tree, true); if (nfound >= resrc_reqst_reqrd_qty (resrc_reqst)) { *selected_tree = select_resources (h, found_tree, resrc_reqst, NULL); resrc_tree_destroy (found_tree, false); if (*selected_tree) { rc = resrc_tree_reserve (*selected_tree, job_id, *completion_time + 1, *completion_time + 1 + walltime); if (rc) { resrc_tree_destroy (*selected_tree, false); *selected_tree = NULL; } else { curr_reservation_depth++; flux_log (h, LOG_DEBUG, "Reserved %"PRId64" nodes for job " "%"PRId64" from %"PRId64" to %"PRId64"", resrc_reqst_reqrd_qty (resrc_reqst), job_id, *completion_time + 1, *completion_time + 1 + walltime); } break; } } prev_completion_time = *completion_time; } ret: return rc; }