-
कुछ साल पहले, मैंने SWAR ट्रिक का उपयोग करके
tolower()को तेज़ करने के तरीकों पर लिखा था। कुछ दिन पहले, Olivier Giniaux के लेख में SIMD निर्देशों का उपयोग करके छोटे strings को प्रोसेस करने के optimization तरीके देखकर मेरी रुचि जगी। यह तरीका Rust में लिखे गए तेज़ hash function में इस्तेमाल होता है. -
SIMD निर्देश छोटे strings को आसानी से संभाल सकते हैं, लेकिन memory और vector register के बीच transfer हमेशा असुविधाजनक रहा है। Olivier के लेख ने इस समस्या का एक दिलचस्प समाधान दिखाया.
उम्मीद के संकेत
-
कुछ SIMD instruction sets string processing के लिए उपयोगी masked load और store सुविधाएँ देते हैं। ये byte स्तर पर काम करती हैं.
- ARM SVE: हाल के बड़े ARM Neoverse cores में उपलब्ध, जैसे Amazon Graviton। लेकिन Apple Silicon पर उपलब्ध नहीं.
- AVX-512-BW: हाल के AMD Zen processors में उपलब्ध। AVX-512 एक जटिल extension set है, और Intel में इसका support बेतरतीब है.
-
मेरे पास एक AMD Zen 4 box है, इसलिए मैंने AVX-512-BW को आज़माने का फैसला किया.
tolower64()
- Intel intrinsics guide का उपयोग करके मैंने एक बेसिक
tolower()फ़ंक्शन लिखा जो एक बार में 64 bytes प्रोसेस कर सकता है.- byte स्तर के AVX-512 functions खोजने के लिए
*को wildcard की तरह इस्तेमाल करmm512*epi8खोजा. - कुछ registers को 64 उपयोगी bytes से भरा.
- uppercase को lowercase में बदलने के लिए आवश्यक संख्याएँ सेट कीं.
- input characters को A और Z से compare करके जाँचा कि वे uppercase हैं या नहीं.
- mask का उपयोग करके uppercase होने पर उन्हें lowercase में बदला.
- byte स्तर के AVX-512 functions खोजने के लिए
bulk load और store
tolower64()kernel को एक अधिक सुविधाजनक फ़ंक्शन में wrap करना पड़ता है। उदाहरण के लिए, ऐसा फ़ंक्शन जो string को copy करते हुए उसे lowercase में बदले.- लंबे strings के लिए unaligned vector load और store instructions का उपयोग किया जाता है.
masked load और store
- छोटे strings और लंबे strings के अंत वाले हिस्से के लिए masked unaligned load और store का उपयोग किया जाता है.
- mask में पहले
lenbits सेट होते हैं. - load और store, mask जुड़े full-width versions के समान होते हैं.
- mask में पहले
benchmarking
-
कई समान फ़ंक्शनों का performance benchmark किया गया.
- Clang 16 से compile किया गया और AMD Ryzen 9 7950X पर चलाया गया.
- inline और code motion के हस्तक्षेप से बचने के लिए हर फ़ंक्शन को अलग से compile किया गया.
-
नतीजे:
tolower64परीक्षण किए गए सभी फ़ंक्शनों में सबसे तेज़ है.copybytes64भीtolower64की तरह AVX-512 का उपयोग करता है, लेकिन बहुत अधिक तेज़ नहीं है.copybytes1byte स्तर परmemcpyकरता है, जो दिखाता है कि Clang 11 की auto-vectorization अपेक्षाकृत अच्छी नहीं है.- मानक
tolower()सबसे धीमा है. tolower1Clang 16 से compile किया गया byte-स्तरीयtolower()है, और auto-vectorization बेहतर हुई है, लेकिन यह अभी भी धीमा है.tolower8पिछले ब्लॉग पोस्ट में प्रस्तुत SWARtolower()है, जिसमें Clang auto-vectorization की कोशिश करता है, लेकिन परिणाम अच्छे नहीं हैं.memcpyशुरुआत में तेज़ है, लेकिनcopybytes64की आधी गति तक गिर जाता है.
निष्कर्ष
-
AVX-512-BW खासकर छोटे strings को प्रोसेस करते समय बहुत उपयोगी है.
-
Zen 4 पर यह बहुत तेज़ है, और built-in functions का उपयोग करना आसान है.
-
AVX-512-BW का performance बहुत smooth है.
-
मेरे पास ARM SVE support वाला box नहीं है, इसलिए मैं इसे विस्तार से जाँच नहीं सका, लेकिन यह जानने की जिज्ञासा है कि SVE छोटे strings पर कितना अच्छा काम करता है.
-
उम्मीद है कि ऐसे instruction set extensions और व्यापक रूप से इस्तेमाल होंगे। ये string processing performance को काफी बेहतर बना सकते हैं.
-
इस ब्लॉग पोस्ट का code मेरी वेबसाइट पर देखा जा सकता है.
GN⁺ का सार
- यह लेख SIMD निर्देशों का उपयोग करके छोटे strings को कुशलता से प्रोसेस करने का तरीका समझाता है.
- यह दिखाता है कि AVX-512-BW और ARM SVE instruction sets string processing के लिए उपयोगी हैं.
- benchmarking के नतीजे बताते हैं कि AVX-512-BW खासकर छोटे strings में बेहतरीन performance देता है.
- performance optimization में रुचि रखने वाले developers के लिए यह लेख उपयोगी होगा.
1 टिप्पणियां
Hacker News राय
Rust और LLVM memory model में "unsafe read beyond of death" ट्रिक को undefined behavior माना जाता है
AMD के AVX512 implementation और Intel के AVX10 competition को लेकर जिज्ञासा है
SWAR optimization सिर्फ 8-byte address पर aligned string के लिए उपयोगी है
mask addition साफ-सुथरा लगता है
Clang का उपयोग करने पर बेहतर परिणाम मिल सकते हैं
छोटी लंबाई की strings के लिए core loop में एक instruction कम है
ASCII को UTF-8 में uppercase/lowercase बदलने का एक समान implementation C# में लिखा गया है
AVX512 का उपयोग करके text को uwu में बदलने का SIMD usage example भी है
Unicode character conversion को ध्यान में रखें तो यह और भी प्रभावशाली होगा
पहले image के चारों ओर काली border जोड़कर buffer SIMD problems से बचने का अनुभव रहा है