top of page

Fusão CUDA do llama.cpp é integrada com processamento de prompts até 10,7% mais rápido

há 2 horas
13 min de leitura

O llama.cpp integrou uma otimização CUDA em 25 de outubro, com benchmarks do colaborador relatando ganhos no processamento de prompts de até 10,7% no DGX Spark. A alteração de fusão CUDA do llama.cpp combina operações dentro da rede feed-forward de um modelo, o componente que transforma representações de tokens entre estágios de atenção. Seu benefício está relacionado à leitura de prompts, e não à produção de cada token subsequente da resposta.

As medições do colaborador anujj também mostram melhorias na RTX 5090 da NVIDIA, embora os ganhos percentuais relatados sejam menores. Estas são comparações relatadas pelo autor, não resultados reproduzidos de forma independente. A alteração subjacente pode ser verificada no código integrado, enquanto seu valor prático ainda depende do formato do modelo, do hardware e da carga de trabalho.

A comparação central é entre a execução fundida, que combina operações relacionadas, e um caminho de execução existente que agenda essas operações separadamente. Uma proposta anterior buscava a mesma oportunidade de outra forma. A abordagem integrada reorganiza como os valores chegam às threads da GPU, reduzindo o trabalho intermediário sem alterar os pesos armazenados do modelo. Para desenvolvedores que executam prompts longos localmente, isso torna essa uma melhoria de software específica que vale medir em relação a uma implantação existente.

O que muda com a integração da fusão CUDA do llama.cpp

A alteração integrada amplia uma otimização existente para cargas maiores de processamento de prompts em hardware NVIDIA compatível.

CUDA, a plataforma de computação em GPU da NVIDIA, fornece o ambiente de execução para esta implementação. MMQ, o caminho de multiplicação de matrizes quantizadas do llama.cpp, processa cálculos que envolvem pesos de modelos comprimidos. A quantização representa esses pesos com precisão numérica reduzida para diminuir os requisitos de armazenamento e memória.

A alteração de fusão integrada visa uma sequência recorrente dentro de camadas feed-forward densas compatíveis. Projeções separadas de gate e up transformam a mesma entrada. Uma unidade linear com porta, ou GLU, então combina seus resultados por meio de uma ativação e multiplicação elemento a elemento.

Anteriormente, cargas maiores nesse caminho processavam as projeções e sua combinação como operações separadas. Segundo anujj, a nova implementação executa essa sequência por meio de um único kernel de multiplicação de matrizes. Um kernel é uma função lançada em threads da GPU.

Essa consolidação importa porque o trabalho ao redor também consome recursos. Preparar entradas, lançar operações, gravar resultados intermediários e lê-los novamente podem adicionar sobrecarga. Combinar operações cria uma oportunidade de remover parte desse tráfego, preservando a transformação matemática pretendida.

A alteração não introduz essa ideia em todos os caminhos de execução ao mesmo tempo. O colaborador afirma que a fusão para pequenos lotes já existia por meio de outras implementações de matriz-vetor. Cálculos de matriz-vetor normalmente atendem a cargas menores do que os cálculos de matriz-matriz enfatizados aqui.

Essa distinção explica por que o anúncio se concentra no processamento de prompts. O prefill, a fase que processa um prompt de entrada antes da geração da resposta, pode expor lotes maiores de trabalho. O caminho de execução recém-suportado aborda essa parte da inferência.

A cronologia também importa. A descrição inicial do pull request é datada de 4 de outubro, enquanto o projeto o integrou em 25 de outubro. A integração leva a implementação ao branch master do projeto. Ela não estabelece que todos os aplicativos empacotados já incluam a alteração.

Um aplicativo para desktop, contêiner ou projeto downstream pode incorporar o llama.cpp em seu próprio cronograma. Portanto, os usuários precisam identificar a versão real do runtime por trás de uma interface. Uma atualização de aplicativo e uma integração no código-fonte upstream são eventos distintos.

Para arquivos de modelo existentes, a questão de compatibilidade é relativamente simples. O colaborador afirma que o layout dos pesos armazenados permanece inalterado. Os usuários não devem interpretar a referência do título a linhas intercaladas como uma exigência para baixar arquivos de modelo especialmente reorganizados.

A notícia imediata é, portanto, restrita e concreta. Uma sequência de execução compatível agora conta com uma otimização adicional disponível upstream. Se uma solicitação específica a utiliza depende das verificações de elegibilidade do runtime.

Os ganhos de benchmark favorecem o Spark, com aumento menor na RTX 5090

Os resultados relatados mostram uma direção consistente nas configurações listadas, mas sua magnitude varia conforme o hardware e a quantização.

O autor testou o DGX Spark usando seu processador GB10 e, separadamente, uma RTX 5090. Ambas as tabelas de benchmark comparam uma linha de base identificada como master com o pull request. Todas as linhas listadas relatam maior throughput de processamento de prompts para a implementação modificada.

No DGX Spark, a maior melhoria percentual listada pertence ao Llama-3.1-8B usando IQ4_XS, um formato de peso comprimido. O throughput aumenta de 2.933,9 para 3.249,0 tokens por segundo. O autor relata um ganho de 10,7% para essa configuração.

Outros resultados do Llama-3.1-8B no Spark ficam abaixo desse pico, mantendo melhorias relatadas substanciais. A configuração Q4_K_M passa de 2.749,3 para 3.000,6 tokens por segundo. A configuração Q5_K_M aumenta de 2.699,4 para 2.960,3 tokens por segundo.

Esses rótulos identificam diferentes configurações de modelo quantizado, e não medições intercambiáveis de um binário idêntico. Seus resultados mostram por que os usuários devem corresponder ao formato exato do arquivo ao avaliar uma otimização. Apenas o nome de uma família de modelos deixa de fora uma variável relevante.

A tabela do Spark também lista modelos identificados como Qwen3.8-27B e Qwen3.6-27B. Esses nomes são reproduzidos aqui como rótulos de benchmark do relatório do colaborador. A própria tabela de desempenho não estabelece de forma independente seus detalhes de treinamento, capacidades ou disponibilidade mais ampla.

Para a entrada identificada como Qwen3.8-27B, as melhorias no Spark variam de 4,6% a 7,4%. A linha Q4_K_M sobe de 840,1 para 899,9 tokens por segundo. A linha IQ4_XS aumenta de 882,4 para 948,0 tokens por segundo.

Os resultados da RTX 5090 apresentam uma escala diferente de melhoria. Nas configurações listadas, o autor relata ganhos entre 1,9% e 4,7%. Essa faixa percentual menor torna essencial uma interpretação específica para o hardware.

Para Llama-3.1-8B em IQ4_XS, o resultado da RTX 5090 aumenta de 12.997,6 para 13.603,3 tokens por segundo. A melhoria relatada é de 4,7%. Para a entrada Qwen3.8-27B Q6_K, o throughput sobe de 3.220,5 para 3.281,0 tokens por segundo, ou 1,9%.

Os benchmarks de fusão do llama.cpp, portanto, sustentam uma conclusão delimitada. Nos testes selecionados pelo autor com prompts longos, a otimização melhora o throughput de entrada medido em toda a matriz relatada. Eles não estabelecem um ganho idêntico para toda GPU compatível.

A comparação percentual também não revela por que o Spark se beneficia mais. Comportamentos de memória, características de execução e gargalos existentes diferentes podem afetar os resultados da otimização. Estabelecer sua contribuição relativa exigiria profiling adicional, que essas medições de destaque por si só não fornecem.

Para compradores, a implicação útil diz respeito à disciplina de avaliação. Esses resultados não justificam a escolha de hardware apenas com base em ganhos percentuais. Throughput absoluto, adequação do modelo, capacidade de memória e a latência real do aplicativo continuam sendo considerações distintas.

Linhas intercaladas eliminam trabalho entre cálculos

O movimento central da implementação é organizar resultados relacionados juntos antes de aplicar a operação de gate.

Anujj descreve o carregamento de linhas de gate e up em blocos alternados de oito. Essa organização posiciona valores correspondentes dentro dos resultados de trabalho da mesma thread. A thread pode então combinar esses valores ao gravar a saída final.

Registradores, os pequenos locais de armazenamento da GPU atribuídos às threads em execução, mantêm esses resultados intermediários. Aplicar a combinação ali evita uma viagem separada de ida e volta por buffers de saída intermediários para essa parte do cálculo. A economia pretendida vem da organização da execução.

A implementação mantém uma organização de acumulador em vez de introduzir um segundo bloco acumulador para a projeção de gate. Um acumulador mantém somas parciais durante a multiplicação. Um bloco é um conjunto de elementos da matriz processados em conjunto.

Essa escolha de design distingue esta implementação da proposta de fusão anterior. Segundo a descrição do colaborador, a abordagem mais recente segue uma sugestão de am17an. Ambas as propostas visam operações relacionadas, mas organizam o cálculo de forma diferente.

A distinção é prática, e não cosmética. Manter mais estado intermediário pode aumentar a pressão sobre os recursos de execução limitados de uma GPU. Combinar operações só ajuda quando as economias superam qualquer custo adicional de agendamento ou armazenamento.

É por isso que “menos kernels” não significa automaticamente “inferência mais rápida”. Uma operação combinada maior pode usar o hardware com menos eficiência em algumas condições. Uma otimização precisa preservar trabalho paralelo suficiente, evitando novas restrições que anulem seus benefícios.

O código integrado reflete essa preocupação por meio de verificações de elegibilidade. Ele avalia se a carga de trabalho é apropriada para esse caminho de fusão. Operações matemáticas compatíveis, por si só, não garantem que a fusão deva ser executada.

A implementação também concorre com stream-k, um método de agendamento que divide o trabalho de multiplicação de matrizes ao longo de sua dimensão de redução. O caminho fundido não pode usar essa decomposição. Por isso, precisa de outra forma de decidir se sua organização em blocos oferece eficiência suficiente.

Johannes Gaessler levantou essa questão durante a revisão, solicitando uma comparação antecipada entre a eficiência esperada do particionamento em blocos e o stream-k. O código integrado inclui uma decisão de eficiência antes de selecionar o caminho fundido. Isso torna a execução condicional parte do design.

A revisão do agendamento da fusão fornece a perspectiva cética mais útil sobre a otimização. Ela se concentra em circunstâncias nas quais uma simplificação atraente poderia perder desempenho. Trata-se de uma limitação técnica, e não de uma discordância sobre a existência do benchmark.

A competição principal aqui, consequentemente, permanece dentro do runtime. A execução fundida precisa superar a abordagem de agendamento existente para a forma de operação elegível. Não há evidência nesses resultados de uma vitória mais ampla sobre outro framework de inferência.

Esse mecanismo também esclarece o que os usuários devem esperar da fusão CUDA do llama.cpp. Ela reorganiza o trabalho para um cálculo existente. Não aumenta a capacidade de raciocínio de um modelo, não amplia seu conhecimento treinado nem elimina limites de memória não relacionados.

O mesmo modelo ainda executa a mesma tarefa geral. A oportunidade de engenharia está em gastar menos tempo para chegar à saída de uma sequência específica.

Processamento de prompts mais rápido altera uma parte do tempo de espera

O benchmark mede o processamento de entrada, portanto seu valor prático depende de quanto o processamento de entrada contribui para uma solicitação real.

O comando relatado processa um prompt contendo 16.384 tokens e solicita zero tokens gerados. Tokens são as unidades de texto que um modelo consome e produz. Essa configuração isola o throughput do prompt em vez de medir uma resposta conversacional completa.

O comando usa tamanhos de lote e microlote de 2.048. Um microlote é uma unidade de execução menor, extraída de um lote maior. Ele também habilita Flash Attention, uma implementação de atenção projetada para reduzir o tráfego de memória durante os cálculos de atenção.

O autor especifica armazenamento em meia precisão para o cache de chave-valor, que guarda informações de atenção de tokens processados anteriormente. Há cinco repetições no comando. Essas configurações definem as condições testadas e devem acompanhar qualquer resultado citado.

A metodologia de benchmark do projeto distingue o processamento de prompts da geração de tokens. Essa separação é crucial para interpretar esses números. Tokens de entrada por segundo e tokens de saída por segundo respondem a questões de desempenho diferentes.

Considere um desenvolvedor pedindo a um modelo local para analisar um grande arquivo de código-fonte. Processar essa entrada pode contribuir significativamente para o atraso antes de a resposta começar. Um caminho de pré-preenchimento mais rápido e elegível atua sobre essa parte da interação.

Uma breve troca de mensagens apresenta outra carga de trabalho. Seu prompt pode exigir relativamente pouco processamento em comparação com o tempo gasto na geração de uma resposta longa. A mesma melhoria de throughput de entrada afetaria, então, uma parcela menor da espera total.

Prompts em cache criam outra distinção. O cache de prompts reutiliza cálculos de entradas que o sistema já processou. Quando uma aplicação reutiliza esse trabalho com sucesso, resta menos entrada nova para essa otimização acelerar.

A análise de documentos também envolve tarefas além da inferência. Uma aplicação pode recuperar arquivos, extrair texto, classificar trechos ou preparar uma instrução antes de enviar qualquer coisa ao modelo. Processar entradas do modelo mais rapidamente não estabelece que essas etapas ao redor terminem antes.

Para equipes que mantêm uma base de conhecimento pesquisável, essa separação favorece melhores decisões de desempenho. A qualidade da recuperação e a seleção de contexto determinam o que chega ao modelo. O throughput de execução determina com que rapidez cálculos elegíveis o processam.

A distinção também aumenta a pressão sobre os responsáveis pela manutenção das aplicações. Eles precisam saber qual runtime seu produto distribui e se suas cargas de trabalho comuns alcançam o caminho otimizado. Uma nota de lançamento genérica sobre IA local mais rápida não pode responder a essas perguntas.

A resposta útil é medir no limite da aplicação. O tempo até o primeiro token mede o atraso antes de a saída começar. O tempo total de resposta mede toda a interação, enquanto o throughput de geração mede o ritmo após o início da saída.

Cada métrica pode se comportar de forma diferente após uma atualização do runtime. Uma melhoria no pré-preenchimento pode reduzir a espera inicial sem alterar a velocidade do texto subsequente. Relatar esses resultados separadamente oferece aos usuários uma descrição mais precisa da atualização.

Para o processamento de prompts do llama.cpp, o caso de uso mais forte continua sendo uma entrada nova e substancial em uma configuração elegível. O benchmark do autor enfatiza deliberadamente essa carga de trabalho. Estender seu resultado a todas as sessões de chat iria além das evidências.

Formatos compatíveis e verificações de correção definem os limites

O código mesclado contém restrições significativas, e o relatório de correção do autor deve ser lido dentro da cobertura de testes declarada.

O pull request descreve suporte aos tipos de pesos Q4_K, Q5_K, Q6_K, Q8_0 e IQ4_XS em arquiteturas NVIDIA Turing ou mais recentes. Essas são famílias de pesos compatíveis. Arquivos de modelo podem combinar tipos, portanto o rótulo geral de um arquivo não descreve todos os tensores internos.

A implementação também verifica se os pesos relevantes de gate e up atendem às condições necessárias para a fusão. Forma, tipo e layout importam porque a operação combinada espera cálculos correspondentes. Um arranjo não compatível deve manter outro caminho de execução.

O código mesclado exclui casos que exigem seu fallback de limite de linha. Um fallback lida com formas que não preenchem de forma limpa os blocos normais de processamento. Essa restrição importa porque a descrição original discute testes que cobrem casos de limite durante o desenvolvimento.

Portanto, os leitores devem distinguir o resumo inicial de testes das regras de seleção do código final. Testar uma implementação de desenvolvimento mais ampla não estabelece que cada forma testada continue elegível na versão mesclada. As verificações finais determinam a execução real.

Também há restrições sobre os parâmetros das operações. O código verifica configurações específicas de ativação antes de selecionar a fusão. Essas verificações impedem que o runtime trate operações superficialmente semelhantes como intercambiáveis quando seu comportamento exigido é diferente.

O escopo também se concentra em operações densas de feed-forward. Modelos de mixture-of-experts, que encaminham tokens por sub-redes selecionadas, introduzem requisitos de execução diferentes. A revisão identifica explicitamente trabalho adicional de suporte, em vez de estabelecer cobertura universal para esses modelos.

Outros backends de hardware não recebem essa otimização apenas por oferecerem suporte ao llama.cpp. O contribuidor separa explicitamente essa alteração dos demais backends. Resultados de hardware NVIDIA, portanto, não podem estabelecer benefícios equivalentes em uma GPU Apple ou em uma configuração AMD.

As evidências de correção são encorajadoras, mas continuam sendo relatadas pelo autor. Anujj afirma que todo o conjunto de testes de operações de backend é aprovado no GB10. O relatório também declara que as suítes de multiplicação de matrizes são aprovadas em uma RTX 5090.

O contribuidor também relata resultados de perplexidade idênticos nos testes especificados, com a fusão habilitada e desabilitada. A perplexidade mede quão bem um modelo prevê um texto de avaliação. Ela fornece uma verificação numérica útil, embora não represente todos os comportamentos possíveis de uma aplicação.

Esse resultado sustenta uma afirmação mais restrita do que identidade universal de saída. Pontuações idênticas em uma avaliação declarada não comprovam respostas geradas idênticas em todos os prompts, configurações ou plataformas. Uma validação mais ampla exige evidências mais amplas.

Os benchmarks de fusão do llama.cpp também não contam com uma reprodução independente nas fontes examinadas para este relatório. A revisão e a mesclagem upstream estabelecem que o projeto aceitou o código. Elas não transformam as medições do contribuidor em uma auditoria externa de desempenho.

Nenhum desses limites elimina o ganho relatado. Eles definem onde a afirmação se torna útil. Um leitor com hardware e tipos de modelo correspondentes tem um motivo concreto para testar, enquanto outras configurações exigem evidências separadas.

A interpretação mais forte combina os dois lados. A alteração tem um mecanismo claro e medições publicadas, juntamente com condições explícitas que determinam quando ela é executada.

Três sinais mostrarão até que ponto a melhoria se propaga

As próximas evidências devem conectar o código upstream, medições reproduzíveis e a latência percebida pelos usuários.

O primeiro sinal é a adoção downstream. Nos próximos meses, lançamentos de aplicações e builds distribuídas deverão estabelecer quais produtos incluem a implementação mesclada. Isso importa porque os usuários frequentemente interagem com o llama.cpp por meio de outra aplicação.

As instruções de build CUDA do projeto descrevem o caminho de compilação upstream. Distribuições empacotadas podem seguir cronogramas de lançamento diferentes. Um identificador de versão vinculado ao código-fonte incluído é mais informativo do que uma alegação geral de uso do backend mais recente.

Se aplicações amplamente usadas incorporarem a alteração, o argumento para adoção imediata se fortalece. Se permanecerem em revisões mais antigas, o alcance prático da mesclagem continuará limitado. Esse resultado diria respeito ao momento da distribuição, e não invalidaria a otimização subjacente.

O segundo sinal é a reprodução independente com configurações explícitas. Relatórios úteis devem identificar hardware, arquivos de modelo, revisões do runtime e argumentos de benchmark. Eles também devem separar o processamento de prompts novos da entrada em cache e da saída gerada.

Reproduções com diferentes tamanhos de prompt esclareceriam o quanto o ganho é sensível ao tamanho da carga de trabalho. Relatórios entre gerações compatíveis de GPU testariam se a direção persiste além das máquinas listadas. Resultados que mostrem regressões ajudariam a identificar limitações na lógica de seleção.

A questão relevante não é se cada execução corresponde ao máximo destacado. A questão é se cargas de trabalho comparáveis mostram uma melhoria repetível com variação aceitável. Um ganho menor e consistente ainda pode ser operacionalmente útil.

O terceiro sinal é a latência da aplicação. As equipes devem medir se um runtime atualizado reduz a espera antes de uma resposta começar em solicitações representativas. Elas devem manter o throughput de geração e o tempo total de resposta como medições separadas.

Essa evidência conectaria a mudança no kernel à experiência do usuário. Um atraso inicial menor em prompts longos e sem cache sustentaria a promessa prática da implementação. Um tempo total de resposta inalterado indicaria que outras etapas dominam o fluxo de trabalho medido.

O suporte ampliado a formatos ou arquiteturas seria desenvolvimento adicional, e não algo estabelecido por esta mesclagem. Alegações futuras devem identificar sua própria implementação e suas próprias medições. Os resultados atuais fornecem uma linha de base para comparação, não uma confirmação antecipada dessas extensões.

Por enquanto, a fusão CUDA do llama.cpp oferece um motivo específico para revisitar o desempenho de inferência local. Ela visa trabalho repetido dentro de cálculos feed-forward elegíveis e relata ganhos mensuráveis em condições divulgadas de processamento de prompts. Isso é suficiente para justificar uma avaliação sem prometer um aumento de velocidade generalizado.

Antes de atualizar uma implantação em funcionamento, preserve o identificador atual do runtime e um conjunto representativo de solicitações. Compare os mesmos arquivos de modelo, tamanhos de prompt, condições de cache e configurações de saída após a atualização. Registre o tempo de espera inicial separadamente da geração da resposta e mantenha os argumentos de benchmark junto de cada resultado. Para fluxos de trabalho com documentos longos, inclua entradas novas que se assemelhem ao uso cotidiano, em vez de depender inteiramente de throughput sintético. Para cargas de trabalho conversacionais, verifique se um atraso menor no processamento de entrada muda a experiência o bastante para importar. Em seguida, use suas próprias medições para decidir onde a melhoria upstream se encaixa no seu cronograma de lançamentos. O runtime atualizado encurta a parte da solicitação pela qual seus usuários realmente esperam?

 
 

Comece grátis

Um assistente de IA local-first com gestão de conhecimento pessoal

Para oferecer uma experiência de IA melhor,

atualmente, o remio é compatível apenas com Windows 10+ (x64) e M-Chip Macs.

Seu parceiro de IA no trabalho
Faça mais com o remio

Planeje. Crie. Entregue.
Tudo em um só lugar.

bottom of page