【问题标题】:OpenMP takes more time than expectedOpenMP 花费的时间比预期的要长
【发布时间】:2018-03-15 23:25:58
【问题描述】:

所以,我在使用 openMp 时遇到了一些困难。我是初学者,我不知道我做错了什么。这是我在大学的一门课程的项目,所以我不寻求解决方案,而是寻求提示或解释。

该项目是计算属于不同集合(比如说 setA 和 setB)的 2 个字符串之间的汉明距离。这两组可能包含 100,1000 或 10000 个字符串,每个字符串由相同长度的字符组成。

我的问题是,尽管我减少了并行程序的执行时间,但它仍然比串行算法花费更多的时间。

所以,我附上我的代码来展示我到目前为止所做的事情。

串行 C 代码。

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

//initialize sets' number and string's length
int m=atoi(argv[1]),n=atoi(argv[2]),I=atoi(argv[3]);
int i=0,j=0,l=0,TotalHammingDistance=0,count;

//creation of 2-dimentional matrices for setA and setB
char **setA = malloc(m * sizeof(char *)); // Allocate row pointers
for(i = 0; i < m; i++)
    setA[i] = malloc((I+1) * sizeof(char));  // Allocate each row separatel

char **setB = malloc(n * sizeof(char *)); // Allocate row pointers
for(i = 0; i < n; i++)
    setB[i] = malloc((I+1) * sizeof(char));  // Allocate each row separatel

// initialize matrices with random string (0 and 1)
for (i=0;i<m;i++){
    for(j=0;j<I;j++){
        setA[i][j]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"[rand() % 62];
    }
    setA[i][I]='\0';
}

for (i=0;i<n;i++){
    for(j=0;j<I;j++){
        setB[i][j]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"[rand() % 62];
    }
    setB[i][I]='\0';
}

//creation of m*n matrix to store all hamming distances and initialize it
int **HamDist = malloc(m * sizeof(int *)); // Allocate row pointers
for(i = 0; i < m; i++)
  HamDist[i] = malloc(n * sizeof(int));

for(i=0;i<m;i++){
    for(j=0;j<n;j++){
        HamDist[i][j]=0;
    }
}

clock_t start=clock();
//Calculate hamming distance for all combinations of the strings
for (i=0;i<m;i++){
    for(j=0;j<n;j++){
        count=0;
        for(l=0;l<=I;l++) {
            if (setA[i][l] != setB[j][l])
                count++;
        }
        HamDist[i][j]=count;
        TotalHammingDistance+=HamDist[i][j];
    }
}
clock_t end =clock();
double hamm_time=(double)(end-start)/CLOCKS_PER_SEC;

printf("\n|Total Hamming execution time= %f",hamm_time);
printf("\n\n*|The Total Hamming Distance is: %d\n",TotalHammingDistance );
} 

OpenMp C 代码

void main(int argc,char **argv)
{
//initialize sets' number and string's length
    int m=atoi(argv[1]),n=atoi(argv[2]),I=atoi(argv[3]);
     int i=0,j=0,TotalHammingDistance=0, tid,nthreads,chunk;

    //creation of 2-dimentional matrices for setA and setB      
    char **setA = malloc(m * sizeof(char *)); // Allocate row pointers
    for(i = 0; i < m; i++)
      setA[i] = malloc((I+1) * sizeof(char));  // Allocate each row separatel

    char **setB = malloc(n * sizeof(char *)); // Allocate row pointers
    for(i = 0; i < n; i++)
      setB[i] = malloc((I+1) * sizeof(char));  // Allocate each row separatel

    // initialize matrices with random string (0 and 1)
    for (i=0;i<m;i++){
        for(j=0;j<I;j++){
            setA[i][j]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"[rand() % 62];
        }
        setA[i][I]='\0';
    }

    for (i=0;i<n;i++){
        for(j=0;j<I;j++){
            setB[i][j]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"[rand() % 62];
        }
        setB[i][I]='\0';
    }

    //creation of m*n matrix to store all hamming distances and initialize it
    uint16_t **HamDist = malloc(m * sizeof(uint16_t *)); // Allocate row pointers
    for(i = 0; i < m; i++)
      HamDist[i] = malloc(n * sizeof(uint16_t));

    for(i=0;i<m;i++){
        for(j=0;j<n;j++){
            HamDist[i][j]=0;
        }
    }

    printf("\n HamDist set \n" );
    int count=0;
    clock_t start=clock();

    omp_set_num_threads(2);
    #pragma omp parallel shared(setA, setB,HamDist ) 
    {
        int k,p,l,count=0;
        #pragma omp for schedule(dynamic, 10000)        
        for (k=0;k<m;k++){
             for(p=0;p<n;p++){
                count=0;
                for(l=0;l<=I;l++){
                    if (setA[k][l] != setB[p][l]){
                        count++;
                    }
                }
                HamDist[k][p]=count;
            }
        }
    }

    clock_t end =clock();
    double per_time=(double)(end-start)/CLOCKS_PER_SEC;
    printf("\n|Total time for two sets= %f",per_time);

    /**/
    for (i=0;i<m;i++){
          for(j=0;j<n;j++){
              TotalHammingDistance+=HamDist[i][j];
          }
    }

printf("\n|Total execution time= %f",per_time);
printf("\n\n*|The Total Hamming Distance is: %d\n",TotalHammingDistance );
}

openmp 程序的执行时间约为 42.011104,串行算法的执行时间约为 32.876482(m=n=10000 和 I=100,其中 m,n 描述了每组字符串的数量,I 是字符串长度)

我坚信并行程序应该花费更少的执行时间。 有什么想法吗??

提前致谢!

【问题讨论】:

  • 您正在测试它的计算机有多少个处理器/内核?您从中获得基准数据的字符串有多长?如果字符串太短,创建线程的开销将超过分配工作负载的优势。
  • 衡量您在所有这些malloc() 电话中花费了多少时间。并打开all你的编译器警告。您还可能在setB[i][j]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"[rand() % 62]; 上花费大量时间,而m=n=10000 则有100,000,000 次调用rand()
  • @AlexQuilliam 我的电脑有 4 个内核。我计算了 2,4 和 6 个线程的执行时间。使用 2 个线程,我得到了帖子中描述的结果。该字符串的长度为 100 个字符。我们发现到目前为止最好的解决方案是 1000 的工作负载(或块大小)。
  • @AndrewHenle 我没有测量初始化表的时间。我只测量汉明距离计算的时间。
  • 您可能希望将 omp_get_num_threads() 设置为 omp_get_max_threads() 而不是 2。

标签: c parallel-processing openmp hamming-distance


【解决方案1】:

测量多处理器性能有点复杂,但我们可以很好地近似“它是否有效?”与time(1)。如果我按原样使用您的代码(使用 GCC gcc-4.8.real (Ubuntu 4.8.5-2ubuntu1~14.04.1) 4.8.5 调用 gcc -W -Wall -Wextra -O3 -fopenmp openmptest.c -o openmptest)我得到了

$ time ./openmptest 10000 10000 100

 HamDist set 

|Total time for two sets= 9.620011
|Total execution time= 9.620011

*|The Total Hamming Distance is: 1248788142

real    0m9.815s
user    0m9.700s
sys 0m0.116s

real 和 user 的值大致相同,也与普通版本大致相同。如果我完全删除 schedule(dynamic, 10000) 并让 Openmp 自己决定,我会得到

$ time ./openmptest 10000 10000 100
 HamDist set 

|Total time for two sets= 9.187761
|Total execution time= 9.187761

*|The Total Hamming Distance is: 1248788142

real    0m4.819s
user    0m9.265s
sys 0m0.112s

那是 5/9 而不是 9/9。如果我将 omp_set_num_threads(2) 设置为 4(我这里有四个 CPU。)我得到

$ time ./openmptest 10000 10000 100
 HamDist set 

|Total time for two sets= 11.438243
|Total execution time= 11.438243

*|The Total Hamming Distance is: 1248788142

real    0m3.080s
user    0m11.540s
sys 0m0.104s

即 3/11 omp_set_num_threads() 与上次尝试没有区别。

您有一个非常简单的程序,其中 OpenMP 的默认设置运行良好。微调 OpenMP 本身就是一门科学,但例如 @Davislor 关于使用 reduction 的评论似乎是一个很好的开始。

顺便说一句:你也有很多警告,其中之一是关于遮蔽count,你声明了两次,一次在循环之前,一次在循环内。你应该摆脱所有的警告。经常发生的情况是,在这几十个警告之间隐藏了非常重要的信息。

【讨论】:

  • 在编译时说实话(gcc -fopenmp -o openmptest openmptest.c)除了声明了两次的变量计数之外,我没有任何警告。尽管如此,在纠正所有警告并按照您的建议进行操作后,时间明显好转!感谢您的帮助!
  • @SotirisDimitras 为什么你没有警告...哦,我的错,对不起。我使用 clang 的“偏执”模式 clang -Weverything ... 来生成警告,因为它的静态分析器比 GCC 更好,并且忘记在 GCC 调用行中添加强制性的 -W -Wall -Wextra,所以:我的错,对不起。
猜你喜欢
  • 2016-05-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-10-30
  • 1970-01-01
  • 2020-04-01
  • 1970-01-01
  • 2021-09-18
相关资源
最近更新 更多