openmp

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

OpenMP

OpenMP

Purpose

目的

Guide agents through OpenMP shared-memory parallelism:
#pragma omp parallel for
with scheduling clauses, reductions, data-sharing attributes, SIMD hints, task parallelism, OpenMP 5.x GPU
target
offloading, common pitfalls (false sharing, data races), environment tuning, and profiling with Score-P or TAU.
指导 Agent 进行 OpenMP 共享内存并行编程:带调度子句的
#pragma omp parallel for
、reduction、数据共享属性、SIMD 提示、任务并行、OpenMP 5.x GPU
target
卸载、常见陷阱(false sharing、数据竞争)、环境调优,以及使用 Score-P 或 TAU 进行性能分析。

When to Use

使用场景

  • Parallelizing C/C++/Fortran loops on multicore CPUs
  • Implementing reductions (sum, max, custom)
  • Task parallelism for irregular workloads
  • Offloading compute to GPU with OpenMP target directives
  • Diagnosing scaling failures (false sharing, load imbalance)
  • Tuning thread count and spin behavior
  • 在多核 CPU 上并行化 C/C++/Fortran 循环
  • 实现 reduction(求和、最大值、自定义)
  • 针对不规则工作负载使用任务并行
  • 使用 OpenMP target 指令将计算卸载到 GPU
  • 诊断并行扩展性能问题(false sharing、负载不均衡)
  • 调整线程数量和自旋行为

Workflow

工作流

1. Basic parallel for

1. 基础并行 for 循环

c
#include <omp.h>
#include <stdio.h>

int main(void) {
    const int n = 1000000;
    double sum = 0.0;

    #pragma omp parallel for reduction(+:sum)
    for (int i = 0; i < n; i++)
        sum += i * 0.001;

    printf("sum = %f, threads = %d\n", sum, omp_get_max_threads());
    return 0;
}
bash
gcc -fopenmp -O3 -o omp_sum omp_sum.c
export OMP_NUM_THREADS=8
./omp_sum
c
#include <omp.h>
#include <stdio.h>

int main(void) {
    const int n = 1000000;
    double sum = 0.0;

    #pragma omp parallel for reduction(+:sum)
    for (int i = 0; i < n; i++)
        sum += i * 0.001;

    printf("sum = %f, threads = %d\n", sum, omp_get_max_threads());
    return 0;
}
bash
gcc -fopenmp -O3 -o omp_sum omp_sum.c
export OMP_NUM_THREADS=8
./omp_sum

2. Schedule clauses

2. 调度子句

c
#pragma omp parallel for schedule(static)          // equal chunks, low overhead
#pragma omp parallel for schedule(dynamic, 64)     // dynamic chunks of 64
#pragma omp parallel for schedule(guided)          // decreasing chunk size
#pragma omp parallel for schedule(auto)            // compiler/runtime decides
ScheduleBest for
static
Uniform work per iteration
dynamic
Variable iteration cost
guided
Decreasing iteration cost
static,1
Cache blocking with interleaved chunks
c
#pragma omp parallel for schedule(static)          // equal chunks, low overhead
#pragma omp parallel for schedule(dynamic, 64)     // dynamic chunks of 64
#pragma omp parallel for schedule(guided)          // decreasing chunk size
#pragma omp parallel for schedule(auto)            // compiler/runtime decides
Schedule适用场景
static
每次迭代的工作量均匀
dynamic
每次迭代的成本可变
guided
每次迭代的成本递减
static,1
使用交错式块进行缓存阻塞

3. Data sharing attributes

3. 数据共享属性

c
int shared_var = 0;
#pragma omp parallel private(i) shared(shared_var)
{
    int i = omp_get_thread_num();
    #pragma omp atomic
    shared_var += i;
}

// firstprivate — copy in; lastprivate — copy out after loop
#pragma omp parallel for firstprivate(offset) lastprivate(result)
for (int i = 0; i < n; i++) { ... }
ClauseMeaning
private
Uninitialized per-thread copy
shared
One variable, all threads
reduction(op:var)
Combine at end (+, *, max, &&, ||)
firstprivate
Initialize from master
lastprivate
Master gets last iteration value
c
int shared_var = 0;
#pragma omp parallel private(i) shared(shared_var)
{
    int i = omp_get_thread_num();
    #pragma omp atomic
    shared_var += i;
}

// firstprivate — copy in; lastprivate — copy out after loop
#pragma omp parallel for firstprivate(offset) lastprivate(result)
for (int i = 0; i < n; i++) { ... }
子句含义
private
每线程一个未初始化的副本
shared
一个变量,由所有线程共享
reduction(op:var)
在结束时合并(+, *, max, &&, ||)
firstprivate
从 master 初始化
lastprivate
master 获取最后一次迭代的值

4. SIMD vectorization hint

4. SIMD 向量化提示

c
#pragma omp simd
for (int i = 0; i < n; i++)
    c[i] = a[i] + b[i];

// SIMD + parallel
#pragma omp parallel for simd
for (int i = 0; i < n; i++)
    c[i] = a[i] * b[i];
Requires
-fopenmp-simd
or
-fopenmp
with compiler SIMD support. Check with
-fopt-info-vec
.
c
#pragma omp simd
for (int i = 0; i < n; i++)
    c[i] = a[i] + b[i];

// SIMD + parallel
#pragma omp parallel for simd
for (int i = 0; i < n; i++)
    c[i] = a[i] * b[i];
需要使用
-fopenmp-simd
,或使用支持 SIMD 的编译器并启用
-fopenmp
。可通过
-fopt-info-vec
检查。

5. Task parallelism

5. 任务并行

c
#pragma omp parallel
{
    #pragma omp single
    {
        for (int i = 0; i < 10; i++) {
            #pragma omp task firstprivate(i)
            process_subtree(i);
        }
        #pragma omp taskwait
    }
}
Tasks suit recursive algorithms (quicksort, tree traversal) where loop parallelism doesn't fit.
c
#pragma omp parallel
{
    #pragma omp single
    {
        for (int i = 0; i < 10; i++) {
            #pragma omp task firstprivate(i)
            process_subtree(i);
        }
        #pragma omp taskwait
    }
}
Task 适合递归算法(quicksort、树遍历)等不适合使用循环并行的场景。

6. Timing

6. 计时

c
double start = omp_get_wtime();
#pragma omp parallel for
for (int i = 0; i < n; i++) work(i);
double elapsed = omp_get_wtime() - start;
printf("elapsed: %f s\n", elapsed);
c
double start = omp_get_wtime();
#pragma omp parallel for
for (int i = 0; i < n; i++) work(i);
double elapsed = omp_get_wtime() - start;
printf("elapsed: %f s\n", elapsed);

7. GPU target offloading (OpenMP 5.x)

7. GPU target 卸载(OpenMP 5.x)

c
#pragma omp target teams distribute parallel for map(to:a[0:n]) map(from:c[0:n])
for (int i = 0; i < n; i++)
    c[i] = a[i] * 2.0f;
bash
undefined
c
#pragma omp target teams distribute parallel for map(to:a[0:n]) map(from:c[0:n])
for (int i = 0; i < n; i++)
    c[i] = a[i] * 2.0f;
bash
undefined

NVIDIA offload

NVIDIA offload

gcc -fopenmp -foffload=-march=sm_80 -o offload offload.c
gcc -fopenmp -foffload=-march=sm_80 -o offload offload.c

Check device

Check device

export OMP_DEFAULT_TARGET_DEVICE=1

Requires compiler offload support (GCC offload, Clang/OpenMP, NVIDIA HPC SDK).
export OMP_DEFAULT_TARGET_DEVICE=1

需要编译器支持 offload(GCC offload、Clang/OpenMP、NVIDIA HPC SDK)。

8. Environment variables

8. 环境变量

bash
export OMP_NUM_THREADS=16
export OMP_PROC_BIND=close        # bind threads to nearby cores
export OMP_PLACES=cores
export GOMP_SPINCOUNT=2000        # spin before sleep
export OMP_WAIT_POLICY=active     # active vs passive waiting
export OMP_DISPLAY_ENV=true       # print config at startup
bash
export OMP_NUM_THREADS=16
export OMP_PROC_BIND=close        # bind threads to nearby cores
export OMP_PLACES=cores
export GOMP_SPINCOUNT=2000        # spin before sleep
export OMP_WAIT_POLICY=active     # active vs passive waiting
export OMP_DISPLAY_ENV=true       # print config at startup

9. Profiling

9. 性能分析

bash
undefined
bash
undefined

Score-P (compile with wrapper)

Score-P (compile with wrapper)

scorep gcc -fopenmp -o app app.c export SCOREP_METRIC_MANAGER=1 scorep ./app scorep-score -f scorep_*/profile.cubex
scorep gcc -fopenmp -o app app.c export SCOREP_METRIC_MANAGER=1 scorep ./app scorep-score -f scorep_*/profile.cubex

TAU

TAU

tau_cc.sh -fopenmp -o app app.c export TAU_TRACE=1 ./app pprof app profile.*
undefined
tau_cc.sh -fopenmp -o app app.c export TAU_TRACE=1 ./app pprof app profile.*
undefined

10. Pitfalls

10. 常见陷阱

False sharing: threads modify adjacent cache lines.
c
// Bad: sum_array[tid] on same cache line
#pragma omp parallel
{
    int tid = omp_get_thread_num();
    sum_array[tid] += local_sum;  // pad to 64 bytes between elements
}

// Fix: padding
double sum_padded[MAX_THREADS][8];  // 8 doubles = 64 bytes
Nested parallelism:
bash
export OMP_MAX_ACTIVE_LEVELS=2
export OMP_NESTED=true   # deprecated; use MAX_ACTIVE_LEVELS
False sharing:线程修改相邻的缓存行。
c
// Bad: sum_array[tid] on same cache line
#pragma omp parallel
{
    int tid = omp_get_thread_num();
    sum_array[tid] += local_sum;  // pad to 64 bytes between elements
}

// Fix: padding
double sum_padded[MAX_THREADS][8];  // 8 doubles = 64 bytes
Nested parallelism:
bash
export OMP_MAX_ACTIVE_LEVELS=2
export OMP_NESTED=true   # deprecated; use MAX_ACTIVE_LEVELS

Common Problems

常见问题

SymptomCauseFix
No speedupLoop too smallIncrease work; check
if
clause threshold
Wrong reduction resultRace on non-reduction varUse
reduction
or
atomic
Slower with more threadsFalse sharingPad per-thread arrays
GPU offload failsNo target deviceCheck
-foffload
;
nvidia-smi
Threads not boundDefault spread
OMP_PROC_BIND=close
Nested deadlockOversubscriptionLimit
OMP_NUM_THREADS
per level
症状原因修复方式
没有加速循环过小增大工作量;检查
if
子句阈值
reduction 结果错误非 reduction 变量存在竞争使用
reduction
或
atomic
线程越多反而越慢False sharing为每线程数组添加填充
GPU offload 失败没有 target 设备检查
-foffload
;
nvidia-smi
线程未绑定默认分散策略
OMP_PROC_BIND=close
嵌套死锁过度订阅限制每一层的
OMP_NUM_THREADS

Related Skills

相关 Skill

  • skills/hpc/mpi
    — distributed memory complement
  • skills/low-level-programming/cpu-cache-opt
    — false sharing deep dive
  • skills/gpu/cuda
    — GPU programming alternative to target offload
  • skills/profilers/intel-vtune-amd-uprof
    — OpenMP region analysis in VTune
  • skills/compilers/gcc
    —
    -fopenmp
    flags
  • skills/allocators/numa-programming
    — NUMA-aware thread binding
  • skills/hpc/mpi
    — 分布式内存的补充方案
  • skills/low-level-programming/cpu-cache-opt
    — false sharing 深入解析
  • skills/gpu/cuda
    — target 卸载之外的 GPU 编程替代方案
  • skills/profilers/intel-vtune-amd-uprof
    — 在 VTune 中进行 OpenMP region 分析
  • skills/compilers/gcc
    —
    -fopenmp
    编译选项
  • skills/allocators/numa-programming
    — NUMA 感知的线程绑定