Skip to content
Como Melhorar o Desempenho de Kernels CUDA com Spill de Registros na Memória Compartilhada (CUDA 13.0)
Source: developer.nvidia.com

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