[Kimchi-devel] [PATCH] Multiple changes in guest maxMemory management

Paulo Vital pvital at linux.vnet.ibm.com
Tue Dec 8 17:57:54 UTC 2015


Reviewed-by: Paulo Vital <pvital at linux.vnet.ibm.com>

On 12/08/2015 02:15 PM, Rodrigo Trujillo wrote:
> This patch includes 3 changes:
> - Set max_memory limit to 1TB
> - Set max_memory to 4*Memory
> - Set memory "hard_limit" tag to (maxMemory + 1Gib)
> 
> All changes are related to issues found with memory in PCI passthrough
> or during Live Migration tests.
> 
> Signed-off-by: Rodrigo Trujillo <rodrigo.trujillo at linux.vnet.ibm.com>
> ---
>  model/vms.py  | 98 ++++++++++++++++++++++++++++++++++-------------------------
>  osinfo.py     | 11 ++++++-
>  vmtemplate.py | 13 ++++++++
>  3 files changed, 79 insertions(+), 43 deletions(-)
> 
> diff --git a/model/vms.py b/model/vms.py
> index 4835adb..47dd0ce 100644
> --- a/model/vms.py
> +++ b/model/vms.py
> @@ -57,6 +57,7 @@ from wok.plugins.kimchi.model.utils import get_ascii_nonascii_name, get_vm_name
>  from wok.plugins.kimchi.model.utils import get_metadata_node
>  from wok.plugins.kimchi.model.utils import remove_metadata_node
>  from wok.plugins.kimchi.model.utils import set_metadata_node
> +from wok.plugins.kimchi.osinfo import MAX_MEM_LIM
>  from wok.plugins.kimchi.screenshot import VMScreenshot
>  from wok.plugins.kimchi.utils import template_name_from_uri
>  from wok.plugins.kimchi.xmlutils.cpu import get_cpu_xml, get_numa_xml
> @@ -881,49 +882,62 @@ class VMModel(object):
>          else:
>              if memory is not None:
>                  root.remove(memory)
> +
> +            def _get_slots(maxMem):
> +                slots = (maxMem - params['memory']) >> 10
> +                # Libvirt does not accepts slots <= 1
> +                if slots < 0:
> +                    raise OperationFailed("KCHVM0041E")
> +                elif slots == 0:
> +                    slots = 1
> +
> +                distro, _, _ = platform.linux_distribution()
> +                if distro == "IBM_PowerKVM":
> +                    # max 32 slots on Power
> +                    if slots > 32:
> +                        slots = 32
> +                return slots
> +            # End of _get_slots
> +
> +            def _get_newMaxMem():
> +                # Setting max memory to 4x memory requested, host total memory,
> +                # or 1 TB. This should avoid problems with live migration
> +                newMaxMem = MAX_MEM_LIM
> +                hostMem = self.conn.get().getInfo()[1] << 10
> +                if hostMem < newMaxMem:
> +                    newMaxMem = hostMem
> +                mem = params.get('memory', 0)
> +                if (mem != 0) and (((mem * 4) << 10) < newMaxMem):
> +                    newMaxMem = (mem * 4) << 10
> +
> +                distro, _, _ = platform.linux_distribution()
> +                if distro == "IBM_PowerKVM":
> +                    # max memory 256MiB alignment
> +                    newMaxMem -= (newMaxMem % 256)
> +                return newMaxMem
> +
>              maxMem = root.find('.maxMemory')
> -            host_mem = self.conn.get().getInfo()[1]
> -            slots = (host_mem - params['memory']) >> 10
> -            # Libvirt does not accepts slots <= 1
> -            if slots < 0:
> -                raise OperationFailed("KCHVM0041E")
> -            elif slots == 0:
> -                slots = 1
> -
> -            force_max_mem_update = False
> -            distro, _, _ = platform.linux_distribution()
> -            if distro == "IBM_PowerKVM":
> -                # max memory 256MiB alignment
> -                host_mem -= (host_mem % PPC_MEM_ALIGN)
> -                # force max memory update if it exists but it's wrong.
> -                if maxMem is not None and\
> -                   int(maxMem.text) != (host_mem << 10):
> -                    force_max_mem_update = True
> -
> -                # max 32 slots on Power
> -                if slots > 32:
> -                    slots = 32
> -
> -            if maxMem is None:
> -                max_mem_xml = E.maxMemory(
> -                    str(host_mem << 10),
> -                    unit='Kib',
> -                    slots=str(slots))
> -                root.insert(0, max_mem_xml)
> -                new_xml = ET.tostring(root, encoding="utf-8")
> -            else:
> -                # Update slots only
> -                new_xml = xml_item_update(ET.tostring(root, encoding="utf-8"),
> -                                          './maxMemory',
> -                                          str(slots),
> -                                          attr='slots')
> -
> -                if force_max_mem_update:
> -                    new_xml = xml_item_update(new_xml,
> -                                              './maxMemory',
> -                                              str(host_mem << 10))
> -
> -            return new_xml
> +            if maxMem is not None:
> +                root.remove(maxMem)
> +
> +            # Setting maxMemory
> +            newMaxMem = _get_newMaxMem()
> +            slots = _get_slots(newMaxMem >> 10)
> +            max_mem_xml = E.maxMemory(
> +                str(newMaxMem),
> +                unit='Kib',
> +                slots=str(slots))
> +            root.insert(0, max_mem_xml)
> +
> +            # Setting memory hard limit to max_memory + 1GiB
> +            memtune = root.find('memtune')
> +            if memtune is not None:
> +                hl = memtune.find('hard_limit')
> +                if hl is not None:
> +                    memtune.remove(hl)
> +                    memtune.insert(0, E.hard_limit(str(newMaxMem + 1048576),
> +                                                   unit='Kib'))
> +
>          return ET.tostring(root, encoding="utf-8")
> 
>      def _get_host_maxcpu(self):
> diff --git a/osinfo.py b/osinfo.py
> index 1891398..33757a3 100644
> --- a/osinfo.py
> +++ b/osinfo.py
> @@ -88,6 +88,9 @@ modern_version_bases = {'x86': {'debian': '6.0', 'ubuntu': '7.10',
>  icon_available_distros = [icon[5:-4] for icon in glob.glob1('%s/images/'
>                            % PluginPaths('kimchi').ui_dir, 'icon-*.png')]
> 
> +# Max memory 1TB, in KiB
> +MAX_MEM_LIM = 1073741824
> +
> 
>  def _get_arch():
>      for arch, sub_archs in SUPPORTED_ARCHS.iteritems():
> @@ -199,7 +202,9 @@ def lookup(distro, version):
>      params['os_version'] = version
>      arch = _get_arch()
> 
> -    # Setting maxMemory of the VM, which will be equal total Host memory in Kib
> +    # Setting maxMemory of the VM, which will be lesser value between:
> +    # [ 1TB,  (Template Memory * 4),  Host Physical Memory.
> +    # Here, we return 1TB or aligned Host Physical Memory
>      if hasattr(psutil, 'virtual_memory'):
>          params['max_memory'] = psutil.virtual_memory().total >> 10
>      else:
> @@ -212,6 +217,10 @@ def lookup(distro, version):
>              alignment = params['max_memory'] % (PPC_MEM_ALIGN << 10)
>              params['max_memory'] -= alignment
> 
> +    # Setting limit to 1TB
> +    if params['max_memory'] > MAX_MEM_LIM:
> +        params['max_memory'] = MAX_MEM_LIM
> +
>      if distro in modern_version_bases[arch]:
>          if LooseVersion(version) >= LooseVersion(
>                  modern_version_bases[arch][distro]):
> diff --git a/vmtemplate.py b/vmtemplate.py
> index b90f221..b6e9431 100644
> --- a/vmtemplate.py
> +++ b/vmtemplate.py
> @@ -352,6 +352,13 @@ class VMTemplate(object):
>          else:
>              params['cdroms'] = cdrom_xml
> 
> +        # In order to avoid problems with live migration, setting maxMemory of
> +        # the VM, which will be lesser value between:
> +        # [ 1TB,  (Template Memory * 4),  Host Physical Memory.
> +        tmp_max_mem = (params['memory'] << 10) * 4
> +        if tmp_max_mem < params['max_memory']:
> +            params['max_memory'] = tmp_max_mem
> +
>          # Setting maximum number of slots to avoid errors when hotplug memory
>          # Number of slots are the numbers of chunks of 1GB that fit inside
>          # the max_memory of the host minus memory assigned to the VM. It
> @@ -367,6 +374,9 @@ class VMTemplate(object):
>              if distro == "IBM_PowerKVM":
>                  params['slots'] = 32
> 
> +        # set a hard limit using max_memory + 1GiB
> +        params['hard_limit'] = params['max_memory'] + (1024 << 10)
> +
>          cpu_topo = self.info.get('cpu_info').get('topology')
>          if (cpu_topo is not None):
>              sockets = int(max_vcpus / (cpu_topo['cores'] *
> @@ -390,6 +400,9 @@ class VMTemplate(object):
>            %(qemu-stream-cmdline)s
>            <name>%(name)s</name>
>            <uuid>%(uuid)s</uuid>
> +          <memtune>
> +            <hard_limit unit='KiB'>%(hard_limit)s</hard_limit>
> +          </memtune>
>            <maxMemory slots='%(slots)s' unit='KiB'>%(max_memory)s</maxMemory>
>            <memory unit='MiB'>%(memory)s</memory>
>            %(vcpus)s
> 




More information about the Kimchi-devel mailing list