MPI:程序根据进程数量而有效

时间:2014-01-28 10:12:42

标签: c mpi

我编写了一个使用MPI库(MPICH-2)的程序。程序找到介于2和N之间的所有素数。如果我只使用两个进程,它可以正常工作,但是当我指定进程数> 2时它不会。 该程序效率非常低,因为我的目标是比较使用MPI的程序和不使用MPI的程序之间的性能。 我有一个双核机器,我在Ubuntu 13.10上使用NetBeans 7.4。问题是否取决于我的机器的核心数量?我知道调度取决于操作系统,但我不知道该怎么想!也许我要放一个MPI_Barrier?我在下面插入代码和输出,因为你可以看到当我用2个以上的proc调用程序时会出现一些奇怪的零。

#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>


int count(int *a, int N){
    int b[N];
    int i, j, n_prime;

    for(i=0; i<N; i++)
        b[i] = a[i];

    b[0] = b[1] = 0;
    for (i=2; i<N; i++) {
        b[i] = 1;
        for (j=2; j<i; j++) 
            if (i % j == 0) {
                    b[i] = 0; 
                    break;
            }
        }
    n_prime = 0;
    for (j=2; j<N; j++) 
    if (b[j]) n_prime++;
    return n_prime;
    }

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

    int size, rank, div;
    int N;
    int *array;
    int i, j, k, check, n_prime, n_prime_loc;
    int *sub_array, *prime, *recv_prime, *b, *prime2;
    double t1, t2;


    if(argc != 2){
    printf("Argument error: %s not recognized as argument\n", argv[0]);
    return -1;
    }

    N = atoi(argv[1]);

    MPI_Init(NULL, NULL);

    t1 = MPI_Wtime();

    MPI_Comm_size(MPI_COMM_WORLD, &size);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    div = N/size;       //elements per process

    b = (int*) malloc(sizeof(int)*N);
    if (b == NULL){
        printf("Cannot allocate array 'b'\n");
        return -1;
    }

    n_prime = count(b, N);

    /* Dynamic allocation of the arrays */
    sub_array = (int*) malloc(sizeof(int)*div);
    if (sub_array == NULL){
        printf("Cannot allocate array 'sub_array'\n");
        return -1;
    }
    recv_prime = (int*) malloc(sizeof(int)*n_prime);
    if (recv_prime == NULL){
        printf("Cannot allocate array 'recv_prime'\n");
        return -1;
    }
    array = (int*) malloc(sizeof(int)*N);
    if (array == NULL){
        printf("Cannot allocate array 'array'\n");
        return -1;
    }
    prime = (int*) malloc(sizeof(int)*n_prime);
    if (prime == NULL){
        printf("Cannot allocate array 'prime'\n");
        return -1;
    }

    /* Initialization of the array */
    for (i=0; i<N; i++)       
        array[i] = i+1;
    for(i=0; i<n_prime; i++)
        prime[i] = 0;
    for(i=0; i<n_prime; i++)
        recv_prime[i] = 0;

    /* Process 0 divides the array among the processes */
    MPI_Scatter(array, div, MPI_INT, sub_array, div, MPI_INT, 0, MPI_COMM_WORLD);

    check = 0;      //used to check if we find a divisor
    k=0;

    for(i=0; i<div; i++){
        check = 0;
        if (sub_array[i] == 1) continue;
        for(j=2; j<sub_array[i]; j++){
            if(sub_array[i] % j == 0){
                check = 1;
            }
        }
        if (check == 0){     //if we don't find a divisor, the number is prime
            prime[k] = sub_array[i];
            k++;
        }
    }

    n_prime_loc = 0;

    for(i=0; i<n_prime; i++)
        if(prime[i]!=0)
            n_prime_loc++;

    prime2 = (int*) malloc(sizeof(int)*n_prime_loc);

    j=0;
    for(i=0; i<n_prime; i++){
        if(prime[i]==0) continue;
        prime2[j] = prime[j];
        j++;
    }

    /* Each process sends its computation to the root process */
    MPI_Gather(prime2, n_prime_loc, MPI_INT, recv_prime, n_prime_loc, MPI_INT, 0, MPI_COMM_WORLD);

    MPI_Barrier(MPI_COMM_WORLD);

    if(rank == 0){

        printf("Prime numbers: ");
        for(i=0; i<n_prime; i++)
            printf("%i ", recv_prime[i]);
        printf("\n");
    }

    /* Free the allocated arrays */
    free(b);
    free(array);
    free(recv_prime);
    free(prime);
    free(prime2);
    free(sub_array);

    t2 = MPI_Wtime();
    //printf("Computation time for Process %i: %f\n", rank, t2-t1);

    MPI_Finalize();

    return (EXIT_SUCCESS);
    }

输出结果为:

hino@hino-X51L:~/NetBeansProjects/Prime$ mpiexec -np 10 ./Prime 1000
Prime numbers: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199
0 0 0 0 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 
317 331 337 347 349 353 359 367 373 379 383 389 397 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521 
523 541 547 557 563 569 571 577 587 593 599 450 451 452 601 607 613 617 619 631 641 
643 647 653 659 661 673 677 683 691 701 709 719 727 733 739 743 751 757 761 769 773 
787 797 649 650 485 486 
hino@hino-X51L:~/NetBeansProjects/Prime$ mpiexec -np 2 ./Prime 1000
Prime numbers: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 
211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 
337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 
461 463 467 479 487 491 499 503 509 521 523 541 547 557 563 569 571 577 587 593 599 
601 607 613 617 619 631 641 643 647 653 659 661 673 677 683 691 701 709 719 727 733 
739 743 751 757 761 769 773 787 797 809 811 821 823 827 829 839 853 857 859 863 877 
881 883 887 907 911 919 929 937 941 947 953 967 971 977 983 991 997 

1 个答案:

答案 0 :(得分:0)

快速扫描显示我有些不对劲:

  1. 您需要确保您的数字数组均匀分开。例如,如果您在3个进程中划分100个数字,那么您将有一些数字不会被MPI_SCATTER正确分发。这不是你的问题。

  2. 您的MPI_GATHER在接收方有问题。这里的问题是您从每个进程发送n_prime_loc个数字,但每个进程的值也不同。例如,等级0可能找到10个素数,因此其n_prime_loc的值将为10,但在等级1上,可能有25个素数(我知道这些例子不准确,但坚持我)。问题在于,由于等级0是MPI_GATHER操作的根,因此将使用n_prime_loc的值,这意味着如果另一个进程正在发送更多等级为0的数字,则会有一个问题。您需要生成一个足够大的缓冲区来保存所有可能的结果并适当地收集结果。或者,您可以选择不使用MPI_GATHER,因为缓冲区的大小不是先验已知的。相反,您可以使用MPI_SENDMPI_RECV,并且可以使用MPI_PROBE来了解制作缓冲区的大小。你可以做任何一个工作。

  3. 你的MPI_BARRIER在这里毫无用处。出于某种原因,当人们不知道在MPI中做什么时,他们会投入MPI_BARRIER。所有这些功能都是让所有进程在此时等待,直到所有其他进程到达同一点。您已经通过调用MPI_GATHER来完成此操作,因为该调用涉及所有其他进程。

  4. 听起来你只是在一个进程上运行这个应用程序。虽然你当然可以做到这一点,但你不会真正获得更多的加速,你将不会获得比你拥有核心更快的速度。如果你有一个双核处理器并且你正在尝试运行4个进程,那么你将花费大量时间来争取CPU和上下文切换。您应该尽量不要使用比核心更多的MPI等级。