अतुल्यकालिक सेलुलर ऑटोमेटा के लिए समानांतर (GPU) एल्गोरिदम


12

मेरे पास कम्प्यूटेशनल मॉडल का एक संग्रह है जिसे अतुल्यकालिक सेलुलर ऑटोमेटा के रूप में वर्णित किया जा सकता है। ये मॉडल ईज़िंग मॉडल से मिलते जुलते हैं, लेकिन थोड़े अधिक जटिल हैं। ऐसा लगता है जैसे सीपीयू के बजाय ऐसे मॉडल को GPU पर चलाने से लाभ होगा। दुर्भाग्य से यह इस तरह के मॉडल को समानांतर करने के लिए बिल्कुल सीधा नहीं है, और यह मेरे लिए बिल्कुल स्पष्ट नहीं है कि इसके बारे में कैसे जाना जाए। मुझे पता है कि इस विषय पर साहित्य है, लेकिन यह सब कट्टर कंप्यूटर वैज्ञानिकों के उद्देश्य से प्रतीत होता है, जो एल्गोरिदमिक जटिलता के विवरणों में रुचि रखते हैं, मेरे बजाय किसी ऐसे व्यक्ति के लिए जो सिर्फ एक चीज का विवरण चाहता है जिसे मैं लागू कर सकता हूं, और नतीजतन मैं इसे बल्कि inpenetrable लगता है।

स्पष्टता के लिए, मैं एक इष्टतम एल्गोरिथ्म की तलाश नहीं कर रहा हूं, क्योंकि CUDA में कुछ मैं तेजी से लागू कर सकता हूं जो कि मेरे सीपीयू कार्यान्वयन पर एक महत्वपूर्ण गति देने की संभावना है। इस परियोजना में कंप्यूटर समय की तुलना में प्रोग्रामर का समय बहुत सीमित है।

मुझे यह भी स्पष्ट करना चाहिए कि एक अतुल्यकालिक सेलुलर ऑटोमोबोन एक सिंक्रोनस से एक अलग चीज है, और सिंक्रोनस सिंक्रोनस सीए (जैसे कि कॉनवे के जीवन) को आसानी से इस समस्या के लिए अनुकूलित नहीं किया जा सकता है। अंतर यह है कि एक सिंक्रोनस सीए हर सेल को हर समय कदम पर एक साथ अपडेट करता है, जबकि एक एसिंक्रोनस एक यादृच्छिक रूप से चुने गए स्थानीय क्षेत्र को हर बार कदम के रूप में नीचे उल्लिखित अपडेट करता है।

जिन मॉडलों को मैं समांतर करना चाहता हूं, वे एक जाली (आमतौर पर एक हेक्सागोनल एक) पर लागू होते हैं, जिसमें ~ 100000 कोशिकाएं होती हैं (हालांकि मैं अधिक उपयोग करना चाहता हूं), और उन्हें चलाने के लिए गैर-समानांतर एल्गोरिदम इस तरह दिखता है:

  1. यादृच्छिक पर कोशिकाओं की एक पड़ोसी जोड़ी चुनें

  2. इन कोशिकाओं के आसपास के एक स्थानीय पड़ोस पर आधारित "ऊर्जा" फ़ंक्शन गणना करेंΔ

  3. प्रायिकता के साथ, जो पर निर्भर करता है (with एक पैरामीटर), या तो दो कोशिकाओं के राज्यों को स्वैप करें या कुछ भी न करें। बीटा-βΔβ

  4. उपरोक्त चरणों को अनिश्चित काल तक दोहराएं।

सीमा की स्थितियों के साथ करने के लिए कुछ जटिलताएं भी हैं, लेकिन मुझे लगता है कि ये समानांतरकरण के लिए बहुत मुश्किल नहीं हैं।

यह ध्यान देने योग्य है कि मैं इन प्रणालियों के क्षणिक गतिकी में दिलचस्पी रखता हूं, न कि केवल संतुलन की स्थिति में, इसलिए मुझे कुछ ऐसी चीज की जरूरत है, जो उपरोक्त समतुल्य गतिकी के बजाय, केवल कुछ ही समान वितरण के लिए दृष्टिकोण करेगी। (चेकरबोर्ड एल्गोरिथ्म की विविधताएं वह नहीं हैं जो मैं खोज रहा हूं।)

उपरोक्त एल्गोरिथ्म को समानांतर करने में मुख्य कठिनाई टकराव है। क्योंकि सभी गणना केवल जाली के एक स्थानीय क्षेत्र पर निर्भर करती हैं, इसलिए कई जाली साइटों को समानांतर में अपडेट किया जाना संभव है, जब तक कि उनके पड़ोस अतिव्यापी नहीं हों। सवाल यह है कि इस तरह के ओवरलैप से कैसे बचा जाए। मैं कई तरीकों के बारे में सोच सकता हूं, लेकिन मुझे नहीं पता कि यदि कोई लागू करने के लिए सबसे अच्छा है। ये इस प्रकार हैं:

  • यादृच्छिक ग्रिड साइटों की सूची बनाने और टकरावों की जांच करने के लिए सीपीयू का उपयोग करें। जब ग्रिड साइटों की संख्या GPU प्रोसेसर की संख्या के बराबर होती है, या यदि टक्कर का पता लगाया जाता है, तो संबंधित ग्रिड साइट को अपडेट करने के लिए निर्देशांक के प्रत्येक सेट को GPU इकाई में भेजें। यह लागू करना आसान होगा, लेकिन शायद यह बहुत गति नहीं देगा, क्योंकि सीपीयू पर टकराव की जाँच करने पर सीपीयू पर संपूर्ण अपडेट करने की तुलना में यह सब सस्ता नहीं होगा।

  • जाली को क्षेत्रों में विभाजित करें (एक GPU इकाई), और एक GPU इकाई है जो अपने क्षेत्र के भीतर बेतरतीब ढंग से ग्रिड कोशिकाओं का चयन और अद्यतन करने के लिए जिम्मेदार है। लेकिन इस विचार के साथ कई मुद्दे हैं जिन्हें मैं नहीं जानता कि कैसे हल करना है, सबसे स्पष्ट है कि वास्तव में क्या होना चाहिए जब एक इकाई अपने क्षेत्र के किनारे को ओवरलैप करते हुए पड़ोस चुनती है।

  • सिस्टम को निम्नानुसार समझें: असतत चरणों में समय दें। जाली को एक अलग में विभाजित करेंपूर्व निर्धारित योजना के अनुसार हर समय कदम पर क्षेत्रों का सेट, और प्रत्येक GPU इकाई को बेतरतीब ढंग से ग्रिड कोशिकाओं की एक जोड़ी का चयन करें और अपडेट करें, जिनके पड़ोस क्षेत्र की सीमा को ओवरलैप नहीं करते हैं। चूंकि सीमाएं हर बार बदलती हैं, इसलिए यह बाधा बहुत अधिक गतिशीलता को प्रभावित नहीं कर सकती है, जब तक कि क्षेत्र अपेक्षाकृत बड़े हैं। यह लागू करना आसान है और तेजी से होने की संभावना है, लेकिन मुझे नहीं पता कि यह गतिशीलता को कितनी अच्छी तरह अनुमानित करेगा, या प्रत्येक समय कदम पर क्षेत्र की सीमाओं को चुनने के लिए सबसे अच्छी योजना क्या है। मुझे "ब्लॉक-सिंक्रोनस सेलुलर ऑटोमेटा" के कुछ संदर्भ मिले, जो इस विचार के समान हो भी सकता है और नहीं भी। (मुझे नहीं पता क्योंकि ऐसा लगता है कि विधि के सभी विवरण या तो रूसी में हैं या उन स्रोतों में हैं जिनमें मेरी पहुंच नहीं है।)

मेरे विशिष्ट प्रश्न इस प्रकार हैं:

  • उपरोक्त एल्गोरिदम में से कोई भी एक अतुल्यकालिक सीए मॉडल के जीपीयू समांतरता तक पहुंचने का एक समझदार तरीका है?

  • क्या कोई बेहतर तरीका है?

  • क्या इस प्रकार की समस्या के लिए मौजूदा लाइब्रेरी कोड है?

  • मुझे "ब्लॉक-सिंक्रोनस" विधि का स्पष्ट अंग्रेजी-भाषा विवरण कहां मिल सकता है?

प्रगति

मेरा मानना ​​है कि मैं एक अतुल्यकालिक सीए को समानांतर बनाने का एक तरीका लेकर आया हूं जो उपयुक्त हो सकता है। नीचे उल्लिखित एल्गोरिथ्म एक सामान्य एसिंक्रोनस सीए के लिए है जो एक बार में केवल एक सेल को अपडेट करता है, बजाय पड़ोसी जोड़ी के कोशिकाओं के रूप में मेरा करता है। मेरे विशिष्ट मामले में इसे सामान्य करने के साथ कुछ मुद्दे हैं, लेकिन मुझे लगता है कि मेरे पास एक विचार है कि उन्हें कैसे हल किया जाए। हालांकि, मुझे यकीन नहीं है कि नीचे दिए गए कारणों के लिए यह कितना गति लाभ देगा।

यह विचार एक अतुल्यकालिक CA (soforth ACA) को स्टोकेस्टिक सिंक्रोनस CA (SCA) से बदलने का है जो समान व्यवहार करता है। ऐसा करने के लिए हम पहले कल्पना करते हैं कि एसीए एक पॉइसन प्रक्रिया है। यही है, समय लगातार आगे बढ़ता है, और प्रत्येक सेल अपने अद्यतन कार्य को करने के प्रति यूनिट समय की निरंतर संभावना के रूप में, अन्य कोशिकाओं के स्वतंत्र रूप से करता है।

हम एक SCA का निर्माण करते हैं, जिसकी कोशिकाएँ दो चीजों को संग्रहीत करती हैं: कोशिका का राज्य (यानी क्रमिक कार्यान्वयन में प्रत्येक कोशिका में संग्रहीत डेटा), और एक अस्थायी बिंदु संख्या प्रतिनिधित्व करना (निरंतर) ) वह समय जिस पर वह अगली बार अद्यतन करेगा। यह निरंतर समय SCA के अद्यतन चरणों के अनुरूप नहीं है। मैं उत्तरार्द्ध को "तार्किक समय" के रूप में संदर्भित करूंगा। समय मानों को एक घातांक वितरण के अनुसार यादृच्छिक रूप से प्रारंभ किया जाता है: । (जहां " एक पैरामीटर है जिसका मान मनमाने ढंग से चुना जा सकता है।) टी मैं जे टी मैं j ( 0 ) ~ ऍक्स्प ( λ ) λएक्समैंजेटीमैंजेटीमैंजे(0)~ऍक्स्प(λ)λ

प्रत्येक तार्किक समय कदम पर, SCA की कोशिकाओं को निम्नानुसार अद्यतन किया जाता है:

  • यदि, किसी भी , के समय के पड़ोस में , कुछ भी नहीं करें।i , j t k l < t i j,एलमैं,जेटीएल<टीमैंजे

  • अन्यथा, (1) राज्य को पड़ोसी एसीए के समान नियम का उपयोग करते हुए, पड़ोसी कोशिकाओं के राज्यों के अनुसार अपडेट करें ; और (2) एक यादृच्छिक मान और को अपडेट । एक्स कश्मीर एल Δ टी ~ ऍक्स्प ( λ ) टी मैं जे टी मैं j + Δ टीएक्समैंजेएक्सएलΔटी~ऍक्स्प(λ)टीमैंजेटीमैंजे+Δटी

मेरा मानना ​​है कि यह सुनिश्चित करता है कि कोशिकाओं को एक क्रम में अद्यतन किया जाएगा जो मूल एसीए के अनुरूप होने के लिए "डीकोड" कर सकते हैं, जबकि टकराव से बचने और कुछ कोशिकाओं को समानांतर में अपडेट करने की अनुमति देते हैं। हालाँकि, ऊपर दिए गए पहले बुलेट पॉइंट के कारण, इसका मतलब है कि SCA के प्रत्येक समय के कदम पर ज्यादातर GPU प्रोसेसर ज्यादातर निष्क्रिय होंगे, जो आदर्श से कम है।

मुझे कुछ और विचार देने की आवश्यकता है कि क्या इस एल्गोरिथ्म के प्रदर्शन में सुधार किया जा सकता है, और एसीए में एक साथ कई कोशिकाओं को अपडेट किए जाने के मामले से निपटने के लिए इस एल्गोरिथ्म का विस्तार कैसे किया जाए। हालाँकि, यह आशाजनक लग रहा है इसलिए मैंने सोचा कि मैं इसका वर्णन यहाँ करूँगा जब कोई भी (ए) साहित्य में कुछ भी समान जानता है, या (बी) इन शेष मुद्दों पर कोई जानकारी दे सकता है।


शायद आप अपनी समस्या को स्टैंसिल-आधारित दृष्टिकोण में बना सकते हैं। स्टैंसिल-आधारित समस्याओं के लिए बहुत सारे सॉफ़्टवेयर मौजूद हैं। आपकी नजर इस पर पड़ सकती है: libgeodecomp.org/gallery.html , कॉनवे का गेम ऑफ लाइफ। इसमें कुछ समानताएँ हो सकती हैं।
vanCompute

@vanCompute जो एक शानदार उपकरण की तरह दिखता है, लेकिन मेरी प्रारंभिक (बल्कि सरसरी) जांच से, ऐसा लगता है कि स्टैंसिल कोड प्रतिमान स्वाभाविक रूप से तुल्यकालिक है, इसलिए यह संभवत: अच्छी तरह से अनुकूल नहीं है कि मैं क्या करने की कोशिश कर रहा हूं। मैं इसे आगे देखूंगा, हालांकि।
नथानिएल

क्या आप इस बारे में कुछ और विवरण प्रदान कर सकते हैं कि आप SIMT का उपयोग करके इसे कैसे समानांतर करेंगे? क्या आप प्रति जोड़ी एक धागा का उपयोग करेंगे? या एकल जोड़ी को अपडेट करने से जुड़े काम को 32 या अधिक थ्रेड में फैलाया जा सकता है?
पेड्रो

@ पेड्रो एक एकल जोड़ी को अपडेट करने में शामिल काम काफी छोटा है (मूल रूप से बस पड़ोस में समेटना, प्लस एक यादृच्छिक संख्या जनरेटर का एक पुनरावृत्ति और एक exp()) तो मैंने सोचा नहीं होगा कि यह कई थ्रेड्स पर फैलाने के लिए बहुत समझ में आता है। मुझे लगता है कि यह बेहतर है (और मेरे लिए आसान है) कोशिश करें और समानांतर में कई जोड़े को अद्यतन करने के लिए, एक जोड़ी प्रति धागे के साथ।
नथानिएल

ठीक है, और आप जोड़ी अपडेट के बीच एक ओवरलैप को कैसे परिभाषित करते हैं? यदि जोड़े खुद को ओवरलैप करते हैं, या यदि उनके पड़ोस ओवरलैप करते हैं?
पेड्रो

जवाबों:


4

मैं पहले विकल्प का उपयोग करता हूं और पहले (GPU का उपयोग करके) एक तुल्यकालिक एसी रन का उपयोग करेगा, टकरावों का पता लगाने के लिए, एक हेक्सागोनल एसी के एक चरण को निष्पादित करेगा जिसका नियम केंद्र सेल का मूल्य = सम (पड़ोसी) है, इस CA के पास होना चाहिए सात राज्यों को बेतरतीब ढंग से चयनित सेल के साथ शुरू किया जाना चाहिए, और प्रत्येक जीपीयू के लिए अद्यतन नियम चलाने से पहले उनकी स्थिति सत्यापित की जानी चाहिए।

नमूना 1. एक पड़ोसी सेल का मूल्य साझा किया जाता है

0 0 0 0 0 0 0 0

  ० ० ० ० ०

0 0 0 0 0 0 0 0

  ० ० ० ० ०

0 0 0 0 0 0 0 0

सीए का एक कदम जिसका नियम हेक्सागोनल केंद्रीय सेल = सम (पड़ोसी) है

0 0 1 1 0 0 0

  0 1 1 1 0 0

० ० १ २ १ १ ० ०

  ० ० १ १ १ ०

0 0 0 1 1 1 0 0

नमूना 2. अद्यतन करने के लिए एक सेल का मूल्य दूसरे पर पड़ोसी के रूप में ध्यान में रखा जाता है

0 0 0 0 0 0 0 0

  ० ० ० ० ०

0 0 0 1 0 0 0 0

  0 0 0 0 0 0 0

0 0 0 0 0 0 0 0

पुनरावृति के बाद

0 0 1 1 0 0 0

  0 1 2 2 0 0

० ० २ १ १ ० ०

  ० ० १ १ ० ०

0 0 0 0 0 0 0 0

नमूना 3. जिसका कोई संबंध न हो

  0 0 0 0 0 0 0

0 0 1 0 0 0 0 0

  0 0 0 0 0 0 0

0 0 0 0 0 0 0 0

  ० ० ० ० ०

0 0 0 0 0 0 0 0

पुनरावृति के बाद

  0 1 1 0 0 0

0 1 1 1 0 0 0

  0 1 1 0 0 0

0 0 0 1 1 1 0 0

  ० ० १ १ १ ०

0 0 0 1 1 1 0 0


हे(n)n

मुझे लगता है कि बहुत कुछ है जो समानांतर किया जा सकता है। Collision प्रोसेसिंग पूरी तरह से GPU पर प्रभाव डालती है एक तुल्यकालिक एसी में एक कदम है जैसा कि ऊपर दिए गए लिंक में दिखाया गया है। सत्यापन के लिए यदि कोई स्थानीय नियम का उपयोग करेगा, तो Sum (पड़ोसी) = 8 NO टकराव, Sum (पड़ोसी)> 8 टकराव, यह आपके नियम नियम बदलने से पहले सत्यापित किया जाएगा यदि कोई टकराव सेल राज्य नहीं है, क्योंकि दोनों को पास रखा जाना चाहिए यदि वे पास नहीं हैं तो मूल्यांकन किए जाने वाले बिंदु अन्य कोशिकाओं के हैं।
jlopez1967 15

मैं समझता हूं कि, लेकिन समस्या यह है कि जब आप टकराव का पता लगाते हैं तो आप क्या करते हैं? जैसा कि मैंने ऊपर बताया, टकराव का पता लगाने में आपका CA एल्गोरिदम केवल पहला कदम है। दूसरा चरण एक राज्य> = 2 के साथ कोशिकाओं के लिए ग्रिड की खोज करना है, और यह तुच्छ नहीं है।
नथानिएल

उदाहरण के लिए, कल्पना करें कि हम सेल्यूलर ऑटोमेटा और निष्पादित राशि (सेल के पड़ोसी (5,7)) पर टक्कर सेल (5.7) का पता लगाना चाहते हैं और यदि मान 8 है और यदि कोई टक्कर नहीं है तो 8 से अधिक कोई टक्कर नहीं है फ़ंक्शन में होना चाहिए जो एसिंक्रोनस सेलुलर ऑटोमेटा में सेल की अगली स्थिति को परिभाषित करने के लिए प्रत्येक सेल का मूल्यांकन करता है। प्रत्येक कोशिका के लिए टकराव का पता लगाना एक स्थानीय नियम है जिसमें केवल इसकी पड़ोसी कोशिकाएँ शामिल हैं
jlopez1967

हां, लेकिन एक अतुल्यकालिक सीए को समानांतर बनाने के लिए हमें जिस प्रश्न का उत्तर देने में सक्षम होना चाहिए, वह है "सेल (5,7) में टक्कर नहीं थी" लेकिन "ग्रिड पर कहीं टकराव था, और यदि ऐसा था तो यह? " ग्रिड पर पुनरावृत्ति किए बिना इसका उत्तर नहीं दिया जा सकता है।
नथानियल

1

उपरोक्त टिप्पणियों में मेरे सवालों के आपके जवाब के बाद, मैं आपको सुझाव दूंगा कि आप लॉक-आधारित दृष्टिकोण की कोशिश करें, जिसमें प्रत्येक थ्रेड पड़ोस को लॉक-डाउन करने की कोशिश करता है जो वास्तविक अपडेट की गणना करने से पहले इसे अपडेट करेगा।

आप इसे CUDA के लिए प्रदान किए गए परमाणु संचालन और intप्रत्येक सेल के लिए ताले रखने की एक सरणी का उपयोग करके कर सकते हैं , जैसे lock। प्रत्येक धागा तब निम्न कार्य करता है:

ci, cj = choose a pair at random.

int locked = 0;

/* Try to lock the cell ci. */
if ( atomicCAS( &lock[ci] , 0 , 1 ) == 0 ) {

    /* Try to lock the cell cj. */
    if ( atomicCAS( &lock[cj] , 0 , 1 ) == 0 ) {

        /* Now try to lock all the neigbourhood cells. */
        for ( cn = indices of all neighbours )
            if ( atomicCAS( &lock[cn] , 0 , 1 ) != 0 )
                break;

        /* If we hit a break above, we have to unroll all the locks. */
        if ( cn < number of neighbours ) {
            lock[ci] = 0;
            lock[cj] = 0;
            for ( int i = 0 ; i < cn ; i++ )
                lock[i] = 0;
            }

        /* Otherwise, we've successfully locked-down the neighbourhood. */
        else
            locked = 1;

        }

    /* Otherwise, back off. */
    else
        lock[ci] = 0;
    }

/* If we got everything locked-down... */
if ( locked ) {

    do whatever needs to be done...

    /* Release all the locks. */
    lock[ci] = 0;
    lock[cj] = 0;
    for ( int i = 0 ; i < cn ; i++ )
        lock[i] = 0;

    }

ध्यान दें कि यह दृष्टिकोण संभवतः सबसे इष्टतम नहीं है, लेकिन यह एक दिलचस्प शुरुआती बिंदु प्रदान कर सकता है। यदि थ्रेड्स के बीच बहुत सारे टकराव होते हैं, यानी एक या एक से अधिक 32 थ्रेड्स (जैसा कि प्रति ताना-बाना एक टकराव में), तो ब्रांच डायवर्जन का एक अच्छा सा हिस्सा होगा। इसके अलावा, परमाणु संचालन थोड़ा धीमा हो सकता है, लेकिन चूंकि आप केवल तुलना-और-स्वैप ऑपरेशन कर रहे हैं, यह ठीक होना चाहिए।

लॉकिंग ओवरहेड भयभीत लग सकता है, लेकिन यह वास्तव में केवल कुछ असाइनमेंट और शाखाएं हैं, बहुत अधिक नहीं।

यह भी ध्यान दें कि मैं iपड़ोसियों के ऊपर की छोरों में संकेतन के साथ तेज और ढीला हो रहा हूं ।

परिशिष्ट: मैं यह अनुमान लगाने के लिए पर्याप्त था कि आप जब जोड़े टकरा सकते हैं तो बस वापस आ सकते हैं। यदि यह मामला नहीं है, तो आप एक whileलूप में दूसरी पंक्ति के रूप में सब कुछ लपेट सकते हैं और breakअंतिम- ifस्थापन के अंत में जोड़ सकते हैं ।

सभी थ्रेड्स को तब तक इंतजार करना होगा जब तक कि अंतिम एक नहीं किया जाता है, लेकिन यदि टकराव दुर्लभ हैं, तो आपको इसके साथ दूर जाने में सक्षम होना चाहिए।

परिशिष्ट 2: क्या नहीं करने के लिए कॉल को जोड़ने के लिए परीक्षा जा __syncthreads()इस कोड में कहीं, विशेष रूप से यह पाशन संस्करण पिछले परिशिष्ट में वर्णित! उत्तरार्द्ध मामले में बार-बार टकराव से बचने के लिए अतुल्यकालिकता आवश्यक है।


धन्यवाद, यह बहुत अच्छा लग रहा है। संभवतः मैं जिस जटिल विचार पर विचार कर रहा था, उससे बेहतर और लागू करने में बहुत आसान। मैं एक बड़े पर्याप्त ग्रिड का उपयोग करके टकराव को दुर्लभ बना सकता हूं, जो शायद ठीक है। यदि जस्ट-बैक-ऑफ विधि काफी तेज हो जाती है, तो मैं इसे अनौपचारिक रूप से मापदंडों की जांच के लिए उपयोग कर सकता हूं, और जब मुझे आधिकारिक परिणाम उत्पन्न करने की आवश्यकता होती है, तब तक सभी के लिए प्रतीक्षा-विधि के लिए स्विच करें। मैं इसे जल्द ही कुछ समय देने की कोशिश करूंगा।
नथानिएल

1

मैं LibGeoDecomp का प्रमुख डेवलपर हूं। जबकि मैं vanCompute से सहमत हूं कि आप अपने ACA को CA के साथ अनुकरण कर सकते हैं, आप सही कह रहे हैं कि यह बहुत कुशल नहीं होगा, क्योंकि किसी भी चरण में केवल कुछ सेल अपडेट होने के लिए होते हैं। यह वास्तव में एक बहुत ही दिलचस्प अनुप्रयोग है - और टिंकर के साथ मज़ा!

मैं आपको jlopez1967 और पेड्रो द्वारा प्रस्तावित समाधानों को संयोजित करने का सुझाव दूंगा: पेड्रो का एल्गोरिथ्म समानांतरवाद को अच्छी तरह से पकड़ता है, लेकिन वे परमाणु ताले बहुत धीमी गति से हैं। Jlopez1967 का समाधान सुरुचिपूर्ण है जब टकरावों का पता लगाने की बात आती है, लेकिन सभी nकोशिकाओं की जांच करते हैं, जब केवल एक छोटा सा उपसमूह (मैं अब से मानता हूं कि कुछ पैरामीटर है kजो कोशिकाओं की संख्या को एक साथ अद्यतन करने के लिए दर्शाता है) सक्रिय हैं। स्पष्ट रूप से निषेधात्मक है।

__global__ void markPoints(Cell *grid, int gridWidth, int *posX, int *posY)
{
    int id = blockIdx.x * blockDim.x + threadIdx.x;
    int x, y;
    generateRandomCoord(&x, &y);
    posX[id] = x;
    posY[id] = y;
    grid[y * gridWidth + x].flag = 1;
}

__global__ void checkPoints(Cell *grid, int gridWidth, int *posX, int *posY, bool *active)
{
    int id = blockIdx.x * blockDim.x + threadIdx.x;
    int x = posX[id];
    int y = posY[id];
    int markedNeighbors = 
        grid[(y - 1) * gridWidth + x + 0].flag +
        grid[(y - 1) * gridWidth + x + 1].flag +
        grid[(y + 0) * gridWidth + x - 1].flag +
        grid[(y + 0) * gridWidth + x + 1].flag +
        grid[(y + 1) * gridWidth + x + 0].flag +
        grid[(y + 1) * gridWidth + x + 1].flag;
    active[id] = (markedNeighbors > 0);
}


__global__ void update(Cell *grid, int gridWidth, int *posX, int *posY, bool *active)
{
    int id = blockIdx.x * blockDim.x + threadIdx.x;
    int x = posX[id];
    int y = posY[id];
    grid[y * gridWidth + x].flag = 0;
    if (active[id]) {
        // do your fancy stuff here
    }
}

int main() 
{
  // alloc grid here, update up to k cells simultaneously
  int n = 1024 * 1024;
  int k = 1234;
  for (;;) {
      markPoints<<<gridDim,blockDim>>>(grid, gridWidth, posX, posY);
      checkPoints<<<gridDim,blockDim>>>(grid, gridWidth, posX, posY, active);
      update<<<gridDim,blockDim>>>(grid, gridWidth, posX, posY, active);
  }
}

GPU पर अच्छे वैश्विक सिंक्रनाइज़ेशन की अनुपस्थिति में, आपको विभिन्न चरणों के लिए कई गुठली लगाने की आवश्यकता है। एनवीडिया के केपलर पर आप मुख्य लूप को भी जीपीयू में स्थानांतरित कर सकते हैं, लेकिन मुझे उम्मीद नहीं है कि इससे बहुत लाभ होगा।

एल्गोरिदम समानता के विन्यास (विन्यास) की डिग्री प्राप्त करता है। मुझे लगता है, दिलचस्प सवाल यह है कि जब आप बढ़ते हैं तो टकराव आपके यादृच्छिक वितरण को प्रभावित करेगा k


0

मैं आपको सुझाव देता हूं कि आप इस लिंक को देखें http://www.wolfram.com/training/courses/hpc021.html लगभग 14:15 मिनट के वीडियो में, गणित का प्रशिक्षण जहां वे CUDA का उपयोग करके सेलुलर ऑटोमेटा का कार्यान्वयन करते हैं। , वहां से और आप इसे संशोधित कर सकते हैं।


दुर्भाग्य से यह एक सिंक्रोनस सीए है, जो कि मैं जिस एसिंक्रोनस के साथ काम कर रहा हूं, उससे अलग किस्म का जानवर है। एक सिंक्रोनस CA में, प्रत्येक सेल को एक साथ अपडेट किया जाता है, और यह GPU पर समानांतर करना आसान है, लेकिन एक एसिंक्रोनस CA में एक एकल बेतरतीब ढंग से चुनी गई सेल को हर बार स्टेप में अपडेट किया जाता है (वास्तव में मेरे मामले में यह दो पड़ोसी सेल हैं), और यह बनाता है समांतरता बहुत कठिन है। मेरे प्रश्न में उल्लिखित समस्याएं एक अतुल्यकालिक अद्यतन फ़ंक्शन की आवश्यकता के लिए विशिष्ट हैं।
नथानिएल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.