summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRick Harris <rick.harris@rackspace.com>2011-05-17 17:27:04 -0500
committerRick Harris <rick.harris@rackspace.com>2011-05-17 17:27:04 -0500
commita4035df4d031d3d90f3f7ce938ff0b8305be6773 (patch)
tree25ecaf98441fa7c3a4d0bfd247a548afa9467b25
parent579bbde235781f43e037410fd6402e4e6ecd534b (diff)
downloadnova-a4035df4d031d3d90f3f7ce938ff0b8305be6773.tar.gz
nova-a4035df4d031d3d90f3f7ce938ff0b8305be6773.tar.xz
nova-a4035df4d031d3d90f3f7ce938ff0b8305be6773.zip
Adding fill first cost function
-rw-r--r--nova/scheduler/least_cost.py12
-rw-r--r--nova/test.py16
-rw-r--r--nova/tests/test_least_cost_scheduler.py33
3 files changed, 56 insertions, 5 deletions
diff --git a/nova/scheduler/least_cost.py b/nova/scheduler/least_cost.py
index e47951f17..79376c358 100644
--- a/nova/scheduler/least_cost.py
+++ b/nova/scheduler/least_cost.py
@@ -34,6 +34,8 @@ flags.DEFINE_list('least_cost_scheduler_cost_functions',
'Which cost functions the LeastCostScheduler should use.')
+# TODO(sirp): Once we have enough of these rules, we can break them out into a
+# cost_functions.py file (perhaps in a least_cost_scheduler directory)
flags.DEFINE_integer('noop_cost_fn_weight', 1,
'How much weight to give the noop cost function')
def noop_cost_fn(host):
@@ -41,6 +43,16 @@ def noop_cost_fn(host):
return 1
+flags.DEFINE_integer('fill_first_cost_fn_weight', 1,
+ 'How much weight to give the fill-first cost function')
+def fill_first_cost_fn(host):
+ """Prefer hosts that have less ram available, filter_hosts will exclude
+ hosts that don't have enough ram"""
+ hostname, caps = host
+ free_mem = caps['compute']['host_memory_free']
+ return free_mem
+
+
class LeastCostScheduler(zone_aware_scheduler.ZoneAwareScheduler):
def get_cost_fns(self):
"""Returns a list of tuples containing weights and cost functions to
diff --git a/nova/test.py b/nova/test.py
index 4deb2a175..401f82d38 100644
--- a/nova/test.py
+++ b/nova/test.py
@@ -181,7 +181,7 @@ class TestCase(unittest.TestCase):
wsgi.Server.start = _wrapped_start
# Useful assertions
- def assertDictMatch(self, d1, d2):
+ def assertDictMatch(self, d1, d2, approx_equal=False, tolerance=0.001):
"""Assert two dicts are equivalent.
This is a 'deep' match in the sense that it handles nested
@@ -212,15 +212,24 @@ class TestCase(unittest.TestCase):
for key in d1keys:
d1value = d1[key]
d2value = d2[key]
+
+ try:
+ within_tolerance = abs(float(d1value) - float(d2value)) < tolerance
+ except ValueError:
+ # If both values aren't convertable to float, just ignore
+ within_tolerance = False
+
if hasattr(d1value, 'keys') and hasattr(d2value, 'keys'):
self.assertDictMatch(d1value, d2value)
elif 'DONTCARE' in (d1value, d2value):
continue
+ elif approx_equal and within_tolerance:
+ continue
elif d1value != d2value:
raise_assertion("d1['%(key)s']=%(d1value)s != "
"d2['%(key)s']=%(d2value)s" % locals())
- def assertDictListMatch(self, L1, L2):
+ def assertDictListMatch(self, L1, L2, approx_equal=False, tolerance=0.001):
"""Assert a list of dicts are equivalent."""
def raise_assertion(msg):
L1str = str(L1)
@@ -236,4 +245,5 @@ class TestCase(unittest.TestCase):
'len(L2)=%(L2count)d' % locals())
for d1, d2 in zip(L1, L2):
- self.assertDictMatch(d1, d2)
+ self.assertDictMatch(d1, d2, approx_equal=approx_equal,
+ tolerance=tolerance)
diff --git a/nova/tests/test_least_cost_scheduler.py b/nova/tests/test_least_cost_scheduler.py
index b2318a3bf..b7bcd2f02 100644
--- a/nova/tests/test_least_cost_scheduler.py
+++ b/nova/tests/test_least_cost_scheduler.py
@@ -119,7 +119,7 @@ class LeastCostSchedulerTestCase(test.TestCase):
def assertWeights(self, expected, num, request_spec, hosts):
weighted = self.sched.weigh_hosts(num, request_spec, hosts)
- self.assertDictListMatch(weighted, expected)
+ self.assertDictListMatch(weighted, expected, approx_equal=True)
def test_no_hosts(self):
num = 1
@@ -137,12 +137,41 @@ class LeastCostSchedulerTestCase(test.TestCase):
num = 1
request_spec = {}
-
hosts = self.sched.filter_hosts(num, request_spec)
expected = [ dict(weight=1, hostname=hostname) for hostname, caps in hosts]
self.assertWeights(expected, num, request_spec, hosts)
+ def test_cost_fn_weights(self):
+ FLAGS.least_cost_scheduler_cost_functions = [
+ 'nova.scheduler.least_cost.noop_cost_fn'
+ ]
FLAGS.noop_cost_fn_weight = 2
+
+ num = 1
+ request_spec = {}
+ hosts = self.sched.filter_hosts(num, request_spec)
+
expected = [ dict(weight=2, hostname=hostname) for hostname, caps in hosts]
self.assertWeights(expected, num, request_spec, hosts)
+
+ def test_fill_first_cost_fn(self):
+ FLAGS.least_cost_scheduler_cost_functions = [
+ 'nova.scheduler.least_cost.fill_first_cost_fn'
+ ]
+ FLAGS.fill_first_cost_fn_weight = 1
+
+ num = 1
+ request_spec = {}
+ hosts = self.sched.filter_hosts(num, request_spec)
+
+ expected = []
+ for idx, (hostname, caps) in enumerate(hosts):
+ # Costs are normalized so over 10 hosts, each host with increasing
+ # free ram will cost 1/N more. Since the lowest cost host has some
+ # free ram, we add in the 1/N for the base_cost
+ weight = 0.1 + (0.1 * idx)
+ weight_dict = dict(weight=weight, hostname=hostname)
+ expected.append(weight_dict)
+
+ self.assertWeights(expected, num, request_spec, hosts)