[haizea-commit] r603 - in branches/TP2.0: src/haizea/core src/haizea/core/enact src/haizea/core/scheduler tests

haizea-commit at mailman.cs.uchicago.edu haizea-commit at mailman.cs.uchicago.edu
Mon Jul 13 11:35:50 CDT 2009


Author: borja
Date: 2009-07-13 11:35:44 -0500 (Mon, 13 Jul 2009)
New Revision: 603

Modified:
   branches/TP2.0/src/haizea/core/enact/__init__.py
   branches/TP2.0/src/haizea/core/enact/opennebula.py
   branches/TP2.0/src/haizea/core/enact/simulated.py
   branches/TP2.0/src/haizea/core/leases.py
   branches/TP2.0/src/haizea/core/manager.py
   branches/TP2.0/src/haizea/core/scheduler/mapper.py
   branches/TP2.0/src/haizea/core/scheduler/resourcepool.py
   branches/TP2.0/src/haizea/core/scheduler/slottable.py
   branches/TP2.0/src/haizea/core/scheduler/vm_scheduler.py
   branches/TP2.0/tests/common.py
   branches/TP2.0/tests/sample_slottables.py
   branches/TP2.0/tests/test_mapper.py
   branches/TP2.0/tests/test_slottable.py
Log:
- Forked ResourceTuple into two classes: ResourceTuple (only used by the scheduler) and Capacity (used by higher-level modules). 
- Implemented multi-instance resource types (e.g., multiple CPUs per node).

Modified: branches/TP2.0/src/haizea/core/enact/__init__.py
===================================================================
--- branches/TP2.0/src/haizea/core/enact/__init__.py	2009-07-07 10:43:04 UTC (rev 602)
+++ branches/TP2.0/src/haizea/core/enact/__init__.py	2009-07-13 16:35:44 UTC (rev 603)
@@ -17,7 +17,6 @@
 # -------------------------------------------------------------------------- #
 
 from haizea.common.utils import abstract
-from haizea.core.scheduler.slottable import ResourceTuple
 
 class ResourcePoolInfo(object):
     def __init__(self):

Modified: branches/TP2.0/src/haizea/core/enact/opennebula.py
===================================================================
--- branches/TP2.0/src/haizea/core/enact/opennebula.py	2009-07-07 10:43:04 UTC (rev 602)
+++ branches/TP2.0/src/haizea/core/enact/opennebula.py	2009-07-13 16:35:44 UTC (rev 603)
@@ -17,7 +17,7 @@
 # -------------------------------------------------------------------------- #
 
 from haizea.core.scheduler import EnactmentError
-from haizea.core.scheduler.resourcepool import Node
+from haizea.core.scheduler.resourcepool import ResourcePoolNode
 from haizea.core.scheduler.slottable import ResourceTuple
 from haizea.core.enact import ResourcePoolInfo, VMEnactment, DeploymentEnactment
 from haizea.common.utils import get_config

Modified: branches/TP2.0/src/haizea/core/enact/simulated.py
===================================================================
--- branches/TP2.0/src/haizea/core/enact/simulated.py	2009-07-07 10:43:04 UTC (rev 602)
+++ branches/TP2.0/src/haizea/core/enact/simulated.py	2009-07-13 16:35:44 UTC (rev 603)
@@ -16,8 +16,7 @@
 # limitations under the License.                                             #
 # -------------------------------------------------------------------------- #
 
-from haizea.core.scheduler.resourcepool import Node
-from haizea.core.scheduler.slottable import ResourceTuple
+from haizea.core.scheduler.resourcepool import ResourcePoolNode
 from haizea.core.enact import ResourcePoolInfo, VMEnactment, DeploymentEnactment
 import haizea.common.constants as constants
 from haizea.common.utils import get_config
@@ -51,7 +50,7 @@
         
         nodes = site.nodes.get_all_nodes()
         
-        self.nodes = [Node(id, "simul-%i" % id, capacity) for (id, capacity) in nodes.items()]
+        self.nodes = [ResourcePoolNode(id, "simul-%i" % id, capacity) for (id, capacity) in nodes.items()]
         for n in self.nodes:
             n.enactment_info = n.nod_id      
         
@@ -74,8 +73,8 @@
             # Unpack action
             pnode = action.vnodes[vnode].pnode
             image = action.vnodes[vnode].diskimage
-            cpu = action.vnodes[vnode].resources.get_by_type(constants.RES_CPU)
-            memory = action.vnodes[vnode].resources.get_by_type(constants.RES_MEM)
+            cpu = 100 #action.vnodes[vnode].resources.get_by_type(constants.RES_CPU)
+            memory = 1024 #action.vnodes[vnode].resources.get_by_type(constants.RES_MEM)
             self.logger.debug("Received request to start VM for L%iV%i on host %i, image=%s, cpu=%i, mem=%i"
                          % (action.lease_haizea_id, vnode, pnode, image, cpu, memory))
     
@@ -108,12 +107,15 @@
                 
         self.bandwidth = config.get("imagetransfer-bandwidth")
         
-        imgcapacity = ResourceTuple.create_empty()
-        imgcapacity.set_by_type(constants.RES_NETOUT, self.bandwidth)
+        # Commenting for now
+        #imgcapacity = ResourceTuple.create_empty()
+        #imgcapacity.set_by_type(constants.RES_NETOUT, self.bandwidth)
 
+        imgcapacity = None
+
         # TODO: Determine node number based on site
-        self.fifo_node = Node(1000, "FIFOnode", imgcapacity)
-        self.edf_node = Node(1001, "EDFnode", imgcapacity)
+        self.fifo_node = ResourcePoolNode(1000, "FIFOnode", imgcapacity)
+        self.edf_node = ResourcePoolNode(1001, "EDFnode", imgcapacity)
         
     def get_edf_node(self):
         return self.edf_node
@@ -121,8 +123,9 @@
     def get_fifo_node(self):
         return self.fifo_node       
     
+    # Commenting for now
     def get_aux_nodes(self):
-        return [self.edf_node, self.fifo_node] 
+        return [] #[self.edf_node, self.fifo_node] 
     
     def get_bandwidth(self):
         return self.bandwidth

Modified: branches/TP2.0/src/haizea/core/leases.py
===================================================================
--- branches/TP2.0/src/haizea/core/leases.py	2009-07-07 10:43:04 UTC (rev 602)
+++ branches/TP2.0/src/haizea/core/leases.py	2009-07-13 16:35:44 UTC (rev 603)
@@ -349,6 +349,30 @@
     def __init__(self):
         StateMachine.__init__(self, LeaseStateMachine.initial_state, LeaseStateMachine.transitions, Lease.state_str)
 
+class Capacity(object):
+    def __init__(self, types):
+        self.ninstances = dict([(type, 1) for type in types])
+        self.quantity = dict([(type, [0]) for type in types])
+        
+    def get_quantity(self, type):
+        return self.get_quantity_instance(type, 1)
+    
+    def get_quantity_instance(self, type, instance):
+        return self.quantity[type][instance-1]
+
+    def set_quantity(self, type, amount):
+        self.set_quantity_instance(type, 1, amount)
+    
+    def set_quantity_instance(self, type, instance, amount):
+        self.quantity[type][instance-1] = amount
+    
+    def set_ninstances(self, type, ninstances):
+        self.ninstances[type] = ninstances
+        self.quantity[type] = [0 for i in range(ninstances)]
+        
+    def get_resource_types(self):
+        return self.quantity.keys()
+
 class Timestamp(object):
     def __init__(self, requested):
         self.requested = requested
@@ -449,12 +473,25 @@
         self.resource_types = resource_types
         self.attr_types = attr_types
         
-    def add_resource(self, name, amount):
-        from haizea.core.scheduler.slottable import ResourceTuple
-        ResourceTuple.add_resource_type(name)
-        self.resource_types.add(name)
-        self.nodes.add_resource(name, amount)
+    def add_resource(self, name, amounts):
+        self.resource_types.append(name)
+        self.nodes.add_resource(name, amounts)
         
+    def create_empty_resource_quantity(self):
+        return Capacity(self.resource_types)
+    
+    def get_resource_types_with_max_instances(self):
+        max_ninstances = dict((rt, 1) for rt in self.resource_types)
+        for node_set in self.nodes.node_sets:
+            capacity = node_set[1]
+            for resource_type in capacity.get_resource_types():
+                if capacity.ninstances[resource_type] > max_ninstances[resource_type]:
+                    max_ninstances[resource_type] = capacity.ninstances[resource_type]
+                    
+        max_ninstances = [(rt,max_ninstances[rt]) for rt in self.resource_types]
+
+        return max_ninstances
+    
     @classmethod
     def from_xml_file(cls, xml_file):
         return cls.__from_xml_element(ET.parse(xml_file).getroot())        
@@ -464,19 +501,25 @@
         return cls.__from_xml_element(ET.parse(xml_file).getroot().find("site"))        
         
     @classmethod
-    def __from_xml_element(cls, site_element):
-        from haizea.core.scheduler.slottable import ResourceTuple
-        
+    def __from_xml_element(cls, site_element):        
         resource_types = site_element.find("resource-types")
-        resource_types = set(resource_types.get("names").split())
-        for resource_type in resource_types:
-            ResourceTuple.add_resource_type(resource_type)
+        resource_types = resource_types.get("names").split()
        
         # TODO: Attributes
+        attrs = []
         
         nodes = Nodes.from_xml_element(site_element.find("nodes"))
 
-        return cls(nodes, resource_types, None)
+        # Validate nodes
+        for node_set in nodes.node_sets:
+            capacity = node_set[1]
+            for resource_type in capacity.get_resource_types():
+                print resource_type, resource_types
+                if resource_type not in resource_types:
+                    # TODO: Raise something more meaningful
+                    raise Exception
+
+        return cls(nodes, resource_types, attrs)
     
     @classmethod
     def from_resources_string(cls, resource_str):
@@ -516,24 +559,33 @@
                 nodenum += 1     
         return nodes   
                 
-    def add_resource(self, type, amount):
+    def add_resource(self, type, amounts):
         for node_set in self.node_sets:
             r = node_set[1]
-            r.set_by_type(type, amount)
+            r.set_ninstances(type, len(amounts))
+            for ninstance, amount in enumerate(amounts):
+                r.set_quantity_instance(type, ninstance+1, amount)
 
     @classmethod
     def from_xml_element(cls, nodes_element):
-        from haizea.core.scheduler.slottable import ResourceTuple
-
         nodesets = []
         nodesets_elems = nodes_element.findall("node-set")
         for nodeset_elem in nodesets_elems:
-            r = ResourceTuple.create_empty()
+            r = Capacity([])
             resources = nodeset_elem.findall("res")
             for i, res in enumerate(resources):
                 type = res.get("type")
-                amount = int(res.get("amount"))
-                r.set_by_type(type, amount)
+                if len(res.getchildren()) == 0:
+                    amount = int(res.get("amount"))
+                    r.set_ninstances(type, 1)
+                    r.set_quantity(type, amount)
+                else:
+                    instances = res.findall("instance")
+                    r.set_ninstances(type, len(instances))
+                    for i, instance in enumerate(instances):
+                        amount = int(instance.get("amount"))
+                        r.set_quantity_instance(type, i+1, amount)
+                                     
             numnodes = int(nodeset_elem.get("numnodes"))
 
             nodesets.append((numnodes,r))

Modified: branches/TP2.0/src/haizea/core/manager.py
===================================================================
--- branches/TP2.0/src/haizea/core/manager.py	2009-07-07 10:43:04 UTC (rev 602)
+++ branches/TP2.0/src/haizea/core/manager.py	2009-07-13 16:35:44 UTC (rev 603)
@@ -149,9 +149,10 @@
             resourcepool = ResourcePool(info_enact, vm_enact, deploy_enact)
     
         # Slot table
-        slottable = SlotTable()
+        slottable = SlotTable(site.get_resource_types_with_max_instances())
         for n in resourcepool.get_nodes() + resourcepool.get_aux_nodes():
-            slottable.add_node(n)
+            rt = slottable.create_resource_tuple_from_capacity(n.capacity)
+            slottable.add_node(rt)
 
         # Policy engine
         self.policy = SimplePolicy(slottable)

Modified: branches/TP2.0/src/haizea/core/scheduler/mapper.py
===================================================================
--- branches/TP2.0/src/haizea/core/scheduler/mapper.py	2009-07-07 10:43:04 UTC (rev 602)
+++ branches/TP2.0/src/haizea/core/scheduler/mapper.py	2009-07-13 16:35:44 UTC (rev 603)
@@ -56,7 +56,7 @@
             capacity = requested_resources[vnode]
             maxend = end 
             for pnode in pnodes:
-                need_to_map = ResourceTuple.create_empty()
+                need_to_map = self.slottable.create_empty_resource_tuple()
                 need_to_map.incr(capacity)
                 avail=aw.get_availability_at_node(start, pnode, preempted_leases = preempting)
                 pnode_done = False
@@ -146,19 +146,18 @@
         return nodes        
 
     def __sort_vnodes(self, requested_resources):
-        max_res = ResourceTuple.create_empty()
+        max_res = self.slottable.create_empty_resource_tuple()
         for res in requested_resources.values():
-            for t in ResourceTuple.get_resource_types():
-                v = res.get_by_type(t)
-                if v > max_res.get_by_type(t):
-                    max_res.set_by_type(t,v)
+            for i in range(len(res._res)):
+                if res._res[i] > max_res._res[i]:
+                    max_res._res[i] = res._res[i]
                     
         norm_res = {}
         for k,v in requested_resources.items():
             norm_capacity = 0
-            for t in ResourceTuple.get_resource_types():
-                if max_res.get_by_type(t) > 0:
-                    norm_capacity += v.get_by_type(t) / float(max_res.get_by_type(t))
+            for i in range(len(max_res._res)):
+                if max_res._res[i] > 0:
+                    norm_capacity += v._res[i] / float(max_res._res[i])
             norm_res[k] = norm_capacity
              
         vnodes = norm_res.items()

Modified: branches/TP2.0/src/haizea/core/scheduler/resourcepool.py
===================================================================
--- branches/TP2.0/src/haizea/core/scheduler/resourcepool.py	2009-07-07 10:43:04 UTC (rev 602)
+++ branches/TP2.0/src/haizea/core/scheduler/resourcepool.py	2009-07-13 16:35:44 UTC (rev 603)
@@ -166,7 +166,7 @@
     def get_max_disk_usage(self):
         return max([n.get_disk_usage() for n in self.nodes])
     
-class Node(object):
+class ResourcePoolNode(object):
     def __init__(self, nod_id, hostname, capacity):
         self.logger = logging.getLogger("RESOURCEPOOL")
         self.nod_id = nod_id
@@ -308,7 +308,7 @@
         return self.get_node(pnode_id).exists_reusable_image(diskimage_id, after = after)
     
     
-class NodeWithReusableImages(Node):
+class ResourcePoolNodeWithReusableImages(ResourcePoolNode):
     def __init__(self, nod_id, hostname, capacity):
         Node.__init__(self, nod_id, hostname, capacity)
         self.reusable_images = []

Modified: branches/TP2.0/src/haizea/core/scheduler/slottable.py
===================================================================
--- branches/TP2.0/src/haizea/core/scheduler/slottable.py	2009-07-07 10:43:04 UTC (rev 602)
+++ branches/TP2.0/src/haizea/core/scheduler/slottable.py	2009-07-13 16:35:44 UTC (rev 603)
@@ -40,70 +40,67 @@
     
     This class ...
     
-    """       
-    type2pos = {}
-    pos2type = {}
-    nres = 0
+    """    
+    SINGLE_INSTANCE = 1
+    MULTI_INSTANCE = 2
     
-    def __init__(self, res):
+    def __init__(self, slottable, res):
+        self.slottable = slottable
         self._res = res
-        
-    @classmethod
-    def from_list(cls, l):
-        return cls(l[:])
+        if self.slottable.has_multiinst:
+            self.multiinst = dict([(i,[]) for i in range(self.slottable.rtuple_len, self.slottable.rtuple_nres)])
 
     @classmethod
     def copy(cls, rt):
-        return cls(rt._res[:])
-    
-    @classmethod
-    def add_resource_type(cls, name):
-        if name in cls.type2pos:
-            # Can't add a resourcetype more than once
-            # TODO: Raise something more meaningful
-            raise
-        cls.type2pos[name] = cls.nres
-        cls.pos2type[cls.nres] = name
-        cls.nres += 1
-
-    @classmethod
-    def get_resource_types(cls):
-        return cls.type2pos.keys()
-
-    @classmethod
-    def create_empty(cls):
-        return cls([0 for x in range(cls.nres)])
+        rt2 = cls(rt.slottable, rt._res[:])
+        if rt.slottable.has_multiinst:
+            rt2.multiinst = dict([(i, l[:]) for (i,l) in rt.multiinst.items()])
+        return rt2 
         
     def fits_in(self, res2):
-        fits = True
-        for i in xrange(len(self._res)):
+        for i in xrange(self.slottable.rtuple_len):
             if self._res[i] > res2._res[i]:
-                fits = False
-                break
-        return fits
+                return False
+        if self.slottable.has_multiinst:
+            multiinst2 = dict([(i, l[:]) for (i,l) in res2.multiinst.items()])
+            for (pos, l) in self.multiinst.items():
+                insts = multiinst2[pos]
+                for quantity in l:
+                    fits = False
+                    for i in range(len(insts)):
+                        if quantity <= insts[i]:
+                            fits = True
+                            insts[i] -= quantity
+                            break
+                    if fits == False:
+                        return False
+        return True
     
-    def get_num_fits_in(self, res2):
-        canfit = 10000 # Arbitrarily large
-        for i in xrange(len(self._res)):
-            if self._res[i] != 0:
-                f = res2._res[i] / self._res[i]
-                if f < canfit:
-                    canfit = f
-        return int(floor(canfit))
-    
     def decr(self, res2):
-        for slottype in xrange(len(self._res)):
+        for slottype in xrange(self.slottable.rtuple_len):
             self._res[slottype] -= res2._res[slottype]
-
+        if self.slottable.has_multiinst:
+            for (pos, l) in res2.multiinst.items():
+                insts = self.multiinst[pos]
+                for quantity in l:
+                    fits = False
+                    for i in range(len(insts)):
+                        if quantity <= insts[i]:
+                            fits = True
+                            insts[i] -= quantity
+                            break
+                    if fits == False:
+                        raise Exception, "Can't decrease"
+                    
     def incr(self, res2):
-        for slottype in xrange(len(self._res)):
+        for slottype in xrange(self.slottable.rtuple_len):
             self._res[slottype] += res2._res[slottype]
+        if self.slottable.has_multiinst:
+            for (pos, l) in res2.multiinst.items():
+                self.multiinst[pos] += l[:]
         
-    def get_by_type(self, resourcetype):
-        return self._res[self.type2pos[resourcetype]]
-
-    def set_by_type(self, resourcetype, value):
-        self._res[self.type2pos[resourcetype]] = value        
+    def get_by_type(self, restype):
+        return self._res[self.slottable.rtuple_restype2pos[restype]]        
         
     def is_zero_or_less(self):
         return sum([v for v in self._res]) <= 0
@@ -111,7 +108,8 @@
     def __repr__(self):
         r=""
         for i, x in enumerate(self._res):
-            r += "%s:%.2f " % (self.pos2type[i], x)
+            r += "%s:%i " % (i, x)
+        r+= `self.multiinst`
         return r
 
     def __eq__(self, res2):
@@ -167,14 +165,8 @@
         return rr
 
 class Node(object):
-    def __init__(self, capacity, resourcepoolnode):
+    def __init__(self, capacity):
         self.capacity = ResourceTuple.copy(capacity)
-        self.resourcepoolnode = resourcepoolnode
-        
-    @classmethod
-    def from_resourcepool_node(cls, node):
-        capacity = node.get_capacity()
-        return cls(capacity, node)
 
 class NodeList(object):
     def __init__(self):
@@ -192,7 +184,7 @@
     def copy(self):
         nodelist = NodeList()
         for n in self.nodelist:
-            nodelist.add(Node(n.capacity, n.resourcepoolnode))
+            nodelist.add(Node(n.capacity))
         return nodelist
    
     def to_dict(self):
@@ -229,16 +221,45 @@
     
     """
     
-    def __init__(self):
+    def __init__(self, resource_types):
         self.logger = logging.getLogger("SLOT")
         self.nodes = NodeList()
+        self.resource_types = resource_types
         self.reservations_by_start = []
         self.reservations_by_end = []
         self.__dirty()
 
-    def add_node(self, resourcepoolnode):
-        self.nodes.add(Node.from_resourcepool_node(resourcepoolnode))
+        # Resource tuple fields
+        res_singleinstance = [rt for rt,ninst in resource_types if ninst == ResourceTuple.SINGLE_INSTANCE]
+        self.rtuple_len = len(res_singleinstance)
+        self.rtuple_nres = len(resource_types)
+        res_multiinstance = [(rt,ninst) for rt,ninst in resource_types if ninst == ResourceTuple.MULTI_INSTANCE]
+        self.has_multiinst = len(res_multiinstance) > 0
+        self.rtuple_restype2pos = dict([(rt,i) for (i,rt) in enumerate(res_singleinstance)])
+        pos = self.rtuple_len
+        for rt, ninst in res_multiinstance:
+            self.rtuple_restype2pos[rt] = pos
+            pos = pos + 1
 
+    def add_node(self, resourcetuple):
+        self.nodes.add(Node(resourcetuple))
+
+    def create_empty_resource_tuple(self):
+        return ResourceTuple(self, [0] * self.rtuple_len)
+    
+    def create_resource_tuple_from_capacity(self, capacity):
+        rt = ResourceTuple(self, [0] * self.rtuple_len)
+        for restype in capacity.get_resource_types():
+            pos = self.rtuple_restype2pos[restype]
+            if pos < self.rtuple_len:
+                rt._res[pos] = capacity.get_quantity(restype)
+            else:
+                ninst = capacity.ninstances[restype]
+                for i in range(ninst):
+                    rt.multiinst[pos].append(capacity.get_quantity_instance(restype, i))
+                    
+        return rt
+
     def is_empty(self):
         return (len(self.reservations_by_start) == 0)
 
@@ -247,7 +268,7 @@
         avail = sum([node.capacity.get_by_type(restype) for node in nodes.values()])
         return (avail == 0)
 
-    def get_total_capacity(self, restype = constants.RES_CPU):
+    def get_total_capacity(self, restype):
         return sum([n.capacity.get_by_type(restype) for n in self.nodes.nodelist])        
 
     def get_reservations_at(self, time):
@@ -526,7 +547,7 @@
             for node in r.resources_in_pnode:
                 if not nodes.has_key(node):
                     n = self.nodes[node]
-                    nodes[node] = Node(n.capacity, n.resourcepoolnode)
+                    nodes[node] = Node(n.capacity)
                 nodes[node].capacity.decr(r.resources_in_pnode[node])
 
         # For the remaining nodes, use a reference to the original node, not a copy
@@ -575,8 +596,9 @@
     def add_lease(self, lease, capacity):
         if not lease in self.leases:
             self.leases.add(lease)
-            self.available_if_preempting[lease] = ResourceTuple.create_empty()
-        self.available_if_preempting[lease].incr(capacity)
+            self.available_if_preempting[lease] = ResourceTuple.copy(capacity)
+        else:
+            self.available_if_preempting[lease].incr(capacity)
         
     def get_avail_withpreemption(self, leases):
         avail = ResourceTuple.copy(available)
@@ -594,6 +616,10 @@
         
     def fits(self, capacity, until):
         for avail in self.avail_list:
+            print capacity
+            print avail.until, avail.available
+            print capacity.fits_in(avail.available)
+            print "----------"
             if avail.until == None or avail.until >= until:
                 return capacity.fits_in(avail.available)
 

Modified: branches/TP2.0/src/haizea/core/scheduler/vm_scheduler.py
===================================================================
--- branches/TP2.0/src/haizea/core/scheduler/vm_scheduler.py	2009-07-07 10:43:04 UTC (rev 602)
+++ branches/TP2.0/src/haizea/core/scheduler/vm_scheduler.py	2009-07-13 16:35:44 UTC (rev 603)
@@ -90,8 +90,11 @@
     def __schedule_exact(self, lease, nexttime, earliest):
         start = lease.start.requested
         end = start + lease.duration.requested
+        
+        requested_resources = dict([(k,self.slottable.create_resource_tuple_from_capacity(v)) for k,v in lease.requested_resources.items()])
+        print requested_resources
         mapping, actualend, preemptions = self.mapper.map(lease, 
-                                                          lease.requested_resources,
+                                                          requested_resources,
                                                           start, 
                                                           end, 
                                                           strictend = True)
@@ -102,7 +105,7 @@
         res = {}
         
         for (vnode,pnode) in mapping.items():
-            vnode_res = lease.requested_resources[vnode]
+            vnode_res = requested_resources[vnode]
             if res.has_key(pnode):
                 res[pnode].incr(vnode_res)
             else:
@@ -204,8 +207,11 @@
 
         reservation = False
 
+        requested_resources = dict([(k,self.slottable.create_resource_tuple_from_capacity(v)) for k,v in lease.requested_resources.items()])
+
         # First, assuming we can't make reservations in the future
         start, end, mapping, preemptions = self.__find_fit_at_points(lease,
+                                                                     requested_resources,
                                                                      changepoints, 
                                                                      duration, 
                                                                      min_duration)
@@ -219,6 +225,7 @@
         # reserve it in the future
         if start == None and allow_reservation_in_future:
             start, end, mapping, preemptions = self.__find_fit_at_points(lease,
+                                                                         requested_resources,
                                                                          futurecp, 
                                                                          duration, 
                                                                          min_duration
@@ -237,7 +244,7 @@
         res = {}
         
         for (vnode,pnode) in mapping.items():
-            vnode_res = lease.requested_resources[vnode]
+            vnode_res = requested_resources[vnode]
             if res.has_key(pnode):
                 res[pnode].incr(vnode_res)
             else:
@@ -354,20 +361,20 @@
             
         
     def get_utilization(self, time):
-        total = self.slottable.get_total_capacity()
+#        total = self.slottable.get_total_capacity()
         util = {}
-        reservations = self.slottable.get_reservations_at(time)
-        for r in reservations:
-            for node in r.resources_in_pnode:
-                if isinstance(r, VMResourceReservation):
-                    use = r.resources_in_pnode[node].get_by_type(constants.RES_CPU)
-                    util[type(r)] = use + util.setdefault(type(r),0.0)
-                elif isinstance(r, SuspensionResourceReservation) or isinstance(r, ResumptionResourceReservation) or isinstance(r, ShutdownResourceReservation):
-                    use = r.vmrr.resources_in_pnode[node].get_by_type(constants.RES_CPU)
-                    util[type(r)] = use + util.setdefault(type(r),0.0)
-        util[None] = total - sum(util.values())
-        for k in util:
-            util[k] /= total
+#        reservations = self.slottable.get_reservations_at(time)
+#        for r in reservations:
+#            for node in r.resources_in_pnode:
+#                if isinstance(r, VMResourceReservation):
+#                    use = r.resources_in_pnode[node].get_by_type(constants.RES_CPU)
+#                    util[type(r)] = use + util.setdefault(type(r),0.0)
+#                elif isinstance(r, SuspensionResourceReservation) or isinstance(r, ResumptionResourceReservation) or isinstance(r, ShutdownResourceReservation):
+#                    use = r.vmrr.resources_in_pnode[node].get_by_type(constants.RES_CPU)
+#                    util[type(r)] = use + util.setdefault(type(r),0.0)
+#        util[None] = total - sum(util.values())
+#        for k in util:
+#            util[k] /= total
             
         return util              
         
@@ -387,14 +394,15 @@
         return self.maxres > 0
 
 
-    def __find_fit_at_points(self, lease, changepoints, duration, min_duration):
+    def __find_fit_at_points(self, lease, requested_resources, changepoints, duration, min_duration):
         found = False
+        
         for time, onlynodes in changepoints:
             start = time
             end = start + duration
             self.logger.debug("Attempting to map from %s to %s" % (start, end))
             mapping, actualend, preemptions = self.mapper.map(lease, 
-                                                              lease.requested_resources,
+                                                              requested_resources,
                                                               start, 
                                                               end, 
                                                               strictend = False,
@@ -634,7 +642,7 @@
         enactment_overhead = get_config().get("enactment-overhead") 
         mem = 0
         for vnode in lease.requested_resources:
-            mem += lease.requested_resources[vnode].get_by_type(constants.RES_MEM)
+            mem += lease.requested_resources[vnode].get_quantity(constants.RES_MEM)
         if susp_exclusion == constants.SUSPRES_EXCLUSION_GLOBAL:
             return lease.numnodes * (self.__compute_suspend_resume_time(mem, rate) + enactment_overhead)
         elif susp_exclusion == constants.SUSPRES_EXCLUSION_LOCAL:

Modified: branches/TP2.0/tests/common.py
===================================================================
--- branches/TP2.0/tests/common.py	2009-07-07 10:43:04 UTC (rev 602)
+++ branches/TP2.0/tests/common.py	2009-07-13 16:35:44 UTC (rev 603)
@@ -120,7 +120,7 @@
     slottable.add_reservation(rr)
 
 def create_tmp_slottable(slottable):
-    tmp_slottable = SlotTable()
+    tmp_slottable = SlotTable(slottable.resource_types)
     tmp_slottable.nodes = slottable.nodes
     tmp_slottable.reservations_by_start = slottable.reservations_by_start[:]
     tmp_slottable.reservations_by_end = slottable.reservations_by_end[:]

Modified: branches/TP2.0/tests/sample_slottables.py
===================================================================
--- branches/TP2.0/tests/sample_slottables.py	2009-07-07 10:43:04 UTC (rev 602)
+++ branches/TP2.0/tests/sample_slottables.py	2009-07-13 16:35:44 UTC (rev 603)
@@ -1,5 +1,5 @@
-from haizea.core.leases import Lease
-from haizea.core.scheduler.resourcepool import Node
+from haizea.core.leases import Lease, Capacity
+from haizea.core.scheduler.resourcepool import ResourcePoolNode
 from haizea.core.scheduler.slottable import ResourceTuple, SlotTable, ResourceReservation, AvailabilityWindow
 from mx import DateTime
 import haizea.common.constants as constants
@@ -20,30 +20,36 @@
 T1415 = DateTime.DateTime(2006,11,25,14,15)
 T1420 = DateTime.DateTime(2006,11,25,14,20)
 
-resource_types = [(constants.RES_CPU, constants.RESTYPE_FLOAT, "CPU"),
-                  (constants.RES_MEM,  constants.RESTYPE_INT, "Mem")]
-ResourceTuple.set_resource_types(resource_types)
+resource_types_with_max_instances = [(constants.RES_CPU,1),(constants.RES_MEM,1)]
 
-FULL_NODE = ResourceTuple.create_empty()
-FULL_NODE.set_by_type(constants.RES_CPU, 1.0)
-FULL_NODE.set_by_type(constants.RES_MEM, 1024)
+def create_capacities(slottable):
+    FULL_NODE = Capacity([constants.RES_CPU,constants.RES_MEM])
+    FULL_NODE.set_quantity(constants.RES_CPU, 100)
+    FULL_NODE.set_quantity(constants.RES_MEM, 1024)
+    FULL_NODE = slottable.create_resource_tuple_from_capacity(FULL_NODE)
+    
+    HALF_NODE = Capacity([constants.RES_CPU,constants.RES_MEM])
+    HALF_NODE.set_quantity(constants.RES_CPU, 50)
+    HALF_NODE.set_quantity(constants.RES_MEM, 512)
+    HALF_NODE = slottable.create_resource_tuple_from_capacity(HALF_NODE)
 
-HALF_NODE = ResourceTuple.create_empty()
-HALF_NODE.set_by_type(constants.RES_CPU, 0.5)
-HALF_NODE.set_by_type(constants.RES_MEM, 512)
+    QRTR_NODE = Capacity([constants.RES_CPU,constants.RES_MEM])
+    QRTR_NODE.set_quantity(constants.RES_CPU, 25)
+    QRTR_NODE.set_quantity(constants.RES_MEM, 256)
+    QRTR_NODE = slottable.create_resource_tuple_from_capacity(QRTR_NODE)
 
-QRTR_NODE = ResourceTuple.create_empty()
-QRTR_NODE.set_by_type(constants.RES_CPU, 0.25)
-QRTR_NODE.set_by_type(constants.RES_MEM, 256)
-
-EMPT_NODE = ResourceTuple.create_empty()
+    EMPT_NODE = slottable.create_empty_resource_tuple()
+    
+    return FULL_NODE, HALF_NODE, QRTR_NODE, EMPT_NODE
         
 def sample_slottable_1():
-    slottable = SlotTable()  
-    slottable.add_node(Node(1, "test-1", FULL_NODE))
-    slottable.add_node(Node(2, "test-2", FULL_NODE))  
-    slottable.add_node(Node(3, "test-3", FULL_NODE))  
-    slottable.add_node(Node(4, "test-4", FULL_NODE))  
+    slottable = SlotTable([(constants.RES_CPU,ResourceTuple.SINGLE_INSTANCE),(constants.RES_MEM,ResourceTuple.SINGLE_INSTANCE)])
+    FULL_NODE, HALF_NODE, QRTR_NODE, EMPT_NODE = create_capacities(slottable)
+    
+    slottable.add_node(FULL_NODE)
+    slottable.add_node(FULL_NODE)  
+    slottable.add_node(FULL_NODE)  
+    slottable.add_node(FULL_NODE)  
 
     lease1 = Lease(None,[],None,None,None,1,None)
     lease1.id = 1
@@ -88,13 +94,14 @@
     return slottable, [lease1,lease2,lease3,lease4,lease5,lease6]
         
 def sample_slottable_2():
-    slottable = SlotTable()
+    slottable = SlotTable([(constants.RES_CPU,ResourceTuple.SINGLE_INSTANCE),(constants.RES_MEM,ResourceTuple.SINGLE_INSTANCE)])
+    FULL_NODE, HALF_NODE, QRTR_NODE, EMPT_NODE = create_capacities(slottable)
+    
+    slottable.add_node(FULL_NODE)
+    slottable.add_node(FULL_NODE)  
+    slottable.add_node(FULL_NODE)  
+    slottable.add_node(FULL_NODE)  
 
-    slottable.add_node(Node(1, "test-1", FULL_NODE))
-    slottable.add_node(Node(2, "test-2", FULL_NODE))  
-    slottable.add_node(Node(3, "test-3", FULL_NODE))  
-    slottable.add_node(Node(4, "test-4", FULL_NODE))  
-
     lease1 = create_ar_lease(lease_id = 1,
                              submit_time = T1200,
                              start = T1330,
@@ -114,13 +121,14 @@
     return slottable, [lease1,lease2]
 
 def sample_slottable_3():
-    slottable = SlotTable()
+    slottable = SlotTable([(constants.RES_CPU,ResourceTuple.SINGLE_INSTANCE),(constants.RES_MEM,ResourceTuple.SINGLE_INSTANCE)])
+    FULL_NODE, HALF_NODE, QRTR_NODE, EMPT_NODE = create_capacities(slottable)
+    
+    slottable.add_node(FULL_NODE)
+    slottable.add_node(FULL_NODE)  
+    slottable.add_node(FULL_NODE)  
+    slottable.add_node(FULL_NODE)  
 
-    slottable.add_node(Node(1, "test-1", FULL_NODE))
-    slottable.add_node(Node(2, "test-2", FULL_NODE))  
-    slottable.add_node(Node(3, "test-3", FULL_NODE))  
-    slottable.add_node(Node(4, "test-4", FULL_NODE))  
-
     lease1 = create_ar_lease(lease_id = 1,
                              submit_time = T1200,
                              start = T1345,

Modified: branches/TP2.0/tests/test_mapper.py
===================================================================
--- branches/TP2.0/tests/test_mapper.py	2009-07-07 10:43:04 UTC (rev 602)
+++ branches/TP2.0/tests/test_mapper.py	2009-07-13 16:35:44 UTC (rev 603)
@@ -1,5 +1,5 @@
 from haizea.core.leases import Lease
-from haizea.core.scheduler.resourcepool import Node
+from haizea.core.scheduler.resourcepool import ResourcePoolNode
 from haizea.core.scheduler.policy import Policy
 from haizea.core.scheduler.slottable import ResourceTuple, SlotTable, ResourceReservation, AvailabilityWindow
 from haizea.core.scheduler.mapper import GreedyMapper
@@ -79,6 +79,7 @@
    
     def test_mapping_nopreemption_strictend(self):
         self.slottable, leases = sample_slottable_2()
+        FULL_NODE, HALF_NODE, QRTR_NODE, EMPT_NODE = create_capacities(self.slottable)
         policy = SimplePolicy(self.slottable, preemption = False)
         self.mapper = GreedyMapper(self.slottable, policy)
         
@@ -138,6 +139,7 @@
 
     def test_mapping_nopreemption_nostrictend(self):
         self.slottable, leases = sample_slottable_3()
+        FULL_NODE, HALF_NODE, QRTR_NODE, EMPT_NODE = create_capacities(self.slottable)
         policy = SimplePolicy(self.slottable, preemption = False)
         self.mapper = GreedyMapper(self.slottable, policy)
         
@@ -197,6 +199,7 @@
         
     def test_mapping_preemption_strictend(self):
         self.slottable, leases = sample_slottable_3()
+        FULL_NODE, HALF_NODE, QRTR_NODE, EMPT_NODE = create_capacities(self.slottable)
         policy = SimplePolicy(self.slottable, preemption = True)        
         self.mapper = GreedyMapper(self.slottable, policy)
 

Modified: branches/TP2.0/tests/test_slottable.py
===================================================================
--- branches/TP2.0/tests/test_slottable.py	2009-07-07 10:43:04 UTC (rev 602)
+++ branches/TP2.0/tests/test_slottable.py	2009-07-13 16:35:44 UTC (rev 603)
@@ -1,5 +1,5 @@
-from haizea.core.leases import Lease
-from haizea.core.scheduler.resourcepool import Node
+from haizea.core.leases import Lease, Capacity
+from haizea.core.scheduler.resourcepool import ResourcePoolNode
 from haizea.core.scheduler.slottable import ResourceTuple, SlotTable, ResourceReservation, AvailabilityWindow
 from mx import DateTime
 from sample_slottables import *
@@ -9,9 +9,99 @@
     def __init__(self):
         self.slottable = None
    
+    def test_resource_tuple(self):
+        
+        multiinst = [(constants.RES_CPU,ResourceTuple.MULTI_INSTANCE),(constants.RES_MEM,ResourceTuple.SINGLE_INSTANCE)]
+        
+        self.slottable = SlotTable(multiinst)
+                
+        c1_100 = Capacity([constants.RES_CPU,constants.RES_MEM])
+        c1_100.set_quantity(constants.RES_CPU, 100)
+        c1_100.set_quantity(constants.RES_MEM, 1024)
+        c1_100 = self.slottable.create_resource_tuple_from_capacity(c1_100)
+
+        c2_100 = Capacity([constants.RES_CPU,constants.RES_MEM])
+        c2_100.set_ninstances(constants.RES_CPU, 2)
+        c2_100.set_quantity_instance(constants.RES_CPU, 1, 100)
+        c2_100.set_quantity_instance(constants.RES_CPU, 2, 100)
+        c2_100.set_quantity(constants.RES_MEM, 1024)
+        c2_100 = self.slottable.create_resource_tuple_from_capacity(c2_100)
+
+        c1_50 = Capacity([constants.RES_CPU,constants.RES_MEM])
+        c1_50.set_quantity(constants.RES_CPU, 50)
+        c1_50.set_quantity(constants.RES_MEM, 1024)
+        c1_50 = self.slottable.create_resource_tuple_from_capacity(c1_50)
+
+        c2_50 = Capacity([constants.RES_CPU,constants.RES_MEM])
+        c2_50.set_ninstances(constants.RES_CPU, 2)
+        c2_50.set_quantity_instance(constants.RES_CPU, 1, 50)
+        c2_50.set_quantity_instance(constants.RES_CPU, 2, 50)
+        c2_50.set_quantity(constants.RES_MEM, 1024)
+        c2_50 = self.slottable.create_resource_tuple_from_capacity(c2_50)
+
+        assert c1_100.fits_in(c2_100)
+        assert not c1_100.fits_in(c1_50)
+        assert not c1_100.fits_in(c2_50)
+
+        assert not c2_100.fits_in(c1_100)
+        assert not c2_100.fits_in(c1_50)
+        assert not c2_100.fits_in(c2_50)
+
+        assert c1_50.fits_in(c1_100)
+        assert c1_50.fits_in(c2_100)
+        assert c1_50.fits_in(c2_50)
+
+        assert c2_50.fits_in(c1_100)
+        assert c2_50.fits_in(c2_100)
+        assert not c2_50.fits_in(c1_50)
+        
+        empty = self.slottable.create_empty_resource_tuple()
+        empty.incr(c2_100)
+        assert empty._res[0] == 1024
+        assert empty.multiinst[1] == [100,100]
+ 
+        empty = self.slottable.create_empty_resource_tuple()
+        empty.incr(c1_100)
+        assert empty._res[0] == 1024
+        assert empty.multiinst[1] == [100]
+        empty.incr(c1_100)
+        assert empty._res[0] == 2048
+        assert empty.multiinst[1] == [100,100]
+
+        empty = self.slottable.create_empty_resource_tuple()
+        empty.incr(c1_100)
+        assert empty._res[0] == 1024
+        assert empty.multiinst[1] == [100]
+        empty.incr(c1_50)
+        assert empty._res[0] == 2048
+        assert empty.multiinst[1] == [100,50]
+   
+        c1_100a = ResourceTuple.copy(c1_100)
+        c1_100a.decr(c1_50)
+        assert c1_100a._res[0] == 0
+        assert c1_100a.multiinst[1] == [50]
+
+        c2_100a = ResourceTuple.copy(c2_100)
+        c2_100a._res[0] = 2048
+        c2_100a.decr(c1_50)
+        assert c2_100a._res[0] == 1024
+        assert c2_100a.multiinst[1] == [50,100]
+        c2_100a.decr(c1_50)
+        assert c2_100a._res[0] == 0
+        assert c2_100a.multiinst[1] == [0,100]
+
+        c2_100a = ResourceTuple.copy(c2_100)
+        c2_100a._res[0] = 2048
+        c2_100a.decr(c2_50)
+        assert c2_100a._res[0] == 1024
+        assert c2_100a.multiinst[1] == [0,100]
+        c2_100a.decr(c2_50)
+        assert c2_100a._res[0] == 0
+        assert c2_100a.multiinst[1] == [0,0]
+   
     def test_slottable(self):
         def assert_capacity(node, percent):
-            assert node.capacity.get_by_type(constants.RES_CPU) == percent * 1.0
+            assert node.capacity.get_by_type(constants.RES_CPU) == percent * 100
             assert node.capacity.get_by_type(constants.RES_MEM) == percent * 1024
             
         def reservations_1_assertions():
@@ -237,38 +327,38 @@
             rrs = self.slottable.get_reservations_ending_between(T1400, T1415)
             assert set(rrs) == set([rr2,rr4,rr5])
             
-            rrs = self.slottable.get_reservations_starting_after(T1300)
+            rrs = self.slottable.get_reservations_starting_on_or_after(T1300)
             assert set(rrs) == set([rr1,rr2,rr3,rr4,rr5])
-            rrs = self.slottable.get_reservations_starting_after(T1305)
+            rrs = self.slottable.get_reservations_starting_on_or_after(T1305)
             assert set(rrs) == set([rr2,rr3,rr4,rr5])
-            rrs = self.slottable.get_reservations_starting_after(T1315)
+            rrs = self.slottable.get_reservations_starting_on_or_after(T1315)
             assert set(rrs) == set([rr2,rr3,rr4,rr5])
-            rrs = self.slottable.get_reservations_starting_after(T1330)
+            rrs = self.slottable.get_reservations_starting_on_or_after(T1330)
             assert set(rrs) == set([rr2,rr4,rr5])
-            rrs = self.slottable.get_reservations_starting_after(T1335)
+            rrs = self.slottable.get_reservations_starting_on_or_after(T1335)
             assert set(rrs) == set([rr5])
-            rrs = self.slottable.get_reservations_starting_after(T1345)
+            rrs = self.slottable.get_reservations_starting_on_or_after(T1345)
             assert set(rrs) == set([rr5])
-            rrs = self.slottable.get_reservations_starting_after(T1400)
+            rrs = self.slottable.get_reservations_starting_on_or_after(T1400)
             assert len(rrs) == 0
-            rrs = self.slottable.get_reservations_starting_after(T1415)
+            rrs = self.slottable.get_reservations_starting_on_or_after(T1415)
             assert len(rrs) == 0
             
-            rrs = self.slottable.get_reservations_ending_after(T1300)
+            rrs = self.slottable.get_reservations_ending_on_or_after(T1300)
             assert set(rrs) == set([rr1,rr2,rr3,rr4,rr5])
-            rrs = self.slottable.get_reservations_ending_after(T1305)
+            rrs = self.slottable.get_reservations_ending_on_or_after(T1305)
             assert set(rrs) == set([rr1,rr2,rr3,rr4,rr5])
-            rrs = self.slottable.get_reservations_ending_after(T1315)
+            rrs = self.slottable.get_reservations_ending_on_or_after(T1315)
             assert set(rrs) == set([rr1,rr2,rr3,rr4,rr5])
-            rrs = self.slottable.get_reservations_ending_after(T1330)
+            rrs = self.slottable.get_reservations_ending_on_or_after(T1330)
             assert set(rrs) == set([rr1,rr2,rr3,rr4,rr5])
-            rrs = self.slottable.get_reservations_ending_after(T1335)
+            rrs = self.slottable.get_reservations_ending_on_or_after(T1335)
             assert set(rrs) == set([rr2,rr3,rr4,rr5])
-            rrs = self.slottable.get_reservations_ending_after(T1345)
+            rrs = self.slottable.get_reservations_ending_on_or_after(T1345)
             assert set(rrs) == set([rr2,rr3,rr4,rr5])
-            rrs = self.slottable.get_reservations_ending_after(T1400)
+            rrs = self.slottable.get_reservations_ending_on_or_after(T1400)
             assert set(rrs) == set([rr2,rr4,rr5])
-            rrs = self.slottable.get_reservations_ending_after(T1415)
+            rrs = self.slottable.get_reservations_ending_on_or_after(T1415)
             assert set(rrs) == set([rr4,rr5])
             
             assert self.slottable.get_next_changepoint(T1255) == T1300
@@ -281,12 +371,13 @@
             assert self.slottable.get_next_changepoint(T1415) == None
             assert self.slottable.get_next_changepoint(T1420) == None
         
-        self.slottable = SlotTable()
-
-        self.slottable.add_node(Node(1, "test-1", FULL_NODE))
-        self.slottable.add_node(Node(2, "test-2", FULL_NODE))  
+        self.slottable = SlotTable([(constants.RES_CPU,ResourceTuple.SINGLE_INSTANCE),(constants.RES_MEM,ResourceTuple.SINGLE_INSTANCE)])
+        FULL_NODE, HALF_NODE, QRTR_NODE, EMPT_NODE = create_capacities(self.slottable)
         
-        assert self.slottable.get_total_capacity(constants.RES_CPU) == 2.0
+        self.slottable.add_node(FULL_NODE)
+        self.slottable.add_node(FULL_NODE)  
+        
+        assert self.slottable.get_total_capacity(constants.RES_CPU) == 200
         assert self.slottable.get_total_capacity(constants.RES_MEM) == 2048
         assert self.slottable.is_empty()
     
@@ -344,6 +435,7 @@
                 assert(node.next_nodeavail == aw.changepoints[next_cp].nodes[node_id])
         
         self.slottable, leases = sample_slottable_1()        
+        FULL_NODE, HALF_NODE, QRTR_NODE, EMPT_NODE = create_capacities(self.slottable)
         
         lease1,lease2,lease3,lease4,lease5,lease6 = leases
         



More information about the Haizea-commit mailing list