|
|
@@ -0,0 +1,461 @@
|
|
|
+AtomicDEVSBlock ResourceHandler {
|
|
|
+ name = "ResourceHandler"
|
|
|
+
|
|
|
+ parameters = 1
|
|
|
+ initialState = "self.state, self.elapsed = {'resources': parameters[0], 'queue': []}, 0.0"
|
|
|
+
|
|
|
+ constructor = """
|
|
|
+ def __init__(self, resources):
|
|
|
+ AtomicDEVS.__init__(self, "__resource_handler")
|
|
|
+ self.state = {'resources': resources, 'queue': []}
|
|
|
+ self.elapsed = 0.0
|
|
|
+ self.resource_in = self.addInPort("resource_in")
|
|
|
+ self.resource_out = self.addOutPort("resource_out")
|
|
|
+ """
|
|
|
+
|
|
|
+ timeAdvance = """
|
|
|
+ if self.state['queue'] and self.state['resources']:
|
|
|
+ # Can grant a resource
|
|
|
+ return 0.0
|
|
|
+ else:
|
|
|
+ # No request queued, or no available resources to handle the request
|
|
|
+ return float('inf')
|
|
|
+ """
|
|
|
+
|
|
|
+ outputFnc = """
|
|
|
+ return {self.resource_out: {'id': self.state['queue'][0]}}
|
|
|
+ """
|
|
|
+
|
|
|
+ intTransition = """
|
|
|
+ # Processed a request that could be processed
|
|
|
+ self.state['resources'] -= 1
|
|
|
+ del self.state['queue'][0]
|
|
|
+ return self.state
|
|
|
+ """
|
|
|
+
|
|
|
+ extTransition = """
|
|
|
+ for inp in inputs[self.resource_in]:
|
|
|
+ if inp['type'] == "request":
|
|
|
+ # Queue the request
|
|
|
+ self.state['queue'].append(inp['id'])
|
|
|
+ elif inp['type'] == "release":
|
|
|
+ # Increment the number of available resources
|
|
|
+ self.state['resources'] += 1
|
|
|
+
|
|
|
+ return self.state
|
|
|
+ """
|
|
|
+}
|
|
|
+
|
|
|
+InputPort rh_ri {
|
|
|
+ name = "resource_in"
|
|
|
+}
|
|
|
+
|
|
|
+OutputPort rh_ro {
|
|
|
+ name = "resource_out"
|
|
|
+}
|
|
|
+
|
|
|
+DEVSBlockToPort (ResourceHandler, rh_ri) {}
|
|
|
+DEVSBlockToPort (ResourceHandler, rh_ro) {}
|
|
|
+
|
|
|
+AtomicDEVSBlock Activity {
|
|
|
+ name = "Activity"
|
|
|
+ parameters = 2
|
|
|
+ initialState = """
|
|
|
+ class ActivityState(object):
|
|
|
+ def __init__(self, name, distribution):
|
|
|
+ self.timer = float('inf')
|
|
|
+ self.mode = "inactive"
|
|
|
+ self.counter = 0
|
|
|
+ self.name = name
|
|
|
+ self.distribution = distribution
|
|
|
+
|
|
|
+ def __str__(self):
|
|
|
+ return str(vars(self))
|
|
|
+
|
|
|
+ def random_sample(self):
|
|
|
+ return self.distribution(self.counter)
|
|
|
+
|
|
|
+ self.state, self.elapsed = ActivityState(parameters[0], parameters[1]), 0.0
|
|
|
+ """
|
|
|
+
|
|
|
+ timeAdvance = """
|
|
|
+ return self.state.timer
|
|
|
+ """
|
|
|
+
|
|
|
+ outputFnc = """
|
|
|
+ if self.state.mode == "active":
|
|
|
+ # Output the control token to the next model in line, and release the resources
|
|
|
+ return {self.control_out: {}, self.resource_out: [{'type': "release"}]}
|
|
|
+ elif self.state.mode == "request_resource":
|
|
|
+ # Output a request for resources with a specified ID (used to find out whether this was our request)
|
|
|
+ return {self.resource_out: [{'type': "request", 'id': "%s-%s" % (self.state.name, self.state.counter)}]}
|
|
|
+ else:
|
|
|
+ return {}
|
|
|
+ """
|
|
|
+
|
|
|
+ intTransition = """
|
|
|
+ self.state.timer -= self.timeAdvance()
|
|
|
+ if self.state.mode == "request_resource":
|
|
|
+ # Go and request the required resource
|
|
|
+ self.state.mode = "wait_resource"
|
|
|
+ self.state.timer = float('inf')
|
|
|
+ elif self.state.mode == "active":
|
|
|
+ # Finished execution, so release resources
|
|
|
+ self.state.mode = "inactive"
|
|
|
+ self.state.timer = 0.0
|
|
|
+ self.state.timer = float('inf')
|
|
|
+ self.state.counter += 1
|
|
|
+ return self.state
|
|
|
+ """
|
|
|
+
|
|
|
+ extTransition = """
|
|
|
+ self.state.timer -= self.elapsed
|
|
|
+ if self.state.mode == "inactive" and self.control_in in inputs:
|
|
|
+ # Got control token, so ask for the required resources
|
|
|
+ self.state.mode = "request_resource"
|
|
|
+ self.state.timer = 0.0
|
|
|
+ # NOTE this violates DEVS, though is easy to debug
|
|
|
+ #print("Activate " + str(self.state.name) + " at time " + str(self.time_last[0] + self.elapsed))
|
|
|
+ elif self.state.mode == "wait_resource" and self.resource_in in inputs and inputs[self.resource_in]['id'] == "%s-%s" % (self.state.name, self.state.counter):
|
|
|
+ # Got required resources, so start execution
|
|
|
+ self.state.mode = "active"
|
|
|
+ self.state.timer = self.state.random_sample()
|
|
|
+ return self.state
|
|
|
+ """
|
|
|
+}
|
|
|
+
|
|
|
+InputPort act_ri {
|
|
|
+ name = "resource_in"
|
|
|
+}
|
|
|
+
|
|
|
+OutputPort act_ro {
|
|
|
+ name = "resource_out"
|
|
|
+}
|
|
|
+
|
|
|
+DEVSBlockToPort (Activity, act_ri) {}
|
|
|
+DEVSBlockToPort (Activity, act_ro) {}
|
|
|
+
|
|
|
+AtomicDEVSBlock ParallelSplit {
|
|
|
+ name = "ParallelSplit"
|
|
|
+ parameters = 0
|
|
|
+
|
|
|
+ initialState = "self.state, self.elapsed = False, 0.0"
|
|
|
+
|
|
|
+ timeAdvance = """
|
|
|
+ if self.state:
|
|
|
+ return 0.0
|
|
|
+ else:
|
|
|
+ return float('inf')
|
|
|
+ """
|
|
|
+
|
|
|
+ outputFnc = """
|
|
|
+ return {self.control_out: {}}
|
|
|
+ """
|
|
|
+
|
|
|
+ intTransition = """
|
|
|
+ return False
|
|
|
+ """
|
|
|
+
|
|
|
+ extTransition = """
|
|
|
+ return True
|
|
|
+ """
|
|
|
+}
|
|
|
+
|
|
|
+InputPort split_ci {
|
|
|
+ name = "control_in"
|
|
|
+}
|
|
|
+
|
|
|
+OutputPort split_co {
|
|
|
+ name = "control_out"
|
|
|
+}
|
|
|
+
|
|
|
+DEVSBlockToPort (ParallelSplit, split_ci) {}
|
|
|
+DEVSBlockToPort (ParallelSplit, split_co) {}
|
|
|
+
|
|
|
+AtomicDEVSBlock ParallelSplit {
|
|
|
+ name = "ParallelSplit"
|
|
|
+ parameters = 0
|
|
|
+
|
|
|
+ initialState = "self.state, self.elapsed = False, 0.0"
|
|
|
+
|
|
|
+ timeAdvance = """
|
|
|
+ if self.state:
|
|
|
+ return 0.0
|
|
|
+ else:
|
|
|
+ return float('inf')
|
|
|
+ """
|
|
|
+
|
|
|
+ outputFnc = """
|
|
|
+ return {self.control_out: {}}
|
|
|
+ """
|
|
|
+
|
|
|
+ intTransition = """
|
|
|
+ return False
|
|
|
+ """
|
|
|
+
|
|
|
+ extTransition = """
|
|
|
+ return True
|
|
|
+ """
|
|
|
+}
|
|
|
+
|
|
|
+InputPort split_ci {
|
|
|
+ name = "control_in"
|
|
|
+}
|
|
|
+
|
|
|
+OutputPort split_co {
|
|
|
+ name = "control_out"
|
|
|
+}
|
|
|
+
|
|
|
+DEVSBlockToPort (ParallelSplit, split_ci) {}
|
|
|
+DEVSBlockToPort (ParallelSplit, split_co) {}
|
|
|
+
|
|
|
+AtomicDEVSBlock Synchronization {
|
|
|
+ name = "Synchronization"
|
|
|
+ parameters = 1
|
|
|
+
|
|
|
+ initialState = "self.state, self.elapsed = {'current': parameters[0], 'max': parameters[0]}, 0.0"
|
|
|
+
|
|
|
+ timeAdvance = """
|
|
|
+ if self.state['current'] == 0:
|
|
|
+ return 0.0
|
|
|
+ else:
|
|
|
+ return float('inf')
|
|
|
+ """
|
|
|
+
|
|
|
+ outputFnc = """
|
|
|
+ return {self.control_out: {}}
|
|
|
+ """
|
|
|
+
|
|
|
+ intTransition = """
|
|
|
+ self.state['current'] = self.state['max']
|
|
|
+ return self.state
|
|
|
+ """
|
|
|
+
|
|
|
+ extTransition = """
|
|
|
+ self.state['current'] -= 1
|
|
|
+ return self.state
|
|
|
+ """
|
|
|
+}
|
|
|
+
|
|
|
+InputPort syn_ci {
|
|
|
+ name = "control_in"
|
|
|
+}
|
|
|
+
|
|
|
+OutputPort syn_co {
|
|
|
+ name = "control_out"
|
|
|
+}
|
|
|
+
|
|
|
+DEVSBlockToPort (Synchronization, syn_ri) {}
|
|
|
+DEVSBlockToPort (Synchronization, syn_ro) {}
|
|
|
+
|
|
|
+AtomicDEVSBlock ExclusiveChoice {
|
|
|
+ name = "ExclusiveChoice"
|
|
|
+ parameters = 1
|
|
|
+
|
|
|
+ initialState = """
|
|
|
+ class ExclusiveChoiceState(object):
|
|
|
+ def __init__(self, distribution):
|
|
|
+ self.counter = 0
|
|
|
+ self.choice = None
|
|
|
+ self.distribution = distribution
|
|
|
+
|
|
|
+ def __str__(self):
|
|
|
+ return str(vars(self))
|
|
|
+
|
|
|
+ def make_choice(self):
|
|
|
+ return self.distribution(self.counter)
|
|
|
+
|
|
|
+ self.state, self.elapsed = ExclusiveChoiceState(parameters[0]), 0.0
|
|
|
+ """
|
|
|
+
|
|
|
+ timeAdvance = """
|
|
|
+ if self.state.choice is not None:
|
|
|
+ return 0.0
|
|
|
+ else:
|
|
|
+ return float('inf')
|
|
|
+ """
|
|
|
+
|
|
|
+ outputFnc = """
|
|
|
+ if self.state.choice == 0:
|
|
|
+ return {self.control_out1: {}}
|
|
|
+ else:
|
|
|
+ return {self.control_out2: {}}
|
|
|
+ """
|
|
|
+
|
|
|
+ intTransition = """
|
|
|
+ self.state.choice = None
|
|
|
+ self.state.counter += 1
|
|
|
+ return self.state
|
|
|
+ """
|
|
|
+
|
|
|
+ extTransition = """
|
|
|
+ # Got a control token, so have to make a choice
|
|
|
+ self.state.choice = self.state.make_choice()
|
|
|
+ return self.state
|
|
|
+ """
|
|
|
+}
|
|
|
+
|
|
|
+InputPort xor_ci {
|
|
|
+ name = "control_in"
|
|
|
+}
|
|
|
+
|
|
|
+OutputPort xor_co1 {
|
|
|
+ name = "control_out1"
|
|
|
+}
|
|
|
+
|
|
|
+OutputPort xor_co2 {
|
|
|
+ name = "control_out2"
|
|
|
+}
|
|
|
+
|
|
|
+DEVSBlockToPort (ExclusiveChoice, xor_ci) {}
|
|
|
+DEVSBlockToPort (ExclusiveChoice, xor_co1) {}
|
|
|
+DEVSBlockToPort (ExclusiveChoice, xor_co2) {}
|
|
|
+
|
|
|
+AtomicDEVSBlock SimpleMerge {
|
|
|
+ name = "SimpleMerge"
|
|
|
+ parameters = 0
|
|
|
+
|
|
|
+ initialState = "self.state, self.elapsed = False, 0.0"
|
|
|
+
|
|
|
+ timeAdvance = """
|
|
|
+ if self.state:
|
|
|
+ return 0.0
|
|
|
+ else:
|
|
|
+ return float('inf')
|
|
|
+ """
|
|
|
+
|
|
|
+ outputFnc = """
|
|
|
+ return {self.control_out: {}}
|
|
|
+ """
|
|
|
+
|
|
|
+ intTransition = """
|
|
|
+ return False
|
|
|
+ """
|
|
|
+
|
|
|
+ extTransition = """
|
|
|
+ return True
|
|
|
+ """
|
|
|
+}
|
|
|
+
|
|
|
+InputPort or_ci {
|
|
|
+ name = "control_in"
|
|
|
+}
|
|
|
+
|
|
|
+OutputPort or_co {
|
|
|
+ name = "control_out"
|
|
|
+}
|
|
|
+
|
|
|
+DEVSBlockToPort (SimpleMerge, or_ci) {}
|
|
|
+DEVSBlockToPort (SimpleMerge, or_co) {}
|
|
|
+
|
|
|
+AtomicDEVSBlock MultiInstance {
|
|
|
+ name = "MultiInstance"
|
|
|
+ parameters = 2
|
|
|
+
|
|
|
+ initialState = """
|
|
|
+ class MultiInstanceState(object):
|
|
|
+ def __init__(self, name, num, distribution):
|
|
|
+ self.spawned = num
|
|
|
+ self.collected = 0
|
|
|
+ self.counter = 0
|
|
|
+ self.mode = "inactive"
|
|
|
+ self.running_tasks = []
|
|
|
+ self.requested = []
|
|
|
+ self.name = name
|
|
|
+ self.distribution = distribution
|
|
|
+
|
|
|
+ def __str__(self):
|
|
|
+ return str(vars(self))
|
|
|
+
|
|
|
+ def task_time(self):
|
|
|
+ return self.distribution(self.counter)
|
|
|
+
|
|
|
+ self.state, self.elapsed = MultiInstanceState(self.name, parameters[0], parameters[1])
|
|
|
+ """
|
|
|
+
|
|
|
+ timeAdvance = """
|
|
|
+ if self.state.mode == "finish":
|
|
|
+ return 0.0
|
|
|
+ elif self.state.running_tasks:
|
|
|
+ return self.state.running_tasks[0][0]
|
|
|
+ elif self.state.mode == "request_resources":
|
|
|
+ return 0.0
|
|
|
+ else:
|
|
|
+ return float('inf')
|
|
|
+ """
|
|
|
+
|
|
|
+ outputFnc = """
|
|
|
+ if self.state.mode == "request_resources":
|
|
|
+ # Request all resources in one go
|
|
|
+ return {self.resource_out: [{'type': 'request', 'id': i} for i in self.state.requested]}
|
|
|
+ elif self.state.mode == "active":
|
|
|
+ # Finished an instance, so release it
|
|
|
+ return {self.resource_out: [{'type': 'release'}]}
|
|
|
+ elif self.state.mode == "finish":
|
|
|
+ # Finished execution of all, so pass on token
|
|
|
+ return {self.control_out: {}}
|
|
|
+ else:
|
|
|
+ return {}
|
|
|
+ """
|
|
|
+
|
|
|
+ intTransition = """
|
|
|
+ ta = self.timeAdvance()
|
|
|
+ for t in self.state.running_tasks:
|
|
|
+ t[0] -= ta
|
|
|
+
|
|
|
+ if self.state.mode == "active":
|
|
|
+ # Finished an instance, so pop it
|
|
|
+ del self.state.running_tasks[0]
|
|
|
+ self.state.collected += 1
|
|
|
+ if self.state.collected == self.state.spawned:
|
|
|
+ self.state.mode = "finish"
|
|
|
+ elif self.state.mode == "request_resources":
|
|
|
+ # Requested resources, so be ready for a response
|
|
|
+ self.state.mode = "active"
|
|
|
+ elif self.state.mode == "finish":
|
|
|
+ self.state.mode = "inactive"
|
|
|
+ self.state.collected = 0
|
|
|
+ self.state.counter += 1
|
|
|
+ self.state.running_tasks = []
|
|
|
+ return self.state
|
|
|
+ """
|
|
|
+
|
|
|
+ extTransition = """
|
|
|
+ # Got input, so have to spawn #num of them
|
|
|
+ for t in self.state.running_tasks:
|
|
|
+ t[0] -= self.elapsed
|
|
|
+
|
|
|
+ if self.state.mode == "inactive" and self.control_in in inputs:
|
|
|
+ self.state.mode = "request_resources"
|
|
|
+ self.state.requested = ["%s-%s-%s" % (self.state.name, self.state.counter, i) for i in range(self.state.spawned)]
|
|
|
+
|
|
|
+ if self.state.mode in ["active", "release_resource"] and self.resource_in in inputs:
|
|
|
+ # Got a resource, so allocate it to an activity
|
|
|
+ self.state.running_tasks.append([self.state.task_time(), self.state.requested.pop(0)])
|
|
|
+ # NOTE this violates DEVS, though is easy to debug
|
|
|
+ #print("Spawn " + str(self.state.running_tasks[-1][1]) + " at time " + str(self.time_last[0] + self.elapsed))
|
|
|
+ self.state.running_tasks.sort()
|
|
|
+ return self.state
|
|
|
+ """
|
|
|
+}
|
|
|
+
|
|
|
+InputPort mi_ci {
|
|
|
+ name = "control_in"
|
|
|
+}
|
|
|
+
|
|
|
+OutputPort mu_co {
|
|
|
+ name = "control_out"
|
|
|
+}
|
|
|
+
|
|
|
+InputPort mi_ri {
|
|
|
+ name = "resource_in"
|
|
|
+}
|
|
|
+
|
|
|
+OutputPort mu_ro {
|
|
|
+ name = "resource_out"
|
|
|
+}
|
|
|
+
|
|
|
+DEVSBlockToPort (MultiInstance, mi_ci) {}
|
|
|
+DEVSBlockToPort (MultiInstance, mi_co) {}
|
|
|
+DEVSBlockToPort (MultiInstance, mi_ri) {}
|
|
|
+DEVSBlockToPort (MultiInstance, mi_ro) {}
|