ff0c852641cf8bb334dcea4484d3eecaa5e5ce72
2 Playground for resource models created by University of Paderborn.
5 from emuvim
.dcemulator
.resourcemodel
import BaseResourceModel
7 LOG
= logging
.getLogger("rm.upb.simple")
8 LOG
.setLevel(logging
.DEBUG
)
11 class UpbSimpleCloudDcRM(BaseResourceModel
):
13 This will be an example resource model that limits the overall
14 resources that can be deployed per data center.
15 No over provisioning. Resources are fixed throughout entire container
19 def __init__(self
, max_cu
=32, max_mu
=1024,
20 deactivate_cpu_limit
=False,
21 deactivate_mem_limit
=False):
24 :param max_cu: Maximum number of compute units available in this DC.
25 :param max_mu: Maximum memory of entire dc.
28 self
.dc_max_cu
= max_cu
29 self
.dc_max_mu
= max_mu
32 self
.deactivate_cpu_limit
= deactivate_cpu_limit
33 self
.deactivate_mem_limit
= deactivate_mem_limit
34 super(self
.__class
__, self
).__init
__()
36 def allocate(self
, d
):
38 Allocate resources for the given container.
39 Defined by d.flavor_name
43 self
._allocated
_compute
_instances
[d
.name
] = d
44 if not self
.deactivate_cpu_limit
:
46 if not self
.deactivate_mem_limit
:
50 def _allocate_cpu(self
, d
):
52 Actually allocate (bookkeeping)
56 fl_cu
= self
._get
_flavor
(d
).get("compute")
57 # check for over provisioning
58 if self
.dc_alloc_cu
+ fl_cu
> self
.dc_max_cu
:
59 raise Exception("Not enough compute resources left.")
60 self
.dc_alloc_cu
+= fl_cu
62 def _allocate_mem(self
, d
):
64 Actually allocate (bookkeeping)
68 fl_mu
= self
._get
_flavor
(d
).get("memory")
69 # check for over provisioning
70 if self
.dc_alloc_mu
+ fl_mu
> self
.dc_max_mu
:
71 raise Exception("Not enough memory resources left.")
72 self
.dc_alloc_mu
+= fl_mu
76 Free resources allocated to the given container.
80 del self
._allocated
_compute
_instances
[d
.name
]
81 if not self
.deactivate_cpu_limit
:
83 if not self
.deactivate_mem_limit
:
87 def _free_cpu(self
, d
):
93 self
.dc_alloc_cu
-= self
._get
_flavor
(d
).get("compute")
95 def _free_mem(self
, d
):
101 self
.dc_alloc_mu
-= self
._get
_flavor
(d
).get("memory")
103 def _apply_limits(self
):
105 Recalculate real resource limits for all allocated containers and apply them
107 We have to recalculate for all to allow e.g. overprovisioning models.
110 for d
in self
._allocated
_compute
_instances
.itervalues():
111 if not self
.deactivate_cpu_limit
:
112 self
._apply
_cpu
_limits
(d
)
113 if not self
.deactivate_mem_limit
:
114 self
._apply
_mem
_limits
(d
)
116 def _apply_cpu_limits(self
, d
):
118 Calculate real CPU limit (CFS bandwidth) and apply.
122 number_cu
= self
._get
_flavor
(d
).get("compute")
123 # get cpu time fraction for entire emulation
124 e_cpu
= self
.registrar
.e_cpu
125 # calculate cpu time fraction of a single compute unit
126 single_cu
= float(e_cpu
) / sum([rm
.dc_max_cu
for rm
in list(self
.registrar
.resource_models
)])
127 # calculate cpu time fraction for container with given flavor
128 cpu_time_percentage
= single_cu
* number_cu
129 # calculate cpu period and quota for CFS
130 # (see: https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt)
131 # Attention minimum cpu_quota is 1ms (micro)
132 cpu_period
= 1000000 # lets consider a fixed period of 1000000 microseconds for now
133 cpu_quota
= cpu_period
* cpu_time_percentage
# calculate the fraction of cpu time for this container
134 # ATTENTION >= 1000 to avoid a invalid argument system error ... no idea why
137 LOG
.warning("Increased CPU quota for %r to avoid system error." % d
.name
)
138 # apply to container if changed
139 if d
.cpu_period
!= cpu_period
or d
.cpu_quota
!= cpu_quota
:
140 LOG
.debug("Setting CPU limit for %r: cpu_quota = cpu_period * limit = %f * %f = %f" % (
141 d
.name
, cpu_period
, cpu_time_percentage
, cpu_quota
))
142 d
.updateCpuLimit(cpu_period
=int(cpu_period
), cpu_quota
=int(cpu_quota
))
144 def _apply_mem_limits(self
, d
):
146 Calculate real mem limit and apply.
150 number_mu
= self
._get
_flavor
(d
).get("memory")
151 # get memory amount for entire emulation
152 e_mem
= self
.registrar
.e_mem
153 # calculate amount of memory for a single mu
154 single_mu
= float(e_mem
) / sum([rm
.dc_max_mu
for rm
in list(self
.registrar
.resource_models
)])
155 # calculate mem for given flavor
156 mem_limit
= single_mu
* number_mu
157 # ATTENTION minimum mem_limit per container is 4MB
160 LOG
.warning("Increased MEM limit for %r because it was less than 4.0 MB." % name
)
162 mem_limit
= int(mem_limit
*1024*1024)
163 # apply to container if changed
164 if d
.mem_limit
!= mem_limit
:
165 LOG
.debug("Setting MEM limit for %r: mem_limit = %f MB" % (d
.name
, mem_limit
/1024/1024))
166 d
.updateMemoryLimit(mem_limit
=mem_limit
)
168 def get_state_dict(self
):
170 Return the state of the resource model as simple dict.
171 Helper method for logging functionality.
176 r
["e_cpu"] = self
.registrar
.e_cpu
177 r
["e_mem"] = self
.registrar
.e_mem
178 r
["dc_max_cu"] = self
.dc_max_cu
179 r
["dc_max_mu"] = self
.dc_max_mu
180 r
["dc_alloc_cu"] = self
.dc_alloc_cu
181 r
["dc_alloc_mu"] = self
.dc_alloc_mu
182 r
["cu_cpu_percentage"] = -1
183 r
["mu_mem_percentage"] = -1
184 r
["allocated_compute_instances"] = None #self._allocated_compute_instances
187 def _get_flavor(self
, d
):
189 Get flavor assigned to given container.
190 Identified by d.flavor_name.
194 if d
.flavor_name
not in self
._flavors
:
195 raise Exception("Flavor %r does not exist" % d
.flavor_name
)
196 return self
._flavors
.get(d
.flavor_name
)