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-weighter
This commit is contained in:
parent
fb0b785169
commit
67f52ab36d
@ -397,9 +397,15 @@ The Filter Scheduler weighs hosts based on the config option
|
||||
`nova.scheduler.weights.all_weighers`, which selects the following weighers:
|
||||
|
||||
* |RAMWeigher| Compute weight based on available RAM on the compute node.
|
||||
Sort with the largest weight winning. If the multiplier is negative, the
|
||||
Sort with the largest weight winning. If the multiplier,
|
||||
:oslo.config:opt:`filter_scheduler.ram_weight_multiplier`, is negative, the
|
||||
host with least RAM available will win (useful for stacking hosts, instead
|
||||
of spreading).
|
||||
* |CPUWeigher| Compute weight based on available vCPUs on the compute node.
|
||||
Sort with the largest weight winning. If the multiplier,
|
||||
:oslo.config:opt:`filter_scheduler.cpu_weight_multiplier`, is negative, the
|
||||
host with least CPUs available will win (useful for stacking hosts, instead
|
||||
of spreading).
|
||||
* |DiskWeigher| Hosts are weighted and sorted by free disk space with the largest
|
||||
weight winning. If the multiplier is negative, the host with less disk space available
|
||||
will win (useful for stacking hosts, instead of spreading).
|
||||
@ -489,6 +495,7 @@ in :mod:`nova.tests.scheduler`.
|
||||
.. |AggregateMultiTenancyIsolation| replace:: :class:`AggregateMultiTenancyIsolation <nova.scheduler.filters.aggregate_multitenancy_isolation.AggregateMultiTenancyIsolation>`
|
||||
.. |NUMATopologyFilter| replace:: :class:`NUMATopologyFilter <nova.scheduler.filters.numa_topology_filter.NUMATopologyFilter>`
|
||||
.. |RAMWeigher| replace:: :class:`RAMWeigher <nova.scheduler.weights.ram.RAMWeigher>`
|
||||
.. |CPUWeigher| replace:: :class:`CPUWeigher <nova.scheduler.weights.cpu.CPUWeigher>`
|
||||
.. |AggregateImagePropertiesIsolation| replace:: :class:`AggregateImagePropertiesIsolation <nova.scheduler.filters.aggregate_image_properties_isolation.AggregateImagePropertiesIsolation>`
|
||||
.. |MetricsFilter| replace:: :class:`MetricsFilter <nova.scheduler.filters.metrics_filter.MetricsFilter>`
|
||||
.. |MetricsWeigher| replace:: :class:`MetricsWeigher <nova.scheduler.weights.metrics.MetricsWeigher>`
|
||||
|
@ -431,7 +431,7 @@ Possible values:
|
||||
default=1.0,
|
||||
deprecated_group="DEFAULT",
|
||||
help="""
|
||||
Ram weight multipler ratio.
|
||||
RAM weight multipler ratio.
|
||||
|
||||
This option determines how hosts with more or less available RAM are weighed. A
|
||||
positive value will result in the scheduler preferring hosts with more
|
||||
@ -450,6 +450,29 @@ Possible values:
|
||||
|
||||
* An integer or float value, where the value corresponds to the multipler
|
||||
ratio for this weigher.
|
||||
"""),
|
||||
cfg.FloatOpt("cpu_weight_multiplier",
|
||||
default=1.0,
|
||||
help="""
|
||||
CPU weight multiplier ratio.
|
||||
|
||||
Multiplier used for weighting free vCPUs. Negative numbers indicate stacking
|
||||
rather than spreading.
|
||||
|
||||
This option is only used by the FilterScheduler and its subclasses; if you use
|
||||
a different scheduler, this option has no effect. Also note that this setting
|
||||
only affects scheduling if the 'cpu' weigher is enabled.
|
||||
|
||||
Possible values:
|
||||
|
||||
* An integer or float value, where the value corresponds to the multipler
|
||||
ratio for this weigher.
|
||||
|
||||
Related options:
|
||||
|
||||
* ``filter_scheduler.weight_classes``: This weigher must be added to list of
|
||||
enabled weight classes if the ``weight_classes`` setting is set to a
|
||||
non-default value.
|
||||
"""),
|
||||
cfg.FloatOpt("disk_weight_multiplier",
|
||||
default=1.0,
|
||||
|
41
nova/scheduler/weights/cpu.py
Normal file
41
nova/scheduler/weights/cpu.py
Normal file
@ -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
|
129
nova/tests/unit/scheduler/weights/test_weights_cpu.py
Normal file
129
nova/tests/unit/scheduler/weights/test_weights_cpu.py
Normal file
@ -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)
|
6
releasenotes/notes/add-cpu-weigher-2e982c9f9751d631.yaml
Normal file
6
releasenotes/notes/add-cpu-weigher-2e982c9f9751d631.yaml
Normal file
@ -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
Block a user