我在使用 MPICH2 1.0.6 的 linux 集群中运行一个程序(我实际上无法将它更新到 MPICH3,所以我坚持使用那个版本)并且没有明显的原因程序没有执行。
我使用 mpicc -o prog prog.c -lm
编译它并使用 mpiexec
执行
该程序是使用 vector 空间模型实现层次凝聚聚类算法。数据集合是一个 n*m
数组(在程序 DOC*MAXWORDS
中),它被分成集群的节点,如 PARTS=DOC/procs
所以每个节点负责 PARTS*MAXWORDS
数据。
当使用 gdb 和 ddd 在串行机器上调试时,我发现程序在代码的特定行中有一个段错误,我找不到它的问题所在。看一看。
while(iterations != DOC-k){//bigLoop
iterations++;
x=y=-1;
pos1=pos2=node1=node2=-1;
for(i=0;i<PARTS;i++){//ELEGXOS MEGISTOU TOPIKA
if(max_array[i]>x){
x=max_array[i];
pos1=i;
}
else if(max_array[i]==x){
pos2=i;
} //ELEGXOS META TO LOOP GIA OMOIOTHTES
}
if(max_array[pos1]!=max_array[pos2]){
for(i=0;i<PARTS;i++){
if(max_array[i]>max_array[pos2] && i!=pos1)
pos2=1;
}
}
if(MPI_Allgather(&x,1,MPI_DOUBLE,
n_max,1,MPI_DOUBLE,MPI_COMM_WORLD) != MPI_SUCCESS) {
printf("Allgather high valuer - error");
exit(1);
}
for(i=0;i<procs;i++){
if(n_max[i]>y){
y=n_max[i];
node1=i;
}
else if(n_max[i]==y){
node2=i;
}
}
for(i=0;i<MAXWORDS;i++){
merger_one[i]=merger_two[i]=0;
}
if(n_max[node1]==n_max[node2]){
if(id==node1){
for(i=0;i<MAXWORDS;i++){
merger_one[i]=vector[node1*PARTS+pos1][i];
last_one[i]=vector[(node1*PARTS)+texts_vectors[node1]][i];
}
size_one=size_of[pos1];
nn_array[pos1]=nn_array[texts_vectors[node1]];
max_array[pos1]=max_array[texts_vectors[node1]];
size_of[pos1]=size_of[texts_vectors[node1]];
texts_vectors[node1]--;
}
if(id==node2){
for(i=0;i<MAXWORDS;i++){
merger_two[i]=vector[node2*PARTS+pos2][i];
last_two[i]=vector[(node2*PARTS)+texts_vectors[node2]][i];
}
j=pos2;
pos2=pos1;
pos1=j;
size_two=size_of[pos2];
nn_array[pos2]=nn_array[texts_vectors[node2]];
max_array[pos2]=max_array[texts_vectors[node2]];
size_of[pos2]=size_of[texts_vectors[node2]];
texts_vectors[node2]--;
}
}
else{
node2=node1;
if(id==node1){
for(i=0;i<MAXWORDS;i++){
merger_one[i]=vector[node1*PARTS+pos1][i];
merger_two[i]=vector[node2*PARTS+pos2][i];
last_one[i]=vector[(node1*PARTS)+texts_vectors[node1]][i];/*SIGSEV ERROR*/
last_two[i]=vector[(node2*PARTS)+texts_vectors[node2]-1][i];
}
size_one=size_of[pos1];
size_two=size_of[pos2];
nn_array[pos1]=nn_array[texts_vectors[node1]];
max_array[pos1]=max_array[texts_vectors[node1]];
size_of[pos1]=size_of[texts_vectors[node1]];
nn_array[pos2]=nn_array[texts_vectors[node2]-1];
max_array[pos2]=max_array[texts_vectors[node2]-1];
size_of[pos2]=size_of[texts_vectors[node2]-1];
texts_vectors[node1]=texts_vectors[node1]-2;
}
}
MPI_Bcast(&pos1, 1, MPI_INT,node1, MPI_COMM_WORLD);
MPI_Bcast(&pos2, 1, MPI_INT,node2, MPI_COMM_WORLD);
MPI_Bcast(&size_one, 1, MPI_INT,node1, MPI_COMM_WORLD);
MPI_Bcast(&size_two, 1, MPI_INT,node2, MPI_COMM_WORLD);
MPI_Bcast(merger_one, MAXWORDS, MPI_INT,node1, MPI_COMM_WORLD);
MPI_Bcast(merger_two, MAXWORDS, MPI_INT,node2, MPI_COMM_WORLD);
MPI_Bcast(last_one, MAXWORDS, MPI_INT,node1, MPI_COMM_WORLD);
MPI_Bcast(last_two, MAXWORDS, MPI_INT,node2, MPI_COMM_WORLD);
MPI_Allgather(&texts_vectors,1,MPI_INT,texts_vectors,1,MPI_INT,MPI_COMM_WORLD);
for(i=0;i<MAXWORDS;i++){
vector[node1*PARTS+pos1][i]=last_one[i];
vector[node2*PARTS+pos2][i]=last_two[i];
}
Pmanager=PARTS+1;
for(i=0;i<procs;i++){
if(texts_vectors[i]<Pmanager)
Pmanager=i;
}
texts_vectors[Pmanager]++;
for(i=0;i<MAXWORDS;i++){
x=merger_one[i]*size_one;
y=merger_two[i]*size_two;
vector[Pmanager*PARTS+texts_vectors[Pmanager]][i]=(x+y)/(size_one + size_two);
}
for(i=id*PARTS; i< (id+1)*texts_vectors[id]; i++){
for(j=0;j<procs;j++){
for(m=j*PARTS;m<j*PARTS+texts_vectors[j];m++){
x=0;y=0;z=0;
for(l=0; l < MAXWORDS; l++){
x+=vector[i][l]*vector[m][l];
y+=vector[i][l]*vector[i][l];
z+=vector[m][l]*vector[m][l];
}
if(i!=m){
if(y!=0 && z!=0){
sim_matrix[i-(PARTS*id)][m] = x / (sqrt(y) * sqrt(z) );
}
else{
sim_matrix[i-(PARTS*id)][m] = 0.0;
}
}
}
}
}
for(i=0; i<texts_vectors[id]; i++){
x=0.0;
for(j=0;j<DOC;j++){
if(sim_matrix[i][j]>x){
nn_array[i]=j;
max_array[i]=x=sim_matrix[i][j];
}
}
}
}
在此之前创建数组并将数据输入到vector[i][j]
我使用 malloc 创建了数组:
int **vector = malloc(DOC * sizeof *vector);
for (i = 0; i < DOC; i++){
vector[i] = malloc(MAXWORDS * sizeof **vector);
}
double **sim_matrix = malloc(PARTS * sizeof *sim_matrix);
for (i = 0; i < PARTS; i++)
sim_matrix[i] = malloc(DOC * sizeof **sim_matrix);
int *list = malloc(WHOLE * sizeof(int));
int *nn_array = malloc(PARTS * sizeof(int));
double *max_array = malloc(PARTS * sizeof(double));
int *size_of = malloc(PARTS * sizeof(int));
double *n_max = malloc(procs * sizeof(double));
int *texts_vectors = malloc(procs * sizeof(int));
int *merger_one = malloc(MAXWORDS * sizeof(int));
int *merger_two = malloc(MAXWORDS * sizeof(int));
int *last_one = malloc(MAXWORDS * sizeof(int));
int *last_two = malloc(MAXWORDS * sizeof(int));
问题依旧的那一行:last_one[i]=vector[(node1*PARTS)+texts_vectors[node1]][i];/*SIGSEV ERROR*/
也在执行if 循环的第一部分 if(n_max[node1]==n_max[node2]){
但在那种情况下没有错误。
唯一觉得这个问题有点可疑的是 texts_vectors[i]
数组,它一直在计算 vector[i][j]
类型数据的数量当前在节点内。但即便如此,我认为我已经涵盖了它。
我真的希望有人能看看这个,因为它真的很令人沮丧,需要完成。
如果您对正在发生的事情有更好的了解并想查看整个代码,i pasted it into a pastezone.干杯并提前致谢。
编辑:
事实证明,我通过数组 text_vectors
传递的值超出了数组的边界。由于该值给出了最大值,因此对于数组中的实际最后位置,我应该减去 1。就是这样,串行 gdb 和 ddd 中没有段错误。但是这个程序现在不会运行超过 2 个节点。如果我在 4> 个节点中执行它,它就会崩溃。
最佳答案
这一行有多个错误:
MPI_Allgather(&texts_vectors,1,MPI_INT,texts_vectors,1,MPI_INT,MPI_COMM_WORLD);
首先,您提供了一个指向数据指针的指针作为收集到所有操作的第一个参数。因此,每个等级传输的值不是 text_vectors
的第一个元素,而是数据的内存地址(或 64 位小端 LP64 系统上地址的下半部分)。
其次,如果您通过从第一个参数的开头删除地址关闭运算符 &
来解决这个问题,您将遇到另一个问题。 MPI 标准不允许 MPI_Allgather
中的源缓冲区和目标缓冲区重叠。一些 MPI 实现不强制执行该要求,而是默默地做The Right Thing (TM)。其他一些 MPI 实现将尝试使用 memcpy
复制数据并遇到 C 库问题(memcpy
不允许重叠缓冲区)。最后,一些 MPI 实现会给你一个很好的关于重叠缓冲区的错误消息并终止你的程序。
由于您发送的是单个整数元素,只需将值复制到一个临时变量中并将其地址用作第一个参数。
关于C MPI - 没有明显原因的崩溃 - 程序接收到信号 SIGSEGV,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24586745/