Skip to content

Commit

Permalink
Merge pull request #8 from dos-group/0.4.0
Browse files Browse the repository at this point in the history
release 0.4.0
  • Loading branch information
birnbaum authored May 16, 2022
2 parents 676fdd1 + 50ff450 commit 5c70099
Show file tree
Hide file tree
Showing 9 changed files with 144 additions and 153 deletions.
29 changes: 14 additions & 15 deletions examples/1_single_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

from leaf.application import Task
from leaf.infrastructure import Node
from leaf.power import PowerModelNode, PowerMeasurement, power_meter
from leaf.power import PowerModelNode, PowerMeasurement, PowerMeter

logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.DEBUG, format='%(levelname)s\t%(message)s')
Expand All @@ -13,34 +13,33 @@ def main():
"""Simple example that adds and removes a task from a single node
Log Output:
DEBUG 0: PowerMeter1: PowerMeasurement(dynamic=0.0W, static=10W)
DEBUG 1: PowerMeter1: PowerMeasurement(dynamic=0.0W, static=10W)
DEBUG 2: PowerMeter1: PowerMeasurement(dynamic=0.0W, static=10W)
DEBUG 0: PowerMeter1: PowerMeasurement(dynamic=0.00W, static=10.00W)
DEBUG 1: PowerMeter1: PowerMeasurement(dynamic=0.00W, static=10.00W)
DEBUG 2: PowerMeter1: PowerMeasurement(dynamic=0.00W, static=10.00W)
INFO task has been added at 3
DEBUG 3: PowerMeter1: PowerMeasurement(dynamic=20.0W, static=10W)
DEBUG 4: PowerMeter1: PowerMeasurement(dynamic=20.0W, static=10W)
DEBUG 5: PowerMeter1: PowerMeasurement(dynamic=20.0W, static=10W)
DEBUG 6: PowerMeter1: PowerMeasurement(dynamic=20.0W, static=10W)
DEBUG 7: PowerMeter1: PowerMeasurement(dynamic=20.0W, static=10W)
DEBUG 3: PowerMeter1: PowerMeasurement(dynamic=20.00W, static=10.00W)
DEBUG 4: PowerMeter1: PowerMeasurement(dynamic=20.00W, static=10.00W)
DEBUG 5: PowerMeter1: PowerMeasurement(dynamic=20.00W, static=10.00W)
DEBUG 6: PowerMeter1: PowerMeasurement(dynamic=20.00W, static=10.00W)
DEBUG 7: PowerMeter1: PowerMeasurement(dynamic=20.00W, static=10.00W)
INFO task has been removed at 8
DEBUG 8: PowerMeter1: PowerMeasurement(dynamic=0.0W, static=10W)
DEBUG 9: PowerMeter1: PowerMeasurement(dynamic=0.0W, static=10W)
DEBUG 8: PowerMeter1: PowerMeasurement(dynamic=0.00W, static=10.00W)
DEBUG 9: PowerMeter1: PowerMeasurement(dynamic=0.00W, static=10.00W)
INFO Total power usage: 200.0 Ws
"""
# Initializing infrastructure and workload
node = Node("node1", cu=100, power_model=PowerModelNode(max_power=30, static_power=10))
task = Task(cu=100)

measurements = []
power_meter = PowerMeter(node, name="PowerMeter1")

env = simpy.Environment() # creating SimPy simulation environment
env.process(placement(env, node, task)) # registering workload placement process
env.process(power_meter(env, node, name="PowerMeter1",
callback=lambda m: measurements.append(m))) # registering power metering process
env.process(power_meter.run(env)) # registering power metering process

env.run(until=10) # run simulation for 10 seconds

logger.info(f"Total power usage: {float(PowerMeasurement.sum(measurements))} Ws")
logger.info(f"Total power usage: {float(PowerMeasurement.sum(power_meter.measurements))} Ws")


def placement(env, node, task):
Expand Down
53 changes: 25 additions & 28 deletions examples/2_application_placement.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from leaf.application import Application, SourceTask, ProcessingTask, SinkTask
from leaf.infrastructure import Node, Link, Infrastructure
from leaf.orchestrator import Orchestrator
from leaf.power import PowerModelNode, PowerModelLink, power_meter
from leaf.power import PowerModelNode, PowerModelLink, PowerMeter

RANDOM_SEED = 1

Expand All @@ -26,41 +26,38 @@ def main():
Log Output:
INFO Placing Application(tasks=3):
INFO - SourceTask(id=0, cu=100) on Node('sensor', cu=0/1000).
INFO - ProcessingTask(id=1, cu=5000) on Node('fog', cu=0/400000).
INFO - SinkTask(id=2, cu=100) on Node('cloud', cu=0/inf).
INFO - SourceTask(id=0, cu=0.1) on Node('sensor', cu=0/1).
INFO - ProcessingTask(id=1, cu=5) on Node('fog', cu=0/400).
INFO - SinkTask(id=2, cu=0.5) on Node('cloud', cu=0/inf).
INFO - DataFlow(bit_rate=1000) on [Link('sensor' -> 'fog', bandwidth=0/30000000.0, latency=10)].
INFO - DataFlow(bit_rate=200) on [Link('fog' -> 'cloud', bandwidth=0/1000000000.0, latency=5)].
DEBUG 0: cloud_and_fog_meter: PowerMeasurement(dynamic=70002.125W, static=30W)
DEBUG 0: infrastructure_meter: PowerMeasurement(dynamic=1570002.2850000001W, static=30.2W)
DEBUG 0.5: application_meter: PowerMeasurement(dynamic=1570002.2850000001W, static=30.2W)
DEBUG 1: cloud_and_fog_meter: PowerMeasurement(dynamic=70002.125W, static=30W)
DEBUG 1.5: application_meter: PowerMeasurement(dynamic=1570002.2850000001W, static=30.2W)
DEBUG 2: infrastructure_meter: PowerMeasurement(dynamic=1570002.2850000001W, static=30.2W)
DEBUG 2: cloud_and_fog_meter: PowerMeasurement(dynamic=70002.125W, static=30W)
DEBUG 2.5: application_meter: PowerMeasurement(dynamic=1570002.2850000001W, static=30.2W)
DEBUG 3: cloud_and_fog_meter: PowerMeasurement(dynamic=70002.125W, static=30W)
DEBUG 3.5: application_meter: PowerMeasurement(dynamic=1570002.2850000001W, static=30.2W)
DEBUG 4: infrastructure_meter: PowerMeasurement(dynamic=1570002.2850000001W, static=30.2W)
DEBUG 4: cloud_and_fog_meter: PowerMeasurement(dynamic=70002.125W, static=30W)
DEBUG 4.5: application_meter: PowerMeasurement(dynamic=1570002.2850000001W, static=30.2W)
DEBUG 0: cloud_and_fog_meter: PowerMeasurement(dynamic=2.38W, static=30.00W)
DEBUG 0: infrastructure_meter: PowerMeasurement(dynamic=2.54W, static=30.20W)
DEBUG 0.5: application_meter: PowerMeasurement(dynamic=2.54W, static=30.20W)
DEBUG 1: cloud_and_fog_meter: PowerMeasurement(dynamic=2.38W, static=30.00W)
DEBUG 1.5: application_meter: PowerMeasurement(dynamic=2.54W, static=30.20W)
DEBUG 2: infrastructure_meter: PowerMeasurement(dynamic=2.54W, static=30.20W)
DEBUG 2: cloud_and_fog_meter: PowerMeasurement(dynamic=2.38W, static=30.00W)
DEBUG 2.5: application_meter: PowerMeasurement(dynamic=2.54W, static=30.20W)
DEBUG 3: cloud_and_fog_meter: PowerMeasurement(dynamic=2.38W, static=30.00W)
DEBUG 3.5: application_meter: PowerMeasurement(dynamic=2.54W, static=30.20W)
DEBUG 4: infrastructure_meter: PowerMeasurement(dynamic=2.54W, static=30.20W)
DEBUG 4: cloud_and_fog_meter: PowerMeasurement(dynamic=2.38W, static=30.00W)
DEBUG 4.5: application_meter: PowerMeasurement(dynamic=2.54W, static=30.20W)
"""
infrastructure = create_infrastructure()
application = create_application(source_node=infrastructure.node("sensor"), sink_node=infrastructure.node("cloud"))
orchestrator = SimpleOrchestrator(infrastructure)
orchestrator.place(application)

application_measurements = []
cloud_and_fog_measurements = []
infrastructure_measurements = []
application_pm = PowerMeter(application, name="application_meter")
cloud_and_fog_pm = PowerMeter([infrastructure.node("cloud"), infrastructure.node("fog")], name="cloud_and_fog_meter")
infrastructure_pm = PowerMeter(infrastructure, name="infrastructure_meter", measurement_interval=2)

env = simpy.Environment()
env.process(power_meter(env, application, name="application_meter", delay=0.5,
callback=lambda m: application_measurements.append(m)))
env.process(power_meter(env, [infrastructure.node("cloud"), infrastructure.node("fog")], name="cloud_and_fog_meter",
callback=lambda m: cloud_and_fog_measurements.append(m)))
env.process(power_meter(env, infrastructure, name="infrastructure_meter", measurement_interval=2,
callback=lambda m: infrastructure_measurements.append(m)))
env.process(application_pm.run(env, delay=0.5))
env.process(cloud_and_fog_pm.run(env))
env.process(infrastructure_pm.run(env))
env.run(until=5)


Expand All @@ -81,8 +78,8 @@ def create_infrastructure():
sensor = Node("sensor", cu=1, power_model=PowerModelNode(max_power=1.8, static_power=0.2))
fog_node = Node("fog", cu=400, power_model=PowerModelNode(max_power=200, static_power=30))
cloud = Node("cloud", power_model=PowerModelNode(power_per_cu=0.5))
wifi_link_up = Link(sensor, fog_node, latency=10, bandwidth=30e6, power_model=PowerModelLink(300))
wan_link_up = Link(fog_node, cloud, latency=5, bandwidth=1e9, power_model=PowerModelLink(6000))
wifi_link_up = Link(sensor, fog_node, latency=10, bandwidth=30e6, power_model=PowerModelLink(300e-9))
wan_link_up = Link(fog_node, cloud, latency=5, bandwidth=1e9, power_model=PowerModelLink(6000e-9))

infrastructure.add_link(wifi_link_up)
infrastructure.add_link(wan_link_up)
Expand Down
2 changes: 1 addition & 1 deletion examples/smart_city_traffic/city.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

from examples.smart_city_traffic.infrastructure import Cloud, FogNode, TrafficLight, LinkWanUp, LinkEthernet, \
LinkWifiBetweenTrafficLights, LinkWanDown, LinkWifiTaxiToTrafficLight, Taxi
from examples.smart_city_traffic.mobility import Location
from mobility import Location
from examples.smart_city_traffic.orchestrator import CityOrchestrator
from examples.smart_city_traffic.settings import *
from leaf.infrastructure import Infrastructure
Expand Down
13 changes: 8 additions & 5 deletions examples/smart_city_traffic/infrastructure.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ def __init__(self, location: "Location"):
# TODO Shutdown!
global _fog_nodes_created
super().__init__(f"fog_{_fog_nodes_created}", cu=FOG_CU,
power_model=PowerModelNode(max_power=FOG_MAX_POWER, static_power=FOG_STATIC_POWER))
power_model=PowerModelNode(max_power=FOG_MAX_POWER, static_power=FOG_STATIC_POWER),
location=location)
_fog_nodes_created += 1
self.location = location
self.shutdown = FOG_IDLE_SHUTDOWN

def measure_power(self) -> PowerMeasurement:
Expand All @@ -48,9 +48,8 @@ def remove_task(self, task: "Task"):
class TrafficLight(Node):
def __init__(self, location: "Location", application_sink: Node):
global _traffic_lights_created
super().__init__(f"traffic_light_{_traffic_lights_created}", cu=0, power_model=PowerModelNode(0, 0))
super().__init__(f"traffic_light_{_traffic_lights_created}", location=location)
_traffic_lights_created += 1
self.location = location
self.application = self._create_cctv_application(application_sink)

def _create_cctv_application(self, application_sink: Node):
Expand All @@ -67,7 +66,7 @@ def _create_cctv_application(self, application_sink: Node):
class Taxi(Node):
def __init__(self, env: simpy.Environment, mobility_model: "TaxiMobilityModel", application_sinks: List[Node]):
global _taxis_created
super().__init__(f"taxi_{_taxis_created}", cu=0, power_model=PowerModelNode(0, 0))
super().__init__(f"taxi_{_taxis_created}")
_taxis_created += 1
self.env = env
self.application = self._create_v2i_application(application_sinks)
Expand All @@ -77,6 +76,10 @@ def __init__(self, env: simpy.Environment, mobility_model: "TaxiMobilityModel",
def location(self) -> "Location":
return self.mobility_model.location(self.env.now)

@location.setter
def location(self, value):
pass # only for initialization, locations of this node is managed by the TaxiMobilityModel

def _create_v2i_application(self, application_sinks: List[Node]) -> Application:
application = Application()
source_task = SourceTask(cu=0, bound_node=self)
Expand Down
35 changes: 18 additions & 17 deletions examples/smart_city_traffic/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
from examples.smart_city_traffic.settings import SIMULATION_TIME, FOG_DCS, POWER_MEASUREMENT_INTERVAL, \
FOG_IDLE_SHUTDOWN
from leaf.infrastructure import Infrastructure
from leaf.power import power_meter
from leaf.power import PowerMeter

logger = logging.getLogger(__name__)
logging.basicConfig(level=logging.WARN, format='%(levelname)s: %(message)s')
Expand All @@ -21,24 +21,32 @@ def main(count_taxis: bool, measure_infrastructure: bool, measure_applications:
# ----------------- Set up experiment -----------------
env = simpy.Environment()
city = City(env)
MobilityManager(env, city)
mobility_manager = MobilityManager(city)
env.process(mobility_manager.run(env))

# ----------------- Initialize meters -----------------
if count_taxis:
# Measures the amount of taxis on the map
taxi_counter = TaxiCounter(env, city.infrastructure)
if measure_infrastructure:
# Measures the power usage of cloud and fog nodes as well as WAN and WiFi links
pm_cloud = _PowerMeter(env, entities=city.infrastructure.nodes(type_filter=Cloud), name="cloud")
pm_fog = _PowerMeter(env, entities=city.infrastructure.nodes(type_filter=FogNode), name="fog")
pm_wan_up = _PowerMeter(env, entities=city.infrastructure.links(type_filter=LinkWanUp), name="wan_up")
pm_wan_down = _PowerMeter(env, entities=city.infrastructure.links(type_filter=LinkWanDown), name="wan_down")
pm_wifi = _PowerMeter(env, entities=lambda: city.infrastructure.links(
type_filter=(LinkWifiBetweenTrafficLights, LinkWifiTaxiToTrafficLight)), name="wifi")
pm_cloud = PowerMeter(entities=city.infrastructure.nodes(type_filter=Cloud), name="cloud", measurement_interval=POWER_MEASUREMENT_INTERVAL)
pm_fog = PowerMeter(entities=city.infrastructure.nodes(type_filter=FogNode), name="fog", measurement_interval=POWER_MEASUREMENT_INTERVAL)
pm_wan_up = PowerMeter(entities=city.infrastructure.links(type_filter=LinkWanUp), name="wan_up", measurement_interval=POWER_MEASUREMENT_INTERVAL)
pm_wan_down = PowerMeter(entities=city.infrastructure.links(type_filter=LinkWanDown), name="wan_down", measurement_interval=POWER_MEASUREMENT_INTERVAL)
pm_wifi = PowerMeter(entities=lambda: city.infrastructure.links(type_filter=(LinkWifiBetweenTrafficLights, LinkWifiTaxiToTrafficLight)), name="wifi", measurement_interval=POWER_MEASUREMENT_INTERVAL)

env.process(pm_cloud.run(env))
env.process(pm_fog.run(env))
env.process(pm_wan_up.run(env))
env.process(pm_wan_down.run(env))
env.process(pm_wifi.run(env))
if measure_applications:
# Measures the power usage of the V2I and CCTV applications
pm_v2i = _PowerMeter(env, entities=lambda: [taxi.application for taxi in city.infrastructure.nodes(type_filter=Taxi)], name="v2i")
pm_cctv = _PowerMeter(env, entities=lambda: [tl.application for tl in city.infrastructure.nodes(type_filter=TrafficLight)], name="cctv")
pm_v2i = PowerMeter(entities=lambda: [taxi.application for taxi in city.infrastructure.nodes(type_filter=Taxi)], name="v2i", measurement_interval=POWER_MEASUREMENT_INTERVAL)
pm_cctv = PowerMeter(entities=lambda: [tl.application for tl in city.infrastructure.nodes(type_filter=TrafficLight)], name="cctv", measurement_interval=POWER_MEASUREMENT_INTERVAL)
env.process(pm_v2i.run(env))
env.process(pm_cctv.run(env))

# ------------------ Run experiment -------------------
for until in tqdm(range(1, SIMULATION_TIME)):
Expand Down Expand Up @@ -70,13 +78,6 @@ def main(count_taxis: bool, measure_infrastructure: bool, measure_applications:
csvfile.write(csv_content)


class _PowerMeter:
def __init__(self, env, entities, **kwargs):
self.measurements = []
env.process(power_meter(env, entities, measurement_interval=POWER_MEASUREMENT_INTERVAL,
callback=lambda m: self.measurements.append(m), **kwargs))


class TaxiCounter:
def __init__(self, env: simpy.Environment, infrastructure: Infrastructure):
self.env = env
Expand Down
62 changes: 15 additions & 47 deletions examples/smart_city_traffic/mobility.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import math
from typing import List, Optional

import networkx as nx
Expand All @@ -7,77 +6,46 @@
from examples.smart_city_traffic.infrastructure import TrafficLight, Taxi
from examples.smart_city_traffic.settings import UPDATE_MOBILITY_INTERVAL, MAX_CARS_PER_MINUTE, RNG, \
TAXI_COUNT_DISTRIBUTION, TAXI_SPEED_DISTRIBUTION


class Location:
def __init__(self, x: float, y: float):
self.x = x
self.y = y

def distance(self, location: "Location") -> float:
return math.sqrt((location.y - self.y) * (location.y - self.y) + (location.x - self.x) * (location.x - self.x))

def __eq__(self, other):
return self.x == other.x and self.y == other.y

def __hash__(self):
return hash((self.x, self.y))
from leaf.mobility import Location


class MobilityManager:

def __init__(self, env: simpy.Environment, city: "City"):
self.env = env
def __init__(self, city: "City"):
self.city = city
self.add_taxis_process = env.process(self._add_taxis_process())

def _add_taxis_process(self):
def run(self, env: simpy.Environment):
while True:
for taxi in self._create_taxis():
for taxi in self._create_taxis(env):
self.city.add_taxi_and_start_v2i_app(taxi)
self.env.process(self._remove_taxi_process(taxi))
yield self.env.timeout(UPDATE_MOBILITY_INTERVAL)
env.process(self._remove_taxi_process(env, taxi))
yield env.timeout(UPDATE_MOBILITY_INTERVAL)

def _remove_taxi_process(self, taxi: "Taxi"):
yield self.env.timeout(taxi.mobility_model.life_time)
def _remove_taxi_process(self, env: simpy.Environment, taxi: "Taxi"):
yield env.timeout(taxi.mobility_model.life_time)
self.city.remove_taxi_and_stop_v2i_app(taxi)

def _create_taxis(self) -> List["Taxi"]:
avg_taxi_speed = _avg_taxi_speed(self.env.now)
avg_taxi_count = _avg_taxi_count(self.env.now)
def _create_taxis(self, env: simpy.Environment) -> List["Taxi"]:
avg_taxi_speed = _avg_taxi_speed(env.now)
avg_taxi_count = _avg_taxi_count(env.now)
taxi_count = RNG.poisson(avg_taxi_count)
return [self._create_taxi(speed=avg_taxi_speed) for _ in range(taxi_count)]
return [self._create_taxi(env=env, speed=avg_taxi_speed) for _ in range(taxi_count)]

def _create_taxi(self, speed: float) -> "Taxi":
def _create_taxi(self, env: simpy.Environment, speed: float) -> "Taxi":
start = self._random_gate_location()
dst = self._random_gate_location()
while not start.distance(dst) > 0.5:
dst = self._random_gate_location()
path = nx.shortest_path(self.city.street_graph, source=start, target=dst)
mobility_model = TaxiMobilityModel(path, speed=speed, start_time=self.env.now)
return Taxi(self.env, mobility_model, application_sinks=self._traffic_lights_on_taxi_path(path))
mobility_model = TaxiMobilityModel(path, speed=speed, start_time=env.now)
return Taxi(env, mobility_model, application_sinks=self._traffic_lights_on_taxi_path(path))

def _random_gate_location(self) -> Location:
return RNG.choice(self.city.entry_point_locations)

def _traffic_lights_on_taxi_path(self, path: List) -> List[TrafficLight]:
return [tl for tl in self.city.infrastructure.nodes(type_filter=TrafficLight) if tl.location in path]

# /**
# * Calculates which traffic light systems are in the path of the taxi.
# */
# private static List<TrafficLightSystem> getTrafficLightSystemsOnPath(Taxi taxi) {
# List<Location> locations = taxi.getMobilityModel().getPath().getVertexList();
# locations.remove(locations.size() - 1);
# locations.remove(0);
# Set<Location> locationSet = new HashSet<>(locations);
#
# InfrastructureGraphCity topologyExp = (InfrastructureGraphCity) taxi.getSimulation().getNetworkTopology();
# return topologyExp.getTraficLightSystems().stream()
# .filter(tls -> locationSet.contains(tls.getLocation()))
# .collect(Collectors.toList());
# }


class TaxiMobilityModel:
def __init__(self, path: List[Location], speed: float, start_time: float):
Expand Down
Loading

0 comments on commit 5c70099

Please sign in to comment.