def schedule(self, cpu): """ Schedule main method. """ self.waiting_schedule = False # At the end of the interval: if self.sim.now() >= self.t_f: self.init_interval() # Stop current timers. for job, timer in self.timers.items(): timer.stop() self.timers = {} # Set timers to stop the jobs that will run. for z, proc in enumerate(self.processors): l = self.allocations[z][1] if l and l[0][0] not in self.timers: timer = Timer(self.sim, BF.end_event, (self, z, l[0][0]), l[0][1], cpu=proc, in_ms=False) timer.start() self.timers[l[0][0]] = timer # Schedule the activated tasks on each processor. decisions = [] for z, proc in enumerate(self.processors): l = self.allocations[z][1] if not l[0][0] or l[0][0].is_active(): decisions.append((l[0][0] if l else None, proc)) return decisions
def schedule(self, cpu): if len(self.ready_list) > 0: # Explication sur la key: # En priorité, on met tous les processeurs libres au début. # Ensuite, on trie tout par ordre décroissant de la deadline. # Et on départage en préférant le processeur "cpu". key = lambda x: ( 1 if (not x.running) or (not self.pseudo_job[x]) else 0, self.pseudo_job[x].cmp_key() if x.running and self.pseudo_job[x] else None, 1 if x is cpu else 0 ) cpu_min = max(self.processors, key=key) pjob = min(self.ready_list, key=lambda x: x.cmp_key()) if (cpu_min.running is None or self.pseudo_job[cpu_min] is None or self.pseudo_job[cpu_min].cmp_key() > pjob.cmp_key()): self.ready_list.remove(pjob) if cpu_min.running and self.pseudo_job[cpu_min]: self.ready_list.append(self.pseudo_job[cpu_min]) self.pseudo_job[cpu_min] = pjob timer = Timer( self.sim, EPDF.pseudo_terminate, (self, pjob), pjob.seq * self.quantum - pjob.job.computation_time, cpu=cpu_min, in_ms=True) timer.start() self.timers.append(timer) return (pjob.job, cpu_min) elif self.pseudo_job[cpu] is None: return (None, cpu)
class RR(Scheduler): def init(self): self.ready_list = Queue() self.running_job = None self.quantum = 1 # ms self.timer = Timer(self.sim, RR.reschedule, (self, self.processors[0]), self.quantum, one_shot=False, cpu=self.processors[0]) self.timer.start() def reschedule(self, cpu): if not self.ready_list.empty(): cpu.resched() def on_activate(self, job): self.ready_list.put(job) job.cpu.resched() def on_terminated(self, job): self.running_job = None job.cpu.resched() def schedule(self, cpu): if not self.ready_list.empty(): job = self.ready_list.get() if self.running_job is not None: self.ready_list.put(self.running_job) self.running_job = job else: job = self.running_job return (job, cpu)
def schedule(self, cpu): if len(self.ready_list) > 0: # Explication sur la key: # En priorité, on met tous les processeurs libres au début. # Ensuite, on trie tout par ordre décroissant de la deadline. # Et on départage en préférant le processeur "cpu". key = lambda x: (1 if (not x.running) or (not self.pseudo_job[x]) else 0, self.pseudo_job[x].cmp_key() if x.running and self.pseudo_job[x] else None, 1 if x is cpu else 0) cpu_min = max(self.processors, key=key) pjob = min(self.ready_list, key=lambda x: x.cmp_key()) if (cpu_min.running is None or self.pseudo_job[cpu_min] is None or self.pseudo_job[cpu_min].cmp_key() > pjob.cmp_key()): self.ready_list.remove(pjob) if cpu_min.running and self.pseudo_job[cpu_min]: self.ready_list.append(self.pseudo_job[cpu_min]) self.pseudo_job[cpu_min] = pjob timer = Timer(self.sim, EPDF.pseudo_terminate, (self, pjob), pjob.seq * self.quantum - pjob.job.computation_time, cpu=cpu_min, in_ms=True) timer.start() self.timers.append(timer) return (pjob.job, cpu_min) elif self.pseudo_job[cpu] is None: return (None, cpu)
class MLLF(Scheduler): """Modified Least Laxity First""" def init(self): self.ready_list = [] self.timer = None def compute_laxity(self, cpu): if self.ready_list: for job in self.ready_list: job.laxity = (job.absolute_deadline - job.ret) * \ self.sim.cycles_per_ms - self.sim.now() cpu.resched() def on_activate(self, job): self.ready_list.append(job) self.compute_laxity(job.cpu) def on_terminated(self, job): self.ready_list.remove(job) self.compute_laxity(job.cpu) def schedule(self, cpu): decisions = [] if self.ready_list: # Sort according to the laxity. self.ready_list.sort( key=lambda x: (x.laxity, x.absolute_deadline)) # m : Nombre de processeurs. m = len(self.processors) # Available processors: l = (proc for proc in self.processors if proc.running not in self.ready_list[:m]) if len(self.ready_list) > m: ta = self.ready_list[m - 1] dmin = self.ready_list[m].absolute_deadline * \ self.sim.cycles_per_ms - self.sim.now() if self.timer: self.timer.stop() self.timer = Timer( self.sim, MLLF.compute_laxity, (self, self.processors[0]), dmin - ta.laxity, one_shot=True, cpu=self.processors[0]) self.timer.start() # The first m jobs should be running: for job in self.ready_list[:m]: if not job.is_running(): proc = next(l) decisions.append((job, proc)) return decisions
class EDF_modified(Scheduler): """ An EDF mono-processor scheduler modified to accept migrating jobs. A migrating job has an infinite priority. """ def init(self): self.ready_list = [] self.migrating_job = None def _resched(self): self.processors[0].resched() def on_activate(self, job): self.ready_list.append(job) self._resched() def on_terminated(self, job): if job is self.migrating_job: self.migrating_job = None elif job in self.ready_list: self.ready_list.remove(job) self._resched() def accept_migrating_job(self, i, job, budget): self.migrating_job = job job.task.cpu = self.processors[0] # Set timer for end. self.timer = Timer(self.sim, EDF_modified.end_migrating_job, (self, i), budget, cpu=self.processors[0], in_ms=False) self.timer.start() self._resched() def end_migrating_job(self, i): self.processors[0].resched() if self.migrating_job and i < len( migrating_tasks[self.migrating_job.task]) - 1: ncpu, nbudget = migrating_tasks[self.migrating_job.task][i + 1] sched = map_cpu_sched[ncpu] sched.accept_migrating_job(i + 1, self.migrating_job, nbudget) self.migrating_job = None def schedule(self, cpu): if self.migrating_job: job = self.migrating_job elif self.ready_list: job = min(self.ready_list, key=lambda x: x.absolute_deadline) else: job = None return (job, cpu)
class MLLF(Scheduler): """Modified Least Laxity First""" def init(self): self.ready_list = [] self.timer = None def update(self, cpu): if self.ready_list: cpu.resched() def on_activate(self, job): self.ready_list.append(job) job.cpu.resched() def on_terminated(self, job): self.ready_list.remove(job) self.update(job.cpu) def schedule(self, cpu): decisions = [] if self.ready_list: # Sort according to the laxity. self.ready_list.sort(key=lambda x: (x.laxity, x.absolute_deadline)) # m : Nombre de processeurs. m = len(self.processors) # Available processors: l = (proc for proc in self.processors if proc.running not in self.ready_list[:m]) if len(self.ready_list) > m: ta = self.ready_list[m - 1] dmin = self.ready_list[m].absolute_deadline * \ self.sim.cycles_per_ms - self.sim.now() if self.timer: self.timer.stop() self.timer = Timer(self.sim, MLLF.update, (self, self.processors[0]), dmin - ta.laxity, one_shot=True, cpu=self.processors[0]) self.timer.start() # The first m jobs should be running: for job in self.ready_list[:m]: if not job.is_running(): proc = next(l) decisions.append((job, proc)) return decisions
class EDF_modified(Scheduler): """ An EDF mono-processor scheduler modified to accept migrating jobs. A migrating job has an infinite priority. """ def init(self): self.ready_list = [] self.migrating_job = None def _resched(self): self.processors[0].resched() def on_activate(self, job): self.ready_list.append(job) self._resched() def on_terminated(self, job): if job is self.migrating_job: self.migrating_job = None elif job in self.ready_list: self.ready_list.remove(job) self._resched() def accept_migrating_job(self, i, job, budget): self.migrating_job = job job.task.cpu = self.processors[0] # Set timer for end. self.timer = Timer(self.sim, EDF_modified.end_migrating_job, (self, i), budget, cpu=self.processors[0], in_ms=False) self.timer.start() self._resched() def end_migrating_job(self, i): self.processors[0].resched() if self.migrating_job and i < len(migrating_tasks[self.migrating_job.task]) - 1: ncpu, nbudget = migrating_tasks[self.migrating_job.task][i + 1] sched = map_cpu_sched[ncpu] sched.accept_migrating_job(i + 1, self.migrating_job, nbudget) self.migrating_job = None def schedule(self, cpu): if self.migrating_job: job = self.migrating_job elif self.ready_list: job = min(self.ready_list, key=lambda x: x.absolute_deadline) else: job = None return (job, cpu)
def on_activate(self, job): # First pseudo-activation pseudo_job = EPDF.PseudoJob(job, 1) self.pseudo_activate(pseudo_job) # Set next pseudo activations : while pseudo_job.seq * self.quantum < job.wcet: pseudo_job = EPDF.PseudoJob(job, pseudo_job.seq + 1) timer = Timer(self.sim, EPDF.pseudo_activate, (self, pseudo_job), pseudo_job.release_date * self.quantum - self.sim.now() / self.sim.cycles_per_ms + job.activation_date, cpu=job.cpu, in_ms=True) timer.start() self.timers.append(timer)
class LLF(Scheduler): """Least Laxity First""" def init(self): self.ready_list = [] self.timer = Timer(self.sim, LLF.update, (self, self.processors[0]), 1, one_shot=False, cpu=self.processors[0], overhead=.001) self.timer.start() def update(self, cpu): if self.ready_list: cpu.resched() def on_activate(self, job): self.ready_list.append(job) job.cpu.resched() def on_terminated(self, job): self.ready_list.remove(job) self.update(job.cpu) def schedule(self, cpu): decisions = [] if self.ready_list: # Sort according to the laxity. self.ready_list.sort(key=lambda x: (x.laxity, x.task.identifier)) # m : Nombre de processeurs. m = len(self.processors) # Available processors: l = (proc for proc in self.processors if proc.running not in self.ready_list[:m]) # The first m jobs should be running: for job in self.ready_list[:m]: if not job.is_running(): proc = next(l) decisions.append((job, proc)) return decisions
class LLF(Scheduler): """Least Laxity First""" def init(self): self.ready_list = [] self.timer = Timer(self.sim, LLF.compute_laxity, (self, self.processors[0]), 1, one_shot=False, cpu=self.processors[0], overhead=.01) self.timer.start() def compute_laxity(self, cpu): if self.ready_list: for job in self.ready_list: job.laxity = job.absolute_deadline - \ (job.ret + self.sim.now_ms()) cpu.resched() def on_activate(self, job): self.ready_list.append(job) self.compute_laxity(job.cpu) def on_terminated(self, job): self.ready_list.remove(job) self.compute_laxity(job.cpu) def schedule(self, cpu): decisions = [] if self.ready_list: # Sort according to the laxity. self.ready_list.sort(key=lambda x: (x.laxity, x.task.identifier)) # m : Nombre de processeurs. m = len(self.processors) # Available processors: l = (proc for proc in self.processors if proc.running not in self.ready_list[:m]) # The first m jobs should be running: for job in self.ready_list[:m]: if not job.is_running(): proc = next(l) decisions.append((job, proc)) return decisions
class RR(Scheduler): """Round Robin scheduler""" def init(self): self.ready_list = [] self.delay = 2 self.timer = Timer(self.sim, RR.end_event, (self, self.processors[0]), self.delay, cpu=self.processors[0], in_ms=True) self.interupt = False def on_activate(self, job): self.ready_list.append(job) job.cpu.resched() def on_terminated(self, job): if job in self.ready_list: self.ready_list.remove(job) self.timer.stop() job.cpu.resched() def end_event(self, cpu): self.interupt = True self.timer.stop() cpu.resched() def schedule(self, cpu): if self.ready_list: job = self.ready_list[0] if not cpu.running or self.interupt: self.interupt = False self.timer.start() self.ready_list.remove(job) if cpu.running: self.ready_list.append(cpu.running) return (job, cpu) else: return None
class ProperSubsystem(object): """ Proper sub-system. A proper sub-system is the set of the tasks belonging to a unit server (server with utilization of 1) and a set of processors. """ def __init__(self, sim, root, processors): self.sim = sim self.root = root self.processors = processors self.virtual = [] self.last_update = 0 self.to_reschedule = False self.timer = None def update_budget(self): """ Update the budget of the servers. """ time_since_last_update = self.sim.now() - self.last_update for server in self.virtual: server.budget -= time_since_last_update self.last_update = self.sim.now() def resched(self, cpu): """ Plannify a scheduling decision on processor cpu. Ignore it if already planned. """ if not self.to_reschedule: self.to_reschedule = True cpu.resched() def virtual_event(self, cpu): """ Virtual scheduling event. Happens when a virtual job terminates. """ self.update_budget() self.resched(cpu) def schedule(self): """ Schedule this proper sub-system. """ self.to_reschedule = False decision = [] self.virtual = [] jobs = select_jobs(self.root, self.virtual) wakeup_delay = min(self.virtual, key=lambda s: s.budget).budget if wakeup_delay > 0: self.timer = Timer(self.sim, ProperSubsystem.virtual_event, (self, self.processors[0]), wakeup_delay, cpu=self.processors[0], in_ms=False) self.timer.start() cpus = [] for cpu in self.processors: if cpu.running in jobs: jobs.remove(cpu.running) else: cpus.append(cpu) for cpu in cpus: if jobs: decision.append((jobs.pop(), cpu)) else: decision.append((None, cpu)) return decision
class LLREF2(Scheduler): def init(self): self.selected_jobs = [] # Jobs currently running. self.budget = {} # Budgets for the active jobs. self.next_deadline = 0 self.waiting_schedule = False self.last_update = 0 # Used to update the budget. def reschedule(self, cpu=None): """ Ask for a scheduling decision. Don't call if not necessary. """ if not self.waiting_schedule: if cpu is None: cpu = self.processors[0] cpu.resched() self.waiting_schedule = True def on_activate(self, job): """ Deal with a job activation. The budget for this job is computed. """ if job.wcet == 0: return # Compute budget for this newly activated job window = self.next_deadline - self.sim.now() self.budget[job] = window * job.wcet / job.period # Find the next absolute deadline among the ready jobs. m_dl = min([rjob.absolute_deadline for rjob in self.budget.keys()]) \ * self.sim.cycles_per_ms # Refill the budgets if we change the interval if m_dl != self.next_deadline: window = m_dl - self.next_deadline self.next_deadline = m_dl for j in self.budget.keys(): self.budget[j] += window * j.wcet / j.period # There's a new job, the system should be rescheduled. self.reschedule() def on_terminated(self, job): if job in self.budget: del self.budget[job] def update_budget(self): """ Remove budget from the currently executing jobs. """ time_since_last_update = self.sim.now() - self.last_update for job in self.selected_jobs: if job in self.budget: if job.is_active(): self.budget[job] -= time_since_last_update else: del self.budget[job] self.last_update = self.sim.now() def date_next_event(self, selected, not_selected): next_event = None if selected: next_bottom_hitting = min(ceil(y) for _, y in selected) next_event = next_bottom_hitting if not_selected: next_ceiling_hitting = self.next_deadline - self.sim.now() \ - ceil(max(y for _, y in not_selected)) if next_event is None or next_ceiling_hitting < next_event: next_event = next_ceiling_hitting return next_event if next_event else 0 def select_jobs(self): window = self.next_deadline - self.sim.now() res = [(job, b) for job, b in self.budget.items() if window <= ceil(b) and job.is_active()] for job, b in sorted(self.budget.items(), key=lambda x: -x[1]): if b > 0 and (job, b) not in res and job.is_active(): res.append((job, b)) return (res[:len(self.processors)], res[len(self.processors):]) def schedule(self, cpu): self.waiting_schedule = False self.update_budget() # Sort the jobs by budgets. selected, not_selected = self.select_jobs() # Compute the (relative) date of the next event. next_event = self.date_next_event(selected, not_selected) if next_event > 0: # Set a timer to reschedule the system at that date. self.timer_a = Timer(self.sim, LLREF2.reschedule, (self,), next_event, cpu=cpu, in_ms=False) self.timer_a.start() # Allocate the selected jobs to the processors. # The processors already running selected jobs are not changed. available_procs = [] self.selected_jobs = [s[0] for s in selected] remaining_jobs = self.selected_jobs[:] for proc in self.processors: if proc.running in self.selected_jobs: # This processor keeps running the same job. remaining_jobs.remove(proc.running) else: # This processor is not running a selected job. available_procs.append(proc) # The remaining processors are running the remaining jobs or None. padded_remaining_jobs = remaining_jobs + \ [None] * (len(available_procs) - len(remaining_jobs)) # zip create a list of couples (job, proc) using the list of remaining # jobs and the list of available processors. decisions = list(zip(padded_remaining_jobs, available_procs)) return decisions
class MLFQ(Scheduler): """Multilevel Feedback Queue scheduler""" QUANTUM = 8 BOOST_DELAY = 200 NUM_QUEUE = 4 def init(self): self.ready_lists = [[] for _ in range(self.NUM_QUEUE)] self.job_timer = None self.timers = [self.create_timer(i) for i in range(self.NUM_QUEUE - 1)] self.prior_table = {} self.boost_timer = Timer( self.sim, MLFQ.boost_event, (self, self.processors[0]), self.BOOST_DELAY, one_shot=False, cpu=self.processors[0], in_ms=True) self.boost_timer.start() self.interupt = False def on_activate(self, job): self.ready_lists[0].append(job) self.prior_table.update({job: 0}) job.cpu.resched() def on_terminated(self, job): prior = self.prior_table[job] if job in self.ready_lists[prior]: self.ready_lists[prior].remove(job) if self.job_timer: self.job_timer.stop() self.prior_table.pop(job, None) job.cpu.resched() def boost_event(self, cpu): for q in range(1, self.NUM_QUEUE): for j in self.ready_lists[q]: self.prior_table[j] = 0 self.ready_lists[0].extend(self.ready_lists[q]) # Add all in first queue del self.ready_lists[q][:] # Cleare all from old queue if cpu.running: self.prior_table[cpu.running] = 0 self.interupt = True cpu.resched() def end_event(self, cpu): if cpu.running: self.interupt = True if self.job_timer: self.job_timer.stop() prior = self.prior_table[cpu.running] self.prior_table[cpu.running] = prior + 1 if prior < self.NUM_QUEUE - 1 else self.NUM_QUEUE - 1 cpu.resched() def create_timer(self, i): return Timer( self.sim, MLFQ.end_event, (self, self.processors[0]), self.QUANTUM*(2**i), cpu=self.processors[0], in_ms=True) def set_timer(self, prior): if self.job_timer: self.job_timer.stop() if prior < self.NUM_QUEUE-1: self.job_timer = self.timers[prior] self.job_timer.start() def schedule(self, cpu): if any(self.ready_lists): for r in range(self.NUM_QUEUE): if self.ready_lists[r]: job = self.ready_lists[r][0] break j_prior = self.prior_table[job] if (not cpu.running or j_prior < self.prior_table[cpu.running] or self.interupt and j_prior <= self.prior_table[cpu.running]): self.set_timer(j_prior) if self.interupt: self.interupt = False if job in self.ready_lists[j_prior]: self.ready_lists[j_prior].remove(job) if cpu.running: self.ready_lists[self.prior_table[cpu.running]].append( cpu.running) return (job, cpu) elif self.interupt: self.interupt = False self.set_timer(self.prior_table[cpu.running]) return None elif self.interupt: self.interupt = False self.set_timer(self.prior_table[cpu.running]) return None else: return None
class ProperSubsystem(object): """ Proper sub-system. A proper sub-system is the set of the tasks belonging to a unit server (server with utilization of 1) and a set of processors. """ def __init__(self, sim, root, processors, dummy, u): self.sim = sim self.root = root self.processors = processors self.dummyTask = dummy self.virtual = [] self.last_update = 0 self.to_reschedule = False self.utilization = u self.timer = None self.dummy_timer2 = None self.dummy_is_running = False self.is_idle = False self.busy = True self.keep = False self.start_idle = 0 self.slack = 0 self.idle_time = 0 self.wcet = False self.dummy_last_cpu = None self.t0 = 0 self.mode = 2 self.sim.logger.log("u= {} or u = {}".format(self.utilization, float(self.utilization))) # Execute real job first #self.dummy_activated(self.processors[0]) #update_deadline2(self.sim, self.dummyTask, INFINITO) def update_budget(self): """ Update the budget of the servers. """ time_since_last_update = self.sim.now() - self.last_update for server in self.virtual: server.budget -= time_since_last_update self.last_update = self.sim.now() def resched(self, cpu): """ Plannify a scheduling decision on processor cpu. Ignore it if already planned. """ if not self.to_reschedule: self.to_reschedule = True cpu.resched() def virtual_event(self, cpu): """ Virtual scheduling event. Happens when a virtual job terminates. """ self.update_budget() self.resched(cpu) def dummy_activated(self, cpu): update_deadline2(self.sim, self.root, self.dummyTask[0], INFINITO) self.is_idle = False self.keep = False #self.sim.logger.log("NOT KEEP NOT IDLE".format()) self.update_budget() self.to_reschedule = True cpu.resched() def add_timer(self, wakeup_delay, CPU): if self.dummy_timer2: self.dummy_timer2.stop() self.dummy_timer2 = Timer(self.sim, ProperSubsystem.dummy_activated, (self, CPU), wakeup_delay, cpu=CPU, in_ms=False) self.dummy_timer2.start() def schedule(self): """ Schedule this proper sub-system. """ self.to_reschedule = False decision = [] self.virtual = [] active_servers = [ s for s in self.root.children if not s.dummyServer and s.budget > 0 ] if self.is_idle is True and self.keep is False and active_servers: self.sim.logger.log("was idle in t".format()) servers = [s for s in self.root.children if not s.dummyServer] # Prolongamento do job dummy liberado em idle_time self.slack = algorithm_1(self, servers, self.sim.now()) # tempo de computação total do job dummy liberado em idle_time delta = self.sim.now() - self.idle_time + self.slack self.sim.logger.log("original slack {} omega {}".format( self.slack, self.sim.now() - self.idle_time)) # período ocioso exato delta self.processors[0].set_idle(delta) # Se houve prolongamento, o nível continua ocioso if self.slack > 0: self.add_timer(self.slack, self.processors[0]) self.keep = True self.is_idle = False self.slack += self.sim.now() # Caso contrário, o nível fica ocupado else: self.is_idle = False self.keep = False elif active_servers and self.sim.now() >= self.slack: self.is_idle = False self.keep = False # Processor level control if not self.busy: self.busy = True self.sim.logger.log("Servidores ativos, BUSY".format()) else: self.sim.logger.log("Sem servidores ativos, IDLE".format()) self.is_idle = True self.idle_time = self.sim.now() selected = select_jobs(self, self.root, self.virtual) idle = [s for s in selected if s.task.name == 'IdleTask'] jobs = [ s.job for s in selected if s.task.name != 'IdleTask' and s.task.name != "wcet" ] """if (idle and not self.keep): servers = [s for s in self.root.children if not s.dummyServer] start_slack = min(servers, key=lambda s: s.next_deadline).next_deadline - self.sim.now() if start_slack > 10: self.slack = uni_algorithm_1(self, servers, self.sim.now()+start_slack) self.sim.logger.log("slack {} D {}".format(self.slack, start_slack)) self.slack += start_slack if int(self.slack) > 0 and self.utilization < 0.995: self.sim.logger.log("add_timer {} D {}".format(self.slack, start_slack)) self.add_timer(self.slack, self.processors[0]) self.keep = True else: update_deadline2(self.sim, self.root, self.dummyTask[0], INFINITO) self.is_idle = False self.keep = False """ min_s = min(self.virtual, key=lambda s: s.budget) wakeup_delay = min_s.budget old = self.virtual while wakeup_delay == 0: old.remove(min_s) min_s = min(old, key=lambda s: s.budget) wakeup_delay = min_s.budget if wakeup_delay > 0: self.timer = Timer(self.sim, ProperSubsystem.virtual_event, (self, self.processors[0]), wakeup_delay, cpu=self.processors[0], in_ms=False) self.timer.start() cpus = [] #first, leave already executing tasks on their current processors; for cpu in self.processors: if cpu.running in jobs: #cpus.append(cpu) jobs.remove(cpu.running) # remove job and cpu else: cpus.append(cpu) # second, assign previously idle tasks to their last-used processor, when its available aux_jobs = list(jobs) for job in aux_jobs: if job.task.last_cpu in cpus: decision.append((job, job.task.last_cpu)) jobs.remove(job) cpus.remove(job.task.last_cpu) # third, assign remaining tasks to free processors arbitrarily for cpu in cpus: if jobs: decision.append((jobs.pop(), cpu)) else: """ period = 0 if self.keep and self.slack > 0: period = self.slack #self.sim.logger.log("slack {}".format(self.slack)) self.slack = 0 cpu.set_idle(period) elif not self.keep and idle: period = next_activation(idle.pop()) - self.sim.now() #self.sim.logger.log("next_activation {}".format(period)) cpu.set_idle(period) """ decision.append((None, cpu)) return decision
class ProperSubsystem(object): """ Proper sub-system. A proper sub-system is the set of the tasks belonging to a unit server (server with utilization of 1) and a set of processors. """ def __init__(self, sim, _id, level, root, processors, dummy, u): self.identifier = _id self.level = level self.sim = sim self.root = root self.processors = processors self.dummyTask = dummy self.virtual = [] self.last_update = 0 self.to_reschedule = False self.utilization = u self.timer = None self.dummy_timer = None #self.dummy_is_running = False if level == 0: self.is_idle = False else: self.is_idle = True self.keep = False self.busy = False self.idle_time = 0 #self.start_idle = 0 self.slack = 0 self.lower_bound = 0 #self.wcet = False #self.dummy_last_cpu = None self.t0 = 0 self.sim.logger.log("u= {} id = {}".format(float(self.utilization), self.identifier)) def update_budget(self): """ Update the budget of the servers. """ time_since_last_update = self.sim.now() - self.last_update for server in self.virtual: server.budget -= time_since_last_update self.last_update = self.sim.now() def resched(self, cpu): """ Plannify a scheduling decision on processor cpu. Ignore it if already planned. """ if not self.to_reschedule: self.to_reschedule = True cpu.resched() def virtual_event(self, cpu): """ Virtual scheduling event. Happens when a virtual job terminates. """ self.update_budget() self.resched(cpu) def end_dummy(self, cpu): #update_deadline2(self.sim, self.root, self.dummyTask[0], INFINITO) self.is_idle = False self.keep = False #self.sim.logger.log("RESEEET NOT IDLE NOT KEEP".format()) self.update_budget() self.to_reschedule = True cpu.resched() def add_timer(self, wakeup_delay, CPU): if self.dummy_timer: self.dummy_timer.stop() self.dummy_timer = Timer(self.sim, ProperSubsystem.end_dummy, (self, CPU), wakeup_delay, cpu=CPU, in_ms=False) self.dummy_timer.start() def schedule_1(self): """ Schedule this proper sub-system. """ self.to_reschedule = False self.virtual = [] decision = [] processors = [] processors = self.processors active_servers = [s for s in self.root.children if not s.dummyServer and s.budget > 0] if self.is_idle is True and self.keep is False and active_servers: self.sim.logger.log("was idle in t {}".format(self.processors[0].name)) servers = [s for s in self.root.children if not s.dummyServer] self.slack = algorithm_1(self, servers, self.sim.now()) self.sim.logger.log("slack {}, sub {}".format(self.slack, self.identifier)) if self.slack > 0: self.add_timer(self.slack, self.processors[0]) self.keep = True # calcular o mínimo ocioso apartir do slack d = self.sim.now() + (float(self.slack)/(1-self.dummyTask[0].utilization)) self.lower_bound = d - self.slack - self.sim.now() self.sim.logger.log("lower_bound {}, d {}, u={}".format(self.lower_bound/self.sim.cycles_per_ms, d, self.dummyTask[len(self.dummyTask)-1].utilization)) self.slack += self.sim.now() else: self.is_idle = False self.keep = False elif active_servers and self.sim.now() >= self.slack: self.is_idle = False self.keep = False if self.lower_bound <= 0: self.lower_bound = sum(s.budget for s in active_servers) self.processors[0].set_idle_extend(self.lower_bound) # Processor level control if not self.busy: self.busy = True processors = self.processors[1:] # Refresh avaliable processors list decision.append((None, self.processors[0])) # Set dummy to first processor self.sim.logger.log("Servidores ativos, BUSY {}".format(self.processors[0].name)) else: self.sim.logger.log("Sem servidores ativos, IDLE {}".format(self.processors[0].name)) self.is_idle = True # Processor level control if self.busy: self.processors[0].stop_idle_extend() self.busy = False self.lower_bound = 0 selected = select_jobs(self, self.root, self.virtual) idle = [s for s in selected if s.task.name == 'IdleTask'] jobs = [s.job for s in selected if s.task.name != 'IdleTask' and s.task.name != "wcet"] wakeup_delay = min([s.budget for s in self.virtual if s.budget > 0]) """old = self.virtual while wakeup_delay == 0: old.remove(min_s) min_s = min(old, key=lambda s: s.budget) wakeup_delay = min_s.budget""" if wakeup_delay > 0: self.timer = Timer(self.sim, ProperSubsystem.virtual_event, (self, self.processors[0]), wakeup_delay, cpu=self.processors[0], in_ms=False) self.timer.start() cpus = [] #first, leave already executing tasks on their current processors; for cpu in processors: if cpu.running in jobs: #cpus.append(cpu) jobs.remove(cpu.running) # remove job and cpu else: cpus.append(cpu) # second, assign previously idle tasks to their last-used processor, when its available aux_jobs = list(jobs) for job in aux_jobs: if job.task.last_cpu in cpus: #if job.task.last_cpu.is_running(): decision.append((job, job.task.last_cpu)) jobs.remove(job) cpus.remove(job.task.last_cpu) # third, assign remaining tasks to free processors arbitrarily for cpu in cpus: if jobs: decision.append((jobs.pop(), cpu)) else: decision.append((None, cpu)) return decision def schedule_0(self): """ Schedule this proper sub-system. """ self.to_reschedule = False decision = [] self.virtual = [] active_servers = [s for s in self.root.children if not s.dummyServer and s.budget > 0] if self.is_idle is True and self.keep is False and active_servers: self.sim.logger.log("was idle in t {}".format(self.processors[0].name)) servers = [s for s in self.root.children if not s.dummyServer] # Prolongamento do job dummy liberado em idle_time self.slack = algorithm_1(self, servers, self.sim.now()) # tempo de computação total do job dummy liberado em idle_time delta = self.sim.now() - self.idle_time + self.slack self.sim.logger.log("original slack {} omega {}".format(self.slack, self.sim.now() - self.idle_time)) # período ocioso exato delta self.processors[0].set_idle(delta) # Se houve prolongamento, o nível continua ocioso if self.slack > 0: self.add_timer(self.slack, self.processors[0]) self.keep = True self.is_idle = False self.slack += self.sim.now() # Caso contrário, o nível fica ocupado else: self.is_idle = False self.keep = False elif active_servers and self.sim.now() >= self.slack: self.is_idle = False self.keep = False # Processor level control if not self.busy: self.busy = True self.sim.logger.log("Servidores ativos, BUSY {}, slack {}".format(self.processors[0].name, self.slack)) else: self.sim.logger.log("Sem servidores ativos, IDLE {}, slack {}".format(self.processors[0].name, self.slack)) self.is_idle = True self.idle_time = self.sim.now() # se o tempo acabar antes de aglomerar # Sinaliza início da ociosidade para energy self.processors[0]._power.flag(self.sim.now()) selected = select_jobs(self, self.root, self.virtual) idle = [s for s in selected if s.task.name == 'IdleTask'] jobs = [s.job for s in selected if s.task.name != 'IdleTask' and s.task.name != "wcet"] """if (idle and not self.keep): servers = [s for s in self.root.children if not s.dummyServer] start_slack = min(servers, key=lambda s: s.next_deadline).next_deadline - self.sim.now() if start_slack > 2: self.slack = uni_algorithm_1(self, servers, self.sim.now()+start_slack) self.slack += start_slack #self.sim.logger.log("slack {}, sub {}, start {}".format(self.slack, self.identifier, start_slack)) if int(self.slack) > 0 and self.utilization < 0.985: self.add_timer(self.slack, self.processors[0]) self.keep = True else: self.is_idle = False self.keep = False """ wakeup_delay = min([s.budget for s in self.virtual if s.budget > 0]) """old = self.virtual while wakeup_delay == 0: old.remove(min_s) min_s = min(old, key=lambda s: s.budget) wakeup_delay = min_s.budget""" if wakeup_delay > 0: self.timer = Timer(self.sim, ProperSubsystem.virtual_event, (self, self.processors[0]), wakeup_delay, cpu=self.processors[0], in_ms=False) self.timer.start() cpus = [] #first, leave already executing tasks on their current processors; for cpu in self.processors: if cpu.running in jobs: #cpus.append(cpu) jobs.remove(cpu.running) # remove job and cpu else: cpus.append(cpu) # second, assign previously idle tasks to their last-used processor, when its available aux_jobs = list(jobs) for job in aux_jobs: if job.task.last_cpu in cpus: decision.append((job, job.task.last_cpu)) jobs.remove(job) cpus.remove(job.task.last_cpu) # third, assign remaining tasks to free processors arbitrarily for cpu in cpus: if jobs: decision.append((jobs.pop(), cpu)) else: period = 0 """if self.keep and self.slack > 0: period = self.slack #self.sim.logger.log("slack {}".format(self.slack)) self.slack = 0 cpu.set_idle(period) elif not self.keep and idle: period = next_activation(idle.pop()) - self.sim.now() #self.sim.logger.log("next_activation {}".format(period)) cpu.set_idle(period) """ decision.append((None, cpu)) return decision
class ProperSubsystem(object): """ Proper sub-system. A proper sub-system is the set of the tasks belonging to a unit server (server with utilization of 1) and a set of processors. """ def __init__(self, sim, root, processors, dummy): self.sim = sim self.root = root self.processors = processors self.dummyTask = dummy self.virtual = [] self.last_update = 0 self.to_reschedule = False self.timer = None self.dummy_timer = None #self.dummy_is_running = False self.idle_time = 0 self.is_idle = True self.keep = False self.busy = False #self.start_idle = 0 self.slack = 0 self.lower_bound = 0 #self.wcet = False #self.dummy_last_cpu = None self.t0 = 0 #self.mode = 2 #self.clock = 0 def update_budget(self): """ Update the budget of the servers. """ time_since_last_update = self.sim.now() - self.last_update for server in self.virtual: server.budget -= time_since_last_update self.last_update = self.sim.now() def resched(self, cpu): """ Plannify a scheduling decision on processor cpu. Ignore it if already planned. """ for cpu in self.sim.processors: if any(x[0] == 2 or x[0] == 3 for x in cpu._evts): return #if not self.to_reschedule: self.to_reschedule = True cpu.resched() def virtual_event(self, cpu): """ Virtual scheduling event. Happens when a virtual job terminates. """ self.update_budget() self.resched(cpu) def end_dummy(self, cpu): #update_deadline2(self.sim, self.root, self.dummyTask[0], INFINITO) self.is_idle = False self.keep = False #self.sim.logger.log("RESEEET NOT IDLE NOT KEEP".format()) self.update_budget() self.to_reschedule = True cpu.resched() def add_timer(self, wakeup_delay, CPU): if self.dummy_timer: self.dummy_timer.stop() self.dummy_timer = Timer(self.sim, ProperSubsystem.end_dummy, (self, CPU), wakeup_delay, cpu=CPU, in_ms=False) self.dummy_timer.start() def schedule(self): """ Schedule this proper sub-system. """ self.to_reschedule = False self.virtual = [] decision = [] processors = [] processors = self.processors active_servers = [ s for s in self.root.children if not s.dummyServer and s.budget > 0 ] if self.is_idle is True and self.keep is False and active_servers: self.sim.logger.log("was idle in t".format()) servers = [s for s in self.root.children if not s.dummyServer] # Prolongamento do job dummy liberado em idle_time self.slack = algorithm_1(self, servers, self.sim.now()) # tempo de computação total do job dummy liberado em idle_time omega = self.sim.now() - self.idle_time + self.slack self.sim.logger.log("original slack {} omega {}".format( self.slack, self.sim.now() - self.idle_time)) # calculo do deadline do job dummy d = self.sim.now() + (float(omega) / (1 - self.dummyTask[0].utilization)) # estimativa do período ocioso no real self.lower_bound = d - omega - self.sim.now() if self.lower_bound < sum(s.budget for s in servers): self.lower_bound = sum(s.budget for s in servers) self.sim.logger.log("lower_bound {}, d {}, u={}".format( self.lower_bound / self.sim.cycles_per_ms, d, self.dummyTask[len(self.dummyTask) - 1].utilization)) # Se houve prolongamento, o nível continua ocioso if self.slack > 0: self.add_timer(self.slack, self.processors[0]) self.keep = True self.is_idle = False self.slack += self.sim.now() # Caso contrário, o nível fica ocupado e o real ocioso, portanto ativa-se um estado de economia de energia else: self.processors[0].set_idle_extend(self.lower_bound) self.is_idle = False self.keep = False elif active_servers and self.sim.now() >= self.slack: self.is_idle = False self.keep = False if self.lower_bound <= 0: self.lower_bound = sum(s.budget for s in active_servers) self.processors[0].set_idle_extend(self.lower_bound) # Processor level control if not self.busy: self.busy = True processors = self.processors[ 1:] # Refresh avaliable processors list decision.append( (None, self.processors[0])) # Set dummy to first processor self.sim.logger.log("Servidores ativos, BUSY".format()) else: self.sim.logger.log("Sem servidores ativos, IDLE".format()) self.is_idle = True self.idle_time = self.sim.now() # Processor level control if self.busy: self.processors[0].stop_idle_extend() self.busy = False self.lower_bound = 0 selected = select_jobs(self, self.root, self.virtual) #idle = [s for s in selected if s.task.name == 'IdleTask'] jobs = [ s.job for s in selected if s.task.name != 'IdleTask' and s.task.name != "wcet" ] #wcet = [s for s in selected if s.task.name == "wcet"] wakeup_delay = min([s.budget for s in self.virtual if s.budget > 0]) if wakeup_delay > 0: self.timer = Timer(self.sim, ProperSubsystem.virtual_event, (self, self.processors[0]), wakeup_delay, cpu=self.processors[0], in_ms=False) self.timer.start() cpus = [] #first, leave already executing tasks on their current processors; for cpu in processors: if cpu.running in jobs: #cpus.append(cpu) jobs.remove(cpu.running) # remove job and cpu else: cpus.append(cpu) # second, assign previously idle tasks to their last-used processor, when its available aux_jobs = list(jobs) for job in aux_jobs: if job.task.last_cpu in cpus: #if job.task.last_cpu.is_running(): decision.append((job, job.task.last_cpu)) jobs.remove(job) cpus.remove(job.task.last_cpu) # third, assign remaining tasks to free processors arbitrarily for cpu in cpus: if jobs: decision.append((jobs.pop(), cpu)) else: decision.append((None, cpu)) return decision
class BDPS(Scheduler): def init(self): self.ready_list = [] self.windowsize = 100 self.window_id = 0 self.queue_index = 0 self.default_quantum = 10 self.timeline = defaultdict(list) self.window_usage = defaultdict(lambda: self.windowsize) self.started = False try: self.MAX_PRIORITY = self.data["max_priority"] except KeyError: self.MAX_PRIORITY = 20 try: self.MAX_B = self.data["max_b"] except KeyError: self.MAX_B = 1000.0 def reset_window(self, cpu): if self.started: self.window_id += 1 else: self.started = True self.queue_index = 0 #clean window self.timeline[self.window_id] = [job for job in self.timeline[self.window_id] if job[0].is_active()] def reschedule(self, cpu): cpu.resched() def on_activate(self, job): try: job.a = job.data['a'] job.b = job.data['b'] except KeyError: job.a = 0.0 job.b = self.MAX_B if job.a == 1.0: job.a = 0.0 try: job.priority = job.data["priority"] except KeyError: job.priority = 1.0 self.ready_list.append(job) prev = len(self.timeline[self.window_id]) wcet = job.wcet w_id = self.window_id while wcet > 0: if self.window_usage[w_id] > 0: f = ((job.b/float(self.MAX_B)) * ((self.MAX_PRIORITY-job.priority)/self.MAX_PRIORITY) * (1-job.a)) slot = float("{0:.2f}".format(max(f * self.windowsize, 1.0))) slot = min(self.window_usage[w_id], slot) self.timeline[w_id].append((job, slot)) self.window_usage[w_id] -= slot wcet -= slot w_id += 1 deadline = self.windowsize * w_id + self.windowsize job._absolute_deadline = job._task._task_info.deadline = deadline if prev == 0 and len(self.timeline[self.window_id]) > 0: job.cpu.resched() def on_terminated(self, job): if job in self.ready_list: self.ready_list.remove(job) self.preempt_timer.stop() seconds = (self.sim.now_ms() - job.activation_date) / 1000.0 benefit = job.b * math.e ** (-job.a * seconds) job.add_custom_event(JobEvent(self, JobEvent.TEXTLABEL, data="{0:.2f}".format(benefit))) def schedule(self, cpu): now = self.sim.now_ms() remaining_time_in_window = float("{0:.2f}".format(self.windowsize - (now % self.windowsize))) if now % self.windowsize == 0: self.reset_window(cpu) cpu.monitor.observe(ProcEvent(ProcEvent.SEPARATOR)) if remaining_time_in_window > 0: try: current_job = self.timeline[self.window_id][self.queue_index][0] # if job has still reserved cpu time if current_job.is_running() and now < current_job.absolute_burst: return (current_job, cpu) except: pass # burst has finished and next prioritary job is selected try: job, burst = self.timeline[self.window_id][self.queue_index] except Exception as e: available = [job[0] for job in self.timeline[self.window_id] if job[0].is_active()] + self.ready_list if len(available): # Slack time, choose random job job = choice(available) burst = self.default_quantum else: # Idle return (None, cpu) burst = float("{0:.2f}".format(burst)) if burst == 0: # gain time if self.ready_list: job = choice(self.ready_list) burst = self.default_quantum # adjust burst ret = float("{0:.2f}".format(job.ret)) burst = min(remaining_time_in_window, burst, ret) if burst == 0 and remaining_time_in_window > 0: burst = remaining_time_in_window self.preempt_timer = Timer(self.sim, BDPS.reschedule, (self, self.processors[0]), burst, one_shot=True, cpu=self.processors[0]) job.absolute_burst = now + burst self.preempt_timer.start() self.queue_index += 1 return (job, cpu)
class LSTR(Scheduler): """ Least Slack Time Rate First """ def init(self): self.ready_list = [] """ However, LSTR scheduling algorithm operates on every basic time unit. Here, we consider the basic time unit of 1 (ms). """ self.timer = Timer(self.sim, LSTR.virtual_event, (self, self.processors[0]), 1, one_shot=False) self.timer.start() def virtual_event(self, cpu): self.reschedule(cpu) def reschedule(self, cpu): if self.ready_list: cpu.resched() def LSTR_rank(self, job): """ calculates rank described in LSTR algorithm for given job return value should be non-negative, negative value means that job has passed deadline """ if not job: return 0 # print(job.absolute_deadline, job.deadline) din = job.absolute_deadline - self.sim.now_ms() if din == 0: return 0 return job.ret / din def on_activate(self, job): self.ready_list.append(job) self.reschedule(job.cpu) def on_terminated(self, job): self.ready_list.remove(job) self.reschedule(job.cpu) def schedule(self, cpu): decision = [] if self.ready_list: self.ready_list.sort(key=self.LSTR_rank, reverse=True) number_of_processors = len(self.processors) jobs = self.ready_list[:number_of_processors] available_proc = [p for p in self.processors if p.running not in jobs] for job in jobs: if job.is_running(): continue for cpu in available_proc: job_on_cpu_rank = self.LSTR_rank(cpu.running) if job_on_cpu_rank < self.LSTR_rank(job): decision.append((job, cpu)) available_proc.remove(cpu) break return decision
class ProperSubsystem(object): """ Proper sub-system. A proper sub-system is the set of the tasks belonging to a unit server (server with utilization of 1) and a set of processors. """ def __init__(self, sim, root, processors, level): self.sim = sim self.root = root self.processors = processors self.level = level self.virtual = [] self.last_update = 0 self.to_reschedule = False self.timer = None self.utilization = sum( [s.utilization for s in root.children if s.dummyServer is False]) self.dummy_timer = None self.is_idle = True self.keep = True self.idleBegin = 0 self.idleEnd = 0 self.busyBegin = 0 self.busyEnd = 0 def update_budget(self): """ Update the budget of the servers. """ time_since_last_update = self.sim.now() - self.last_update for server in self.virtual: server.budget -= time_since_last_update self.last_update = self.sim.now() def bug(self, subsystem): for cpu in subsystem.processors: if any(x[0] == 2 or x[0] == 3 for x in cpu._evts) and self.sim.now() > 0: return True return False def resched(self, cpu): """ Plannify a scheduling decision on processor cpu. Ignore it if already planned. """ if not self.bug(self): self.to_reschedule = True cpu.resched() def virtual_event(self, cpu): """ Virtual scheduling event. Happens when a virtual job terminates. """ self.update_budget() self.resched(cpu) def end_dummy(self, cpu): self.update_budget() self.to_reschedule = True self.resched(cpu) def add_timer(self, wakeup_delay, CPU): if self.dummy_timer: self.dummy_timer.stop() self.dummy_timer = Timer(self.sim, ProperSubsystem.end_dummy, (self, CPU), wakeup_delay, cpu=CPU, in_ms=False) self.dummy_timer.start() # cumulative slack computation def CSC(self, t): active_servers = [ s for s in self.root.children if (s.dummyServer is False) and s.budget > 0 ] servers = [s for s in self.root.children if s.dummyServer is False] beta = beta = sum(s.budget for s in servers) omega = max(0, self.root.next_deadline - t - beta) if self.is_idle is True: delta = omega if delta > 0: self.idleEnd = t + delta self.busyBegin = self.idleEnd self.busyEnd = self.idleBegin + ( self.idleEnd - self.idleBegin) / float(1 - self.utilization) else: self.idleEnd = t self.busyBegin = self.idleEnd self.busyEnd = max(beta, self.busyEnd) else: if active_servers: self.busyEnd = max(t + beta, self.busyEnd) else: omegat = omega_t(self, servers, t, self.root.next_deadline) self.idleBegin = t self.idleEnd = self.root.next_deadline + omegat self.busyBegin = self.idleEnd self.busyEnd = self.root.next_deadline + ( omegat / float(1 - self.utilization)) def schedule(self): """ Schedule this proper sub-system. """ self.to_reschedule = False self.virtual = [] decision = [] processors = [] processors = self.processors self.CSC(self.sim.now()) t = self.sim.now() if t >= self.idleBegin and t < self.idleEnd: self.is_idle = True # add schedule event - end of idle period self.add_timer(self.idleEnd - t, self.processors[0]) else: self.is_idle = False selected = select_jobs(self, self.root, self.virtual) idle = [s for s in selected if s.task.name == 'IdleTask'] jobs = [ s.job for s in selected if s.task.name != 'IdleTask' and s.task.name != "wcet" ] if idle: # CSC dual level if self.level % 2 == 0: # use busyInterval to save energy self.processors[0].set_dummy(self.busyEnd - t) # CSC primal level else: # use idleInterval to save energy self.processors[0].set_dummy(self.idleEnd - t) processors = self.processors[ 1:] # Refresh available processors list decision.append( (None, self.processors[0])) # Set dummy to first processor else: self.processors[0].stop_dummy() wakeup_delay = min([s.budget for s in self.virtual if s.budget > 0]) if wakeup_delay > 0: self.timer = Timer(self.sim, ProperSubsystem.virtual_event, (self, self.processors[0]), wakeup_delay, cpu=self.processors[0], in_ms=False) self.timer.start() cpus = [] #first, leave already executing tasks on their current processors; for cpu in processors: if cpu.running in jobs: jobs.remove(cpu.running) # remove job and cpu else: cpus.append(cpu) # second, assign previously idle tasks to their last-used processor, when its available aux_jobs = list(jobs) for job in aux_jobs: if job.task.last_cpu in cpus: decision.append((job, job.task.last_cpu)) jobs.remove(job) cpus.remove(job.task.last_cpu) # third, assign remaining tasks to free processors arbitrarily for cpu in cpus: if jobs: decision.append((jobs.pop(), cpu)) else: decision.append((None, cpu)) return decision
class DPS(Scheduler): def init(self): self.ready_list = [] self.windowsize = 100 self.window_id = 0 self.queue_index = 0 self.default_quantum = 10 self.window_queue = [] def fill_window_queue(self): while sqrt(self.windowsize) > len(self.window_queue) and len(self.ready_list) > 0: self.window_queue.append(self.ready_list.pop(0)) def reset_window(self, cpu): self.window_id += 1 self.queue_index = 0 # remove finished jobs self.window_queue = [job for job in self.window_queue if job.is_active()] # fill the window queue self.fill_window_queue() def reschedule(self, cpu): cpu.resched() def on_activate(self, job): self.ready_list.append(job) job.priority = len(self.window_queue) + self.ready_list.index(job) + 1 # deadline prediction job._absolute_deadline = job._task._task_info.deadline = ceil(job._activation_date + (2**job.priority) * job.wcet) prev = len(self.window_queue) self.fill_window_queue() if prev == 0 and len(self.window_queue) > 0: job.cpu.resched() def on_terminated(self, job): if job in self.ready_list: self.ready_list.remove(job) self.preempt_timer.stop() def schedule(self, cpu): now = self.sim.now_ms() remaining_time_in_window = self.windowsize - (now % self.windowsize) if now % self.windowsize == 0: self.reset_window(cpu) if remaining_time_in_window > 0: try: current_job = self.window_queue[self.queue_index] # if job has still reserved cpu time if current_job.is_running() and now < current_job.absolute_burst: return (current_job, cpu) except: pass # burst has finished and next prioritary job is selected try: job = self.window_queue[self.queue_index] priority = job.priority burst = self.windowsize / 2**priority except Exception as e: available = [job for job in self.window_queue if job.is_active()] + self.ready_list if len(available): # Slack time, choose random job job = choice(available) burst = self.default_quantum else: # Idle return (None, cpu) if burst == 0: # gain time if self.ready_list: job = choice(self.ready_list) burst = min(self.default_quantum, remaining_time_in_window) else: # adjust burst burst = min(remaining_time_in_window, (min(burst, job.ret))) if burst == 0 and remaining_time_in_window > 0: burst = remaining_time_in_window self.preempt_timer = Timer(self.sim, DPS.reschedule, (self, self.processors[0]), ceil(burst), one_shot=True, cpu=self.processors[0]) job.absolute_burst = now + burst self.preempt_timer.start() self.queue_index += 1 return (job, cpu)
class DPSDy(Scheduler): def init(self): self.ready_list = [] self.windowsize = 100 #float(100.0) self.window_id = 0 self.queue_index = 0 self.default_quantum = 10 self.timeline = defaultdict(list) self.started = False def reset_window(self, cpu): if self.started: self.window_id += 1 else: self.started = True self.queue_index = 0 #clean window self.timeline[self.window_id] = [job for job in self.timeline[self.window_id] if job.is_active()] def reschedule(self, cpu): cpu.resched() def on_activate(self, job): self.ready_list.append(job) prev = len(self.timeline[self.window_id]) wcet = job.wcet w_id = self.window_id while wcet > 0: if sqrt(self.windowsize) > len(self.timeline[w_id]): self.timeline[w_id].append(job) wcet -= self.windowsize / 2**(self.timeline[w_id].index(job)+1) w_id += 1 deadline = self.windowsize * w_id + self.windowsize job._absolute_deadline = job._task._task_info.deadline = deadline if prev == 0 and len(self.timeline[self.window_id]) > 0: job.cpu.resched() def on_terminated(self, job): if job in self.ready_list: self.ready_list.remove(job) self.preempt_timer.stop() def schedule(self, cpu): now = self.sim.now_ms() remaining_time_in_window = self.windowsize - (now % self.windowsize) if now % self.windowsize == 0: self.reset_window(cpu) if remaining_time_in_window > 0: try: current_job = self.timeline[self.window_id][self.queue_index] # if job has still reserved cpu time if current_job.is_running() and now < current_job.absolute_burst: return (current_job, cpu) except: pass # burst has finished and next prioritary job is selected try: job = self.timeline[self.window_id][self.queue_index] priority = self.queue_index + 1 burst = self.windowsize / 2**priority except Exception as e: available = [job for job in self.timeline[self.window_id] if job.is_active()] + self.ready_list if len(available): # Slack time, choose random job job = choice(available) burst = self.default_quantum else: # Idle return (None, cpu) if burst == 0: # gain time if self.ready_list: job = choice(self.ready_list) burst = min(self.default_quantum, remaining_time_in_window) else: # adjust burst burst = min(remaining_time_in_window, (min(burst, job.ret))) if burst == 0 and remaining_time_in_window > 0: burst = remaining_time_in_window #print "[{3}] JOB {0}, scheduled with burst {1} until {2}".format(job.name, burst, now+burst, now) self.preempt_timer = Timer(self.sim, DPSDy.reschedule, (self, self.processors[0]), ceil(burst), one_shot=True, cpu=self.processors[0]) job.absolute_burst = now + burst self.preempt_timer.start() self.queue_index += 1 return (job, cpu)
class ProperSubsystem(object): """ Proper sub-system. A proper sub-system is the set of the tasks belonging to a unit server (server with utilization of 1) and a set of processors. """ def __init__(self, sim, root, processors, level): self.sim = sim self.root = root self.processors = processors self.level = level self.virtual = [] self.last_update = 0 self.to_reschedule = False self.timer = None self.is_idle = False self.keep = False def update_budget(self): """ Update the budget of the servers. """ time_since_last_update = self.sim.now() - self.last_update for server in self.virtual: server.budget -= time_since_last_update self.last_update = self.sim.now() def resched(self, cpu): """ Plannify a scheduling decision on processor cpu. Ignore it if already planned. """ if not self.to_reschedule: self.to_reschedule = True cpu.resched() def virtual_event(self, cpu): """ Virtual scheduling event. Happens when a virtual job terminates. """ self.update_budget() self.resched(cpu) def schedule(self): """ Schedule this proper sub-system. """ self.to_reschedule = False decision = [] self.virtual = [] active_servers = [ s for s in self.root.children if s.budget > 0 and not s.dummyServer ] selected = select_jobs(self, self.root, self.virtual) idle = [s for s in selected if s.task.name == 'IdleTask'] jobs = [ s.job for s in selected if s.task.name != 'IdleTask' and s.task.name != "wcet" ] min_s = min(self.virtual, key=lambda s: s.budget) wakeup_delay = min_s.budget if wakeup_delay > 0: self.timer = Timer(self.sim, ProperSubsystem.virtual_event, (self, self.processors[0]), wakeup_delay, cpu=self.processors[0], in_ms=False) self.timer.start() processors = [] t = self.sim.now() beta = sum([s.budget for s in active_servers]) omega = max(0, self.root.next_deadline - t, beta) if idle: if self.level % 2 == 0: decision.append((None, self.processors[0])) self.processors[0].set_dummy(beta) # primal level else: self.processors[0].set_dummy(omega) processors = self.processors[ 1:] # Refresh available processors list decision.append( (None, self.processors[0])) # Set dummy to first processor else: processors = self.processors self.processors[0].stop_dummy() cpus = [] #first, leave already executing tasks on their current processors; for cpu in processors: if cpu.running in jobs: jobs.remove(cpu.running) # remove job and cpu else: cpus.append(cpu) # second, assign previously idle tasks to their last-used processor, when its available aux_jobs = list(jobs) for job in aux_jobs: if job.task.last_cpu in cpus: decision.append((job, job.task.last_cpu)) jobs.remove(job) cpus.remove(job.task.last_cpu) # third, assign remaining tasks to free processors arbitrarily for cpu in cpus: if jobs: decision.append((jobs.pop(), cpu)) else: period = 0 decision.append((None, cpu)) return decision
class ProperSubsystem(object): """ Proper sub-system. A proper sub-system is the set of the tasks belonging to a unit server (server with utilization of 1) and a set of processors. """ def __init__(self, sim, _id, level, root, processors, dummy, u): self.identifier = _id self.level = level self.sim = sim self.root = root self.processors = processors self.dummyTask = dummy self.utilization = u self.virtual = [] self.last_update = 0 self.to_reschedule = False self.timer = None self.dummy_timer = None #self.dummy_is_running = False if level == 0: self.is_idle = False else: self.is_idle = True self.keep = False self.busy = False self.idle_time = 0 self.slack = 0 self.lower_bound = 0 self.t0 = 0 #self.mode = 2 #self.clock = 0 def update_budget(self): """ Update the budget of the servers. """ time_since_last_update = self.sim.now() - self.last_update for server in self.virtual: server.budget -= time_since_last_update self.last_update = self.sim.now() def resched(self, cpu): """ Plannify a scheduling decision on processor cpu. Ignore it if already planned. """ if not self.to_reschedule: self.to_reschedule = True cpu.resched() def virtual_event(self, cpu): """ Virtual scheduling event. Happens when a virtual job terminates. """ self.update_budget() self.resched(cpu) def end_dummy(self, cpu): #update_deadline2(self.sim, self.root, self.dummyTask[0], INFINITO) self.is_idle = False self.keep = False #self.sim.logger.log("RESEEET NOT IDLE NOT KEEP".format()) self.update_budget() self.to_reschedule = True cpu.resched() def add_timer(self, wakeup_delay, CPU): if self.dummy_timer: self.dummy_timer.stop() self.dummy_timer = Timer(self.sim, ProperSubsystem.end_dummy, (self, CPU), wakeup_delay, cpu=CPU, in_ms=False) self.dummy_timer.start() def schedule(self): """ Schedule this proper sub-system. """ self.to_reschedule = False self.virtual = [] decision = [] processors = [] processors = self.processors active_servers = [s for s in self.root.children if not s.dummyServer and s.budget > 0] if self.is_idle is True and self.keep is False and active_servers: self.sim.logger.log("was idle in t {}".format(self.processors[0].name)) servers = [s for s in self.root.children if not s.dummyServer] beta = sum(s.budget for s in servers) self.slack = max(0, self.root.next_deadline - self.sim.now() - beta) # tempo de computação total do job dummy liberado em idle_time delta = self.sim.now() - self.idle_time + self.slack self.sim.logger.log("original slack {} omega {}".format(self.slack, self.sim.now() - self.idle_time)) # período ocioso exato delta self.processors[0].set_idle(delta) # Se houve prolongamento, o nível continua ocioso if self.slack > 0: self.add_timer(self.slack, self.processors[0]) self.keep = True self.is_idle = False self.slack += self.sim.now() # Caso contrário, o nível fica ocupado else: self.is_idle = False self.keep = False elif active_servers and self.sim.now() >= self.slack: self.is_idle = False self.keep = False # Processor level control if not self.busy: self.busy = True self.sim.logger.log("Servidores ativos, BUSY {}, slack {}".format(self.processors[0].name, self.slack)) else: self.sim.logger.log("Sem servidores ativos, IDLE {}, slack {}".format(self.processors[0].name, self.slack)) self.is_idle = True self.idle_time = self.sim.now() # se o tempo acabar antes de aglomerar # Sinaliza início da ociosidade para energy self.processors[0]._power.flag(self.sim.now()) selected = select_jobs(self, self.root, self.virtual) #idle = [s for s in selected if s.task.name == 'IdleTask'] jobs = [s.job for s in selected if s.task.name != 'IdleTask' and s.task.name != "wcet"] #wcet = [s for s in selected if s.task.name == "wcet"] wakeup_delay = min([s.budget for s in self.virtual if s.budget > 0]) if wakeup_delay > 0: self.timer = Timer(self.sim, ProperSubsystem.virtual_event, (self, self.processors[0]), wakeup_delay, cpu=self.processors[0], in_ms=False) self.timer.start() cpus = [] #first, leave already executing tasks on their current processors; for cpu in processors: if cpu.running in jobs: #cpus.append(cpu) jobs.remove(cpu.running) # remove job and cpu else: cpus.append(cpu) # second, assign previously idle tasks to their last-used processor, when its available aux_jobs = list(jobs) for job in aux_jobs: if job.task.last_cpu in cpus: #if job.task.last_cpu.is_running(): decision.append((job, job.task.last_cpu)) jobs.remove(job) cpus.remove(job.task.last_cpu) # third, assign remaining tasks to free processors arbitrarily for cpu in cpus: if jobs: decision.append((jobs.pop(), cpu)) else: decision.append((None, cpu)) return decision
class LLREF(Scheduler): def init(self): self.selected_jobs = [] # Jobs currently running. self.budget = {} # Budgets for the active jobs. self.next_deadline = 0 self.waiting_schedule = False self.last_update = 0 # Used to update the budget. def reschedule(self, cpu=None): """ Ask for a scheduling decision. Don't call if not necessary. """ if not self.waiting_schedule: if cpu is None: cpu = self.processors[0] cpu.resched() self.waiting_schedule = True def on_activate(self, job): """ Deal with a job activation. The budget for this job is computed. """ # Compute budget for this newly activated job window = self.next_deadline - self.sim.now() self.budget[job] = window * job.wcet / job.period # Find the next absolute deadline among the ready jobs. m_dl = min([rjob.absolute_deadline for rjob in self.budget.keys()]) \ * self.sim.cycles_per_ms # Refill the budgets if we change the interval if m_dl != self.next_deadline: window = m_dl - self.next_deadline self.next_deadline = m_dl for j in self.budget.keys(): self.budget[j] += window * j.wcet / j.period # There's a new job, the system should be rescheduled. self.reschedule() def on_terminated(self, job): if job in self.budget: del self.budget[job] def update_budget(self): """ Remove budget from the currently executing jobs. """ time_since_last_update = self.sim.now() - self.last_update for job in self.selected_jobs: if job in self.budget: if job.is_active(): self.budget[job] -= time_since_last_update else: del self.budget[job] self.last_update = self.sim.now() def date_next_event(self, selected, not_selected): next_event = 0 if selected: next_bottom_hitting = selected[-1][1] next_event = next_bottom_hitting if not_selected: next_ceiling_hitting = self.next_deadline - self.sim.now() \ - not_selected[0][1] if next_ceiling_hitting < next_bottom_hitting: next_event = next_ceiling_hitting return next_event def schedule(self, cpu): self.waiting_schedule = False self.update_budget() # Sort the jobs by budgets. sorted_budgets = sorted([(x, ceil(y)) for x, y in self.budget.items()], key=lambda x: (-x[1], x[0].name)) selected = sorted_budgets[:len(self.processors)] not_selected = sorted_budgets[len(self.processors):] # Compute the (relative) date of the next event. next_event = self.date_next_event(selected, not_selected) if next_event > 0: # Set a timer to reschedule the system at that date. self.timer_a = Timer(self.sim, LLREF.reschedule, (self, ), next_event, cpu=cpu, in_ms=False) self.timer_a.start() # Allocate the selected jobs to the processors. # The processors already running selected jobs are not changed. available_procs = [] self.selected_jobs = [s[0] for s in selected if s[1] > 0] remaining_jobs = self.selected_jobs[:] for proc in self.processors: if proc.running in self.selected_jobs: # This processor keeps running the same job. remaining_jobs.remove(proc.running) else: # This processor is not running a selected job. available_procs.append(proc) # The remaining processors are running the remaining jobs or None. padded_remaining_jobs = remaining_jobs + \ [None] * (len(available_procs) - len(remaining_jobs)) # zip create a list of couples (job, proc) using the list of remaining # jobs and the list of available processors. decisions = list(zip(padded_remaining_jobs, available_procs)) return decisions
class LSTR(Scheduler): """ Least Slack Time Rate First """ def init(self): self.ready_list = [] """ However, LSTR scheduling algorithm operates on every basic time unit. Here, we consider the basic time unit of 1 (ms). """ self.timer = Timer(self.sim, LSTR.virtual_event, (self, self.processors[0]), 1, one_shot=False) self.timer.start() def virtual_event(self, cpu): self.reschedule(cpu) def reschedule(self, cpu): if self.ready_list: cpu.resched() def LSTR_rank(self, job): """ calculates rank described in LSTR algorithm for given job return value should be non-negative, negative value means that job has passed deadline """ if not job: return 0 # print(job.absolute_deadline, job.deadline) din = job.absolute_deadline - self.sim.now_ms() if din == 0: return 0 return job.ret / din def on_activate(self, job): self.ready_list.append(job) self.reschedule(job.cpu) def on_terminated(self, job): self.ready_list.remove(job) self.reschedule(job.cpu) def schedule(self, cpu): decision = [] if self.ready_list: self.ready_list.sort(key=self.LSTR_rank, reverse=True) number_of_processors = len(self.processors) jobs = self.ready_list[:number_of_processors] available_proc = [ p for p in self.processors if p.running not in jobs ] for job in jobs: if job.is_running(): continue for cpu in available_proc: job_on_cpu_rank = self.LSTR_rank(cpu.running) if job_on_cpu_rank < self.LSTR_rank(job): decision.append((job, cpu)) available_proc.remove(cpu) break return decision
class ProperSubsystem(object): """ Proper sub-system. A proper sub-system is the set of the tasks belonging to a unit server (server with utilization of 1) and a set of processors. """ def __init__(self, sim, root, processors, dummy): self.sim = sim self.root = root self.processors = processors self.dummyTask = dummy self.virtual = [] self.last_update = 0 self.to_reschedule = False self.timer = None self.dummy_timer2 = None self.dummy_is_running = False self.is_idle = False self.keep = False self.start_idle = 0 self.slack = 0 self.wcet = False self.dummy_last_cpu = None self.t0 = 0 self.mode = 2 self.clock = 0 # Execute real job first #self.dummy_activated(self.processors[0]) #update_deadline2(self.sim, self.dummyTask, INFINITO) def update_budget(self): """ Update the budget of the servers. """ time_since_last_update = self.sim.now() - self.last_update for server in self.virtual: server.budget -= time_since_last_update self.last_update = self.sim.now() def resched(self, cpu): """ Plannify a scheduling decision on processor cpu. Ignore it if already planned. """ if not self.to_reschedule: self.to_reschedule = True cpu.resched() def virtual_event(self, cpu): """ Virtual scheduling event. Happens when a virtual job terminates. """ self.update_budget() self.resched(cpu) def dummy_activated(self, cpu): update_deadline(self.sim, self.root, self.dummyTask[0]) self.is_idle = False self.keep = False self.sim.logger.log("RESEEET NOT IDLE NOT KEEP".format()) self.update_budget() self.to_reschedule = True cpu.resched() def add_timer(self, wakeup_delay, CPU): if self.dummy_timer2: self.dummy_timer2.stop() self.dummy_timer2 = Timer(self.sim, ProperSubsystem.dummy_activated, (self, CPU), wakeup_delay, cpu=CPU, in_ms=False) self.dummy_timer2.start() def schedule(self): """ Schedule this proper sub-system. """ self.to_reschedule = False decision = [] self.virtual = [] active_servers = [ s for s in self.root.children if s.budget > 0 and not s.dummyServer ] selected = select_jobs(self, self.root, self.virtual) idle = [s for s in selected if s.task.name == 'IdleTask'] jobs = [ s.job for s in selected if s.task.name != 'IdleTask' and s.task.name != "wcet" ] wcet = [s for s in selected if s.task.name == "wcet"] min_s = min(self.virtual, key=lambda s: s.budget) wakeup_delay = min_s.budget old = self.virtual while wakeup_delay == 0: old.remove(min_s) min_s = min(old, key=lambda s: s.budget) wakeup_delay = min_s.budget if wakeup_delay > 0: self.timer = Timer(self.sim, ProperSubsystem.virtual_event, (self, self.processors[0]), wakeup_delay, cpu=self.processors[0], in_ms=False) self.timer.start() processors = [] if idle: processors = self.processors[1:] decision.append((None, self.processors[0])) soma = sum([s.budget for s in active_servers]) self.sim.logger.log("DUMMY TASK Executing on {}".format( self.processors[0].name)) self.processors[0].set_idle_extend(soma) #self.processors[0].set_dummy() else: processors = self.processors #self.sim.logger.log("stop".format()) self.processors[0].stop_idle_extend() #self.processors[0].set_busy() cpus = [] #first, leave already executing tasks on their current processors; for cpu in processors: if cpu.running in jobs: #cpus.append(cpu) jobs.remove(cpu.running) # remove job and cpu else: cpus.append(cpu) # second, assign previously idle tasks to their last-used processor, when its available aux_jobs = list(jobs) for job in aux_jobs: if job.task.last_cpu in cpus: #if job.task.last_cpu.is_running(): decision.append((job, job.task.last_cpu)) jobs.remove(job) cpus.remove(job.task.last_cpu) # third, assign remaining tasks to free processors arbitrarily for cpu in cpus: if jobs: decision.append((jobs.pop(), cpu)) else: decision.append((None, cpu)) return decision
class LRE_TL(Scheduler): def init(self): """ Initialization of the scheduler. This function is called when the system is ready to run. """ self.t_f = 0 self.h_b = [] # Heap of running tasks. self.h_c = [] # Heap of waiting tasks. self.h_d = [] # Heap of deadlines. self.pmin = min([task.period for task in self.task_list]) \ * self.sim.cycles_per_ms self.evt_bc = False self.activations = [] self.waiting_schedule = False def reschedule(self, cpu=None): """ Ask for a scheduling decision. Don't call if not necessary. """ if not self.waiting_schedule: if cpu is None: cpu = self.processors[0] cpu.resched() self.waiting_schedule = True def on_activate(self, job): """ A-event. """ self.activations.append(job.task) self.reschedule() def init_tl_plane(self): decisions = [] for task in self.activations: dl = int(task.job.absolute_deadline * self.sim.cycles_per_ms) if dl not in self.h_d: heappush(self.h_d, dl) self.t_f = self.sim.now() + self.pmin if self.h_d[0] <= self.t_f: self.t_f = heappop(self.h_d) z = 0 self.h_b = [] self.h_c = [] for task in self.task_list: l = ceil(task.wcet * (self.t_f - self.sim.now()) / task.period) if z < len(self.processors) and task.job.is_active(): heappush(self.h_b, (self.sim.now() + l, task)) decisions.append((task.job, self.processors[z])) z += 1 else: heappush(self.h_c, (self.t_f - l, task)) while z < len(self.processors): decisions.append((None, self.processors[z])) z += 1 return decisions def handle_evt_a(self, task): """ Handle an "A-Event". """ decisions = [] tasks_h_c = [t for _, t in self.h_c] tasks_h_b = [t for _, t in self.h_b] if task not in tasks_h_b and task not in tasks_h_c: l = ceil(task.wcet * (self.t_f - self.sim.now()) / task.period) if len(self.h_b) < len(self.processors): idle_proc = [z for z in self.processors if not z.is_running()][0] decisions.append((task.job, idle_proc)) heappush(self.h_b, (self.sim.now() + l, task)) else: if task.wcet < task.period: heappush(self.h_c, ((self.t_f - l), task)) else: key_b, task_b = heapreplace(self.h_b, (self.t_f + l, task)) heappush(self.h_c, (self.t_f - key_b + self.sim.now())) dl = int(task.job.absolute_deadline * self.sim.cycles_per_ms) if dl not in self.h_d: heappush(self.h_d, dl) return decisions def handle_evt_bc(self): """ Handle a "BC-Event". """ decisions = [] while self.h_b and self.h_b[0][0] == self.sim.now(): task_b = heappop(self.h_b)[1] if self.h_c: key_c, task_c = heappop(self.h_c) heappush(self.h_b, (self.t_f - key_c + self.sim.now(), task_c)) decisions.append((task_c.job, task_b.cpu)) else: decisions.append((None, task_b.cpu)) if self.h_c: while self.h_c[0][0] == self.sim.now(): key_b, task_b = heappop(self.h_b) key_c, task_c = heappop(self.h_c) key_b = self.t_f - key_b + self.sim.now() assert key_c != key_b, "Handle Evt BC failed." key_c = self.t_f - key_c + self.sim.now() heappush(self.h_b, (key_c, task_c)) heappush(self.h_c, (key_b, task_b)) decisions.append((task_c.job, task_b.cpu)) return decisions def event_bc(self): """ B or C event. """ self.evt_bc = True self.reschedule() def schedule(self, cpu): """ Take the scheduling decisions. """ self.waiting_schedule = False decisions = [] self.h_c = [(d, t) for d, t in self.h_c if t.job.is_active()] heapify(self.h_c) if self.sim.now() == self.t_f: decisions = self.init_tl_plane() else: for task in self.activations: decisions += self.handle_evt_a(task) if self.evt_bc: decisions += self.handle_evt_bc() self.activations = [] self.evt_bc = False if self.h_b: t_next = self.h_b[0][0] if self.h_c: t_next = min(t_next, self.h_c[0][0]) self.timer = Timer(self.sim, LRE_TL.event_bc, (self, ), t_next - self.sim.now(), cpu=self.processors[0], in_ms=False) else: self.timer = Timer(self.sim, LRE_TL.reschedule, (self, ), self.t_f - self.sim.now(), cpu=self.processors[0], in_ms=False) self.timer.start() return decisions
class U_EDF(Scheduler): def init(self): self.al = {} self.timer = None self.toresched = False self.running_jobs = {} self.last_event = 0 self.newly_activated = False self.ui = {task: task.wcet / task.period for task in self.task_list} def reschedule(self): if not self.toresched: self.processors[0].resched() self.toresched = True def hp(self, job): for task in self.sorted_task_list: if task.job is job: return else: yield task.job def res(self, job, j, t1, t2): s = self.s[job] u = max(0, min(1, (s + self.ui[job.task] - j)))\ - max(0, min(1, (s - j))) return (t2 - t1) * u def bdg(self, job, j, t2): return self.al[job][j] + self.res( job, j, job.absolute_deadline * self.sim.cycles_per_ms, t2) def compute_al(self): t = self.sim.now() cycles_per_ms = self.sim.cycles_per_ms self.sorted_task_list = sorted( self.task_list, key=lambda t: (t.job.absolute_deadline, t.identifier)) self.s = {} for task in self.task_list: self.al[task.job] = [0] * len(self.processors) self.s[task.job] = sum(self.ui[x.task] for x in self.hp(task.job)) for task in self.sorted_task_list: job = task.job if not job.is_active(): continue for j in range(len(self.processors)): almax = (job.absolute_deadline * cycles_per_ms - t) \ - sum(self.bdg(x, j, job.absolute_deadline * cycles_per_ms) for x in self.hp(job)) - sum(self.al[job]) self.al[job][j] = int(ceil(min( almax, job.ret * self.sim.cycles_per_ms - sum(self.al[job])))) def on_activate(self, job): self.newly_activated = True self.reschedule() def update_al(self): delta = self.sim.now() - self.last_event for job, j in self.running_jobs.items(): self.al[job][j] -= delta def schedule(self, cpu): self.toresched = False if self.newly_activated: self.compute_al() self.newly_activated = False else: self.update_al() self.last_event = self.sim.now() next_event = None decisions = [] selected_jobs = {} # Select the jobs: for j, proc in enumerate(self.processors): eligible = [task.job for task in self.task_list if task.job.is_active() and task.job not in selected_jobs and task.job in self.al and self.al[task.job][j] > 0] if not eligible: continue job = min(eligible, key=lambda x: (x.absolute_deadline, x.task.identifier)) if next_event is None or next_event > self.al[job][j]: next_event = self.al[job][j] selected_jobs[job] = j # Set the timer for the next event: if self.timer: self.timer.stop() self.timer = None if next_event is not None: self.timer = Timer(self.sim, U_EDF.reschedule, (self,), next_event, self.processors[0], in_ms=False) self.timer.start() # Bind jobs to processors: jobs = list(selected_jobs.keys()) available_procs = list(self.processors) was_not_running = [] for job in jobs: if job in self.running_jobs: available_procs.remove(job.cpu) else: was_not_running.append(job) remaining_jobs = [] for job in was_not_running: if job.cpu in available_procs: decisions.append((job, job.cpu)) available_procs.remove(job.cpu) else: remaining_jobs.append(job) for p, job in enumerate(remaining_jobs): decisions.append((job, available_procs[p])) self.running_jobs = selected_jobs return decisions
class ER_PD2(Scheduler): def init(self): self.ready_list = [] self.timers = [] self.terminate_timers = [] self.waiting_schedule = False self.running_vjobs = [] ER_PD2.quantum = self.sim.cycles_per_ms // 10 # 0.1ms. #ER_PD2.quantum = 1000000 #while not self.is_schedulable() and ER_PD2.quantum > 1000: # ER_PD2.quantum /= 2 self.timer = Timer( self.sim, ER_PD2.reschedule, (self, ), ER_PD2.quantum, cpu=self.processors[0], in_ms=False, one_shot=False) self.timer.start() def is_schedulable(self, q=None): load = 0.0 cycles_per_ms = self.sim.cycles_per_ms for task in self.task_list: wcet = rounded_wcet_cycles(task, q) load += wcet / task.period if wcet > task.period * cycles_per_ms \ or load > len(self.processors) * cycles_per_ms: return False return True def reschedule(self, cpu=None): """ Ask for a scheduling decision. Don't call if not necessary. """ if not self.waiting_schedule: if cpu is None: cpu = self.processors[0] cpu.resched() self.waiting_schedule = True def virtual_terminate(self, virtual_job): pjob = virtual_job.get_next_job() if not pjob or not virtual_job.job.is_active(): self.ready_list.remove(virtual_job) def on_activate(self, job): virtual_job = VirtualJob(job) self.ready_list.append(virtual_job) if self.sim.now() == 0: self.reschedule() def schedule(self, cpu): self.waiting_schedule = False decisions = [] for vjob in self.running_vjobs: self.virtual_terminate(vjob) vjobs = [vjob for vjob in self.ready_list if vjob.job.is_active()] self.running_vjobs = sorted( vjobs, key=lambda x: x.get_current_job().cmp_key() )[:len(self.processors)] selected_jobs = [vjob.job for vjob in self.running_vjobs] remaining_jobs = selected_jobs[:] available_procs = [] # Remove from the list of remaining jobs the jobs that already runs. for proc in self.processors: if proc.running in selected_jobs: # This processor keeps running the same job. remaining_jobs.remove(proc.running) else: # This processor is not running a selected job. available_procs.append(proc) # Jobs not currently running for vjob in self.running_vjobs: if vjob.job in remaining_jobs: decisions.append((vjob.job, available_procs.pop())) # Unused processors for proc in available_procs: decisions.append((None, proc)) return decisions
class LRE_TL(Scheduler): def init(self): """ Initialization of the scheduler. This function is called when the system is ready to run. """ self.t_f = 0 self.h_b = [] # Heap of running tasks. self.h_c = [] # Heap of waiting tasks. self.h_d = [] # Heap of deadlines. self.pmin = min([task.period for task in self.task_list]) \ * self.sim.cycles_per_ms self.evt_bc = False self.activations = [] self.waiting_schedule = False def reschedule(self, cpu=None): """ Ask for a scheduling decision. Don't call if not necessary. """ if not self.waiting_schedule: if cpu is None: cpu = self.processors[0] cpu.resched() self.waiting_schedule = True def on_activate(self, job): """ A-event. """ self.activations.append(job.task) self.reschedule() def init_tl_plane(self): decisions = [] for task in self.activations: dl = int(task.job.absolute_deadline * self.sim.cycles_per_ms) if dl not in self.h_d: heappush(self.h_d, dl) self.t_f = self.sim.now() + self.pmin if self.h_d[0] <= self.t_f: self.t_f = heappop(self.h_d) z = 0 self.h_b = [] self.h_c = [] for task in self.task_list: l = ceil(task.wcet * (self.t_f - self.sim.now()) / task.period) if z < len(self.processors) and task.job.is_active(): heappush(self.h_b, (self.sim.now() + l, task)) decisions.append((task.job, self.processors[z])) z += 1 else: heappush(self.h_c, (self.t_f - l, task)) while z < len(self.processors): decisions.append((None, self.processors[z])) z += 1 return decisions def handle_evt_a(self, task): """ Handle an "A-Event". """ decisions = [] tasks_h_c = [t for _, t in self.h_c] tasks_h_b = [t for _, t in self.h_b] if task not in tasks_h_b and task not in tasks_h_c: l = ceil(task.wcet * (self.t_f - self.sim.now()) / task.period) if len(self.h_b) < len(self.processors): idle_proc = [z for z in self.processors if not z.is_running()][0] decisions.append((task.job, idle_proc)) heappush(self.h_b, (self.sim.now() + l, task)) else: if task.wcet < task.period: heappush(self.h_c, ((self.t_f - l), task)) else: key_b, task_b = heapreplace(self.h_b, (self.t_f + l, task)) heappush(self.h_c, (self.t_f - key_b + self.sim.now())) dl = int(task.job.absolute_deadline * self.sim.cycles_per_ms) if dl not in self.h_d: heappush(self.h_d, dl) return decisions def handle_evt_bc(self): """ Handle a "BC-Event". """ decisions = [] while self.h_b and self.h_b[0][0] == self.sim.now(): task_b = heappop(self.h_b)[1] if self.h_c: key_c, task_c = heappop(self.h_c) heappush(self.h_b, (self.t_f - key_c + self.sim.now(), task_c)) decisions.append((task_c.job, task_b.cpu)) else: decisions.append((None, task_b.cpu)) if self.h_c: while self.h_c[0][0] == self.sim.now(): key_b, task_b = heappop(self.h_b) key_c, task_c = heappop(self.h_c) key_b = self.t_f - key_b + self.sim.now() assert key_c != key_b, "Handle Evt BC failed." key_c = self.t_f - key_c + self.sim.now() heappush(self.h_b, (key_c, task_c)) heappush(self.h_c, (key_b, task_b)) decisions.append((task_c.job, task_b.cpu)) return decisions def event_bc(self): """ B or C event. """ self.evt_bc = True self.reschedule() def schedule(self, cpu): """ Take the scheduling decisions. """ self.waiting_schedule = False decisions = [] self.h_c = [(d, t) for d, t in self.h_c if t.job.is_active()] heapify(self.h_c) if self.sim.now() == self.t_f: decisions = self.init_tl_plane() else: for task in self.activations: decisions += self.handle_evt_a(task) if self.evt_bc: decisions += self.handle_evt_bc() self.activations = [] self.evt_bc = False if self.h_b: t_next = self.h_b[0][0] if self.h_c: t_next = min(t_next, self.h_c[0][0]) self.timer = Timer(self.sim, LRE_TL.event_bc, (self,), t_next - self.sim.now(), cpu=self.processors[0], in_ms=False) else: self.timer = Timer(self.sim, LRE_TL.reschedule, (self,), self.t_f - self.sim.now(), cpu=self.processors[0], in_ms=False) self.timer.start() return decisions
class NVNLF(Scheduler): def init(self): self.selected_jobs = [] # Jobs currently running. self.budget = {} # Budgets for the active jobs. self.next_deadline = 0 self.waiting_schedule = False self.last_update = 0 # Used to update the budget. def reschedule(self, cpu=None): """ Ask for a scheduling decision. Don't call if not necessary. """ if not self.waiting_schedule: if cpu is None: cpu = self.processors[0] cpu.resched() self.waiting_schedule = True def on_activate(self, job): """ Deal with a job activation. The budget for this job is computed. """ if job.wcet == 0: return self.budget[job] = 0 # Find the next absolute deadline among the ready jobs. self.next_deadline = min([task.job.absolute_deadline for task in self.task_list]) \ * self.sim.cycles_per_ms window = self.next_deadline - self.sim.now() for j in self.budget.keys(): self.budget[j] = ceil(window * j.wcet / j.period) L = window * len(self.processors) - sum(self.budget.values()) rem = [] for j, l in self.budget.items(): e = ceil(j.ret * self.sim.cycles_per_ms) if e <= l: a = e - l L -= a self.budget[j] = e else: rem.append(j) for j in rem: e = ceil(j.ret * self.sim.cycles_per_ms) l = self.budget[j] if e <= window: a = min(e - l, L) else: a = min(window - l, L) self.budget[j] += a L -= a self.last_update = self.sim.now() # There's a new job, the system should be rescheduled. self.reschedule() def on_terminated(self, job): if job in self.budget: del self.budget[job] def update_budget(self): """ Remove budget from the currently executing jobs. """ time_since_last_update = self.sim.now() - self.last_update for job in self.selected_jobs: if job in self.budget: if job.is_active(): self.budget[job] -= time_since_last_update else: del self.budget[job] self.last_update = self.sim.now() def date_next_event(self, selected, not_selected): next_event = None if selected: next_bottom_hitting = min(ceil(y) for _, y in selected) next_event = next_bottom_hitting if not_selected: next_ceiling_hitting = self.next_deadline - self.sim.now() \ - ceil(max(y for _, y in not_selected)) if next_event is None or next_ceiling_hitting < next_event: next_event = next_ceiling_hitting return next_event if next_event else 0 def select_jobs(self): window = self.next_deadline - self.sim.now() res = [(job, b) for job, b in self.budget.items() if window <= ceil(b) and job.is_active()] for job, b in self.budget.items(): if b > 0 and (job, b) not in res and job.is_active(): res.append((job, b)) return (res[:len(self.processors)], res[len(self.processors):]) def schedule(self, cpu): self.waiting_schedule = False self.update_budget() # Sort the jobs by budgets. selected, not_selected = self.select_jobs() # Compute the (relative) date of the next event. next_event = self.date_next_event(selected, not_selected) if next_event > 0: # Set a timer to reschedule the system at that date. self.timer_a = Timer(self.sim, NVNLF.reschedule, (self,), next_event, cpu=cpu, in_ms=False) self.timer_a.start() # Allocate the selected jobs to the processors. # The processors already running selected jobs are not changed. available_procs = [] self.selected_jobs = [s[0] for s in selected] remaining_jobs = self.selected_jobs[:] for proc in self.processors: if proc.running in self.selected_jobs: # This processor keeps running the same job. remaining_jobs.remove(proc.running) else: # This processor is not running a selected job. available_procs.append(proc) # The remaining processors are running the remaining jobs or None. padded_remaining_jobs = remaining_jobs + \ [None] * (len(available_procs) - len(remaining_jobs)) # zip create a list of couples (job, proc) using the list of remaining # jobs and the list of available processors. decisions = list(zip(padded_remaining_jobs, available_procs)) return decisions
class Modified_EDF(Scheduler): def init(self): self.ready_list = [] self.migrating_task1 = None # sous la forme (task, rate) self.migrating_task2 = None self.migrating_job1 = None self.migrating_job2 = None self.next_deadline = 0 def on_activate(self, job): self.ready_list.append(job) job.cpu.resched() def on_terminated(self, job): self.ready_list.remove(job) job.cpu.resched() def conf(self, next_deadline): if next_deadline > self.next_deadline: self.next_deadline = next_deadline self.migrating_task1, self.migrating_task2 = self.migrating_task2, self.migrating_task1 if self.migrating_task1: time_a = ceil((next_deadline - self.sim.now()) * self.migrating_task1[1]) self.timer_a = Timer( self.sim, Modified_EDF.on_end_migrating1, (self,), time_a, cpu=self.processors[0], in_ms=False ) self.timer_a.start() self.migrating_job2 = None if self.migrating_task2: time_b = int((next_deadline - self.sim.now()) * (1 - self.migrating_task2[1])) self.timer_b = Timer( self.sim, Modified_EDF.on_start_migrating2, (self,), time_b, cpu=self.processors[0], in_ms=False ) self.timer_b.start() self.processors[0].resched() if self.migrating_task1: self.migrating_job1 = self.migrating_task1[0].job self.processors[0].resched() else: self.migrating_job1 = None def on_end_migrating1(self): self.migrating_job1 = None self.processors[0].resched() def on_start_migrating2(self): self.migrating_job2 = self.migrating_task2[0].job self.processors[0].resched() def schedule(self, cpu): if self.migrating_job1 and self.migrating_job1.is_active(): return (self.migrating_job1, cpu) if self.migrating_job2 and self.migrating_job2.is_active(): return (self.migrating_job2, cpu) if self.ready_list: job = min(self.ready_list, key=lambda x: x.absolute_deadline) else: job = None return (job, cpu)
class Modified_EDF(Scheduler): def init(self): self.ready_list = [] self.migrating_task1 = None # sous la forme (task, rate) self.migrating_task2 = None self.migrating_job1 = None self.migrating_job2 = None self.next_deadline = 0 def on_activate(self, job): self.ready_list.append(job) job.cpu.resched() def on_terminated(self, job): self.ready_list.remove(job) job.cpu.resched() def conf(self, next_deadline): if next_deadline > self.next_deadline: self.next_deadline = next_deadline self.migrating_task1, self.migrating_task2 = \ self.migrating_task2, self.migrating_task1 if self.migrating_task1: time_a = ceil( (next_deadline - self.sim.now()) * self.migrating_task1[1]) self.timer_a = Timer(self.sim, Modified_EDF.on_end_migrating1, (self, ), time_a, cpu=self.processors[0], in_ms=False) self.timer_a.start() self.migrating_job2 = None if self.migrating_task2: time_b = int((next_deadline - self.sim.now()) * (1 - self.migrating_task2[1])) self.timer_b = Timer(self.sim, Modified_EDF.on_start_migrating2, (self, ), time_b, cpu=self.processors[0], in_ms=False) self.timer_b.start() self.processors[0].resched() if self.migrating_task1: self.migrating_job1 = self.migrating_task1[0].job self.processors[0].resched() else: self.migrating_job1 = None def on_end_migrating1(self): self.migrating_job1 = None self.processors[0].resched() def on_start_migrating2(self): self.migrating_job2 = self.migrating_task2[0].job self.processors[0].resched() def schedule(self, cpu): if self.migrating_job1 and self.migrating_job1.is_active(): return (self.migrating_job1, cpu) if self.migrating_job2 and self.migrating_job2.is_active(): return (self.migrating_job2, cpu) if self.ready_list: job = min(self.ready_list, key=lambda x: x.absolute_deadline) else: job = None return (job, cpu)