MPI分布式内存编程技术
Fortran 77 是什么呀~~
- 单个进程(process)
- 拥有独立的执行环境
- 独立地申请和占有内存空间
- 单机内多个进程
- 多个进程可同时存在在单机内同一个操作系统
- 进程间相互独立,内存空间不相交
- 进程间可以相互交换信息
- 包含于通过网络链接的不同处理器的多个进程
- 进程独立存在,需要通过一些接口函数来实现目前编程空间的需求
- 物理隔离,不能越过内存,访问需要通过“复印“的操作
MPI
重要概念
- 进程序号(rank)的进程由进程组活通信器序号唯一确定
- 也就是每个进程自己的名字
- 同一个进程在不同的通信组或通信器之间可以有不同的序号
- 消息(message)
MPI
原始数据类型
MPI类型 | C类型 |
---|---|
MPI_CHAR | signed char |
MPI_SHORT | signed short int |
MPI_INT | signed int |
MPI_LONG | signed long |
MPI_UNSIGNED_CHAR | unsigned char |
MPI_UNSIGNED_SHORT | unsigned short int |
MPI_UNSIGNED | unsigned int |
MPI_UNSIGNED_LONG | unsigned long int |
MPI_FLOAT | float |
MPI_DOUBLE | double |
MPI_LONG_DOUBLE | long double |
MPI_BYTE | |
MPI_PACKED |
MPI——BYTE
(一个字节)
MPI_PACKED
(打包数据)
MPI
基本结构
MPI include file
变量定义
MPI
环境初始化
int MPI_Init(int *argc,char *argv[]);
int MPI_Init(NULL,NULL);
执行程序
进程间通信
退出``MPI`环境
int MPI_Finalize(void);
MPI
基本函数
开始
终止
获取墙钟时间
double MPI_Wtime(void)
Sample Hello World
点对点通信
-
定义
- communicator(通信子,通信域) source destination 0
-
阻塞式点对点通信
-
int MPI_Send(void *buf,int count,MPI_Datatype,int dest,int tag ,MPI_Comm comm); //count是指定数据类型的个数 //dest范围是0~np-1,或MPI_PROC_NULL //tag范围是0~MPI_TAG_UB,用来区分消息
- ```c int MPI_Recv(void *buf,int count,MPI_Datatype datatype,int source,int tag,MPI_Comm comm,MPI_Status *status); //count是接受缓冲区的大小,表示接受上界。
-
-
编写安全的``MPI`程序
-
非阻塞式点对点通信
int MPI_Isend(void* buf, int count, MPI_Datatype datatype, int dest, int tag,MPI_Comm COmm,MPI_Request *request);
/*
IN buf 发送缓冲区的起始地址
IN count 发送缓冲区的大小(发送元素个数)
IN datatype 发送缓冲区数据的数据类型
IN dest 月的进程的rank值
IN tag 消息标签
IN comm 通信空间/通信城
OUT request 非阳塞通信完成对象(句树)
MPI_Ibsend/MPI_Issend/MPI_Irsend:非阻塞缓冲模式/非阻赛同步模式/
*/
int MPI_Irecv(void* buf, int count, MPI_Datatype datatype, int source, int tag,MPI_Comm comm,MPI_Request* request);
并行计算优化技巧
编译优化
IPCC比赛环境:CPU AMD EPYC 7452
-O3-fopenmp -march=znver1 -mfma -fomit-frame-pointer -mavx2 -mtune=znever**……**
Cache 优化
//matrix multiplication
for(int i = 0; i < n; i++){
for(int k = 0; k < n; k++){
for(int j = 0;j < n; j++){
c[i][j] += A[i][k] * B[k][j];
}
}
}
//ikj这个组合是最快,多重循环套一起,可以尝试将循环次序进行交换
SIMD
向量指令是一种并行计算技术,可以在一次指令中同时处理多个数据元素,从而提高计算效率。与传统的标量指令相比,向量指令能够耨将计算操作应用**……**
- 使用条件
- 最内层循环
- 循环的长度是固定的
- 循环体内没有变量依赖关系。 不然就不好进行
- 循环访问的数据最好是连续的,或者最起码是相同的步长间隔
- 循环体内没有复杂的分支判断
- 循环内没有调用其他复杂的函数
查CPU手册
-
对齐
-
在C语言中可以使用aligned_alloc函数来申请对齐的内存。该函数的声明:
-
……
-
一个例子
记得free
-
边角料的处理 加一个非SIMD的处理
-
内部处理
-
外部处理
向量点乘
- 手动/自动向量化
- #pragma ivdep
- #pragma vector aligned
- #pragma vector
- ** ……**
预取
__builtin_prefetch函数
……
- 执行缓存预取操作。可以将制定地址的数据预取到cache中
Openmp task
TASK定义一个可以被任何线程执行的独立的工作单元
- if:指定是否生成一个任务
- final:制定是否将生成的任务和它的所有子任务都标记为final,即不可再分
- ……
任务流
- 一个例子
打比赛用不上
工程好用,cpu和gpu都可用
C++不支持异步程序
Qt是C++界面库,需要手动wait
排序
-
SortKey 排一个
-
SortPairs 排点对(结构体)
-
Std::sort
-
Omp task sort
-
__gnu_parallel::sort 网上的项目,开源库
-
parallel_radix_sort 开源的并行的基数排序
IPCC 2022初赛
支撑点切比雪夫距离和——SumDistance
k = 2,3,的情况
伪代码
……
- j < i
PAC2019初赛
CFD 应用物理量梯度求解算法优化
PAC2019-初赛题
简介
计算流体力学程序中,粘性项离散的关键是计算物理量在界面处的梯度。求梯度的原理是高斯-格林公式:
$\oint_{V}\triangledown Q dV=\iint_{\partial V} Q \cdot\vec{n} dS$
即单元中心的梯度可以积分面心的值得到。
核心是将几个循环进行合并,然后将代码修改为编译器更容易优化的形式,关键还是使用omp来优化,当然对于这种计算比较原子操作而且数量大的操作使用cuda肯定也挺好的,
lxc
试了一下确实是这样的