Skip to content

Commit 5c70099

Browse files
authored
Merge pull request #8 from dos-group/0.4.0
release 0.4.0
2 parents 676fdd1 + 50ff450 commit 5c70099

File tree

9 files changed

+144
-153
lines changed

9 files changed

+144
-153
lines changed

examples/1_single_node.py

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from leaf.application import Task
55
from leaf.infrastructure import Node
6-
from leaf.power import PowerModelNode, PowerMeasurement, power_meter
6+
from leaf.power import PowerModelNode, PowerMeasurement, PowerMeter
77

88
logger = logging.getLogger(__name__)
99
logging.basicConfig(level=logging.DEBUG, format='%(levelname)s\t%(message)s')
@@ -13,34 +13,33 @@ def main():
1313
"""Simple example that adds and removes a task from a single node
1414
1515
Log Output:
16-
DEBUG 0: PowerMeter1: PowerMeasurement(dynamic=0.0W, static=10W)
17-
DEBUG 1: PowerMeter1: PowerMeasurement(dynamic=0.0W, static=10W)
18-
DEBUG 2: PowerMeter1: PowerMeasurement(dynamic=0.0W, static=10W)
16+
DEBUG 0: PowerMeter1: PowerMeasurement(dynamic=0.00W, static=10.00W)
17+
DEBUG 1: PowerMeter1: PowerMeasurement(dynamic=0.00W, static=10.00W)
18+
DEBUG 2: PowerMeter1: PowerMeasurement(dynamic=0.00W, static=10.00W)
1919
INFO task has been added at 3
20-
DEBUG 3: PowerMeter1: PowerMeasurement(dynamic=20.0W, static=10W)
21-
DEBUG 4: PowerMeter1: PowerMeasurement(dynamic=20.0W, static=10W)
22-
DEBUG 5: PowerMeter1: PowerMeasurement(dynamic=20.0W, static=10W)
23-
DEBUG 6: PowerMeter1: PowerMeasurement(dynamic=20.0W, static=10W)
24-
DEBUG 7: PowerMeter1: PowerMeasurement(dynamic=20.0W, static=10W)
20+
DEBUG 3: PowerMeter1: PowerMeasurement(dynamic=20.00W, static=10.00W)
21+
DEBUG 4: PowerMeter1: PowerMeasurement(dynamic=20.00W, static=10.00W)
22+
DEBUG 5: PowerMeter1: PowerMeasurement(dynamic=20.00W, static=10.00W)
23+
DEBUG 6: PowerMeter1: PowerMeasurement(dynamic=20.00W, static=10.00W)
24+
DEBUG 7: PowerMeter1: PowerMeasurement(dynamic=20.00W, static=10.00W)
2525
INFO task has been removed at 8
26-
DEBUG 8: PowerMeter1: PowerMeasurement(dynamic=0.0W, static=10W)
27-
DEBUG 9: PowerMeter1: PowerMeasurement(dynamic=0.0W, static=10W)
26+
DEBUG 8: PowerMeter1: PowerMeasurement(dynamic=0.00W, static=10.00W)
27+
DEBUG 9: PowerMeter1: PowerMeasurement(dynamic=0.00W, static=10.00W)
2828
INFO Total power usage: 200.0 Ws
2929
"""
3030
# Initializing infrastructure and workload
3131
node = Node("node1", cu=100, power_model=PowerModelNode(max_power=30, static_power=10))
3232
task = Task(cu=100)
3333

34-
measurements = []
34+
power_meter = PowerMeter(node, name="PowerMeter1")
3535

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

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

43-
logger.info(f"Total power usage: {float(PowerMeasurement.sum(measurements))} Ws")
42+
logger.info(f"Total power usage: {float(PowerMeasurement.sum(power_meter.measurements))} Ws")
4443

4544

4645
def placement(env, node, task):

examples/2_application_placement.py

Lines changed: 25 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from leaf.application import Application, SourceTask, ProcessingTask, SinkTask
66
from leaf.infrastructure import Node, Link, Infrastructure
77
from leaf.orchestrator import Orchestrator
8-
from leaf.power import PowerModelNode, PowerModelLink, power_meter
8+
from leaf.power import PowerModelNode, PowerModelLink, PowerMeter
99

1010
RANDOM_SEED = 1
1111

@@ -26,41 +26,38 @@ def main():
2626
2727
Log Output:
2828
INFO Placing Application(tasks=3):
29-
INFO - SourceTask(id=0, cu=100) on Node('sensor', cu=0/1000).
30-
INFO - ProcessingTask(id=1, cu=5000) on Node('fog', cu=0/400000).
31-
INFO - SinkTask(id=2, cu=100) on Node('cloud', cu=0/inf).
29+
INFO - SourceTask(id=0, cu=0.1) on Node('sensor', cu=0/1).
30+
INFO - ProcessingTask(id=1, cu=5) on Node('fog', cu=0/400).
31+
INFO - SinkTask(id=2, cu=0.5) on Node('cloud', cu=0/inf).
3232
INFO - DataFlow(bit_rate=1000) on [Link('sensor' -> 'fog', bandwidth=0/30000000.0, latency=10)].
3333
INFO - DataFlow(bit_rate=200) on [Link('fog' -> 'cloud', bandwidth=0/1000000000.0, latency=5)].
34-
DEBUG 0: cloud_and_fog_meter: PowerMeasurement(dynamic=70002.125W, static=30W)
35-
DEBUG 0: infrastructure_meter: PowerMeasurement(dynamic=1570002.2850000001W, static=30.2W)
36-
DEBUG 0.5: application_meter: PowerMeasurement(dynamic=1570002.2850000001W, static=30.2W)
37-
DEBUG 1: cloud_and_fog_meter: PowerMeasurement(dynamic=70002.125W, static=30W)
38-
DEBUG 1.5: application_meter: PowerMeasurement(dynamic=1570002.2850000001W, static=30.2W)
39-
DEBUG 2: infrastructure_meter: PowerMeasurement(dynamic=1570002.2850000001W, static=30.2W)
40-
DEBUG 2: cloud_and_fog_meter: PowerMeasurement(dynamic=70002.125W, static=30W)
41-
DEBUG 2.5: application_meter: PowerMeasurement(dynamic=1570002.2850000001W, static=30.2W)
42-
DEBUG 3: cloud_and_fog_meter: PowerMeasurement(dynamic=70002.125W, static=30W)
43-
DEBUG 3.5: application_meter: PowerMeasurement(dynamic=1570002.2850000001W, static=30.2W)
44-
DEBUG 4: infrastructure_meter: PowerMeasurement(dynamic=1570002.2850000001W, static=30.2W)
45-
DEBUG 4: cloud_and_fog_meter: PowerMeasurement(dynamic=70002.125W, static=30W)
46-
DEBUG 4.5: application_meter: PowerMeasurement(dynamic=1570002.2850000001W, static=30.2W)
34+
DEBUG 0: cloud_and_fog_meter: PowerMeasurement(dynamic=2.38W, static=30.00W)
35+
DEBUG 0: infrastructure_meter: PowerMeasurement(dynamic=2.54W, static=30.20W)
36+
DEBUG 0.5: application_meter: PowerMeasurement(dynamic=2.54W, static=30.20W)
37+
DEBUG 1: cloud_and_fog_meter: PowerMeasurement(dynamic=2.38W, static=30.00W)
38+
DEBUG 1.5: application_meter: PowerMeasurement(dynamic=2.54W, static=30.20W)
39+
DEBUG 2: infrastructure_meter: PowerMeasurement(dynamic=2.54W, static=30.20W)
40+
DEBUG 2: cloud_and_fog_meter: PowerMeasurement(dynamic=2.38W, static=30.00W)
41+
DEBUG 2.5: application_meter: PowerMeasurement(dynamic=2.54W, static=30.20W)
42+
DEBUG 3: cloud_and_fog_meter: PowerMeasurement(dynamic=2.38W, static=30.00W)
43+
DEBUG 3.5: application_meter: PowerMeasurement(dynamic=2.54W, static=30.20W)
44+
DEBUG 4: infrastructure_meter: PowerMeasurement(dynamic=2.54W, static=30.20W)
45+
DEBUG 4: cloud_and_fog_meter: PowerMeasurement(dynamic=2.38W, static=30.00W)
46+
DEBUG 4.5: application_meter: PowerMeasurement(dynamic=2.54W, static=30.20W)
4747
"""
4848
infrastructure = create_infrastructure()
4949
application = create_application(source_node=infrastructure.node("sensor"), sink_node=infrastructure.node("cloud"))
5050
orchestrator = SimpleOrchestrator(infrastructure)
5151
orchestrator.place(application)
5252

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

5757
env = simpy.Environment()
58-
env.process(power_meter(env, application, name="application_meter", delay=0.5,
59-
callback=lambda m: application_measurements.append(m)))
60-
env.process(power_meter(env, [infrastructure.node("cloud"), infrastructure.node("fog")], name="cloud_and_fog_meter",
61-
callback=lambda m: cloud_and_fog_measurements.append(m)))
62-
env.process(power_meter(env, infrastructure, name="infrastructure_meter", measurement_interval=2,
63-
callback=lambda m: infrastructure_measurements.append(m)))
58+
env.process(application_pm.run(env, delay=0.5))
59+
env.process(cloud_and_fog_pm.run(env))
60+
env.process(infrastructure_pm.run(env))
6461
env.run(until=5)
6562

6663

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

8784
infrastructure.add_link(wifi_link_up)
8885
infrastructure.add_link(wan_link_up)

examples/smart_city_traffic/city.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
from examples.smart_city_traffic.infrastructure import Cloud, FogNode, TrafficLight, LinkWanUp, LinkEthernet, \
77
LinkWifiBetweenTrafficLights, LinkWanDown, LinkWifiTaxiToTrafficLight, Taxi
8-
from examples.smart_city_traffic.mobility import Location
8+
from mobility import Location
99
from examples.smart_city_traffic.orchestrator import CityOrchestrator
1010
from examples.smart_city_traffic.settings import *
1111
from leaf.infrastructure import Infrastructure

examples/smart_city_traffic/infrastructure.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ def __init__(self, location: "Location"):
2323
# TODO Shutdown!
2424
global _fog_nodes_created
2525
super().__init__(f"fog_{_fog_nodes_created}", cu=FOG_CU,
26-
power_model=PowerModelNode(max_power=FOG_MAX_POWER, static_power=FOG_STATIC_POWER))
26+
power_model=PowerModelNode(max_power=FOG_MAX_POWER, static_power=FOG_STATIC_POWER),
27+
location=location)
2728
_fog_nodes_created += 1
28-
self.location = location
2929
self.shutdown = FOG_IDLE_SHUTDOWN
3030

3131
def measure_power(self) -> PowerMeasurement:
@@ -48,9 +48,8 @@ def remove_task(self, task: "Task"):
4848
class TrafficLight(Node):
4949
def __init__(self, location: "Location", application_sink: Node):
5050
global _traffic_lights_created
51-
super().__init__(f"traffic_light_{_traffic_lights_created}", cu=0, power_model=PowerModelNode(0, 0))
51+
super().__init__(f"traffic_light_{_traffic_lights_created}", location=location)
5252
_traffic_lights_created += 1
53-
self.location = location
5453
self.application = self._create_cctv_application(application_sink)
5554

5655
def _create_cctv_application(self, application_sink: Node):
@@ -67,7 +66,7 @@ def _create_cctv_application(self, application_sink: Node):
6766
class Taxi(Node):
6867
def __init__(self, env: simpy.Environment, mobility_model: "TaxiMobilityModel", application_sinks: List[Node]):
6968
global _taxis_created
70-
super().__init__(f"taxi_{_taxis_created}", cu=0, power_model=PowerModelNode(0, 0))
69+
super().__init__(f"taxi_{_taxis_created}")
7170
_taxis_created += 1
7271
self.env = env
7372
self.application = self._create_v2i_application(application_sinks)
@@ -77,6 +76,10 @@ def __init__(self, env: simpy.Environment, mobility_model: "TaxiMobilityModel",
7776
def location(self) -> "Location":
7877
return self.mobility_model.location(self.env.now)
7978

79+
@location.setter
80+
def location(self, value):
81+
pass # only for initialization, locations of this node is managed by the TaxiMobilityModel
82+
8083
def _create_v2i_application(self, application_sinks: List[Node]) -> Application:
8184
application = Application()
8285
source_task = SourceTask(cu=0, bound_node=self)

examples/smart_city_traffic/main.py

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from examples.smart_city_traffic.settings import SIMULATION_TIME, FOG_DCS, POWER_MEASUREMENT_INTERVAL, \
1212
FOG_IDLE_SHUTDOWN
1313
from leaf.infrastructure import Infrastructure
14-
from leaf.power import power_meter
14+
from leaf.power import PowerMeter
1515

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

2627
# ----------------- Initialize meters -----------------
2728
if count_taxis:
2829
# Measures the amount of taxis on the map
2930
taxi_counter = TaxiCounter(env, city.infrastructure)
3031
if measure_infrastructure:
3132
# Measures the power usage of cloud and fog nodes as well as WAN and WiFi links
32-
pm_cloud = _PowerMeter(env, entities=city.infrastructure.nodes(type_filter=Cloud), name="cloud")
33-
pm_fog = _PowerMeter(env, entities=city.infrastructure.nodes(type_filter=FogNode), name="fog")
34-
pm_wan_up = _PowerMeter(env, entities=city.infrastructure.links(type_filter=LinkWanUp), name="wan_up")
35-
pm_wan_down = _PowerMeter(env, entities=city.infrastructure.links(type_filter=LinkWanDown), name="wan_down")
36-
pm_wifi = _PowerMeter(env, entities=lambda: city.infrastructure.links(
37-
type_filter=(LinkWifiBetweenTrafficLights, LinkWifiTaxiToTrafficLight)), name="wifi")
33+
pm_cloud = PowerMeter(entities=city.infrastructure.nodes(type_filter=Cloud), name="cloud", measurement_interval=POWER_MEASUREMENT_INTERVAL)
34+
pm_fog = PowerMeter(entities=city.infrastructure.nodes(type_filter=FogNode), name="fog", measurement_interval=POWER_MEASUREMENT_INTERVAL)
35+
pm_wan_up = PowerMeter(entities=city.infrastructure.links(type_filter=LinkWanUp), name="wan_up", measurement_interval=POWER_MEASUREMENT_INTERVAL)
36+
pm_wan_down = PowerMeter(entities=city.infrastructure.links(type_filter=LinkWanDown), name="wan_down", measurement_interval=POWER_MEASUREMENT_INTERVAL)
37+
pm_wifi = PowerMeter(entities=lambda: city.infrastructure.links(type_filter=(LinkWifiBetweenTrafficLights, LinkWifiTaxiToTrafficLight)), name="wifi", measurement_interval=POWER_MEASUREMENT_INTERVAL)
38+
39+
env.process(pm_cloud.run(env))
40+
env.process(pm_fog.run(env))
41+
env.process(pm_wan_up.run(env))
42+
env.process(pm_wan_down.run(env))
43+
env.process(pm_wifi.run(env))
3844
if measure_applications:
3945
# Measures the power usage of the V2I and CCTV applications
40-
pm_v2i = _PowerMeter(env, entities=lambda: [taxi.application for taxi in city.infrastructure.nodes(type_filter=Taxi)], name="v2i")
41-
pm_cctv = _PowerMeter(env, entities=lambda: [tl.application for tl in city.infrastructure.nodes(type_filter=TrafficLight)], name="cctv")
46+
pm_v2i = PowerMeter(entities=lambda: [taxi.application for taxi in city.infrastructure.nodes(type_filter=Taxi)], name="v2i", measurement_interval=POWER_MEASUREMENT_INTERVAL)
47+
pm_cctv = PowerMeter(entities=lambda: [tl.application for tl in city.infrastructure.nodes(type_filter=TrafficLight)], name="cctv", measurement_interval=POWER_MEASUREMENT_INTERVAL)
48+
env.process(pm_v2i.run(env))
49+
env.process(pm_cctv.run(env))
4250

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

7280

73-
class _PowerMeter:
74-
def __init__(self, env, entities, **kwargs):
75-
self.measurements = []
76-
env.process(power_meter(env, entities, measurement_interval=POWER_MEASUREMENT_INTERVAL,
77-
callback=lambda m: self.measurements.append(m), **kwargs))
78-
79-
8081
class TaxiCounter:
8182
def __init__(self, env: simpy.Environment, infrastructure: Infrastructure):
8283
self.env = env

examples/smart_city_traffic/mobility.py

Lines changed: 15 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import math
21
from typing import List, Optional
32

43
import networkx as nx
@@ -7,77 +6,46 @@
76
from examples.smart_city_traffic.infrastructure import TrafficLight, Taxi
87
from examples.smart_city_traffic.settings import UPDATE_MOBILITY_INTERVAL, MAX_CARS_PER_MINUTE, RNG, \
98
TAXI_COUNT_DISTRIBUTION, TAXI_SPEED_DISTRIBUTION
10-
11-
12-
class Location:
13-
def __init__(self, x: float, y: float):
14-
self.x = x
15-
self.y = y
16-
17-
def distance(self, location: "Location") -> float:
18-
return math.sqrt((location.y - self.y) * (location.y - self.y) + (location.x - self.x) * (location.x - self.x))
19-
20-
def __eq__(self, other):
21-
return self.x == other.x and self.y == other.y
22-
23-
def __hash__(self):
24-
return hash((self.x, self.y))
9+
from leaf.mobility import Location
2510

2611

2712
class MobilityManager:
2813

29-
def __init__(self, env: simpy.Environment, city: "City"):
30-
self.env = env
14+
def __init__(self, city: "City"):
3115
self.city = city
32-
self.add_taxis_process = env.process(self._add_taxis_process())
3316

34-
def _add_taxis_process(self):
17+
def run(self, env: simpy.Environment):
3518
while True:
36-
for taxi in self._create_taxis():
19+
for taxi in self._create_taxis(env):
3720
self.city.add_taxi_and_start_v2i_app(taxi)
38-
self.env.process(self._remove_taxi_process(taxi))
39-
yield self.env.timeout(UPDATE_MOBILITY_INTERVAL)
21+
env.process(self._remove_taxi_process(env, taxi))
22+
yield env.timeout(UPDATE_MOBILITY_INTERVAL)
4023

41-
def _remove_taxi_process(self, taxi: "Taxi"):
42-
yield self.env.timeout(taxi.mobility_model.life_time)
24+
def _remove_taxi_process(self, env: simpy.Environment, taxi: "Taxi"):
25+
yield env.timeout(taxi.mobility_model.life_time)
4326
self.city.remove_taxi_and_stop_v2i_app(taxi)
4427

45-
def _create_taxis(self) -> List["Taxi"]:
46-
avg_taxi_speed = _avg_taxi_speed(self.env.now)
47-
avg_taxi_count = _avg_taxi_count(self.env.now)
28+
def _create_taxis(self, env: simpy.Environment) -> List["Taxi"]:
29+
avg_taxi_speed = _avg_taxi_speed(env.now)
30+
avg_taxi_count = _avg_taxi_count(env.now)
4831
taxi_count = RNG.poisson(avg_taxi_count)
49-
return [self._create_taxi(speed=avg_taxi_speed) for _ in range(taxi_count)]
32+
return [self._create_taxi(env=env, speed=avg_taxi_speed) for _ in range(taxi_count)]
5033

51-
def _create_taxi(self, speed: float) -> "Taxi":
34+
def _create_taxi(self, env: simpy.Environment, speed: float) -> "Taxi":
5235
start = self._random_gate_location()
5336
dst = self._random_gate_location()
5437
while not start.distance(dst) > 0.5:
5538
dst = self._random_gate_location()
5639
path = nx.shortest_path(self.city.street_graph, source=start, target=dst)
57-
mobility_model = TaxiMobilityModel(path, speed=speed, start_time=self.env.now)
58-
return Taxi(self.env, mobility_model, application_sinks=self._traffic_lights_on_taxi_path(path))
40+
mobility_model = TaxiMobilityModel(path, speed=speed, start_time=env.now)
41+
return Taxi(env, mobility_model, application_sinks=self._traffic_lights_on_taxi_path(path))
5942

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

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

66-
# /**
67-
# * Calculates which traffic light systems are in the path of the taxi.
68-
# */
69-
# private static List<TrafficLightSystem> getTrafficLightSystemsOnPath(Taxi taxi) {
70-
# List<Location> locations = taxi.getMobilityModel().getPath().getVertexList();
71-
# locations.remove(locations.size() - 1);
72-
# locations.remove(0);
73-
# Set<Location> locationSet = new HashSet<>(locations);
74-
#
75-
# InfrastructureGraphCity topologyExp = (InfrastructureGraphCity) taxi.getSimulation().getNetworkTopology();
76-
# return topologyExp.getTraficLightSystems().stream()
77-
# .filter(tls -> locationSet.contains(tls.getLocation()))
78-
# .collect(Collectors.toList());
79-
# }
80-
8149

8250
class TaxiMobilityModel:
8351
def __init__(self, path: List[Location], speed: float, start_time: float):

0 commit comments

Comments
 (0)