【问题标题】:Using MPI_Reduce in c在 c 中使用 MPI_Reduce
【发布时间】:2011-01-20 07:21:44
【问题描述】:

我正在尝试使用 MPI 库在 c 中编写程序。 在我的程序中,我正在解决 TSP(但不是使用任何特殊算法......)。 我的输入参数是int nCitesint xCoord[]int yCoord[]。 我将它们捆绑到Coordinates 并使用MPI_Bcast 使它们可用于所有线程。

我的问题是:在计算完每个线程中所有路径的权重后,我想将它们减少为一个结果,最好的一个。我试过使用MPI_Reduce,但是有些东西,这就是我感到困惑的地方,会导致分段错误(仅在一个线程中,通常是root)。

这是主要代码和结构:

typedef struct Coordinates_t {
    int* x;
    int* y;
    int n;
} Coordinates;

typedef struct PathAndLength_t {
    int* path;
    int pathSize;
    int length;
} PathAndLength;

void comparePaths(void* a, void* b, int* len, MPI_Datatype* dataType) {
    ...
}

int tsp_main(int nCites, int xCoord[], int yCoord[], int P[]){
    int numOfProcs, rank;
    if (MPI_Comm_size(MPI_COMM_WORLD, &numOfProcs))
        throw "Error: MPI_Comm_size failed";
    if (MPI_Comm_rank(MPI_COMM_WORLD, &rank))
        throw "Error: MPI_Comm_rank failed";

    Coordinates crds;
    crds.x = xCoord;
    crds.y = yCoord;
    crds.n = nCites;

    MPI_Datatype data;
    createInDataType(&crds, &data);

    if (MPI_Bcast(&crds, 1, data, 0, MPI_COMM_WORLD))
        throw "Error: MPI_Comm_size failed";

        ...

    PathAndLength* pal = (PathAndLength*)malloc(sizeof(PathAndLength));
    pal->path = (int*)malloc(sizeof(int)*crds.n);

    pal->length = min_length;
    for (int i = 0; i < crds.n; ++i) {
        (pal->path)[i] = min_path[i];
    }
    pal->pathSize = crds.n;
    MPI_Datatype outDatatype;
    MPI_Op op;

    createOutDataType(pal, &outDatatype);

    MPI_Op_create(&comparePaths, 1, &op);

    PathAndLength* result = (PathAndLength*)malloc(sizeof(PathAndLength));
    result->path = (int*)malloc(sizeof(int)*crds.n);
    MPI_Reduce(pal, result, crds.n, outDatatype, op, 0, MPI_COMM_WORLD);

    ...

    return result->length;
}

这些是我在代码中使用的createOutDataTypecreateInDataType

void createInDataType(Coordinates* indata, MPI_Datatype* message_type_ptr) {
    // Build a derived datatype
    int block_lengths[3];
    MPI_Aint displacements[3];
    MPI_Aint addresses[4];
    MPI_Datatype typelist[3];

    // First specify the types
    typelist[0] = typelist[1] = typelist[2] = MPI_INT;

    // Specify the number of elements of each type
    block_lengths[0] = block_lengths[1] = indata->n;
    block_lengths[2] = 1;

    // Calculate the displacements of the members relative to indata
    MPI_Address(indata, &addresses[0]);
    MPI_Address(indata->x, &addresses[1]);
    MPI_Address(indata->y, &addresses[2]);
    MPI_Address(&indata->n, &addresses[3]);
    displacements[0] = addresses[1] - addresses[0];
    displacements[1] = addresses[2] - addresses[0];
    displacements[2] = addresses[3] - addresses[0];

    // Create the derived type
    MPI_Type_struct(3, block_lengths, displacements, typelist, message_type_ptr);

    // Commit it so that it can be used
    MPI_Type_commit(message_type_ptr);
}

void createOutDataType(PathAndLength* outdata, MPI_Datatype* message_type_ptr) {
    // Build a derived datatype
    int block_lengths[2];
    MPI_Aint displacements[2];
    MPI_Aint addresses[3];
    MPI_Datatype typelist[2];

    // First specify the types
    typelist[0] = MPI_INT;
    typelist[1] = MPI_INT;

    // Specify the number of elements of each type
    block_lengths[0] = outdata->pathSize;
    block_lengths[1] = 1;

    // Calculate the displacements of the members relative to outdata
    MPI_Address(outdata, &addresses[0]);
    MPI_Address(outdata->path, &addresses[1]);
    MPI_Address(&outdata->length, &addresses[2]);
    displacements[0] = addresses[1] - addresses[0];
    displacements[1] = addresses[2] - addresses[0];

    // Create the derived type
    MPI_Type_struct(2, block_lengths, displacements, typelist, message_type_ptr);

    // Commit it so that it can be used
    MPI_Type_commit(message_type_ptr);
}

很抱歉包含这么多代码,但我无法确定哪些无关紧要(如果有的话)...
谢谢。

【问题讨论】:

    标签: c parallel-processing mpi


    【解决方案1】:
    PathAndLength* result = (PathAndLength*)malloc(sizeof(PathAndLength));
    result->path = (int*)malloc(sizeof(int)*crds.n);
    MPI_Reduce(pal, result, crds.n, outDatatype, op, 0, MPI_COMM_WORLD);
    

    您将crds.n*outDatatypes 接收到大小为sizeof(PathAndLength) 的结果缓冲区中。你似乎有设计缺陷。

    【讨论】:

    • +1,应该只是 1 outDatatype: MPI_Reduce(pal, result, 1, outDatatype, op, 0, MPI_COMM_WORLD);
    • 这是怎么回事?我的印象是outDatatype 将被插入到result 中,而crds.n 只是为了方便我的一个参数,它将被发送到我的MPI_Op 函数中。伙计,那是 12 小时的调试时间...... RTFM 嗯?
    • @sus 最有可能,但很难说:PathAndLength 有指针成员 - 对 mpi 不友好
    • @aaa:我宁愿说“对开发人员不友好”。只要您完全清楚每个进程的内存中的内容并相应地定义数据类型,指针成员就没有任何问题。不过,问题中的解决方案对我来说确实不错。
    • @sus,它对我来说看起来也不错,但是在我按照你的建议修复了前面的代码之后(...result, 1, outDatatype...),我仍然有一些内存访问问题.另外,当我说我只有一种数据类型时,它就像我在撒谎一样。所以我稍微改变了设计,将指针移出结构,现在一切似乎都工作正常。
    猜你喜欢
    • 2015-02-14
    • 1970-01-01
    • 2013-01-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-24
    • 2014-01-25
    相关资源
    最近更新 更多