使用 MPI 的质数计数器(埃拉托色尼筛法),太慢了

Posted

技术标签:

【中文标题】使用 MPI 的质数计数器(埃拉托色尼筛法),太慢了【英文标题】:Prime Number Counter (Sieve of Eratosthenes) Using MPI, Too Slow 【发布时间】:2014-06-28 15:38:24 【问题描述】:

以下代码对所有质数进行计数,直到 50,000,000 并且 100% 正确运行。问题是它需要的时间太长了。使用 32 个处理器,我得到了大约 42 秒。我的一个同行有 16 秒,我似乎无法找到我的代码滞后的地方。请留下任何建议:)

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

const int n=50000000;   //number until which primes are counted (inclusive)

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

    long local_count=0, global_count=0,     //variables used to keep count of the primes
    start, finish,      //highest and lowest possible primes for this processor 
    i;  

    int rank,           //processor id 
    p,          //number of processes
    size, proc0_size;   //amount of numbers to check on any processor and proc 0
double runtime;         //variable used to keep track of total elapsed time

    //initialize the MPI execution environment
    MPI_Init (NULL, NULL);

    //determine the rank of the calling processor in the communicator
    MPI_Comm_rank (MPI_COMM_WORLD, &rank);
        //determine the size of communicator
    MPI_Comm_size (MPI_COMM_WORLD, &p);

    //Ensures that every processor enters code at around the same time
    MPI_Barrier(MPI_COMM_WORLD);
    //Start the timer
    runtime = -MPI_Wtime();

    //compute the range and size to be used for this processor
    start = 2 + rank*(n-1)/p;
    finish = 1 + (rank+1)*(n-1)/p;
    size = finish - start + 1;

    //determine the size of processor 0
    proc0_size = (n-1)/p;

    //in the case where there are too many processors for the amount of numbers
    //to check...   
    if ((2 + proc0_size) < (long) sqrt((double) n)) 
        if (rank == 0)
            printf ("Too many processors to calculate the number of primes up to %d\n", n);
        MPI_Finalize();
        exit(1);
    

    int j;
    //check every number in the range of this processor
    for (j=start; j<=finish; j++)
     //if the number is not composite, ie prime, increment the local counter
     if (isComposite(j)==0)
        local_count++;
     
     

     //MPI_Reduce used to combine all local counts
         MPI_Reduce (&local_count, &global_count, 1, MPI_LONG_LONG, MPI_SUM, 0, MPI_COMM_WORLD);

     //adjust the total elapsed runtime
     runtime += MPI_Wtime();
     printf("Process %d finished\n", rank); 

     // print the results from process ranked root
     if (rank == 0) 
            printf ("There are %ld primes less than or equal to %d\n", global_count, n);
        printf ("Total elapsed time:  %f seconds\n", runtime);
     

     //terminate the execution environment
     MPI_Finalize ();
     return 0;
   

//function to check if a number is composite
//returns 0 if it is not composite (prime) and returns a 1 if it is composite

int isComposite (int num)

int retval=0;

if(num==1)
        retval = 1;

   else if(num%2 == 0 && num!=2)
        retval = 1;

    if(retval != 1) 
    int j;
    for(j=3; j<num; j+=2) 
                if(num%j == 0 )
                        retval = 1;
                        break;
                
                if(j*j>num) break;
            
    

if(retval == 0)
    return 0;
else 
    return 1;

【问题讨论】:

【参考方案1】:

我编译了你的测试并在本地机器上运行它。

我明白了

 3001134 primes less than or equal to 50000000 

Total elapsed time: 大约需要 35-37 秒。我的电脑有 4 个 2.4 GHz 的 Q6600 内核,64 位 ubuntu。测试编译为mpicc t.c -o t -lm -O3

只有两个核心 - 时间是 66 秒。

我注意到:排名较高的进程有更多的工作要做,并且它们比排名较低的进程更晚结束计算。因此,当您使用批次流程时,总执行时间由排名最高的最后一个流程定义。

尝试重新分配工作(为更高级别的进程分配更少的段)并优化您的isComposite 函数。正如我在使用 perf record 进行分析的结果中看到的那样,num%j == 0 行需要很长时间(大约 80%)。

最好先准备小素数列表并用它们进行筛分,然后再切换到更昂贵的筛分。

筛分也意味着不在 start..finish 上迭代 j 并测试每个 j,而是从 start..finish 创建数组,然后使用 i 迭代 - 每个数字减去 sqrt(finish),并标记 @ 987654334@、array[3*i]array[4*i]array[5*i] 等作为复合(您可以使用加法而不是乘法)。然后,您将从数组中计算未标记的元素,以从区间中获取素数。 (请检查来自http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes 的动画)。您的代码可能是最慢的http://en.wikipedia.org/wiki/Trial_division

【讨论】:

在实现 simples sieve 之后,我的程序可以在 2 个或 4 个 CPU 上在 21 秒内找到高达 500000000 的所有素数(是原始情况的十倍)。原稿尺寸 - 2.2 - 2.6 秒。 PS:验证表在这里:primes.utm.edu/howmany.shtml

以上是关于使用 MPI 的质数计数器(埃拉托色尼筛法),太慢了的主要内容,如果未能解决你的问题,请参考以下文章

使用埃拉托色尼筛法找到第 n 个素数

埃拉托色尼筛法(Sieve of Eratosthenes)求素数。

埃拉托色尼筛的问题

埃拉托色尼质数筛法

埃拉托色尼筛选法的介绍

优化埃拉托色尼筛