एक mpi_allgather ऑपरेशन की कम्प्यूटेशनल लागत एक इकट्ठा / तितर बितर ऑपरेशन के साथ तुलना कैसे करती है?


11

मैं एक ऐसी समस्या पर काम कर रहा हूं जिसे एक एकल mpi_allgather ऑपरेशन या एक mpi_scatter और एक mpi_gather ऑपरेशन का उपयोग करके समानांतर किया जा सकता है। इन ऑपरेशनों को थोड़ी देर के भीतर कहा जाता है, इसलिए उन्हें कई बार कहा जा सकता है।

MPI_allgather योजना के कार्यान्वयन में, मैं डुप्लिकेट मैट्रिक्स समाधान के लिए सभी प्रक्रियाओं पर एक वितरित वेक्टर इकट्ठा कर रहा हूं। अन्य कार्यान्वयन में, मैं वितरित वेक्टर को एक प्रोसेसर (रूट नोड) पर इकट्ठा करता हूं, इस प्रोसेसर पर रैखिक प्रणाली को हल करता हूं, और फिर सभी प्रक्रियाओं पर समाधान वेक्टर को वापस बिखेरता हूं।

मुझे यह जानने की उत्सुकता है कि क्या ऑलगेदर ऑपरेशन की लागत बिखराव से अधिक है और संयुक्त ऑपरेशन को इकट्ठा करना है। क्या संदेश की लंबाई इसकी जटिलता में महत्वपूर्ण भूमिका निभाती है? क्या यह एमपीआई के कार्यान्वयन के बीच भिन्न है?

संपादित करें:


कृपया संचार की संरचना और शामिल आकारों का वर्णन करें। एक के MPI_Scatterबाद एक MPI_Gatherही संचार अर्थ प्रदान नहीं करता है MPI_Allgather। जब आप ऑपरेशन को किसी भी तरह से व्यक्त करते हैं तो शायद अतिरेक शामिल होता है?
जेड ब्राउन

पॉल, जेड सही है, क्या आपका मतलब है एक MPI_Gatherद्वारा पीछा किया MPI_Bcast?
एरन अहमदिया

@JedBrown: मैंने थोड़ी और जानकारी जोड़ी।
पॉल

@AronAhmadia: मुझे नहीं लगता कि मुझे MPI_Bcast का उपयोग करना चाहिए क्योंकि मैं वेक्टर के एक हिस्से को भेज रहा हूं, प्रत्येक प्रक्रिया को, संपूर्ण वेक्टर नहीं। मेरा तर्क यह है कि एक छोटा संदेश एक बड़े संदेश की तुलना में सामान्य रूप से भेजने के लिए तेज़ होगा। इसका कोई मतलब भी है क्या?
पॉल

क्या मैट्रिक्स पहले से ही अनावश्यक रूप से वितरित किया गया है? क्या यह पहले से ही तथ्यहीन है? क्या कई प्रक्रियाएं समान कैश और मेमोरी बस साझा करती हैं? (यह निरर्थक प्रणालियों को हल करने की गति को प्रभावित करेगा।) सिस्टम कितने बड़े / महंगे हैं? क्यों हल करें धारावाहिक?
जैड ब्राउन

जवाबों:


9

सबसे पहले, सटीक उत्तर इस पर निर्भर करता है: (1) उपयोग, अर्थात फ़ंक्शन इनपुट तर्क, (2) MPI कार्यान्वयन गुणवत्ता और विवरण, और (3) आपके द्वारा उपयोग किए जा रहे हार्डवेयर। अक्सर, (2) और (3) संबंधित होते हैं, जैसे कि जब हार्डवेयर विक्रेता अपने नेटवर्क के लिए MPI का अनुकूलन करता है।

सामान्य तौर पर, छोटे संदेशों के लिए फ़्यूज़िंग एमपीआई कलेक्टिव बेहतर होता है, क्योंकि स्टार्ट-अप की लागतें नैटिव हो सकती हैं और कॉल्स को ब्लॉक करने के लिए कंप्यूर टाइम में भिन्नता होने पर कलेक्टिव्स को ब्लॉक करके सिंक्रोनाइजेशन को कम से कम किया जाना चाहिए। बड़े संदेशों के लिए, लक्ष्य यह होना चाहिए कि भेजे जाने वाले डेटा की मात्रा कम से कम हो।

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

दूसरी तरफ, यदि कोई ब्लू जीन पर है, तो ऐसा MPI_Reduce_scatter_blockकरना MPI_Allreduce, जो कि अधिक संचार करता है MPI_Reduceऔर MPI_Scatterसंयुक्त है, वास्तव में काफी तेज है। यह कुछ ऐसा है जिसे मैंने हाल ही में खोजा है और एमपीआई में प्रदर्शन आत्म-स्थिरता के सिद्धांत का एक दिलचस्प उल्लंघन है (यह सिद्धांत "स्व-सुसंगत एमपीआई प्रदर्शन दिशानिर्देश" में अधिक विस्तार से वर्णित है )।

तितर बितर + इकट्ठा करने के विशिष्ट मामले में, विचार करें कि पूर्व में, सभी डेटा को एक प्रक्रिया से और उसके पास जाना चाहिए, जो इसे अड़चन बनाता है, जबकि allgather में, डेटा सभी रैंकों में और बाहर प्रवाह कर सकते हैं , क्योंकि सभी रैंकों के पास सभी अन्य रैंकों को भेजने के लिए कुछ डेटा है। हालांकि, सभी नोड्स से एक बार में डेटा भेजना जरूरी नहीं है कि कुछ नेटवर्क पर एक अच्छा विचार है।

अंत में, इस प्रश्न का उत्तर देने का सबसे अच्छा तरीका यह है कि अपने कोड में निम्नलिखित करें और प्रयोग द्वारा प्रश्न का उत्तर दें।

#ifdef TWO_MPI_CALLS_ARE_BETTER_THAN_ONE
  MPI_Scatter(..)
  MPI_Gather(..)
#else
  MPI_Allgather(..)
#endif

एक बेहतर विकल्प यह है कि अपने कोड को पहले दो पुनरावृत्तियों के दौरान प्रयोगात्मक रूप से मापें, फिर शेष पुनरावृत्तियों के लिए जो भी तेज़ हो उसका उपयोग करें:

const int use_allgather = 1;
const int use_scatter_then_gather = 2;

int algorithm = 0;
double t0 = 0.0, t1 = 0.0, dt1 = 0.0, dt2 = 0.0;

while (..)
{
    if ( (iteration==0 && algorithm==0) || algorithm==use_scatter_then_gather )
    {
        t0 = MPI_Wtime();
        MPI_Scatter(..);
        MPI_Gather(..);
        t1 = MPI_Wtime();
        dt1 = t1-t0;
    } 
    else if ( (iteration==1 && algorithm==0) || algorithm==use_allgather)
    {
        t0 = MPI_Wtime();
        MPI_Allgather(..);
        t1 = MPI_Wtime();
        dt2 = t1-t0;
    }

    if (iteration==1)
    {
       dt2<dt1 ? algorithm=use_allgather : algorithm=use_scatter_then_gather;
    }
}

यह एक बुरा विचार नहीं है ... उन दोनों को समय और निर्धारित करें कि कौन सा तेज है।
पॉल

अधिकांश आधुनिक एचपीसी वातावरण हार्डवेयर कई MPI कॉल का अनुकूलन करते हैं। कभी-कभी यह अविश्वसनीय स्पीडअप, अन्य समय, बेहद अपारदर्शी व्यवहार की ओर जाता है। सावधान रहे!
मेववप्ल २

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

@ पाओल टोपोलॉजी यहाँ का प्रमुख कारक नहीं है, लेकिन वसा वाले पेड़ में पर्याप्त द्वि घातुमान बैंडविड्थ है, जो कि अल्टरनेटर्स को सस्ता बना सकता है। हालांकि, इकट्ठा हमेशा ऑलगेदर से सस्ता होना चाहिए। हालांकि बड़े संदेशों के लिए, यह 2 के कारक से कम हो सकता है
जेफ

5

यह सुनिश्चित करने के एकमात्र तरीके के बारे में जेफ का पूर्ण अधिकार है - हम वैज्ञानिक हैं, आखिरकार, और यह एक अनुभवजन्य सवाल है - और इस तरह के मापों को लागू करने के बारे में उत्कृष्ट सलाह देता है। अब मुझे एक विपरीत (या, शायद, पूरक) दृश्य प्रदान करते हैं।

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

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

  • कोड अब और अधिक स्पष्ट रूप से दर्शाता है कि आप क्या करने की कोशिश कर रहे हैं, जिससे यह अगले व्यक्ति के लिए और अधिक समझ में आता है जो अगले वर्ष आपके कोड में आता है, जिसे यह पता नहीं है कि कोड क्या करने वाला है (वह व्यक्ति आपके साथ अच्छा हो सकता है);
  • इस अधिक विशिष्ट मामले के लिए MPI स्तर पर अनुकूलन उपलब्ध हैं जो अधिक सामान्य मामले में नहीं हैं, इसलिए आपकी MPI लाइब्रेरी आपकी सहायता कर सकती है; तथा
  • अपने खुद के रोल करने की कोशिश करने की संभावना होगी; भले ही यह MPI कार्यान्वयन Y.ZZ के साथ मशीन X पर बेहतर प्रदर्शन करता है, लेकिन जब आप किसी अन्य मशीन पर जाते हैं, या अपने MPI कार्यान्वयन को अपग्रेड करते हैं, तो यह बहुत बुरा प्रदर्शन कर सकता है।

इस काफी सामान्य मामले में, यदि आपको पता चलता है कि कुछ MPI सामूहिक आपकी मशीन पर अनुचित रूप से धीरे-धीरे काम करता है, तो सबसे अच्छी बात यह है कि mpi विक्रेता के साथ बग रिपोर्ट दर्ज करें; आप MPI लाइब्रेरी स्तर पर ठीक से तय किए जाने वाले एप्लिकेशन कोड में काम करने की कोशिश करने वाले अपने स्वयं के सॉफ़्टवेयर को जटिल नहीं करना चाहते हैं।

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

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


मुझे लगता है कि मैं इस बिंदु पर अनुकूलन की तुलना में पोर्टेबिलिटी में अधिक रुचि है, लेकिन मैं हमेशा अगर वहाँ एक और कार्यान्वयन पोर्टेबल के रूप में समान रूप से है कि पता करने के लिए उत्सुक हूँ लेकिन तेजी से :)
पॉल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.