1 pontos por GN⁺ 2025-05-11 | 1 comentários | Compartilhar no WhatsApp
  • 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

 
GN⁺ 2025-05-11
Comentários do Hacker News
  • É muito absurdo que a Intel tenha investido por anos até em área de chip para suportar AVX-512 em produtos de consumo e, justamente agora que as bibliotecas começaram a usar isso cada vez mais, tenha removido o AVX-512 dos SKUs de consumidor; não é nem que a AMD tenha um suporte melhor a AVX-512, a ironia é que o AVX-512 acabou entrando nas CPUs de consumo da AMD porque a própria Intel abandonou o que havia investido
    • A Intel sempre repete esse padrão de criar um mercado tecnológico (Optane) e depois se retirar de repente (câmeras de profundidade), confundindo os consumidores; aposta tudo de uma vez numa tecnologia nova e, se não houver adoção, abandona logo; o suporte ao Optane foi interrompido justamente quando estava começando a amadurecer no kernel Linux; também há umas estratégias estranhas de corte de custos; se olhar a história, ela repete os mesmos erros desde o Intel iAPX 432
    • Neste artigo, com CPU AMD, foram observadas velocidades de original: 18GB/s, AVX2: 20GB/s, AVX512: 21GB/s; o AVX-512 quase não traz vantagem sobre o AVX2; CPUs de consumo da Intel suportam AVX2 até nos E-cores; o benchmark é single-thread; a Intel tirou o AVX-512 do chip para colocar mais núcleos, e como resultado o topo chega a 24 núcleos, enquanto a AMD tem 16; como a diferença de AVX2 para AVX512 é mínima, em multithread pode vencer o lado com mais núcleos; na maioria das cargas reais, aumentar a quantidade de núcleos traz mais benefício do que AVX-512; exceto em algumas tarefas muito específicas, considero a decisão da Intel razoável
    • O AVX-10 deve chegar em breve e deve ter um conjunto de recursos quase igual ao AVX-512 (não sei exatamente qual é a diferença)
    • O ponto mais interessante deste artigo, para mim, foi que no AMD 9950X o parser AVX2 foi cerca de 10% mais rápido que o parser baseado em AVX-512 (20GB/s contra 21GB/s); no fim, AVX-512 não parece ajudar muito o consumidor real; se o parsing de CSV chega a 20GB/s, já não tenho do que reclamar; só os fanáticos por assembly ligam para esse suporte
    • É realmente inacreditável como a Intel está agindo de forma tão burra
    • Se serve de consolo, o Sep usa AVX-512 sempre que pode, sem exigir configuração separada; roda bem em runtime JIT, então você não perde nada por, sem querer, mirar no piso mínimo de desempenho
    • A Intel também não vai muito bem em suporte de software; a iGPU do meu notebook é até bem decente, mas é uma pena que não haja suporte adequado em PyTorch e afins; llama.cpp e inferência com Vulkan funcionam bem, então eu gostaria que outros softwares também oferecessem suporte assim
  • Em vez de fazer quatro comparações por caractere ('\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 com vpternlogd e vpor
  • É lamentável a Intel decidir que precisa colocar núcleos lentos em CPUs de consumo e simplesmente remover todo o AVX-512 sem nem considerar “multi-pumping”
    • O principal motivo dessa escolha foram os problemas no processo de 10nm; como o rendimento era ruim e o custo alto demais, tentaram cortar o chip ao máximo e extrair lucro com núcleos da linha Atom/marketing de baixo consumo; nos produtos caros, aumentaram o tamanho e reduziram margens para proteger o mercado de servidores/cloud; no fim a rentabilidade caiu e eles ainda perderam participação, mas pelo menos tentaram
  • A afirmação de que houve quase 3x de ganho de velocidade em dois anos desde o lançamento do Sep (junho de 2023) é discutível se considerarmos também o salto de hardware
    • No mesmo hardware, o ganho de software (0.9.0 para 0.10.0) é de 17%, e se somar 17% aos 13088 do 0.9.0 dá 15375; comparando com os 7335 do 0.1.0, isso dá cerca de 2,1x de melhora
    • A alegação é de um ganho de 3GB/s em relação à versão anterior do sep no mesmo hardware; as velocidades reais e as informações de hardware estão descritas com transparência
    • Hoje já passamos de uma era tipo Lei de Moore, então é difícil esperar um ganho de 3x só com hardware; mesmo assim, considero esse resultado suficientemente impressionante para os padrões atuais
    • É verdade que afirmar um ganho de 3x sem considerar o salto de hardware abre espaço para debate, mas ainda assim é interessante como uma forma de olhar para o desempenho real do software ao longo dos anos
    • O gráfico de benchmark salta nada menos que quatro gerações de CPU e de repente parece um “grande salto de desempenho”, então não passa muita confiança
  • Espero que Arthur Whitney se sinta provocado por esse resultado e o supere com uma linha de código, ou que bata o recorde em uma linha junto com uma atualização do engine shakti ou uma atualização da notícia; espero novos avanços
  • Dá até arrepios imaginar quem precisa processar dezenas de milhões de linhas CSV nessa velocidade
    • Eu também já passei por isso; no começo escolhemos CSV por causa de volumes pequenos, e porque era fácil para não desenvolvedores — especialmente quem sabe mexer bem em Excel — lerem os dados; assim, logs/processos também eram tratados de forma limpa em CSV; mas quando o volume cresce 10x, 100x, otimizar a ingestão rápida de CSVs com bilhões de linhas vira uma necessidade real; esse tipo de otimização acaba comprando tempo para migrar gradualmente os processos internos para formatos mais adequados
    • CSV é um formato usado internamente com mais frequência do que se imagina e ainda tem a vantagem de ser fácil de comprimir (deflate); certa vez lidei com um código em que CSV despejava dados Netflow na velocidade da placa NIC; pessoalmente, acho que se vai haver tanta complexidade assim, melhor usar protocol buffers; protobuf nem é um formato tão difícil, mas a adoção não acontece muito
    • O que me assusta mais é o que significa armazenar o resultado de processar CSV a 21GB/s; por mais útil que seja a agregação, nessa velocidade tudo isso vai ter de se acumular em algum lugar, e isso me deixa curioso
    • Apesar de todos os defeitos, ainda acho que CSV continua sendo o formato de troca de dados mais comum
    • No setor financeiro, CSV pode ser compartilhado por todo mundo e, por ser baseado em texto, dá para enfiar em qualquer lugar e processar
    • Um exemplo são os arquivos de produto cartesiano que o departamento de contabilidade manda no fim do ano
    • Na prática, estou sofrendo justamente por ter de lidar com esse tipo antigo de CSV
    • Em quase todos os casos, HDF5 é melhor que CSV; ainda assim, só dá para explicar isso por ignorância, preguiça ou pelo raciocínio de “já funciona assim”
  • Entrei esperando código em assembly, mas fiquei surpreso e impressionado por ser C#; ótimo resultado
    • O .NET moderno é a “linguagem de alto nível” que integrou SIMD e intrinsics vetoriais da forma mais profunda; Tanner Gooding, da Microsoft, puxou muitos desses avanços, e os posts dele no blog também são excelentes
  • É confuso que o texto não defina claramente o que exatamente o código de 21GB/s faz; por exemplo, não fica claro qual é exatamente o formato do parsing (como tratamento de aspas em CSV etc.) nem como o resultado é usado depois do parsing (se é colocado em alguma estrutura de dados, por exemplo)
    • No artigo, o valor calculado de ns/row é cerca de 27ns/row (algo como 37.000 linhas por segundo), mas se forem 21GB/s isso daria algo como 570KB por linha, então parece um benchmark bem anormal
  • Na minha experiência, era difícil obter um ganho grande com código SIMD customizado em relação à autovetorização dos compiladores modernos (especialmente em código amigável a vetores), embora casos especiais como parsing de JSON sejam um pouco diferentes
  • Recentemente trabalhei com uma extração CSV de 300GB e perdi tempo demais com manipulação e verificação de integridade, então um parser de CSV rápido assim é realmente muito necessário
    • Não consigo entender por que não usam um formato especializado em armazenar dados de ponto flutuante; HDF5 é uma alternativa muito melhor