Jul 30

MPI 简单上手 不指定

felix021 @ 2013-7-30 18:47 [IT » 程序设计] 评论(0) , 引用(0) , 阅读(20766) | Via 本站原创 | |
简单地说,MPI 就是个并行计算框架,模型也很直接——就是多进程。和hadoop不同,它不提供计算任务的map和reduce,只提供了一套通信接口,需要程序员来完成这些任务;它也不提供冗余容错等机制,完全依赖于其下层的可靠性。但是因为把控制权几乎完全交给了程序员,所以有很大的灵活性,可以最大限度地榨取硬件性能。超级计算机上的运算任务,基本上都是使用MPI来开发的。

~ 下载编译安装:

现在貌似一般都用MPICH,开源的MPI库,可以从这里获取: http://www.mpich.org/ ,现在的最新版本是3.0.4,编译安装过程可以参考安装包里的README的说明,基本步骤如下(万恶的configure):

引用

$ wget http://www.mpich.org/static/downloads/3.0.4/mpich-3.0.4.tar.gz
$ tar zxf mpich-3.0.4.tar.gz
$ cd mpich-3.0.4
$ mkdir ~/mpich
$ ./configure --prefix=$HOME/mpich --disable-f77 --disable-fc 2>&1 | tee c.txt #我禁用了fortran的支持
$ make -j4 2>&1 | tee m.txt
$ make install 2>&1 | tee i.txt
$ echo 'export PATH=$PATH:~/mpich/bin' >> ~/.bashrc


下面给出三个例子,参考教程:http://wenku.baidu.com/view/ee8bf3390912a216147929f3.html (注:22页有BUG,它把 MPI_Comm_XXX 错写成了 MPI_Common_xxx //包括全大写版本,共四处),给出了MPI框架中最常用、最基础的6个API的例子。更复杂的API可以参考mpich的手册。这些例子只是简单地演示了MPI框架的使用;实际上在使用MPI开发并行计算的软件时,还需要考虑到很多方面的问题,这里就不展开说了(其实真相是我也不会-.-,有兴趣的话可以请教 @momodi@dumbear 两位)。

1. 最简单的:Hello world

代码如下: hello.c
#include <stdio.h>
#include <mpi.h>

int main(int argc, char *argv[])
{
    MPI_Init(&argc, &argv); //初始化MPI环境

    printf("Hello world!\n");

    MPI_Finalize(); //结束MPI环境
    return 0;
}


编译:
$ mpicc -o hello hello.c

运行:
$ mpiexec -n 4 ./hello
Hello world!
Hello world!
Hello world!
Hello world!

可以看到这里启动了4个进程。注意 -n 和 4 之间一定要有空格,否则会报错。


2. 进程间通信

MPI最基本的通信接口是 MPI_Send/MPI_Recv:

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

int main(int argc, char *argv[])
{
    int myid, numprocs, source, msg_tag = 0;
    char msg[100];

    MPI_Status status;

    MPI_Init(&argc, &argv);

    MPI_Comm_size(MPI_COMM_WORLD, &numprocs); //共启动几个进程
    MPI_Comm_rank(MPI_COMM_WORLD, &myid);  //当前进程的编号(0~n-1)

    printf("I'm %d of %d\n", myid, numprocs);
    if (myid != 0)
    {
        int len = sprintf(msg, "hello from %d", myid);
        MPI_Send(msg, len, MPI_CHAR, 0, msg_tag, MPI_COMM_WORLD); //向id=0的进程发送信息
    }
    else
    {
        for (source = 1; source < numprocs; source++)
        {
            //从id=source的进程接受消息
            MPI_Recv(msg, 100, MPI_CHAR, source, msg_tag, MPI_COMM_WORLD, &status);
            printf("from %d: %s\n", source, msg);
        }
    }

    MPI_Finalize();
    return 0;
}


编译运行:
$ mpicc comm.c
$ mpiexec -n 4 ./a.out
I'm 0 of 4
from 1: hello from 1
from 2: hello from 2
I'm 1 of 4
I'm 2 of 4
from 3: hello from 3
I'm 3 of 4


3. 来个复杂点的:数数前1亿个自然数里有几个 雷劈数

代码后附,答案是97(真少),不过这不是重点,重点是MPI对硬件的利用率是怎样 :D

测试机器是 16核 AMD Opteron 6128HE @2GHz,32G内存

单进程(无MPI版本):56.9s
4进程:15.3s
8进程:7.85s
12进程:5.35s

考虑到16核跑满可能会受到其他进程的影响(性能不稳定,4.2~4.9s),这个数据就不列进来比较了。

可以看出来,在这个例子里,因为通信、同步只有在计算完之后才有那么一点点,所以在SMP架构下,耗费的时间基本上是跟进程数成反比的,说明MPI框架对硬件性能的利用率还是相当高的。

具体代码如下:
#include <stdio.h>
#include <mpi.h>

int is_lp(long long x)
{
    long long t = x * x, i = 10;
    while (i < t)
    {
        long long l = t / i, r = t % i;
        if (l + r == x)
            return 1;
        i *= 10;
    }
    return 0;
}

int main(int argc, char *argv[])
{
    int myid, numprocs, source;
    const int N = 100000000;

    MPI_Status status;

    MPI_Init(&argc, &argv);
    MPI_Comm_rank(MPI_COMM_WORLD, &myid);
    MPI_Comm_size(MPI_COMM_WORLD, &numprocs);

    printf("I'm %d of %d\n", myid, numprocs);
    int start = myid * (N / numprocs), stop = (myid + 1) * (N / numprocs);
    if (myid == numprocs - 1)
        stop = N;
    printf("start from %d to %d\n", start, stop);
    int ans = 0, i;
    for (i = start; i < stop; i++)
        if (is_lp(i))
            ans += 1;
    printf("%d finished calculation with %d numbers\n", myid, ans);

    if (myid != 0)
    {
        MPI_Send(&ans, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
    }
    else
    {
        int tmp;
        for (source = 1; source < numprocs; source++)
        {
            MPI_Recv(&tmp, 1, MPI_INT, source, 0, MPI_COMM_WORLD, &status);
            printf("from %d: %d\n", source, tmp);
            ans += tmp;
        }
        printf("final ans: %d\n", ans);
    }

    MPI_Finalize();
    return 0;
}


转载请注明出自 ,如是转载文则注明原出处,谢谢:)
RSS订阅地址: http://www.felix021.com/blog/feed.php
发表评论
表情
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
打开HTML
打开UBB
打开表情
隐藏
记住我
昵称   密码   *非必须
网址   电邮   [注册]