- sorted array में membership check को पाठ्यपुस्तक वाले binary search से भी तेज़ बनाया जा सकता है, और SIMD Quad हर measured condition में
std::binary_search से तेज़ था
- SIMD Quad 16-bit unsigned integer sorted array को 16-element ब्लॉक्स में बाँटता है, block boundaries पर 4-way interpolation search करता है, और block के अंदर SIMD parallel comparison चलाता है
- आधुनिक 64-bit ARM और x64 (Intel/AMD) एक ही instruction में 8 16-bit integers की तुलना कर सकते हैं, इसलिए एक बार में सिर्फ एक value जाँचने वाले binary search ढाँचे का कड़ाई से पालन करना अब उतना ज़रूरी नहीं रह जाता
- benchmark 2~4096 आकार के 100,000 sorted arrays और 10 million membership queries के साथ चलाया गया; cold mode cache miss और warm mode cache hit को simulate करता है
- Intel पर warm cache में SIMD Quad, binary search से 2x से अधिक तेज़ था; Apple पर cold cache में 2x से अधिक तेज़ था; और Intel पर बड़े arrays के cold cache में 4-way approach ने memory-level parallelism का बेहतर उपयोग किया
sorted array membership check की bottleneck
- sorted array में कोई value मौजूद है या नहीं, इसे जाँचने का सबसे सरल तरीका values को एक-एक करके देखना है, यानी linear search; C++ में
std::find से यही प्रभाव मिलता है
- बड़े arrays में binary search ज़्यादा तेज़ होता है; यह search range के बीच वाले value को आधार बनाकर ऊपरी या निचला आधा हटाता है, और value मिलने या range खाली होने तक यह प्रक्रिया दोहराता है
- C++ का
std::binary_search value मौजूद है या नहीं, इसे boolean के रूप में लौटाता है
- Roaring Bitmap format 1~4096 आकार के 16-bit integer arrays का उपयोग करता है, और membership check के लिए binary search इस्तेमाल करता है
SIMD Quad की शुरुआत
- ज़्यादातर आधुनिक processors में data-parallel instructions यानी SIMD होते हैं, और 64-bit ARM तथा x64 (Intel/AMD) एक instruction में 8 16-bit integers की target value से तुलना कर सकते हैं
- इस वजह से binary search को 8 से छोटे blocks तक नीचे ले जाना ज़रूरी नहीं रहता, और 16 या उससे अधिक elements की तुलना भी सस्ते में की जा सकती है
- binary search एक बार में एक value जाँचता है, लेकिन आधुनिक processors एक साथ कई values load और check कर सकते हैं, और memory-level parallelism भी अच्छा होता है
- array को आधा बाँटने की जगह 4 हिस्सों में बाँटने वाला 4-way search आज़माया जा सकता है; instructions थोड़ी बढ़ें तो भी bottleneck शायद instruction count न हो
SIMD Quad algorithm की संरचना
- SIMD Quad, 16-bit unsigned integer sorted arrays के लिए search algorithm है, जो 4-way interpolation search और SIMD को जोड़ता है
- array को 16-element fixed-size blocks में बाँटा जाता है, और आख़िरी block अपवाद हो सकता है
- हर block के आख़िरी element को interpolation key की तरह इस्तेमाल करके range को उस एक block तक सीमित किया जाता है जहाँ target value होने की संभावना सबसे ज़्यादा हो; फिर उस block के 16 elements को SIMD से एक साथ जाँचा जाता है
- core flow एक hierarchical search है: block boundaries पर interpolation search से comparison count कम करना, और block के अंदर SIMD से parallel comparison चलाना
- काम करने के चरण इस प्रकार हैं
- अगर element count 16 से कम है, तो पूरे array पर simple linear search किया जाता है
cardinality आकार के array को 16 लगातार elements वाले blocks में बाँटा जाता है, और कुल block count num_blocks = cardinality / 16 होता है
16-1, 32-1 जैसी positions पर block के आख़िरी elements को key की तरह लेकर current search range के 1/4 points की target pos से तुलना की जाती है और base adjust किया जाता है
- interpolation के नतीजे के अनुसार उपयुक्त block index
lo चुना जाता है
- अगर block valid है, तो ARM पर NEON और x64 पर SSE2 से 16 elements load करके target value के साथ parallel equality comparison किया जाता है; match मिलने पर
true लौटाया जाता है
- पूरे 16-element blocks में शामिल न होने वाले बचे हुए elements पर linear search किया जाता है
benchmark का तरीका
- benchmark में 2~4096 के हर array size के लिए 16-bit unsigned integers के 100,000 sorted arrays बनाए गए
- हर size पर membership query 10 million बार, दो modes में चलाई गई
- cold mode: हर query अलग array में search करती है, जिससे cache miss simulate होता है
- warm mode: queries को array के हिसाब से group किया जाता है और उसी array को लगातार 100 बार search किया जाता है, जिससे cache hit simulate होता है
- measurement target average query time था, और comparison algorithms थे linear search (
std::find), binary search (std::binary_search), और SIMD Quad
- measurement systems थे Apple M4 के साथ Apple LLVM, और Intel Emerald Rapids processor के साथ GCC
measurement results
- linear search और binary search की तुलना में, array बड़ा होने पर binary search, linear search से बेहतर निकला
- cold cache में अधिक data access के कारण cache failures बढ़ते हैं, इसलिए linear search तुलनात्मक रूप से और कमज़ोर हो जाता है
- binary search के linear search पर कुल बढ़त दिखने के बाद, इसकी तुलना SIMD Quad से की गई
- Intel और Apple platforms पर परिणाम साफ़ तौर पर अलग थे
- Intel platform पर warm cache में SIMD Quad, binary search से 2x से अधिक तेज़ था
- Intel platform के cold cache में लाभ कम था
- Apple platform पर इसके उलट cold cache में SIMD Quad, 2x से अधिक तेज़ था, जबकि warm cache में लाभ अपेक्षाकृत सीमित था
- हर मामले में SIMD Quad, binary search से तेज़ था
- SIMD वाला हिस्सा special instructions से काम घटाता है, और instructions तथा branches दोनों कम होने से speedup को समझना आसान होता है
4-way search का प्रभाव
- SIMD optimization को बनाए रखते हुए, 4-way interpolation search को standard binary search से बदलने वाला SIMD binary version भी compare किया गया
- Apple platform पर 4-way approach का असर छोटा था
- Intel platform पर बड़े arrays के cold cache scenario में 4-way approach meaningful optimization साबित हुआ
- Intel server पर 4-way search ने memory-level parallelism का बेहतर उपयोग किया
implementation की मुख्य बातें
simd_quad function uint16_t array, element count cardinality, और खोजी जाने वाली value pos लेकर boolean लौटाता है
gap को 16 पर fixed रखा गया है; अगर cardinality < gap हो, तो simple loop से value खोजी जाती है
- block search loop में
n > 3 रहने तक 1/4, 2/4, 3/4 points पर block के आख़िरी values पढ़े जाते हैं, pos से तुलना की जाती है, और तीन comparison results के योग से base को आगे बढ़ाया जाता है
- इसके बाद
n > 1 रहने तक half-based comparison करके बाकी range घटाई जाती है, और आख़िर में lo block चुना जाता है
- चुने गए block में ARM NEON के
vceqq_u16 या x64 SSE2 के _mm_cmpeq_epi16 से 16 elements को दो batches में compare किया जाता है
- बचे हुए elements वाले हिस्से में
v >= pos होने वाली जगह पर v == pos लौटाया जाता है, और अंत तक न मिलने पर false लौटाया जाता है
निष्कर्ष और सामग्री
- पाठ्यपुस्तक वाला binary search ठीक-ठाक algorithm है, लेकिन वास्तविक performance में मायने रखने वाले तरीक़े से इसे और तेज़ बनाया जा सकता है
- standard algorithms अक्सर आज के computers की उच्च parallelism को ध्यान में रखकर डिज़ाइन नहीं किए गए थे
- SIMD Quad, memory-level parallelism और data parallelism दोनों का उपयोग करने की कोशिश करने वाला approach है
- इससे भी बेहतर algorithms संभव हो सकते हैं, और अधिक रचनात्मक approaches की ज़रूरत है
- source code
- Faster intersections between sorted arrays with shotgun
अभी कोई टिप्पणी नहीं है.