Merge "Fix overcommit for NUMA-based instances"
This commit is contained in:
commit
5ac6b2ef40
|
@ -137,19 +137,23 @@ class NUMACell(base.NovaObject):
|
|||
cpu_usage=cpu_usage, memory_usage=memory_usage,
|
||||
mempages=[], pinned_cpus=set([]), siblings=[])
|
||||
|
||||
def can_fit_hugepages(self, pagesize, memory):
|
||||
"""Returns whether memory can fit into hugepages size
|
||||
def can_fit_pagesize(self, pagesize, memory, use_free=True):
|
||||
"""Returns whether memory can fit into a given pagesize.
|
||||
|
||||
:param pagesize: a page size in KibB
|
||||
:param memory: a memory size asked to fit in KiB
|
||||
:param use_free: if true, assess based on free memory rather than total
|
||||
memory. This means overcommit is not allowed, which should be the
|
||||
case for hugepages since these are memlocked by the kernel and
|
||||
can't be swapped out.
|
||||
|
||||
:returns: whether memory can fit in hugepages
|
||||
:raises: MemoryPageSizeNotSupported if page size not supported
|
||||
"""
|
||||
for pages in self.mempages:
|
||||
avail_kb = pages.free_kb if use_free else pages.total_kb
|
||||
if pages.size_kb == pagesize:
|
||||
return (memory <= pages.free_kb and
|
||||
(memory % pages.size_kb) == 0)
|
||||
return memory <= avail_kb and (memory % pages.size_kb) == 0
|
||||
raise exception.MemoryPageSizeNotSupported(pagesize=pagesize)
|
||||
|
||||
|
||||
|
@ -193,6 +197,11 @@ class NUMAPagesTopology(base.NovaObject):
|
|||
"""Returns the avail memory size in KiB."""
|
||||
return self.free * self.size_kb
|
||||
|
||||
@property
|
||||
def total_kb(self):
|
||||
"""Returns the total memory size in KiB."""
|
||||
return self.total * self.size_kb
|
||||
|
||||
|
||||
@base.NovaObjectRegistry.register
|
||||
class NUMATopology(base.NovaObject):
|
||||
|
|
|
@ -135,7 +135,8 @@ class _TestNUMA(object):
|
|||
self.assertEqual(512, pages_topology.free)
|
||||
self.assertEqual(1048576, pages_topology.free_kb)
|
||||
|
||||
def test_can_fit_hugepages(self):
|
||||
def test_can_fit_pagesize(self):
|
||||
# NOTE(stephenfin): '**' is Python's "power of" symbol
|
||||
cell = objects.NUMACell(
|
||||
id=0, cpuset=set([1, 2]), memory=1024,
|
||||
siblings=[set([1]), set([2])], pinned_cpus=set([]),
|
||||
|
@ -148,18 +149,42 @@ class _TestNUMA(object):
|
|||
size_kb=1048576, total=4, used=1, reserved=1)])
|
||||
|
||||
pagesize = 2048
|
||||
self.assertTrue(cell.can_fit_hugepages(pagesize, 2 ** 20))
|
||||
self.assertFalse(cell.can_fit_hugepages(pagesize, 2 ** 21))
|
||||
self.assertFalse(cell.can_fit_hugepages(pagesize, 2 ** 19 + 1))
|
||||
self.assertTrue(cell.can_fit_pagesize(pagesize, 2 ** 20))
|
||||
self.assertFalse(cell.can_fit_pagesize(pagesize, 2 ** 21))
|
||||
self.assertFalse(cell.can_fit_pagesize(pagesize, 2 ** 19 + 1))
|
||||
|
||||
pagesize = 1048576
|
||||
self.assertTrue(cell.can_fit_hugepages(pagesize, 2 ** 20))
|
||||
self.assertTrue(cell.can_fit_hugepages(pagesize, 2 ** 20 * 2))
|
||||
self.assertFalse(cell.can_fit_hugepages(pagesize, 2 ** 20 * 3))
|
||||
self.assertTrue(cell.can_fit_pagesize(pagesize, 2 ** 20))
|
||||
self.assertTrue(cell.can_fit_pagesize(pagesize, 2 ** 20 * 2))
|
||||
self.assertFalse(cell.can_fit_pagesize(pagesize, 2 ** 20 * 3))
|
||||
|
||||
self.assertRaises(
|
||||
exception.MemoryPageSizeNotSupported,
|
||||
cell.can_fit_hugepages, 12345, 2 ** 20)
|
||||
cell.can_fit_pagesize, 12345, 2 ** 20)
|
||||
|
||||
def test_can_fit_pagesize_oversubscription(self):
|
||||
"""Validate behavior when using page oversubscription.
|
||||
|
||||
While hugepages aren't themselves oversubscribable, we also track small
|
||||
pages which are.
|
||||
"""
|
||||
# NOTE(stephenfin): '**' is Python's "power of" symbol
|
||||
cell = objects.NUMACell(
|
||||
id=0, cpuset=set([1, 2]), memory=1024,
|
||||
siblings=[set([1]), set([2])], pinned_cpus=set([]),
|
||||
mempages=[
|
||||
# 1 GiB total, all used
|
||||
objects.NUMAPagesTopology(
|
||||
size_kb=4, total=2 ** 18, used=2 ** 18),
|
||||
])
|
||||
|
||||
pagesize = 4
|
||||
# request 2^20 KiB (so 1 GiB)
|
||||
self.assertTrue(cell.can_fit_pagesize(
|
||||
pagesize, 2 ** 20, use_free=False))
|
||||
# request 2^20 + 1 KiB (so # > 1 GiB)
|
||||
self.assertFalse(cell.can_fit_pagesize(
|
||||
pagesize, 2 ** 20 + 1, use_free=False))
|
||||
|
||||
def test_default_behavior(self):
|
||||
inst_cell = objects.NUMACell()
|
||||
|
|
|
@ -636,7 +636,7 @@ def _numa_cell_supports_pagesize_request(host_cell, inst_cell):
|
|||
def verify_pagesizes(host_cell, inst_cell, avail_pagesize):
|
||||
inst_cell_mem = inst_cell.memory * units.Ki
|
||||
for pagesize in avail_pagesize:
|
||||
if host_cell.can_fit_hugepages(pagesize, inst_cell_mem):
|
||||
if host_cell.can_fit_pagesize(pagesize, inst_cell_mem):
|
||||
return pagesize
|
||||
|
||||
if inst_cell.pagesize == MEMPAGES_SMALL:
|
||||
|
@ -1038,13 +1038,16 @@ def _numa_fit_instance_cell(host_cell, instance_cell, limit_cell=None,
|
|||
# The instance provides a NUMA topology but does not define any
|
||||
# particular page size for its memory.
|
||||
if host_cell.mempages:
|
||||
# The host supports explicit page sizes. Use the smallest
|
||||
# available page size.
|
||||
# The host supports explicit page sizes. Use a pagesize-aware
|
||||
# memory check using the smallest available page size.
|
||||
pagesize = _get_smallest_pagesize(host_cell)
|
||||
LOG.debug('No specific pagesize requested for instance, '
|
||||
'selected pagesize: %d', pagesize)
|
||||
if not host_cell.can_fit_hugepages(
|
||||
pagesize, instance_cell.memory * units.Ki):
|
||||
# we want to allow overcommit in this case as we're not using
|
||||
# hugepages
|
||||
if not host_cell.can_fit_pagesize(pagesize,
|
||||
instance_cell.memory * units.Ki,
|
||||
use_free=False):
|
||||
LOG.debug('Not enough available memory to schedule instance '
|
||||
'with pagesize %(pagesize)d. Required: '
|
||||
'%(required)s, available: %(available)s, total: '
|
||||
|
@ -1055,8 +1058,12 @@ def _numa_fit_instance_cell(host_cell, instance_cell, limit_cell=None,
|
|||
'pagesize': pagesize})
|
||||
return
|
||||
else:
|
||||
# NOTE (ndipanov): do not allow an instance to overcommit against
|
||||
# itself on any NUMA cell
|
||||
# The host does not support explicit page sizes. Ignore pagesizes
|
||||
# completely.
|
||||
# NOTE(stephenfin): Do not allow an instance to overcommit against
|
||||
# itself on any NUMA cell, i.e. with 'ram_allocation_ratio = 2.0'
|
||||
# on a host with 1GB RAM, we should allow two 1GB instances but not
|
||||
# one 2GB instance.
|
||||
if instance_cell.memory > host_cell.memory:
|
||||
LOG.debug('Not enough host cell memory to fit instance cell. '
|
||||
'Required: %(required)d, actual: %(actual)d',
|
||||
|
|
Loading…
Reference in New Issue