Qwen 3.8-27B em um M1 Ultra: De 12.1 a 20.3 tok/s Medindo Tudo
5 experimentos controlados rodando Qwen 3.8-27B em um M1 Ultra de 128 GB: scheduler QoS pinning, MTP speculative decoding, um GGUF challenger, e um MoE que perdeu por overhead de despacho — rodado com Kimi K3 em alta reflexão, com a evidência powermetrics para cada chamada.
Developed by Robert E. Beckner III (Merlin) | rbeckner.com
Os pesos para Qwen3.8-27B chegaram de manhã, e no mesmo dia comecei uma aventura com Kimi K3 rodando em modo de alta reflexão. Iniciei tudo com uma única pergunta: poderia este 27B denso — facilmente o modelo aberto mais forte em sua classe de tamanho — servir meus agentes de codificação em velocidade real em um Mac Studio com um M1 Ultra, 20 núcleos de CPU, 128 GB de memória unificada, e 800 GB/s de largura de banda de memória? O conhecimento comum diz que modelos densos decodificam lentamente em Apple Silicon porque são limitados por largura de banda de memória, e eu queria descobrir se essa quantidade de RAM e largura de banda poderia quebrar o padrão. Os pesos MLX de 4 bits chegaram a 15 GB, o framework estava atual, nada mais estava rodando na máquina, e o primeiro número foi 12.1 tokens por segundo. Parecia errado.
Eu vinha circulando esse tipo de experimento há um tempo. Em março, trabalhando com outra IA em meu laboratório de refinamento autônomo, rastreamos uma parede de <20 tok/s para modelos 30B em um M4 Max devido à fome de largura de banda de paginação em nível de SO — e essa investigação deixou um playbook: powermetrics primeiro, amostragem por cluster, pinning de memória antes de culpar. A corrida desta vez começou de pura curiosidade: eu tinha ouvido falar das otimizações de Qwen3.8, e queria saber se rodaria rápido fora da caixa nessa máquina com tanta RAM. Apenas no meio do experimento a realidade limitada por largura de banda se fez sentir. O que seguiu foi um sprint de experimentos controlados que projetamos juntos — Kimi elaborou as hipóteses e leu os contadores de hardware ao meu lado enquanto eu mantinha as mãos no metal. Cada experimento foi construído para absolver ou condenar uma única camada da pilha. As vitórias vieram de 2 lugares que o folklore de inferência local subestima: dicas de scheduler de CPU e speculative decoding. As alternativas 2 fashion — uma build GGUF servida por llama.cpp, e um modelo mixture-of-experts que parecia invencível em papel — perderam na medição. Este artigo é a trilha de evidências completa que construímos juntos, porque o método acabou valendo mais que qualquer número único.
O revezamento de rede e o servidor foram os primeiros suspeitos, e ambos foram inocentes#
O caminho de serviço tinha 3 saltos: minha estação de trabalho, um revezamento de execução baseado em SSH, e o servidor de modelo no loopback do Studio. Culpar o revezamento teria sido fácil, então o medimos primeiro. Os próprios tempos do servidor disseram 12.1 tok/s de decodificação; um benchmark de geração em processo bruto, sem servidor e sem revezamento, produziu 11.5 tok/s. O transporte custava cerca de 25% por sobrecarga por conexão, e o próprio modelo era a camada lenta.
Um bug de transporte valia a pena consertar de qualquer forma, e é o tipo de detalhe que custa horas se você nunca o viu: um revezamento Python TCP que usa um read(65536) bufferizado entrará em deadlock contra um protocolo local chatty, porque o leitor bufferizado espera por um buffer cheio ou EOF antes de retornar. Mudar para read1(), que retorna após uma única leitura subjacente, fez o revezamento se comportar. O sintoma parecia um travamento de rede; a causa era a semântica stdio.
Com o transporte absolvido, trabalhamos através da camada usual de sysctl. Elevar o limite de memória com fio da GPU (iogpu.wired_limit_mb) não mudou nada com 128 GB de RAM livres, então revertamos. O processo Python era nativo arm64, o MLX relatou a GPU como seu dispositivo padrão, e powermetrics mostrou a GPU em 54-62% de residência ativa desenhando 20-23 W durante a decodificação. Todos os suspeitos nesta rodada saíram livres — o que foi em si o resultado útil, porque apontou a investigação para a CPU.
O scheduler havia estacionado a inferência nos núcleos de eficiência#
Ler powermetrics por cluster de CPU em vez de por máquina expôs a primeira descoberta real. Durante a decodificação, os clusters de eficiência operavam em 75-93% ocupados enquanto os clusters de desempenho ficavam ociosos em 1-12%. Qualquer coisa lançada sobre SSH herda uma classe de qualidade de serviço que o macOS lê como trabalho de baixa prioridade, e o scheduler estava honrando essa dica mantendo uma carga de trabalho crítica de latência nos núcleos lentos.
A correção foi 1 linha de ctypes, executada antes do carregamento dos pesos do modelo:
Essa fixação, mais o carregamento da torre de texto do modelo através de mlx-lm em vez da pilha de visão completa, moveu a decodificação bruta de 11,5 para 15,1 tok/s — um ganho de 31% pela colocação do scheduler e um carregador mais enxuto, sem alteração no modelo. Posteriormente descobrimos que o alcance da fixação tem um limite: ela move a thread chamadora, e as threads de trabalho do MLX mantêm sua própria classe de agendamento. Para este modelo, a thread principal carregava suficiente trabalho para importar.
Decodificação especulativa entregou o salto que nenhum sysctl poderia#
A maior vitória única veio de um recurso que o modelo base já possuía. Qwen3.8 embarca com uma cabeça de previsão multi-token — um pequeno módulo auxiliar que redige vários tokens à frente — e o conversor MLX silenciosamente descarta esses tensores 15 durante a conversão. Um pacote comunitário re-hospeda a cabeça como um redator independente 253 MB, que me permitiu combiná‑la novamente com o modelo com o qual foi treinada.
O padrão de serviço é redigir‑depois‑verificar: o redator propõe alguns tokens, o modelo completo os verifica em uma 1 passagem, e os tokens aceitos contam todos. Com --draft-model e --draft-kind mtp no servidor, a aceitação de rascunho mediu 94% em prompts de codificação e chat realistas, e a decodificação passou de 15,1 para 20,3 tok/s no lado do servidor — 13,4 tok/s de ponta a ponta através do relay, subindo de 9,0. A GPU contou a história confirmatória: 77% residência ativa, tudo em plena 1296 MHz, consumindo 48 W, com o cluster de desempenho 97% ocupado. O pré-preenchimento melhorou na mesma atualização, de 14.7 tok/s para 18-55 dependendo da forma do prompt.
Decode speed by configuration (tok/s, M1 Ultra, 27B-4bit)Chart data
Postagens comunitárias colocam llama.cpp com um rascunho especulativo em 25-32 tok/s para esta classe de modelo no M1 Ultra, confortavelmente à frente de nossos números MLX, então demos ao concorrente um ringue justo: o Q4_K_M GGUF oficial, um modelo de rascunho apenas MTP correspondente, e uma build atual do llama.cpp com aceleração Metal confirmada ativa. A pista GGUF mediu 9.2 tok/s de base e 12.2 com o rascunho — cerca de 40% atrás da pilha MLX que deveria derrubar.
O llama.cpp continua sendo engenharia excelente; a lacuna provavelmente reside em como os kernels Metal de cada runtime lidam com este ponto de verificação neste chip. A lição durável é mais simples: um número que alguém mais mediu em sua máquina, sua build e seu ponto de verificação é uma hipótese sobre o seu. Os 18 GB de pesos do concorrente saíram da máquina na mesma tarde, e o binário de 50 MB do llama.cpp permaneceu para futuros rematches. Eu já escrevi sobre esta regra antes como benchmark-driven development — ela levou SEOReport from heuristics to a product — e aqui salvou uma migração.
Um MoE de 3B ativo deveria ter vencido, e o medidor GPU explicou a perda#
O último challenger tinha a teoria mais forte — o mesmo conhecimento comum que havíamos decidido testar no início. Modelos densos decodificam lentamente em Apple Silicon porque cada token gerado paga para ler quase todos os pesos; um modelo de mistura de especialistas com 35B parâmetros totais ativa apenas cerca de 3B por token, então em uma máquina limitada por largura de banda sua decodificação deve ser várias vezes mais rápida que um denso 27B — cada token lê cerca de 11% dos pesos. Baixamos o MoE de 4-bit e seu rascunho MTP correspondente, aquecemos o servidor e medimos 14,7 tok/s bruto: a mesma velocidade do modelo denso que deveria ser humilhado. Com decodificação especulativa atingiu 19 tok/s em prompts realistas e 26.3 em texto altamente previsível — um empate contra o 20.3 do modelo denso, sem argumento de qualidade para quebrar o empate.
powermetrics identificou o regime em 1 amostra. Durante a decodificação MoE a GPU ficou em 0-3% de residência ativa enquanto os clusters de eficiência caíam em 60-90%. O modelo gasta seu orçamento por token em trabalho do lado da CPU, e o tempo de nível de operação mostrou por quê: cada operação despachada custa 50-100 microsegundos de sobrecarga, e essa arquitetura híbrida — atenção linear GatedDeltaNet mais 256 especialistas atrás de um pequeno estado oculto de 2048 largura — emite cerca de 78 operações por camada em 40 camadas. Em tamanho de lote 1, a GPU termina cada kernel pequeno antes que a CPU possa enfileirar o próximo. A máquina estava limitada por despacho, e cargas de trabalho limitadas por despacho não ganham nada ao ler menos pesos por token.
Diagram source
graph TB
A[Decodificação lenta
no lote 1] --> B{GPU ocupada
durante decodificação?}
B -->|sim| C[Limitado por largura de banda
menos bytes vence]
B -->|não| D[Limitado por despacho
menos operações vence]
C --> E[MoE ajuda
quantização menor ajuda]
D --> F[Decodificação especulativa
ajuda mais]
style E fill:transparent,stroke:#10B981,stroke-width:2px
style F fill:transparent,stroke:#3B82F6,stroke-width:2px
Para fechar o ciclo, provamos que o caminho GPU em si estava saudável com um teste sintético: um loop de multiplicação de matriz 8192³ atingiu 10,8 TFLOPS em bfloat16 com a GPU em 97-100% de residência e 68 W. Evidências externas concordaram com o diagnóstico local — estimativas independentes colocam essa classe MoE perto de 21,7 tok/s em um M2 Ultra, e um problema OpenVINO documenta o mesmo modelo perdendo para um denso 8B em backends com caminhos de despacho mais fracos. O denso 27B com seu redator MTP manteve o slot de produção, e 38,5 GB de MoE pesos foram excluídos na mesma noite.
GPU active residency during decode (powermetrics, %)Chart data
GPU active residency (%)
dense 27B + MTP
77
MoE 35B-A3B
2
matmul hog test
100
O que os experimentos controlados 5 deixaram para trás#
A máquina agora serve Qwen 3.8-27B em 20.3 tok/s do lado do servidor, uma melhoria de 68% em relação ao início do dia, e o rendimento mais duradouro é uma lista de verificação que reutilizaremos em cada caixa futura:
Decodificar em tamanho de lote 1 tem 2 regimes, limitado por largura de banda e limitado por despacho, e uma amostra de 2 segundos powermetrics identifica a sua antes de você gastar um download no conserto errado.
Decodificação especulativa é o controle de serviço de maior alavancagem para uma caixa de usuário único. Ele adicionou 34% aqui e se compõe com cada outra otimização, porque lotes de verificação trabalham a GPU enquanto o redator absorve as lacunas ociosas.
Scheduler QoS é um parâmetro real de inferência no macOS. Qualquer coisa lançada sobre SSH deve fixar suas threads deliberadamente, e o efeito da fixação é verificável por cluster em vez de por vibrações.
Alegações de throughput comunitário viajam mal entre checkpoints, builds e chips. Um benchmark local é mais barato que uma migração.
Exclusão faz parte do fluxo de trabalho. Todo desafiante que perdeu deixou o disco dentro do dia, o que mantém o próximo experimento honesto e a máquina enxuta.
A parte satisfatória desta aventura é que as respostas estavam todas nos contadores de hardware, esperando que alguém fizesse perguntas precisas — e desta vez as fizemos juntos. Um modelo local que você mediu vale mais do que um modelo maior que você supôs — o mesmo retorno composto que obtenho tratando ganhos de IA local como infraestrutura em vez de trivia. Iniciei tudo na manhã em que os pesos chegaram, e Kimi K3 permaneceu na luta por cada experimento, cada leitura de contador, e esta redação das notas de laboratório da mesma noite. O próximo experimento já está na fila: gráficos de decodificação compilados prometem reduzir o custo de despacho por operação que decidiu o veredicto MoE, e quando um lançamento MLX chegar, a revanche levará uma tarde e 1 download.