Mencapai Parsing CSV 21 GB/s dengan SIMD di AMD 9950X
(nietras.com)- Sep 0.10.0 mencapai 21 GB/s dalam parsing CSV level rendah berkat optimasi untuk CPU yang mendukung AVX-512 seperti AMD 9950X (Zen 5), lebih cepat dari sebelumnya sekitar 18 GB/s
- Peningkatan performa berasal dari perubahan struktur parser untuk mengurangi bottleneck akibat bolak-balik register mask dalam pembuatan kode AVX-512 di .NET 9.0
- Parser AVX-512-to-256 baru memuat
chardalam 512-bit lalu mengubahnya menjadi vektor byte 256-bit, sehingga menghindari biaya pemrosesan mask dan permutasi terpisah - Performa parsing level rendah Sep meningkat sekitar 3×, dari sekitar 7 GB/s pada 5950X/.NET 7.0 di versi 0.1.0 tahun 2023 menjadi sekitar 21 GB/s pada 9950X/.NET 9.0 di versi 0.10.0
- Dalam benchmark tingkat atas, Sep multithread di 9950X memproses 1 juta baris package assets dalam 72,213 ms, sekitar 8,0 GB/s, dan data floats juga mencatat sekitar 8,1 GB/s
Tujuan dan hasil Sep 0.10.0
- Sep 0.10.0 dirilis pada 22 April 2025, dan mencakup optimasi untuk CPU yang mendukung AVX-512 seperti AMD 9950X (Zen 5) serta benchmark 9950X
- Berdasarkan parsing CSV level rendah, Sep mencapai 21 GB/s di 9950X
- Sebelum 0.10.0, pada 9950X yang sama angkanya sekitar 18 GB/s
- Cakupan analisis adalah parsing
Rowslevel rendah pada data CSV package assets, dan semua angka berdasarkan single thread - Angka benchmark dapat berubah beberapa poin persentase, sehingga regresi kecil bisa terlihat pada rilis tertentu
Perubahan performa dari 0.1.0 hingga 0.10.0
- Performa Sep meningkat bertahap melalui kombinasi perubahan kode, perubahan versi .NET, dan perubahan generasi CPU
- Alur performa representatifnya sebagai berikut
- 0.1.0, 5950X, .NET 7.0: sekitar 7 GB/s
- 0.3.0, 5950X, .NET 8.0: sekitar 12 GB/s
- 0.6.0, 5950X, .NET 9.0: sekitar 13 GB/s
- 0.9.0, 9950X, .NET 9.0: sekitar 18 GB/s
- 0.10.0, 9950X, .NET 9.0: sekitar 21 GB/s
- Sejak Sep dipublikasikan pada Juni 2023, kecepatannya naik sekitar 3× dalam waktu sedikit kurang dari 2 tahun
- Jika membandingkan penggunaan Sep 0.9.0 di 5950X dengan Sep 0.10.0 di 9950X, peningkatannya sekitar 1,6×
- Boost clock 9950X adalah 5,7 GHz, sedangkan 5950X adalah 4,9 GHz
- Perbedaan clock ini saja diperkirakan dapat menjelaskan sekitar 1,2×
Bottleneck register mask pada pembuatan kode AVX-512 .NET
- Sep mendukung AVX-512 sejak 0.2.3, tetapi saat itu .NET 8 belum mendukung register mask
k1-k8AVX-512 secara eksplisit - Dalam pembuatan kode AVX-512 lama, hasil perbandingan masuk ke register mask, lalu dipindahkan ke register umum, kemudian kembali lagi ke register mask
- Setelah upgrade ke 9950X, Sep 0.9.0 mencatat sekitar 18 GB/s dalam parsing CSV level rendah, sekitar 1,4× lebih cepat dari 5950X
- Ketika parser diubah lewat variabel lingkungan untuk perbandingan, parser AVX2 di 9950X mencatat sekitar 20 GB/s, sekitar 10% lebih cepat dari parser AVX-512 lama
- Selisih ini memastikan bahwa pemrosesan register mask AVX-512 masih memengaruhi performa
Struktur dasar loop parsing Sep
- Semua parser Sep mengikuti struktur dasar yang sama, dan mendukung dua jalur dengan perilaku penanganan tanda kutip berbeda melalui satu metode generik
ParseParseColInfos: digunakan saat menangani tanda kutip dan membutuhkan pelacakan status lebih banyakParseColEnds: digunakan ketika tidak ada penanganan tanda kutip
- Parsing dilakukan per span
charyang diambil dari array, dengan contoh berukuran 16K- Ukuran ini cukup kecil untuk masuk ke cache CPU, dan juga menguntungkan untuk multithreading yang efisien setelahnya
- Loop memuat data karakter 16-bit ke register SIMD, mengubahnya menjadi register SIMD byte, lalu membandingkan karakter khusus CSV
- Target perbandingan mencakup
\n,\r,",;, dan lainnya
- Target perbandingan mencakup
- Hasil perbandingan diubah menjadi bitmask, dan hanya bit yang disetel dalam mask yang di-parse secara berurutan
- Perbedaan performa sangat bergantung pada bagaimana kode SIMD C# ini dikompilasi JIT menjadi machine code oleh .NET
Parser AVX-512 lama dan penyesuaian di 0.10.0
SepParserAvx512PackCmpOrMoveMaskTzcntpada 0.9.0 memuat masing-masing 32charke dua register SIMD 512-bit, lalu mengemasnya menjadi satu vektor byte 512-bit untuk memproses 64 karakter per loop- Data yang sudah dikemas memiliki urutan yang tercampur, sehingga perlu disusun ulang dengan
PermuteVar8x64 - Dalam assembly .NET 9.0, setiap
Vec.Equalsditerjemahkan menjadi dua instruksi,vpcmpeqbdanvpmovm2b, dan perpindahan antara register mask sepertik1dan register vektor umumzmmterjadi berulang kali - Pada Sep 0.10.0, pemanggilan
MoveMaskdimajukan untuk mengurangi jumlah bolak-balik antara register mask dan register umum- Di parser lain,
MoveMaskhanya dipanggil saat diperlukan untuk mengurangi jumlah instruksi pada fast path “tanpa karakter khusus”
- Di parser lain,
- Setelah penyesuaian, perpindahan dari register mask ke register umum masih tersisa, tetapi jumlah instruksi assembly secara keseluruhan berkurang
AVX2 dan parser AVX-512-to-256 baru
- Assembly dari
SepParserAvx2PackCmpOrMoveMaskTzcntberbasis AVX2 memiliki struktur yang lebih lurus karena tidak ada register mask - Berkat struktur ini, parser AVX2 lebih cepat daripada parser AVX-512 lama di 0.9.0
SepParserAvx512To256CmpOrMoveMaskTzcntbaru di 0.10.0 memuatchardengan instruksi AVX-512 lalu membuat vektor byte 256-bit menggunakanConvertToVector256ByteWithSaturation- Instruksi aktualnya adalah
vpmovuswb - Throughput per loop “hanya” 32
char, tetapi strukturnya lebih sederhana
- Instruksi aktualnya adalah
- Pendekatan ini menghindari masalah register mask 512-bit, dan karena data yang dikemas sudah berada dalam urutan yang benar di
ymm4, permutasi terpisah juga tidak diperlukan - Parser baru ini menaikkan performa parsing Sep di 9950X hingga sekitar 21 GB/s
Benchmark level rendah parser di 9950X
- Hasil perbandingan menjalankan semua parser melalui variabel lingkungan di AMD 9950X menunjukkan bahwa parser AVX-512-to-256 baru adalah yang tercepat
- Hasil utamanya sebagai berikut
SepParserAvx512To256CmpOrMoveMaskTzcnt: 21597,7 MB/s, 27,0 ns/row, 1,351 msSepParserVector256NrwCmpExtMsbTzcnt: 20608,5 MB/s, 28,3 ns/row, 1,416 msSepParserAvx2PackCmpOrMoveMaskTzcnt: 20599,3 MB/s, 28,3 ns/row, 1,417 msSepParserAvx512PackCmpOrMoveMaskTzcnt: 19944,3 MB/s, 29,3 ns/row, 1,463 ms
- Parser cross-platform berbasis
Vector256mencapai level yang hampir sama dengan AVX2 - Parser cross-platform berbasis
Vector128danVector512masih cepat tetapi 5–10% lebih lambat, danVector512lebih lambat daripadaVector128 SepParserIndexOfAnytertinggal jauh pada 2787,0 MB/s, danVector64tidak diakselerasi di 9950X sehingga hanya berada di 459,9 MB/s
Benchmark tingkat atas 5950X dan 9950X
- Pada data package assets, hasil pemrosesan 1 juta baris menunjukkan 9950X jauh lebih cepat daripada 5950X
- 5950X
Sep_MT: 119,430 ms, 4888,1 MB/s - 9950X
Sep_MT: 72,213 ms, 8084,1 MB/s
- 5950X
- Di 9950X,
Sepsingle thread memproses 1 juta baris package assets dalam 291,979 ms, 1999,4 MB/s - Dalam benchmark package assets yang sama di 9950X, pembanding menunjukkan performa berikut
Sylvan: 413,265 ms, 1412,6 MB/sReadLine_: 377,033 ms, 1548,4 MB/s, alokasi 1991,04 MBCsvHelper: 1005,323 ms, 580,7 MB/s
- Pada data floats, Sep multithread di 9950X juga memproses 25.000 baris dalam 2,497 ms, 8136,8 MB/s
- Besaran peningkatan benchmark tingkat atas dari 5950X ke 9950X mirip dengan benchmark level rendah, yaitu sekitar 1,5–1,6×
Belum ada komentar.