前言
OpenMP 是基于共享内存模式的一种并行编程模型, 使用十分方便, 只需要串行程序中加入OpenMP预处理指令, 就可以实现串行程序的并行化. 这里主要进行一些学习记录, 使用的书籍为: Using OpenMP: Portable Shared Memory Parallel Programming 和OpenMP编译原理及实现技术
No Start No End
OpenMP 是基于共享内存模式的一种并行编程模型, 使用十分方便, 只需要串行程序中加入OpenMP预处理指令, 就可以实现串行程序的并行化. 这里主要进行一些学习记录, 使用的书籍为: Using OpenMP: Portable Shared Memory Parallel Programming 和OpenMP编译原理及实现技术
向量化简单的说就是使用SIMD指令, 来实现使用一条指令同时处理多个数据, MIC中具有32个长度为512位的向量处理单元, 每个向量处理单元可以处理16个32位或者8个64位的数据. 这里主要记录一下MIC向量化的使用方式以及一些向量指令的作用.
MIC中使用下面的数据类型作为执行向量函数的操作数1
__m512, __m512i __m512d
下面是它们的各自的作用:
__m512
- 处理单精度向量(float32 vector)__m512d
- 处理双精度向量(float64 vector)__m512i
- 处理整形向量, 包括32位和64位整形(int32/int64)
我们可以使用fopen()创建一个新的或者打开一个文件, 文件信息会保存在一个FILE
类型的指针中, 该函数的原型为:1
FILE *fopen( const char * filename, const char * mode );
filename
是文件名, mode
是打开模式, 可选值如下:
r
- 以只读方式打开一个文件, 该文件必须存在w
- 以只写方式打开一个文件, 文件不存在会创建新的文件, 文件存在会首先清空原有内容a
- 以追加的方式写文件, 文件不存在会创建新的文件, 文件存在从文件尾开始写文件r+
- 以读写方式打开文件, 文件不存在不会创建新的文件w+
- 以读写方式打开文件, 文件不存在会创建新的文件, 文件存在会首先清空原有内容a+
- 以追加方式读写文件, 文件不存在会创建新的文件, 文件存在从文件尾开始写文件如果是操作二进制文件, 那么需要在mode
里加上b
, 如下所示:1
"rb", "wb", "ab", "rb+", "r+b", "wb+", "w+b", "ab+", "a+b"
文件成功打开会返回一个’FILE’类型的指针, 如果打开失败, 会返回一个空指针, 并把错误代码存在errno
中.
当使用#pragma offload target(mic) 方式分载时, cpu会等待offload的代码块执行完再继续往下执行, 如果不希望等待offload, 我们可以使用cpu和mic异步计算的方式. 具体方法为在offload的时候添加一个信号量, 如下面的形式:1
2
3
4
5
6char signal_var;
#pragma offload target(mic:0)signal(&signal_var)
{
...
}
此时offload 的代码就会异步执行, 需要注意的一点是要制定mic的编号(如上面的target(mic:0)
), 如果需要等待offload执行完后在往下执行, 可以使用offload_wait
, 如下面的形式
1 | #pragma offload_wait target(mic:0) wait(&signal_var) |
使用#pragma offload target(mic) 方式将程序分载到MIC上计算是比较常用的方式, 但是这种方式只支持一维指针, 如果有较为复杂的数据结构, 比如二维指针, 树, 链表等结构则需要将这些数据结构转换为一维结构(如果可以), 否则不能将数据传到MIC上去. 为了满足复杂的数据结构, mic提供了共享虚拟内存的方式, 即将mic的内存和cpu的内存看做共享同一块虚拟内存, 在共享内存中的数据被cpu和mic共享, 不需要使用offload将数据在cpu和mic之间相互传递.
使用into可以将一个变量的值上传到另外一个变量中, 比如in (a into(b))
, 表示将CPU上变量a的值赋给MIC上的变量b, 也可以out(b into(c))
将MIC上变量b的值传回给CPU上的变量c. 需要注意的地方是into 只能用于in或者out中, 不能用于inout或者nocopy中. 下面是使用示例:
下面的代码主要使用in作为测试, out和inout的用法应该是类似的, 下面主要以代码为主, 并且附带执行结果。
这种方式对应于我们前面所说的非共享内存模型,这里记录一下它的基本用法
如果是局部变量, 那么我们不需要做额外的工作, 如果全局变量或者函数, 要在mic上使用它们, 则需要使用下面的方式声明或者定义:1
2
3
4__declspec( target (mic)) function-declaration
__declspec( target (mic)) variable-declaration
__attribute__ (( target (mic))) function-declaration
__attribute__ (( target (mic))) variable-declaration
其中__declspec
可以用于windows或者linux系统, 而_attribute__
只能用于linux.
以下摘自”MIC高性能编程指南”
通常提及MIC系列, 会提及以下几个名词: MIC(Many Integrated Core), Knights系列(如Knights Corner. KNC), Intel® Xeon PhiTM(官方中文译名:英特尔® 至强融核TM). MIC作为这个系列的架构名称, 类似于CPU, 是对采用这种架构的产品的总称. Knights 系列, 是Intel公司推出的MIC产品的研发代号, 类似于Ivy Bridge, 是内部研发人员对某一代产品的命名,不用于商业用途, 例如第一代正式产品锁采用的,就是Knights Corner架构. 提到具体KNx的架构, 与MIC架构相比, 可以看做是面向对象中父类与子类的关系, MIC架构是父类, 而KNx则是子类. Intel® Xeon PhiTM则是产品线的总称, 类似于Pentium、 Xeon等产品系列, Intel® Xeon PhiTM 是Intel公司推出的基于MIC架构的高性能计算协处理器卡的系列产品名称.