def extract_scheduled_jobs(result, resource_set, job_security_time, now): jids = [] jobs_lst = [] jobs = {} prev_jid = 0 roids = [] rid2jid = {} global job # (job, a, b, c) = req[0] if result: for x in result: j, moldable_id, start_time, walltime, r_id = x if j.id != prev_jid: if prev_jid != 0: job.res_set = unordered_ids2itvs(roids) jobs_lst.append(job) jids.append(job.id) jobs[job.id] = job roids = [] prev_jid = j.id job = j job.start_time = start_time job.walltime = walltime + job_security_time job.moldable_id = moldable_id job.ts = False job.ph = NO_PLACEHOLDER job.assign = False job.find = False if job.suspended == "YES": job.walltime += get_job_suspended_sum_duration(job.id, now) roid = resource_set.rid_i2o[r_id] roids.append(roid) rid2jid[roid] = j.id job.res_set = unordered_ids2itvs(roids) if job.state == "Suspended": job.res_set = sub_intervals( job.res_set, resource_set.suspendable_roid_itvs) jobs_lst.append(job) jids.append(job.id) jobs[job.id] = job get_jobs_types(jids, jobs) return (jobs, jobs_lst, jids, rid2jid)
def get_waiting_reservations_already_scheduled(resource_set, job_security_time): result = db.query(Job, GanttJobsPrediction.start_time, GanttJobsResource.resource_id, MoldableJobDescription.walltime, MoldableJobDescription.id)\ .filter((Job.state == 'Waiting') | (Job.state == 'toAckReservation'))\ .filter(Job.reservation == 'Scheduled')\ .filter(Job.id == MoldableJobDescription.job_id)\ .filter(GanttJobsPrediction.moldable_id == MoldableJobDescription.id)\ .filter(GanttJobsResource.moldable_id == MoldableJobDescription.id)\ .order_by(Job.id).all() first_job = True jobs = {} jids = [] prev_jid = 0 roids = [] global job if result: for x in result: j, start_time, resource_id, walltime, moldable_id = x if j.id != prev_jid: if first_job: first_job = False else: job.res_set = unordered_ids2itvs(roids) jids.append(job.id) jobs[job.id] = job roids = [] prev_jid = j.id job = j job.start_time = start_time job.walltime = walltime + job_security_time roids.append(resource_set.rid_i2o[resource_id]) job.res_set = unordered_ids2itvs(roids) jids.append(job.id) jobs[job.id] = job get_jobs_types(jids, jobs) return (jids, jobs)
def save_assigns_simu(self, jobs, resource_set): print("save_assigns_simu") for jid, job in iteritems(jobs): jres_set = job.res_set print("job.res_set before", jid, job.res_set) r_ids = [resource_set.rid_o2i[roid] for roid in itvs2ids(jres_set)] job.res_set = unordered_ids2itvs(r_ids) self.assigned_jobs = jobs
def get_jobs_in_multiple_states(states, resource_set): result = db.query(Job, AssignedResource.moldable_id, AssignedResource.resource_id)\ .filter(Job.state.in_(tuple(states)))\ .filter(Job.assigned_moldable_job == AssignedResource.moldable_id)\ .order_by(Job.id).all() first_job = True jobs = {} prev_jid = 0 roids = [] global job if result: for x in result: j, moldable_id, resource_id = x if j.id != prev_jid: if first_job: first_job = False else: job.res_set = unordered_ids2itvs(roids) jobs[job.id] = job roids = [] prev_jid = j.id job = j job.moldable_id = moldable_id roids.append(resource_set.rid_i2o[resource_id]) job.res_set = unordered_ids2itvs(roids) jobs[job.id] = job return jobs
def save_assigns_simu_and_default(self, jobs, resource_set): print("save_assigns_simu_and_default........................") # assigned_jobs = {} for jid, job in iteritems(jobs): sid = self.db_jid2s_jid[jid] jobsimu = self.jobs[sid] jres_set = job.res_set r_ids = [resource_set.rid_o2i[roid] for roid in itvs2ids(jres_set)] jobsimu.res_set = unordered_ids2itvs(r_ids) print("save assign jid, sid, res_set: ", jid, " ", sid, " ", jobsimu.res_set) jobsimu.start_time = job.start_time jobsimu.walltime = job.walltime # assigned_jobs[sid] = jobsimu # self.assigned_jobs = assigned_jobs return save_assigns(jobs, resource_set)
def get_data_jobs(jobs, jids, resource_set, job_security_time, besteffort_duration=0): """ oarsub -q test \ -l "nodes=1+{network_address='node3'}/nodes=1/resource_id=1" \ sleep job_id: 12 [(16L, 7200, [ ( [(u'network_address', 1)], [(0, 7)] ), ( [(u'network_address', 1), (u'resource_id', 1)], [(4, 7)] ) ])] """ result = db.query(Job.id, Job.properties, MoldableJobDescription.id, MoldableJobDescription.walltime, JobResourceGroup.id, JobResourceGroup.property, JobResourceDescription.group_id, JobResourceDescription.resource_type, JobResourceDescription.value)\ .filter(MoldableJobDescription.index == 'CURRENT')\ .filter(JobResourceGroup.index == 'CURRENT')\ .filter(JobResourceDescription.index == 'CURRENT')\ .filter(Job.id.in_(tuple(jids)))\ .filter(Job.id == MoldableJobDescription.job_id)\ .filter(JobResourceGroup.moldable_id == MoldableJobDescription.id)\ .filter(JobResourceDescription.group_id == JobResourceGroup.id)\ .order_by(MoldableJobDescription.id, JobResourceGroup.id, JobResourceDescription.order)\ .all() # .join(MoldableJobDescription)\ # .join(JobResourceGroup)\ # .join(JobResourceDescription)\ cache_constraints = {} first_job = True prev_j_id = 0 prev_mld_id = 0 prev_jrg_id = 0 prev_res_jrg_id = 0 mld_res_rqts = [] jrg = [] jr_descriptions = [] res_constraints = [] prev_mld_id_walltime = 0 global job for x in result: # remove res_order (j_id, j_properties, moldable_id, mld_id_walltime, jrg_id, jrg_grp_property, res_jrg_id, res_type, res_value) = x # # new job # if j_id != prev_j_id: if first_job: first_job = False else: jrg.append((jr_descriptions, res_constraints)) mld_res_rqts.append((prev_mld_id, prev_mld_id_walltime, jrg)) job.mld_res_rqts = mld_res_rqts mld_res_rqts = [] jrg = [] jr_descriptions = [] job.key_cache = {} job.deps = [] job.ts = False job.ph = NO_PLACEHOLDER job.assign = False job.find = False prev_mld_id = moldable_id prev_j_id = j_id job = jobs[j_id] if besteffort_duration: prev_mld_id_walltime = besteffort_duration else: prev_mld_id_walltime = mld_id_walltime + job_security_time else: # # new moldable_id # if moldable_id != prev_mld_id: if jrg != []: jrg.append((jr_descriptions, res_constraints)) mld_res_rqts.append( (prev_mld_id, prev_mld_id_walltime, jrg)) prev_mld_id = moldable_id jrg = [] jr_descriptions = [] if besteffort_duration: prev_mld_id_walltime = besteffort_duration else: prev_mld_id_walltime = mld_id_walltime + job_security_time # # new job resources groupe_id # if jrg_id != prev_jrg_id: prev_jrg_id = jrg_id if jr_descriptions != []: jrg.append((jr_descriptions, res_constraints)) jr_descriptions = [] # # new set job descriptions # if res_jrg_id != prev_res_jrg_id: prev_res_jrg_id = res_jrg_id jr_descriptions = [(res_type, res_value)] # # determine resource constraints # if (j_properties == "" and (jrg_grp_property == "" or jrg_grp_property == "type = 'default'")): res_constraints = deepcopy(resource_set.roid_itvs) else: if j_properties == "" or jrg_grp_property == "": and_sql = "" else: and_sql = " AND " sql_constraints = j_properties + and_sql + jrg_grp_property if sql_constraints in cache_constraints: res_constraints = cache_constraints[sql_constraints] else: request_constraints = db.query( Resource.id).filter(text(sql_constraints)).all() roids = [resource_set.rid_i2o[int(y[0])] for y in request_constraints] res_constraints = unordered_ids2itvs(roids) cache_constraints[sql_constraints] = res_constraints else: # add next res_type , res_value jr_descriptions.append((res_type, res_value)) # complete the last job jrg.append((jr_descriptions, res_constraints)) mld_res_rqts.append((prev_mld_id, prev_mld_id_walltime, jrg)) job.mld_res_rqts = mld_res_rqts job.key_cache = {} job.deps = [] job.ts = False job.ph = NO_PLACEHOLDER job.assign = False job.find = False get_jobs_types(jids, jobs) get_current_jobs_dependencies(jobs) set_jobs_cache_keys(jobs)
def schedule_fifo_cycle(plt, queue="default", hierarchy_use=False): assigned_jobs = {} now = plt.get_time() logger.info("Begin scheduling....now: " + str(now) + ", queue: " + queue) # # Retrieve waiting jobs # waiting_jobs, waiting_jids, nb_waiting_jobs = plt.get_waiting_jobs(queue) if nb_waiting_jobs > 0: logger.info("nb_waiting_jobs:" + str(nb_waiting_jobs)) for jid in waiting_jids: logger.debug("waiting_jid: " + str(jid)) # # Determine Global Resource Intervals # resource_set = plt.resource_set() res_itvs = deepcopy(resource_set.roid_itvs) # # Get additional waiting jobs' data # job_security_time = int(config["SCHEDULER_JOB_SECURITY_TIME"]) plt.get_data_jobs(waiting_jobs, waiting_jids, resource_set, job_security_time) # # Remove resources used by running job # for job in plt.get_scheduled_jobs(resource_set, job_security_time, now): if job.state == "Running": res_itvs = sub_intervals(res_itvs, job.res_itvs) # # Assign resource to jobs # for jid in waiting_jids: job = waiting_jobs[jid] # We consider only one instance of resources request (no support for moldable) (mld_id, walltime, hy_res_rqts) = job.mld_res_rqts[0] if hierarchy_use: # Assign resources which hierarchy support (uncomment) itvs = find_resource_hierarchies_job(res_itvs, hy_res_rqts, resource_set.hierarchy) else: # OR assign resource by considering only resource_id (no hierarchy) # and only one type of resource (hy_level_nbs, constraints) = hy_res_rqts[0] (h_name, nb_asked_res) = hy_level_nbs[0] itvs_avail = intersec(constraints, res_itvs) ids_avail = itvs2ids(itvs_avail) if len(ids_avail) < nb_asked_res: itvs = [] else: itvs = unordered_ids2itvs(ids_avail[:nb_asked_res]) if (itvs != []): job.moldable_id = mld_id job.res_set = itvs assigned_jobs[job.id] = job res_itvs = sub_intervals(res_itvs, itvs) else: logger.debug("Not enough available resources, it's a FIFO scheduler, we stop here.") break # # Save assignement # logger.info("save assignement") plt.save_assigns(assigned_jobs, resource_set) else: logger.info("no waiting jobs")
def __init__(self): # prepare resource order/indirection stuff order_by_clause = config["SCHEDULER_RESOURCE_ORDER"] self.rid_i2o = array("i", [0] * MAX_NB_RESOURCES) self.rid_o2i = array("i", [0] * MAX_NB_RESOURCES) # suspend suspendable_roids = [] if "SCHEDULER_AVAILABLE_SUSPENDED_RESOURCE_TYPE" not in config: config["SCHEDULER_AVAILABLE_SUSPENDED_RESOURCE_TYPE"] = "default" res_suspend_types = ( config["SCHEDULER_AVAILABLE_SUSPENDED_RESOURCE_TYPE"]).split() # prepare hierarchy stuff # "HIERARCHY_LABELS" = "resource_id,network_address" conf_hy_labels = config[ "HIERARCHY_LABELS"] if "HIERARCHY_LABELS" in config else "resource_id,network_address" hy_labels = conf_hy_labels.split(",") hy_labels_w_id = ["id" if v == "resource_id" else v for v in hy_labels] hy_roid = {} for hy_label in hy_labels_w_id: hy_roid[hy_label] = OrderedDict() # available_upto for pseudo job in slot available_upto = {} self.available_upto = {} roids = [] default_rids = [] # retreive resource in order from DB self.resources_db = db.query(Resource).order_by(text(order_by_clause)).all() # fill the different structures for roid, r in enumerate(self.resources_db): if (r.state == "Alive") or (r.state == "Absent"): rid = int(r.id) roids.append(roid) if r.type == 'default': default_rids.append(rid) self.rid_i2o[rid] = roid self.rid_o2i[roid] = rid # fill hy_rid structure for hy_label in hy_labels_w_id: v = getattr(r, hy_label) if v in hy_roid[hy_label]: hy_roid[hy_label][v].append(roid) else: hy_roid[hy_label][v] = [roid] # fill available_upto structure if r.available_upto in available_upto: available_upto[r.available_upto].append(roid) else: available_upto[r.available_upto] = [roid] # fill resource available for suspended job if r.type in res_suspend_types: suspendable_roids.append(roid) # global ordered resources intervals # print roids self.roid_itvs = ordered_ids2itvs(roids) if "id" in hy_roid: hy_roid["resource_id"] = hy_roid["id"] del hy_roid["id"] # create hierarchy self.hierarchy = Hierarchy(hy_rid=hy_roid).hy # transform available_upto for k, v in iteritems(available_upto): self.available_upto[k] = ordered_ids2itvs(v) # self.suspendable_roid_itvs = ordered_ids2itvs(suspendable_roids) default_roids = [self.rid_i2o[i] for i in default_rids] self.default_resource_itvs = unordered_ids2itvs(default_roids) # update global variable default_resource_itvs = self.default_resource_itvs
def test_unordered_ids2itvs(): y = [12, 23, 7, 5, 4, 11, 10, 1, 3] r = [(1, 1), (3, 5), (7, 7), (10, 12), (23, 23)] a = unordered_ids2itvs(y) assert a == r
def estimate_job_nb_resources(resource_request, j_properties): '''returns an array with an estimation of the number of resources that can be used by a job: (resources_available, [(nbresources => int, walltime => int)]) ''' # estimate_job_nb_resources estimated_nb_resources = [] resource_available = False resource_set = ResourceSet() resources_itvs = resource_set.roid_itvs for mld_idx, mld_resource_request in enumerate(resource_request): resource_desc, walltime = mld_resource_request if not walltime: walltime = default_job_walltime result = [] for prop_res in resource_desc: jrg_grp_property = prop_res['property'] resource_value_lst = prop_res['resources'] # # determine resource constraints # if (not j_properties) and (not jrg_grp_property or (jrg_grp_property == "type = 'default'")): constraints = deepcopy(resource_set.roid_itvs) else: if not j_properties or not jrg_grp_property: and_sql = "" else: and_sql = " AND " sql_constraints = j_properties + and_sql + jrg_grp_property try: request_constraints = db.query(Resource.id).filter(text(sql_constraints)).all() except exc.SQLAlchemyError: print_error('Bad resource SQL constraints request:', sql_constraints) print_error('SQLAlchemyError: ', exc) result = [] break roids = [resource_set.rid_i2o[int(y[0])] for y in request_constraints] constraints = unordered_ids2itvs(roids) hy_levels = [] hy_nbs = [] for resource_value in resource_value_lst: res_name = resource_value['resource'] value = resource_value['value'] hy_levels.append(resource_set.hierarchy[res_name]) hy_nbs.append(int(value)) cts_resources_itvs = intersec(constraints, resources_itvs) res_itvs = find_resource_hierarchies_scattered(cts_resources_itvs, hy_levels, hy_nbs) if res_itvs: result.extend(res_itvs) else: result = [] break if result: resource_available = True estimated_nb_res = itvs_size(result) estimated_nb_resources.append((estimated_nb_res, walltime)) print_info('Moldable instance: ', mld_idx, ' Estimated nb resources: ', estimated_nb_res, ' Walltime: ', walltime) if not resource_available: print_error("There are not enough resources for your request") sub_exit(-5) return(resource_available, estimated_nb_resources)