我试图学习MPI,所以我创建了这个简单的程序,用于对uint8灰度图像进行卷积。我修改了openMP代码,该代码运行得很好,将每个处理器的矢量化图像切成多个部分-设置为scatterDataSize,但是我从MPI中得到了奇怪的错误:
“主作业正常终止,但是返回了1个进程 非零退出代码。按照用户的指示,作业已中止。
mpirun注意到在节点wn25上具有PID 5360的进程等级1在信号11(分段故障)上退出。”
我尝试使用MPI_Scatter将其广播到所有进程,并在卷积后使用MPI_Gather或MPI_Allgather收集数据,但是两者的结果相同...
argv是图像尺寸-图像为input1000_800.bin,因此程序执行如下:
mpirun -np 4 ./main 1000 800,我程序的源代码是:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <omp.h>
#include <mpi.h>
const int ROOT = 0;
const double filter[][5] = { {0,0,1,0,0},
{0,1,2,1,0},
{1,2,-16,2,1},
{0,1,2,1,0},
{0,0,1,0,0} };
unsigned char normalize(double value);
double convolution(int i, int j, unsigned char *image, int height, int width, int filterDimension);
void saveImage(char* filename[], unsigned char* image, long fileLength);
long getFileSize(char* filename[]);
unsigned char * readImage(char* filename[]);
int main(int argc, char * argv[])
{
int width = atoi(argv[1]);
int height = atoi(argv[2]);
const char * prefixInFile = "../../labMPI/infile";
const char * prefixOutFile = "result";
const char * fileExtension = ".bin";
char outFileName[64], fileName[64];
unsigned char * image, *buffer, *data;
long fileSize;
int processorsAmount, processId, scatterDataSize;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &processorsAmount);
MPI_Comm_rank(MPI_COMM_WORLD, &processId);
strcpy(fileName, prefixInFile);
strcat(fileName, argv[1]);
strcat(fileName, "_");
strcat(fileName, argv[2]);
strcat(fileName, fileExtension);
strcpy(outFileName, prefixOutFile);
strcat(outFileName, argv[1]);
strcat(outFileName, "_");
strcat(outFileName, argv[2]);
strcat(outFileName, fileExtension);
fileSize = getFileSize(fileName);
data = (unsigned char *)malloc(fileSize * sizeof(unsigned char));
scatterDataSize = fileSize / processorsAmount;
int startPoint = scatterDataSize * processId;
int endPoint = scatterDataSize * (processId + 1);
printf("filesize: %d\nprocessorsAmount: %d\niam: %d\nscatterDataSize: %d\nstartPoint: %d\nendPoint: %d\n",
fileSize, processorsAmount, processId, scatterDataSize, startPoint, endPoint);
if (processId == ROOT)
{
printf("Reading file %s on ROOT \n output file will be: %s \n", fileName, outFileName);
image = readImage(fileName);
}
MPI_Bcast(image,fileSize, MPI_UNSIGNED_CHAR, ROOT, MPI_COMM_WORLD);
#pragma omp parallel for
for (int i = startPoint; i < endPoint; i++)
{
register int col = i % width;
register int row = i / width;
register long idx = col + width * row;
data[idx] = normalize(convolution(col, row, image, height, width, 5));
}
/* i am not sure how to collect processed data on workers back to root and perform save */
MPI_Bcast(data,fileSize, MPI_UNSIGNED_CHAR, ROOT, MPI_COMM_WORLD);
if (processId == ROOT)
{
saveImage(outFileName, data, fileSize);
printf("Image processing is finished");
free(image);
}
free(data);
MPI_Finalize();
return 0;
}
double convolution(int i, int j, unsigned char *image, int height, int width, int filterDimension)
{
register int filterHeight, filterWidth, kernelCenter, ii, jj;
filterHeight = filterWidth = filterDimension;
kernelCenter = filterHeight / 2;
register double tmp = 0;
for (long m = 0; m < filterHeight; ++m) {
for (long n = 0; n < filterWidth; ++n) {
ii = i + (kernelCenter - m);
jj = j + (kernelCenter - n);
if (ii >= 0 && ii < width && jj >= 0 && jj < height)
tmp += image[jj * width + ii] * filter[m][n];
}
}
return tmp;
}
unsigned char * readImage(char* filename[])
{
FILE *inFile = fopen(filename, "rb");
fseek(inFile, 0, SEEK_END);
long long fileLength = ftell(inFile);
fseek(inFile, 0, SEEK_SET);
unsigned char * image = (unsigned char *)malloc(fileLength * sizeof(unsigned char));
fread(image, sizeof(unsigned char), fileLength, inFile);
fclose(inFile);
return image;
}
long getFileSize(char* filename[])
{
FILE *inFile = fopen(filename, "rb");
fseek(inFile, 0, SEEK_END);
long fileLength = ftell(inFile);
fclose(inFile);
return fileLength;
}
void saveImage(char* filename[], unsigned char* image, long fileLength)
{
FILE *write = fopen(filename, "wb");
fwrite(image, sizeof(unsigned char), fileLength * sizeof(unsigned char), write);
fclose(write);
}
unsigned char normalize(double value)
{
if (value > 255)
{
value = 255;
}
else if (value < 0) {
value = 0;
}
return (unsigned char)value;
}