Como Melhorar o Desempenho de Kernels CUDA com Spill de Registros na Memória Compartilhada (CUDA 13.0)
Sources: https://developer.nvidia.com/blog/how-to-improve-cuda-kernel-performance-with-shared-memory-register-spilling, https://developer.nvidia.com/blog/how-to-improve-cuda-kernel-performance-with-shared-memory-register-spilling/, NVIDIA Dev Blog
Visão geral
Quando um kernel CUDA requer mais registradores de hardware do que os disponíveis, o compilador pode derramar o excesso de variáveis para memória local, localizada na memória global do dispositivo. Esse spilling de registradores pode prejudicar o desempenho, devido à maior latência e largura de banda das leituras/gravações na memória local. O CUDA 13.0 apresenta uma nova otimização: spill de registradores na memória compartilhada para kernels CUDA. O compilador prioriza derramar os registradores para a memória compartilhada disponível primeiro e, caso o espaço seja insuficiente, derrama para memória local. Essa memória on‑chip de baixa latência mantém os dados derramados mais próximos da SM, reduzindo a pressão na cache L2 e melhorando o desempenho em caminhos com alta pressão de registradores. No CUDA 13.0, o PTXAS adiciona suporte para derramamento de registradores para memória compartilhada em kernels CUDA. Se a funcionalidade estiver habilitada, o compilador tenta derramar para a memória compartilhada primeiro e recorre à memória local apenas quando necessário, preservando a correção do programa. Essa otimização complementa as grandes caches L1/L2, buscando reduzir a latência da memória on‑chip para dados derramados. Anteriormente, os derrames eram sempre direcionados para a memória local. O novo caminho pode levar a ganhos significativos em kernels com alta pressão de registradores, como laços apertados ou seções de código executadas com frequência. O recurso foi avaliado em vários kernels CUDA da biblioteca QUDA, usada para cálculos de lattice QCD em GPUs, e mostrou ganhos típicos na faixa de 5–10%, atribuídos à redução ou eliminação de spills para memória local. A otimização não está disponível em toolkits anteriores ao CUDA 13.0. Ela requer que os desenvolvedores usem CUDA 13.0 ou posterior e façam a opt‑in via inline assembly.
O que muda no compilador
No CUDA 13.0, o PTXAS introduz um mecanismo de opt‑in que redireciona spills para a memória compartilhada quando há espaço para eles. Quando habilitado, o compilador utiliza primeiro a memória compartilhada para spills e só usa memória local se a memória compartilhada se esgota. Um kernel compilado com esse recurso mostra, em saídas de debug/benchmark, o uso de memória compartilhada por bloco (por exemplo, 46080 bytes de smem). A ideia é manter os dados derramados próximos à SM, reduzindo a pressão de eviction na L2 em regiões de desempenho crítico. Essa otimização é ativada inserindo uma diretiva PTX (pragma) enable_smem_spilling via assembly inline dentro da função, logo após a declaração da função. O recurso é válido apenas dentro do escopo de uma função. Não é recomendado usá‑lo quando os limites de lançamento (launch bounds) não forem especificados explicitamente, pois a estimulação de blocos por SM pode se tornar imprecisa, possivelmente limitando a concorrência e reduzindo o desempenho. Quando os limites de lançamento são bem definidos e o uso de memória compartilhada é estável, ativar o spill para memória compartilhada pode melhorar o desempenho.
Principais recursos
- Suporte do PTXAS para derramamento de registradores para memória compartilhada (CUDA 13.0+).
- Spill priorizado para memória compartilhada on‑chip; fallback para memória local se não houver espaço.
- Potenciais ganhos de desempenho devido à redução da latência e menor pressão na L2 em regiões críticas.
- Ativação via inline assembly PTX: enable_smem_spilling, colocado após a declaração da função.
- Válido apenas dentro do escopo de uma função; recomenda-se para kernels com limites de lançamento bem definidos.
- Demonstração de ganhos típicos na faixa de 5–10% em cargas como QUDA lattice QCD.
- Disponível apenas no CUDA 13.0 e posteriores; toolkits anteriores não suportam spilled registers na memória compartilhada.
- Se a memória compartilhada por bloco for consistentemente subutilizada, a otimização pode ainda assim ser benéfica quando a pressão de registradores é alta.
Casos de uso comuns
- Kernels com alta pressão de registradores e laços apertados, onde spills para memória local eram gargalos.
- Cargas em que boa parte da memória compartilhada por bloco permanece ociosa, tornando viável alocar dados derramados na memória on‑chip.
- Cenários em que o occupancy é limitado pelo uso de registradores em vez da memória compartilhada.
- Aplicações com limites de lançamento bem definidos e uso previsível de memória compartilhada que tolerem o acréscimo de footprint de memória por bloco.
Setup & instalação (comandos exatos)
- Garanta que você está usando o CUDA 13.0 ou posterior.
- Faça a opt‑in para spill de memória compartilhada inserindo uma pragma PTX inline após a declaração da função: enable_smem_spilling. Esse acionamento é descrito como válido dentro do escopo de uma função e deve ser usado quando os limites de lançamento estiverem explicitamente definidos. Observação: a fonte descreve o método de opt‑in e avisa sobre as restrições, mas não fornece comandos de instalação externos além da exigência da versão do toolkit CUDA.
// Ativar spill de memória compartilhada (CUDA 13.0+)
// Colocar após a declaração da função
// Inline PTX pragma: enable_smem_spilling
Quick start (exemplo mínimo executável)
Abaixo existem dois esboços de kernel mínimos para ilustrar conceitualmente a ideia. O primeiro mostra um kernel simples sem a opt‑in de spilling. O segundo indica onde e como a opt‑in de spilling seria aplicada no código, seguindo a orientação de CUDA 13.0.
// Kernel mínimo (base, sem a opt‑in de spilling)
extern "C" __global__ void demo_kernel(float* in, float* out) {
int idx = threadIdx.x + blockIdx.x * blockDim.x;
float v = in[idx];
out[idx] = v * 2.0f;
}
// Kernel mínimo (conceitual: enable_smem_spilling após a declaração da função)
extern "C" __global__ void demo_kernel(float* in, float* out) {
// Ativar spill de memória compartilhada (CUDA 13.0+)
// Inline PTX pragma: enable_smem_spilling
int idx = threadIdx.x + blockIdx.x * blockDim.x;
float v = in[idx];
out[idx] = v * 2.0f;
}
Observação: a sintaxe exata para habilitar via inline PTX é descrita na fonte como uma pragma PTX colocada após a declaração da função. Os exemplos acima ilustram passagem e intenção, não necessariamente uma diretiva de compilador literal.
Prós e contras
- Prós
- Ganhos de desempenho potenciais (tipicamente 5–10%) em kernels com alta pressão de registradores, ao reduzir spills para memória local.
- Mantém spilled data na memória compartilhada on‑chip, reduzindo latência e pressão na L2 quando há espaço disponível.
- Fornece um caminho de otimização direcionado para kernels com limites de lançamento bem definidos e uso estável de memória compartilhada.
- Contras
- Requer ativação explícita; não é automático para todos os kernels.
- Não é aplicável se a memória compartilhada por bloco já estiver saturada ou se a pressão de registradores não for o gargalo.
- Pode haver imprecisão na ocupação se os limites de lançamento não forem especificados, potencialmente reduzindo a ocupação.
- Disponível apenas no CUDA 13.0 e posterior; toolkits mais antigos não suportam spills na memória compartilhada.
Alternatives (comparações rápidas)
| Abordagem | Prós | Contras |---|---|---| | Spill de registradores na memória compartilhada (CUDA 13.0+) | Reduz spills para memória local; usa memória on‑chip | Requer ativação explícita; depende da disponibilidade de memória compartilhada |Spill para memória local (comportamento pré‑CUDA 13.0) | Sem necessidade de alterações de código | Latência maior; maior pressão na L2 |Otimização de código para reduzir pressão de registradores | Reduz spills de forma geral | Pode exigir refatoração significativa; nem sempre é viável |
Pricing or License
Informação de preço ou licenciamento não é fornecida na fonte apresentada. A funcionalidade é descrita como parte do conjunto de ferramentas CUDA 13.0.
References
More resources
CUDA Toolkit 13.0 para Jetson Thor: Ecossistema Unificado de Arm e Mais
Kit de ferramentas CUDA unificado para Arm no Jetson Thor com coerência total de memória, compartilhamento de GPU entre processos, interoperabilidade OpenRM/dmabuf, suporte NUMA e melhorias de ferramentas para embarcados e servidores.
Reduzir Custos de Implantação de Modelos Mantendo Desempenho com Swap de Memória de GPU
Utilize o swap de memória da GPU (hot-swapping de modelos) para compartilhar GPUs entre múltiplos LLMs, reduzir custos de ociosidade e melhorar o autoscaling mantendo os SLAs.
Aprimorando a auto-tunagem de GEMM com nvMatmulHeuristics no CUTLASS 4.2
Apresenta nvMatmulHeuristics para escolher rapidamente um conjunto pequeno de configurações de kernels GEMM com alto potencial para o CUTLASS 4.2, reduzindo drasticamente o tempo de tuning enquanto se aproxima do desempenho da busca exaustiva.
Fine-Tuning gpt-oss para Precisão e Desempenho com Treinamento de Quantização (QAT)
Guia de fine-tuning do gpt-oss com SFT + QAT para recuperar a precisão em FP4 mantendo a eficiência, incluindo upcasting para BF16, MXFP4, NVFP4 e implantação com TensorRT-LLM.
Como Modelos de Linguagem Pequenos são a Chave para IA Agentica Escalável
Explora como modelos de linguagem pequenos permitem IA agentica mais barata, flexível e escalável, ao lado de LLMs, com NVIDIA NeMo e Nemotron Nano 2.
Guia de Início com NVIDIA Isaac para Saúde: Fluxo de Telesurgery
Fluxo de telesurgery modular e pronto para produção do NVIDIA Isaac for Healthcare, unificando simulação e implantação clínica em uma arquitetura de baixo atraso com três máquinas. Abrange streaming de vídeo/sensores, controle de robô, haptics e simulação.