2013-02-21 23 views
5

Paralel olarak birkaç FFT gerçekleştirmeye çalışıyorum. FFTW ve OpenMP kullanıyorum. Her bir FFT farklıdır, bu yüzden FFTW'nin çoklu katmanı (OpenMP kullanır biliyorum) güvenmiyorum.OpenMP kullanarak FFTW planı oluşturma

int m; 

// assume: 
// int numberOfColumns = 100; 
// int numberOfRows = 100; 

#pragma omp parallel for default(none) private(m) shared(numberOfColumns, numberOfRows)// num_threads(4) 
    for(m = 0; m < 36; m++){ 

     // create pointers 
     double   *inputTest; 
     fftw_complex *outputTest; 
     fftw_plan  testPlan; 

     // preallocate vectors for FFTW 
     outputTest = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*numberOfRows*numberOfColumns); 
     inputTest = (double *)fftw_malloc(sizeof(double)*numberOfRows*numberOfColumns); 

     // confirm that preallocation worked 
     if (inputTest == NULL || outputTest == NULL){ 
      logger_.log_error("\t\t FFTW memory not allocated on m = %i", m); 
     } 

     // EDIT: insert data into inputTest 
     inputTest = someDataSpecificToThisIteration(m); // same size for all m 

     // create FFTW plan 
     #pragma omp critical (make_plan) 
     { 
      testPlan = fftw_plan_dft_r2c_2d(numberOfRows, numberOfColumns, inputTest, outputTest, FFTW_ESTIMATE); 
     } 

     // confirm that plan was created correctly 
     if (testPlan == NULL){ 
      logger_.log_error("\t\t failed to create plan on m = %i", m); 
     } 

     // execute plan 
     fftw_execute(testPlan); 

     // clean up 
     fftw_free(inputTest); 
     fftw_free(outputTest); 
     fftw_destroy_plan(testPlan); 

    }// end parallelized for loop 

Bu her şey düzgün çalışıyor. Ancak, kritik yapıyı plan oluşturma işleminden kaldırırsam (fftw_plan_dft_r2c_2d) kodum başarısız olur. Birisi nedenini açıklayabilir mi? fftw_plan_dft_r2c_2d gerçekten bir "yetim" değil, doğru mu? İki iş parçacığının her ikisi de aynı anda numberOfRows veya numberOfColumns bellek konumunu vurmaya çalışabilir mi?

+0

Fftw'nin çok iş parçacıklı yeteneklerini KULLANMAYIN. Aslında, 36 tek iş parçacıklı dönüşümü paralel yapıyorsunuz. –

+0

Biliyorum. İlk sorumda _Each FFT'nin farklı olduğunu söylüyorum, bu yüzden FFTW'nin çoklu yapıya güvenmiyorum. Paralel olarak 36 tek-dişli dönüşüm yapmak istiyorum. – tir38

+0

Üzgünüm, benim hatam, tam tersini okudum ;-) –

cevap

7

Hemen hemen tüm FFTW belgelerinde yaklaşık thread safety yazıldığı için:

... ama bazı dikkat edilmesi gerekir çünkü aramaları ve planları arasında planlayıcısı rutinleri payı verileri (örneğin bilgelik ve trigonometrik tablolar).

Kesintiler, FFTW'deki tek iş parçacığı güvenli (yeniden giriş yapan) yordamın fftw_execute (ve bunun yeni dizi varyantları) olmasıdır. Diğer tüm rutinler (ör. Planlayıcı) sadece bir seferde bir iş parçacığından çağrılmalıdır. Örneğin, bir semafor kilidini planlayıcıya yapılan tüm çağrılar etrafına sarabilirsiniz; Daha da basit olarak, tüm planlarınızı tek bir iş parçacığından oluşturabilirsiniz. Bunun önemli bir kısıtlama olduğunu düşünmüyoruz (FFTW, tek performansa duyarlı kodun, dönüşümün gerçek uygulaması olduğu durum için tasarlandı) ve paylaşılan verilerin planların faydaları açısından harika.

FFT planlarının tipik bir uygulamasında nadiren oluşturulur, bu nedenle oluşturulmalarını eşitlemeniz gerekip gerekmediği gerçekten önemli değildir. Durumunuzda, verilerin boyutu değişmedikçe, her yinelemede yeni bir plan oluşturmanız gerekmez. Şimdi planları her iplik ve fftw_execute() her yürütülmesine azalacaktır seri yükü yalnızca bir defa oluşturulur

#pragma omp parallel default(none) private(m) shared(numberOfColumns, numberOfRows) 
{ 
    // create pointers 
    double   *inputTest; 
    fftw_complex *outputTest; 
    fftw_plan  testPlan; 

    // preallocate vectors for FFTW 
    outputTest = (fftw_complex*)fftw_malloc(sizeof(fftw_complex)*numberOfRows*numberOfColumns); 
    inputTest = (double *)fftw_malloc(sizeof(double)*numberOfRows*numberOfColumns); 

    // confirm that preallocation worked 
    if (inputTest == NULL || outputTest == NULL){ 
     logger_.log_error("\t\t FFTW memory not allocated on m = %i", m); 
    } 

    // create FFTW plan 
    #pragma omp critical (make_plan) 
    testPlan = fftw_plan_dft_r2c_2d(numberOfRows, numberOfColumns, inputTest, outputTest, FFTW_ESTIMATE); 

    #pragma omp for 
    for (m = 0; m < 36; m++) { 
     // execute plan 
     fftw_execute(testPlan); 
    } 

    // clean up 
    fftw_free(inputTest); 
    fftw_free(outputTest); 
    fftw_destroy_plan(testPlan); 
} 

: Sen yerine aşağıdaki yapardı. Bir NUMA sisteminde çalışıyorsanız (ör. Çoklu soketli bir AMD64 veya Intel (post-) Nehalem sistemi), maksimum performans elde etmek için iplik bağını etkinleştirmelisiniz.

+0

Sadece el kitabının bir kısmını okudum ... Kendi sorumu cevaplamak için geldi ve seninkini gördüm. Çekini al. "Veri boyutu değişmediği sürece" diyorsunuz, ancak boyutlar aynıysa ancak değerler farklıysa ne olur? Orijinal sorumu bunu yansıtmak için güncelledim. – tir38

+0

@ tir38, bu yüzden planı birden çok kez çalıştırıyorsunuz değil mi? Giriş ve çıkış dizilerini yeniden kullandığınız sürece tek bir plan tamamdır. Sadece bir işaretçi olduğu için "inputTest" gibi atamayın. BazıDataSpecificToThisIteration (m, inputData) 'gibi bir şey olmasını ve' inputData' içine koyduğu işlevin çıktısını almayı tercih edersiniz. –

+0

Üzgünüz yine. BazıDataSpecificToThisIteration [m] 'demek istedim. Onun bir yöntem çağrısı değil, bazı jenerik diziden bir çekme. Bu yüzden sadece "inputData" bu verilere işaretçi olmak zorundayım. 36 dizi girişine 36 işaretçim olduğu için 36 plana ihtiyacım var, değil mi? – tir38