C和OpenMP:指向共享只读数据的指针会降低执行速度

时间:2013-03-23 21:12:24

标签: c parallel-processing openmp

这是我的情况,我有一个指针数组,指向一些数据的数组...让我们说:

    Data** array = malloc ( 100 * sizeof(Data*));
    for(i = 0; i < 100; i++) array[i] = malloc (20 * sizeof(Data);

在并行区域内,我进行了一些使用该数据的操作。例如:

    #pragma omp parallel num_threads(4) firstprivate(array)
    {
         function(array[0], array[omp_get_thread_num()];
    }

第一个参数是只读的,但在所有线程中都是相同的......

问题在于,如果我使用不同的数据块作为第一个参数,即:array [omp_get_thread_num()+ 1],则每个函数持续1seg。但是当我使用相同的数据块时,array [0],每个函数调用会持续4segs。

我的理论是,没有办法知道函数是否会被函数更改,因此每个线程都要求复制并使其他线程拥有的副本无效,这应该解释延迟。

我试着像这样制作一个数组[0]的本地副本:

    #pragma omp parallel num_threads(4) firstprivate(array)
    {
        Data* tempData = malloc(20 * sizeof(Data));
        memcpy(tempData,array[0], 20*sizeof(Data));

        function(tempData, array[omp_get_thread_num()];
    }

但是我得到了相同的结果......这就像线程没有'释放'数据块所以其他线程可以使用它......

我必须注意第一个参数并不总是数组[0]所以我不能在pragma行中使用firstprivate(array [0])...

问题是:

  • 我做错了吗?
  • 有没有办法'释放'共享内存块,以便其他线程 可以用吗?

尝试让我理解是非常困难的,如果您需要更多信息,请告诉我!

提前致谢... Javier

编辑:我无法更改函数声明,因为它来自一个库! (ACML)

2 个答案:

答案 0 :(得分:2)

我认为你的分析是正确的,编译器无法知道指向的数组在他背后没有改变。实际上他知道他们可能会改变,因为线程0也接收相同的array[0]作为可修改的参数。

所以他必须经常重新加载这些值。首先,您应该声明您的函数类似

void function(Data const*restrict A, Data*restrict B);

这首先告诉编译器,A中的值不能改变,然后没有一个指针可以被另一个(或任何其他指针)别名,所以他我知道数组中的值只会被函数本身改变。

对于线程号0,上面的断言不正确,数组AB实际上是相同的。因此,在进入array[0]之前,最好将temparray复制到公共#pragma omp parallel ,并将相同的temparray作为第一个参数传递每个线程:

Data const* tempData = memcpy(malloc(20 * sizeof(Data)), array[0], 20*sizeof(Data));

#pragma omp parallel num_threads(4)
function(tempData, array[omp_get_thread_num()];

答案 1 :(得分:0)

我认为你的分析错了。如果数据未更改,则不会在核心之间同步。减速有两个可能的原因。

  1. 核心#0获得function(array[0], array[0])。你说第一个参数是只读的,但第二个参数不是。所以核心#0将改变array[0]中的数据,并且CPU必须始终在核心之间同步这些数据。

  2. 第二个可能的原因是阵列的小尺寸(20个元素)。会发生的是核心#1获取指向20个元素数组的指针,核心#2获取指向数组的指针,这可能就在内存中的数组#1之后。因此,它们很可能位于同一缓存线上。 CPU不跟踪更改每个特定元素 - 如果它看到同一缓存行上的元素发生更改,它将同步核心之间的缓存。解决方案是使每个数组变大(这样在20个元素之后你有未使用的空间等于缓存大小(128K?256K?))

  3. 我猜您的代码中存在#1和#2两个问题。