Loading .gitignore 0 → 100644 +2 −0 Original line number Diff line number Diff line .idea __pycache__ LICENSE 0 → 100644 +25 −0 Original line number Diff line number Diff line BSD 2-Clause License Copyright (c) 2019, Michael Pfeiffer All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. README.md 0 → 100644 +33 −0 Original line number Diff line number Diff line Tenant separation simulation ============================ DES simulating the overhead of a IaaS cloud platform with hardware-separated tenants. Dependencies ------------ * [Python](https://www.python.org/) >= 3.5 * [Numpy](https://www.numpy.org/) * [SciPy](https://www.scipy.org/) * [Pandas](https://pandas.pydata.org/) * [Matplotlib](https://matplotlib.org/) Usage ----- Scenario parameters can be configured in the `SCENARIOS` dictionary in `main.py`. The simulation can be started with: ``` ./main.py ``` For each scenario, the four migration strategies (None, Migration, Separation, Separation+Migration) are simulated in 32 runs. All available CPU cores are used. The results are saved to CSV files. Afterwards, the CSV files can be aggregated by running: ``` ./plot.py ``` Some provisional plots are created as well. cloud.py 0 → 100644 +144 −0 Original line number Diff line number Diff line import math import random from host import Host from vm import VM class Cloud: def __init__(self, sim): self.sim = sim self.strategy = sim.strategy self.hosts = {} self.vms = set() self.tenants = {} self.record_state() def record_state(self): num_vms = len(self.vms) used_hosts = sum(len(t) for t in self.hosts.values()) active_tenants = len(self.tenants) wasted_hosts = 0 for tenant_hosts in self.hosts.values(): wasted_hosts += len(tenant_hosts) - math.ceil(sum(h.load for h in tenant_hosts) / Host.host_size) self.sim.stats.record_cloud_state(self.sim.clock, num_vms, used_hosts, active_tenants, wasted_hosts) def add_host(self, tenant): h = Host(self) if tenant not in self.hosts: self.hosts[tenant] = {h, } else: self.hosts[tenant].add(h) return h def _best_hosts(self, tid, size): best_room = Host.host_size best_hosts = [] for h in self.hosts[tid]: room = Host.host_size - h.load if room == best_room: best_hosts.append(h) elif size <= room < best_room: best_room = room best_hosts = [h] return best_hosts def find_free_host(self, size, tenant): if self.strategy in ('sep', 'sepmig'): tid = tenant else: tid = 0 if tid not in self.hosts: return self.add_host(tid) best_hosts = self._best_hosts(tid, size) if len(best_hosts) > 0: return random.choice(best_hosts) else: return self.add_host(tid) def create_vm(self): size = self.sim.vm_sizes_distribution.rvs() tenant = self.sim.vm_tenant_distribution.rvs() if tenant not in self.tenants: self.tenants[tenant] = 1 else: self.tenants[tenant] += 1 self.sim.stats.record_vm_creation(size, tenant) host = self.find_free_host(size, tenant) vm = VM(size, tenant, host) self.vms.add(vm) host.add(vm) self.record_state() self.sim.schedule_vm_deletion(vm) self.sim.schedule_vm_creation(self) def delete_vm(self, vm): self.vms.remove(vm) self.tenants[vm.tenant] -= 1 if self.tenants[vm.tenant] == 0: del self.tenants[vm.tenant] if self.strategy in ('sep', 'sepmig'): tid = vm.tenant else: tid = 0 if len(vm.host.vms) == 0: self.hosts[tid].remove(vm.host) if len(self.hosts[tid]) == 0: del self.hosts[tid] if self.strategy in ('mig', 'sepmig'): if tid in self.hosts and len(self.hosts[tid]) > 1: self.compact_tenant(tid) self.record_state() def compact_tenant(self, tid): min_load = Host.host_size min_hosts = [] for h in self.hosts[tid]: if h.load == min_load: min_hosts.append(h) elif h.load < min_load: min_load = h.load min_hosts = [h] old_host = random.choice(min_hosts) vm = random.sample(old_host.vms, 1)[0] best_hosts = self._best_hosts(tid, vm.size) if len(best_hosts) == 0: return new_host = random.choice(best_hosts) if new_host.load <= old_host.load: return old_host.vms.remove(vm) old_host.load -= vm.size old_host.tenants[vm.tenant] -= 1 if old_host.tenants[vm.tenant] == 0: del old_host.tenants[vm.tenant] if len(old_host.vms) == 0: self.hosts[tid].remove(old_host) if len(self.hosts[tid]) == 0: raise RuntimeError('Tenant should not be empty') vm.host = new_host new_host.add(vm) host.py 0 → 100644 +27 −0 Original line number Diff line number Diff line class Host: host_size = 32 def __init__(self, cloud): self.cloud = cloud self.vms = set() self.load = 0 self.tenants = {} def add(self, vm): self.vms.add(vm) self.load += vm.size if vm.tenant not in self.tenants: self.tenants[vm.tenant] = 1 else: self.tenants[vm.tenant] += 1 def delete(self, vm): self.vms.remove(vm) self.load -= vm.size self.tenants[vm.tenant] -= 1 if self.tenants[vm.tenant] == 0: del self.tenants[vm.tenant] self.cloud.delete_vm(vm) Loading
LICENSE 0 → 100644 +25 −0 Original line number Diff line number Diff line BSD 2-Clause License Copyright (c) 2019, Michael Pfeiffer All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
README.md 0 → 100644 +33 −0 Original line number Diff line number Diff line Tenant separation simulation ============================ DES simulating the overhead of a IaaS cloud platform with hardware-separated tenants. Dependencies ------------ * [Python](https://www.python.org/) >= 3.5 * [Numpy](https://www.numpy.org/) * [SciPy](https://www.scipy.org/) * [Pandas](https://pandas.pydata.org/) * [Matplotlib](https://matplotlib.org/) Usage ----- Scenario parameters can be configured in the `SCENARIOS` dictionary in `main.py`. The simulation can be started with: ``` ./main.py ``` For each scenario, the four migration strategies (None, Migration, Separation, Separation+Migration) are simulated in 32 runs. All available CPU cores are used. The results are saved to CSV files. Afterwards, the CSV files can be aggregated by running: ``` ./plot.py ``` Some provisional plots are created as well.
cloud.py 0 → 100644 +144 −0 Original line number Diff line number Diff line import math import random from host import Host from vm import VM class Cloud: def __init__(self, sim): self.sim = sim self.strategy = sim.strategy self.hosts = {} self.vms = set() self.tenants = {} self.record_state() def record_state(self): num_vms = len(self.vms) used_hosts = sum(len(t) for t in self.hosts.values()) active_tenants = len(self.tenants) wasted_hosts = 0 for tenant_hosts in self.hosts.values(): wasted_hosts += len(tenant_hosts) - math.ceil(sum(h.load for h in tenant_hosts) / Host.host_size) self.sim.stats.record_cloud_state(self.sim.clock, num_vms, used_hosts, active_tenants, wasted_hosts) def add_host(self, tenant): h = Host(self) if tenant not in self.hosts: self.hosts[tenant] = {h, } else: self.hosts[tenant].add(h) return h def _best_hosts(self, tid, size): best_room = Host.host_size best_hosts = [] for h in self.hosts[tid]: room = Host.host_size - h.load if room == best_room: best_hosts.append(h) elif size <= room < best_room: best_room = room best_hosts = [h] return best_hosts def find_free_host(self, size, tenant): if self.strategy in ('sep', 'sepmig'): tid = tenant else: tid = 0 if tid not in self.hosts: return self.add_host(tid) best_hosts = self._best_hosts(tid, size) if len(best_hosts) > 0: return random.choice(best_hosts) else: return self.add_host(tid) def create_vm(self): size = self.sim.vm_sizes_distribution.rvs() tenant = self.sim.vm_tenant_distribution.rvs() if tenant not in self.tenants: self.tenants[tenant] = 1 else: self.tenants[tenant] += 1 self.sim.stats.record_vm_creation(size, tenant) host = self.find_free_host(size, tenant) vm = VM(size, tenant, host) self.vms.add(vm) host.add(vm) self.record_state() self.sim.schedule_vm_deletion(vm) self.sim.schedule_vm_creation(self) def delete_vm(self, vm): self.vms.remove(vm) self.tenants[vm.tenant] -= 1 if self.tenants[vm.tenant] == 0: del self.tenants[vm.tenant] if self.strategy in ('sep', 'sepmig'): tid = vm.tenant else: tid = 0 if len(vm.host.vms) == 0: self.hosts[tid].remove(vm.host) if len(self.hosts[tid]) == 0: del self.hosts[tid] if self.strategy in ('mig', 'sepmig'): if tid in self.hosts and len(self.hosts[tid]) > 1: self.compact_tenant(tid) self.record_state() def compact_tenant(self, tid): min_load = Host.host_size min_hosts = [] for h in self.hosts[tid]: if h.load == min_load: min_hosts.append(h) elif h.load < min_load: min_load = h.load min_hosts = [h] old_host = random.choice(min_hosts) vm = random.sample(old_host.vms, 1)[0] best_hosts = self._best_hosts(tid, vm.size) if len(best_hosts) == 0: return new_host = random.choice(best_hosts) if new_host.load <= old_host.load: return old_host.vms.remove(vm) old_host.load -= vm.size old_host.tenants[vm.tenant] -= 1 if old_host.tenants[vm.tenant] == 0: del old_host.tenants[vm.tenant] if len(old_host.vms) == 0: self.hosts[tid].remove(old_host) if len(self.hosts[tid]) == 0: raise RuntimeError('Tenant should not be empty') vm.host = new_host new_host.add(vm)
host.py 0 → 100644 +27 −0 Original line number Diff line number Diff line class Host: host_size = 32 def __init__(self, cloud): self.cloud = cloud self.vms = set() self.load = 0 self.tenants = {} def add(self, vm): self.vms.add(vm) self.load += vm.size if vm.tenant not in self.tenants: self.tenants[vm.tenant] = 1 else: self.tenants[vm.tenant] += 1 def delete(self, vm): self.vms.remove(vm) self.load -= vm.size self.tenants[vm.tenant] -= 1 if self.tenants[vm.tenant] == 0: del self.tenants[vm.tenant] self.cloud.delete_vm(vm)