LU分解MPI

时间:2014-03-03 08:00:27

标签: mpi openmpi

这是LU分解的MPI代码。

我使用了以下策略 -

有一个主人(等级0),其他人是奴隶。主设备向每个从设备发送行。 由于每个从站可能会收到多个行,因此我将所有收到的行存储在a中 缓冲,然后对其执行LU分解。做完之后我发回去了 缓冲到主人。主人不做任何计算。它只是发送和接收。

for(i=0; i<n; i++)
    map[i] = i%(numProcs-1) + 1;

for(i=0; i<n-1; i++)
{
    if(rank == 0)
    {
        status = pivot(LU,i,n);

        for(j=0; j<n; j++)
            row1[j] = LU[n*i+j];
    }

    MPI_Bcast(&status, 1, MPI_INT, 0, MPI_COMM_WORLD);

    if(status == -1)
        return -1;

    MPI_Bcast(row1, n, MPI_DOUBLE, 0, MPI_COMM_WORLD);

    int tag1 = 1, tag2 = 2, tag3 = 3, tag4 = 4;

    if(rank == 0)
    {
        int pno, start, index, l, rowsReceived = 0;
        MPI_Request req;
        MPI_Status stat;

        for(j=i+1; j<n; j++)
            MPI_Isend(&LU[n*j], n, MPI_DOUBLE, map[j], map[j], MPI_COMM_WORLD, &req);

        if(i>=n-(numProcs-1))
            cnt++;

        for(j=0; j<numProcs-1-cnt; j++)
        {
            MPI_Recv(&pno, 1, MPI_INT, MPI_ANY_SOURCE, tag2, MPI_COMM_WORLD, &stat);
            //printf("1. Recv from %d and j : %d and i : %d\n",pno,j,i);
            MPI_Recv(&rowsReceived, 1, MPI_INT, pno, tag3, MPI_COMM_WORLD, &stat);
            MPI_Recv(rowFinal, n*rowsReceived, MPI_DOUBLE, pno, tag4, MPI_COMM_WORLD, &stat);

            /* Will not go more than numProcs anyways */
            for(k=i+1; k<n; k++)
            {
                if(map[k] == pno)
                {
                    start = k;
                    break; 
                }
            }

            for(k=0; k<rowsReceived; k++)
            {
                index = start + k*(numProcs-1);

                for(l=0; l<n; l++)
                    LU[n*index+l] = rowFinal[n*k+l];
            }
        }
    }

    else
    {
        int rowsReceived = 0;
        MPI_Status stat, stats[3];
        MPI_Request reqs[3];

        for(j=i+1; j<n; j++)
            if(map[j] == rank)
                rowsReceived += 1;


        for(j=0; j<rowsReceived; j++)
        {
            MPI_Recv(&rowFinal[n*j], n, MPI_DOUBLE, 0, rank, MPI_COMM_WORLD, &stat);
        }

        for(j=0; j<rowsReceived; j++)
        {
            double factor = rowFinal[n*j+i]/row1[i];

            for(k=i+1; k<n; k++)
                rowFinal[n*j+k] -= (row1[k]*factor);

            rowFinal[n*j+i] = factor;
        }

        if(rowsReceived != 0)
        {
            //printf("Data sent from %d iteration : %d\n",rank,i);
            MPI_Isend(&rank, 1, MPI_INT, 0, tag2, MPI_COMM_WORLD, &reqs[0]);
            MPI_Isend(&rowsReceived, 1, MPI_INT, 0, tag3, MPI_COMM_WORLD, &reqs[1]);
            MPI_Isend(rowFinal, n*rowsReceived, MPI_DOUBLE, 0, tag4, MPI_COMM_WORLD, &reqs[2]);
        }
        //MPI_Waitall(3,reqs,stats);
    }
}

我面临的问题是有时程序会挂起。我的猜测是 发送和接收没有匹配,但我无法匹配 找出问题所在。

我在大小为1000x1000,2000x2000,3000x3000,5000x5000的矩阵上运行测试用例 和7000x7000。 目前代码挂起7000x7000 。请有人帮忙 我出去了吗?

注意事项: -

  1. map 实现了映射方案,哪一行转到哪个slave。

  2. rowsReceived 告诉每个从属设备它将接收的行数。我不需要 每次计算,但我稍后会修复它。

  3. row1 是存储活动行的缓冲区。

  4. rowFinal 是正在接收和修改的行的缓冲区。

  5. cnt 并不重要,可以忽略。为此检查 rowReceived!= 0需要删除。

1 个答案:

答案 0 :(得分:0)

看起来你永远不会完成非阻塞操作。在整个代码中,您有大量的MPI_IsendMPI_Irecv来电,但您永远不会进行MPI_WaitMPI_Test(或其中一次类似的通话)。如果没有完成调用,那些非阻塞调用将永远不会完成。