与openmp中线程数相关的性能
performance related to number of threads in openmp
我使用 OpenMP 编写了一个小型矩阵乘法程序。当我使用 2 个线程时性能最佳,而当我使用 1000 个线程时性能最差。
我总共有 64 个处理器。当线程数为 1 或 2 时,我获得最佳性能。
~/openmp/mat_mul> cat /proc/cpuinfo | grep processor | wc -l
64
~/openmp/mat_mul> export OMP_NUM_THREADS=2
~/openmp/mat_mul> time ./main
Total threads : 2
Master thread initializing
real 0m1.536s
user 0m2.728s
sys 0m0.200s
~/openmp/mat_mul> export OMP_NUM_THREADS=64
~/openmp/mat_mul> time ./main
Total threads : 64
Master thread initializing
real 0m25.755s
user 4m34.665s
sys 21m5.595s
这是我的矩阵乘法代码。
#include <omp.h>
#include <stdio.h>
#include <stdlib.h>
#define ROW_SIZE_A 100
#define COL_SIZE_A 5000
#define COL_SIZE_B 300
int get_random();
int main(int argc, char* argv[])
{
int a[ROW_SIZE_A][COL_SIZE_A];
int b[COL_SIZE_A][COL_SIZE_B];
int c[ROW_SIZE_A][COL_SIZE_B];
int i,j,k, tid, thread_cnt;
srand(time(NULL));
#pragma omp parallel shared(a,b,c,thread_cnt) private(i,j,k,tid)
{
tid = omp_get_thread_num();
if(tid == 0)
{
thread_cnt = omp_get_num_threads();
printf("Total threads : %d\n", thread_cnt);
printf("Master thread initializing\n");
}
#pragma omp parallel for schedule(static)
for(i=0; i<ROW_SIZE_A; i++)
{
for(j=0; j<COL_SIZE_A; j++)
{
a[i][j] = get_random();
}
}
#pragma omp parallel for schedule(static)
for(i=0; i<COL_SIZE_A; i++)
{
for(j=0; j<COL_SIZE_B; j++)
{
b[i][j] = get_random();
}
}
#pragma omp parallel for schedule(static)
for(i=0; i<ROW_SIZE_A; i++)
{
for(j=0; j<COL_SIZE_B; j++)
{
c[i][j] = 0;
}
}
#pragma omp barrier
#pragma omp parallel for schedule(static)
for(i=0; i<ROW_SIZE_A; i++)
{
for(j=0; j<COL_SIZE_B; j++)
{
c[i][j] = 0;
for(k=0; k<COL_SIZE_A; k++)
{
c[i][j] += a[i][k] + b[k][j];
}
}
}
}
return 0;
}
有人能告诉我为什么会这样吗?
一般来说,您的处理器只能运行 固定数量的并行线程。增加超过该数量的线程数不会加快您的程序。事实上,大量的线程会导致大量的调度开销,从而使您的计算速度变得缓慢。
还要记住 Amdahl's law,并行性只会提高你的性能。
您的 for 循环未正确并行化,因为您使用了错误的 OpenMP 结构。 parallel for
是一个组合指令,它既创建了一个新的并行区域,又在其中嵌入了一个 for
工作共享结构。然后循环的迭代分布在内区的线程中。结果,您有 64 个线程,每个线程 运行 全部循环并同时写入 c
。除了产生错误的答案外,它还会对观察到的性能造成灾难性后果。此外,嵌套区域默认串行执行,除非通过调用 omp_set_nested(1);
或通过适当设置 OMP_NESTED
环境变量明确启用嵌套并行性。
从并行区域内的所有 for 循环中删除 parallel
关键字:
#pragma omp parallel shared(a,b,c,thread_cnt) private(i,j,k,tid)
{
...
#pragma omp parallel for schedule(static)
^^^^^^^^
for(i=0; i<ROW_SIZE_A; i++)
{
...
}
...
}
应该变成
#pragma omp parallel shared(a,b,c,thread_cnt) private(i,j,k,tid)
{
...
#pragma omp for schedule(static)
for(i=0; i<ROW_SIZE_A; i++)
{
...
}
...
}
这将按预期启用外部区域线程之间循环迭代的工作共享。
我使用 OpenMP 编写了一个小型矩阵乘法程序。当我使用 2 个线程时性能最佳,而当我使用 1000 个线程时性能最差。 我总共有 64 个处理器。当线程数为 1 或 2 时,我获得最佳性能。
~/openmp/mat_mul> cat /proc/cpuinfo | grep processor | wc -l
64
~/openmp/mat_mul> export OMP_NUM_THREADS=2
~/openmp/mat_mul> time ./main
Total threads : 2
Master thread initializing
real 0m1.536s
user 0m2.728s
sys 0m0.200s
~/openmp/mat_mul> export OMP_NUM_THREADS=64
~/openmp/mat_mul> time ./main
Total threads : 64
Master thread initializing
real 0m25.755s
user 4m34.665s
sys 21m5.595s
这是我的矩阵乘法代码。
#include <omp.h>
#include <stdio.h>
#include <stdlib.h>
#define ROW_SIZE_A 100
#define COL_SIZE_A 5000
#define COL_SIZE_B 300
int get_random();
int main(int argc, char* argv[])
{
int a[ROW_SIZE_A][COL_SIZE_A];
int b[COL_SIZE_A][COL_SIZE_B];
int c[ROW_SIZE_A][COL_SIZE_B];
int i,j,k, tid, thread_cnt;
srand(time(NULL));
#pragma omp parallel shared(a,b,c,thread_cnt) private(i,j,k,tid)
{
tid = omp_get_thread_num();
if(tid == 0)
{
thread_cnt = omp_get_num_threads();
printf("Total threads : %d\n", thread_cnt);
printf("Master thread initializing\n");
}
#pragma omp parallel for schedule(static)
for(i=0; i<ROW_SIZE_A; i++)
{
for(j=0; j<COL_SIZE_A; j++)
{
a[i][j] = get_random();
}
}
#pragma omp parallel for schedule(static)
for(i=0; i<COL_SIZE_A; i++)
{
for(j=0; j<COL_SIZE_B; j++)
{
b[i][j] = get_random();
}
}
#pragma omp parallel for schedule(static)
for(i=0; i<ROW_SIZE_A; i++)
{
for(j=0; j<COL_SIZE_B; j++)
{
c[i][j] = 0;
}
}
#pragma omp barrier
#pragma omp parallel for schedule(static)
for(i=0; i<ROW_SIZE_A; i++)
{
for(j=0; j<COL_SIZE_B; j++)
{
c[i][j] = 0;
for(k=0; k<COL_SIZE_A; k++)
{
c[i][j] += a[i][k] + b[k][j];
}
}
}
}
return 0;
}
有人能告诉我为什么会这样吗?
一般来说,您的处理器只能运行 固定数量的并行线程。增加超过该数量的线程数不会加快您的程序。事实上,大量的线程会导致大量的调度开销,从而使您的计算速度变得缓慢。
还要记住 Amdahl's law,并行性只会提高你的性能。
您的 for 循环未正确并行化,因为您使用了错误的 OpenMP 结构。 parallel for
是一个组合指令,它既创建了一个新的并行区域,又在其中嵌入了一个 for
工作共享结构。然后循环的迭代分布在内区的线程中。结果,您有 64 个线程,每个线程 运行 全部循环并同时写入 c
。除了产生错误的答案外,它还会对观察到的性能造成灾难性后果。此外,嵌套区域默认串行执行,除非通过调用 omp_set_nested(1);
或通过适当设置 OMP_NESTED
环境变量明确启用嵌套并行性。
从并行区域内的所有 for 循环中删除 parallel
关键字:
#pragma omp parallel shared(a,b,c,thread_cnt) private(i,j,k,tid)
{
...
#pragma omp parallel for schedule(static)
^^^^^^^^
for(i=0; i<ROW_SIZE_A; i++)
{
...
}
...
}
应该变成
#pragma omp parallel shared(a,b,c,thread_cnt) private(i,j,k,tid)
{
...
#pragma omp for schedule(static)
for(i=0; i<ROW_SIZE_A; i++)
{
...
}
...
}
这将按预期启用外部区域线程之间循环迭代的工作共享。