Você pode ter um NVMe rápido, dezenas de núcleos sobrando e, mesmo assim, estar perdendo desempenho por um detalhe que quase ninguém vê: a forma como as IRQs do armazenamento acabam “caindo” em CPUs que não conversam bem entre si.
Em máquinas com muitos cores, o número de IRQs de NVMe pode ser menor do que o total de CPUs. O resultado é simples e cruel: vários núcleos passam a compartilhar a mesma IRQ. Quando essa afinidade não respeita a topologia do processador, especialmente em arquiteturas com clusters de núcleos que compartilham cache L2, o kernel cria um caminho mais longo para buscar dados. A perda aparece como latência extra, gargalo de cache e queda de throughput.
O fim do gargalo invisível
O patch “cluster-aware” em lib/group_cpus muda o jogo ao tornar o agrupamento de CPUs consciente de clusters dentro de cada domínio NUMA, melhorando a localidade entre CPUs e suas IRQs de NVMe.
O que muda, na prática:
- Antes: o algoritmo espalhava grupos de CPUs dentro do nó NUMA sem considerar clusters, e algumas IRQs acabavam “misturando” núcleos de clusters diferentes, forçando acesso cruzado ao cache L2.
- Agora: o kernel tenta formar grupos respeitando clusters dentro do NUMA. Isso reduz o custo de memória/cache quando múltiplas CPUs compartilham a mesma IRQ.
- Por que isso importa: em plataformas onde 4 núcleos formam um módulo (cluster) e compartilham L2, manter a IRQ “dentro do cluster” evita que um núcleo atenda interrupções puxando dados por um caminho menos local.
Exemplo simplificado do problema (IRQ “escapa” do cluster):
CPU |28 29 30 31|32 33 34 35|36 ...
-------- -------- --------
IRQ 8 9 10Quando uma IRQ fica “ancorada” em CPU32, mas atende também CPU31, você cria o cenário clássico de acesso cruzado de L2.
Com o patch, a distribuição tende a ficar mais “limpa”, reduzindo esse cruzamento:
CPU |00 01 02 03|04 05 06 07|08 09 10 11| ...
----- ----- ----------- -----------
IRQ 1 2 3 4O resultado que fez esse patch ganhar atenção é direto: mais de 15% de diferença em FIO (libaio, randread, bloco de 8k), num cenário onde I/O e interrupções viram o gargalo real em vez do “poder bruto” da CPU.
O detalhe importante para quem acompanha o kernel de perto: isso foi enfileirado por Andrew Morton na árvore de testes (mm) a partir do trabalho de Wangyang Guo, com ajustes no histórico do patch e uma correção para evitar loop infinito quando a máscara de cluster retorna inválida. Ainda é o tipo de mudança que costuma passar por ciclo de testes antes de virar “padrão” para todo mundo.
Se você roda banco de dados, storage pesado, virtualização, CI com muita leitura aleatória ou qualquer workload com NVMe sob pressão, esse é o tipo de correção que parece mágica: nada de troca de hardware, apenas o kernel parando de desperdiçar performance por topologia.
