在多线程环境中的Malloc性能

Bil*_*hon 10 malloc performance multithreading openmp

我一直在使用openmp框架进行一些实验,发现了一些奇怪的结果,我不知道我知道如何解释.

我的目标是创建这个巨大的矩阵,然后用值填充它.为了从多线程环境中获得性能,我将代码的某些部分作为并行循环.我在一台配有2个四核xeon处理器的机器上运行它,所以我可以安全地在那里放置8个并发线程.

一切都按预期工作,但由于某种原因,实际分配矩阵行的for循环在仅运行3个线程时具有奇怪的峰值性能.从那以后,添加更多线程只会让我的循环花费更长时间.8个线程实际上只需要一个线程就可以获得更多时间.

这是我的并行循环:

 int width = 11;
 int height = 39916800;
 vector<vector<int> > matrix;
 matrix.resize(height);    
 #pragma omp parallel shared(matrix,width,height) private(i) num_threads(3)
 {
   #pragma omp for schedule(dynamic,chunk)
   for(i = 0; i < height; i++){
     matrix[i].resize(width);
   }
 } /* End of parallel block */
Run Code Online (Sandbox Code Playgroud)

这让我想知道:在多线程环境中调用malloc(我想是矢量模板类的resize方法实际调用的)时是否存在已知的性能问题?我在一个多线程环境中发现了一些关于释放堆空间性能损失的文章,但没有具体说明在这种情况下分配新空间.

举一个例子,我将下面的图表显示循环完成所需的时间作为分配循环的线程数的函数,以及一个只读取来自这个巨大矩阵的数据的正常循环稍后的.

并行区域1,其中有分配

并行区域2,没有分配

两次使用gettimeofday函数测量并且似乎在不同的执行实例中返回非常相似和准确的结果.那么,任何人都有一个很好的解释?

小智 7

你对内部调用malloc的vector :: resize()是正确的.实现方式malloc相当复杂.我可以看到malloc可以在多线程环境中导致争用的多个地方.

  1. malloc可能在用户空间中保留全局数据结构来管理用户的堆地址空间.需要保护此全局数据结构以防止并发访问和修改.一些分配器有优化来减少访问这个全局数据结构的次数......我不知道Ubuntu出现了多远.

  2. malloc分配地址空间.因此,当您实际开始触摸分配的内存时,您将经历"软页面错误",这是一个页面错误,允许操作系统内核为分配的地址空间分配后备RAM.这可能是昂贵的,因为内核之旅并且需要内核采取一些全局锁来访问其自己的全局RAM资源数据结构.

  3. 用户空间分配器可能会保留一些分配的空间来提供新的分配.但是,一旦这些分配用完,分配器就需要返回内核并从内核中分配更多的地址空间.这也很昂贵,并且需要访问内核并且内核需要一些全局锁来访问其全局地址空间管理相关的数据结构.

最重要的是,这些相互作用可能相当复杂.如果您遇到这些瓶颈,我建议您只需"预先分配"您的记忆.这将涉及分配它然后触摸所有它(全部来自单个线程),以便您可以在以后从所有线程使用该内存,而不会在用户或内核级别遇到锁争用.