Executando verificação de segurança...
2

O que aprendi sobre CUDA/programação fazendo este projeto?

Estive tendo aulas sobre Wavelets durante meu mestrado na UNESP. Nunca tive uma introdução a este tópico até este ano. Já tinha ouvido falar de Fourier Transform, e até brinquei um pouco com a versão quântica do algoritmo, mas nunca tinha entendido de fato.

Contudo, durante uma das aulas, o professor nos ensinou sobre o algoritmo de Mallat para as Wavelets, mais precisamente a DTWT (discrete-time wavelet transform). De forma geral, o algoritmo usa de algebra linear e uns truques matemáticos para realizar uma convolução de um sinal e assim processá-lo.

Fiquei maravilhado com a simplicidade do algoritmo e, por ser basseado em matrizes, fiquei com uma tremenda vontade de implementar ele em cuda.

Acabei postergando o projeto um pouco, mas durante o feriado do dia do trabalhador não me contive e comecei a implementar o algoritmo.

Tomei alguns dias para terminar a implementação, mas fiquei bastante feliz com o resultado.


Como sou relativamente novato em CUDA, gostaria de compartilhar algumas coias que aprendi durante o projeto:

  1. Tome cuidado com o Compute Capability

No geral, cada arquitetura de GPU tem um compute capability associado que define funcionalidades que estão disponíveis.

No meu caso, tenho uma placa bem antiga GTX 1060, que possui cc 6.1. Durate o desenvolvimento, acabei utilizando APIs mais novas, como unified memory que não estavam presentes em versões mais antigas. Assim, meu código funcionava, mas não funcionava 😅

Assim, fique de olho na compatibilidade de features que você usa quando estiver brincando de cuda.

  1. Problemas em Headers

Para a minha placa, estava testando cuda 13.0, no entando, vi que seria melhor fazer o downgrade para 12.8 ou 12.9.

Contudo, ao tentar importar, recebia erros em alguns headers internos. A solução para isso foi editá-los manualmente como dito em https://forums.developer.nvidia.com/t/error-exception-specification-is-incompatible-for-cospi-sinpi-cospif-sinpif-with-glibc-2-41/323591

  1. CUDA-GDB é seu amigo

Como muitos devem saber, calcular indices de elementos nos kernels é algo corriqueiro. Muitas vezes fazer isso de forma arbitrária é complicado e dificil de interpretar.

Por isso, usar cuda-gdb é incrível para ir pulando entre threads/blocks e verificando se faz sentido seu cálculo.

  1. Transposição de matrizes

Uma matriz transposta é basicamente a inversão da posição de elementos trocando o número da linha pelo da coluna.

Em cuda isso é trivial. Como tinha definido um kernel para DTWT, para calcular a sua inversa bastava inverter os indices que estavem sendo usados.

  1. Over-engineering é o maior mal

Quando comecei com o projeto, minha ideia era ter CI+CD+DOCKER+CONAN+CMAKE+MAKE+TUDO, no entanto isso só fazia eu querer parar com o projeto e ir fazer qualquer outra coisa.

Acredito que meu principal acerto com esse projeto foi manter ele na medida que ele deveria estar.

Ao invés de adicionar mais complexidade, fiz um setup pequeno com CMAKE+MAKE e fiz minha própria suite de testes usando C++ puro, sem maiores complexidades.

Acredito que a complexidade depende de quais são suas necessidades, para um experimento como esse nada de muito complexo era requerido.


Espero ter ajudado alguém com meu post 😁

Carregando publicação patrocinada...