2013-02-21 26 views
5

Tôi đang cố gắng thực hiện một số FFT song song. Tôi đang sử dụng FFTW và OpenMP. Mỗi FFT là khác nhau, vì vậy tôi không phụ thuộc vào đa luồng xây dựng trong FFTW (mà tôi biết sử dụng OpenMP).Tạo kế hoạch FFTW bằng cách sử dụng OpenMP

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 

Tất cả đều hoạt động tốt. Tuy nhiên, nếu tôi loại bỏ các cấu trúc quan trọng từ xung quanh việc tạo kế hoạch (fftw_plan_dft_r2c_2d) mã của tôi sẽ thất bại. Ai đó có thể giải thích lý do tại sao? fftw_plan_dft_r2c_2d không thực sự là một "đứa trẻ mồ côi", đúng không? Có phải vì hai luồng có thể vừa cố gắng truy cập vào vị trí bộ nhớ numberOfRows hoặc numberOfColumns cùng một lúc?

+0

Bạn KHÔNG sử dụng khả năng đa luồng của fftw. Bạn đang thực sự tạo 36 biến đổi đơn luồng song song. –

+0

Tôi biết. Tôi nói rằng trong câu hỏi ban đầu của tôi _Each FFT là khác nhau, vì vậy tôi không dựa vào xây dựng trong multithreading_ FFTW. Tôi muốn thực hiện 36 biến đổi đơn luồng song song. – tir38

+0

Xin lỗi, sai lầm của tôi, tôi đã đọc chính xác điều ngược lại ;-) –

Trả lời

7

Nó khá nhiều bài viết trong tài liệu FFTW về thread safety:

... nhưng một số bạn phải cẩn thận vì thói quen lập kế hoạch chia sẻ dữ liệu (ví dụ khôn ngoan và bảng lượng giác) giữa các cuộc gọi và các kế hoạch.

Kết quả là quy trình an toàn chỉ (tái nhập cảnh) duy nhất trong FFTW là fftw_execute (và các biến thể mảng mới của chúng). Tất cả các thói quen khác (ví dụ: kế hoạch) chỉ nên được gọi từ một luồng tại một thời điểm. Vì vậy, ví dụ, bạn có thể bọc một khóa semaphore xung quanh bất kỳ cuộc gọi đến kế hoạch; thậm chí đơn giản hơn, bạn chỉ có thể tạo tất cả các kế hoạch của mình từ một chuỗi. Chúng tôi không nghĩ rằng đây nên là một hạn chế quan trọng (FFTW được thiết kế cho tình huống mà mã chỉ có hiệu suất duy nhất là việc thực thi biến đổi) và lợi ích của dữ liệu được chia sẻ giữa các gói là rất lớn.

Trong một ứng dụng điển hình của các kế hoạch FFT được xây dựng ít khi, vì vậy nó không thực sự quan trọng nếu bạn phải đồng bộ hóa việc tạo của chúng. Trong trường hợp của bạn, bạn không cần phải tạo một kế hoạch mới tại mỗi lần lặp, trừ khi kích thước của dữ liệu thay đổi. Bạn thà làm như sau:

#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); 
} 

Bây giờ các kế hoạch được tạo ra chỉ một lần trong mỗi chủ đề và các chi phí serialization sẽ giảm với nhau thực hiện fftw_execute(). Nếu chạy trên hệ thống NUMA (ví dụ: hệ thống N64 của AMD64 hoặc Intel multi-socket), thì bạn nên bật tính năng ràng buộc chuỗi để đạt được hiệu suất tối đa.

+0

Tôi chỉ đọc phần đó của hướng dẫn ... Tôi quay lại để trả lời câu hỏi của chính tôi và thấy bạn. Bạn nhận được séc. Bạn nói "trừ khi kích thước của dữ liệu thay đổi" nhưng nếu kích thước là như nhau nhưng các giá trị khác nhau thì sao? Tôi đã cập nhật câu hỏi ban đầu của mình để phản ánh điều này. – tir38

+0

@ tir38, đó là lý do tại sao bạn thực hiện kế hoạch nhiều lần, phải không? Một kế hoạch duy nhất là OK miễn là bạn sử dụng lại các mảng đầu vào và đầu ra. Chỉ cần không gán cho 'inputTest' như thế vì nó là một con trỏ. Bạn muốn có một cái gì đó như 'someDataSpecificToThisIteration (m, inputData)' và có đầu ra từ hàm được đưa vào 'inputData'. –

+0

xin lỗi lần nữa. Ý tôi là 'someDataSpecificToThisIteration [m]'. Nó không phải là một cuộc gọi phương thức, mà là một lệnh kéo từ một số mảng chung. Vì vậy, tôi chỉ có 'inputData' là con trỏ đến dữ liệu đó. Bởi vì tôi có 36 con trỏ tới 36 mảng, tôi cần 36 kế hoạch, đúng không? – tir38

Các vấn đề liên quan