我做了一个简单的程序,我逐个像素地比较两个图像,并确定图片是否相同。我正在尝试将其改编为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;
}
答案 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)像素不同,则并行版本将花费与序列图像相同的时间。
因此,并行加速是非常不可预测的,并且对实际输入非常敏感。