nbd-vram - Ferramenta para usar a VRAM de GPUs NVIDIA como espaço de swap no Linux
(github.com/c0dejedi)- nbd-vram é um pequeno daemon que permite usar a VRAM ociosa de uma GPU NVIDIA no Linux como espaço de swap de alta prioridade
- Em notebooks com gráficos híbridos, onde a memória é soldada e difícil de expandir e a GPU integrada AMD/ATI cuida da saída de vídeo, ele aproveita a VRAM NVIDIA que ficaria ociosa para aliviar a pressão de memória
- O ambiente de teste foi AMD/ATI + RTX 3070 Laptop, RAM de 16GB, VRAM de 8GB, driver NVIDIA 580.159.03, kernel 6.17 e Pop!_OS; com 7GB de VRAM alocados como swap, somando também zram e swap em SSD, o sistema chega a cerca de 46GB de memória endereçável
- A ordem de funcionamento é: a RAM enche primeiro, depois a VRAM absorve as páginas excedentes via PCIe, em seguida o zram faz compressão na CPU e, por fim, usa-se o SSD
- O daemon aloca VRAM pela CUDA driver API e fornece um dispositivo de bloco pelo protocolo NBD (Network Block Device) sobre um socket Unix; o driver
nbdembutido no kernel o expõe como/dev/nbdX, permitindo uso como um dispositivo de swap comum - O caminho dos dados é kernel swap subsystem →
/dev/nbdX→ nbd kernel driver → Unix socket → nbd-vram daemon →cuMemcpyHtoD/DtoH→ VRAM da GPU - Não são necessários módulo de kernel separado nem símbolos de kernel da NVIDIA, então a solução pode continuar funcionando após atualizações de kernel e driver sem precisar recompilar
- A abordagem com a API NVIDIA P2P falha em GPUs GeForce de consumo porque
nvidia_p2p_get_pages_persistentretornaEINVAL, e a abordagem deioremap_wcdireto no BAR1 também falha, retornando 0 na leitura de áreas fora de cerca de 16MiB do framebuffer de exibição - O caminho de cópia via CUDA, com
cuMemcpyHtoDecuMemcpyDtoH, funciona em GPUs CUDA sem privilégios especiais, então o acesso por NBD contorna as limitações de P2P e BAR1 - Os requisitos são GPU NVIDIA com suporte a CUDA, driver NVIDIA com
libcuda.so.1, módulo nbd do Linux kernel 3.0+,nbd-client,gccemake; o CUDA toolkit não é necessário - Após a instalação, o serviço systemd
vram-swap-nbdé executado automaticamente na inicialização, e é possível ajustar o limite máximo de VRAM usada e a prioridade do swap comVRAM_SETUP_SIZE_MBeVRAM_SWAP_PRIORITYem/etc/systemd/system/vram-swap-nbd.service - O daemon tenta primeiro o tamanho de VRAM solicitado e, se faltar memória na GPU, reduz a alocação em blocos de 512MiB; assim,
VRAM_SETUP_SIZE_MBfunciona como limite superior, não como tamanho obrigatório - Se o gerenciamento com reconhecimento de energia estiver ativado, o serviço para automaticamente ao desconectar da energia AC ou ao ficar abaixo do limite de bateria, e reinicia quando a energia volta; um
systemctl stopmanual não é sobrescrito - No benchmark com RTX 3070 Laptop, a NVMe é mais rápida em throughput sequencial e I/O aleatório sustentado, mas na latência de leitura 4K com 1 request/sec a VRAM teve média de 335us, 27 vezes mais rápida que os 9.05ms da NVMe
- É distribuído sob a licença MIT, e o repositório inclui
test-nbd.shpara smoke test,test-fill.shpara verificação de partição completa e scripts de benchmark de throughput, IOPS e latência
1 comentários
Comentários no Hacker News
Se fosse tratado via CUDA como armazenamento de arquivos ou algo montável, o overhead seria alto; usando BAR, parece que daria para melhorar bastante a taxa de transferência e os IOPS
Se a explicação é que isso serve para notebooks com memória soldada, sem caminho de upgrade, então responde à dúvida imediata de por que usar swap de uma RAM cara para uma RAM ainda mais cara
O caso de uso parece limitado, mas usar 8GB de VRAM ociosa quando o sistema está fazendo swap para SSD parece uma boa ideia quando necessário
Por exemplo, se você comprou a GPU para jogar, quando não está jogando não precisa de 16GB de VRAM para renderizar o desktop, então talvez faça sentido usar para outra coisa
Mas isso pressupõe que, ao iniciar um jogo, o sistema consiga liberar a VRAM que estava sendo usada como swap; fico curioso se isso é realmente possível
No Amstrad PCW, comum no Reino Unido de meados dos anos 80 até meados dos 90, dava para usar até 512kB de RAM, e uma parte considerável disso podia virar RAM disk
Compilar em Turbo Pascal também ficava muito rápido :-)
A ideia é boa, mas parece haver algo muito errado aqui
Dizem que no RTX 3070 Laptop a taxa sequencial é de cerca de 1.3 GB/s, mas esse chip RTX 3070 é PCIe 4.0 x16, então deveria dar 64GB/s, e os próprios 8GB de GDDR6 têm 448GB/s
Fazer swap para um drive NVMe provavelmente seria duas vezes mais rápido, embora com latência maior
O benchmark também foi feito com ZRAM, e o ZRAM comprime as páginas antes de gravá-las no swap. Não sei exatamente qual é o overhead disso, mas há uma boa chance de ser significativo
Primeiro, o programa em espaço de usuário fica preso ao driver nbd, que é conhecido por ser lento, e ainda usa um bounce buffer em espaço de usuário antes de transferir para a GPU. Quando o kernel precisa fazer swap de uma página, ele primeiro copia para um buffer exposto ao espaço de usuário, depois o programa em espaço de usuário precisa acordar de novo e emitir a operação CUDA para copiar essa página para a memória do dispositivo
O nbd também não lida bem com alta profundidade de fila nem com fusão de acessos adjacentes. Se o kernel emitir muitos swaps de páginas de 4K sem fusão, só para sustentar 4 GB/s já seriam necessárias pelo menos um milhão de trocas de contexto kernel/usuário por segundo. 64 GB/s então nem se fala. E isso olhando só para a parte do NBD, sem contar a complexidade do driver da NVIDIA
O PCIe consegue mover muitos dados, mas para chegar perto da largura de banda total você precisa usar um motor de DMA com listas longas de páginas. Se você configurar uma transferência para cada página de 4K no PCIe, não vai conseguir saturar completamente o barramento
O caminho de swap para NVMe é altamente otimizado. O swaper pode enviar diretamente listas de páginas ao driver NVMe, e o controlador as busca diretamente da RAM via DMA, sem nenhuma cópia do lado da CPU nem troca de contexto
Talvez migrando para o driver ublk dê para evitar o bounce buffer em espaço de usuário, e também seria possível configurar em paralelo cópias CUDA com várias filas de escrita, o que pode melhorar
RAM e VRAM não se degradam por serem usadas
Tenho uma máquina de desenvolvimento com 32GB de RAM e 32GB de VRAM que fica majoritariamente ociosa quando não estou rodando modelos de IA, então essa ideia não parece tão ruim
Fico pensando como isso lida com backpressure. O que acontece se surgir uma demanda de alocação de VRAM enquanto a VRAM está sendo usada como espaço de swap?
No X11, os buffers já são pré-alocados, então não é tão ruim, mas no Wayland as alocações são muito mais dinâmicas, então se a VRAM acabar o desktop inteiro pode morrer facilmente
Já tive alguns travamentos assim ao alternar a máquina entre Hyprland+llama-server+KVM, sem conseguir liberar a VRAM
Criar um dispositivo de swap em nível de usuário sempre foi um daqueles problemas clássicos supostamente insolúveis
Se o daemon precisa fazer swap-in de uma página, mas para fazer isso antes precisa fazer swap-in das próprias páginas do daemon, o que acontece?
Pelo menos havia esse tipo de discussão como motivo de microkernels nunca poderem funcionar de verdade. Não entendo bem qual é a solução aqui
O kernel do Linux também impede que suas próprias páginas de texto sejam swapadas, então a solução já existe, e não vejo por que ela não se aplicaria a projetos de microkernel
Se você travar toda a memória desse daemon, o problema fica resolvido de forma trivial
Lembro de ter feito algo parecido no passado com o driver MTD/phram do Linux: https://wiki.archlinux.org/title/Swap_on_video_RAM
Só não sei se ainda é relevante hoje, porque não sei como isso interage com DRM nem como se faz a reserva de uma parte da VRAM. A sugestão de limitar via xorg.conf provavelmente já está bem ultrapassada
Nessa página também há um sistema de arquivos FUSE implementado sobre OpenCL: https://github.com/Overv/vramfs
Talvez esse tenha melhor compatibilidade
Dá até nostalgia
Também vi algo parecido no Windows alguns anos atrás
Era um driver experimental de prova de conceito que permitia criar um RAM drive com a VRAM de placas NVIDIA, e o acesso sequencial era rápido como esperado, embora o acesso aleatório ainda tivesse bastante espaço para melhorar
GpuRamDrive cria um drive virtual sustentado por RAM da GPU: https://github.com/prsyahmi/GpuRamDrive
Fork com suporte a AMD: https://github.com/brzz/GpuRamDrive/
É parecido, mas usa a API OpenCL, então também funciona em AMD
Só que o driver da AMD é bem bugado, então é preciso definir o que significa “funcionar”: https://libguestfs.org/nbdkit-vram-plugin.1.html
Não entendo por que um Mac Apple Silicon com 32GB de RAM, ainda com 20GB não usados/“free”, usa ou até cria arquivo de swap
Por que não existe algo tão simples quanto
swapoff -ano Linux para desativar completamente o arquivo de swap?A menos que a ideia seja reduzir deliberadamente a vida útil do SSD, isso parece meio bobo
Seria bom haver uma configuração no GUI para desligar o arquivo de swap, e a Apple também poderia finalmente abandonar a atual “etapa” de layout/configurações do sistema. Comparado com décadas de painéis de preferências, ainda parece uma salada de palavras
#Apple #Feedback #swapfile
Até o conceito de “memória disponível” idealmente é mais próximo de “memória que pode ser recuperada rapidamente para outro propósito”
Em certos momentos, pode ser melhor deixar conteúdo de arquivos em cache ocupar esse espaço do que manter memória anônima na memória principal continuamente