2012-08-23 38 views
9

Tôi mới ở đây và một lập trình viên mới bắt đầu ở C. Tôi đang gặp một số vấn đề khi sử dụng openmp để tăng tốc cho vòng lặp. Dưới đây là ví dụ đơn giản:OpenMP và C song song cho vòng lặp: tại sao mã của tôi làm chậm khi sử dụng OpenMP?

#include <stdlib.h> 
#include <stdio.h> 
#include <gsl/gsl_rng.h> 
#include <omp.h> 

gsl_rng *rng; 

main() 
{ 
int i, M=100000000; 
double tmp; 

/* initialize RNG */ 
gsl_rng_env_setup(); 
rng = gsl_rng_alloc (gsl_rng_taus); 
gsl_rng_set (rng,(unsigned long int)791526599); 

// option 1: parallel   
    #pragma omp parallel for default(shared) private(i, tmp) schedule(dynamic) 
    for(i=0;i<=M-1;i++){ 
    tmp=gsl_ran_gamma_mt(rng, 4, 1./3); 
    } 


// option 2: sequential  
    for(i=0;i<=M-1;i++){ 
    tmp=gsl_ran_gamma_mt(rng, 4, 1./3); 
    } 
} 

Mã rút ra từ phân phối ngẫu nhiên gamma cho các lần lặp M. Nó chỉ ra cách tiếp cận song song với openmp (tùy chọn 1) mất khoảng 1 phút trong khi phương pháp tiếp cận tuần tự (tùy chọn 2) chỉ mất 20 giây. Trong khi chạy với openmp, tôi có thể thấy việc sử dụng CPU là 800% (máy chủ tôi đang sử dụng có 8 CPU). Và hệ thống này là Linux với GCC 4.1.3. Lệnh biên dịch tôi đang sử dụng là gcc -fopenmp -lgsl -lgslcblas -lm (Tôi đang sử dụng GSL)

Tôi có làm gì sai không? Làm ơn giúp tôi! Cảm ơn!

P.S. Như được chỉ ra bởi một số người dùng, nó có thể được gây ra bởi rng. Nhưng ngay cả khi tôi thay

tmp=gsl_ran_gamma_mt(rng, 4, 1./3); 

bởi nói

tmp=1000*10000; 

vấn đề vẫn còn đó ...

+0

Bạn không nên biến biến vòng lặp của mình thành riêng tư - OpenMP sẽ xử lý điều đó. Tôi không biết nếu điều này ảnh hưởng đến việc thực hiện, nhưng bạn nên sửa chữa nó và kiểm tra lại. –

+0

Ngoài ra, lưu ý rằng tmp = 1000 * 10000 có thể được tối ưu hóa bởi trình biên dịch thành một vòng, do đó sẽ làm lệch thời gian của bạn. –

+0

Bạn có chắc chắn thực sự có 8 CPU không? Nó có thể là một quad-core với hyperthreading? –

Trả lời

12

gsl_ran_gamma_mt lẽ khóa trên rng để ngăn chặn vấn đề đồng thời (nếu nó không, song song của bạn mã có thể chứa một điều kiện chủng tộc và do đó mang lại kết quả sai). Giải pháp sau đó sẽ có một cá thể rng riêng biệt cho mỗi luồng, do đó tránh khóa.

+1

cảm ơn rất nhiều! nhưng vấn đề vẫn còn nếu tôi thay thế tmp = gsl_ran_gamma_mt (rng, 4, 1./3) với tmp = 1000 * 10000 – user1620200

+0

@ user1620200 Odd, cần có sự giảm bớt mạnh mẽ. Tất nhiên, vẫn còn một chi phí rất lớn cho tính toán song song liên quan kể từ khi tính toán thực tế là khá nhanh, ngay cả với rất nhiều lần lặp lại. Lịch động không hiệu quả (hãy thử lịch tĩnh, không có lý do nào cho lịch biểu động ở đây vì các tác vụ đều có cùng kích thước). Cuối cùng, hãy thử lời khuyên của Stephane nhưng tôi sẽ ngạc nhiên nếu đó là vấn đề vì điều này nên được tối ưu hóa một cách trivially. –

+0

Cảm ơn. Tôi phát hiện ra rằng nếu tôi thoát khỏi lịch trình (năng động), vấn đề đã biến mất! Tôi tự hỏi tại sao? – user1620200

5

Biến số rng của bạn được chia sẻ, do đó, các chủ đề dành tất cả thời gian chờ đợi để có thể sử dụng trình tạo số ngẫu nhiên. Cung cấp cho mỗi luồng một cá thể riêng biệt của RNG. Điều này có thể có nghĩa là làm cho mã khởi tạo RNG chạy song song.

+0

cảm ơn rất nhiều! nhưng vấn đề vẫn còn nếu tôi thay thế tmp = gsl_ran_gamma_mt (rng, 4, 1./3) với tmp = 1000 * 10000; – user1620200

1

Một lần nữa cảm ơn mọi người đã trợ giúp. Tôi vừa phát hiện ra rằng nếu tôi loại bỏ

schedule(dynamic) 

trong mã này, sự cố sẽ biến mất. Nhưng tại sao vậy?

+1

Lập lịch 'động' là khá tốn kém và chỉ nên được sử dụng trong những trường hợp lặp lại mất nhiều thời gian để hoàn thành nhưng thời gian này có thể thay đổi đáng kể với mỗi lần lặp. 'hướng dẫn' thậm chí còn đắt hơn vì nó làm cho các khối lặp lại nhỏ hơn và nhỏ hơn. Sử dụng lập lịch 'tĩnh' cho các lần lặp với thời gian tính toán cố định. –

+0

Cảm ơn rất nhiều Hristo Iliev! – user1620200

+1

Tôi nghĩ bạn có thể chấp nhận câu trả lời của riêng bạn, vì bạn là người giải quyết vấn đề. –

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