• Sep 0.10.0 ने AMD 9950X (Zen 5) जैसे AVX-512 समर्थित CPU के लिए optimization के साथ low-level CSV parsing में 21 GB/s हासिल किया, जो पहले के लगभग 18 GB/s से तेज है
  • performance improvement parser structure को बदलने से आया, ताकि .NET 9.0 के AVX-512 code generation में होने वाली mask register round-trip bottleneck कम हो सके
  • नया AVX-512-to-256 parser 512-bit में char लोड करने के बाद उसे 256-bit byte vector में बदलता है, जिससे mask handling और अलग permutation cost से बचा जाता है
  • Sep की low-level parsing performance 2023 के 0.1.0 में 5950X/.NET 7.0 पर लगभग 7 GB/s से बढ़कर 0.10.0 में 9950X/.NET 9.0 पर लगभग 21 GB/s हो गई, यानी लगभग 3 गुना सुधार
  • higher-level benchmark में भी 9950X multi-threaded Sep ने package assets की 10 लाख rows को 72.213ms, लगभग 8.0 GB/s पर process किया, और floats data में भी लगभग 8.1 GB/s दर्ज किया

Sep 0.10.0 का लक्ष्य और नतीजे

  • Sep 0.10.0 22 अप्रैल 2025 को रिलीज़ हुआ, और इसमें AMD 9950X (Zen 5) जैसे AVX-512 समर्थित CPU के लिए optimization और 9950X benchmarks शामिल हैं
  • low-level CSV parsing के आधार पर Sep ने 9950X पर 21 GB/s हासिल किया
    • 0.10.0 से पहले उसी 9950X पर यह लगभग 18 GB/s था
  • analysis का दायरा package assets CSV data की low-level Rows parsing तक सीमित है, और सभी आँकड़े single-thread आधार पर हैं
  • benchmark numbers कुछ percentage points तक बदल सकते हैं, इसलिए किसी खास release में छोटे regression दिख सकते हैं

0.1.0 से 0.10.0 तक performance में बदलाव

  • Sep की performance code changes, .NET version changes और CPU generation changes के संयुक्त असर से धीरे-धीरे बेहतर हुई
  • representative performance flow इस प्रकार है
    • 0.1.0, 5950X, .NET 7.0: लगभग 7 GB/s
    • 0.3.0, 5950X, .NET 8.0: लगभग 12 GB/s
    • 0.6.0, 5950X, .NET 9.0: लगभग 13 GB/s
    • 0.9.0, 9950X, .NET 9.0: लगभग 18 GB/s
    • 0.10.0, 9950X, .NET 9.0: लगभग 21 GB/s
  • जून 2023 में Sep के सार्वजनिक होने के बाद लगभग 2 साल से थोड़ा कम समय में यह लगभग 3 गुना तेज हुआ
  • 5950X पर Sep 0.9.0 और 9950X पर Sep 0.10.0 की तुलना करें तो लगभग 1.6 गुना सुधार दिखता है
    • 9950X की boost clock 5.7GHz है, जबकि 5950X की 4.9GHz है
    • माना गया है कि सिर्फ इस clock difference से लगभग 1.2 गुना तक की व्याख्या हो सकती है

.NET AVX-512 code generation में mask register bottleneck

  • Sep ने 0.2.3 से AVX-512 support दिया था, लेकिन उस समय .NET 8 में AVX-512 के k1-k8 mask registers का explicit support नहीं था
  • पुराने AVX-512 code generation में comparison result पहले mask register में जाता था, फिर general register में ले जाया जाता था, और फिर वापस mask register में लौटता था
  • 9950X पर upgrade के बाद Sep 0.9.0 ने low-level CSV parsing में लगभग 18 GB/s दर्ज किया, जो 5950X की तुलना में लगभग 1.4 गुना तेज था
  • environment variable से parser बदलकर तुलना करने पर 9950X पर AVX2 parser ने लगभग 20 GB/s दर्ज किया, जो पुराने AVX-512 parser से लगभग 10% तेज था
  • इस अंतर से पुष्टि हुई कि AVX-512 mask register handling अभी भी performance को प्रभावित कर रही थी

Sep parsing loop की बुनियादी संरचना

  • Sep के सभी parsers एक ही मूल संरचना का पालन करते हैं, और एक Parse generic method के जरिए quote handling के हिसाब से दो paths को support करते हैं
    • ParseColInfos: quote handling होने पर उपयोग होता है और इसमें अधिक state tracking चाहिए
    • ParseColEnds: quote handling न होने पर उपयोग होता है
  • parsing array से लाए गए char span units पर होती है, और उदाहरण आकार 16K है
    • यह आकार इतना छोटा है कि CPU cache में समा सके, और बाद में efficient multithreading के लिए भी फायदेमंद है
  • loop SIMD registers में 16-bit character data लोड करता है, उसे byte SIMD registers में बदलता है, और फिर CSV special characters से तुलना करता है
    • comparison targets में \n, \r, ", ; आदि शामिल हैं
  • comparison results को bitmask में बदला जाता है, और mask में set bits को ही क्रम से parse किया जाता है
  • performance difference काफी हद तक इस बात पर निर्भर करता है कि यह SIMD C# code .NET में किस machine code में JIT compile होता है

पुराना AVX-512 parser और 0.10.0 के बदलाव

  • 0.9.0 का SepParserAvx512PackCmpOrMoveMaskTzcnt दो 512-bit SIMD registers में 32-32 char लोड करता है, उन्हें एक 512-bit byte vector में pack करता है, और हर loop में 64 characters process करता है
  • packed data का क्रम गड़बड़ होता है, इसलिए PermuteVar8x64 से उसे फिर से reorder करना पड़ता है
  • .NET 9.0 assembly में हर Vec.Equals के बाद vpcmpeqb और vpmovm2b दो instructions आती थीं, और k1 जैसे mask registers तथा zmm general vector registers के बीच movement बार-बार होता था
  • Sep 0.10.0 में MoveMask calls को और पहले खिसकाया गया, ताकि mask registers और general registers के बीच round-trip count कम हो सके
    • दूसरे parsers में “special character नहीं है” वाले fast path में instruction count घटाने के लिए MoveMask सिर्फ जरूरत पड़ने पर ही call किया जाता है
  • बदलाव के बाद भी mask register से general register में movement बना रहता है, लेकिन कुल assembly instruction count घट जाता है

AVX2 और नया AVX-512-to-256 parser

  • AVX2 आधारित SepParserAvx2PackCmpOrMoveMaskTzcnt की assembly में mask registers नहीं होते, इसलिए इसकी संरचना अधिक सीधी है
  • इसी वजह से AVX2 parser पुरानी 0.9.0 AVX-512 parser implementation से तेज था
  • 0.10.0 का नया SepParserAvx512To256CmpOrMoveMaskTzcnt AVX-512 instructions से char लोड करता है और ConvertToVector256ByteWithSaturation से 256-bit byte vector बनाता है
    • वास्तविक instruction vpmovuswb है
    • हर loop में throughput “सिर्फ” 32 char का है, लेकिन संरचना अधिक सरल है
  • यह तरीका 512-bit mask register समस्या से बचता है, और packed data पहले से सही क्रम में ymm4 में होने के कारण अलग permutation की भी जरूरत नहीं पड़ती
  • नए parser ने 9950X पर Sep parsing performance को लगभग 21 GB/s तक पहुँचा दिया

parser-वार 9950X low-level benchmarks

  • AMD 9950X पर environment variable से सभी parsers चलाकर तुलना करने पर नया AVX-512-to-256 parser सबसे तेज निकला
  • मुख्य नतीजे इस प्रकार हैं
    • SepParserAvx512To256CmpOrMoveMaskTzcnt: 21597.7 MB/s, 27.0 ns/row, 1.351ms
    • SepParserVector256NrwCmpExtMsbTzcnt: 20608.5 MB/s, 28.3 ns/row, 1.416ms
    • SepParserAvx2PackCmpOrMoveMaskTzcnt: 20599.3 MB/s, 28.3 ns/row, 1.417ms
    • SepParserAvx512PackCmpOrMoveMaskTzcnt: 19944.3 MB/s, 29.3 ns/row, 1.463ms
  • Vector256 आधारित cross-platform parser लगभग AVX2 के बराबर पहुँच गया
  • Vector128 और Vector512 आधारित cross-platform parsers अभी भी तेज थे, लेकिन 5~10% धीमे रहे, और Vector512, Vector128 से भी धीमा था
  • SepParserIndexOfAny 2787.0 MB/s पर काफी पीछे रहा, और Vector64 को 9950X पर acceleration नहीं मिला, इसलिए यह 459.9 MB/s पर ही रहा

5950X और 9950X के higher-level benchmarks

  • package assets data में 10 लाख rows process करने के नतीजों में 9950X, 5950X से काफी तेज था
    • 5950X Sep_MT: 119.430ms, 4888.1 MB/s
    • 9950X Sep_MT: 72.213ms, 8084.1 MB/s
  • 9950X पर single-thread Sep ने package assets की 10 लाख rows को 291.979ms, 1999.4 MB/s पर process किया
  • उसी 9950X package assets benchmark में comparison targets की performance इस प्रकार रही
    • Sylvan: 413.265ms, 1412.6 MB/s
    • ReadLine_: 377.033ms, 1548.4 MB/s, allocation 1991.04MB
    • CsvHelper: 1005.323ms, 580.7 MB/s
  • floats data में भी 9950X का multi-threaded Sep 25,000 rows को 2.497ms, 8136.8 MB/s पर process करता है
  • 5950X से 9950X पर higher-level benchmark improvement भी low-level benchmark की तरह लगभग 1.5~1.6 गुना है

अभी कोई टिप्पणी नहीं है.

अभी कोई टिप्पणी नहीं है.