gpt4 book ai didi

c - NUMA 处理器上的 OpenMP 内存分配

转载 作者:太空狗 更新时间:2023-10-29 15:41:37 26 4
gpt4 key购买 nike

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

我对编写“NUMA 感知”应用程序的想法很陌生,但从我读到的内容中得出的主要共识是数据局部性是最大化性能的重要组成部分。在内核之间并行化代码时,我应该尽可能将数据在执行处理的线程本地使用。

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

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 架构的速度?

编辑:

为了澄清,这是我最初尝试的,我注意到执行时间比我连续运行代码慢:

     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 时应该不难获得更高的性能。我不确定如何着手找出瓶颈到底是什么以及如何缓解它。

最佳答案

在 TILE64 数据表的快速搜索和扫描中,它看起来不像架构公开性能计数器,就像您通过 oprofile、VTune 或 xperf 等工具在 x86 上使用的那样。如果没有这些,您将不得不设计一些自己的实验,以迭代地缩小代码的哪一部分是热的以及为什么 - 在没有微体系结构文档以及指示您的代码如何使用硬件的工具的情况下,有点逆向工程任务。

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

  1. 做一些缩放实验。曲线中是否存在拐点,超过一定的问题大小或线程数会对整体性能产生重大影响?该数字是否暗示与内存层次结构中某个级别的大小或处理器网格的维度等存在某种明确的关系?
  2. 记录程序中几个点的执行时间。例如,了解在较高级别上花费了多少时间在 mallocs 与第一个循环与第二个循环上可能会很有用。
  3. “通过使用 OMP_PROC_BIND=true 固定线程,我已经通过这种方式实现了加速,但我担心将单个结果累加到最终数组中可能会导致开销,从而抵消加速。” - 这种担忧也可以根据经验进行测试,特别是如果您正在处理足够大的问题,那么(2)中的计时器准确性对于隔离收集步骤所花费的时间与完全可并行化的部分而言不是问题。
  4. 尝试不同的操作 - 例如,加法或逐元素除法而不是减法,看看是否会改变结果。在许多架构上,不同的算术运算具有不同的延迟和吞吐量。如果您查找并发现 TILE64 就是这种情况,那么进行这样的更改并检测第二个示例的运行时可能会告诉您一些有用的信息,说明串行运行它所花费的时间实际上有多少与数据有关局部性问题与启动时间或与 OpenMP 运行时相关的其他开销相比,与并行实现的适当并行部分实际运行速度较慢相比,与 OpenMP 运行时相关的整体结果可能更多地涉及它与小问题规模的关系。
  5. 您可以检查生成的程序集。假设编译器会在您发布的示例中做基本相同的事情似乎是合理的,但在查看奇怪的性能时不一定像您希望的那样强烈。也许代码大小或布局在有/没有 OpenMP 的情况下会发生变化,或者当从一种并行方法转移到另一种时,例如指令缓存的使用、保留站的可用性或 ROB 条目(如果 TILE64 有这些东西)......?谁知道,直到你看。

关于c - NUMA 处理器上的 OpenMP 内存分配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42381936/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com