Skip to content

Commit 4b195c2

Browse files
committed
Merge branch 'release-0.3'
2 parents aa352b7 + 2c6b41d commit 4b195c2

27 files changed

+803
-366
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,4 @@ target/
6161
conf/gvas.yaml
6262
docs/slate
6363
.ipynb_checkpoints
64+
fixtures/*

conf/gvas-example.yaml

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,37 @@ vizualization:
2929
random_seed: 42
3030
max_sim_time: 1000
3131

32+
# generalized default values used across simulations
3233
defaults:
3334
network:
34-
capacity: 500
35+
capacity: 1000
3536
base_latency: 10
3637
cluster:
37-
size: 4
38+
size: 2
3839
rack:
39-
size: 96
40+
size: 4
41+
egress_latency: 20
4042
node:
4143
cpus: 4
4244
memory: 16
45+
program:
46+
cpus: 1
47+
memory: 4
48+
49+
# simulation specific parameters
50+
simulations:
51+
52+
# a basic simulation to exercise the cluster objects
53+
simple:
54+
55+
# the number of nodes to add to the cluster
56+
node_count: 8
57+
58+
# the number of nodes that should start in a work phase
59+
start_team_size: 4
60+
61+
# ranges for message size and values
62+
min_msg_size: 10
63+
max_msg_size: 50
64+
min_msg_value: 10
65+
max_msg_value: 50

gvas/__init__.py

Lines changed: 1 addition & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -17,32 +17,7 @@
1717
## Imports
1818
##########################################################################
1919

20-
21-
##########################################################################
22-
## Module Info
23-
##########################################################################
24-
25-
__version_info__ = {
26-
'major': 0,
27-
'minor': 2,
28-
'micro': 0,
29-
'releaselevel': 'final',
30-
'serial': 0,
31-
}
32-
33-
34-
def get_version(short=False):
35-
"""
36-
Prints the version.
37-
"""
38-
assert __version_info__['releaselevel'] in ('alpha', 'beta', 'final')
39-
vers = ["%(major)i.%(minor)i" % __version_info__, ]
40-
if __version_info__['micro']:
41-
vers.append(".%(micro)i" % __version_info__)
42-
if __version_info__['releaselevel'] != 'final' and not short:
43-
vers.append('%s%i' % (__version_info__['releaselevel'][0],
44-
__version_info__['serial']))
45-
return ''.join(vers)
20+
from .version import get_version
4621

4722
##########################################################################
4823
## Package Version

gvas/base.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
from gvas.config import settings
2424
from gvas.dynamo import Sequence
25+
from gvas.results import Results
2526

2627
##########################################################################
2728
## Base Process Objects
@@ -74,16 +75,25 @@ def __init__(self, **kwargs):
7475

7576
self.max_sim_time = kwargs.get('max_sim_time', settings.max_sim_time)
7677
self.env = simpy.Environment()
78+
self.diary = Results()
7779

7880
def script(self):
7981
"""
8082
Use the environment to generate a script.
8183
"""
8284
raise NotImplementedError("Every simulation requires a script.")
8385

86+
def complete(self):
87+
"""
88+
Override for a final report or cleanup at the end of the run.
89+
"""
90+
pass
91+
8492
def run(self):
8593
"""
8694
The entry point for all simulations.
8795
"""
8896
self.script()
89-
self.env.run(until=self.max_sim_time)
97+
with self.diary.timer:
98+
self.env.run(until=self.max_sim_time)
99+
self.complete()

gvas/cluster/cluster.py

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
# Imports
1818
##########################################################################
1919

20+
import random
21+
2022
from gvas.config import settings
2123
from gvas.exceptions import ClusterLacksCapacity
2224
from .base import Machine
@@ -69,14 +71,24 @@ def filter(self, evaluator):
6971
Uses the evaluator function to test against the Node instances and
7072
return a list of matches.
7173
"""
72-
pass
74+
return filter(evaluator, self.nodes)
7375

7476
def first(self, evaluator):
7577
"""
7678
Uses the evaluator function to test against the Node instances and
7779
return the first match.
7880
"""
79-
pass
81+
for n in self.nodes:
82+
if evaluator(n):
83+
return n
84+
return None
85+
86+
def random(self, evaluator=lambda n: True):
87+
"""
88+
Uses the evaluator function to test against the Node instances and
89+
return a random match.
90+
"""
91+
return random.choice(self.filter(evaluator))
8092

8193
def send(self, *args, **kwargs):
8294
"""
@@ -117,7 +129,6 @@ def run(self):
117129
"""
118130
Method to kickoff process simulation.
119131
"""
120-
# TODO: placeholder code
121132
yield self.env.timeout(1)
122133

123134
@property
@@ -131,25 +142,38 @@ def id(self):
131142
return self._id
132143

133144
@property
134-
def first_available_rack(self):
145+
def nodes(self):
146+
"""
147+
Returns a generator to iterate through all of the nodes in the racks.
135148
"""
149+
for r in self.racks.itervalues():
150+
for n in r.nodes.itervalues():
151+
yield n
136152

153+
@property
154+
def first_available_rack(self):
155+
"""
156+
Returns the first rack with room for a node or raises
157+
ClusterLacksCapacity.
137158
"""
138159
ids = sorted(self.racks.keys())
139160

140161
for id in ids:
141162
if not self.racks[id].full:
142163
return self.racks[id]
143164

144-
else:
145-
raise ClusterLacksCapacity()
146-
147-
148-
149-
150-
165+
raise ClusterLacksCapacity()
151166

167+
def __str__(self):
168+
nodes = sum([len(r.nodes) for r in self.racks.itervalues()])
169+
return "Cluster: id: {}, racks={}, nodes={}".format(
170+
self.id,
171+
self.size,
172+
nodes
173+
)
152174

175+
def __repr__(self):
176+
return "<{}>".format(self.__str__())
153177

154178
##########################################################################
155179
# Execution

gvas/cluster/network.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ class Network(object):
3131

3232
def __init__(self, env, parent=None, *args, **kwargs):
3333
self.parent = parent
34+
self.message_count = 0
3435
self.capacity = kwargs.get(
3536
'capacity',
3637
settings.defaults.network.capacity
@@ -59,10 +60,10 @@ def send(self, size):
5960
Removes available bandwidth thereby simulating additional traffic on
6061
the network medium.
6162
"""
62-
try:
63-
self.medium.get(size)
64-
except ValueError:
63+
if self.medium.level < size:
6564
raise BandwidthExceeded()
65+
self.medium.get(size)
66+
self.message_count += 1
6667

6768
def recv(self, size):
6869
"""
@@ -71,6 +72,7 @@ def recv(self, size):
7172
"""
7273
try:
7374
self.medium.put(size)
75+
self.message_count -= 1
7476
except ValueError:
7577
raise
7678

@@ -93,9 +95,11 @@ def latency(self):
9395
return self.base_latency + delay
9496

9597
def __str__(self):
96-
return "Network: capacity={}, base_latency={}".format(
98+
return "Network: capacity={}, bandwidth={}, base_latency={}, latency={}".format(
9799
self.capacity,
98-
self.base_latency
100+
self.bandwidth,
101+
self.base_latency,
102+
self.latency,
99103
)
100104

101105
def __repr__(self):

gvas/cluster/node.py

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
# Classes
2828
##########################################################################
2929

30+
3031
class Node(Machine):
3132

3233
def __init__(self, env, *args, **kwargs):
@@ -45,44 +46,55 @@ def create(cls, env, *args, **kwargs):
4546
while True:
4647
yield cls(env, *args, **kwargs)
4748

48-
def send(self, address, size, value=None):
49+
def send(self, address, port, size, value=None):
4950
"""
50-
Puts a message onto the containing Rack.
51+
Puts a message onto the parent Rack.
5152
"""
52-
pass
53+
self.rack.send(address=address, port=port, size=size, value=value)
5354

54-
def recv(self):
55+
def recv(self, port, size, value=None):
5556
"""
56-
Obtains a message from the containing Rack.
57+
Obtains a message from the parent Rack.
5758
"""
58-
pass
59+
program = None
60+
for p in self.programs.itervalues():
61+
if port in p.ports:
62+
program = p
63+
64+
if program:
65+
program.recv(value)
5966

6067
def assign(self, program):
6168
"""
6269
Ingests a new Program for processing. If there aren't enough resources
6370
available then raises `NodeLacksCapacity`.
6471
"""
65-
# TODO: ensure we have capacity
72+
if self.idle_cpus < program.cpus:
73+
raise NodeLacksCapacity('{} cpus requested but only {} are free.'
74+
.format(program.cpus, self.idle_cpus))
75+
76+
if self.idle_memory < program.memory:
77+
raise NodeLacksCapacity('{}GB requested but only {}GB are free.'
78+
.format(program.memory, self.idle_memory))
6679

6780
self.programs[program.id] = program
6881
program.node = self
69-
program.run()
7082

7183
def run(self):
7284
"""
7385
Method to kickoff process simulation.
7486
"""
75-
# TODO: replace with actual code or returned Program process
76-
while True:
77-
yield self.env.timeout(1)
78-
# print "Node {} checking in at {}".format(self.id, self.env.now)
87+
yield self.env.timeout(1)
7988

8089
@property
8190
def address(self):
8291
"""
8392
Addressable identifier for this node containing the Rack and Node ID.
8493
"""
85-
pass
94+
return "{}:{}".format(
95+
self.rack.id,
96+
self.id
97+
)
8698

8799
@property
88100
def id(self):
@@ -121,8 +133,6 @@ def __repr__(self):
121133
return "<{}>".format(self.__str__())
122134

123135

124-
125-
126136
##########################################################################
127137
# Execution
128138
##########################################################################

gvas/cluster/program.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@
2727
class Program(NamedProcess):
2828

2929
def __init__(self, env, *args, **kwargs):
30-
self.cpus = kwargs.get('cpus', settings.defaults.program.cpus)
31-
self.memory = kwargs.get('memory', settings.defaults.program.memory)
32-
self.ports = kwargs.get('ports', [])
33-
self.node = kwargs.get('node', None)
30+
self.cpus = kwargs.pop('cpus', settings.defaults.program.cpus)
31+
self.memory = kwargs.pop('memory', settings.defaults.program.memory)
32+
self.ports = kwargs.pop('ports', [])
33+
self.node = kwargs.pop('node', None)
3434
super(Program, self).__init__(env, *args, **kwargs)
3535

3636
@classmethod

0 commit comments

Comments
 (0)