2009-10-20 27 views
5

Tôi đang sử dụng phương pháp monte carlo để tính pi và làm một kinh nghiệm cơ bản với lập trình song song và OpenMPParallel, nhưng chậm hơn

vấn đề là khi tôi sử dụng 1 chủ đề, x lần lặp lại, luôn luôn chạy nhanh hơn so với chủ đề n , x lặp lại. bất cứ ai đó có thể trả lời tôi tại sao?

Ví dụ mã chạy như thế này "a.out 1 1000000", trong đó 1 là chủ đề và 1000000 sự lặp

include <omp.h> 
include <stdio.h> 
include <stdlib.h> 
include <iostream> 
include <iomanip> 
include <math.h> 

using namespace std; 

int main (int argc, char *argv[]) { 

double arrow_area_circle, pi; 
float xp, yp; 
int i, n; 
double pitg= atan(1.0)*4.0; //for pi error 
cout << "Number processors: " << omp_get_num_procs() << endl; 

//Number of divisions 
iterarions=atoi(argv[2]); 
arrow_area_circle = 0.0; 

#pragma omp parallel num_threads(atoi(argv[1])) 
{ 
srandom(omp_get_thread_num()); 

#pragma omp for private(xp, yp) reduction(+:arrow_area_circle) //*,/,-,+ 
for (i = 0; i < iterarions; i++) { 
    xp=rand()/(float)RAND_MAX; 
    yp=rand()/(float)RAND_MAX; 

    if(pow(xp,2.0)+pow(yp,2.0)<=1) arrow_area_circle++; 
} 
} 

pi = 4*arrow_area_circle/iterarions; 
cout << setprecision(18) << "PI = " << pi << endl << endl; 
cout << setprecision(18) << "Erro = " << pitg-pi << endl << endl; 

return 0; 
} 

Trả lời

2

bối cảnh chuyển đổi.

10

Nhiệm vụ chuyên sâu của CPU như thế này sẽ chậm hơn nếu bạn thực hiện công việc trong nhiều chủ đề hơn là có CPU trong hệ thống. Nếu bạn đang chạy nó trên một hệ thống CPU duy nhất, bạn chắc chắn sẽ thấy một sự chậm lại với nhiều hơn một sợi. Điều này là do hệ điều hành phải chuyển đổi giữa các luồng khác nhau - đây là phí trên không thuần túy. Bạn nên lý tưởng có cùng một số luồng như lõi cho một nhiệm vụ như thế này.

Một vấn đề khác là arrow_area_circle được chia sẻ giữa các chuỗi. Nếu bạn có một luồng chạy trên mỗi lõi, việc tăng thêm arrow_area_circle sẽ làm mất hiệu lực bản sao trong bộ nhớ cache của các lõi khác, khiến chúng phải nạp lại. arrow_area_circle ++ nên thực hiện một vài chu kỳ sẽ mất hàng chục hoặc hàng trăm chu kỳ. Hãy thử tạo mũi tên_area_circle cho mỗi chuỗi và kết hợp chúng ở cuối.

CHỈNH SỬA: Joe Duffy vừa đăng một số blog entry về chi phí chia sẻ dữ liệu giữa các chuỗi.

+0

tôi có bộ đôi lõi, nhưng tôi sẽ thử một giải pháp cho arrow_area_circle – blueomega

+0

Bạn sẽ thấy tốc độ tăng lên ở 2 luồng và sau đó giảm tốc độ sau đó. – Michael

7

Dường như bạn đang sử dụng một số loại trình biên dịch tự động song song. Tôi sẽ giả sử bạn có nhiều hơn 1 lõi/CPU trong hệ thống của bạn (vì điều đó sẽ quá rõ ràng - và không có siêu phân luồng trên Pentium 4 không được tính là có hai lõi, bất kể tiếp thị của Intel sẽ giúp bạn tin gì .) Có hai vấn đề mà tôi thấy. Đầu tiên là tầm thường và có lẽ không phải vấn đề của bạn:

  1. Nếu arrow_area_circle biến được chia sẻ giữa các quá trình của bạn, sau đó hành động thực hiện arrow_area_circle ++ sẽ gây ra một hướng dẫn lồng vào nhau được sử dụng để đồng bộ hóa các giá trị trong một cách đó là âm thanh nguyên tử. Bạn nên tăng biến "riêng tư", sau đó thêm giá trị đó chỉ một lần ở cuối vào biến arrow_area_circle chung thay vì gia tăng arrow_area_circle trong vòng lặp bên trong của bạn.

  2. Hàm rand(), hoạt động tốt, phải thực thi nội bộ bằng phần quan trọng. Lý do là trạng thái bên trong/hạt giống của nó là một biến chia sẻ tĩnh; nếu không, sẽ có thể có hai quy trình khác nhau để có được kết quả tương tự từ rand() với xác suất cao bất thường, chỉ vì chúng đang gọi rand() gần như cùng một lúc. Điều đó có nghĩa rand() chạy chậm, và đặc biệt là vì nhiều luồng/quy trình đang gọi nó cùng một lúc. Không giống như biến arrow_area_circle (chỉ cần tăng nguyên tử), một phần quan trọng thực sự phải được gọi bởi rand() vì cập nhật trạng thái của nó phức tạp hơn. Để giải quyết vấn đề này, bạn nên lấy mã nguồn cho trình tạo số ngẫu nhiên của riêng bạn và sử dụng nó với một hạt nhân hoặc trạng thái riêng riêng. Mã nguồn cho việc thực hiện rand() chuẩn trong hầu hết các trình biên dịch có sẵn rộng rãi.

Tôi cũng muốn chỉ ra rằng bạn đang sử dụng hàm pow (,) để thực hiện điều tương tự như x * x. Sau đó là khoảng 300 lần nhanh hơn so với trước đây. Mặc dù điểm này không liên quan đến câu hỏi bạn đang hỏi.:)

1

Chỉ cần nhấn mạnh rằng bạn phải thực sự cẩn thận khi sử dụng các số ngẫu nhiên trong cài đặt song song. Trong thực tế, bạn nên sử dụng một cái gì đó như SPRNG

Dù bạn làm gì, hãy đảm bảo rằng mỗi chuỗi không sử dụng số cùng số ngẫu nhiên.

2

rand() đang chặn chức năng. Nó có nghĩa là nó có phần quan trọng bên trong.

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