class Disk(Process): mean_service_time = 0.02 # Mean service time for one IO request. def reset(self): self.state = TSeries(numeric=False, time_fnc=self.sim.clock.get) self.state.collect("Idle") @Chain def initialize(self): sim = self.sim queue = sim.members["Queue"] while True: if queue.size.get() == 0: self.state.collect("Idle") yield Poll.greater_than(0, queue.size) self.state.collect("Busy") io_request = queue.get() io_request.service = sim.time yield sample.nonnegative(sim.rng.expovariate, 1.0 / Disk.mean_service_time) io_request.departure = self.sim.time queue.collect(io_request) def finalize(self): queue = self.sim.members["Queue"] if queue.running: queue.stop() # Make sure to finalize the queue before the disk. self.state.collect(self.state.last_value()) self.state.pareto_chart(axes=queue.plotter, title=self.name) print self, "utilization:", self.state.wrel_frequency("Busy")
class PhysicalCPU(Process): clients = [] speed = 1.0 def status(self): if len(self.clients) == 0: return "idle" client_speed = 100.0 / len(self.clients) * self.speed lines = ["%d clients (%.02f%% to each)" % (len(self.clients), client_speed)] lines.extend(client.path for client in self.clients) return "\n".join(lines) def reset(self): self.state = TSeries(numeric=False, time_fnc=self.sim.clock.get) self.state.collect("Idle") self.clients = set() def finalize(self): self.state.collect("Idle" if len(self.clients) == 0 else "Busy") @Chain def acquire(self, client): yield Chain.result(self) if len(self.clients) == 0: self.state.collect("Busy") self.clients.add(client) self.update() def release(self, client): self.clients.remove(client) if len(self.clients) == 0: self.state.collect("Idle") else: self.update() def update(self): if len(self.clients) > 0: client_speed = self.speed / len(self.clients) for client in self.clients: client.set_speed(client_speed) def utilization(self): return self.state.wrel_frequency("Busy") * 100.0
class DiskFIFO(Process): """A first-in-first-out disk.""" current = None def status(self): if self.current is None: return "idle" lines = ["%s (%d queued)" % (self.current, len(self.queue))] lines.extend(client.path for client in self.queue) return "\n".join(lines) def reset(self): self.state = TSeries(numeric=False, time_fnc=self.sim.clock.get) self.state.collect("Idle") self.current = None self.queue = Deque() def finalize(self): self.state.collect("Idle" if self.current is None else "Busy") @Chain def acquire(self, client): yield Chain.result(self) if self.current is None: self.current = client self.state.collect("Busy") raise Chain.success() self.queue.append(client) yield Action() # suspend until activated by release() def release(self, client): assert client is self.current if len(self.queue) > 0: self.current = self.queue.popleft() self.current.action.succeed() # activate next in line else: self.current = None self.state.collect("Idle") def utilization(self): return self.state.wrel_frequency("Busy") * 100.0
class Agent(Process): """Necessary configuration parameters: skills :: [skill] service_time :: {need: float} """ client = None def status(self): if self.client is None: return "idle" return "%s (%s)" % (self.client.name, self.client.need) def reset(self): self.client = None self.state = TSeries(numeric=False, time_fnc=self.sim.clock.get) @Chain def initialize(self): sim = self.sim queue = sim.members["queue"] self.state.collect("idle") while True: self.state.collect("idle") self.client = (yield queue.content.get(filter=self.can_answer)).result yield 0.0 self.client.action.fail() # cause the timeout to fail self.state.collect("busy") yield self.service_time[self.client.need] self.client = None def finalize(self): results = self.sim.simulation.results if "utilization" not in results: results.utilization = Namespace() self.state.collect("idle" if self.client is None else "busy") results.utilization[self.path] = self.state.wrel_frequency("busy") def can_answer(self, client): # filter function for Store.content.get() return client.need in self.skills
class PSQueue(Process): """Single-server processor sharing queue. This is used to represent how processes or threads run in time-sharing mode in modern operating systems.""" remaining = {} # {request: remaining_servtime} def status(self): lines = ["%d requests" % (len(self.remaining),)] for request, remaining in self.remaining.iteritems(): lines.append("%s (remaining=%f)" % (request.owner.name, remaining)) return "\n".join(lines) def reset(self): self.remaining = {} self.ongoing = Checkable(0) self.state = TSeries(numeric=False, time_fnc=self.sim.clock.get) self.finishing = False self.start_time = None @Chain def initialize(self): while True: if len(self.remaining) == 0: self.state.collect("Idle") yield Poll.greater_than(0, self.ongoing) self.state.collect("Busy") self.start_time = self.sim.time nprocs = len(self.remaining) delay = Delay(min(self.remaining.itervalues()) * nprocs) yield delay self.update() if delay.failed(): # Interrupted by put_request(), wait until it exits yield Action() def finalize(self): self.state.collect("Idle" if len(self.remaining) == 0 else "Busy") def put_request(self, process, servtime): request = Request(servtime) request.bind(process) interrupted = False if len(self.remaining) > 0 and not self.finishing: self.action.fail() interrupted = True self.remaining[request] = servtime self.ongoing.set(len(self.remaining)) if interrupted: self.action.succeed() return request def update(self): # Update remaining service times and check for finished requests. nprocs = len(self.remaining) elapsed = (self.sim.time - self.start_time) / nprocs finished = [] for request, remaining in self.remaining.iteritems(): # This is required because of damn floating point arithmetic errors... if remaining - elapsed < 1e-6: finished.append(request) else: self.remaining[request] = remaining - elapsed # Remove finished requests. if len(finished) > 0: self.finishing = True for request in finished: del self.remaining[request] request.fulfill() self.ongoing.set(len(self.remaining)) self.finishing = False def utilization(self): return self.state.wrel_frequency("Busy") * 100.0