Parallel Programming Models: OpenMP
Course: COMP52315 GPU Programming
Lecturer: Christopher Marcotte
📧 christopher.marcotte@durham.ac.uk
📌 Recap
- 基础 CUDA 编程方法
- CUDA 优化技术:
- CUDA 中的任务并行表达方式:
💡 OpenMP 简介
- OpenMP 是一种并行编程模型,支持 C/C++/Fortran 语言。
- 支持 CPU 和 GPU 架构上的可扩展性与可移植性。
- 当前版本:5.2,本课程基于 OpenMP 4.5(Nvidia HPC SDK 支持)。
📖 参考资料:
🧠 架构和内存模型
1
2
| Host (CPU) Target (GPU)
Main Memory ⇄ Bus ⇄ Global Memory
|
- Host 设备运行 OpenMP 程序主线程
- Target 设备可通过 OpenMP 指令进行代码和数据 offload
- 数据传输可以由运行时自动完成,也可以显式管理
🔁 执行模型
- 基于 Fork-Join:并行阶段 + 顺序阶段
- Host-centric:主线程在 Host 执行,offload 到 Target
- 支持层次化并行:
parallel
表示线程块teams
表示线程块网格
🧱 编程模型
OpenMP 使用 directive(指令)驱动编程方式:
1
| #pragma omp directive-name [clauses]
|
- 指令只能应用于一个结构化代码块(如花括号括起来)
- clause 顺序不敏感,可以重复使用
⚙️ GPU 编程模型
- GPU 包含多个 SIMD 计算单元(CU)
- 指令用法:
#pragma omp teams
:创建多个线程 team(使用多个 CU)#pragma omp parallel
:创建线程 team(使用多个 lane)#pragma omp target
:在 GPU 上执行,隐式数据传输
⚠️ 无法访问 CUDA 的低级特性(如 __shared__
,threadIdx.x
)
🧮 数据并行指令
🔹 生成并行
1
2
| #pragma omp parallel
#pragma omp teams
|
🔹 分配工作
1
2
| #pragma omp for
#pragma omp distribute
|
🔹 组合构造(简写)
1
2
3
| #pragma omp parallel for
#pragma omp teams distribute
#pragma omp teams distribute parallel for
|
📤 显式数据传输
1
| #pragma omp target map(map-type : list)
|
map-type
: to
, from
, tofrom
list
: 要传输的数组切片
示例:
1
| #pragma omp target map(tofrom : A[0:N], B[0:M])
|
📦 持久数据映射
结构化数据:
1
| #pragma omp target data map(...)
|
非结构化数据(如 struct/class):
1
2
| #pragma omp target enter data map(...)
#pragma omp target exit data map(...)
|
🧪 示例:向量加法
1
2
3
4
| #pragma omp target teams distribute parallel for map(to: X[0:N], Y[0:N]) map(tofrom: Z[0:N])
for(int i = 0; i < N; i++) {
Z[i] = X[i] + Y[i];
}
|
→ 两层并行:线程和线程团队
➕ 示例:并行归约
1
2
3
4
| #pragma omp target teams distribute parallel for reduction(+:sum)
for (int i = 0; i < N; i++) {
sum = sum + X[i];
}
|
📘 自学推荐:CUDA Reduction
⚒️ 任务并行指令
1
| #pragma omp task [clauses]
|
- 多线程可生成任务,需使用
#pragma omp single
限制 - 使用
#pragma omp barrier
等待所有任务完成
🔹 依赖关系
1
| #pragma omp task depend(in|out: list)
|
📘 推荐阅读:OpenMP Tasking Dependencies
📌 示例:OpenMP Tasks
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
| int x = 0, y = 0, z = 0;
#pragma omp parallel
#pragma omp single
{
#pragma omp task depend(out: x)
{ x = 1; }
#pragma omp task depend(in: x)
{ y = 2 * x; }
#pragma omp task depend(in: x)
{ z = 1 + x; }
#pragma omp task depend(out: x) depend(in: y,z)
{ x = y + z; }
}
|
✅ 编程建议
🛠 编写流程
- 设置执行环境(默认 CPU)
- 生成并行结构(
teams
, parallel
) - 分配工作(如
for
, distribute
) - 使用
map
, enter data
等进行数据管理优化
🧪 编译与执行
- 支持编译器:
gcc/g++
, clang/clang++
, nvc++
(非 nvcc
)
示例命令:
1
2
3
| module load nvidia-hpc
nvc++ -fopenmp -mp=gpu my_omp.cpp -o exe
OMP_NUM_THREADS=1 OMP_NUM_TEAMS=1 ./exe
|
🔍 最佳实践
- 充分挖掘并行性(如 collapse,tasking)
- 并行粒度横向 + 纵向并用(设置线程数/团队数)
- 避免不必要的数据传输
- 不建议在嵌套函数或编译单元中生成并行
- OpenMP target 代码中不可使用标准库