Board logo

标题: 多核多处理器架构软件设计的注意事项应用细节 [打印本页]

作者: look_w    时间: 2018-1-9 16:19     标题: 多核多处理器架构软件设计的注意事项应用细节

避免伪共享如果两个或多个处理器正在向同一缓存行的不同部分中写入数据,那么很多缓存和总线通信可能会导致其他处理器上的旧行的每个缓存副本失效或进行更新。这称为 “伪共享” 或者也称为 “CPU 缓存行干扰”。和两个或多个线程共享同一数据(因此需要程序化的同步机制来确保按顺序访问)的真正共享不同,当两个或多个线程访问位于同一缓存行上的无关数据时,就会产生伪共享。
通过以下代码片段更好地了解伪共享(参考:)。
清单 1. 用于演示伪共享的代码示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
double sumLocal[N_THREADS];
. . . . .
. . . . .
void ThreadFunc(void *data)
{
      . . . . . . .
      int id = p->threadId;
      sumLocal[id] = 0.0;
      . . . . . .
      . . . . . .
      for (i=0; i<N; i++)
      sumLocal[id] += p;
      . . . . . .
}




在上面的代码示例中,变量 sumLocal 的大小与线程的数量相同。数组 sumLocal 可能会导致伪共享,因为当它们修改的元素位于同一缓存行上时,多个线程会在数组中执行写入操作。 演示了当在 sumLocal 中修改两个连续的元素时,线程 0 和线程 1 之间的伪共享。线程 0 和线程 1 正在修改数组 sumLocal 中连续的不同元素。这些元素在内存中彼此邻近,因此将位于同一个缓存行上。如图所示,缓存行被加载到 CPU0 和 CPU1 的缓存中(灰色箭头)。即使线程正在修改内存中的不同区域(红色和蓝色箭头),为了保持缓存一致性,在加载该缓存行的所有处理器上,该缓存行会失效,从而强制进行更新。
图 2. 伪共享(参考:部分中的避免和标识线程之间的伪共享。)伪共享会严重降低应用程序的性能,并且很不容易检测到。有关演示伪共享不良影响的简单程序,请参阅  部分中的文章 “多核平台 - CS Liu 的内存问题”。
避免伪共享的技巧消除伪共享?错误!在理想情况下,我们的目标是消除共享,而不只是伪共享。通常,软件设计应该尽力消除对锁、同步机制以及共享的需求。有关的重要观点,请参阅 Dmitriy Vyukov 的。

伪共享不容易检测,但有几个工具(如 Oprofile 和 Valgrind 的 )可以为您提供帮助。
消除或减少锁争用这个设计注意事项是前面提到的两个考虑事项的扩展,目的是避免内存争用和伪共享。正如前面部分所述,软件设计者的主要目标应该是消除共享,以便线程或进程之间不会发生资源争用。前面部分中所述的一些技巧(如使用线程本地变量代替全局共享区域)可以防止发生内存争用和伪共享。但是,该技巧并不适用于所有情况。
例如,如果有一个保持资源状态的数据结构,则有可能无法在每个线程中包含该结构的副本。该数据结构可能必须由应用程序中的所有线程读取和修改。因此,必须使用同步技术来保持数据的一致性以及此类共享数据结构的完整性。如果存在用于保护共享资源的锁或同步构造,则可能会在多个线程或进程之间出现锁争用,从而降低性能。
在多核、多处理器系统上,可能有空间来同时运行大量线程或进程,但是,如果这些线程必须不断地彼此竞争,以访问或修改共享资源或数据结构,那么系统的总体吞吐量会有所降低。这会导致应用程序无法通过伸缩来有效地利用可用的计算资源。在由于锁争用而导致性能降低的极坏情况下,随着核心或处理器数量的增加,应用程序的性能会有所降低。
避免锁争用的技巧减少锁争用的技巧检测锁争用以及消除或减少锁争用对于在多核、多处理器环境中提供应用程序的可伸缩性非常重要。操作系统提供了用于检测和度量由于锁争用而导致性能瓶颈的实用工具。例如,Solaris 提供了 Lockstat 实用工具,用于度量内核模块中的锁争用。同样,Linux 内核也提供了 Lockstat 和 Lockdep 框架,用于检测和度量锁争用以及性能瓶颈。"Windows 性能工具包 - Xperf" 在 Windows 上提供了类似的功能。有关的详细信息,请参阅  部分。
避免堆争用C/C++ 标准内存管理例程是使用特定于平台的内存管理 API 实现的,它通常基于堆的概念。这些库例程(无论是单线程版本还是多线程版本)在单个堆上分配或释放内存。它是全局资源,在某个进程中的线程之间共享并争用。堆争用是内存密集型多线程应用程序的瓶颈之一。
避免堆争用的技巧 部分中的 “多核平台的内存问题 - CS Liu” 文章提供了一个堆争用示例。在这个参考资料中,作者演示了如何使用专用堆将性能提高 3 倍左右(与使用全局堆相比)。
注意:提高处理器关联处理器关联是一个线程或进程属性,该属性告诉操作系统可以在哪些核或逻辑处理器上运行进程。这更适合嵌入式软件设计。
显示了一个系统配置,该配置包含两个处理器,每个处理器有两个核,这两个核都有一个共享的 L2 缓存。在该配置中,在同一处理器上的两个核之间以及不同处理器上的两个核之间,缓存子系统的行为将会有所不同。如果两个相关的进程或某个进程的两个相关线程被分配给同一处理器上的两个核,那么它们可以更好地利用共享的 L2 缓存,而且可以减少保持缓存一致性的开销。
图 3. 多个核共享一个 L2 缓存的系统设计注意事项编程模型当为应用程序中的线程分配工作时,软件设计者可以考虑两个不同的编程模型。它们是:
软件所需的操作类型以及数据特性都会影响模型的选择,但是必须了解这些模型如何在多处理器或多核环境中执行。
软件设计者需要考虑的几个注意事项在 部分中的多核多处理器系统的软件设计问题参考文献中,详细介绍了编程模型、为多核多处理器架构进行软件设计时应用这些模型的挑战和优势。




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0