f0b147f2b3782ccc1939fd89596549018143fd57
2 Playground for resource models created by University of Paderborn.
7 from emuvim
.dcemulator
.resourcemodel
import BaseResourceModel
9 LOG
= logging
.getLogger("rm.upb.simple")
10 LOG
.setLevel(logging
.DEBUG
)
13 class UpbSimpleCloudDcRM(BaseResourceModel
):
15 This will be an example resource model that limits the overall
16 resources that can be deployed per data center.
17 No over provisioning. Resources are fixed throughout entire container
21 def __init__(self
, max_cu
=32, max_mu
=1024,
22 deactivate_cpu_limit
=False,
23 deactivate_mem_limit
=False):
26 :param max_cu: Maximum number of compute units available in this DC.
27 :param max_mu: Maximum memory of entire dc.
30 self
.dc_max_cu
= max_cu
31 self
.dc_max_mu
= max_mu
34 self
.deactivate_cpu_limit
= deactivate_cpu_limit
35 self
.deactivate_mem_limit
= deactivate_mem_limit
38 super(self
.__class
__, self
).__init
__()
40 def allocate(self
, d
):
42 Allocate resources for the given container.
43 Defined by d.flavor_name
47 self
._allocated
_compute
_instances
[d
.name
] = d
48 if not self
.deactivate_cpu_limit
:
50 if not self
.deactivate_mem_limit
:
54 def _allocate_cpu(self
, d
):
56 Actually allocate (bookkeeping)
60 fl_cu
= self
._get
_flavor
(d
).get("compute")
61 # check for over provisioning
62 if self
.dc_alloc_cu
+ fl_cu
> self
.dc_max_cu
:
63 raise Exception("Not enough compute resources left.")
64 self
.dc_alloc_cu
+= fl_cu
66 def _allocate_mem(self
, d
):
68 Actually allocate (bookkeeping)
72 fl_mu
= self
._get
_flavor
(d
).get("memory")
73 # check for over provisioning
74 if self
.dc_alloc_mu
+ fl_mu
> self
.dc_max_mu
:
75 raise Exception("Not enough memory resources left.")
76 self
.dc_alloc_mu
+= fl_mu
80 Free resources allocated to the given container.
84 del self
._allocated
_compute
_instances
[d
.name
]
85 if not self
.deactivate_cpu_limit
:
87 if not self
.deactivate_mem_limit
:
91 def _free_cpu(self
, d
):
97 self
.dc_alloc_cu
-= self
._get
_flavor
(d
).get("compute")
99 def _free_mem(self
, d
):
105 self
.dc_alloc_mu
-= self
._get
_flavor
(d
).get("memory")
107 def _apply_limits(self
):
109 Recalculate real resource limits for all allocated containers and apply them
111 We have to recalculate for all to allow e.g. overprovisioning models.
114 for d
in self
._allocated
_compute
_instances
.itervalues():
115 if not self
.deactivate_cpu_limit
:
116 self
._apply
_cpu
_limits
(d
)
117 if not self
.deactivate_mem_limit
:
118 self
._apply
_mem
_limits
(d
)
120 def _apply_cpu_limits(self
, d
):
122 Calculate real CPU limit (CFS bandwidth) and apply.
126 number_cu
= self
._get
_flavor
(d
).get("compute")
127 # get cpu time fraction for entire emulation
128 e_cpu
= self
.registrar
.e_cpu
129 # calculate cpu time fraction of a single compute unit
130 self
.single_cu
= float(e_cpu
) / sum([rm
.dc_max_cu
for rm
in list(self
.registrar
.resource_models
)])
131 # calculate cpu time fraction for container with given flavor
132 cpu_time_percentage
= single_cu
* number_cu
133 # calculate cpu period and quota for CFS
134 # (see: https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt)
135 # Attention minimum cpu_quota is 1ms (micro)
136 cpu_period
= 1000000 # lets consider a fixed period of 1000000 microseconds for now
137 cpu_quota
= cpu_period
* cpu_time_percentage
# calculate the fraction of cpu time for this container
138 # ATTENTION >= 1000 to avoid a invalid argument system error ... no idea why
141 LOG
.warning("Increased CPU quota for %r to avoid system error." % d
.name
)
142 # apply to container if changed
143 if d
.cpu_period
!= cpu_period
or d
.cpu_quota
!= cpu_quota
:
144 LOG
.debug("Setting CPU limit for %r: cpu_quota = cpu_period * limit = %f * %f = %f" % (
145 d
.name
, cpu_period
, cpu_time_percentage
, cpu_quota
))
146 d
.updateCpuLimit(cpu_period
=int(cpu_period
), cpu_quota
=int(cpu_quota
))
148 def _apply_mem_limits(self
, d
):
150 Calculate real mem limit and apply.
154 number_mu
= self
._get
_flavor
(d
).get("memory")
155 # get memory amount for entire emulation
156 e_mem
= self
.registrar
.e_mem
157 # calculate amount of memory for a single mu
158 self
.single_mu
= float(e_mem
) / sum([rm
.dc_max_mu
for rm
in list(self
.registrar
.resource_models
)])
159 # calculate mem for given flavor
160 mem_limit
= single_mu
* number_mu
161 # ATTENTION minimum mem_limit per container is 4MB
164 LOG
.warning("Increased MEM limit for %r because it was less than 4.0 MB." % d
.name
)
166 mem_limit
= int(mem_limit
*1024*1024)
167 # apply to container if changed
168 if d
.mem_limit
!= mem_limit
:
169 LOG
.debug("Setting MEM limit for %r: mem_limit = %f MB" % (d
.name
, mem_limit
/1024/1024))
170 d
.updateMemoryLimit(mem_limit
=mem_limit
)
172 def get_state_dict(self
):
174 Return the state of the resource model as simple dict.
175 Helper method for logging functionality.
178 # collect info about all allocated instances
179 allocation_state
= dict()
180 for k
, d
in self
._allocated
_compute
_instances
.iteritems():
182 s
["cpu_period"] = d
.cpu_period
183 s
["cpu_quota"] = d
.cpu_quota
184 s
["cpu_shares"] = d
.cpu_shares
185 s
["mem_limit"] = d
.mem_limit
186 s
["memswap_limit"] = d
.memswap_limit
187 allocation_state
[k
] = s
190 r
["e_cpu"] = self
.registrar
.e_cpu
191 r
["e_mem"] = self
.registrar
.e_mem
192 r
["dc_max_cu"] = self
.dc_max_cu
193 r
["dc_max_mu"] = self
.dc_max_mu
194 r
["dc_alloc_cu"] = self
.dc_alloc_cu
195 r
["dc_alloc_mu"] = self
.dc_alloc_mu
196 r
["allocation_state"] = allocation_state
199 def _get_flavor(self
, d
):
201 Get flavor assigned to given container.
202 Identified by d.flavor_name.
206 if d
.flavor_name
not in self
._flavors
:
207 raise Exception("Flavor %r does not exist" % d
.flavor_name
)
208 return self
._flavors
.get(d
.flavor_name
)
210 def _write_log(self
, d
, path
, action
):
212 Helper to log RM info for experiments.
214 :param path: log path
215 :param action: allocate or free
220 # we have a path: write out RM info
223 l
["container_state"] = d
.getStatus()
225 l
["rm_state"] = self
.get_state_dict()
227 with
open(path
, "a") as f
:
228 f
.write("%s\n" % json
.dumps(l
))