BSP模型简介
使用的BSP模型是基于MPI编译的BSPonMPI
项目连接: wijnand-suijlen/bsponmpi: BSPlib implementation on top MPI
项目里的版本较低,最新版在官网里
官网: BSPonMPI
文档:refman.pdf
编译和使用
这里下载的是BSPonMPI2.0,编译和运行与MPI的命令类似
编译 注意-lbsponmpi参数
1 | mpicc ./hello.c -o hello -lbsponmpi |
运行
1 | mpirun -np 4 example |
使用时引入头文件
1 |
BSPonMPI使用的是c99,标准,不支持c++,如restrict
关键字等使用导致c++编译器无法编译引入bsp.h的程序
编译成功后把libbsponmpi.so.0动态链接库的位置添加到环境变量中。
1 | export LD_LIBRARY_PATH=/path/to/library:$LD_LIBRARY_PATH |
BSP使用
bsp.h存在如下函数
1 | /** @name Initialisation */ |
初始化函数
bsp_init
1 | void bsp_init (void(∗)(void) spmd_part, int argc, char ∗ argv[]) |
类似于MPI::Init()
在程序开始时调用该函数
第一个参数是用来执行并行部分函数的地址
1 | bsp_init(&spmd_part, argc, argv); |
bsp_begin
1 | void bsp_begin (int maxprocs) |
并行部分的开始,参数是用于分配进程的数量。
这里进程数可自己设置-np参数设置的进程数不一定全部会用上。但不会超过这个数
bsp_end
1 | void bsp_end () |
在并行化部分执行完后调用该函数,该函数之后的代码仅由0号进程执行
终止函数
bsp_abort
1 | void bsp_abort (const char ∗ format, ...) |
终止函数,终止程序并打印信息,参数类似于printf
注:spmd_part()
中不在bsp_begin
中的部分会在调用bsp_init
时多执行一遍,而不是主动调用spmd_part
时去执行。主动去调用spmd_part()
时也只会从bsp_begin
开始去执行
查询函数
bsp_nprocs
1 | int bsp_nprocs () |
返回可用/已分配的进程数
bsp_init()
执行过,但bsp_begin()
没有执行官,返回可用的进程数
两个函数都执行过,返回已分配进程数
如果都没执行过,返回错误代码-1
bsp_pid
1 | int bsp_pid () |
返回当前进程号。
类似于MPI::COMM_WORLD.Get_rank()
bsp_time()
1 | double bsp_time () |
返回从bsp_begin()
开始所经过的时间
supersteps函数
bsp_sync()
1 | void bsp_sync () |
划分supersteps
bsp_sync()
前后为两步supersteps
内存管理函数
bsp_push_reg
1 | void bsp_push_reg (const void ∗ ident, int size) |
使指定大小的内存空间可用,内存空间可以用于下一步的supersteps中内存的操作
不加这个,无法对目标内存进行bsp_put
和bsp_get
操作
参数
- ident 指向一块内存的指针
- size 内存大小
bsp_pop_reg
1 | void bsp_pop_reg (const void ∗ ident) |
注销内存位置
bsp_pop_reg
用完后注销掉
参数
- ident 指向目标内存的指针
bsp_put
1 | void bsp_put (int pid, const void ∗ src, void ∗ dst, int offset, int nbytes) |
在下一个supersteps中,给目标进程的目标位置特定的数据,其他进程数据不变
参数
- pid 目标进程号
- src 指向源位置的指针
- dst 指向目标位置的指针
- offset dst上的偏移
- nbytes 发送的字节数
bsp_get
1 | void bsp_get (int pid, const void ∗ src, int offset, void ∗ dst, int nbytes) |
在下一个supersteps中从其他进程获取数据
参数
- pid 源进程号
- src 指向源的指针
- offset src上的偏移
- dst 目标位置
- nbytes
结合bsp_sync
bsp_get
和bsp_put
两个函数仅仅作为缓冲,不会立刻改变内存,只有调用了bsp_sync
后内存才会刷新
简单的进程间通信
1 |
|
1 | $ mpirun -np 5 ./hello |
BSMP函数
bsp_send
1 | void bsp_send (int pid, const void ∗ tag, const void ∗ payload, int payload_nbytes) |
给一个进程发送信息,可以发送tag和payload,tag默认发送的大小为0,需要在bsp_set_tagsize()
单独设置
经过实验,bsp_send
也要加bsp_sync
才能保障消息进入消息队列
参数
- pid 目标进程号
- tag 指向tag的指针
- payload 指向payload的指针
- payload_nbytes 发送信息的大小
bsp_qsize
1 | void bsp_qsize (int ∗restrict nmessages, int ∗restrict accum_nbytes) |
给出队列中消息的数量和payload的大小总和。
结果直接赋值到两个指针中去
参数
- nmessages int类型的指针,指向的值会被设置成队列中消息的数量
- accum_nbytes int类型指针,指针的值会被设置成payload大小的和
bsp_get_tag
1 | void bsp_get_tag (int ∗restrict status, void ∗restrict tag) |
给出消息队列中tag和payload的大小
status返回payload,tag返回tag,具体同上
bsp_move
1 | void bsp_move (void ∗ payload, int reception_nbytes) |
从消息队列中接收数据
参数
- payload 指向一块足够大的内存空间
- reception_nbytes 最大接收数量
bsp_set_tagsize
1 | void bsp_set_tagsize (int ∗ tag_nbytes) |
为下一个superstep的tag设置大小
参数
- tag_nbytes 是一个int类型的指针,指向的是tag的大小
bsp_send和bsp_move实现进程间通信
1 |
|
1 | $ mpirun -np 5 ./hello |
高性能函数
1 | void bsp_hpput (int pid, const void ∗src, void ∗dst, int offset, int nbytes) |
这两个函数和bsp_put
,bsp_get
一模一样
由
1 | #define bsp_hpput bsp_put |
定义
1 | int bsp_hpmove (void ∗∗ tag_ptr, void ∗∗ payload_ptr) |
使用
1 |
|
bsp_hpmove
直接修改指针,省去了内存复制
- 相比于
bsp_move
只需要根据tag判断消息,不需要用if判断进程