Oracle® Developer Studio 12.5:OpenMP API 用户指南

退出打印视图

更新时间: 2016 年 7 月
 
 

8.2 避免伪共享

如果不慎将共享内存结构与 OpenMP 应用程序一起使用,可能导致性能下降且可伸缩性受限制。多个处理器更新内存中相邻共享数据将导致多处理器互连的通信过多,因而造成计算序列化。

8.2.1 什么是伪共享?

在大多数共享内存多处理器计算机中,每个处理器都有自己的本地高速缓存。高速缓存充当着慢速内存与处理器的高速寄存器之间的缓冲区。访问内存位置时,会使包含所请求内存位置的一部分实际内存(缓存代码行)被复制到高速缓存中。对同一内存位置或其周围位置的后续引用将在高速缓存外满足,直至系统决定有必要在高速缓存和内存之间保持一致性。

当不同处理器上的线程修改驻留在同一缓存代码行上的变量时,就会发生伪共享。这种情况称为伪共享(与真正意义上的共享加以区分),因为线程并没有访问相同的变量,而是访问正好驻留在同一缓存代码行上的不同变量。

当线程修改其高速缓存中的变量时,该变量所在的整个缓存代码行将被标为无效。如果另一个线程尝试访问同一缓存代码行上的变量,则修改后的缓存代码行将写回到内存,线程将从内存中获取缓存代码行。这是因为基于缓存代码行保持高速缓存一致性,而不是针对单个变量或元素。发生伪共享后,线程将被强制从内存中获取缓存代码行的最新副本,即使它尝试访问的变量并未修改。

如果经常发生伪共享,互连流量将增加,而 OpenMP 应用程序的性能和可伸缩性则会显著下降。在出现以下所有情况时,伪共享会使性能下降。

  • 多个线程修改共享数据

  • 多个线程修改同一缓存代码行中的数据

  • 数据修改频率非常高(如在紧凑循环中)

请注意,访问只读共享数据不会发生伪共享。

8.2.2 减少伪共享

当访问特定变量的开销似乎特别高时,通常会检测到伪共享。在执行应用程序时,对占据主导地位的并行循环进行仔细分析即可揭示伪共享造成的性能可伸缩性问题。

通常,可以使用以下方法减少伪共享:

  • 尽可能使用专用或线程专用数据。

  • 利用编译器的优化功能来消除内存负载和存储。

  • 填充数据结构,以使每个线程的数据都驻留在不同的缓存代码行上。填充的大小取决于系统,等于将线程的数据推入到另一缓存代码行所需的大小。

  • 修改数据结构,以减少线程之间的数据共享。

处理伪共享的方法与特定应用程序紧密相关。在某些情况下,更改数据的分配方式可以减少伪共享。在其他情况下,通过更改迭代到线程的映射,为每个块中的每个线程分配更多的工作(通过更改 chunk_size 值),也可以减少伪共享。