2015-05-28 36 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