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
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>
- Optional: Teste o desempenho da VM usando as ferramentas e utilitários aplicáveis.
Montar e montar 1 GiB páginas enormes no host:
Adicione a seguinte linha à linha de comando do kernel do host:
padrão_hugepagesz=1G hugepagesz=1G
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
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.
Tornar executável o roteiro criado na etapa anterior:
# chmod x /etc/systemd/hugetlb-reserve-pages.sh
Permitir a reserva de páginas enormes na inicialização:
# systemctl enable hugetlb-gigantic-pages
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
Ajuste a configuração XML da VM da seguinte maneira:
-
Configure a VM para usar 8 vCPUs estáticas. Use o elemento
<vcpu/>
para fazer isso. 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>
Configure o VM para usar 1 página gigantesca GiB:
<memoryBacking> <hugepages> <page size='1' unit='GiB'/> </hugepages> </memoryBacking>
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>
Certifique-se de que o modo CPU esteja configurado para
host-passthrough
, e que a CPU utilize o cache no modopassthrough
:<cpu mode="host-passthrough"> <topology sockets="2" cores="2" threads="2"/> <cache mode="passthrough"/>
-
Configure a VM para usar 8 vCPUs estáticas. Use o elemento
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>
- 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'/>