You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

OpenMP嵌套并行区域性能远低于预期问题排查

CC-NUMA系统下OpenMP嵌套并行SpMV性能异常问题

环境与实验配置

  • 硬件:4节点、128核CC-NUMA系统
  • 计算任务:稀疏矩阵-向量乘积(SpMV)
  • OpenMP配置:
    • 版本1:直接创建128个线程,通过proc_bind(spread)分布在所有节点上,并行处理全量行数据
    • 版本2:采用嵌套并行:外层创建4个线程(每个节点1个),先计算当前节点负责的行范围;内层在每个节点上创建32个线程,处理对应行范围,目的是让节点内线程写入结果向量y的连续区域
  • 验证:已设置OMP_PLACES指定节点位置,通过numactl的numa_node_of_cpu(cpu)和sched_getcpu()确认线程绑定符合预期;版本2已调用omp_set_nested(1)启用嵌套并行支持

性能异常现象

  • 版本1性能符合预期,但版本2的性能比版本1慢约100倍,即使将输入数据复制到每个节点(确保线程访问本地内存域数据),性能差异依然存在
  • 额外调度问题:尝试静态调度时,尽管每行非零元素数量相同、迭代工作量一致,性能仍比guided调度差约70%

代码实现

int *row_idx = ...;
int *col_idx = ...;
double *val = ...;
double *y = ...;
double *x = ...;
int num_rows = ...;

// 版本1:创建128个线程分布在所有节点
#pragma omp parallel proc_bind(spread) num_threads(128)
{
    #pragma omp for schedule(guided, 512)
    for(int i = 0; i < num_rows; i++){
        double temp = 0;
        for(int j = row_idx[i]; j < row_idx[i + 1]; j++){
            temp += val[j] * x[col_idx[j]];
        }
        y[i] = temp;
    }
}

// 版本2:嵌套并行,先按节点拆分任务,再在节点内并行
omp_set_nested(1);
// 外层:每个节点1个线程
#pragma omp parallel proc_bind(spread) num_threads(4)
{
    // 计算当前节点负责的行范围
    int id = omp_get_thread_num();
    int start = num_rows / 4 * id;
    int end = start + (num_rows / 4);
    // 内层:当前节点上创建32个线程
    #pragma omp parallel proc_bind(master) num_threads(32)
    {
        #pragma omp for schedule(guided, 512)
        for(int i = start; i < end; i++){
            double temp = 0;
            for(int j = row_idx[i]; j < row_idx[i + 1]; j++){
                temp += val[j] * x[col_idx[j]];
            }
            y[i] = temp;
        }
    }
}

内容的提问来源于stack exchange,提问作者lulle2007200

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 17:22:54