O argumento, em uma frase. CUDA é uma boa linguagem acoplada a um fornecedor. OpenCL é uma linguagem pior acoplada a nenhum. Como a maior parte do meu trabalho é matemática — aritmética sobre buffers —, o acoplamento me custa mais do que a ergonomia me rende. Por isso eu escrevo OpenCL.

Nada roda até você pedir. Nenhum contexto WebGL2 é criado ao abrir a página: o canvas nasce no clique e o código é buscado de /shaders-gpu. Um único contexto compartilhado serve a página inteira, então um shader anima por vez. Rodar outro devolve o atual ao estado inicial.

O que eu afirmo, e com que força

A distinção abaixo é a mesma que uso no resto do site. Nenhuma linha aqui diz "OpenCL é mais rápido" — porque eu não medi isso, e é a parte que está em aberto.

AfirmaçãoForçaPor quê
Toda GPU NVIDIA expõe um dispositivo OpenCLEXACTGarantido pelo driver; checklist de compatibilidade da Khronos
Existem GPUs e aceleradores com OpenCL e sem CUDAEXACTAMD, Intel, Apple, FPGA, CPU — nenhum roda CUDA
O mesmo kernel em GLSL/OpenCL C/CUDA é o mesmo textoEXACTVerdadeiro para aritmética; falso assim que entra biblioteca
O SIMT de CUDA é mais expressivo que OpenCL 1.2EXACTShuffle/ballot nativos; OpenCL só teve subgroups no 2.0
OpenCL é competitivo em desempenho com CUDAOPENDepende do kernel e do driver; eu não medi
Meu M22 mediu GPU além de NVIDIAFALSOtorch.cuda.is_available() é a única detecção

EXACT verificável na documentação · OPEN em aberto — não medi · FALSO afirmação que eu não posso fazer

A dívida, declarada. No módulo M22 do meu benchmark.py a detecção de hardware é literalmente gpu_available = torch.cuda.is_available(), e os backends medidos são ["cpu"], "cuda" e "mps". Não existe uma linha de OpenCL no meu código. Quando eu escrevo "GPU" numa tabela do meu relatório, leia "GPU NVIDIA". O argumento desta página é sobre API e ecossistema — não é, e não pode ser, uma reivindicação de desempenho meu.

A Cadeia CUDA: fonte → PTX → SASS

três camadas, e só a primeira é sua
M22 · benchmark.py (branch pure_physics_PsiQRH) + CUDA Toolkit docs EXACT cadeia-ptx.glsl

Do lado de fora, o que você escreve. No meio, o PTX — ISA virtual, só NVIDIA. No centro, o SASS: ISA real, não documentada, específica de cada arquitetura.

Como ler a imagem

Três anéis. O externo é o que você escreve: CUDA C++, regular e legível. O médio é o PTX, a ISA virtual da NVIDIA — ainda regular, mas já só dela. O núcleo é o SASS: a ISA real, não documentada, que muda a cada arquitetura. A cada volta do relógio o núcleo se remexe: é a arquitetura mudando por baixo do seu código.

O que ainda não está provado

O que a imagem não mostra é o que acontece na fonte: PTX é compatível para frente entre arquiteturas NVIDIA, então seu binário PTX sobrevive a uma troca de placa — mas não sobrevive a uma troca de fornecedor. A cadeia é fechada na primeira camada, não na última. Não estou dizendo que isso é ilegal ou errado: é uma escolha de engenharia da NVIDIA, e ela é o motivo pelo qual o ecossistema funciona.

O que já é exato

A imagem custa três máscaras de raio e um hash. O argumento custa uma linha de especificação: SASS não é público.

cadeia-ptx.glsl Um contexto WebGL2 é criado só ao clicar. O código é buscado de shaders-gpu/cadeia-ptx.glsl.
.glsl

Alcance: CUDA × OpenCL

o mesmo kernel, contado em dispositivos
Khronos OpenCL registry · NVIDIA CUDA compatibility docs EXACT alcance-runtime.glsl

Cada célula é um dispositivo. Aceso = o kernel roda nela. O slider atravessa de CUDA (só NVIDIA) para OpenCL (GPU, CPU, FPGA, acelerador).

Como ler a imagem

Uma malha de dispositivos. Cada célula é uma peça de hardware que existe hoje num datacenter ou numa mesa. O brilho é se o seu kernel consegue rodar nela: verde é NVIDIA, vermelho AMD, azul Intel, branco Apple, amarelo FPGA, violeta CPU, ciano acelerador. Leve o slider da esquerda para a direita e a malha inteira acende. Não é analogia — é a contagem de dispositivos endereçáveis.

O que ainda não está provado

Preciso ser direto sobre o que este desenho NÃO prova. OpenCL endereçar mais hardware é uma afirmação sobre a API, não sobre o desempenho. Em GPU NVIDIA, CUDA normalmente ganha — mais bibliotecas afinadas, mais controle de memória, mais gente otimizando. A minha tese não é "OpenCL é mais rápido". É "OpenCL não te tranca", e essas duas coisas são diferentes.

O que já é exato

A imagem custa um hash por célula. A afirmação custa uma linha: toda GPU NVIDIA fala OpenCL; nem toda GPU que fala OpenCL fala CUDA.

alcance-runtime.glsl Um contexto WebGL2 é criado só ao clicar. O código é buscado de shaders-gpu/alcance-runtime.glsl.
.glsl

Warp em lockstep — e o custo da divergência

32 lanes, uma instrução por vez, sem máscara
NVIDIA CUDA C Programming Guide §5.4 (SIMT) · OpenCL 2.0 subgroups EXACT warp-lockstep.glsl

32 colunas = 32 lanes de um warp. A divergência acende em vermelho e o passo do warp é refeito serialmente para cada caminho.

Como ler a imagem

Trinta e duas colunas: um warp. Cada linha dentro da coluna é uma instrução, e todas as 32 colunas andam juntas. Isso é SIMT. Aumente a divergência: algumas colunas saem do passo e o warp inteiro espera por elas. O vermelho é o custo — lanes ociosas.

O que ainda não está provado

Este é o argumento a favor de CUDA, e eu não vou escondê-lo. O modelo SIMT com garantia explícita de lockstep por warp permitiu à NVIDIA construir primitivas que OpenCL não tinha: shuffle, ballot, reduções cooperativas. OpenCL 2.0 trouxe subgroup operations justamente para cobrir essa lacuna — e a cobertura ainda é irregular entre drivers. Aqui CUDA ganha. O que estou argumentando não é que CUDA é pior; é que o ganho dele é técnico, e o preço dele é vendor lock-in.

O que já é exato

Uma máscara de coluna e um passo de divergência. A conta real é a de lanes ociosas: um warp de 32 com k caminhos divergentes executa em até k passos.

warp-lockstep.glsl Um contexto WebGL2 é criado só ao clicar. O código é buscado de shaders-gpu/warp-lockstep.glsl.
.glsl

O mesmo kernel em GLSL, OpenCL e CUDA

rotação de fase — uma expressão, três linguagens
minhas publicações ΨQRH · linguagens: GLSL ES 3.00, OpenCL C 1.2, CUDA C++ EXACT portabilidade-kernel.glsl

O campo abaixo é gerado por uma única expressão de rotação de fase. Ela compila sem alteração nas três linguagens; o shader é literalmente essa linha.

Como ler a imagem

Um campo vetorial. Cada seta é o resultado da mesma função, aplicada a uma coordenada diferente. Esse texto — a função inteira — é válido em GLSL, em OpenCL C e em CUDA, mudando só o nome do tipo. O desenho roda nas três linguagens porque não há nada nele além dessa expressão. Onde CUDA exigiria reescrita, aqui não há o que reescrever: a seta não sabe em que linguagem foi compilada.

O que ainda não está provado

Preciso separar duas coisas que costumam ser vendidas juntas. "Portável" aqui significa portável para o kernel que eu escrevo. Não significa que meu projeto inteiro compile nos três: o host diverge, o gerenciamento de memória diverge, e qualquer chamada a cuBLAS ou cuDNN me prende de volta. A portabilidade que eu reivindico é a do núcleo matemático — que, na minha pesquisa, é quase tudo o que importa.

O que já é exato

Isto é uma expressão, não uma biblioteca. Se o seu código depende de cuBLAS, cuDNN, NCCL ou Thrust, a portabilidade acaba antes de começar.

portabilidade-kernel.glsl Um contexto WebGL2 é criado só ao clicar. O código é buscado de shaders-gpu/portabilidade-kernel.glsl.
.glsl

O que o meu M22 mediu — e o que ficou de fora

cobertura real do módulo de hardware do meu benchmark
benchmark.py · M22 "hardware-performance profiling" (branch pure_physics_PsiQRH) EMPIRICAL_NS divida-m22.glsl

Quatro classes de hardware. Verde = medida de fato pelo meu M22. Cinza = existe no mundo e não entrou na minha amostra.

Como ler a imagem

Quatro barras. Verde é o que eu realmente medi. A barra cinza-clara é o tamanho inteiro da amostra; a verde é a fração que meu código conseguiu tocar. Olhe a diferença. Ela não é pequena.

O que ainda não está provado

Esta é a parte que eu preciso dizer contra mim mesmo. No módulo M22 do meu benchmark a detecção de GPU é literalmente `torch.cuda.is_available()`. "GPU", no meu relatório, quer dizer "GPU NVIDIA". Rodo em CPU e em MPS. Não existe uma linha de OpenCL no meu código, e a coluna "GPU" das minhas tabelas nunca incluiu AMD, Intel, nem FPGA. Então eu não posso citar o meu próprio benchmark como evidência de que OpenCL é viável — eu não medi. O argumento desta página é sobre a API e o ecossistema, e ele está em aberto na parte que mais importa: desempenho.

O que já é exato

Consertar isso não é caro: um backend OpenCL no M22, rodando o mesmo BenchmarkNetwork, com o mesmo protocolo de warmup e n_runs. É a próxima coisa que eu devo fazer, e não está feita.

divida-m22.glsl Um contexto WebGL2 é criado só ao clicar. O código é buscado de shaders-gpu/divida-m22.glsl.
.glsl

A camada de tradução: CUDA × OpenCL

a mesma luz, sete dispositivos, duas respostas
Khronos OpenCL 3.0 spec · CUDA Toolkit (NVIDIA only) EXACT camada-de-traducao.glsl

A coluna verde é NVIDIA. As outras seis são AMD, Intel, Apple, FPGA e CPU. O slider alterna a camada do meio e mostra quem recebe luz.

Como ler a imagem

Sete colunas, sete dispositivos. A luz desce e atravessa a camada de tradução. Sobre CUDA, ela bate numa parede: só a coluna NVIDIA recebe luz. Sobre OpenCL, ela passa em todas. Nada no desenho mudou entre os dois lados — só a camada do meio.

O que ainda não está provado

O que OpenCL não te dá de graça: você escreve a inicialização do dispositivo, escolhe plataforma, compila o kernel em runtime, e paga com um pequeno overhead de dispatch. E cada driver é um driver — diferenças de comportamento entre fabricantes existem e doem. Não estou vendendo OpenCL como gratuito. Estou dizendo que o custo dele é trabalho, e o custo do CUDA é dependência. São custos de naturezas diferentes, e eu prefiro o que eu posso pagar com o meu próprio esforço.

O que já é exato

Inicialização de plataforma, contexto e fila de comando: ~150 linhas de host code que o CUDA resolve com três chamadas. É o preço, e ele é real.

camada-de-traducao.glsl Um contexto WebGL2 é criado só ao clicar. O código é buscado de shaders-gpu/camada-de-traducao.glsl.
.glsl

O que eu não estou dizendo

Não estou dizendo que CUDA é ruim. O modelo SIMT dele é melhor documentado, as bibliotecas (cuBLAS, cuDNN, NCCL, CUTLASS) não têm equivalente maduro em OpenCL, e a experiência de depuração é superior — compute-sanitizer e nsight não têm par. Se o seu problema é treinar um transformer em NVIDIA hoje, CUDA é a resposta correta e OpenCL vai te custar semanas.

O que eu estou dizendo é mais estreito: o meu kernel não precisa disso. O que eu escrevo é aritmética sobre buffers — filtro de fase, rotação de quaternion, projeção de manifold. Nada nessa lista pede shuffle, nem tensor core, nem biblioteca afinada. Quando o problema não pede, a dependência só cobra.

Onde eu ainda estou errado

Eu não tenho números. Não rodei o M22 em OpenCL, não comparei o mesmo BenchmarkNetwork entre clCreateProgramWithSource e nvcc, e portanto não posso afirmar nada sobre overhead de dispatch, qualidade dos drivers das três fabricantes, ou diferença de throughput num kernel real. Isso é uma lacuna no meu trabalho, não uma vitória retórica. A correção é mecânica e está na lista: um backend OpenCL no M22, mesmo protocolo, mesmas seeds, mesmo n_runs.

Reproduzir localmente

Cada arquivo está em /shaders-gpu/ com extensão .glsl e compila em qualquer ambiente WebGL2 — incluindo twigl.app e glsl.app, no modo 300 es. Nesses ambientes troque uRes por resolution, uTime por time e uParam1 por uma constante.