- A versão mais recente, Sep 0.10.0, alcança uma impressionante velocidade de parsing de CSV de 21 GB/s no AMD 9950X
- O desempenho melhorou significativamente com suporte a AVX-512 e a superação de problemas com registradores de máscara
- O novo parser AVX-512-to-256 superou o AVX2 e o parser AVX-512 anterior
- Em um ambiente multithread, processa 1 milhão de linhas em 72 ms, registrando largura de banda de 8 GB/s
- Com otimização contínua de software e hardware, obteve cerca de 3x de melhoria de desempenho em 2 anos
Visão geral do lançamento do Sep 0.10.0 e dos ganhos de desempenho
- O Sep recentemente fez otimizações, no lançamento 0.10.0, para CPUs com suporte a AVX-512 (como AMD 9950X, Zen 5), e os resultados de benchmark foram atualizados
- Na versão mais recente, registrou o notável resultado de 21 GB/s em parsing de CSV de baixo nível
- Em comparação com a versão anterior, representa um aumento considerável de desempenho em relação aos 18 GB/s
- Os detalhes das melhorias podem ser vistos nas releases do GitHub e no README do Sep
- O texto explica o processo de ganho de desempenho por meio de código C# baseado em SIMD e assembly SIMD x64, superando a ineficiência do código de máquina AVX-512 do .NET 9.0
Evolução do desempenho do Sep
- A evolução do Sep é mostrada visualmente desde o 0.1.0 até o 0.10.0, do .NET 7.0 ao 9.0, e do AMD 5950X (Zen 3) ao 9950X (Zen 5)
- Os benchmarks são em thread única, e pode haver pequenas variações entre releases
- A mensagem principal é que tanto grandes refatorações (como a reescrita da estrutura interna no 0.2.0) quanto pequenas mudanças acumuladas levaram a melhorias contínuas de desempenho
- Com a evolução conjunta de hardware e software, foi possível atingir cerca de 21 GB/s de parsing, aproximadamente 3x mais rápido em uma média de 2 anos
- Só a mudança de geração de hardware (5950X→9950X, 4.9→5.7GHz) já explica uma melhora superior a 1,2x
Geração de código AVX-512 e problema dos registradores de máscara
- O Sep oferece suporte a AVX-512 desde a versão 0.2.3, mas havia limitações no uso dos registradores de máscara do AVX-512 (k1-k8)
- No .NET 8, não havia suporte direto a registradores de máscara, então cópias e conversões repetidas entre registradores normais causavam perda de desempenho
- No início, como não havia uma CPU separada com suporte a AVX-512, os testes foram feitos de forma limitada em um Xeon Silver 4316, confirmando que ainda assim era a opção mais rápida
Upgrade para o 9950X e comparação entre AVX-512 e AVX2
- Recentemente, ao atualizar a CPU de Zen 3 (5950X) para Zen 5 (9950X), os benchmarks do Sep chegaram a 18 GB/s
- Em um teste comparando diretamente os parsers AVX-512 e AVX2, de forma um pouco surpreendente, o AVX2 mostrou cerca de 20 GB/s, aproximadamente 10% mais rápido que o AVX-512
- Isso sugere que a ineficiência do tratamento de registradores de máscara pelo JIT do .NET ainda continua sendo um problema
Código do parser, análise de assembly e novo parser AVX-512-to-256
- Todos os parsers do Sep processam blocos de char span de 16K e usam operações de comparação baseadas em registradores SIMD (
Vector256 etc.)
- Com SIMD, identificam rapidamente caracteres especiais (quebra de linha, aspas, delimitadores etc.) e os convertem em bitmasks, otimizando operações de conjunto
- O parser baseado em AVX-512 tinha muitas operações redundantes devido à movimentação repetida entre registradores de máscara (
k1 etc.) e registradores gerais (zmm etc.)
- Na versão 0.10.0, a chamada de
MoveMask foi antecipada para minimizar conversões de máscara desnecessárias, reduzindo o número de instruções em assembly
- O parser AVX2, por não ter registradores de máscara, tinha uma estrutura muito mais simples e, na prática, era mais rápido que o AVX-512
- O novo parser AVX-512-to-256 lê os dados com AVX-512 e usa instruções de conversão para 256 bits para contornar o problema do tratamento de máscaras, simplificando a implementação e alcançando desempenho acima de 21 GB/s
Resumo de benchmarks de vários parsers
- Ao comparar, via variável de ambiente, os benchmarks de todos os tipos de parser, o parser AVX-512-to-256 foi o mais rápido, com 21,5 GB/s
- Os parsers baseados em AVX2 e
Vector256 também apresentaram desempenho próximo, com diferença de menos de 5%
- Os parsers baseados em
Vector128 e Vector512 foram de 5% a 10% mais lentos que o AVX2, e o parser Vector512, em especial, foi mais lento até que o Vector128
- O parser
IndexOfAny foi muito mais lento que os outros parsers SIMD. O Vector64 teve desempenho muito baixo, já que não recebe aceleração no 9950X
- Os parsers SIMD baseados em AVX-512 e AVX2 demonstram desempenho amplamente superior em comparação com outros parsers CSV da mesma categoria
Benchmarks de nível superior: comparação entre 5950X e 9950X
- Com base em 1 milhão de linhas de ativos de pacotes, o Sep_MT registrou 72 ms (8 GB/s) no 9950X e 119 ms (4,9 GB/s) no 5950X
- Mesmo em dados com carga real (como
float), o 9950X alcançou largura de banda de ~8 GB/s em multithread
- A mudança de geração (5950X→9950X) trouxe um ganho de cerca de 1,5x a 1,6x em parsing de aplicações reais
- Em comparação com bibliotecas CSV concorrentes (Sylvan, ReadLine, CsvHelper etc.), mostrou throughput muito superior e alocação mínima de recursos
Conclusão e resumo
- O Sep 0.10.0 supera os limites de desempenho em parsing de CSV ao combinar otimização de software com recursos de hardware mais modernos (AVX-512, clock mais alto)
- O centro da inovação está no desenho de algoritmos SIMD modernos e nas melhorias na estrutura do código JIT e do assembly do .NET
- O efeito combinado de melhorias cumulativas de desempenho e da mudança de geração da arquitetura em um curto período é impressionante
- O Sep apresenta, na área de parsing de CSV, um nível de alto desempenho, multiplataforma e escalabilidade que está efetivamente entre os melhores do setor
1 comentários
Comentários do Hacker News
llama.cppe inferência com Vulkan funcionam bem, então eu gostaria que outros softwares também oferecessem suporte assim'\n','\r',';','“') seguidas de três operações de or, dá para usar um truque comum e fazer 1 shuffle, 1 comparação e 0 operações de or; publiquei esse truque num blog, então vale conferir; dito isso, neste artigo também reduziram as operações de or comvpternlogdevpor