2015-06-08 10 views
6

मैं ओपनएमपी पर कुछ परीक्षण कर रहा हूं और इस प्रोग्राम को "सर" के झूठे साझाकरण के कारण स्केल नहीं करना चाहिए। मेरी समस्या यह है कि यह स्केल करता है। यहां तक ​​कि "बदतर":झूठी साझाकरण के बावजूद बढ़ी हुई गति

  • साथ 1 धागा: 4 सेकंड (icpc), 4 सेकंड (छ ++)
  • 2 धागे के साथ: 2 सेकंड (icpc), 2 सेकंड (छ ++)
  • 4 धागे से : 0.5 सेकंड (आईसीपीसी), 1 सेकंड (जी ++)

मुझे वास्तव में इंटेल कंपाइलर्स के साथ 2 धागे से 4 धागे तक की गति प्राप्त नहीं होती है। लेकिन सबसे महत्वपूर्ण यह है: क्यों इतना अच्छा स्केलिंग कर रहा है भले ही इसे झूठी साझाकरण प्रदर्शित करनी चाहिए?

#include <iostream> 
#include <chrono> 

#include <array> 

#include <omp.h> 

int main(int argc, const char *argv[]) 
{ 
    const auto nb_threads = std::size_t{4}; 
    omp_set_num_threads(nb_threads); 

    const auto num_steps = std::size_t{1000000000}; 
    const auto step = double{1.0/num_steps}; 
    auto sum = std::array<double, nb_threads>{0.0}; 
    std::size_t actual_nb_threads; 

    auto start_time = std::chrono::high_resolution_clock::now(); 
    #pragma omp parallel 
    { 
     const auto id = std::size_t{omp_get_thread_num()}; 
     if (id == 0) { 
      // This is needed because OMP might give us less threads 
      // than the numbers of threads requested 
      actual_nb_threads = omp_get_num_threads(); 
     } 
     for (auto i = std::size_t{0}; i < num_steps; i += nb_threads) { 
      auto x = double{(i + 0.5) * step}; 
      sum[id] += 4.0/(1.0 + x * x); 
     } 
    } 
    auto pi = double{0.0}; 
    for (auto id = std::size_t{0}; id < actual_nb_threads; id++) { 
     pi += step * sum[id]; 
    } 
    auto end_time = std::chrono::high_resolution_clock::now(); 
    auto time = std::chrono::duration_cast<std::chrono::nanoseconds>(end_time - start_time).count(); 

    std::cout << "Pi: " << pi << std::endl; 
    std::cout << "Time: " << time/1.0e9 << " seconds" << std::endl; 
    std::cout << "Total nb of threads actually used: " << actual_nb_threads << std::endl; 

    return 0; 
} 
+0

जब आप झूठी साझाकरण को ठीक करते हैं तो यह कितनी तेज़ है? – JimmyB

+0

बिल्कुल वही गति। – InsideLoop

+1

मुझे नहीं लगता कि आपके पास पहले स्थान पर झूठी साझाकरण है। प्रत्येक थ्रेड सरणी के केवल एक समर्पित तत्व तक पहुंचता है। ऐसा लगता है कि प्रत्येक थ्रेड के पास योग को स्टोर करने के लिए अपना एकल चर था। आप समवर्ती कोड में किसी भी सरणी डेटा पर पुनरावृत्ति नहीं करते हैं, इसलिए झूठे तरीके से साझा करने के लिए कुछ भी नहीं है। – JimmyB

उत्तर

7

कि कोड निश्चित रूप से झूठी बंटवारे का प्रदर्शन कर सकता है, यदि संकलक इसे उस तरह से लागू करने के लिए चुना है। लेकिन यह संकलक के लिए एक मूर्ख बात होगी।

पहले पाश में, प्रत्येक थ्रेड केवल sum के एक तत्व तक पहुंचता है। num_steps उस तत्व को संग्रहीत वास्तविक स्टैक मेमोरी को लिखने का कोई कारण नहीं है; मूल्य को केवल एक रजिस्टर में रखने के लिए बहुत तेज़ है, और फॉर-लूप खत्म हो जाने के बाद इसे वापस लिखें। चूंकि सरणी अस्थिर या परमाणु नहीं है, इसलिए इस तरह से व्यवहार करने से संकलक को रोकना कुछ भी नहीं है।

और, ज़ाहिर है, दूसरे लूप में सरणी को कोई लेखन नहीं है, इसलिए कोई झूठी साझाकरण नहीं है।

+0

समझ में आता है। ओपनएमपी पर इंटेल वीडियो झूठी साझाकरण की व्याख्या करने और छात्रों को अपने कंप्यूटर पर चलाने के लिए कहने के लिए इस उदाहरण का चयन करता है। तो मैंने उम्मीद की कि उनके कंपाइलर्स समस्या को "कामकाज" न करें। मैं अभी भी 2 से 4 धागे की गति को समझ नहीं पा रहा हूं! – InsideLoop

+0

@InsideLoop यह थोड़ा अजीब है। ओपनएमपी अनुकूलन इतने अपारदर्शी हैं, हालांकि, मैं शायद ही आश्चर्यचकित हूं। आईसीसी में कुछ अस्पष्ट छोटे ट्यूनिंग हेरिस्टिक गहरे 2 या 1 से 4 धागे के लिए बेहतर काम करने लगे। – Sneftel

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