Uso CUDA há algumas semanas, mas tenho algumas dúvidas sobre a alocação de blocos / warps / threads. Estou estudando a arquitetura do ponto de vista didático (projeto universitário), portanto, atingir o máximo desempenho não é minha preocupação.
Antes de mais, gostaria de entender se entendi esses fatos:
O programador escreve um kernel e organiza sua execução em uma grade de blocos de threads.
Cada bloco é atribuído a um Streaming Multiprocessor (SM). Uma vez atribuído, ele não pode migrar para outra SM.
Cada SM divide seus próprios blocos em Warps (atualmente com um tamanho máximo de 32 threads). Todos os threads em um warp são executados simultaneamente nos recursos do SM.
A execução real de um encadeamento é realizada pelos núcleos CUDA contidos no SM. Não há mapeamento específico entre threads e núcleos.
Se um warp contiver 20 threads, mas atualmente houver apenas 16 núcleos disponíveis, o warp não será executado.
Por outro lado, se um bloco contiver 48 threads, ele será dividido em 2 warps e eles serão executados em paralelo, desde que haja memória suficiente disponível.
Se um encadeamento iniciar em um núcleo, ele será interrompido para acesso à memória ou para uma operação longa de ponto flutuante, sua execução poderá continuar em um núcleo diferente.
Eles estão corretos?
Agora, eu tenho uma GeForce 560 Ti, de acordo com as especificações, ela é equipada com 8 SM, cada uma contendo 48 núcleos CUDA (384 núcleos no total).
Meu objetivo é garantir que todos os núcleos da arquitetura executem as mesmas instruções. Supondo que meu código não exija mais registro do que os disponíveis em cada SM, imaginei abordagens diferentes:
Crio 8 blocos de 48 threads cada, para que cada SM tenha 1 bloco para executar. Nesse caso, os 48 threads serão executados em paralelo no SM (explorando todos os 48 núcleos disponíveis para eles)?
Existe alguma diferença se eu lançar 64 blocos de 6 threads? (Supondo que eles sejam mapeados igualmente entre as SMs)
Se eu "submergir" a GPU no trabalho agendado (criando 1024 blocos de 1024 threads cada, por exemplo), é razoável supor que todos os núcleos serão usados em um determinado ponto e executem os mesmos cálculos (assumindo que os threads nunca parar)?
Existe alguma maneira de verificar essas situações usando o criador de perfil?
Existe alguma referência para essas coisas? Li o guia de programação da CUDA e os capítulos dedicados à arquitetura de hardware em "Programando processadores massivamente paralelos" e "Design e desenvolvimento de aplicativos CUDA"; mas não consegui uma resposta precisa.