【问题标题】:MPI_Scatterv: segmentation fault 11 on process 0 onlyMPI_Scatterv:仅在进程 0 上出现分段错误 11
【发布时间】:2014-10-30 21:57:44
【问题描述】:

我正在尝试在属于超立方体组(快速排序项目)的进程之间分散值。 根据进程的数量,我要么创建一个不包括过多进程的新通信器,要么复制 MPI_COMM_WORLD,如果它恰好适合任何超立方体(2 的幂)。

在这两种情况下,除 0 之外的进程都会收到它们的数据,但是: - 在第一种情况下,进程 0 引发分段错误 11 - 在第二种情况下,没有任何错误,但进程 0 收到的值是乱码。

注意:如果我尝试使用常规的 MPI_Scatter,一切正常。

//Input
vector<int> LoadFromFile();

int d;                      //dimension of hypercube
int p;                      //active processes
int idle;                   //idle processes 
vector<int> values;         //values loaded
int arraySize;              //number of total values to distribute

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

int mpiRank; 
int mpiSize;

MPI_Init(&argc, &argv);

MPI_Comm_rank(MPI_COMM_WORLD, &mpiWorldRank);
MPI_Comm_size(MPI_COMM_WORLD, &mpiWorldSize);
MPI_Comm MPI_COMM_HYPERCUBE;

d = log2(mpiWorldSize);     
p = pow(2, d);                  //Number of processes belonging to the hypercube
idle = mpiWorldSize - p;        //number of processes in excess
int toExclude[idle];            //array of idle processes to exclude from communicator
int sendCounts[p];              //array of values sizes to be sent to processes

//
int i = 0;
while (i < idle)
{
    toExclude[i] = mpiWorldSize - 1 - i;
    ++i;
}

//CREATING HYPERCUBE GROUP: Group of size of power of 2 -----------------
MPI_Group world_group;
MPI_Comm_group(MPI_COMM_WORLD, &world_group);

// Remove excessive processors if any from communicator
if (idle > 0)
{
    MPI_Group newGroup;     
    MPI_Group_excl(world_group, 1, toExclude, &newGroup);
    MPI_Comm_create(MPI_COMM_WORLD, newGroup, &MPI_COMM_HYPERCUBE);
    //Abort any processor not part of the hypercube.    
    if (mpiWorldRank > p)
    {
        cout << "aborting: " << mpiWorldRank <<endl;
        MPI_Finalize();
        return 0;
    }   
}   
else 
{
    MPI_Comm_dup(MPI_COMM_WORLD, &MPI_COMM_HYPERCUBE);
}

MPI_Comm_rank(MPI_COMM_HYPERCUBE, &mpiRank);
MPI_Comm_size(MPI_COMM_HYPERCUBE, &mpiSize);
//END OF: CREATING HYPERCUBE GROUP --------------------------

if (mpiRank == 0)
{
    //STEP1: Read input
    values = LoadFromFile();
    arraySize = values.size();
}

//Transforming input vector into an array
int valuesArray[values.size()];
if(mpiRank == 0)
{
    copy(values.begin(), values.end(), valuesArray);
}

//Broadcast input size to all processes
MPI_Bcast(&arraySize, 1, MPI_INT, 0, MPI_COMM_HYPERCUBE);

//MPI_Scatterv: determining size of arrays to be received and displacement
int nmin = arraySize / p;
int remainingData = arraySize % p;
int displs[p];
int recvCount;

int k = 0;
for (i=0; i<p; i++)
{
    sendCounts[i] = i < remainingData
        ? nmin+1
        : nmin;
    displs[i] = k;
    k += sendCounts[i];
}

recvCount = sendCounts[mpiRank];
int recvValues[recvCount];

//Following MPI_Scatter works well:     
// MPI_Scatter(&valuesArray, 13, MPI_INT, recvValues , 13, MPI_INT, 0, MPI_COMM_HYPERCUBE);

MPI_Scatterv(&valuesArray, sendCounts, displs, MPI_INT, recvValues , recvCount, MPI_INT, 0, MPI_COMM_HYPERCUBE);

int j = 0;
while (j < recvCount)
{
    cout << "rank " << mpiRank << " received: " << recvValues[j] << endl;
    ++j;
}   

MPI_Finalize();
return 0;
}

【问题讨论】:

  • 我会为所有可能失败的操作和一堆调试输出(printf 或类似)添加错误检查。如果值不是您认为的值或操作失败,则有一堆数组可能会溢出。拥有多进程使得通过手动读取代码来调试变得更加困难或不可能。

标签: c++ c openmpi scatter scatterview


【解决方案1】:

首先,您向MPI_Group_excl 提供了错误的参数:

MPI_Group_excl(world_group, 1, toExclude, &newGroup);
//                          ^

第二个参数指定排除列表中的条目数,因此应该等于idle。由于您仅排除单个等级,因此生成的组具有mpiWorldSize-1 等级,因此MPI_Scatterv 预计sendCounts[]displs[] 都具有那么多元素。其中只有p 元素被正确初始化,其余的都是随机的,因此MPI_Scatterv 在根目录中崩溃。

另一个错误是中止空闲进程的代码:它应该读取if (mpiWorldRank &gt;= p)

我建议将整个排除代码替换为对 MPI_Comm_split 的一次调用:

MPI_Comm comm_hypercube;
int colour = mpiWorldRank >= p ? MPI_UNDEFINED : 0;

MPI_Comm_split(MPI_COMM_WORLD, colour, mpiWorldRank, &comm_hypercube);
if (comm_hypercube == MPI_COMM_NULL)
{
   MPI_Finalize();
   return 0;
}

当没有进程提供MPI_UNDEFINED 作为其颜色时,调用等效于MPI_Comm_dup

请注意,您应避免在以 MPI_ 开头的代码名称中使用,因为这些名称可能与 MPI 实现中的符号冲突。

附加说明:std::vector&lt;T&gt; 使用连续存储,因此您可以不将元素复制到常规数组中,只需提供对 MPI_Scatter(v) 的调用中第一个元素的地址:

MPI_Scatterv(&values[0], ...);

【讨论】:

    猜你喜欢
    • 2021-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-02
    • 2016-08-06
    • 2021-04-26
    • 1970-01-01
    • 2014-11-29
    相关资源
    最近更新 更多