Vantagens e desvantagens de HugePages

Vantagens e desvantagens de HugePages

Tradução do artigo elaborado para alunos do curso "Administrador Linux".

Anteriormente, falei sobre como testar e habilitar Hugepages no Linux.
Este artigo só será útil se você realmente tiver um lugar para usar o Hugepages. Conheci muitas pessoas que se deixam enganar pela perspectiva de que o Hugepages melhorará magicamente a produtividade. No entanto, HugePaging é um tópico complexo e pode prejudicar o desempenho se usado incorretamente.

Parte 1: Verificando se o Hugepages está habilitado no Linux (original aqui)

Problema:
Você precisa verificar se HugePages está habilitado em seu sistema.

solução:
É bem simples:

cat /sys/kernel/mm/transparent_hugepage/enabled

Você obterá algo assim:

always [madvise] never

Você verá uma lista de opções disponíveis (sempre, louco, nunca), e a opção atualmente ativa estará entre parênteses (por padrão louco).

louco significa que transparent hugepages ativado apenas para áreas de memória que solicitam explicitamente páginas enormes usando louco(2).

sempre significa que transparent hugepages sempre habilitado para todos os processos. Isso geralmente melhora o desempenho, mas se você tiver um caso de uso em que muitos processos consomem uma pequena quantidade de memória, a carga geral da memória poderá aumentar drasticamente.

nunca significa que transparent hugepages não será incluído mesmo quando solicitado usando madvise. Para saber mais, entre em contato documentação Núcleos Linux.

Como alterar o valor padrão

opção 1: Alterar diretamente sysfs (após a reinicialização o parâmetro retornará ao seu valor padrão):

echo always >/sys/kernel/mm/transparent_hugepage/enabled
echo madvise >/sys/kernel/mm/transparent_hugepage/enabled
echo never >/sys/kernel/mm/transparent_hugepage/enabled

opção 2: Altere o padrão do sistema recompilando o kernel com uma configuração modificada (esta opção só é recomendada se você estiver usando um kernel personalizado):

  • Para definir sempre como padrão, use:
    CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y
    # Comment out CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
  • Para definir madvise como padrão, use:
    CONFIG_TRANSPARENT_HUGEPAGE_MADVISE=y
    # Comment out CONFIG_TRANSPARENT_HUGEPAGE_ALWAYS=y

Parte 2: Vantagens e Desvantagens do HugePages

Tentaremos explicar seletivamente as vantagens, desvantagens e possíveis armadilhas do uso do Hugepages. Como um artigo tecnologicamente complexo e pedante provavelmente será difícil de entender para as pessoas que estão iludidas ao pensar que o Hugepages é uma panacéia, sacrificarei a precisão pela simplicidade. Só vale a pena ter em mente que muitos dos tópicos são realmente complexos e, portanto, bastante simplificados.

Observe que estamos falando de sistemas x64 de 86 bits rodando Linux, e estou simplesmente assumindo que o sistema suporta páginas enormes transparentes (uma vez que não é uma desvantagem que páginas enormes não sejam sobrescritas), como é o caso em quase todos os sistemas Linux modernos. ambiente.

Anexarei mais descrições técnicas nos links abaixo.

Memória virtual

Se você é um programador C++, sabe que os objetos na memória possuem endereços específicos (valores de ponteiro).

Entretanto, esses endereços não refletem necessariamente endereços físicos na memória (endereços RAM). Eles representam endereços na memória virtual. O processador possui um módulo MMU (unidade de gerenciamento de memória) especial que ajuda o kernel a mapear a memória virtual para um local físico.

Esta abordagem tem muitas vantagens, mas as mais importantes são:

  • Desempenho (por vários motivos);
  • Isolamento de programa, ou seja, nenhum programa pode ler a memória de outro programa.

O que são páginas?

A memória virtual é dividida em páginas. Cada página individual aponta para uma memória física específica, pode apontar para uma área na RAM ou pode apontar para um endereço atribuído a um dispositivo físico, como uma placa de vídeo.

A maioria das páginas com as quais você lida aponta para RAM ou são trocadas, o que significa que são armazenadas em seu disco rígido ou SSD. O kernel gerencia o layout físico de cada página. Se uma página falsificada for acessada, o kernel interrompe o thread que está tentando acessar a memória, lê a página do disco rígido/SSD para a RAM e continua executando o thread.

Este processo é transparente ao fluxo, o que significa que não necessariamente lê diretamente do HDD/SSD. O tamanho das páginas normais é 4096 bytes. O tamanho do Hugepages é de 2 megabytes.

Buffer associativo de tradução (TLB)

Quando um programa acessa uma página de memória, a CPU deve saber de qual página física ler os dados (ou seja, ter um mapa de endereço virtual).

O kernel possui uma estrutura de dados (tabela de páginas) que contém todas as informações sobre as páginas que estão sendo utilizadas. Usando esta estrutura de dados, você pode mapear um endereço virtual para um endereço físico.

No entanto, a tabela de páginas é bastante complexa e lenta, por isso simplesmente não podemos analisar toda a estrutura de dados sempre que um processo acessa a memória.

Felizmente, nosso processador possui um TLB que armazena em cache o mapeamento entre endereços virtuais e físicos. Isso significa que embora precisemos analisar a tabela de páginas na primeira tentativa de acesso, todos os acessos subsequentes à página podem ser tratados no TLB, permitindo uma operação rápida.

Por ser implementado como um dispositivo físico (o que o torna rápido em primeiro lugar), sua capacidade é limitada. Portanto, se você quiser acessar mais páginas, o TLB não conseguirá armazenar mapeamentos para todas elas, fazendo com que seu programa seja executado muito mais lentamente.

Hugepages vem ao resgate

Então, o que podemos fazer para evitar o estouro do TLB? (Assumimos que o programa ainda precisa da mesma quantidade de memória).

É aqui que entra o Hugepages. Em vez de 4096 bytes exigindo apenas uma entrada TLB, uma entrada TLB agora pode apontar para impressionantes 2 megabytes. Vamos supor que o TLB tenha 512 entradas, aqui sem o Hugepages podemos igualar:

4096 b⋅512=2 MB

Então, como podemos comparar com eles:

2 MB⋅512=1 GB

É por isso que Hugepages é incrível. Eles podem melhorar a produtividade sem muito esforço. Mas há advertências significativas aqui.

Falsificação de páginas enormes

O kernel monitora automaticamente a frequência com que cada página de memória é usada. Se não houver memória física (RAM) suficiente, o kernel moverá páginas menos importantes (usadas com menos frequência) para o disco rígido para liberar um pouco de RAM para páginas mais importantes.
Em princípio, o mesmo se aplica ao Hugepages. No entanto, o kernel só pode trocar páginas inteiras, não bytes individuais.

Digamos que temos um programa como este:

char* mymemory = malloc(2*1024*1024); // Возьмем это за одну Hugepage!
// Заполним mymemory какими-либо данными
// Сделаем много других вещей,
// которые приведут к подмене страницы mymemory
// ...
// Запросим доступ только к первому байту
putchar(mymemory[0]); 

Nesse caso, o kernel precisará substituir (ler) até 2 megabytes de informações do disco rígido/SSD apenas para você ler um byte. Quanto às páginas normais, apenas 4096 bytes precisam ser lidos do disco rígido/SSD.

Portanto, se o Hugepage for substituído, a leitura só será mais rápida se você precisar acessar a página inteira. Isso significa que se você estiver tentando acessar aleatoriamente diferentes partes da memória e estiver lendo apenas alguns kilobytes, deverá usar páginas normais e não se preocupar com mais nada.

Por outro lado, se você precisar acessar uma grande parte da memória sequencialmente, o Hugepages melhorará seu desempenho. No entanto, você precisa testar você mesmo (não com software abstrato) e ver o que funciona mais rápido.

Alocação na memória

Se você escreve C, sabe que pode solicitar quantidades arbitrariamente pequenas (ou quase arbitrariamente grandes) de memória do heap usando malloc(). Digamos que você precise de 30 bytes de memória:

char* mymemory = malloc(30);

Para um programador, pode parecer que você está “solicitando” 30 bytes de memória do sistema operacional e retornando um ponteiro para alguma memória virtual. Mas na verdade malloc () é apenas uma função C que chama de dentro da função brk e sbrk para solicitar ou liberar memória do sistema operacional.

Entretanto, solicitar cada vez mais memória para cada alocação é ineficiente; é mais provável que algum segmento de memória já tenha sido liberado (free()), e podemos reutilizá-lo. malloc() implementa algoritmos bastante complexos para reutilizar a memória liberada.

Ao mesmo tempo, tudo acontece despercebido para você, então por que isso deveria te preocupar? Mas porque o desafio free() não significa que a memória é necessariamente devolvida imediatamente ao sistema operacional.

Existe algo como fragmentação de memória. Em casos extremos, existem segmentos de heap onde apenas alguns bytes são usados ​​enquanto tudo o que está entre eles foi liberado (free()).

Observe que a fragmentação da memória é um tópico incrivelmente complexo e até mesmo pequenas alterações em um programa podem ter um impacto significativo. Na maioria dos casos, os programas não causarão fragmentação significativa da memória, mas você deve estar ciente de que, se houver um problema de fragmentação em alguma área do heap, páginas enormes podem piorar a situação.

Uso seletivo de páginas enormes

Depois de ler este artigo, você determinou quais partes do seu programa podem se beneficiar do uso de páginas enormes e quais não. Então, as páginas enormes deveriam ser habilitadas?

Felizmente você pode usar madvise()para ativar o HugePaging apenas para as áreas de memória onde seria útil.

Primeiro, verifique se o Hugepages está rodando no modo madvise() usando instruções no início do artigo.

Então, use madvise()para dizer ao kernel exatamente onde usar o Hugepages.

#include <sys/mman.h>
// Аллоцируйте большое количество памяти, которую будете использовать
size_t size = 256*1024*1024;
char* mymemory = malloc(size);
// Просто включите hugepages…
madvise(mymemory, size, MADV_HUGEPAGE);
// … и задайте следующее
madvise(mymemory, size, MADV_HUGEPAGE | MADV_SEQUENTIAL)

Observe que este método é simplesmente um conselho ao kernel sobre como gerenciar a memória. Isso não significa que o kernel usará automaticamente páginas enormes para uma determinada memória.

Consulte a documentação (página de manual) avisopara saber mais sobre gerenciamento de memória e madvise(), este tópico tem uma curva de aprendizado incrivelmente íngreme. Portanto, se você pretende ficar realmente bom nisso, prepare-se para ler e testar por algumas semanas antes de esperar resultados positivos.

O que ler?

Ter uma questão? Escreva nos comentários!

Fonte: habr.com

Adicionar um comentário