2015-05-28 40 views
4

我正在編寫測試數字是否爲素數的程序。在開始時,我會計算每個進程分配的數量,然後將這個數量發送到進程。接下來,執行計算並將數據發送回處理0,以保存結果。下面的代碼工作,但是當我增加進程數時,我的程序不加速。在我看來,我的程序不能並行工作。怎麼了?這是我在MPI中的第一個程序,因此歡迎任何意見。MPI - 不增加進程量的加速

我使用mpich2 an我在Intel Core i7-950上測試我的程序。

main.cpp中:

if (rank == 0) { 
    int workers = (size-1); 
    readFromFile(path); 
    int elements_per_proc = (N + (workers-1))/workers; 
    int rest = N % elements_per_proc; 

    for (int i=1; i <= workers; i++) { 
     if((i == workers) && (rest != 0)) 
      MPI_Send(&rest, 1, MPI_INT, i, 0, MPI_COMM_WORLD); 
     else 
      MPI_Send(&elements_per_proc, 1, MPI_INT, i, 0, MPI_COMM_WORLD); 
    } 

    int it = 1; 
    for (int i=0; i < N; i++) { 
     if((i != 0) && ((i % elements_per_proc) == 0)) 
     it++; 
     MPI_Isend(&input[i], 1, MPI_INT, it, 0, MPI_COMM_WORLD, &send_request); 
    } 
} 

if (rank != 0) { 
    int count; 
    MPI_Recv(&count, 1, MPI_INT, 0, MPI_ANY_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE); 
    for (int j=0; j < count; j++) { 
     MPI_Recv(&number, 1, MPI_INT, 0, MPI_ANY_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE); 
     result = test(number, k); 
     send_array[0] = number; 
     send_array[1] = result; 
     MPI_Send(send_array, 2, MPI_INT, 0, 0, MPI_COMM_WORLD); 
    } 
} 

if (rank == 0) { 
    for (int i=0; i < N; i++) { 
     MPI_Recv(rec_array, 2, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, MPI_STATUS_IGNORE); 
     // save results 
    } 
} 
+0

是您的首要測試算法順序? –

+0

@DieterLücking,我使用Miller-Rabin素數測試。每個流程都會測試部分數字,這些操作是獨立的。 – Bakus123

回答

3

你的實現可能不會很好地擴展到多的過程,因爲你每一步溝通。您當前正在傳送每個單一輸入的數字和結果,這會導致較大的延遲開銷。相反,您應該考慮通過輸入散裝(即使用單個消息)進行通信。

此外,使用MPI的集體操作(MPI_Scatter/MPI_Gather)代替的MPI_Send/MPI_Recv循環可能會增加你的表現更進一步。

另外,您還可以利用進程來處理輸入塊。然後

一個更具擴展性的實現可能如下:

// tell everybody how many elements there are in total 
MPI_Bcast(&N, 1, MPI_INT, 0, MPI_COMM_WORLD); 

// everybody determines how many elements it will work on 
// (include the master process) 
int num_local_elements = N/size + (N % size < rank ? 1 : 0); 
// allocate local size 
int* local_input = (int*) malloc(sizeof(int)*num_local_elements); 

// distribute the input from master to everybody using MPI_Scatterv 
int* counts; int* displs; 
if (rank == 0) { 
    counts = (int*)malloc(sizeof(int) * size); 
    displs = (int*)malloc(sizeof(int) * size); 
    for (int i = 0; i < size; i++) { 
     counts[i] = N/size + (N % size < i ? 1 : 0); 
     if (i > 0) 
      displs[i] = displs[i-1] + counts[i-1]; 
    } 
    // scatter from master 
    MPI_Scatterv(input, counts, displs, MPI_INT, local_input, num_local_elements, MPI_INT, 0, MPI_COMM_WORLD); 
} else { 
    // receive scattered numbers 
    MPI_Scatterv(NULL, NULL, NULL, MPI_DATATYPE_NULL, local_input, num_local_elements, MPI_INT, 0, MPI_COMM_WORLD); 
} 

// perform prime testing 
int* local_results = (int*) malloc(sizeof(int)*num_local_elements); 
for (int i = 0; i < num_local_elements; ++i) { 
    local_results[i] = test(local_input[i], k); 
} 

// gather results back to master process 
int* results; 
if (rank == 0) { 
    results = (int*)malloc(sizeof(int)*N); 
    MPI_Gatherv(local_results, num_local_elements, MPI_INT, results, counts, displs, MPI_INT, 0, MPI_COMM_WORLD); 
    // TODO: save results on master process 
} else { 
    MPI_Gatherv(local_results, num_local_elements, MPI_INT, NULL, NULL, NULL, MPI_INT, 0, MPI_COMM_WORLD); 
} 
+0

非常感謝你,你的實施是偉大的。我想過MPI_Scatterv和MPI_Gatherv,但是在這種情況下,所有進程都發送/接收數據(也是等級0)。我想這樣做等級0不參與計算只能播放數據並保存結果。我能做些什麼來增加我的實施? – Bakus123

+1

您可以做兩件事:1.)發送問題並批量接收結果。這意味着你有兩個溝通階段。避免自行發送每一個數字/結果。 2.)編輯scatterv/gatherv,使得進程「0」的計數爲「0」,問題分佈在「(size-1)」而不是「size」進程中。 – Patrick