2015-06-08 16 views
6

OpenMP üzerinde bazı testler yapıyorum ve "toplam" dizisinin yanlış paylaşımı nedeniyle ölçeklenmemesi gereken bu programı yaptım. Sahip olduğum problem, ölçek yapması. Hatta "kötü": 4 sn (ICPC), 4 saniye (g ++) Yanlış paylaşıma rağmen artırılmış hız

  • 2 parçacığı ile: 2 saniye (ICPC), 2 saniye (g ++)
  • 4 iplik ile

    • iplik 1 : 0,5 saniye (icpc), 1 saniye (g ++)

    2 derlemeden Intel derleyicileri olan 4 ileti dizisine ulaştığımda gerçekten hızlanmadım. Ama en önemlisi: Sahte paylaşım sergilemesine rağmen neden bu kadar iyi ölçeklendiriliyor? derleyici bu şekilde uygulamayı seçti eğer

    #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

    Yanlış paylaşımı düzelttiğinizde ne kadar hızlı? – JimmyB

    +0

    Tam olarak aynı hız. – InsideLoop

    +1

    Burada ilk başta sahte paylaşım olduğunu düşünmüyorum. Her iş parçacığı dizinin yalnızca bir özel öğesine erişir. Her iş parçacığı toplamı saklamak için kendi tek değişkenine sahipmiş gibi. Eşzamanlı koddaki herhangi bir dizi verisi üzerinde yineleme yapmazsınız, bu yüzden yanlış bir şekilde paylaşacak bir şey yoktur. – JimmyB

    cevap

    7

    Bu kod kesinlikle , sahte paylaşımı sergileyecektir. Ama derleyicinin yapması saçma bir şey olurdu.

    İlk döngüde, her iş parçacığı yalnızca sum öğesinin bir öğesine erişir. Bu öğeyi saklayan gerçek yığın belleğe num_steps yazması için bir neden yoktur; Değeri bir kayıtta tutmak ve for-döngüsü bittikten sonra tekrar yazmak için çok daha hızlıdır. Dizi uçucu veya atomik olmadığından, derleyicinin bu şekilde davranmasını engelleyen hiçbir şey yoktur.

    Ve elbette, ikinci döngüde diziye yazı yok, dolayısıyla yanlış paylaşım yok.

    +0

    Anlam ifade ediyor. OpenMP'deki Intel videosu, yanlış paylaşımı açıklamak ve öğrencilerin bilgisayarlarında çalıştırmasını istemek için bu örneği seçmektedir. Bu yüzden derleyicilerinin problemi "geçici çözüm" olarak görmemelerini bekledim. Hala 2 ila 4 iş parçacığı hızını anlamıyorum! – InsideLoop

    +0

    @InsideLoop Biraz garip. OpenMP optimizasyonları çok opak olsa da, hiç şaşırmadım. ICC'nin derinliklerinde bazı belirsiz küçük tuning sezgileri, 2 veya 1'den 4 iplik için daha iyi çalışmıştır. – Sneftel