首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >NUMA处理器上的OpenMP内存分配

NUMA处理器上的OpenMP内存分配
EN

Stack Overflow用户
提问于 2017-02-22 03:03:59
回答 1查看 805关注 0票数 4

目前,我正试图在Maestro处理器上使用OpenMP加速一个简单的矩阵减法基准测试,该处理器具有NUMA体系结构,并且基于Tilera Tile64处理器。大师板有49个处理器,排列在一个二维数组中,配置为7x7。每个核心都有自己的L1和L2缓存。在这里可以看到板的布局:http://i.imgur.com/naCWTuK.png

我对编写“NUMA感知”的应用程序的想法并不熟悉,但我所读到的主要共识是,数据局部性是最大化性能的一个重要部分。当在内核之间并行化代码时,我应该将数据保存在线程的本地进行尽可能的处理。

对于这个矩阵减法基准(Ci = Ai ),我认为最好分配每个线程自己的私有A、B和C数组,其大小是工作总大小除以线程数。因此,例如,如果数组的总大小为6000*6000,并且我试图在20个线程中并行化,我将分配大小为( 6000*6000 )/20的私有数组,每个线程将对自己的私有数组执行减法,然后将结果收集回总大小6000*6000的最终数组中。例如(没有将每个线程的结果收集到最终数组中):

代码语言:javascript
运行
复制
int threads = 20;
int size = 6000;
uint8_t *C_final = malloc(sizeof(uint8_t)*(size*size));
#pragma omp parallel num_threads(threads) private(j)
{
     uint8_t *A_priv = malloc(sizeof(uint8_t)*((size*size)/threads));
     uint8_t *B_priv = malloc(sizeof(uint8_t)*((size*size)/threads));
     uint8_t *C_priv = malloc(sizeof(uint8_t)*((size*size)/threads));

     for(j=0; j<((size*size)/threads); j++)
       {
            A_priv[j]=100;
            B_priv[j]=omp_get_thread_num();
            C_priv[j]=0;
       }

     for(j=0; j<((size*size)/threads); j++)
       {
           C_priv[j] = A_priv[j]-B_priv[j];
       }
}

数组的初始值是任意的,其中只有omp_get_thread_num(),因此我从每个线程获得不同的C_priv值。我目前正在试验用户动态网络(),它提供在CPU之间路由数据包的硬件,以便将所有单独的线程结果累积到最终的结果数组中。

我已经实现了加速比,并将线程固定在OMP_PROC_BIND=true中,但我担心,将单个结果积累到最终数组中可能会导致开销,从而抵消加速。

这是解决这类问题的正确方法吗?对于这样一个使用OpenMP的问题,我应该考虑哪些类型的技术来加速NUMA体系结构?

编辑:

为了澄清这一点,这是我最初尝试过的,我注意到执行时间比我只是按顺序运行代码的时间要慢:

代码语言:javascript
运行
复制
     int threads = 20;
     int size = 6000;
     uint8_t *A_priv = malloc(sizeof(uint8_t)*(size*size));
     uint8_t *B_priv = malloc(sizeof(uint8_t)*(size*size));
     uint8_t *C_priv = malloc(sizeof(uint8_t)*(size*size));

     int i;
     for(i=0; i<(size*size); i++)
     {
       A[i] = 10;
       B[i] = 5;
       C[i] = 0;
     }

     #pragma omp parallel for num_threads(threads)
     for(i=0; i<(size*size); i++)
     {
       C[i] = A[i] - B[i];
     }

在看到我在使用OpenMP时执行时间较慢之后,我尝试探究为什么会出现这种情况。似乎数据局部性才是问题所在。这个假设基于我所读到的关于NUMA架构的内容。

我很难弄清楚如何缓解阻碍它发展的瓶颈。我在类似的问题上找到了一些帮助:OpenMP: for schedule,在这里,它会为每个线程分配数据,这样每个线程就可以在本地数据上工作。

我只是觉得像矩阵减法这样简单的东西在使用OpenMP时应该不会很难获得更高的性能。我不知道如何找出瓶颈到底是什么,以及如何缓解瓶颈。

EN

回答 1

Stack Overflow用户

发布于 2019-06-15 01:00:03

在快速搜索和扫描TILE64数据表时,该体系结构似乎不像您通过oprofile、VTune或xperf等工具在x86上使用的那样公开性能计数器。没有这些,您就必须自己设计一些实验,迭代地缩小代码的哪些部分是热的,以及为什么--在没有微体系结构文档的情况下,还需要一些工具来说明代码是如何使用硬件的,这是一项反向工程任务。

关于从哪里开始的一些想法:

  1. 做一些缩放实验。在曲线中是否有一个膝盖,通过某个问题、线程大小或线程数对整体性能有很大影响?这个数字是否暗示了与内存层次结构中某个级别的大小,或者处理器网格的一个维度,或者类似的维度之间的明确关系?
  2. 通过程序记录几个点的执行时间。例如,在较高的水平上知道在恶意代码上花费了多少时间,对于第一个循环和第二个循环来说,这可能是有用的。
  3. “我已经通过这种方式实现了加速,并将线程固定在OMP_PROC_BIND=true上,但我担心,将单个结果积累到最终数组中可能会导致开销,从而否定加速。”--这种担忧在经验上也是可测试的,尤其是如果您正在处理一个足够大的问题,而您的计时器精度(如(2)所示)并不能隔离收集步骤相对于完全可并行性部分所需的时间。
  4. 尝试一个不同的操作--例如,加法或按元素进行除法,而不是减法--看看这是否改变了结果。在许多体系结构上,不同的算术操作具有不同的延迟和吞吐量。如果您查找并发现TILE64的情况是这样的话,进行这样的更改并对第二个示例的运行时进行检测可能会告诉您一些有用的信息:在连续运行它所花费的时间中,有多少实际上与数据局部性问题、启动时间或与OpenMP运行时相关的其他开销有关--与其与小问题大小的关系的总体结果有关,而不是与实际运行速度较慢的并行实现的正确并行部分有关。
  5. 您可以检查生成的程序集。假设编译器将在您发布的示例中执行基本相同的操作,这似乎是合理的,但在查看奇怪的性能时,并不一定会像您希望的那样强大。也许有一些关于代码大小或布局的变化,比如使用指令缓存、预订站或ROB条目的可用性(如果OpenMP有这些东西的话).?天知道,直到你看到。
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42381936

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档