文章

GPU编程PPT3

GPU编程PPT3

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)
  • in:读取数据
  • out:写入数据

📘 推荐阅读: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; }
}

✅ 编程建议

🛠 编写流程

  1. 设置执行环境(默认 CPU)
  2. 生成并行结构(teams, parallel
  3. 分配工作(如 for, distribute
  4. 使用 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

🔍 最佳实践

  1. 充分挖掘并行性(如 collapse,tasking)
  2. 并行粒度横向 + 纵向并用(设置线程数/团队数)
  3. 避免不必要的数据传输
  4. 不建议在嵌套函数或编译单元中生成并行
  5. OpenMP target 代码中不可使用标准库
本文由作者按照 CC BY 4.0 进行授权