Cada vez mais aplicativos fazem uso do aprendizado de máquina. Assim, é importante ter opções FOSS para acelerar essas atividades. Infelizmente, as opções presentes neste espaço geralmente não são atraentes, fazendo com que os usuários optem por alternativas específicas do fornecedor com kernels downstream e espaço do usuário. Um exemplo disso é o VIPNano-QI NPU IP da VeriSilicon, que é usado para cargas de trabalho de ML, mas não tem suporte upstream.
Esta postagem fornecerá uma breve visão geral do estado das opções do FOSS ML e anunciará alguns trabalhos que estamos fazendo para oferecer suporte ao OpenCL no driver Etnaviv.
Opções FOSS para atividades de ML
Até recentemente, não havia boas opções para executar cargas de trabalho de aprendizado de máquina em aceleradores com FOSS. A opção mais realista era usar o delegado de GPU do TensorFlow Lite com o back-end OpenGL em um driver Mesa com bom suporte para sombreadores de computação, conforme especificado no OpenGL ES 3.1.
O principal problema com essa abordagem era a dependência do OpenGL ES 3.1, que nem sempre está presente nos aceleradores de ML. Mesmo quando for, o teto de desempenho para GL ES 3.1 será menor do que o possível com OpenCL, dadas suas restrições.
Há também a opção de usar o ONNX Runtime com oneDNN em cima de um driver Mesa com bom suporte a OpenCL ou usar o back-end OpenCL do delegado TFLite GPU com um driver Mesa compatível com CL. Mas o suporte OpenCL que tínhamos no Mesa até setembro de 2022 não era abrangente, para dizer o mínimo; principalmente trabalhando apenas em r600.
OpenCL no Mesa
O Mesa tem suporte OpenCL através do Clover desde 2012, mas ele só suportava hardware AMD e não estava sendo desenvolvido muito ativamente. Uma das principais limitações que tinha era a dependência de um tipo específico de LLVM IR. Em agosto de 2019, Karol Herbst adicionou suporte para NIR, permitindo que outros drivers que não consomem LLVM IR possam usar o Clover.
Algum tempo depois, Karol começou a trabalhar em outro caminho para oferecer suporte ao OpenCL no Mesa, cunhado Rusticl, que acabou sendo fundido em 12 de setembro de 2022. Como o Clover, o Rusticl também implementa o OpenCL como um front-end de gálio, mas as semelhanças param por aí. Rusticl é escrito em Rust, é baseado em SPIR-V e NIR, tem como objetivo se comportar de maneira muito próxima ao st/mesa
, suporta imagens, é compatível com OpenCL 3.0 no Intel 12th-Gen e também passa nos testes 3.0 no radeonsi.
A adição do Rusticl foi um passo para obter mais drivers de gálio para oferecer suporte ao OpenCL, o que é útil para nosso objetivo de adicionar suporte ao OpenCL ao Etnaviv.
Objetivos
Um dos IPs presentes em vários SoCs no mercado é o VIPNano-QI NPU IP da VeriSilicon, que é usado para acelerar redes neurais e está presente, por exemplo, no VIM3. Graças à comunidade Etnaviv, em particular a Christian Gmeiner e Lucas Stach, temos algumas informações sobre este IP, e ele está intimamente relacionado a outros IPs de GPU Vivante, como o GC7000.
Com isso em mente, escolhemos como objetivo para este projeto executar um modelo TFLite com Etnaviv no VIM3 NPU usando OpenCL. Nosso objetivo é especificamente os recursos comumente usados por atividades de aprendizado de máquina, não visando a conformidade total com OpenCL ainda.
OpenCL em Etnaviv
Como ponto de partida para este projeto, o driver etnaviv não suportava GL ES 3.0 e, mais especificamente, não suportava as extensões de computação, que são relevantes para fazer o OpenCL funcionar, seja através do Clover ou Rusticl. Além disso, não havia suporte para o NPU específico presente no VIM3, que é o VIPNano-QI.
No lado do kernel, estávamos usando um kernel linux Khadas VIM3 downstream com alguns patches para ajudar a desenvolver o driver do espaço do usuário. Tomeu adicionou o nó DT e a entrada do banco de dados de hardware etnaviv para o VIPNano, permitindo alternar entre o uso do driver galcore e o etnaviv, que é útil para depuração.
Tomeu também implementou as APIs de computação de gálio e os intrínsecos NIR ausentes, a ponto de podermos realmente emitir tarefas do kernel e, com alguma sorte, ler os resultados do VIM3 NPU.
Usando informações e ferramentas dos repositórios etnaviv RE, poderíamos continuar a partir daqui comparando cmdstream e shader assembly com o driver galcore.
Nesse ponto, ainda estávamos usando o Clover porque o Rusticl não havia sido mesclado. Depois de mesclado, passamos a usá-lo, o que foi bastante direto, exceto por algumas alterações aqui e ali para oferecer suporte a dispositivos com espaços de endereço de 32 bits.
Também tivemos que fazer alterações no compilador porque, quando comparado ao GL ES 2.0, o OpenCL é mais rigoroso sobre o que o compilador precisa suportar. Essas diferenças incluem exigir suporte para mais tamanhos de bits e tamanhos de vetor, regras de alinhamento mais rígidas e fluxo de controle menos rígido. Além disso, também acabamos adicionando suporte para algumas operações ausentes, além de corrigir alguns bugs que apareceram pelo caminho.
Por fim, Tomeu começou a adicionar integração contínua com piglit CL, para que possamos evitar a regressão do Etnaviv OpenCL no futuro.
Mais detalhes no blob da Collabora.