Red Hat Training

A Red Hat training course is available for RHEL 8

16.5.4. Exemplo de cenário de ajuste de desempenho da vCPU

Para obter o melhor desempenho possível da vCPU, a Red Hat recomenda o uso do manual vcpupin, emulatorpin e numatune, por exemplo, como no cenário a seguir.

Cenário inicial

  • Seu anfitrião tem as seguintes especificações de hardware:

    • 2 nós NUMA
    • 3 núcleos de CPU em cada nó
    • 2 roscas em cada núcleo

    A saída de virsh nodeinfo de uma máquina desse tipo seria semelhante:

    # virsh nodeinfo
    CPU model:           x86_64
    CPU(s):              12
    CPU frequency:       3661 MHz
    CPU socket(s):       2
    Core(s) per socket:  3
    Thread(s) per core:  2
    NUMA cell(s):        2
    Memory size:         31248692 KiB
  • Você pretende modificar uma VM existente para ter 8 vCPUs, o que significa que ela não caberá em um único nó NUMA.

    Portanto, você deve distribuir 4 vCPUs em cada nó NUMA e fazer com que a topologia da vCPU se pareça o mais próximo possível da topologia do hospedeiro. Isto significa que as vCPUs que funcionam como filamentos irmãos de uma determinada CPU física devem ser fixadas para hospedar filamentos no mesmo núcleo. Para obter detalhes, veja o site Solution abaixo:

Solução

  1. Obter as informações sobre a topologia do hospedeiro:

    # virsh capabilities

    A saída deve incluir uma seção que se pareça com a seguinte:

    <topology>
      <cells num="2">
        <cell id="0">
          <memory unit="KiB">15624346</memory>
          <pages unit="KiB" size="4">3906086</pages>
          <pages unit="KiB" size="2048">0</pages>
          <pages unit="KiB" size="1048576">0</pages>
          <distances>
            <sibling id="0" value="10" />
            <sibling id="1" value="21" />
          </distances>
          <cpus num="6">
            <cpu id="0" socket_id="0" core_id="0" siblings="0,3" />
            <cpu id="1" socket_id="0" core_id="1" siblings="1,4" />
            <cpu id="2" socket_id="0" core_id="2" siblings="2,5" />
            <cpu id="3" socket_id="0" core_id="0" siblings="0,3" />
            <cpu id="4" socket_id="0" core_id="1" siblings="1,4" />
            <cpu id="5" socket_id="0" core_id="2" siblings="2,5" />
          </cpus>
        </cell>
        <cell id="1">
          <memory unit="KiB">15624346</memory>
          <pages unit="KiB" size="4">3906086</pages>
          <pages unit="KiB" size="2048">0</pages>
          <pages unit="KiB" size="1048576">0</pages>
          <distances>
            <sibling id="0" value="21" />
            <sibling id="1" value="10" />
          </distances>
          <cpus num="6">
            <cpu id="6" socket_id="1" core_id="3" siblings="6,9" />
            <cpu id="7" socket_id="1" core_id="4" siblings="7,10" />
            <cpu id="8" socket_id="1" core_id="5" siblings="8,11" />
            <cpu id="9" socket_id="1" core_id="3" siblings="6,9" />
            <cpu id="10" socket_id="1" core_id="4" siblings="7,10" />
            <cpu id="11" socket_id="1" core_id="5" siblings="8,11" />
          </cpus>
        </cell>
      </cells>
    </topology>
  2. Optional: Teste o desempenho da VM usando as ferramentas e utilitários aplicáveis.
  3. Montar e montar 1 GiB páginas enormes no host:

    1. Adicione a seguinte linha à linha de comando do kernel do host:

      padrão_hugepagesz=1G hugepagesz=1G
    2. Crie o arquivo /etc/systemd/system/hugetlb-gigantic-pages.service com o seguinte conteúdo:

      [Unit]
      Description=HugeTLB Gigantic Pages Reservation
      DefaultDependencies=no
      Before=dev-hugepages.mount
      ConditionPathExists=/sys/devices/system/node
      ConditionKernelCommandLine=hugepagesz=1G
      
      [Service]
      Type=oneshot
      RemainAfterExit=yes
      ExecStart=/etc/systemd/hugetlb-reserve-pages.sh
      
      [Install]
      WantedBy=sysinit.target
    3. Crie o arquivo /etc/systemd/hugetlb-reserve-pages.sh com o seguinte conteúdo:

      #!/bin/sh
      
      nodes_path=/sys/devices/system/node/
      if [ ! -d $nodes_path ]; then
      	echo "ERROR: $nodes_path does not exist"
      	exit 1
      fi
      
      reserve_pages()
      {
      	echo $1 > $nodes_path/$2/hugepages/hugepages-1048576kB/nr_hugepages
      }
      
      reserve_pages 4 node1
      reserve_pages 4 node2

      Isto reserva quatro páginas enormes da 1GiB de node1 e quatro páginas enormes da 1GiB de node2.

    4. Tornar executável o roteiro criado na etapa anterior:

      # chmod x /etc/systemd/hugetlb-reserve-pages.sh
    5. Permitir a reserva de páginas enormes na inicialização:

      # systemctl enable hugetlb-gigantic-pages
  4. Use o comando virsh edit para editar a configuração XML da VM que você deseja otimizar, neste exemplo super-VM:

    # virsh edit super-vm
  5. Ajuste a configuração XML da VM da seguinte maneira:

    1. Configure a VM para usar 8 vCPUs estáticas. Use o elemento <vcpu/> para fazer isso.
    2. Fixe cada uma das roscas da vCPU nas roscas correspondentes da CPU hospedeira que ela espelha na topologia. Para fazer isso, use os elementos <vcpupin/> na seção <cputune>.

      Observe que, como mostrado pelo utilitário virsh capabilities acima, os fios da CPU do host não são ordenados seqüencialmente em seus respectivos núcleos. Além disso, as roscas vCPU devem ser fixadas ao conjunto mais alto disponível de núcleos hospedeiros no mesmo nó NUMA. Para uma ilustração da tabela, veja a seção Additional Resources abaixo.

      A configuração XML para as etapas a. e b. pode parecer semelhante a:

      <cputune>
        <vcpupin vcpu='0' cpuset='1'/>
        <vcpupin vcpu='1' cpuset='4'/>
        <vcpupin vcpu='2' cpuset='2'/>
        <vcpupin vcpu='3' cpuset='5'/>
        <vcpupin vcpu='4' cpuset='7'/>
        <vcpupin vcpu='5' cpuset='10'/>
        <vcpupin vcpu='6' cpuset='8'/>
        <vcpupin vcpu='7' cpuset='11'/>
        <emulatorpin cpuset='6,9'/>
      </cputune>
    3. Configure o VM para usar 1 página gigantesca GiB:

      <memoryBacking>
        <hugepages>
          <page size='1' unit='GiB'/>
        </hugepages>
      </memoryBacking>
    4. Configurar os nós NUMA da VM para usar a memória dos nós NUMA correspondentes no host. Para fazer isso, use os elementos <memnode/> na seção <numatune/>:

      <numatune>
        <memory mode="preferred" nodeset="1"/>
        <memnode cellid="0" mode="strict" nodeset="0"/>
        <memnode cellid="1" mode="strict" nodeset="1"/>
      </numatune>
    5. Certifique-se de que o modo CPU esteja configurado para host-passthrough, e que a CPU utilize o cache no modo passthrough:

      <cpu mode="host-passthrough">
        <topology sockets="2" cores="2" threads="2"/>
        <cache mode="passthrough"/>
  6. A configuração XML resultante da VM deve incluir uma seção similar à seguinte:

    [...]
      <memoryBacking>
        <hugepages>
          <page size='1' unit='GiB'/>
        </hugepages>
      </memoryBacking>
      <vcpu placement='static'>8</vcpu>
      <cputune>
        <vcpupin vcpu='0' cpuset='1'/>
        <vcpupin vcpu='1' cpuset='4'/>
        <vcpupin vcpu='2' cpuset='2'/>
        <vcpupin vcpu='3' cpuset='5'/>
        <vcpupin vcpu='4' cpuset='7'/>
        <vcpupin vcpu='5' cpuset='10'/>
        <vcpupin vcpu='6' cpuset='8'/>
        <vcpupin vcpu='7' cpuset='11'/>
        <emulatorpin cpuset='6,9'/>
      </cputune>
      <numatune>
        <memory mode="preferred" nodeset="1"/>
        <memnode cellid="0" mode="strict" nodeset="0"/>
        <memnode cellid="1" mode="strict" nodeset="1"/>
      </numatune>
      <cpu mode="host-passthrough">
        <topology sockets="2" cores="2" threads="2"/>
        <cache mode="passthrough"/>
        <numa>
          <cell id="0" cpus="0-3" memory="2" unit="GiB">
            <distances>
              <sibling id="0" value="10"/>
              <sibling id="1" value="21"/>
            </distances>
          </cell>
          <cell id="1" cpus="4-7" memory="2" unit="GiB">
            <distances>
              <sibling id="0" value="21"/>
              <sibling id="1" value="10"/>
            </distances>
          </cell>
        </numa>
      </cpu>
    </domain>
  7. Optional: Teste o desempenho da VM usando as ferramentas e utilitários aplicáveis para avaliar o impacto da otimização da VM.

Recursos adicionais

  • As tabelas a seguir ilustram as conexões entre as vCPUs e as CPUs anfitriãs às quais elas devem ser fixadas:

    Tabela 16.1. Topologia do hospedeiro

    CPU threads

    0

    3

    1

    4

    2

    5

    6

    9

    7

    10

    8

    11

    Cores

    0

    1

    2

    3

    4

    5

    Sockets

    0

    1

    NUMA nodes

    0

    1

    Tabela 16.2. Topologia VM

    vCPU threads

    0

    1

    2

    3

    4

    5

    6

    7

    Cores

    0

    1

    2

    3

    Sockets

    0

    1

    NUMA nodes

    0

    1

    Tabela 16.3. Topologia combinada de host e VM

    vCPU threads

     

    0

    1

    2

    3

     

    4

    5

    6

    7

    Host CPU threads

    0

    3

    1

    4

    2

    5

    6

    9

    7

    10

    8

    11

    Cores

    0

    1

    2

    3

    4

    5

    Sockets

    0

    1

    NUMA nodes

    0

    1

    Neste cenário, existem 2 nós NUMA e 8 vCPUs. Portanto, 4 fios de vCPU devem ser fixados a cada nó.

    Além disso, a Red Hat recomenda deixar pelo menos uma única linha de CPU disponível em cada nó para as operações do sistema hospedeiro.

    Como neste exemplo, cada nó NUMA abriga 3 núcleos, cada um com 2 fios de CPU hospedeira, o conjunto para o nó 0 se traduz como segue:

    <vcpupin vcpu='0' cpuset='1'/>
    <vcpupin vcpu='1' cpuset='4'/>
    <vcpupin vcpu='2' cpuset='2'/>
    <vcpupin vcpu='3' cpuset='5'/>