MPI BMP图像比较效率更高

时间:2016-06-02 02:36:55

标签: c++ image mpi

我做了一个简单的程序,我逐个像素地比较两个图像,并确定图片是否相同。我正在尝试将其改编为MPI,但我担心通信耗时太长会使其效率低于顺序通信。我尝试过非常大分辨率的图像,结果是一样的:顺序代码比并行代码更有效。有没有办法让它更有效率?

顺序代码:

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

    unsigned char* BMP(char* filename,int* sizes)
    {
        int i;
        FILE* f = fopen(filename, "rb");
        unsigned char info[54];
        fread(info, sizeof(unsigned char), 54, f);

        int ancho = *(int*)&info[18];
        int alto = *(int*)&info[22];

        int size = 3 * ancho * alto;
        *sizes = size;
        unsigned char* data = new unsigned char[size];
        fread(data, sizeof(unsigned char), size, f);
        fclose(f);
        for(i = 0; i < size; i += 3)
        {
                unsigned char tmp = data[i];
                data[i] = data[i+2];
                data[i+2] = tmp;
        }

        return data;
    }

    int main(int argc,char **argv){
      int sizes,i,bol;
      clock_t t1,t2;
      double tiemp;
      t1 = clock();
      bol=1;
      unsigned char* data1= BMP(argv[1],&sizes);
      unsigned char* data2= BMP(argv[2],&sizes);
      for (i =0; i<sizes; i += 3)
      {
        if(data1[i]!=data2[i]){
          printf("The images are not the same\n");
          bol=0;
          break;}
        }

      if(bol==1)
       printf("The images are the same\n");

       t2 = clock();
       tiemp = ((double) (t2 - t1)) / (CLOCKS_PER_SEC);
       printf("%f\n",tiemp );
      return 0;
     }

MPI计数器部分

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

    unsigned char* BMP(char* filename,int* sizes)
    {
        int i;

        FILE* f = fopen(filename, "rb");
        unsigned char info[54];
        fread(info, sizeof(unsigned char), 54, f);

        int ancho = *(int*)&info[18];
        int alto = *(int*)&info[22];

        int size = 3 * ancho * alto;
        *sizes = size;
        unsigned char* data = new unsigned char[size];
        fread(data, sizeof(unsigned char), size, f);
        fclose(f);
        for(i = 0; i < size; i += 3)
        {
                unsigned char tmp = data[i];
                data[i] = data[i+2];
                data[i+2] = tmp;
        }

        return data;
    }

    int main(int argc,char **argv){
      int sizes,i,world_rank,world_size;
      clock_t t1,t2;
      double tiemp;
      t1 = clock();

      MPI_Init(&argc, &argv);
      MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
      MPI_Comm_size(MPI_COMM_WORLD, &world_size);
      unsigned char* data1;
      unsigned char* data2;
      int root = 0;
      if(world_rank==0){
      data1= BMP(argv[1],&sizes);
      data2= BMP(argv[2],&sizes);
      printf("%d",sizes);
      }
      MPI_Bcast(&sizes,1,MPI_INT,root,MPI_COMM_WORLD);
      int num_elements_por_proc = sizes/world_size;
      unsigned char* subdata2=new unsigned char[num_elements_por_proc];
      unsigned char* subdata1=new unsigned char[num_elements_por_proc];
      MPI_Scatter( data1, num_elements_por_proc, MPI_UNSIGNED_CHAR, subdata1, num_elements_por_proc, MPI_UNSIGNED_CHAR, root, MPI_COMM_WORLD );
      MPI_Scatter( data2, num_elements_por_proc, MPI_UNSIGNED_CHAR, subdata2, num_elements_por_proc, MPI_UNSIGNED_CHAR, root, MPI_COMM_WORLD );
      int bol = 0;
      if(world_rank!=0){


        for(i=0;i<=num_elements_por_proc;i++){
          if(subdata1[i]!=subdata2[i]){
            bol = 1;
            break;
          }
         }
     }
     int bolls;
     MPI_Reduce(&bol,&bolls,1, MPI_INT, MPI_SUM, 0,MPI_COMM_WORLD);

     if(world_rank==0){
      if(bolls !=0){
        printf("The images are not the samen");}
      else{
        printf("The images are the same \n" );}

     t2 = clock();
     tiemp = ((double) (t2 - t1)) / (CLOCKS_PER_SEC);
     printf("%f\n",tiemp );
     }
     MPI_Finalize();
     return 0;
     }

2 个答案:

答案 0 :(得分:1)

此代码不适合并行化。您的瓶颈很可能只是读取文件。即使文件已经存在于根进程的内存中,发送数据然后只查看每个数据元素(实际上只有1/3)一次,也不会比在根进程本身上做得快。

在这里利用并行性的唯一方法是存储分发的文件,并分发它们。然后你可以在每个节点上计算一个哈希并比较它们。

还有一些评论:

  • 考虑使用MPI_LOR(逻辑或)来减少而不是添加
  • std::swap代替tmp
  • 将每个新对与删除配对,即使在示例代码中也是如此。
  • 正确格式化代码。为了您自己和为了人们不得不在这里阅读它。如果您很懒,请使用clang-format等工具。

答案 1 :(得分:1)

除了由@Zulan解释的I / O绑定外,您的算法还有一个基本属性,这使得它不适合并行化。要了解原因,请看以下具体构造的极端情况。

您有两个图像,它们的区别仅在于它们的第一个像素(线性化时),否则它们是相同的。您现在将图像分成N个部分并将它们分配到N个等级进行比较。第一个等级立即找到差异,打破循环,并进入MPI_Reduce调用,但其他N-1等级必须超过其整个迭代范围才能得出图像部分相同的结论。 MPI_Reduce是一项集体行动,只有在所有参赛队伍都加入其中后才会完成,换句话说,在N-1排名完全检查其图像片段之前不会完成。

串口程序将在第一次迭代时找到差异并立即中断循环。这是一个明显的案例,其中并行版本不能更快,反之则相当慢。它还说明了负载不平衡的一个示例 - 不同的进程执行不同的工作量,而更快的进程必须等待较慢的完成。您可以实现某种通知机制,并使第一个等级完成通知其他人,以便他们可以突破他们的比较循环。这种方式更适合在具有OpenMP等范例的共享内存系统上实现,尽管后者的取消机制需要付出代价。

另一方面,如果图像相同,那么并行程序将比串行程序快N倍。如果图像的(长度/ N)像素不同,则并行版本将花费与序列图像相同的时间。

因此,并行加速是非常不可预测的,并且对实际输入非常敏感。