使用OpenMP并行化memcpy

时间:2017-07-27 12:12:05

标签: c multithreading openmp memcpy

我需要复制两个数组,我正在尝试并行化代码。我尝试了两种不同的方式,但我无法弄清楚为什么一种方法比另一种更快。

第一种方法为单独的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。为什么会这样?第一种方法只使用两个线程,第二种方法使用所有线程,为什么它会变慢?第一种方法更好,还是我只是对第二种方法做错了?

1 个答案:

答案 0 :(得分:0)

要利用不同的IO通道和类似的东西来获得更高的并行吞吐量,您必须确保将线程映射到架构的不同部分(核心,套接字),这样它们就不会步骤在他们的脚上,他们也使用“接近”的记忆。

通常,OpenMp没有提供太多方法来详细说明。

hwloc工具箱[1]为您提供命令行界面和API,以便携式方式处理这些事情。但通常你需要直接用线程编程。

[1] https://www.open-mpi.org/projects/hwloc/