static int find_all_sockets_cores (resrc_api_ctx_t *rsapi, resrc_t *node, int *nsocks, int *ncs) { json_t *reqobj= NULL; resrc_reqst_t *req = NULL; resrc_tree_t *st = NULL; resrc_tree_t *ct = NULL; reqobj = Jnew (); create_req4allsocks (reqobj); req = resrc_reqst_from_json (rsapi, reqobj, NULL); *nsocks = resrc_tree_search (rsapi, node, req, &st, false); resrc_reqst_destroy (rsapi, req); resrc_tree_destroy (rsapi, st, false, false); Jput (reqobj); reqobj = Jnew (); create_req4allcores (reqobj); req = resrc_reqst_from_json (rsapi, reqobj, NULL); *ncs = resrc_tree_search (rsapi, node, req, &ct, false); resrc_reqst_destroy (rsapi, req); resrc_tree_destroy (rsapi, ct, false, false); Jput (reqobj); return (*nsocks > 0 && *ncs > 0) ? 0 : -1; }
/* * 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; }
/* returns the number of resource or resource composites found */ int64_t resrc_tree_search (resrc_t *resrc_in, resrc_reqst_t *resrc_reqst, resrc_tree_t **found_tree, bool available) { int64_t nfound = 0; resrc_tree_list_t *children = NULL; resrc_tree_t *child_tree; resrc_tree_t *new_tree = NULL; if (!resrc_in || !found_tree || !resrc_reqst) { goto ret; } if (resrc_match_resource (resrc_in, resrc_reqst, available)) { if (resrc_reqst_num_children (resrc_reqst)) { if (resrc_tree_num_children (resrc_phys_tree (resrc_in))) { new_tree = resrc_tree_new (*found_tree, resrc_in); children = resrc_tree_children (resrc_phys_tree (resrc_in)); if (match_children (children, resrc_reqst->children, new_tree, available)) { nfound = 1; resrc_reqst->nfound++; } else { resrc_tree_destroy (new_tree, false); } } } else { (void) resrc_tree_new (*found_tree, resrc_in); nfound = 1; resrc_reqst->nfound++; } } else if (resrc_tree_num_children (resrc_phys_tree (resrc_in))) { /* * This clause visits the children of the current resource * searching for a match to the resource request. The found * 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. */ if (*found_tree) new_tree = resrc_tree_new (*found_tree, resrc_in); else { new_tree = resrc_tree_new (NULL, resrc_in); *found_tree = new_tree; } children = resrc_tree_children (resrc_phys_tree (resrc_in)); child_tree = resrc_tree_list_first (children); while (child_tree) { nfound += resrc_tree_search (resrc_tree_resrc (child_tree), resrc_reqst, &new_tree, available); child_tree = resrc_tree_list_next (children); } } ret: return nfound; }
static int find_all_nodes (resrc_api_ctx_t *rsapi, resrc_t *root, resrc_tree_t **ot) { json_t *reqobj = NULL; int64_t size = 0; resrc_reqst_t *req = NULL; reqobj = Jnew (); create_req4allnodes (reqobj); req = resrc_reqst_from_json (rsapi, reqobj, NULL); size = resrc_tree_search (rsapi, root, req, ot, false); resrc_reqst_destroy (rsapi, req); Jput (reqobj); return (size > 0) ? 0 : -1; }
/* * cycles through all of the resource children and returns the number of * requested resources found */ static int64_t match_child (resrc_tree_list_t *r_trees, resrc_reqst_t *resrc_reqst, resrc_tree_t *found_parent, bool available) { int64_t nfound = 0; resrc_t *resrc = NULL; resrc_tree_t *resrc_tree = NULL; resrc_tree = resrc_tree_list_first (r_trees); while (resrc_tree) { resrc = resrc_tree_resrc (resrc_tree); nfound += resrc_tree_search (resrc, resrc_reqst, &found_parent, available); resrc_tree = resrc_tree_list_next (r_trees); } return nfound; }
/* * 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; } *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; }
static int test_a_resrc (resrc_t *resrc, bool rdl) { int found = 0; int rc = 0; int64_t nowtime = epochtime (); JSON o = NULL; JSON req_res = NULL; resrc_reqst_t *resrc_reqst = NULL; resrc_tree_t *deserialized_tree = NULL; resrc_tree_t *found_tree = NULL; resrc_tree_t *resrc_tree = NULL; resrc_tree_t *selected_tree = NULL; resrc_tree = resrc_phys_tree (resrc); ok ((resrc_tree != NULL), "resource tree valid"); if (!resrc_tree) goto ret; if (verbose) { printf ("Listing resource tree\n"); resrc_tree_print (resrc_tree); printf ("End of resource tree\n"); } /* * Build a resource composite to search for. Two variants are * constructed depending on whether the loaded resources came * from the sample RDL file or from the hwloc. The hwloc request * does not span multiple nodes or contain the localid property. */ req_res = Jnew (); if (rdl) { JSON bandwidth = Jnew (); JSON child_core = Jnew (); JSON child_sock = Jnew (); JSON graph_array = Jnew_ar (); JSON ja = Jnew_ar (); JSON jpropo = Jnew (); /* json property object */ JSON memory = Jnew (); JSON power = Jnew (); /* JSON jtago = Jnew (); /\* json tag object *\/ */ /* Jadd_bool (jtago, "maytag", true); */ /* Jadd_bool (jtago, "yourtag", true); */ Jadd_str (memory, "type", "memory"); Jadd_int (memory, "req_qty", 1); Jadd_int (memory, "size", 100); json_object_array_add (ja, memory); Jadd_str (child_core, "type", "core"); Jadd_int (child_core, "req_qty", 6); Jadd_bool (child_core, "exclusive", true); Jadd_int (jpropo, "localid", 1); json_object_object_add (child_core, "properties", jpropo); json_object_array_add (ja, child_core); Jadd_str (child_sock, "type", "socket"); Jadd_int (child_sock, "req_qty", 2); json_object_object_add (child_sock, "req_children", ja); Jadd_str (bandwidth, "type", "bandwidth"); Jadd_int (bandwidth, "size", 100); json_object_array_add (graph_array, bandwidth); Jadd_str (power, "type", "power"); Jadd_int (power, "size", 10); json_object_array_add (graph_array, power); Jadd_str (req_res, "type", "node"); Jadd_int (req_res, "req_qty", 2); Jadd_int64 (req_res, "starttime", nowtime); /* json_object_object_add (req_res, "tags", jtago); */ json_object_object_add (req_res, "req_child", child_sock); json_object_object_add (req_res, "graphs", graph_array); } else { Jadd_str (req_res, "type", "core"); Jadd_int (req_res, "req_qty", 2); Jadd_bool (req_res, "exclusive", true); } resrc_reqst = resrc_reqst_from_json (req_res, NULL); Jput (req_res); ok ((resrc_reqst != NULL), "resource request valid"); if (!resrc_reqst) goto ret; if (verbose) { printf ("Listing resource request tree\n"); resrc_reqst_print (resrc_reqst); printf ("End of resource request tree\n"); } init_time (); found = resrc_tree_search (resrc, resrc_reqst, &found_tree, true); ok (found, "found %d requested resources in %lf", found, ((double)get_time ())/1000000); if (!found) goto ret; if (verbose) { printf ("Listing found tree\n"); resrc_tree_print (found_tree); printf ("End of found tree\n"); } o = Jnew (); init_time (); rc = resrc_tree_serialize (o, found_tree); ok (!rc, "found resource serialization took: %lf", ((double)get_time ())/1000000); if (verbose) { printf ("The found resources serialized: %s\n", Jtostr (o)); } deserialized_tree = resrc_tree_deserialize (o, NULL); if (verbose) { printf ("Listing deserialized tree\n"); resrc_tree_print (deserialized_tree); printf ("End of deserialized tree\n"); } Jput (o); init_time (); /* * Exercise time-based allocations for the rdl case and * now-based allocations for the hwloc case */ selected_tree = test_select_resources (found_tree, NULL, 1); if (rdl) rc = resrc_tree_allocate (selected_tree, 1, nowtime, nowtime + 3600); else rc = resrc_tree_allocate (selected_tree, 1, 0, 0); ok (!rc, "successfully allocated resources for job 1"); resrc_tree_destroy (selected_tree, false); resrc_tree_unstage_resources (found_tree); selected_tree = test_select_resources (found_tree, NULL, 2); if (rdl) rc = resrc_tree_allocate (selected_tree, 2, nowtime, nowtime + 3600); else rc = resrc_tree_allocate (selected_tree, 2, 0, 0); ok (!rc, "successfully allocated resources for job 2"); resrc_tree_destroy (selected_tree, false); resrc_tree_unstage_resources (found_tree); selected_tree = test_select_resources (found_tree, NULL, 3); if (rdl) rc = resrc_tree_allocate (selected_tree, 3, nowtime, nowtime + 3600); else rc = resrc_tree_allocate (selected_tree, 3, 0, 0); ok (!rc, "successfully allocated resources for job 3"); resrc_tree_destroy (selected_tree, false); resrc_tree_unstage_resources (found_tree); selected_tree = test_select_resources (found_tree, NULL, 4); if (rdl) rc = resrc_tree_reserve (selected_tree, 4, nowtime, nowtime + 3600); else rc = resrc_tree_reserve (selected_tree, 4, 0, 0); ok (!rc, "successfully reserved resources for job 4"); resrc_tree_destroy (selected_tree, false); resrc_tree_unstage_resources (found_tree); printf (" allocate and reserve took: %lf\n", ((double)get_time ())/1000000); if (verbose) { printf ("Allocated and reserved resources\n"); resrc_tree_print (resrc_tree); } init_time (); rc = resrc_tree_release (found_tree, 1); ok (!rc, "resource release of job 1 took: %lf", ((double)get_time ())/1000000); if (verbose) { printf ("Same resources without job 1\n"); resrc_tree_print (resrc_tree); } init_time (); resrc_reqst_destroy (resrc_reqst); resrc_tree_destroy (deserialized_tree, true); resrc_tree_destroy (found_tree, false); printf (" destroy took: %lf\n", ((double)get_time ())/1000000); ret: return rc; }
/* * 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; }