Compartilhe

Entendendo os tamanhos da página de memória no ARM64 - SitePoint

Uma das maneiras pelas quais a arquitetura ARM64 é diferente de X86 é a capacidade de configurar o tamanho das páginas de memória na unidade de gerenciamento de memória (MMU) da CPU para 4K, 16K ou 64K. Este artigo resume o tamanho da página de memória, como configurar o tamanho da página em sistemas Linux e quando pode fazer sentido usar um tamanho de página diferente em seus aplicativos.

Introdução ao tamanho da página de memória

Como discutimos anteriormente em Diagnosticando e corrigindo um problema de desempenho de falha de página com ARM64 AtomicsOs sistemas operacionais apresentam um espaço de endereço de memória virtual para aplicativos e mapeie as páginas de memória física para endereços de memória virtual usando uma tabela de página. A CPU fornece um mecanismo chamado Buffer de Lokaside de Tradução (TLB) para garantir que as páginas de memória acessadas recentemente possam ser identificadas e lidas mais rapidamente usando o cache CPU L1 ou L2.

O tamanho das páginas de memória física (chamadas de grânulos) na arquitetura x86 é um 4KB fixo. Nos sistemas ARM64, como a Ampere Altra (R) ou a Ampereona (R), no entanto, o desenvolvedor pode configurar o tamanho das páginas de memória física para 4KB, 16KB ou 64KB.

Quando usar tamanhos de página maiores?

À medida que a alteração do tamanho da página pode afetar a eficiência da memória e o desempenho do seu sistema, é importante entender quando faz sentido usar um tamanho de página maior e as compensações envolvidas. Tamanhos de página maiores podem levar a um uso menos eficiente da memória, com páginas que não estão cheias.

Por exemplo, se armazenarmos 7 KB de dados na memória, isso usará duas páginas de 4 KB para um total de 8kb de memória em um sistema com páginas de kernel de 4 KB, uma eficiência de 87,5%. Em um sistema com páginas de 64 KB, no entanto, agora estamos consumindo uma única página de 64kb com 7 KB de dados para uma eficiência de 11% com a alocação única acima.

No entanto, o MMU e o kernel do sistema operacional são inteligentes o suficiente para usar blocos contíguos de memória que foram alocados anteriormente, mas não estão cheios de alocações futuras de memória. Se o mesmo processo alocar 32kb de memória posteriormente, ainda estaremos usando apenas uma página de 64kb com 39kb ocupada. Com o tamanho da página em 4K, agora estaremos gerenciando dez páginas de 4 KB.

O segundo trade-off está em desempenho devido a falhas de cache para as pesquisas da tabela de páginas. Há um número relativamente pequeno de entradas de página armazenadas no TLB para cada nível de cache (L1, L2, cache no nível do sistema).

Com tamanhos de página maiores, essas entradas TLB cobrem uma quantidade maior da memória física. Nos processadores Ampere Altra e Altra Max, por exemplo, os dados L1 TLB possuem 48 entradas e o L2 TLB possui 1280 entradas.

Isso significa que, com um grânulo de 4 KB, o L1 TLB pode cache os endereços de cache para 192 KB de memória física, e o L2 TLB pode armazenar endereços de página que cobrem 5 MB de memória física.

Com os tamanhos de página de 64 KB, isso aumenta para 3MB para dados L1 TLB e 80 MB para o L2 TLB. Cada cache erra no TLB adiciona tempo para uma página para encontrar a página física correspondendo a uma pesquisa de memória virtual, armazenando em cache a página uma vez localizada e atualizando o TLB adequadamente. Com páginas maiores, você tem menos erros de cache e melhor desempenho para cargas de trabalho intensivas em memória.

Você também melhora o desempenho de E/S tendo zonas maiores de memória contígua disponível. Como resultado, aplicativos intensivos em dados que possuem muitos dados na memória ou em trânsito podem se beneficiar de tamanhos de página maiores. Algumas dessas aplicações são:

  • Bancos de dados: Os sistemas de banco de dados tendem a armazenar muitas informações na memória para fins de armazenamento em cache e têm muita E/S de disco para grandes conjuntos de dados. Ambas as características tornam os servidores de banco de dados ótimos candidatos para grandes tamanhos de página de memória.
  • Infraestrutura de virtualização: As máquinas virtuais (VMs) incluem uma imagem de disco, compreendendo um kernel do sistema operacional e todos os aplicativos exigidos por essa VM, e variam em tamanho de centenas de megabytes a centenas de gigabytes. Como resultado, eles podem usar grandes quantidades de memória e podem se beneficiar de tamanhos de página maiores.
  • Crie servidores para integração contínua: Tarefas como criar o processo do kernel Linux milhares de arquivos de origem e usar muita RAM enquanto os compilam. Como uma carga de trabalho de alta taxa de transferência, os hosts configurados com tamanhos de página maiores tendem a ter um desempenho melhor como servidores de construção.
  • Aplicações de rede ou E/S pesadas: Para aplicativos com muita E/S de rede e processamento de dados na memória, como caches de objetos, balanceadores de carga, firewalls ou streaming de vídeo, páginas de memória grandes podem resultar em menos falhas de página, melhorando o desempenho.
  • Aplicativos intensivos em memória, como inferência de IA: A IA Inferência, executando um modelo treinado como um mecanismo de recomendação de um chatbot LLM, é uma carga de trabalho intensiva em memória e CPU, onde grandes tamanhos de página de memória podem ajudar a fornecer alto desempenho.

Em geral, o desempenho desses tipos de aplicativos com tamanhos de página maiores dependerá de vários fatores, incluindo os conjuntos de dados envolvidos e o padrão de acesso à memória do aplicativo.

Se você acredita que seu aplicativo pode se beneficiar de páginas de memória maiores, deve comparar sua carga de trabalho de destino com páginas 4K e 64K e tomar sua decisão de implantação com base nos resultados de seus testes.

Além de comparar seu aplicativo de destino com páginas 4K e 64K usando dados no estilo de produção, você pode avaliar o benefício potencial de tamanhos de página maiores usando a ferramenta “Perf”, medindo as bancas da TLB (ou seja, com que frequência as ervas TLB resultam no pipeline da CPU para parar enquanto as informações são carregadas de memória).

Primeiro, verifique se o kernel suporta os contadores de barraca TLB nas CPUs AmpereOne e mais recentes.

# perf list | grep end_tlb
stall_backend_tlb
stall_frontend_tlb

Com o suporte do kernel, confirmou que as barracas de pipeline devido a erros de TLB podem ser medidas:

# perf stat -e instructions,cycles,stall_frontend_tlb,stall_backend_tlb ./a.out 
time for 12344321 * 100M nops: 3.7 s 
Performance counter stats for './a.out': 
12,648,071,049 instructions # 1.14 insn per cycle  
11,109,161,102 cycles  
1,482,795,078 stall_frontend_tlb  
1,334,751 stall_backend_tlb  
3. 706937365 seconds time elapsed 
3. 629966000 seconds user 
0. 000995000 seconds sys

A razão (Stall_frontend_TLB + Stall_Backend_Tlb)/Cycles é um limite superior para o tempo que pode ser salvo usando páginas de memória maiores.

Cuidado, no entanto, que, como 4K, tem sido o tamanho da página padrão há tanto tempo, alguns pacotes de software podem fazer essa suposição sobre o seu sistema, resultando em baixa eficiência no uso da memória. Esta não é uma situação muito comum nas pilhas de software modernas, mas é recomendável executar alguns testes e benchmarking antes de se comprometer com tamanhos de página maiores.

Configurando tamanhos de página maiores nas CPUs Ampere

Alterar o tamanho do tamanho da página de memória requer a execução de um kernel do sistema operacional que foi compilado para suportar o tamanho desejado. Para sistemas operacionais populares em nuvem, como o Red Hat Enterprise Linux, o Oracle Enterprise Linux, o SUSE Enterprise Linux ou o Ubuntu da Canonical, os sistemas operacionais são enviados com kernels pré-construídos que suportam tamanho de página de 4kb e tamanho de página de 64kb no ARM64.

Para usar um kernel com páginas de 64 KB no Red Hat Enterprise Linux 9:

1. Instale o pacote Kernel-64K:

dnf –y install kernel-64k 

2. Para permitir que o núcleo de 64k seja inicializado por padrão na hora da inicialização:

k=$(echo /boot/vmlinuz*64k)
grubby --set-default=$k  
     --update-kernel=$k  
     --args="crashkernel=2G-:640M" 

Para inicializar um kernel de 64kb no Ubuntu 22.04:

1. Instale o largemem ARM64+ISO, que contém o kernel de 64k por padrão, ou:
2. Instale o pacote Linux-Generic-64K, que adicionará uma opção de kernel de 64k ao menu de inicialização com o comando sudo apt install linux-generic-64k
3. Você pode definir o kernel de 64k como a opção de inicialização padrão atualizando o menu de inicialização GRUB2 com o comando:

echo "GRUB_FLAVOUR_ORDER=generic-64k" | sudo tee
/etc/default/grub.d/local-order.cfg

Para páginas de 64 KB no Oracle Linux:

1. Instale o pacote Kernel-UEK64K:

sudo dnf install -y kernel-uek64k

2. Defina o kernel de 64k como o padrão na hora da inicialização:

sudo grubby --set-default=$(echo /boot/vmlinuz*64k)

3. Depois de reiniciar o sistema, você pode verificar se está executando o kernel de 64k usando o getConf, conforme descrito abaixo.

Instruções semelhantes podem estar disponíveis nos sites de outras distribuições do sistema operacional.

Se você estiver construindo seu próprio kernel Linux, poderá usar o Make Menuconfig para alterar a configuração do kernel. No submenu “Tipo e recursos do processador”, você encontrará os registros de recursos do ARM64 CPU com base na opção de configuração de recursos do kernel, que você pode alterar para 16K ou 64K.

Como alternativa, você pode alterar o arquivo de configuração do kernel .config diretamente para definir o valor de config_arm_page_shift do seu valor padrão de 12 (4K = 212 bytes) para 14 (16K = 214 bytes) ou16 (64K = 216 bytes). Você pode escolher qual kernel inicializar no momento da inicialização criando várias entradas no seu carregador de inicialização para os kernels com diferentes tamanhos de página e escolhendo o kernel apropriado no momento da inicialização.

Para verificar qual é a configuração do tamanho da página do kernel para o seu kernel Linux atual, você pode usar o utilitário getConf do sistema. Com um tamanho de página de 64 mil, eles mostrarão o seguinte:

$ getconf PAGESIZE 
65536 

Conclusão

Para resumir: alterar o tamanho da página de memória do kernel em seus sistemas de nuvem pode ter um impacto positivo no desempenho do aplicativo para muitas cargas de trabalho em nuvem comuns. Se o seu aplicativo incluir muito disco, memória ou E/S de rede, você poderá melhorar significativamente seu desempenho usando um kernel com páginas de 16k ou 64 mil habilitadas nos hosts ARM.

No entanto, isso não é uma panacéia, e sua milhagem pode variar. Recomendamos que você teste com testes de referência sintética e do mundo real para verificar se a alteração do tamanho da página resultará em um impacto positivo nos seus resultados.

Muitas distribuições de Linux comuns com compilações ARM64 já incluem vários kernels em seus repositórios de distribuição. Ao instalar esses pacotes de kernel e inicializá-los na start-up, o custo para tentar kernels maiores para testar se eles fornecem uma melhoria de desempenho é relativamente baixo.