2015-05-26 4 views
7

मैं ओपनएमपी का उपयोग कर समानांतर तरीके से युगल की एक श्रृंखला में लिखने (अपडेट) करने की कोशिश कर रहा हूं। विचार यह है कि जिस तत्व को अद्यतन करने की आवश्यकता है उसे एक से अधिक बार अपडेट किया जा सकता है और तत्व स्वयं पर फ्लाई पर गणना की जाती है। यह दौड़ की स्थिति के लिए बहुत प्रवण होता है जब तक कि मैं उस परमाणु ऑपरेशन के साथ अद्यतन होने वाले तत्व के लिए मेमोरी क्षेत्र संवाददाता को "लॉक" नहीं करता। नीचे दिए गए उदाहरण के रूप में:परमाणु संचालन के साथ युगल की सरणी अद्यतन करना

#include<omp.h> 
#include<stdlib.h> 

int main() 
{ 

    double *x=NULL, contribution = 1234.5; 
    size_t xlen=1000, i, n; 

    if ((x = (double *) calloc(xlen,sizeof(double))) == NULL) exit(-1) 

    #pragma omp parallel for shared(x) private(n,contribution) 
    for (i=0; i<xlen; i++) { 
     n = find_n_on_the_fly(i); 

     #pragma omp atomic update 
     x[n]+=contribution; // in the more complicated case contributions are different 

    } 

    return 0; 
} 

मैं अभी भी इस दृष्टिकोण के साथ दौड़ की स्थिति में दौड़ रहा हूं। मैंने महत्वपूर्ण वर्गों का उपयोग करने की कोशिश की लेकिन यह पूरी तरह से मारता है क्योंकि सरणी बड़ी हैं और अपडेट की संख्या भी बड़ी है।

प्रश्न: इस दृष्टिकोण के साथ क्या गलत है? क्या इसे संभालने का कोई बेहतर तरीका है?

नोट: इसे संभालने के लिए मैं धागे के प्रत्येक के लिए सरणी की प्रतियां बनाकर और बाद में उन्हें कम करके कुछ बेवकूफ कर रहा हूं। लेकिन स्मृति सीमाएं मुझे आगे जाने की अनुमति नहीं देती हैं।

+1

क्यों नहीं 'एन' /' योगदान 'जोड़े की सूची बनाएं, इसमें धक्का रखें, फिर उन्हें' x' सरणी, या किसी अन्य प्रकार के स्पैस प्रतिनिधित्व में कम करें? – user3528438

+0

@ user3528438 यह एक विचार है और मेरे नोट के अनुरूप है। क्या आपके पास एक वास्तविक कामकाजी उदाहरण है जो कि मैं पहले से ही क्या कर रहा हूं उससे कम नहीं करता? –

+0

परिभाषा के अनुसार, 64-बिट मान के लिए एक परमाणु संचालन केवल 64-बिट (या अधिक) हार्डवेयर आर्किटेक्चर के साथ संभव है। फ़्लोटिंग पॉइंट लाइब्रेरी उस मुद्दे की जड़ पर हो सकती है जो आप यहां देख रहे हैं। क्या आपने टाइपिंग को 'हस्ताक्षरित लंबे समय तक' करने का प्रयास किया है? साथ ही, प्रत्येक तत्व के लिए लूप के माध्यम से खोजने के बजाय, हैश तालिका सरणी तत्वों को देखने के लिए बहुत तेज होगी। –

उत्तर

0

मैं इसे "समानांतर कंप्यूटिंग के लिए बहुत नया" के साथ पेश करूंगा और यह आपके उपयोग के मामले के आधार पर व्यवहार्य नहीं हो सकता है।

एक विचार जो उपयोगी हो सकता है प्रोग्राम के पहलुओं को अद्यतन करने और अद्यतन करने के लिए अलग करना है। मास्टर/कंट्रोल प्रोसेस/थ्रेड की स्थापना करना जिसमें सरणी के लिए एकमात्र पहुंच है और दास/गणना प्रक्रियाओं/धागे से एकत्र की गई जानकारी से कतार फैशन में अपडेट करता है। यह पारंपरिक अर्थ में लॉक करने की आवश्यकता को कम करने के लिए काम कर सकता है।

मुझे उम्मीद है कि कम से कम समस्या को देखने का एक अलग तरीका प्रदान करता है।

1

मेरे लिए, कोड से ऊपर कुशल लगता है।

1- आपके द्वारा उपयोग की calloc के बजाय इनपुट में से एक के रूप में कैश लाइन आकार के साथ _mm_malloc नामक एक स्मृति आवंटन समारोह का उपयोग करना:

हालांकि, आपके पास दो विकल्प इसे सुधारने के लिए की है। सबसे बड़ी बात जो आप अभी सामना कर रहे हैं वह झूठी साझाकरण है। उपर्युक्त विधि का उपयोग करके एफएस के प्रभावों को छोड़ने के लिए, आप मूल रूप से अंतर्निहित लाइब्रेरी को स्मृति (या आपकी सरणी) आवंटित करने के लिए मजबूर कर रहे हैं ताकि प्रत्येक तत्व कैश पर एक पंक्ति में रह रहा हो। इस तरह, धागे दो अलग-अलग आपसी चर को पुनः प्राप्त करने के लिए कैश लाइन पर नहीं लड़ेंगे। दूसरे शब्दों में, यह कैश लाइन में दो चर के आवंटन को रोक देगा। यह एक बहु थ्रेडेड कार्यक्रम में प्रदर्शन को बढ़ावा देगा। अधिक जानकारी के लिए Google _mm_malloc। हालांकि, निम्नलिखित मूल उपयोग हैं। अधिकांश आधुनिक कंप्यूटरों में, कैश लाइन 64 है।

#if defined(__INTEL_COMPILER) 
#include <malloc.h> 
#else 
#include <mm_malloc.h> 
#endif 

int CPU_Cache_line_size = 64; 

int xlen = 100; 
double *ptr = _mm_malloc(xlen*sizeof(double), CPU_Cache_line_size); 
/* 
    do something ... 
*/ 
_mm_free(ptr); 

__CPU_CACHE_LINE_SIZE__ निम्न तरीकों से आपके सिस्टम के लिए क्वेरी की जा सकती है:

  • लिनक्स आदेश:

    getconf LEVEL1_DCACHE_LINESIZE

  • प्रोग्राम के:

    int CPU_Cache_line_size = sysconf (_SC_LEVEL1_DCACHE_LINESIZE);

  • कैश के बारे में विस्तृत जानकारी:

    /sys/devices/system/cpu/cpu0/cache/

2- आप स्वयं इस उल्लेख किया, लेकिन सीमाओं अपनी स्थिति के लिए गंभीर हैं: धागा प्रति एक सरणी का उपयोग कर और फिर उन्हें कम। यह दृष्टिकोण अधिक कुशल है। यदि आप कर सकते हैं तो इस दृष्टिकोण का उपयोग करने के लिए फिर से विचार करें।

+0

ध्यान दें कि '_mm_malloc' और '_mm_free' केवल तभी वैध हैं जब आप इंटेल' आईसीसी 'या' आईसीपीसी 'कंपाइलर्स का उपयोग करते हैं। यदि आप एक अलग का उपयोग कर अपना प्रोग्राम बनाते हैं तो अन्य विकल्पों का उपयोग करने पर विचार करें। गठबंधन आवंटन के लिए POSIX विकल्प 'posix_memalign' है: https://linux.die.net/man/3/posix_memalign । सी 11 मानक संस्करण 'aligned_alloc' है (http://en.cppreference.com/w/c/memory/aligned_alloc)। –

संबंधित मुद्दे