Add CPUWeigher
nova provides many different types of filter, providing both resource stacking/spreading and affinity/anti-affinity patterns. Curiously enough, however, there is no way to configure a stack or spread policy of CPUs. Add one. Change-Id: I90ee8a2081c2a0465441a8d81d161f4887b4e1fb Implements: bp vcpu-weighterchanges/25/379525/11
parent
fb0b785169
commit
67f52ab36d
@ -0,0 +1,41 @@
|
||||
# Copyright (c) 2016, Red Hat Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""
|
||||
CPU Weigher. Weigh hosts by their CPU usage.
|
||||
|
||||
The default is to spread instances across all hosts evenly. If you prefer
|
||||
stacking, you can set the 'cpu_weight_multiplier' option to a negative
|
||||
number and the weighing has the opposite effect of the default.
|
||||
"""
|
||||
|
||||
import nova.conf
|
||||
from nova.scheduler import weights
|
||||
|
||||
CONF = nova.conf.CONF
|
||||
|
||||
|
||||
class CPUWeigher(weights.BaseHostWeigher):
|
||||
minval = 0
|
||||
|
||||
def weight_multiplier(self):
|
||||
"""Override the weight multiplier."""
|
||||
return CONF.filter_scheduler.cpu_weight_multiplier
|
||||
|
||||
def _weigh_object(self, host_state, weight_properties):
|
||||
"""Higher weights win. We want spreading to be the default."""
|
||||
vcpus_free = (host_state.vcpus_total * host_state.cpu_allocation_ratio
|
||||
- host_state.vcpus_used)
|
||||
return vcpus_free
|
@ -0,0 +1,129 @@
|
||||
# Copyright 2016, Red Hat Inc.
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
"""
|
||||
Tests For Scheduler CPU weights.
|
||||
"""
|
||||
|
||||
from nova.scheduler import weights
|
||||
from nova.scheduler.weights import cpu
|
||||
from nova import test
|
||||
from nova.tests.unit.scheduler import fakes
|
||||
|
||||
|
||||
class CPUWeigherTestCase(test.NoDBTestCase):
|
||||
def setUp(self):
|
||||
super(CPUWeigherTestCase, self).setUp()
|
||||
self.weight_handler = weights.HostWeightHandler()
|
||||
self.weighers = [cpu.CPUWeigher()]
|
||||
|
||||
def _get_weighed_host(self, hosts, weight_properties=None):
|
||||
if weight_properties is None:
|
||||
weight_properties = {}
|
||||
return self.weight_handler.get_weighed_objects(self.weighers,
|
||||
hosts, weight_properties)[0]
|
||||
|
||||
def _get_all_hosts(self):
|
||||
host_values = [
|
||||
('host1', 'node1', {'vcpus_total': 8, 'vcpus_used': 8,
|
||||
'cpu_allocation_ratio': 1.0}), # 0 free
|
||||
('host2', 'node2', {'vcpus_total': 4, 'vcpus_used': 2,
|
||||
'cpu_allocation_ratio': 1.0}), # 2 free
|
||||
('host3', 'node3', {'vcpus_total': 6, 'vcpus_used': 0,
|
||||
'cpu_allocation_ratio': 1.0}), # 6 free
|
||||
('host4', 'node4', {'vcpus_total': 8, 'vcpus_used': 0,
|
||||
'cpu_allocation_ratio': 2.0}), # 16 free
|
||||
]
|
||||
return [fakes.FakeHostState(host, node, values)
|
||||
for host, node, values in host_values]
|
||||
|
||||
def test_multiplier_default(self):
|
||||
hostinfo_list = self._get_all_hosts()
|
||||
|
||||
# host1: vcpus_free=0
|
||||
# host2: vcpus_free=2
|
||||
# host3: vcpus_free=6
|
||||
# host4: vcpus_free=16
|
||||
|
||||
# so, host4 should win:
|
||||
weighed_host = self._get_weighed_host(hostinfo_list)
|
||||
self.assertEqual(1.0, weighed_host.weight)
|
||||
self.assertEqual('host4', weighed_host.obj.host)
|
||||
|
||||
def test_multiplier_none(self):
|
||||
self.flags(cpu_weight_multiplier=0.0, group='filter_scheduler')
|
||||
hostinfo_list = self._get_all_hosts()
|
||||
|
||||
# host1: vcpus_free=0
|
||||
# host2: vcpus_free=2
|
||||
# host3: vcpus_free=6
|
||||
# host4: vcpus_free=16
|
||||
|
||||
# We do not know the host, all have same weight.
|
||||
weighed_host = self._get_weighed_host(hostinfo_list)
|
||||
self.assertEqual(0.0, weighed_host.weight)
|
||||
|
||||
def test_multiplier_positive(self):
|
||||
self.flags(cpu_weight_multiplier=2.0, group='filter_scheduler')
|
||||
hostinfo_list = self._get_all_hosts()
|
||||
|
||||
# host1: vcpus_free=0
|
||||
# host2: vcpus_free=2
|
||||
# host3: vcpus_free=6
|
||||
# host4: vcpus_free=16
|
||||
|
||||
# so, host4 should win:
|
||||
weighed_host = self._get_weighed_host(hostinfo_list)
|
||||
self.assertEqual(1.0 * 2, weighed_host.weight)
|
||||
self.assertEqual('host4', weighed_host.obj.host)
|
||||
|
||||
def test_multiplier_negative(self):
|
||||
self.flags(cpu_weight_multiplier=-1.0, group='filter_scheduler')
|
||||
hostinfo_list = self._get_all_hosts()
|
||||
|
||||
# host1: vcpus_free=0
|
||||
# host2: vcpus_free=2
|
||||
# host3: vcpus_free=6
|
||||
# host4: vcpus_free=16
|
||||
|
||||
# so, host1 should win:
|
||||
weighed_host = self._get_weighed_host(hostinfo_list)
|
||||
self.assertEqual('host1', weighed_host.obj.host)
|
||||
|
||||
def test_negative_host(self):
|
||||
self.flags(cpu_weight_multiplier=1.0, group='filter_scheduler')
|
||||
hostinfo_list = self._get_all_hosts()
|
||||
host_attr = {'vcpus_total': 4, 'vcpus_used': 6,
|
||||
'cpu_allocation_ratio': 1.0}
|
||||
host_state = fakes.FakeHostState('negative', 'negative', host_attr)
|
||||
hostinfo_list = list(hostinfo_list) + [host_state]
|
||||
|
||||
# host1: vcpus_free=0
|
||||
# host2: vcpus_free=2
|
||||
# host3: vcpus_free=6
|
||||
# host4: vcpus_free=16
|
||||
# negative: vcpus_free=-2
|
||||
|
||||
# so, host4 should win
|
||||
weights = self.weight_handler.get_weighed_objects(self.weighers,
|
||||
hostinfo_list, {})
|
||||
|
||||
weighed_host = weights[0]
|
||||
self.assertEqual(1, weighed_host.weight)
|
||||
self.assertEqual('host4', weighed_host.obj.host)
|
||||
|
||||
# and negativehost should lose
|
||||
weighed_host = weights[-1]
|
||||
self.assertEqual(0, weighed_host.weight)
|
||||
self.assertEqual('negative', weighed_host.obj.host)
|
@ -0,0 +1,6 @@
|
||||
---
|
||||
features:
|
||||
- |
|
||||
Add ``CPUWeigher`` weigher. This can be used to spread (default) or pack
|
||||
workloads on hosts based on their vCPU usage. This can be configured using
|
||||
the ``[filter_scheduler] cpu_weight_multiplier`` configuration option.
|
Loading…
Reference in New Issue