From 7e084ea1579fe004470577274b20df66f5122ca0 Mon Sep 17 00:00:00 2001 From: edmaas Date: Mon, 28 Nov 2016 13:50:23 +0100 Subject: [PATCH] added implementation for resource limits --- src/emuvim/api/sonata/dummygatekeeper.py | 58 ++++++++++++++++++++++-- src/emuvim/dcemulator/node.py | 7 +-- 2 files changed, 58 insertions(+), 7 deletions(-) diff --git a/src/emuvim/api/sonata/dummygatekeeper.py b/src/emuvim/api/sonata/dummygatekeeper.py index 70fce59..ca00176 100755 --- a/src/emuvim/api/sonata/dummygatekeeper.py +++ b/src/emuvim/api/sonata/dummygatekeeper.py @@ -301,7 +301,32 @@ class Service(object): assert(target_dc is not None) if not self._check_docker_image_exists(docker_name): raise Exception("Docker image %r not found. Abort." % docker_name) - # 3. do the dc.startCompute(name="foobar") call to run the container + + # 3. get the resource limits + res_req = u.get("resource_requirements") + cpu_list = res_req.get("cpu").get("cores") + if not cpu_list or len(cpu_list)==0: + cpu_list="1" + cpu_bw = res_req.get("cpu").get("cpu_bw") + if not cpu_bw: + cpu_bw=1 + mem_num = str(res_req.get("memory").get("size")) + if len(mem_num)==0: + mem_num="2" + mem_unit = str(res_req.get("memory").get("size_unit")) + if str(mem_unit)==0: + mem_unit="GB" + mem_limit = float(mem_num) + if mem_unit=="GB": + mem_limit=mem_limit*1024*1024*1024 + elif mem_unit=="MB": + mem_limit=mem_limit*1024*1024 + elif mem_unit=="KB": + mem_limit=mem_limit*1024 + mem_lim = int(mem_limit) + cpu_period, cpu_quota = self._calculate_cpu_cfs_values(float(cpu_bw)) + + # 4. do the dc.startCompute(name="foobar") call to run the container # TODO consider flavors, and other annotations intfs = vnfd.get("connection_points") @@ -317,7 +342,8 @@ class Service(object): LOG.info("Starting %r as %r in DC %r" % (vnf_name, self.vnf_name2docker_name[vnf_name], vnfd.get("dc"))) LOG.debug("Interfaces for %r: %r" % (vnf_name, intfs)) - vnfi = target_dc.startCompute(self.vnf_name2docker_name[vnf_name], network=intfs, image=docker_name, flavor_name="small") + vnfi = target_dc.startCompute(self.vnf_name2docker_name[vnf_name], network=intfs, image=docker_name, flavor_name="small", \ + cpu_quota=cpu_quota, cpu_period=cpu_period, cpuset=cpu_list, mem_limit=mem_lim) return vnfi def _stop_vnfi(self, vnfi): @@ -372,8 +398,9 @@ class Service(object): config = vnfi.dcinfo.get("Config", dict()) env = config.get("Env", list()) for env_var in env: - if "SON_EMU_CMD=" in env_var: - cmd = str(env_var.split("=")[1]) + var, cmd = map(str.strip, map(str, env_var.split('=', 1))) + LOG.debug("%r = %r" % (var , cmd)) + if var=="SON_EMU_CMD": LOG.info("Executing entry point script in %r: %r" % (vnfi.name, cmd)) # execute command in new thread to ensure that GK is not blocked by VNF t = threading.Thread(target=vnfi.cmdPrint, args=(cmd,)) @@ -527,6 +554,29 @@ class Service(object): for name, vnfd in self.vnfds.iteritems(): LOG.info("Placed VNF %r on DC %r" % (name, str(vnfd.get("dc")))) + def _calculate_cpu_cfs_values(self, cpu_time_percentage): + """ + Calculate cpu period and quota for CFS + :param cpu_time_percentage: percentage of overall CPU to be used + :return: cpu_period, cpu_quota + """ + if cpu_time_percentage is None: + return -1, -1 + if cpu_time_percentage < 0: + return -1, -1 + # (see: https://www.kernel.org/doc/Documentation/scheduler/sched-bwc.txt) + # Attention minimum cpu_quota is 1ms (micro) + cpu_period = 1000000 # lets consider a fixed period of 1000000 microseconds for now + LOG.debug("cpu_period is %r, cpu_percentage is %r" % (cpu_period, cpu_time_percentage)) + cpu_quota = cpu_period * cpu_time_percentage # calculate the fraction of cpu time for this container + # ATTENTION >= 1000 to avoid a invalid argument system error ... no idea why + if cpu_quota < 1000: + LOG.debug("cpu_quota before correcting: %r" % cpu_quota) + cpu_quota = 1000 + LOG.warning("Increased CPU quota to avoid system error.") + LOG.debug("Calculated: cpu_period=%f / cpu_quota=%f" % (cpu_period, cpu_quota)) + return int(cpu_period), int(cpu_quota) + """ Some (simple) placement algorithms diff --git a/src/emuvim/dcemulator/node.py b/src/emuvim/dcemulator/node.py index b88913b..a0112cf 100755 --- a/src/emuvim/dcemulator/node.py +++ b/src/emuvim/dcemulator/node.py @@ -105,7 +105,7 @@ class Datacenter(object): self.name = "dc%d" % Datacenter.DC_COUNTER Datacenter.DC_COUNTER += 1 # use this for user defined names that can be longer than self.name - self.label = label + self.label = label # dict to store arbitrary metadata (e.g. latitude and longitude) self.metadata = metadata # path to which resource information should be logged (e.g. for experiments). None = no logging @@ -140,7 +140,7 @@ class Datacenter(object): def start(self): pass - def startCompute(self, name, image=None, command=None, network=None, flavor_name="tiny"): + def startCompute(self, name, image=None, command=None, network=None, flavor_name="tiny", **params): """ Create a new container as compute resource and connect it to this data center. @@ -172,7 +172,8 @@ class Datacenter(object): dimage=image, dcmd=command, datacenter=self, - flavor_name=flavor_name + flavor_name=flavor_name, + **params ) # apply resource limits to container if a resource model is defined -- 2.17.1