Uma instrução, vários números de uma vez.
SIMD é a sigla em inglês para "uma instrução, vários dados". Em vez de somar um número de cada vez, o processador pega um bloco de 4, 8 ou 16 números e faz a mesma conta em todos com um único comando. Cada posição do bloco é uma faixa.
Pense num caixa de supermercado. O caixa comum passa um produto por vez numa esteira só. O caixa SIMD tem quatro esteiras lado a lado e um único gesto passa quatro produtos. No fim, ele junta os quatro subtotais num total. É por isso que acelera: menos gestos para o mesmo número de produtos.
E é por isso que o resultado muda. Número com vírgula, no computador, tem precisão limitada: depois de uns sete dígitos significativos (na precisão de 32 bits), o resto é arredondado. Cada soma arredonda um pouquinho. Somar em outra ordem, em quatro subtotais em vez de uma fila, arredonda em outros lugares, e o último dígito sai diferente.
Um programa, vários tamanhos de bloco.
Até a versão 1.26, o Go só oferecia SIMD para os chips Intel e AMD. A versão 1.27 acrescentou os chips ARM (os do Mac e dos celulares), o WebAssembly (que roda no navegador) e, o mais importante, um pacote portátil: você escreve uma vez, e o compilador gera uma versão para cada tamanho de bloco, escolhida quando o programa começa a rodar.
Cada família de chip tem o seu jeito de fazer SIMD. NEON é o dos chips ARM e trata 4 números de 32 bits por vez. AVX2 é o da maioria dos servidores Intel e AMD, com 8. AVX-512 é o dos servidores mais caros, com 16.
Isso é conveniente: o mesmo programa roda com 4 faixas no Mac, 8 num servidor comum e 16 num servidor de ponta. E é exatamente aí que mora o problema: quantos números cada faixa soma, e em que ordem, depende da máquina.
Ainda faltam peças: não há um comando pronto para juntar as faixas numa soma só (vem na versão 1.28), nem para espalhar resultados por posições arbitrárias da memória. O pacote é experimental e pode mudar.
Onde acelera, onde piora.
Testamos três trechos de programa que se repetem milhões de vezes em dois sistemas nossos. O primeiro é a conferência do nosso codec de telemetria, o TUBE: ele confere se nenhum valor reconstruído se afastou do original mais do que o combinado. O segundo é um histograma das variações do mesmo sinal, que conta quantas variações caem em cada faixa de tamanho. O terceiro é a distância entre vetores do nosso índice de busca, o SIEVE. Usamos dado real: 182.976 medições de vibração de um rolamento (CWRU, 12 kHz).
O SIMD deixou 2,2× mais rápida a conferência e 2,7× a distância. No histograma, nada: o trabalho pesado ali é jogar cada valor na sua caixa, uma posição de memória diferente por vez, e o pacote não sabe fazer isso em bloco.
A surpresa veio do modo de imitação. Quando o chip não tem SIMD, ou quando alguém desliga com uma variável de ambiente, o Go imita as instruções em software. A documentação promete que isso funciona direito. Medimos 10× mais lento que a versão comum na conferência e 4× no histograma. Uma configuração esquecida no servidor vira uma lentidão grande e silenciosa.
Medido num Mac com chip ARM, mediana de 6 repetições, sem isolar o processador de outras tarefas: há ruído. A diferença do histograma cabe nesse ruído. Ainda não medimos em servidores Intel/AMD com AVX2 ou AVX-512.
| Trecho | Versão comum | Com SIMD | Modo de imitação | Resultado |
|---|---|---|---|---|
| Conferência do codec | 3,87 ns/medição | 1,74 (2,2×) | 37 (≈10× pior) | idêntico: achar o maior valor não depende da ordem |
| Histograma das variações | 6,6 ns/medição | 7,2 (≈1×) | 26 (≈4× pior) | idêntico: cada conta é feita num número só, sem somar com outros |
| Distância entre vetores | 335 µs | 126 (2,7×) | não medido | diferente: soma em 32 bits, desvio de ~1,5 parte em 10 milhões |
O mesmo programa, três impressões digitais.
Nosso codec de telemetria (o TUBE, parte da família de telemetria certificada) promete uma coisa acima de todas: o mesmo arquivo, byte a byte, em qualquer máquina. É isso que permite selar o arquivo com uma impressão digital (um resumo matemático que muda se um único bit mudar) e conferi-la depois em outro lugar.
Passamos para SIMD as somas que o codec faz em cada bloco de medições e comparamos com a versão comum: o resultado mudou em 98,7% dos blocos. Os números que de fato vão para o arquivo saíram iguais nos 304 blocos, porque o arredondamento final absorveu a diferença. Mas isso foi sorte com este sinal, não garantia: uma soma bem na fronteira de arredondamento vira outro número e muda o arquivo.
A opção de multiplicar e somar num passo só piora o quadro. O mesmo programa, com o mesmo dado, deu uma impressão digital no chip ARM, que faz esse passo único, e outra num chip Intel imitado pelo Rosetta 2 (o tradutor do Mac para programas Intel), que não tem esse recurso e faz multiplicação e soma separadas. Um programa que se adapta ao tamanho do bloco também adapta o resultado em qualquer soma de números com vírgula.
O que decidimos.
SIMD só em conta que não depende da ordem
Achar o maior ou o menor valor, comparar, subtrair, dividir cada número por outro: o resultado é o mesmo em qualquer ordem. Somas de números com vírgula que viram arquivo ou impressão digital ficam fora. É a mesma regra que já proibia o "multiplicar e somar num passo só" no codec, estendida para a ordem das somas.
O modo de imitação não é plano B
Manter a versão comum, um número por vez, escrita e escolhida de propósito. Confiar na imitação é aceitar uma lentidão de 10× que ninguém vê até a conta chegar.
Onde a soma é inevitável, conferir perto da fronteira
A distância do índice precisa de soma. Então o SIMD decide sozinho só quando a resposta está longe da fronteira; perto dela, recalcula com precisão total (seção abaixo).
Medir na máquina de verdade
O tamanho do bloco muda com o chip, e o resultado também. Teste de velocidade e de bits tem de rodar no servidor de produção, não só no notebook.
Decide rápido longe da borda, confere perto dela.
Nosso índice de busca (o SIEVE) promete não deixar nenhum vizinho de fora: se um item está dentro do raio da busca, ele aparece. Com SIMD, a distância sai em precisão de 32 bits, com um pequeno erro. Calculamos o tamanho máximo desse erro, cerca de 8 milionésimos da própria distância para vetores de 128 dimensões, e o testamos contra a conta exata em 3.000 pares, com quatro tipos de dado, três tamanhos de vetor e três tamanhos de bloco, com e sem o passo único: o erro nunca passou do limite.
Depois plantamos 20 mil pontos de propósito rente ao raio da busca. A conta em 32 bits, sozinha, errou se 9 a 38 deles estavam dentro ou fora, o que quebraria a promessa. Com uma faixa de conferência (perto do raio, recalcula com precisão total), errou zero.
O custo da faixa: 16 recálculos em 200 mil (0,008%). O ganho de 2,7× sobrevive quase inteiro.
Trecho repetido, conta pesada, números pequenos.
O SIMD rende mais quando a mesma conta se repete sobre muitos dados independentes, que já estão na memória rápida perto do processador, e quando a conta é o gargalo, não a espera pela memória nem as decisões do tipo "se isto, faça aquilo". Quanto mais o trecho se aproxima disso, maior o ganho.
- Nenhuma repetição depende da anterior. Por isso o coração do nosso codec, em que cada previsão depende do valor anterior, não aproveita SIMD, e é nele que está o custo.
- Dados enfileirados e do mesmo tipo, lado a lado na memória. Buscar ou gravar em posições espalhadas mata o ganho.
- Poucas decisões no meio do caminho, ou decisões que podem virar uma máscara aplicada ao bloco inteiro.
- Conta pesada para cada número lido. Se o trecho só lê e soma uma vez, quem manda é a velocidade da memória.
- Números pequenos. Com bytes cabem de 16 a 64 por bloco, contra 2 a 8 com números de 64 bits. Por isso processar texto ganha mais do que cálculo científico.
Rende muito
- Texto: ler JSON, validar acentuação (UTF-8), achar vírgulas e quebras de linha em CSV, base64.
- Compressão e conferência de arquivos: empacotar números, códigos de verificação (CRC), criptografia (AES).
- Busca por semelhança: distância entre vetores, sobretudo com números inteiros.
- Imagem, áudio, planilhas enormes e bancos de dados de análise.
Rende pouco ou atrapalha
- Contas em que cada passo depende do anterior: compressores de entropia, leitores com muitos estados, previsão adaptativa.
- Trechos que esperam a memória e acessos espalhados (grafos, tabelas de busca).
- Somas de números com vírgula que precisam dar o mesmo resultado em qualquer máquina.
- Trechos curtos, em que preparar o bloco custa mais que a conta.
Se o trecho se repete muito, a conta é o gargalo e dá para usar números inteiros, vale muito. Se falta qualquer um dos três, mude primeiro o algoritmo ou a organização dos dados: esse ganho costuma ser maior e sobrevive à troca de máquina. No nosso índice, a distância entre vetores formados por inteiros de 0 a 255 é exata em 32 bits, porque a soma cabe inteira na precisão disponível; já a distância até o centro de um grupo, que tem vírgula, não é.
Cada posição do bloco que o processador trata de uma vez. Um chip de Mac tem 4 faixas para números de 32 bits; um servidor de ponta, 16.
O computador guarda número com vírgula com uns sete dígitos significativos (em 32 bits). O resto é arredondado, e a ordem das contas decide onde.
Um resumo matemático do arquivo que muda se um único bit mudar. Serve para provar que dois arquivos são idênticos sem compará-los inteiros.
Onde isso pode estar errado.
Um Mac com ruído
Sem isolar o processador de outras tarefas nem fixar a frequência. A próxima rodada é num servidor Linux, com o teste preso a um núcleo e repetições suficientes para separar sinal de ruído.
Servidor de ponta de verdade
O tradutor do Mac não imita o AVX-512. Como o "passo único" se comporta e quanto se ganha com 16 faixas num servidor real fica em aberto.
Do trecho ao sistema
Os 2,7× são de um trecho com os dados já na memória rápida. No índice inteiro, com milhões de vetores, a espera pela memória pode comer boa parte. Só a medida do sistema completo responde.
Pacote experimental
O pacote muda até deixar de ser experimental. Nada disso entra em produção antes; o que já vale é a regra de não somar em SIMD o que precisa dar o mesmo resultado.
← Caderno de pesquisa · stickybit.com.br
- The Go Blog: o experimento de SIMD portátil · discussão no Hacker News
- Nossas páginas: Telemetria certificada (a família) · TUBE, telemetria com erro limitado · SIEVE, busca vetorial certificada.
- Dado: Case Western Reserve University Bearing Data Center, acelerômetro 12 kHz (182.976 medições).
- Medições próprias, Go 1.27.0 com o pacote experimental ligado (
GOEXPERIMENT=simd), 25 set 2026. O limite de erro da soma em 32 bits segue a análise clássica de somas em ponto flutuante (γₙ = nu/(1−nu), u = 2⁻²⁴).