【问题标题】:Sum of the number 1 to 10000 using MPI_Scatter使用 MPI_Scatter 的数字 1 到 10000 的总和
【发布时间】:2021-12-09 06:24:06
【问题描述】:

我目前正在开发一段包含 10 个进程的代码。进程 0 共读取 10000 个(来自 lab7.csv)。之后,它将数组分发给所有进程。为了做到这一点,我创建了一个名为“intArray[10000]”的数组,由所有进程共享。 49893236 是正确的总和。

以下代码使用 10 个处理器计算从 1 到 1000 范围内的数字的总和。此聚合由每个处理器计算,结果显示在屏幕上。

结果显示跟随错误。

我没有弄清楚问题是什么。请在这件事上帮助我。

#include <mpi.h>
#include <stdio.h>
#include <string.h>

int main()
{
        int rank, nodes;
        MPI_Init(NULL, NULL);
        MPI_Comm_rank(MPI_COMM_WORLD, &rank);
        MPI_Comm_size(MPI_COMM_WORLD, &nodes);
        MPI_Status status;

        int intArray[10000];
        int subIntArray[1000];

        if(rank == 0) {
                // Substitute the full file path for the string file_path
                FILE *fp = fopen("./lab7.csv", "r");

                int i = 0;
                int num;

                if (!fp) {
                        printf("Can't open file\n");
                } else {
                        while (fscanf(fp, "%d", &num) > 0)
                        {
                                intArray[i] = num;
                                i++;
                        }
                        // Close the file
                        fclose(fp);
                }
        }

        MPI_Scatter(intArray, 10000, MPI_INT, subIntArray, 1000, MPI_INT, 0, MPI_COMM_WORLD);


        int ans = 0;
        int total = 0;

        int start = rank * 1000;
        int end = start + 999;

        for(int i = start; i <= end; i++) {
                ans = ans + subIntArray[i];
        }

        if(rank != 0) {
                MPI_Ssend(&ans, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
        } else {
                total = ans;
                for(int j = 1; j < 10; j++) {
                        MPI_Recv(&ans, 1, MPI_INT, j, 0, MPI_COMM_WORLD, &status);
                        total += ans;
                }
                printf("Total is %d\n", total);
        }

        MPI_Finalize();
        return 0;
}

作为关注者的 PBS Job 文件,

#PBS -l nodes=2
#PBS -l walltime=00:02:00
#PBS -l select=5
cat $PBS_NODEFILE
NPROC=10
cd $PBS_O_WORKDIR
MPISIZE=$NPROC
MPIPROG=`basename $PBS_JOBNAME .pbs`
echo 'Running MPI program' $MPIPROG 'on' $MPISIZE 'processes'
echo 'Started at' `date`
echo '--------------------------------------------------------------------------------'
(time mpirun -n $MPISIZE ./$MPIPROG) 2>&1
echo '--------------------------------------------------------------------------------'
echo 'Finished at' `date`

这是显示在终端上的错误信息。

【问题讨论】:

    标签: c parallel-processing


    【解决方案1】:

    MPI_Scatter 的方向与您的方向有点不同。

    你说:我有NTOT 数据元素,我想将它们发送到NODECOUNT 节点,所以我希望每个节点处理NTOT / NODECOUNT 的数据。如果NTOT 不是NODECOUNT 的精确倍数不是,这不起作用

    但是,MPI_Scatter 的方向相反:我有 NPER 每个节点应该处理的元素数量,以及 NODECOUNT 节点,所以元素的总数是 NTOT = NPER * NODECOUNT 这就是手册页示例显示它。

    您想将NPER 计数为MPI_Scatter NTOT。而且,您希望发送和接收计数匹配。

    另外,因为MPI_Scatter 为您进行拆分,从属节点应该使用您计算的start/end,但始终使用:

    start = 0;
    end = NPER - 1;
    

    另外,在您的代码中...

    您正在对subIntArray 进行索引,就好像您可以访问0-9999 而不是0-999,所以您超出了数组的末尾并且有UB(未定义的行为)

    到处硬连线101001000 有点不稳定。最好使用一些#define 和实际的节点代码nodes

    并且,您假设您有 10000 个有效的输入数据元素,而不是在您执行 fscanf 时根据您的 i 索引变量来计算它


    这是更正后的代码,我使用了一些额外的调试代码。

    我使用预处理器条件来表示旧代码与新代码(例如):

    #if 0
    // old code
    #else
    // new code
    #endif
    
    #if 1
    // new code
    #endif
    

    另外,我没有你的数据文件,所以我必须合成输入数据。

    不管怎样,这里是:

    #include <mpi.h>
    #include <stdio.h>
    #include <string.h>
    #include <stdarg.h>
    #include <unistd.h>
    
    int rank;
    int nodes;
    FILE *xfdbg;
    
    #define dbgprtattr(_lvl) \
        __attribute__((__format__(__printf__,_lvl,_lvl + 1)))
    
    #if DEBUG || _USE_ZPRT_
    #define dbgprt(_fmt...) \
        _dbgprt(_fmt)
    #else
    #define dbgprt(_fmt...) \
        do { } while (0)
    #endif
    
    void dbgprtattr(1)
    _dbgprt(const char *fmt,...)
    {
        va_list ap;
        char buf[10000];
        char *bp = buf;
    
        bp += sprintf(bp,"[%d] ",rank);
    
        va_start(ap,fmt);
        bp += vsprintf(bp,fmt,ap);
        va_end(ap);
    
        fputs(buf,xfdbg);
        fflush(xfdbg);
    }
    
    //#define NTOT      10000
    //#define NPER      (NTOT / nodes)
    
    int
    main()
    {
    
        MPI_Init(NULL, NULL);
        MPI_Comm_rank(MPI_COMM_WORLD, &rank);
        MPI_Comm_size(MPI_COMM_WORLD, &nodes);
        MPI_Status status;
    
        char logf[100];
        sprintf(logf,"log_%2.2d",rank);
        xfdbg = fopen(logf,"w");
    
    #if 0
        int BIGSIZE = nodes * 1000;
        int NPER = NTOT / nodes;
    #else
        //int NPER = 1000;
        int NPER = 50;
        //int NTOT = NPER * nodes;
    #endif
    
        int val;
        int truetotal = 0;
    
    #if 0
        int intArray[NTOT];
    #else
        int intArray[nodes][NPER];
    #endif
    
    #if 1
        int subIntArray[NPER];
    #else
        int subIntArray[NTOT];
    #endif
    
        if (rank == 0) {
    #if 0
            // Substitute the full file path for the string file_path
            FILE *fp = fopen("./lab7.csv", "r");
    
            int i = 0;
            int num;
    
            if (!fp) {
                printf("Can't open file\n");
            }
            else {
                while (fscanf(fp, "%d", &num) > 0) {
                    intArray[i] = num;
                    i++;
                }
                // Close the file
                fclose(fp);
            }
    #endif
    
            for (int nd = 0;  nd < nodes;  ++nd) {
                for (int i = 0;  i < NPER;  ++i) {
                    val = (nd << 16) | i;
                    intArray[nd][i] = val;
                    truetotal += val;
                }
            }
        }
    
        dbgprt("main: hello\n");
    #if 0
        MPI_Scatter(intArray, NTOT, MPI_INT,
            subIntArray, NPER, MPI_INT,
            0, MPI_COMM_WORLD);
        dbgprt("main: post\n");
    #endif
    #if 1
        MPI_Scatter(intArray, NPER, MPI_INT,
            subIntArray, NPER, MPI_INT,
            0, MPI_COMM_WORLD);
        dbgprt("main: post\n");
    #endif
    #if 0
        MPI_Scatter(intArray, NTOT, MPI_INT,
            subIntArray, NTOT, MPI_INT,
            0, MPI_COMM_WORLD);
        dbgprt("main: post\n");
    #endif
    
        //sleep(10);
    
        int ans = 0;
        int total = 0;
    
    #if 0
        int start = rank * NPER;
        int end = start + NPER - 1;
    #else
        int start = 0;
        int end = NPER - 1;
    #endif
    
        dbgprt("main: START start=%d end=%d\n",start,end);
    
        for (int i = start; i <= end; i++) {
            dbgprt("main: DATA i=%d sub=%8.8X\n",i,subIntArray[i]);
            ans = ans + subIntArray[i];
        }
    
        dbgprt("main: loopdone ans=%d\n",ans);
    
        if (rank != 0) {
            MPI_Ssend(&ans, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
        }
        else {
            total = ans;
            for (int j = 1; j < nodes; j++) {
                MPI_Recv(&ans, 1, MPI_INT, j, 0, MPI_COMM_WORLD, &status);
                total += ans;
            }
            printf("Total is %d\n", total);
            printf("Total is %d (TRUE)\n", truetotal);
    
        }
    
        fclose(xfdbg);
    
        MPI_Finalize();
        return 0;
    }
    

    【讨论】:

    • 非常感谢您的帮助,但我很抱歉?。我没明白。我很难吸收,但我正在努力。
    • 不用担心。多想一想,多看几遍。如果您仍然卡住,您可以在这里评论您 [现在] 理解的内容以及您仍然遇到的问题。我也许可以增强/扩展我的解释或在代码中添加更好的 cmets 以提供帮助
    猜你喜欢
    • 1970-01-01
    • 2022-11-17
    • 1970-01-01
    • 2013-11-30
    • 2017-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多