13 个不稳定版本 (5 个破坏性更新)
0.8.0 | 2024 年 5 月 3 日 |
---|---|
0.7.0 | 2023 年 10 月 21 日 |
0.6.0 | 2022 年 8 月 5 日 |
0.5.4 | 2018 年 3 月 27 日 |
0.2.0 | 2015 年 11 月 10 日 |
#28 在 并发 中排名
911 每月下载次数
用于 9 crates
300KB
5.5K SLoC
Rust 的 MPI 绑定
消息传递接口(MPI)是一种用于消息传递风格并发库的规范。MPI 的实现通常用于在高性能计算系统上结构化并行计算。MPI 规范描述了 C 编程语言(及其通过 C++)以及 Fortran 编程语言的绑定。这个库试图填补进入更 Rust 风格世界的差距。
需求
符合 MPI-3.1 的 C 语言接口实现。目前 rsmpi
正在使用这些实现进行测试
- OpenMPI 4.0.3 在 Ubuntu-20.04,4.1.2 在 macOS
- MPICH 3.3.2 在 Ubuntu 20.04
- MS-MPI (Windows) 10.1.2 在 Windows 2022
用户还使用这些 MPI 实现取得了成功,但在 CI 中未进行测试
- Spectrum MPI 10.3.0.1
- Cray MPI 8.1.16 与
PrgEnv-amd/8.3.3
为了在使用任何 MPI 实现时提高 rsmpi
成功的可能性,您必须拥有以下之一
- 将
MPI_PKG_CONFIG
导出为您的实现中 pkg-config 的名称或路径rsmpi
在 Cray 环境中自动使用CRAY_MPICH_DIR
,因此上述设置无需设置- 默认情况下将尝试使用
mpich
和ompi
作为最后的手段 - 提示:使用类似
pkg-config --cflags ---libs mpich
的命令进行测试
- 该实现提供了一个 C 编译器包装器
mpicc
- 导出
MPICC=/path/to/mpicc
来指定完整路径 - 否则在
$PATH
中尝试mpicc
mpicc -show
应该打印用于调用包装的 C 编译器的完整命令行,使用与 gcc 兼容的语法(例如,-lmpi
,-I/usr/local/include
,...)
- 导出
- 在 Windows 上,应设置变量
MSMPI_INC
以及MSMPI_LIB32
或MSMPI_LIB64
- 请参阅 GitHub Actions 中的示例
由于 MPI 标准未指定 C API 的某些细节(是否使用预处理器宏或原生 C 构造来实现某些常量和函数,以及大多数类型的细节等),rsmpi
采用两步方法来生成功能性的底层绑定。
首先,它使用一个用 C 编写的薄静态库(参见 rsmpi.h 和 rsmpi.c),该库试图捕获未指定的标识符并将它们以固定的 C API 形式重新导出。该库使用 build.rs 并使用 gcc
crate 构建。
其次,为了生成针对每个 MPI 实现定制的 FFI 定义,rsmpi
使用 rust-bindgen
,它需要 libclang
。有关更多信息,请参阅 bindgen 项目页面。
此外,rsmpi
使用 libffi
crate,它安装了依赖于某些构建工具的本地 libffi
。有关更多信息,请参阅 libffi 项目页面。
使用方法
将 mpi
crate 添加到您的 Cargo.toml
中的依赖项
# "features" is optional
[dependencies]
mpi = { version = "0.8.0", features = ["user-operations", "derive"] }
然后在您的程序中使用它,如下所示
use mpi::request::WaitGuard;
use mpi::traits::*;
fn main() {
let universe = mpi::initialize().unwrap();
let world = universe.world();
let size = world.size();
let rank = world.rank();
let next_rank = (rank + 1) % size;
let previous_rank = (rank - 1 + size) % size;
let msg = vec![rank, 2 * rank, 4 * rank];
mpi::request::scope(|scope| {
let _sreq = WaitGuard::from(
world
.process_at_rank(next_rank)
.immediate_send(scope, &msg[..]),
);
let (msg, status) = world.any_process().receive_vec();
println!(
"Process {} got message {:?}.\nStatus is: {:?}",
rank, msg, status
);
let x = status.source_rank();
assert_eq!(x, previous_rank);
assert_eq!(vec![x, 2 * x, 4 * x], msg);
let root_rank = 0;
let root_process = world.process_at_rank(root_rank);
let mut a;
if world.rank() == root_rank {
a = vec![2, 4, 8, 16];
println!("Root broadcasting value: {:?}.", &a[..]);
} else {
a = vec![0; 4];
}
root_process.broadcast_into(&mut a[..]);
println!("Rank {} received value: {:?}.", world.rank(), &a[..]);
assert_eq!(&a[..], &[2, 4, 8, 16]);
});
}
功能
这些绑定遵循 MPI 3.1 规范。
目前支持
- 组、上下文、通信器:
- 第 6 节中的组和(内部)通信器管理基本完成。
- 无互连通信器
- 无进程拓扑结构
- 点对点通信:
- 标准、缓冲、同步和就绪模式发送,有阻塞和非阻塞变体
- 接收,有阻塞和非阻塞变体
- 发送-接收
- 探测
- 匹配探测/接收
- 集体通信:
- 屏障
- 广播
- (全部)归约
- 分散
- 全部对全部
- 可变计数操作
- 归约/扫描
- 阻塞和非阻塞变体
- 数据类型:在 Rust 类型与 MPI 基本类型以及可以作为缓冲区视图的自定义 MPI 数据类型之间进行桥接。
不支持(尚不支持)
- 单方面通信(RMA)
- MPI 并行 I/O
- 成千上万的小事情
可选 Cargo 功能
您可以在 cargo 清单中启用这些可选功能。请参阅上面的 使用 部分。
user-operations
启用捕获 lambda 和在 UserOperation
中安全创建。此功能需要 libffi
系统库,该库不是所有系统都默认可用的。
let mut h = 0;
comm.all_reduce_into(
&(rank + 1),
&mut h,
&UserOperation::commutative(|x, y| {
let x: &[Rank] = x.downcast().unwrap();
let y: &mut [Rank] = y.downcast().unwrap();
for (&x_i, y_i) in x.iter().zip(y) {
*y_i += x_i;
}
}),
);
derive
允许启用 Equivalence
派生宏,这使得发送结构体时无需担心填充问题,并允许结构体之间进行任意数据类型的匹配,这些结构体具有相同的字段顺序但不同的布局。
#[derive(Equivalence)]
struct MyProgramOpts {
name: [u8; 100],
num_cycles: u32,
material_properties: [f64; 20],
}
文档
rsmpi
的每个公共项至少应与一段文档相关联。文档可以通过以下方式生成:
cargo doc
最新版本 rsmpi
的文档在 GitHub Pages 上托管。
示例
请参阅 examples/ 目录下的文件。这些示例还充当 集成测试。
Python 集成
可以使用 rsmpi
与由 mpi4py 提供的通信器一起使用。一个展示此功能的示例项目是 mpi4py_with_rsmpi。
许可证
许可证为以下之一:
- Apache License, Version 2.0, (LICENSE-APACHE 或 https://apache.ac.cn/licenses/LICENSE-2.0)
- MIT 许可证 (LICENSE-MIT 或 http://opensource.org/licenses/MIT)
任选其一。
贡献
除非你明确说明,否则任何有意提交以包含在你所定义的工作中的贡献,根据 Apache-2.0 许可证,应作为上述双重许可,不附加任何额外条款或条件。
依赖关系
~0.4–3.5MB
~72K SLoC