我需要复制两个数组,我正在尝试并行化代码。我尝试了两种不同的方式,但我无法弄清楚为什么一种方法比另一种更快。
第一种方法为单独的memcpy
中的每个数组复制调用omp section
。使用16个线程运行此操作需要0.063秒。
void copy_uv(void *u, int u_sz, void *v, int v_sz, void *u_copy, void *v_copy) {
#pragma omp parallel sections
{
#pragma omp section
{
memcpy(u_copy, u, u_sz);
}
#pragma omp section
{
memcpy(v_copy, v, v_sz);
}
}
}
第二种方法根据线程数以块的形式分隔数组,每个线程复制自己的块。块大小是64字节(高速缓存行大小)的倍数,以避免错误共享。如果相关,阵列也分配了mkl_malloc(sz, 64)
。 16线程需要0.135秒。
void copy_uv(double *u, int u_sz, double *v, int v_sz, double *u_copy, double *v_copy) {
int threads = omp_get_num_threads();
int u_blocksz = ceil((float)u_sz / threads);
u_blocksz = u_blocksz - (u_blocksz % 64);
int v_blocksz = ceil((float)v_sz / threads);
v_blocksz = v_blocksz - (v_blocksz % 64);
int i,j;
#pragma omp parallel
{
#pragma omp for nowait
for (i = 0; i < threads; ++i) {
int index_i = i * u_blocksz;
if (i == threads-1)
memcpy(u_copy+index_i, u+index_i, u_sz - index_i);
else
memcpy(u_copy+index_i, u+index_i, u_blocksz);
}
#pragma omp for nowait
for (j = 0; j < threads; ++j) {
int index_j = j * v_blocksz;
if (j == threads-1)
memcpy(v_copy+index_j, v+index_j, v_sz - index_j);
else
memcpy(v_copy+index_j, v+index_j, v_blocksz);
}
}
}
在这种情况下,最后一个线程可能有更多的内存要复制,并且可能需要更长的时间,但即使我给它相同的内存量来复制并忽略数组末尾的剩余字节,时间不会改变。
如果以较少的线程运行,结果变化很小。有4个螺纹,0.075和0.145。为什么会这样?第一种方法只使用两个线程,第二种方法使用所有线程,为什么它会变慢?第一种方法更好,还是我只是对第二种方法做错了?
答案 0 :(得分:0)
要利用不同的IO通道和类似的东西来获得更高的并行吞吐量,您必须确保将线程映射到架构的不同部分(核心,套接字),这样它们就不会步骤在他们的脚上,他们也使用“接近”的记忆。
通常,OpenMp没有提供太多方法来详细说明。
hwloc
工具箱[1]为您提供命令行界面和API,以便携式方式处理这些事情。但通常你需要直接用线程编程。