Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/performance/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading OpenMP:堆阵列性能差(堆栈阵列工作正常)_Multithreading_Performance_Stack_Heap_Openmp - Fatal编程技术网

Multithreading OpenMP:堆阵列性能差(堆栈阵列工作正常)

Multithreading OpenMP:堆阵列性能差(堆栈阵列工作正常),multithreading,performance,stack,heap,openmp,Multithreading,Performance,Stack,Heap,Openmp,我是一位经验丰富的OpenMP用户,但我刚刚遇到了一个令人费解的问题,我希望这里的人能够提供帮助。问题是一个简单的散列算法对堆栈分配的数组性能良好,但对堆上的数组性能较差 下面的示例使用i%M(i模M)对各个数组元素中的每个第M个整数进行计数。为了简单起见,假设N=1000000,M=10。如果N%M==0,则结果应该是bins[]的每个元素都等于N/M: #pragma omp for for (int i=0; i<N; i++) bins[ i%M ]++; 对于OM

我是一位经验丰富的OpenMP用户,但我刚刚遇到了一个令人费解的问题,我希望这里的人能够提供帮助。问题是一个简单的散列算法对堆栈分配的数组性能良好,但对堆上的数组性能较差

下面的示例使用i%M(i模M)对各个数组元素中的每个第M个整数进行计数。为了简单起见,假设N=1000000,M=10。如果N%M==0,则结果应该是bins[]的每个元素都等于N/M:

#pragma omp for
  for (int i=0; i<N; i++) 
    bins[ i%M ]++;
对于OMP_NUM_线程=10

OpenMP threads: 10
Time with stack array: 0.329 sec, checksum=1073741824 (must be 1073741824).
Time with heap  array: 2.150 sec, checksum=1073741824 (must be 1073741824).

我将非常感谢任何帮助

这是一个可爱的问题:对于上面的代码(gcc4.4,Intel i7),我得到了4个线程

OpenMP threads: 4
Time with stack array:        1.696 sec, checksum=1073741824 (must be 1073741824).
Time with heap  array:        5.413 sec, checksum=1073741824 (must be 1073741824).
但是如果我把malloc行改为

    int* bins_thread_heap=(int*)malloc(sizeof(int)*M*1024);
更新:甚至

    int* bins_thread_heap=(int*)malloc(sizeof(int)*16);
)

然后我得到

OpenMP threads: 4
Time with stack array:        1.578 sec, checksum=1073741824 (must be 1073741824).
Time with heap  array:        1.574 sec, checksum=1073741824 (must be 1073741824).
这里的问题是。默认的malloc非常(空间)高效,并且将请求的小分配都放在一个内存块中,彼此相邻;但由于分配非常小,以至于多个线程可以在同一缓存线中进行匹配,这意味着每次一个线程更新其值时,它都会弄脏相邻线程中值的缓存线。通过使请求的内存足够大,这不再是一个问题

顺便说一句,应该很清楚为什么堆栈分配的情况下没有看到这个问题;不同的线程-不同的堆栈-内存足够明显,错误共享不是问题

作为一个补充——这里使用的M大小并不重要,但如果M(或线程数)更大,omp临界值将是一个很大的串行瓶颈;您可以使用来更有效地求和校验和

#pragma omp parallel reduction(+:checksum)
    { // Each openmp thread should have a private copy of 
        // bins_thread_heap on the heap:
        int* bins_thread_heap=(int*)malloc(sizeof(int)*M*1024);
        for (int j=0; j<M; j++) bins_thread_heap[j]=0;
#pragma omp for
        for (int i=0; i<N; i++)
        { // Accumulating every M-th number in respective array element
            const int j=i%M;
            bins_thread_heap[j]++;
        }
        for (int j=0; j<M; j++)
            checksum+=bins_thread_heap[j];
        free(bins_thread_heap);
 }
#pragma omp并行归约(+:校验和)
{//每个openmp线程都应该有一个
//堆上的bin\u线程\u堆:
int*bins\u thread\u heap=(int*)malloc(sizeof(int)*M*1024);

对于(int j=0;j而言,最初的问题暗示堆数组比堆栈数组慢。不幸的是,这种慢的原因与多线程应用程序中缓存线冲突的特定情况有关。这并不能证明堆数组通常比堆栈数组慢的暗示是正确的。
在大多数情况下,性能没有显著差异,特别是在阵列比缓存线大得多的情况下。情况往往相反,因为针对所需大小使用可分配堆阵列会比需要更多内存传输的较大固定大小阵列带来性能优势。

太好了,乔纳森,谢谢!那么这是否意味着有效使用堆的唯一方法就是浪费它?也许OpenMP的一些实现有一个特殊的malloc函数,我必须研究一下。顺便说一句,你说的关键块是瓶颈的说法是不正确的。关键块在我的并行部分的末尾,不是在for循环内部。事实上,`reduce'子句就是通过这样做来实现缩减的,在并行部分的末尾放置一个关键块。但是感谢大家提醒!啊,但是(a)关键是一个非常重的操作,并且(b)它的粒度比需要的粗-你可以先进行局部求和,然后再进行关键运算(或者更好的是,一个原子)来更新全局和。但即使如此,对于大量线程,减少的速度仍然会更快,因为最终的减少可以按层次(在ln(线程数)时间内完成,而不是在(线程数)时间内完成。)至于堆的有效使用——避免错误共享是所有共享内存操作都会遇到的问题,避免错误共享的唯一方法是确保内存块之间至少有一条缓存线相隔。该间距的大小将取决于系统;将其设为多个K是一个过大的问题,通常是512字节左右我会的。当然,你们们对我能为这段小代码做的小调整是正确的。我对关键部分的使用实际上是我正在解决的实际问题的产物。在这里,我有Fortran 90派生类型的数组,而不是整数数组,我一辈子都想不出一种更优雅的方法来求和结果为了其他浏览者的缘故,这里有一个链接,指向查询缓存线大小的讨论
OpenMP threads: 4
Time with stack array:        1.578 sec, checksum=1073741824 (must be 1073741824).
Time with heap  array:        1.574 sec, checksum=1073741824 (must be 1073741824).
#pragma omp parallel reduction(+:checksum)
    { // Each openmp thread should have a private copy of 
        // bins_thread_heap on the heap:
        int* bins_thread_heap=(int*)malloc(sizeof(int)*M*1024);
        for (int j=0; j<M; j++) bins_thread_heap[j]=0;
#pragma omp for
        for (int i=0; i<N; i++)
        { // Accumulating every M-th number in respective array element
            const int j=i%M;
            bins_thread_heap[j]++;
        }
        for (int j=0; j<M; j++)
            checksum+=bins_thread_heap[j];
        free(bins_thread_heap);
 }