当一个MPI进程执行MPI_Barrier()时,其他进程挂起

时间:2015-09-05 13:29:15

标签: parallel-processing mpi openmpi

我有一个MPI程序,用于从包含文件名列表的文件中读取多个进程,并根据读取的文件名 - 它读取相应的文件并计算单词的频率。

如果其中一个进程完成此操作并返回 - 阻止执行MPI_Barrier(),则其他进程也会挂起。在调试时,可以看到 readFile()函数未被 process_files()中当前进程输入。无法弄清楚为什么会发生这种情况。请找到以下代码:

#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#include <ctype.h>
#include <string.h>
#include "hash.h"

void process_files(char*, int* , int, hashtable_t* );

void initialize_word(char *c,int size)
{
    int i;
    for(i=0;i<size;i++)
        c[i]=0;

    return;
}



char* readFilesList(MPI_File fh, char* file,int rank, int nprocs, char* block, const int overlap, int* length)
{
    char *text;
    int blockstart,blockend;

    MPI_Offset size;
    MPI_Offset blocksize;
    MPI_Offset begin;
    MPI_Offset end;
    MPI_Status status;

    MPI_File_open(MPI_COMM_WORLD,file,MPI_MODE_RDONLY,MPI_INFO_NULL,&fh);
    MPI_File_get_size(fh,&size);

    /*Block size calculation*/
    blocksize = size/nprocs;
    begin = rank*blocksize;
    end = begin+blocksize-1;

    end+=overlap;

    if(rank==nprocs-1)
        end = size;

    blocksize = end-begin+1;

    text = (char*)malloc((blocksize+1)*sizeof(char));
    MPI_File_read_at_all(fh,begin,text,blocksize,MPI_CHAR, &status);
    text[blocksize+1]=0;

    blockstart = 0;
    blockend = blocksize;

    if(rank!=0)
    {
        while(text[blockstart]!='\n' && blockstart!=blockend) blockstart++;
        blockstart++;
    }

    if(rank!=nprocs-1)
    {

        blockend-=overlap;
        while(text[blockend]!='\n'&& blockend!=blocksize) blockend++;
    }



    blocksize = blockend-blockstart;

    block = (char*)malloc((blocksize+1)*sizeof(char));
    block = memcpy(block, text + blockstart, blocksize);
    block[blocksize]=0;
    *length = strlen(block);

    MPI_File_close(&fh);
    return block;
}

void calculate_term_frequencies(char* file, char* text, hashtable_t *hashtable,int rank)
{
    printf("Start File %s, rank %d \n\n ",file,rank);
    fflush(stdout);
    if(strlen(text)!=0||strlen(file)!=0)
    {

        int i,j;
        char w[100];
        i=0,j=0;
        while(text[i]!=0)
        {
            if((text[i]>=65&&text[i]<=90)||(text[i]>=97&&text[i]<=122))
            {
                w[j]=text[i];
                j++; i++;
            }

            else
            {

                w[j] = 0;
                if(j!=0)
                {
                    //ht_set( hashtable, strcat(strcat(w,"#"),file),1);
                }
                j=0;
                i++;
                initialize_word(w,100);
            }

        }
    }
    return;
}

void readFile(char* filename, hashtable_t *hashtable,int rank)
{
    MPI_Status stat;
    MPI_Offset size;
    MPI_File fx;
    char* textFromFile=0;

    printf("Start File %d, rank %d \n\n ",strlen(filename),rank);
    fflush(stdout);

    if(strlen(filename)!=0)
    {
        MPI_File_open(MPI_COMM_WORLD,filename,MPI_MODE_RDONLY,MPI_INFO_NULL,&fx);
        MPI_File_get_size(fx,&size);

        printf("Start File %s, rank %d \n\n ",filename,rank);
        fflush(stdout);

        textFromFile = (char*)malloc((size+1)*sizeof(char));
        MPI_File_read_at_all(fx,0,textFromFile,size,MPI_CHAR, &stat);
        textFromFile[size]=0;
        calculate_term_frequencies(filename, textFromFile, hashtable,rank);

        MPI_File_close(&fx);

    }

    printf("Done File %s, rank %d \n\n ",filename,rank);
    fflush(stdout);
    return;   
}

void process_files(char* block, int* length, int rank,hashtable_t *hashtable)
{

    char s[2];
    s[0] = '\n';
    s[1] = 0;

    char *file;
    if(*length!=0)
    {
        /* get the first file */
        file = strtok(block, s);

        /* walk through other tokens */
        while( file != NULL ) 
        {
            readFile(file,hashtable,rank);
            file = strtok(NULL, s);
        }
    }
    return;
}

void execute_process(MPI_File fh, char* file, int rank, int nprocs, char* block, const int overlap, int * length, hashtable_t *hashtable)
{

    block = readFilesList(fh,file,rank,nprocs,block,overlap,length);
    process_files(block,length,rank,hashtable);
}


int main(int argc, char *argv[]){

    /*Initialization*/
    MPI_Init(&argc, &argv);
    MPI_File fh=0;
    int rank,nprocs,namelen;
    char *block=0;
    const int overlap = 70;
    char* file = "filepaths.txt";
    int *length = (int*)malloc(sizeof(int));

    hashtable_t *hashtable = ht_create( 65536 );

    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &nprocs);

    char processor_name[MPI_MAX_PROCESSOR_NAME];
    MPI_Get_processor_name(processor_name, &namelen);
    printf("Rank %d is on processor %s\n",rank,processor_name);
    fflush(stdout);

    execute_process(fh,file,rank,nprocs,block,overlap,length,hashtable);

    printf("Rank %d returned after processing\n",rank);
    MPI_Barrier(MPI_COMM_WORLD);

    MPI_Finalize();
    return 0;

}

filepaths.txt是一个包含普通文本文件的绝对文件名的文件:

例如:

/home/mpiuser/mpi/MPI_Codes/code/test1.txt
/home/mpiuser/mpi/MPI_Codes/code/test2.txt
/home/mpiuser/mpi/MPI_Codes/code/test3.txt

1 个答案:

答案 0 :(得分:0)

你的readFilesList函数非常令人困惑,我相信它并没有做你想做的事情,但也许我只是不理解它。我相信它应该从列表文件中为每个进程收集一堆文件名。每个流程的不同集合。它没有那样做,但这不是问题,即使这样做你想要的,后续的MPI IO也行不通。

读取文件时,使用MPI_File_read_all和MPI_COMM_WORLD作为通信器。这要求所有进程都参与读取此文件。现在,如果每个进程都应该读取不同的文件,这显然不会起作用。

因此,您的实现存在一些问题,但我无法真正解释您描述的行为,我宁愿先启动并尝试修复它们,然后再详细调试,可能会出现问题。

我的印象是,你希望在这些方面有一个算法:

  • 阅读文件名列表

  • 将该文件列表平均分配给所有进程

  • 让每个流程都在自己的文件集上工作

  • 对此处理中的数据执行某些操作

我建议用以下方法尝试:

  • 在单个进程上读取列表(无MPI IO)

  • 将文件列表分散到所有进程,以便所有进程都可以进行相同的工作量

  • 让每个进程独立地以串行方式处理其文件列表(串行文件访问和处理)

  • 根据需要使用MPI进行一些数据缩减

我相信,这将是您的方案中最好(最简单,最快)的策略。注意,这里根本没有涉及MPI IO。我不认为在第一步中对文件列表进行一些复杂的分布式读取会在这里产生任何优势,并且在实际处理中它实际上是有害的。您的流程越独立,通常的可扩展性就越好。